#include "RTSPCommon.hh"#include "Locale.hh"#include <string.h>#include <stdio.h>#include <ctype.h>#include <time.h>#include <signal.h>Include dependency graph for RTSPCommon.cpp:

Go to the source code of this file.
Defines | |
| #define | USE_SIGNALS 1 |
Functions | |
| static void | decodeURL (char *url) |
| Boolean | parseRTSPRequestString (char const *reqStr, unsigned reqStrSize, char *resultCmdName, unsigned resultCmdNameMaxSize, char *resultURLPreSuffix, unsigned resultURLPreSuffixMaxSize, char *resultURLSuffix, unsigned resultURLSuffixMaxSize, char *resultCSeq, unsigned resultCSeqMaxSize, char *resultSessionIdStr, unsigned resultSessionIdStrMaxSize, unsigned &contentLength) |
| Boolean | parseRangeParam (char const *paramStr, double &rangeStart, double &rangeEnd, char *&absStartTime, char *&absEndTime) |
| Boolean | parseRangeHeader (char const *buf, double &rangeStart, double &rangeEnd, char *&absStartTime, char *&absEndTime) |
| static Boolean | isSeparator (char c) |
| Boolean | RTSPOptionIsSupported (char const *commandName, char const *optionsResponseString) |
| char const * | dateHeader () |
| void | ignoreSigPipeOnSocket (int socketNum) |
| #define USE_SIGNALS 1 |
Definition at line 31 of file RTSPCommon.cpp.
| char const* dateHeader | ( | ) |
Definition at line 303 of file RTSPCommon.cpp.
Referenced by RTSPServer::RTSPClientConnection::authenticationOK(), RTSPServer::RTSPClientConnection::handleCmd_bad(), RTSPServer::RTSPClientConnection::handleCmd_DESCRIBE(), RTSPServer::RTSPClientConnection::handleCmd_notSupported(), RTSPServer::RTSPClientConnection::handleCmd_OPTIONS(), RTSPServer::RTSPClientSession::handleCmd_PLAY(), RTSPServer::RTSPClientSession::handleCmd_SETUP(), RTSPServer::RTSPClientConnection::handleHTTPCmd_notFound(), RTSPServer::RTSPClientConnection::handleHTTPCmd_notSupported(), RTSPServerSupportingHTTPStreaming::RTSPClientConnectionSupportingHTTPStreaming::handleHTTPCmd_StreamingGET(), and RTSPServer::RTSPClientConnection::setRTSPResponse().
00303 { 00304 static char buf[200]; 00305 #if !defined(_WIN32_WCE) 00306 time_t tt = time(NULL); 00307 strftime(buf, sizeof buf, "Date: %a, %b %d %Y %H:%M:%S GMT\r\n", gmtime(&tt)); 00308 #else 00309 // WinCE apparently doesn't have "time()", "strftime()", or "gmtime()", 00310 // so generate the "Date:" header a different, WinCE-specific way. 00311 // (Thanks to Pierre l'Hussiez for this code) 00312 // RSF: But where is the "Date: " string? This code doesn't look quite right... 00313 SYSTEMTIME SystemTime; 00314 GetSystemTime(&SystemTime); 00315 WCHAR dateFormat[] = L"ddd, MMM dd yyyy"; 00316 WCHAR timeFormat[] = L"HH:mm:ss GMT\r\n"; 00317 WCHAR inBuf[200]; 00318 DWORD locale = LOCALE_NEUTRAL; 00319 00320 int ret = GetDateFormat(locale, 0, &SystemTime, 00321 (LPTSTR)dateFormat, (LPTSTR)inBuf, sizeof inBuf); 00322 inBuf[ret - 1] = ' '; 00323 ret = GetTimeFormat(locale, 0, &SystemTime, 00324 (LPTSTR)timeFormat, 00325 (LPTSTR)inBuf + ret, (sizeof inBuf) - ret); 00326 wcstombs(buf, inBuf, wcslen(inBuf)); 00327 #endif 00328 return buf; 00329 }
| static void decodeURL | ( | char * | url | ) | [static] |
Definition at line 34 of file RTSPCommon.cpp.
References NULL.
Referenced by parseRTSPRequestString().
00034 { 00035 // Replace (in place) any %<hex><hex> sequences with the appropriate 8-bit character. 00036 char* cursor = url; 00037 while (*cursor) { 00038 if ((cursor[0] == '%') && 00039 cursor[1] && isxdigit(cursor[1]) && 00040 cursor[2] && isxdigit(cursor[2])) { 00041 // We saw a % followed by 2 hex digits, so we copy the literal hex value into the URL, then advance the cursor past it: 00042 char hex[3]; 00043 hex[0] = cursor[1]; 00044 hex[1] = cursor[2]; 00045 hex[2] = '\0'; 00046 *url++ = (char)strtol(hex, NULL, 16); 00047 cursor += 3; 00048 } else { 00049 // Common case: This is a normal character or a bogus % expression, so just copy it 00050 *url++ = *cursor++; 00051 } 00052 } 00053 00054 *url = '\0'; 00055 }
| void ignoreSigPipeOnSocket | ( | int | socketNum | ) |
Definition at line 331 of file RTSPCommon.cpp.
Referenced by RTSPClient::openConnection(), RTSPServer::registerStream(), RTSPClient::responseHandlerForHTTP_GET1(), and RTSPServer::RTSPServer().
00331 { 00332 #ifdef USE_SIGNALS 00333 #ifdef SO_NOSIGPIPE 00334 int set_option = 1; 00335 setsockopt(socketNum, SOL_SOCKET, SO_NOSIGPIPE, &set_option, sizeof set_option); 00336 #else 00337 signal(SIGPIPE, SIG_IGN); 00338 #endif 00339 #endif 00340 }
| static Boolean isSeparator | ( | char | c | ) | [static] |
| Boolean parseRangeHeader | ( | char const * | buf, | |
| double & | rangeStart, | |||
| double & | rangeEnd, | |||
| char *& | absStartTime, | |||
| char *& | absEndTime | |||
| ) |
Definition at line 257 of file RTSPCommon.cpp.
References _strncasecmp, False, and parseRangeParam().
Referenced by RTSPServer::RTSPClientSession::handleCmd_PLAY(), and RTSPServer::RTSPClientSession::handleCmd_SETUP().
00257 { 00258 // First, find "Range:" 00259 while (1) { 00260 if (*buf == '\0') return False; // not found 00261 if (_strncasecmp(buf, "Range: ", 7) == 0) break; 00262 ++buf; 00263 } 00264 00265 // Then, run through each of the fields, looking for ones we handle: 00266 char const* fields = buf + 7; 00267 while (*fields == ' ') ++fields; 00268 return parseRangeParam(fields, rangeStart, rangeEnd, absStartTime, absEndTime); 00269 }
| Boolean parseRangeParam | ( | char const * | paramStr, | |
| double & | rangeStart, | |||
| double & | rangeEnd, | |||
| char *& | absStartTime, | |||
| char *& | absEndTime | |||
| ) |
Definition at line 209 of file RTSPCommon.cpp.
References False, NULL, Numeric, and True.
Referenced by RTSPClient::handlePLAYResponse(), and parseRangeHeader().
00209 { 00210 delete[] absStartTime; delete[] absEndTime; 00211 absStartTime = absEndTime = NULL; // by default, unless "paramStr" is a "clock=..." string 00212 double start, end; 00213 int numCharsMatched = 0; 00214 Locale l("C", Numeric); 00215 if (sscanf(paramStr, "npt = %lf - %lf", &start, &end) == 2) { 00216 rangeStart = start; 00217 rangeEnd = end; 00218 } else if (sscanf(paramStr, "npt = %lf -", &start) == 1) { 00219 if (start < 0.0) { 00220 // special case for "npt = -<endtime>", which seems to match here: 00221 rangeStart = 0.0; 00222 rangeEnd = -start; 00223 } else { 00224 rangeStart = start; 00225 rangeEnd = 0.0; 00226 } 00227 } else if (strcmp(paramStr, "npt=now-") == 0) { 00228 rangeStart = 0.0; 00229 rangeEnd = 0.0; 00230 } else if (sscanf(paramStr, "clock = %n", &numCharsMatched) == 0 && numCharsMatched > 0) { 00231 rangeStart = rangeEnd = 0.0; 00232 00233 char const* utcTimes = ¶mStr[numCharsMatched]; 00234 size_t len = strlen(utcTimes) + 1; 00235 char* as = new char[len]; 00236 char* ae = new char[len]; 00237 int sscanfResult = sscanf(utcTimes, "%[^-]-%s", as, ae); 00238 if (sscanfResult == 2) { 00239 absStartTime = as; 00240 absEndTime = ae; 00241 } else if (sscanfResult == 1) { 00242 absStartTime = as; 00243 delete[] ae; 00244 } else { 00245 delete[] as; delete[] ae; 00246 return False; 00247 } 00248 } else if (sscanf(paramStr, "smtpe = %n", &numCharsMatched) == 0 && numCharsMatched > 0) { 00249 // We accept "smtpe=" parameters, but currently do not interpret them. 00250 } else { 00251 return False; // The header is malformed 00252 } 00253 00254 return True; 00255 }
| Boolean parseRTSPRequestString | ( | char const * | reqStr, | |
| unsigned | reqStrSize, | |||
| char * | resultCmdName, | |||
| unsigned | resultCmdNameMaxSize, | |||
| char * | resultURLPreSuffix, | |||
| unsigned | resultURLPreSuffixMaxSize, | |||
| char * | resultURLSuffix, | |||
| unsigned | resultURLSuffixMaxSize, | |||
| char * | resultCSeq, | |||
| unsigned | resultCSeqMaxSize, | |||
| char * | resultSessionIdStr, | |||
| unsigned | resultSessionIdStrMaxSize, | |||
| unsigned & | contentLength | |||
| ) |
Definition at line 57 of file RTSPCommon.cpp.
References _strncasecmp, decodeURL(), False, and True.
Referenced by RTSPClient::handleIncomingRequest(), and RTSPServer::RTSPClientConnection::handleRequestBytes().
00069 { 00070 // This parser is currently rather dumb; it should be made smarter ##### 00071 00072 // Read everything up to the first space as the command name: 00073 Boolean parseSucceeded = False; 00074 unsigned i; 00075 for (i = 0; i < resultCmdNameMaxSize-1 && i < reqStrSize; ++i) { 00076 char c = reqStr[i]; 00077 if (c == ' ' || c == '\t') { 00078 parseSucceeded = True; 00079 break; 00080 } 00081 00082 resultCmdName[i] = c; 00083 } 00084 resultCmdName[i] = '\0'; 00085 if (!parseSucceeded) return False; 00086 00087 // Skip over the prefix of any "rtsp://" or "rtsp:/" URL that follows: 00088 unsigned j = i+1; 00089 while (j < reqStrSize && (reqStr[j] == ' ' || reqStr[j] == '\t')) ++j; // skip over any additional white space 00090 for (; (int)j < (int)(reqStrSize-8); ++j) { 00091 if ((reqStr[j] == 'r' || reqStr[j] == 'R') 00092 && (reqStr[j+1] == 't' || reqStr[j+1] == 'T') 00093 && (reqStr[j+2] == 's' || reqStr[j+2] == 'S') 00094 && (reqStr[j+3] == 'p' || reqStr[j+3] == 'P') 00095 && reqStr[j+4] == ':' && reqStr[j+5] == '/') { 00096 j += 6; 00097 if (reqStr[j] == '/') { 00098 // This is a "rtsp://" URL; skip over the host:port part that follows: 00099 ++j; 00100 while (j < reqStrSize && reqStr[j] != '/' && reqStr[j] != ' ') ++j; 00101 } else { 00102 // This is a "rtsp:/" URL; back up to the "/": 00103 --j; 00104 } 00105 i = j; 00106 break; 00107 } 00108 } 00109 00110 // Look for the URL suffix (before the following "RTSP/"): 00111 parseSucceeded = False; 00112 for (unsigned k = i+1; (int)k < (int)(reqStrSize-5); ++k) { 00113 if (reqStr[k] == 'R' && reqStr[k+1] == 'T' && 00114 reqStr[k+2] == 'S' && reqStr[k+3] == 'P' && reqStr[k+4] == '/') { 00115 while (--k >= i && reqStr[k] == ' ') {} // go back over all spaces before "RTSP/" 00116 unsigned k1 = k; 00117 while (k1 > i && reqStr[k1] != '/') --k1; 00118 00119 // ASSERT: At this point 00120 // i: first space or slash after "host" or "host:port" 00121 // k: last non-space before "RTSP/" 00122 // k1: last slash in the range [i,k] 00123 00124 // The URL suffix comes from [k1+1,k] 00125 // Copy "resultURLSuffix": 00126 unsigned n = 0, k2 = k1+1; 00127 if (i <= k) { // There's a slash after "host" or "host:port" 00128 if (k - k1 + 1 > resultURLSuffixMaxSize) return False; // there's no room 00129 while (k2 <= k) resultURLSuffix[n++] = reqStr[k2++]; 00130 } 00131 resultURLSuffix[n] = '\0'; 00132 00133 // The URL 'pre-suffix' comes from [i+1,k1-1] 00134 // Copy "resultURLPreSuffix": 00135 n = 0; k2 = i + 1; 00136 if (i <= k) { // There's a slash after "host" or "host:port" 00137 if (k1 - i > resultURLPreSuffixMaxSize) return False; // there's no room 00138 while (k2 <= k1 - 1) resultURLPreSuffix[n++] = reqStr[k2++]; 00139 } 00140 resultURLPreSuffix[n] = '\0'; 00141 decodeURL(resultURLPreSuffix); 00142 00143 i = k + 7; // to go past " RTSP/" 00144 parseSucceeded = True; 00145 break; 00146 } 00147 } 00148 if (!parseSucceeded) return False; 00149 00150 // Look for "CSeq:" (mandatory, case insensitive), skip whitespace, 00151 // then read everything up to the next \r or \n as 'CSeq': 00152 parseSucceeded = False; 00153 for (j = i; (int)j < (int)(reqStrSize-5); ++j) { 00154 if (_strncasecmp("CSeq:", &reqStr[j], 5) == 0) { 00155 j += 5; 00156 while (j < reqStrSize && (reqStr[j] == ' ' || reqStr[j] == '\t')) ++j; 00157 unsigned n; 00158 for (n = 0; n < resultCSeqMaxSize-1 && j < reqStrSize; ++n,++j) { 00159 char c = reqStr[j]; 00160 if (c == '\r' || c == '\n') { 00161 parseSucceeded = True; 00162 break; 00163 } 00164 00165 resultCSeq[n] = c; 00166 } 00167 resultCSeq[n] = '\0'; 00168 break; 00169 } 00170 } 00171 if (!parseSucceeded) return False; 00172 00173 // Look for "Session:" (optional, case insensitive), skip whitespace, 00174 // then read everything up to the next \r or \n as 'Session': 00175 resultSessionIdStr[0] = '\0'; // default value (empty string) 00176 for (j = i; (int)j < (int)(reqStrSize-8); ++j) { 00177 if (_strncasecmp("Session:", &reqStr[j], 8) == 0) { 00178 j += 8; 00179 while (j < reqStrSize && (reqStr[j] == ' ' || reqStr[j] == '\t')) ++j; 00180 unsigned n; 00181 for (n = 0; n < resultSessionIdStrMaxSize-1 && j < reqStrSize; ++n,++j) { 00182 char c = reqStr[j]; 00183 if (c == '\r' || c == '\n') { 00184 break; 00185 } 00186 00187 resultSessionIdStr[n] = c; 00188 } 00189 resultSessionIdStr[n] = '\0'; 00190 break; 00191 } 00192 } 00193 00194 // Also: Look for "Content-Length:" (optional, case insensitive) 00195 contentLength = 0; // default value 00196 for (j = i; (int)j < (int)(reqStrSize-15); ++j) { 00197 if (_strncasecmp("Content-Length:", &(reqStr[j]), 15) == 0) { 00198 j += 15; 00199 while (j < reqStrSize && (reqStr[j] == ' ' || reqStr[j] == '\t')) ++j; 00200 unsigned num; 00201 if (sscanf(&reqStr[j], "%u", &num) == 1) { 00202 contentLength = num; 00203 } 00204 } 00205 } 00206 return True; 00207 }
| Boolean RTSPOptionIsSupported | ( | char const * | commandName, | |
| char const * | optionsResponseString | |||
| ) |
Definition at line 274 of file RTSPCommon.cpp.
References False, isSeparator(), NULL, and True.
Referenced by continueAfterOPTIONS().
00274 { 00275 do { 00276 if (commandName == NULL || optionsResponseString == NULL) break; 00277 00278 unsigned const commandNameLen = strlen(commandName); 00279 if (commandNameLen == 0) break; 00280 00281 // "optionsResponseString" is assumed to be a list of command names, separated by " " and/or ",", ";", or ":" 00282 // Scan through these, looking for "commandName". 00283 while (1) { 00284 // Skip over separators: 00285 while (*optionsResponseString != '\0' && isSeparator(*optionsResponseString)) ++optionsResponseString; 00286 if (*optionsResponseString == '\0') break; 00287 00288 // At this point, "optionsResponseString" begins with a command name (with perhaps a separator afterwads). 00289 if (strncmp(commandName, optionsResponseString, commandNameLen) == 0) { 00290 // We have at least a partial match here. 00291 optionsResponseString += commandNameLen; 00292 if (*optionsResponseString == '\0' || isSeparator(*optionsResponseString)) return True; 00293 } 00294 00295 // No match. Skip over the rest of the command name: 00296 while (*optionsResponseString != '\0' && !isSeparator(*optionsResponseString)) ++optionsResponseString; 00297 } 00298 } while (0); 00299 00300 return False; 00301 }
1.5.2