LCOV - code coverage report
Current view: top level - ietf - rtsp_common.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 107 198 54.0 %
Date: 2021-04-29 23:48:07 Functions: 7 7 100.0 %

          Line data    Source code
       1             : /*
       2             :  *                      GPAC - Multimedia Framework C SDK
       3             :  *
       4             :  *                      Authors: Jean Le Feuvre
       5             :  *                      Copyright (c) Telecom ParisTech 2000-2012
       6             :  *                                      All rights reserved
       7             :  *
       8             :  *  This file is part of GPAC / IETF RTP/RTSP/SDP sub-project
       9             :  *
      10             :  *  GPAC is free software; you can redistribute it and/or modify
      11             :  *  it under the terms of the GNU Lesser General Public License as published by
      12             :  *  the Free Software Foundation; either version 2, or (at your option)
      13             :  *  any later version.
      14             :  *
      15             :  *  GPAC is distributed in the hope that it will be useful,
      16             :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
      17             :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      18             :  *  GNU Lesser General Public License for more details.
      19             :  *
      20             :  *  You should have received a copy of the GNU Lesser General Public
      21             :  *  License along with this library; see the file COPYING.  If not, write to
      22             :  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
      23             :  *
      24             :  */
      25             : 
      26             : #include <gpac/internal/ietf_dev.h>
      27             : 
      28             : #ifndef GPAC_DISABLE_STREAMING
      29             : 
      30             : #include <gpac/token.h>
      31             : 
      32             : 
      33          56 : GF_Err gf_rtsp_read_reply(GF_RTSPSession *sess)
      34             : {
      35             :         GF_Err e;
      36          56 :         u32 res, body_size = 0;
      37          56 :         u32 BodyStart = 0;
      38             : 
      39             :         //fetch more data on the socket if needed
      40             :         while (1) {
      41             :                 //Locate header / body
      42          56 :                 if (!BodyStart) gf_rtsp_get_body_info(sess, &BodyStart, &body_size);
      43             : 
      44          56 :                 if (BodyStart) {
      45             :                         //enough data
      46          56 :                         res = sess->CurrentSize - sess->CurrentPos;
      47          56 :                         if (!body_size || (res >= body_size + BodyStart)) {
      48             :                                 //done
      49             :                                 break;
      50             :                         }
      51             :                 }
      52             :                 //this is the tricky part: if we do NOT have a body start -> we refill
      53           0 :                 e = gf_rtsp_refill_buffer(sess);
      54           0 :                 if (e) return e;
      55             :         }
      56             :         return GF_OK;
      57             : }
      58             : 
      59         112 : void gf_rtsp_get_body_info(GF_RTSPSession *sess, u32 *body_start, u32 *body_size)
      60             : {
      61             :         u32 i;
      62             :         s32 start;
      63             :         char *buffer;
      64             :         char *cl_str;
      65             : 
      66         112 :         *body_start = *body_size = 0;
      67             : 
      68         112 :         buffer = sess->tcp_buffer + sess->CurrentPos;
      69         112 :         start = gf_token_find(buffer, 0, sess->CurrentSize - sess->CurrentPos, "\r\n\r\n");
      70         112 :         if (start<=0) {
      71             :                 return;
      72             :         }
      73             : 
      74             :         //if found add the 2 "\r\n" and parse it
      75         112 :         *body_start = start + 4;
      76             : 
      77             :         //get the content length
      78         112 :         cl_str = strstr(buffer, "Content-Length: ");
      79         112 :         if (!cl_str) cl_str = strstr(buffer, "Content-length: ");
      80             : 
      81         112 :         if (cl_str) {
      82             :                 char val[30];
      83          10 :                 cl_str += 16;
      84             :                 i = 0;
      85          50 :                 while (cl_str[i] != '\r') {
      86          30 :                         val[i] = cl_str[i];
      87          30 :                         i += 1;
      88             :                 }
      89          10 :                 val[i] = 0;
      90          10 :                 *body_size = atoi(val);
      91             :         } else {
      92         102 :                 *body_size = 0;
      93             :         }
      94             : }
      95             : 
      96             : 
      97           1 : GF_Err gf_rtsp_refill_buffer(GF_RTSPSession *sess)
      98             : {
      99             :         GF_Err e;
     100             :         u32 res;
     101             :         char *ptr;
     102             : 
     103           1 :         if (!sess) return GF_BAD_PARAM;
     104           1 :         if (!sess->connection) return GF_IP_NETWORK_EMPTY;
     105             : 
     106           1 :         res = sess->CurrentSize - sess->CurrentPos;
     107           1 :         if (!res) return gf_rtsp_fill_buffer(sess);
     108             : 
     109           1 :         ptr = (char *)gf_malloc(sizeof(char) * res);
     110           1 :         memcpy(ptr, sess->tcp_buffer + sess->CurrentPos, res);
     111           1 :         memcpy(sess->tcp_buffer, ptr, res);
     112           1 :         gf_free(ptr);
     113             : 
     114           1 :         sess->CurrentPos = 0;
     115           1 :         sess->CurrentSize = res;
     116             : 
     117             :         //now read from current pos
     118           1 :         e = gf_sk_receive(sess->connection, sess->tcp_buffer + sess->CurrentSize, sess->SockBufferSize - sess->CurrentSize, &res);
     119             : 
     120           1 :         if (!e) {
     121           1 :                 sess->CurrentSize += res;
     122             :         }
     123             :         return e;
     124             : }
     125             : 
     126             : 
     127        2862 : GF_Err gf_rtsp_fill_buffer(GF_RTSPSession *sess)
     128             : {
     129             :         GF_Err e = GF_OK;
     130             : 
     131        2862 :         if (!sess->connection) return GF_IP_NETWORK_EMPTY;
     132             : 
     133        2837 :         if (sess->CurrentSize == sess->CurrentPos) {
     134        2835 :                 e = gf_sk_receive(sess->connection, sess->tcp_buffer, sess->SockBufferSize, &sess->CurrentSize);
     135        2835 :                 sess->CurrentPos = 0;
     136        2835 :                 sess->tcp_buffer[sess->CurrentSize] = 0;
     137        2835 :                 if (e) sess->CurrentSize = 0;
     138           2 :         } else if (!sess->CurrentSize) e = GF_IP_NETWORK_EMPTY;
     139             :         return e;
     140             : }
     141             : 
     142             : 
     143          12 : GF_RTSPTransport *gf_rtsp_transport_parse(u8 *buffer)
     144             : {
     145             :         Bool IsFirst;
     146             :         char buf[100], param_name[100], param_val[100];
     147             :         s32 pos, nPos;
     148             :         u32 v1, v2;
     149             :         GF_RTSPTransport *tmp;
     150          12 :         if (!buffer) return NULL;
     151             :         //only support for RTP/AVP for now
     152          12 :         if (strnicmp(buffer, "RTP/AVP", 7) && strnicmp(buffer, "RTP/SAVP", 8)) return NULL;
     153             : 
     154          12 :         GF_SAFEALLOC(tmp, GF_RTSPTransport);
     155          12 :         if (!tmp) return NULL;
     156             : 
     157             :         IsFirst = GF_TRUE;
     158             :         pos = 0;
     159             :         while (1) {
     160          69 :                 pos = gf_token_get(buffer, pos, " ;", buf, 100);
     161          69 :                 if (pos <= 0) break;
     162          57 :                 if (strstr(buf, "=")) {
     163          33 :                         nPos = gf_token_get(buf, 0, "=", param_name, 100);
     164          33 :                         /*nPos = */gf_token_get(buf, nPos, "=", param_val, 100);
     165             :                 } else {
     166             :                         strcpy(param_name, buf);
     167             :                 }
     168             : 
     169             :                 //very first param is the profile
     170          57 :                 if (IsFirst) {
     171          12 :                         tmp->Profile = gf_strdup(param_name);
     172             :                         IsFirst = GF_FALSE;
     173          12 :                         continue;
     174             :                 }
     175             : 
     176          45 :                 if (!stricmp(param_name, "destination")) {
     177           2 :                         if (tmp->destination) gf_free(tmp->destination);
     178           2 :                         tmp->destination = gf_strdup(param_val);
     179             :                 }
     180          43 :                 else if (!stricmp(param_name, "source")) {
     181           6 :                         if (tmp->source) gf_free(tmp->source);
     182           6 :                         tmp->source = gf_strdup(param_val);
     183             :                 }
     184          37 :                 else if (!stricmp(param_name, "unicast")) tmp->IsUnicast = GF_TRUE;
     185          27 :                 else if (!stricmp(param_name, "RECORD")) tmp->IsRecord = GF_TRUE;
     186          27 :                 else if (!stricmp(param_name, "append")) tmp->Append = GF_TRUE;
     187          27 :                 else if (!stricmp(param_name, "interleaved")) {
     188             :                         u32 rID, rcID;
     189           2 :                         tmp->IsInterleaved = GF_TRUE;
     190           2 :                         if (sscanf(param_val, "%u-%u", &rID, &rcID) == 1) {
     191           0 :                                 sscanf(param_val, "%u", &rID);
     192           0 :                                 tmp->rtcpID = tmp->rtpID = (u8) rID;
     193             :                         } else {
     194           2 :                                 tmp->rtpID = (u8) rID;
     195           2 :                                 tmp->rtcpID = (u8) rcID;
     196             :                         }
     197             :                 }
     198          25 :                 else if (!stricmp(param_name, "layers")) sscanf(param_val, "%u", &tmp->MulticastLayers);
     199          25 :                 else if (!stricmp(param_name, "ttl")) sscanf(param_val, "%c      ", &tmp->TTL);
     200          23 :                 else if (!stricmp(param_name, "port")) {
     201           2 :                         sscanf(param_val, "%u-%u", &v1, &v2);
     202           2 :                         tmp->port_first = (u16) v1;
     203           2 :                         tmp->port_last = (u16) v2;
     204             :                 }
     205             :                 /*do not use %hud here, broken on Win32 (sscanf returns 1)*/
     206          21 :                 else if (!stricmp(param_name, "server_port")) {
     207           4 :                         sscanf(param_val, "%d-%d", &v1, &v2);
     208           4 :                         tmp->port_first = (u16) v1;
     209           4 :                         tmp->port_last = (u16) v2;
     210             :                 }
     211             :                 /*do not use %hud here, broken on Win32 (sscanf returns 1)*/
     212          17 :                 else if (!stricmp(param_name, "client_port")) {
     213           9 :                         sscanf(param_val, "%d-%d", &v1, &v2);
     214           9 :                         tmp->client_port_first = (u16) v1;
     215           9 :                         tmp->client_port_last = (u16) v2;
     216             :                 }
     217           8 :                 else if (!stricmp(param_name, "ssrc")) sscanf(param_val, "%X", &tmp->SSRC);
     218             :         }
     219             :         return tmp;
     220             : }
     221             : 
     222             : 
     223             : 
     224          56 : GF_Err gf_rtsp_parse_header(u8 *buffer, u32 BufferSize, u32 BodyStart, GF_RTSPCommand *com, GF_RTSPResponse *rsp)
     225             : {
     226             :         char LineBuffer[1024];
     227             :         char HeaderBuf[100], ValBuf[1024], temp[400];
     228             :         s32 Pos, LinePos;
     229             :         u32 HeaderLine;
     230             : 
     231             :         //then parse the full header
     232             :         LinePos = 0;
     233             :         strcpy(HeaderBuf, "");
     234             :         while (1) {
     235         307 :                 LinePos = gf_token_get_line(buffer, LinePos, BufferSize, LineBuffer, 1024);
     236         307 :                 if (LinePos <= 0) return GF_REMOTE_SERVICE_ERROR;
     237             : 
     238             :                 //extract field header and value. Warning: some params (transport, ..) may be on several lines
     239         307 :                 Pos = gf_token_get(LineBuffer, 0, ":\r\n", temp, 400);
     240             : 
     241             :                 //end of header
     242         307 :                 if (Pos <= 0) {
     243             :                         HeaderLine = 2;
     244             :                 }
     245             :                 //this is a header
     246         251 :                 else if (LineBuffer[0] != ' ') {
     247             :                         HeaderLine = 1;
     248             :                 } else {
     249           0 :                         Pos = gf_token_get(LineBuffer, 0, ", \r\n", temp, 400);
     250             :                         //end of header - process any pending one
     251           0 :                         if (Pos <= 0) {
     252             :                                 HeaderLine = 2;
     253             :                         } else {
     254             :                                 //n-line value - append
     255             :                                 strcat(ValBuf, "\r\n");
     256             :                                 strcat(ValBuf, temp);
     257           0 :                                 continue;
     258             :                         }
     259             :                 }
     260             :                 //process current value
     261         307 :                 if (HeaderLine && strlen(HeaderBuf)) {
     262         251 :                         if (rsp) {
     263         126 :                                 gf_rtsp_set_response_value(rsp, HeaderBuf, ValBuf);
     264             :                         }
     265             :                         else {
     266         125 :                                 gf_rtsp_set_command_value(com, HeaderBuf, ValBuf);
     267             :                         }
     268             :                 }
     269             :                 //done with the header
     270         307 :                 if ( (HeaderLine == 2) || ((u32) LinePos >= BodyStart) ) return GF_OK;
     271             : 
     272             :                 //process current line
     273             :                 strcpy(HeaderBuf, temp);
     274             : 
     275             :                 //skip ':'
     276         251 :                 Pos += 1;
     277             :                 //a server should normally reply with a space, but check it
     278         251 :                 if (LineBuffer[Pos] == ' ') Pos += 1;
     279             :                 /*!! empty value !! - DSS may send these for CSeq if something goes wrong*/
     280         251 :                 if (!strcmp(LineBuffer+Pos, "\r\n")) {
     281           0 :                         HeaderBuf[0] = 0;
     282           0 :                         continue;
     283             :                 }
     284         251 :                 Pos = gf_token_get(LineBuffer, Pos, "\r\n", ValBuf, 400);
     285         251 :                 if (Pos <= 0) break;
     286             : 
     287             :         }
     288             :         //if we get here we haven't reached the BodyStart
     289             :         return GF_REMOTE_SERVICE_ERROR;
     290             : }
     291             : 
     292             : 
     293             : GF_EXPORT
     294         112 : const char *gf_rtsp_nc_to_string(u32 ErrCode)
     295             : {
     296         112 :         switch (ErrCode) {
     297             :         case NC_RTSP_Continue:
     298             :                 return "Continue";
     299         112 :         case NC_RTSP_OK:
     300         112 :                 return "OK";
     301           0 :         case NC_RTSP_Created:
     302           0 :                 return "Created";
     303           0 :         case NC_RTSP_Low_on_Storage_Space:
     304           0 :                 return "Low on Storage Space";
     305           0 :         case NC_RTSP_Multiple_Choice:
     306           0 :                 return "Multiple Choice";
     307           0 :         case NC_RTSP_Moved_Permanently:
     308           0 :                 return "Moved Permanently";
     309           0 :         case NC_RTSP_Moved_Temporarily:
     310           0 :                 return "Moved Temporarily";
     311           0 :         case NC_RTSP_See_Other:
     312           0 :                 return "See Other";
     313           0 :         case NC_RTSP_Use_Proxy:
     314           0 :                 return "Use Proxy";
     315           0 :         case NC_RTSP_Bad_Request:
     316           0 :                 return "Bad Request";
     317           0 :         case NC_RTSP_Unauthorized:
     318           0 :                 return "Unauthorized";
     319           0 :         case NC_RTSP_Payment_Required:
     320           0 :                 return "Payment Required";
     321           0 :         case NC_RTSP_Forbidden:
     322           0 :                 return "Forbidden";
     323           0 :         case NC_RTSP_Not_Found:
     324           0 :                 return "Not Found";
     325           0 :         case NC_RTSP_Method_Not_Allowed:
     326           0 :                 return "Method Not Allowed";
     327           0 :         case NC_RTSP_Not_Acceptable:
     328           0 :                 return "Not Acceptable";
     329           0 :         case NC_RTSP_Proxy_Authentication_Required:
     330           0 :                 return "Proxy Authentication Required";
     331           0 :         case NC_RTSP_Request_Timeout:
     332           0 :                 return "Request Timeout";
     333           0 :         case NC_RTSP_Gone:
     334           0 :                 return "Gone";
     335           0 :         case NC_RTSP_Length_Required:
     336           0 :                 return "Length Required";
     337           0 :         case NC_RTSP_Precondition_Failed:
     338           0 :                 return "Precondition Failed";
     339           0 :         case NC_RTSP_Request_Entity_Too_Large:
     340           0 :                 return "Request Entity Too Large";
     341           0 :         case NC_RTSP_Request_URI_Too_Long:
     342           0 :                 return "Request URI Too Long";
     343           0 :         case NC_RTSP_Unsupported_Media_Type:
     344           0 :                 return "Unsupported Media Type";
     345           0 :         case NC_RTSP_Invalid_parameter:
     346           0 :                 return "Invalid parameter";
     347           0 :         case NC_RTSP_Illegal_Conference_Identifier:
     348           0 :                 return "Illegal Conference Identifier";
     349           0 :         case NC_RTSP_Not_Enough_Bandwidth:
     350           0 :                 return "Not Enough Bandwidth";
     351           0 :         case NC_RTSP_Session_Not_Found:
     352           0 :                 return "Session Not Found";
     353           0 :         case NC_RTSP_Method_Not_Valid_In_This_State:
     354           0 :                 return "Method Not Valid In This State";
     355           0 :         case NC_RTSP_Header_Field_Not_Valid:
     356           0 :                 return "Header Field Not Valid";
     357           0 :         case NC_RTSP_Invalid_Range:
     358           0 :                 return "Invalid Range";
     359           0 :         case NC_RTSP_Parameter_Is_ReadOnly:
     360           0 :                 return "Parameter Is Read-Only";
     361           0 :         case NC_RTSP_Aggregate_Operation_Not_Allowed:
     362           0 :                 return "Aggregate Operation Not Allowed";
     363           0 :         case NC_RTSP_Only_Aggregate_Operation_Allowed:
     364           0 :                 return "Only Aggregate Operation Allowed";
     365           0 :         case NC_RTSP_Unsupported_Transport:
     366           0 :                 return "Unsupported Transport";
     367           0 :         case NC_RTSP_Destination_Unreachable:
     368           0 :                 return "Destination Unreachable";
     369           0 :         case NC_RTSP_Internal_Server_Error:
     370           0 :                 return "Internal Server Error";
     371           0 :         case NC_RTSP_Bad_Gateway:
     372           0 :                 return "Bad Gateway";
     373           0 :         case NC_RTSP_Service_Unavailable:
     374           0 :                 return "Service Unavailable";
     375           0 :         case NC_RTSP_Gateway_Timeout:
     376           0 :                 return "Gateway Timeout";
     377           0 :         case NC_RTSP_RTSP_Version_Not_Supported:
     378           0 :                 return "RTSP Version Not Supported";
     379           0 :         case NC_RTSP_Option_not_support:
     380           0 :                 return "Option not support";
     381             : 
     382           0 :         case NC_RTSP_Not_Implemented:
     383             :         default:
     384           0 :                 return "Not Implemented";
     385             :         }
     386             : }
     387             : 
     388             : #endif /*GPAC_DISABLE_STREAMING*/

Generated by: LCOV version 1.13