diff --git a/limelight-common/Rtsp.h b/limelight-common/Rtsp.h index bc5cd94..1d7d6d1 100644 --- a/limelight-common/Rtsp.h +++ b/limelight-common/Rtsp.h @@ -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); diff --git a/limelight-common/RtspConnection.c b/limelight-common/RtspConnection.c index ef06a41..05c6801 100644 --- a/limelight-common/RtspConnection.c +++ b/limelight-common/RtspConnection.c @@ -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) { + char sequenceNumberStr[16]; + + // FIXME: Hacked CSeq attribute due to RTSP parser bug createRtspRequest(msg, NULL, 0, command, target, "RTSP/1.0", - currentSeqNumber++, NULL, NULL); + 0, NULL, NULL, 0); - if (!addOption(msg, "X-GS-ClientVersion", RTSP_CLIENT_VERSION_S)) { + 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); } diff --git a/limelight-common/RtspParser.c b/limelight-common/RtspParser.c index 9f90946..4335c9d 100644 --- a/limelight-common/RtspParser.c +++ b/limelight-common/RtspParser.c @@ -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; }