liveMedia/RTSPCommon.cpp File Reference

#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 Documentation

#define USE_SIGNALS   1

Definition at line 31 of file RTSPCommon.cpp.


Function Documentation

char const* dateHeader (  ) 

Definition at line 303 of file RTSPCommon.cpp.

References DWORD, and NULL.

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]

Definition at line 272 of file RTSPCommon.cpp.

Referenced by RTSPOptionIsSupported().

00272 { return c == ' ' || c == ',' || c == ';' || c == ':'; }

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 = &paramStr[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 }


Generated on Thu May 30 08:15:28 2013 for live by  doxygen 1.5.2