Fix RTSP parser and connection bugs

This commit is contained in:
Cameron Gutman 2014-08-17 20:06:05 -07:00
parent 5a97188197
commit 6571708eb5
3 changed files with 57 additions and 23 deletions

View File

@ -37,6 +37,7 @@ typedef struct _RTSP_MESSAGE {
char *protocol;
POPTION_ITEM options;
char *payload;
int payloadLength;
char* messageBuffer;
@ -54,10 +55,10 @@ typedef struct _RTSP_MESSAGE {
} message;
} RTSP_MESSAGE, *PRTSP_MESSAGE;
int parseRtspMessage(PRTSP_MESSAGE msg, char *rtspMessage);
int parseRtspMessage(PRTSP_MESSAGE msg, char *rtspMessage, int length);
void freeMessage(PRTSP_MESSAGE msg);
void createRtspResponse(PRTSP_MESSAGE msg, char* messageBuffer, int flags, char *protocol, int statusCode, char *statusString, int sequenceNumber, POPTION_ITEM optionsHead, char *payload);
void createRtspRequest(PRTSP_MESSAGE msg, char* messageBuffer, int flags, char *command, char *target, char *protocol, int sequenceNumber, POPTION_ITEM optionsHead, char *payload);
void createRtspResponse(PRTSP_MESSAGE msg, char* messageBuffer, int flags, char *protocol, int statusCode, char *statusString, int sequenceNumber, POPTION_ITEM optionsHead, char *payload, int payloadLength);
void createRtspRequest(PRTSP_MESSAGE msg, char* messageBuffer, int flags, char *command, char *target, char *protocol, int sequenceNumber, POPTION_ITEM optionsHead, char *payload, int payloadLength);
char *getOptionContent(POPTION_ITEM optionsHead, char *option);
void insertOption(POPTION_ITEM *optionsHead, POPTION_ITEM opt);
void freeOptionList(POPTION_ITEM optionsHead);

View File

@ -4,14 +4,15 @@
static SOCKET sock = INVALID_SOCKET;
static IP_ADDRESS remoteAddr;
static int currentSeqNumber = 1;
static char* rtspTargetUrl;
static char rtspTargetUrl[256];
static char sessionIdString[16];
static int hasSessionId = 0;
// GFE 2.1.1
#define RTSP_CLIENT_VERSION 10
#define RTSP_CLIENT_VERSION_S "10"
#define RTSP_MAX_RESP_SIZE 1024
#define RTSP_MAX_RESP_SIZE 16384
static POPTION_ITEM createOptionItem(char* option, char* content)
{
@ -58,10 +59,15 @@ static int addOption(PRTSP_MESSAGE msg, char* option, char* content)
static int initializeRtspRequest(PRTSP_MESSAGE msg, char* command, char* target)
{
createRtspRequest(msg, NULL, 0, command, target, "RTSP/1.0",
currentSeqNumber++, NULL, NULL);
char sequenceNumberStr[16];
if (!addOption(msg, "X-GS-ClientVersion", RTSP_CLIENT_VERSION_S)) {
// FIXME: Hacked CSeq attribute due to RTSP parser bug
createRtspRequest(msg, NULL, 0, command, target, "RTSP/1.0",
0, NULL, NULL, 0);
sprintf(sequenceNumberStr, "%d", currentSeqNumber++);
if (!addOption(msg, "CSeq", sequenceNumberStr) ||
!addOption(msg, "X-GS-ClientVersion", RTSP_CLIENT_VERSION_S)) {
freeMessage(msg);
return 0;
}
@ -113,7 +119,7 @@ static int transactRtspMessage(PRTSP_MESSAGE request, PRTSP_MESSAGE response) {
}
}
if (parseRtspMessage(response, responseBuffer) == RTSP_ERROR_SUCCESS) {
if (parseRtspMessage(response, responseBuffer, offset) == RTSP_ERROR_SUCCESS) {
// Successfully parsed response
ret = 1;
}
@ -178,7 +184,7 @@ static int setupStream(PRTSP_MESSAGE response, char* target) {
ret = initializeRtspRequest(&request, "SETUP", target);
if (ret != 0) {
if (sessionIdString[0] != 0) {
if (hasSessionId) {
if (!addOption(&request, "Session", sessionIdString)) {
ret = 0;
goto FreeMessage;
@ -241,6 +247,7 @@ static int sendVideoAnnounce(PRTSP_MESSAGE response, PSTREAM_CONFIGURATION strea
goto FreeMessage;
}
request.flags |= FLAG_ALLOCATED_PAYLOAD;
request.payloadLength = payloadLength;
sprintf(payloadLengthStr, "%d", payloadLength);
if (!addOption(&request, "Content-length", payloadLengthStr)) {
@ -257,7 +264,12 @@ static int sendVideoAnnounce(PRTSP_MESSAGE response, PSTREAM_CONFIGURATION strea
}
int performRtspHandshake(IP_ADDRESS addr, PSTREAM_CONFIGURATION streamConfigPtr) {
struct in_addr inaddr;
// Initialize global state
remoteAddr = addr;
inaddr.S_un.S_addr = addr;
sprintf(rtspTargetUrl, "rtsp://%s", inet_ntoa(inaddr));
{
RTSP_MESSAGE response;
@ -314,6 +326,9 @@ int performRtspHandshake(IP_ADDRESS addr, PSTREAM_CONFIGURATION streamConfigPtr)
return -1;
}
strcpy(sessionIdString, sessionId);
hasSessionId = 1;
freeMessage(&response);
}

View File

@ -48,14 +48,13 @@ static int getMessageLength(PRTSP_MESSAGE msg){
count += 2;
/* Add the length of the payload, if any */
if (msg->payload != NULL)
count += strlen(msg->payload);
count += msg->payloadLength;
return count;
}
/* Given an RTSP message string rtspMessage, parse it into an RTSP_MESSAGE struct msg */
int parseRtspMessage(PRTSP_MESSAGE msg, char *rtspMessage) {
int parseRtspMessage(PRTSP_MESSAGE msg, char *rtspMessage, int length) {
char *token, *protocol, *endCheck, *target, *statusStr, *command, *sequence, *content, flag;
char messageEnded = 0, *payload = NULL, *opt = NULL;
int statusCode, sequenceNum, exitCode;
@ -69,12 +68,15 @@ int parseRtspMessage(PRTSP_MESSAGE msg, char *rtspMessage) {
char typeFlag = TOKEN_OPTION;
/* Put the raw message into a string we can use */
char *messageBuffer = malloc((strlen(rtspMessage) + 1) * sizeof(*rtspMessage));
char *messageBuffer = malloc(length + 1);
if (messageBuffer == NULL) {
exitCode = RTSP_ERROR_NO_MEMORY;
goto ExitFailure;
}
strcpy(messageBuffer, rtspMessage);
memcpy(messageBuffer, rtspMessage, length);
// The payload logic depends on a null-terminator at the end
messageBuffer[length] = 0;
/* Get the first token of the message*/
token = strtok(messageBuffer, delim);
@ -135,7 +137,7 @@ int parseRtspMessage(PRTSP_MESSAGE msg, char *rtspMessage) {
}
/* Parse remaining options */
while (token != NULL){
token = strtok(NULL, optDelim);
token = strtok(NULL, typeFlag == TOKEN_OPTION ? optDelim : end);
if (token != NULL){
/* The token is an option */
@ -194,10 +196,12 @@ int parseRtspMessage(PRTSP_MESSAGE msg, char *rtspMessage) {
}
/* Package the new parsed message into the struct */
if (flag == TYPE_REQUEST){
createRtspRequest(msg, messageBuffer, FLAG_ALLOCATED_MESSAGE_BUFFER | FLAG_ALLOCATED_OPTION_ITEMS, command, target, protocol, sequenceNum, options, payload);
createRtspRequest(msg, messageBuffer, FLAG_ALLOCATED_MESSAGE_BUFFER | FLAG_ALLOCATED_OPTION_ITEMS, command, target,
protocol, sequenceNum, options, payload, payload ? length - (messageBuffer - payload) : 0);
}
else {
createRtspResponse(msg, messageBuffer, FLAG_ALLOCATED_MESSAGE_BUFFER | FLAG_ALLOCATED_OPTION_ITEMS, protocol, statusCode, statusStr, sequenceNum, options, payload);
createRtspResponse(msg, messageBuffer, FLAG_ALLOCATED_MESSAGE_BUFFER | FLAG_ALLOCATED_OPTION_ITEMS, protocol, statusCode,
statusStr, sequenceNum, options, payload, payload ? length - (messageBuffer - payload) : 0);
}
return RTSP_ERROR_SUCCESS;
@ -214,13 +218,14 @@ ExitFailure:
/* Create new RTSP message struct with response data */
void createRtspResponse(PRTSP_MESSAGE msg, char *message, int flags, char *protocol,
int statusCode, char *statusString, int sequenceNumber, POPTION_ITEM optionsHead, char *payload) {
int statusCode, char *statusString, int sequenceNumber, POPTION_ITEM optionsHead, char *payload, int payloadLength) {
msg->type = TYPE_RESPONSE;
msg->flags = flags;
msg->messageBuffer = message;
msg->protocol = protocol;
msg->options = optionsHead;
msg->payload = payload;
msg->payloadLength = payloadLength;
msg->sequenceNumber = sequenceNumber;
msg->message.response.statusString = statusString;
msg->message.response.statusCode = statusCode;
@ -228,13 +233,14 @@ void createRtspResponse(PRTSP_MESSAGE msg, char *message, int flags, char *proto
/* Create new RTSP message struct with request data */
void createRtspRequest(PRTSP_MESSAGE msg, char *message, int flags,
char *command, char *target, char *protocol, int sequenceNumber, POPTION_ITEM optionsHead, char *payload) {
char *command, char *target, char *protocol, int sequenceNumber, POPTION_ITEM optionsHead, char *payload, int payloadLength) {
msg->type = TYPE_REQUEST;
msg->flags = flags;
msg->protocol = protocol;
msg->messageBuffer = message;
msg->options = optionsHead;
msg->payload = payload;
msg->payloadLength = payloadLength;
msg->sequenceNumber = sequenceNumber;
msg->message.request.command = command;
msg->message.request.target = target;
@ -286,7 +292,7 @@ void freeOptionList(POPTION_ITEM optionsHead){
while (current != NULL){
temp = current;
current = current->next;
if (optionsHead->flags & FLAG_ALLOCATED_OPTION_FIELDS){
if (temp->flags & FLAG_ALLOCATED_OPTION_FIELDS){
free(temp->option);
free(temp->content);
}
@ -299,7 +305,7 @@ char *serializeRtspMessage(PRTSP_MESSAGE msg, int *serializedLength){
int size = getMessageLength(msg);
char *serializedMessage = malloc(size);
POPTION_ITEM current = msg->options;
char *statusCodeStr = malloc(sizeof(int));
char *statusCodeStr = malloc(4); // 3 characeters + NUL
if (msg->type == TYPE_REQUEST){
/* command [space] */
@ -336,9 +342,21 @@ char *serializeRtspMessage(PRTSP_MESSAGE msg, int *serializedLength){
strcat(serializedMessage, "\r\n");
/* payload */
strcat(serializedMessage, msg->payload);
if (msg->payload != NULL) {
int offset;
// Find end of the RTSP message header
for (offset = 0; serializedMessage[offset] != 0; offset++);
// Add the payload after
memcpy(&serializedMessage[offset], msg->payload, msg->payloadLength);
*serializedLength = offset + msg->payloadLength;
}
else {
*serializedLength = strlen(serializedMessage);
}
*serializedLength = strlen(serializedMessage) + 1;
return serializedMessage;
}