/* Create an RTSP Request */ static int initializeRtspRequest(PRTSP_MESSAGE msg, char* command, char* target) { char sequenceNumberStr[16]; char clientVersionStr[16]; // 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++); sprintf(clientVersionStr, "%d", rtspClientVersion); if (!addOption(msg, "CSeq", sequenceNumberStr) || !addOption(msg, "X-GS-ClientVersion", clientVersionStr)) { freeMessage(msg); return 0; } return 1; }
// Given an RTSP message string rtspMessage, parse it into an RTSP_MESSAGE struct msg int parseRtspMessage(PRTSP_MESSAGE msg, char* rtspMessage, int length) { char* token; char* protocol; char* endCheck; char* target; char* statusStr; char* command; char* sequence; char flag; char messageEnded = 0; char* payload = NULL; char* opt = NULL; int statusCode = 0; int sequenceNum; int exitCode; POPTION_ITEM options = NULL; POPTION_ITEM newOpt; // Delimeter sets for strtok() char* delim = " \r\n"; char* end = "\r\n"; char* optDelim = " :\r\n"; char typeFlag = TOKEN_OPTION; // Put the raw message into a string we can use char* messageBuffer = malloc(length + 1); if (messageBuffer == NULL) { exitCode = RTSP_ERROR_NO_MEMORY; goto ExitFailure; } 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); if (token == NULL) { exitCode = RTSP_ERROR_MALFORMED; goto ExitFailure; } // The message is a response if (startsWith(token, "RTSP")) { flag = TYPE_RESPONSE; // The current token is the protocol protocol = token; // Get the status code token = strtok(NULL, delim); statusCode = atoi(token); if (token == NULL) { exitCode = RTSP_ERROR_MALFORMED; goto ExitFailure; } // Get the status string statusStr = strtok(NULL, end); if (statusStr == NULL) { exitCode = RTSP_ERROR_MALFORMED; goto ExitFailure; } // Request fields - we don't care about them here target = NULL; command = NULL; } // The message is a request else { flag = TYPE_REQUEST; command = token; target = strtok(NULL, delim); if (target == NULL) { exitCode = RTSP_ERROR_MALFORMED; goto ExitFailure; } protocol = strtok(NULL, delim); if (protocol == NULL) { exitCode = RTSP_ERROR_MALFORMED; goto ExitFailure; } // Response field - we don't care about it here statusStr = NULL; } if (strcmp(protocol, "RTSP/1.0")) { exitCode = RTSP_ERROR_MALFORMED; goto ExitFailure; } // Parse remaining options while (token != NULL) { token = strtok(NULL, typeFlag == TOKEN_OPTION ? optDelim : end); if (token != NULL) { if (typeFlag == TOKEN_OPTION) { opt = token; } // The token is content else { // Create a new node containing the option and content newOpt = (POPTION_ITEM)malloc(sizeof(OPTION_ITEM)); if (newOpt == NULL) { freeOptionList(options); exitCode = RTSP_ERROR_NO_MEMORY; goto ExitFailure; } newOpt->flags = 0; newOpt->option = opt; newOpt->content = token; newOpt->next = NULL; insertOption(&options, newOpt); // Check if we're at the end of the message portion marked by \r\n\r\n // endCheck points to the remainder of messageBuffer after the token endCheck = &token[0] + strlen(token) + 1; // See if we've hit the end of the message. The first \r is missing because it's been tokenized if (startsWith(endCheck, "\n\r\n")) { // We've encountered the end of the message - mark it thus messageEnded = 1; // The payload is the remainder of messageBuffer. If none, then payload = null if (endCheck[3] != '\0') payload = &endCheck[3]; break; } } } typeFlag ^= 1; // flip the flag } // If we never encountered the double CRLF, then the message is malformed! if (!messageEnded) { exitCode = RTSP_ERROR_MALFORMED; goto ExitFailure; } // Get sequence number as an integer sequence = getOptionContent(options, "CSeq"); if (sequence != NULL) { sequenceNum = atoi(sequence); } else { sequenceNum = SEQ_INVALID; } // 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, payload ? length - (int)(messageBuffer - payload) : 0); } else { createRtspResponse(msg, messageBuffer, FLAG_ALLOCATED_MESSAGE_BUFFER | FLAG_ALLOCATED_OPTION_ITEMS, protocol, statusCode, statusStr, sequenceNum, options, payload, payload ? length - (int)(messageBuffer - payload) : 0); } return RTSP_ERROR_SUCCESS; ExitFailure: if (options) { free(options); } if (messageBuffer) { free(messageBuffer); } return exitCode; }