LCOV - code coverage report
Current view: top level - ietf - rtsp_response.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 330 396 83.3 %
Date: 2021-04-29 23:48:07 Functions: 14 14 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             : GF_EXPORT
      34          32 : GF_RTSPResponse *gf_rtsp_response_new()
      35             : {
      36             :         GF_RTSPResponse *tmp;
      37          32 :         GF_SAFEALLOC(tmp, GF_RTSPResponse);
      38          32 :         if (!tmp) return NULL;
      39          32 :         tmp->Transports = gf_list_new();
      40          32 :         tmp->RTP_Infos = gf_list_new();
      41          32 :         tmp->Xtensions = gf_list_new();
      42          32 :         return tmp;
      43             : }
      44             : 
      45             : 
      46             : #define RSP_FREE_CLEAN(hdr)             if (rsp->hdr) gf_free(rsp->hdr);  \
      47             :                                                                 rsp->hdr = NULL;
      48             : 
      49             : GF_EXPORT
      50        2067 : void gf_rtsp_response_reset(GF_RTSPResponse *rsp)
      51             : {
      52        2067 :         if (!rsp) return;
      53             : 
      54             :         //free all headers
      55        2067 :         RSP_FREE_CLEAN(Accept);
      56        2067 :         RSP_FREE_CLEAN(Accept_Encoding);
      57        2067 :         RSP_FREE_CLEAN(Accept_Language);
      58        2067 :         RSP_FREE_CLEAN(Allow);
      59        2067 :         RSP_FREE_CLEAN(Authorization);
      60        2067 :         RSP_FREE_CLEAN(Cache_Control);
      61        2067 :         RSP_FREE_CLEAN(Conference);
      62        2067 :         RSP_FREE_CLEAN(Connection);
      63        2067 :         RSP_FREE_CLEAN(Content_Base);
      64        2067 :         RSP_FREE_CLEAN(Content_Encoding);
      65        2067 :         RSP_FREE_CLEAN(Content_Language);
      66        2067 :         RSP_FREE_CLEAN(Content_Location);
      67        2067 :         RSP_FREE_CLEAN(Content_Type);
      68        2067 :         RSP_FREE_CLEAN(Date);
      69        2067 :         RSP_FREE_CLEAN(Expires);
      70        2067 :         RSP_FREE_CLEAN(From);
      71        2067 :         RSP_FREE_CLEAN(Host);
      72        2067 :         RSP_FREE_CLEAN(If_Match);
      73        2067 :         RSP_FREE_CLEAN(If_Modified_Since);
      74        2067 :         RSP_FREE_CLEAN(Last_Modified);
      75        2067 :         RSP_FREE_CLEAN(Location);
      76        2067 :         RSP_FREE_CLEAN(Proxy_Authenticate);
      77        2067 :         RSP_FREE_CLEAN(Proxy_Require);
      78        2067 :         RSP_FREE_CLEAN(Public);
      79        2067 :         RSP_FREE_CLEAN(Referer);
      80        2067 :         RSP_FREE_CLEAN(Require);
      81        2067 :         RSP_FREE_CLEAN(Retry_After);
      82        2067 :         RSP_FREE_CLEAN(Server);
      83        2067 :         RSP_FREE_CLEAN(Session);
      84        2067 :         RSP_FREE_CLEAN(Timestamp);
      85        2067 :         RSP_FREE_CLEAN(Unsupported);
      86        2067 :         RSP_FREE_CLEAN(User_Agent);
      87        2067 :         RSP_FREE_CLEAN(Vary);
      88        2067 :         RSP_FREE_CLEAN(Via);
      89        2067 :         RSP_FREE_CLEAN(WWW_Authenticate);
      90             : 
      91             :         //this is for us
      92        2067 :         RSP_FREE_CLEAN(ResponseInfo);
      93        2067 :         RSP_FREE_CLEAN(body);
      94             : 
      95        2067 :         rsp->Bandwidth = rsp->Blocksize = rsp->ResponseCode = rsp->Content_Length = rsp->CSeq = 0;
      96        2067 :         rsp->Scale = rsp->Speed = 0.0;
      97        2067 :         if (rsp->Range) gf_free(rsp->Range);
      98        2067 :         rsp->Range = NULL;
      99             : 
     100        2067 :         rsp->SessionTimeOut = 0;
     101             : 
     102        4140 :         while (gf_list_count(rsp->Transports)) {
     103           6 :                 GF_RTSPTransport *trans = (GF_RTSPTransport*) gf_list_get(rsp->Transports, 0);
     104           6 :                 gf_list_rem(rsp->Transports, 0);
     105           6 :                 gf_rtsp_transport_del(trans);
     106             :         }
     107             : 
     108        2073 :         while (gf_list_count(rsp->RTP_Infos)) {
     109           6 :                 GF_RTPInfo *inf = (GF_RTPInfo*) gf_list_get(rsp->RTP_Infos, 0);
     110           6 :                 gf_list_rem(rsp->RTP_Infos, 0);
     111           6 :                 if (inf->url) gf_free(inf->url);
     112           6 :                 gf_free(inf);
     113             :         }
     114        2067 :         while (gf_list_count(rsp->Xtensions)) {
     115           0 :                 GF_X_Attribute *att = (GF_X_Attribute*)gf_list_get(rsp->Xtensions, 0);
     116           0 :                 gf_list_rem(rsp->Xtensions, 0);
     117           0 :                 gf_free(att->Name);
     118           0 :                 gf_free(att->Value);
     119           0 :                 gf_free(att);
     120             :         }
     121             : }
     122             : 
     123             : GF_EXPORT
     124          32 : void gf_rtsp_response_del(GF_RTSPResponse *rsp)
     125             : {
     126          32 :         if (!rsp) return;
     127             : 
     128          32 :         gf_rtsp_response_reset(rsp);
     129          32 :         gf_list_del(rsp->RTP_Infos);
     130          32 :         gf_list_del(rsp->Xtensions);
     131          32 :         gf_list_del(rsp->Transports);
     132          32 :         gf_free(rsp);
     133             : }
     134             : 
     135             : 
     136             : 
     137             : GF_EXPORT
     138          23 : GF_RTSPRange *gf_rtsp_range_parse(char *range_buf)
     139             : {
     140             :         GF_RTSPRange *rg;
     141             : 
     142          23 :         if (!strstr(range_buf, "npt")) return NULL;
     143             : 
     144          23 :         GF_SAFEALLOC(rg, GF_RTSPRange);
     145          23 :         if (!rg) return NULL;
     146          23 :         if (sscanf(range_buf, "npt=%lf-%lf", &rg->start, &rg->end) != 2) {
     147          18 :                 rg->end = -1.0;
     148          18 :                 sscanf(range_buf, "npt=%lf-", &rg->start);
     149             :         }
     150             :         return rg;
     151             : }
     152             : 
     153             : GF_EXPORT
     154          18 : void gf_rtsp_transport_del(GF_RTSPTransport *transp)
     155             : {
     156          18 :         if (!transp) return;
     157          18 :         if (transp->destination) gf_free(transp->destination);
     158          18 :         if (transp->Profile) gf_free(transp->Profile);
     159          18 :         if (transp->source) gf_free(transp->source);
     160          18 :         gf_free(transp);
     161             : }
     162             : 
     163             : GF_EXPORT
     164           6 : GF_RTSPTransport *gf_rtsp_transport_clone(GF_RTSPTransport *original)
     165             : {
     166             :         GF_RTSPTransport *tr;
     167             : 
     168           6 :         if (!original) return NULL;
     169             : 
     170           6 :         tr = (GF_RTSPTransport*) gf_malloc(sizeof(GF_RTSPTransport));
     171             :         memcpy(tr, original, sizeof(GF_RTSPTransport));
     172           6 :         tr->destination = tr->source = tr->Profile = NULL;
     173           6 :         if (original->destination) tr->destination = gf_strdup(original->destination);
     174           6 :         if (original->source) tr->source = gf_strdup(original->source);
     175           6 :         if (original->Profile) tr->Profile = gf_strdup(original->Profile);
     176             :         return tr;
     177             : }
     178             : 
     179             : GF_EXPORT
     180          12 : GF_RTSPRange *gf_rtsp_range_new()
     181             : {
     182             :         GF_RTSPRange *tmp;
     183          12 :         GF_SAFEALLOC(tmp, GF_RTSPRange);
     184          12 :         return tmp;
     185             : }
     186             : 
     187             : GF_EXPORT
     188           5 : void gf_rtsp_range_del(GF_RTSPRange *range)
     189             : {
     190           5 :         if (!range) return;
     191           5 :         gf_free(range);
     192             : }
     193             : 
     194         126 : void gf_rtsp_set_response_value(GF_RTSPResponse *rsp, char *Header, char *Value)
     195             : {
     196             :         char LineBuffer[400], buf[1000], param_name[100], param_val[1000];
     197             :         s32 LinePos, Pos, nPos, s_val;
     198             :         GF_RTPInfo *info;
     199             :         GF_RTSPTransport *trans;
     200             :         GF_X_Attribute *x_Att;
     201             : 
     202         126 :         if (!stricmp(Header, "Accept")) rsp->Accept = gf_strdup(Value);
     203         126 :         else if (!stricmp(Header, "Accept-Encoding")) rsp->Accept_Encoding = gf_strdup(Value);
     204         126 :         else if (!stricmp(Header, "Accept-Language")) rsp->Accept_Language = gf_strdup(Value);
     205         126 :         else if (!stricmp(Header, "Allow")) rsp->Allow = gf_strdup(Value);
     206         126 :         else if (!stricmp(Header, "Authorization")) rsp->Authorization = gf_strdup(Value);
     207         126 :         else if (!stricmp(Header, "Bandwidth")) sscanf(Value, "%u", &rsp->Bandwidth);
     208         126 :         else if (!stricmp(Header, "Blocksize")) sscanf(Value, "%u", &rsp->Blocksize);
     209         126 :         else if (!stricmp(Header, "Cache-Control")) rsp->Cache_Control = gf_strdup(Value);
     210         126 :         else if (!stricmp(Header, "com.ses.streamID")) sscanf(Value, "%u", &rsp->StreamID);
     211         126 :         else if (!stricmp(Header, "Conference")) rsp->Conference = gf_strdup(Value);
     212         126 :         else if (!stricmp(Header, "Connection")) rsp->Connection = gf_strdup(Value);
     213         102 :         else if (!stricmp(Header, "Content-Base")) rsp->Content_Base = gf_strdup(Value);
     214         102 :         else if (!stricmp(Header, "Content-Encoding")) rsp->Content_Encoding = gf_strdup(Value);
     215         102 :         else if (!stricmp(Header, "Content-Length")) sscanf(Value, "%u", &rsp->Content_Length);
     216          97 :         else if (!stricmp(Header, "Content-Language")) rsp->Content_Language = gf_strdup(Value);
     217          97 :         else if (!stricmp(Header, "Content-Location")) rsp->Content_Location = gf_strdup(Value);
     218          97 :         else if (!stricmp(Header, "Content-Type")) rsp->Content_Type = gf_strdup(Value);
     219          97 :         else if (!stricmp(Header, "CSeq")) sscanf(Value, "%u", &rsp->CSeq);
     220          69 :         else if (!stricmp(Header, "Date")) rsp->Date = gf_strdup(Value);
     221          69 :         else if (!stricmp(Header, "Expires")) rsp->Expires = gf_strdup(Value);
     222          69 :         else if (!stricmp(Header, "From")) rsp->From = gf_strdup(Value);
     223          69 :         else if (!stricmp(Header, "Host")) rsp->Host = gf_strdup(Value);
     224          69 :         else if (!stricmp(Header, "If-Match")) rsp->If_Match = gf_strdup(Value);
     225          69 :         else if (!stricmp(Header, "If-Modified-Since")) rsp->If_Modified_Since = gf_strdup(Value);
     226          69 :         else if (!stricmp(Header, "Last-Modified")) rsp->Last_Modified = gf_strdup(Value);
     227          69 :         else if (!stricmp(Header, "Location")) rsp->Location = gf_strdup(Value);
     228          69 :         else if (!stricmp(Header, "Proxy-Authenticate")) rsp->Proxy_Authenticate = gf_strdup(Value);
     229          69 :         else if (!stricmp(Header, "Proxy-Require")) rsp->Proxy_Require = gf_strdup(Value);
     230          69 :         else if (!stricmp(Header, "Public")) rsp->Public = gf_strdup(Value);
     231          69 :         else if (!stricmp(Header, "Referer")) rsp->Referer = gf_strdup(Value);
     232          69 :         else if (!stricmp(Header, "Require")) rsp->Require = gf_strdup(Value);
     233          69 :         else if (!stricmp(Header, "Retry-After")) rsp->Retry_After = gf_strdup(Value);
     234          69 :         else if (!stricmp(Header, "Scale")) sscanf(Value, "%lf", &rsp->Scale);
     235          69 :         else if (!stricmp(Header, "Server")) rsp->Server = gf_strdup(Value);
     236          69 :         else if (!stricmp(Header, "Speed")) sscanf(Value, "%lf", &rsp->Speed);
     237          69 :         else if (!stricmp(Header, "Timestamp")) rsp->Timestamp = gf_strdup(Value);
     238          69 :         else if (!stricmp(Header, "Unsupported")) rsp->Unsupported = gf_strdup(Value);
     239          69 :         else if (!stricmp(Header, "User-Agent")) rsp->User_Agent = gf_strdup(Value);
     240          41 :         else if (!stricmp(Header, "Vary")) rsp->Vary = gf_strdup(Value);
     241          41 :         else if (!stricmp(Header, "Via")) rsp->Vary = gf_strdup(Value);
     242          41 :         else if (!stricmp(Header, "WWW_Authenticate")) rsp->Vary = gf_strdup(Value);
     243          41 :         else if (!stricmp(Header, "Transport")) {
     244             :                 LinePos = 0;
     245             :                 while (1) {
     246          12 :                         LinePos = gf_token_get(Value, LinePos, "\r\n", LineBuffer, 400);
     247          18 :                         if (LinePos <= 0) return;
     248           6 :                         trans = gf_rtsp_transport_parse(Value);
     249           6 :                         if (trans) gf_list_add(rsp->Transports, trans);
     250             :                 }
     251             :         }
     252             :         //Session
     253          35 :         else if (!stricmp(Header, "Session")) {
     254          23 :                 LinePos = gf_token_get(Value, 0, ";\r\n", LineBuffer, 400);
     255          23 :                 rsp->Session = gf_strdup(LineBuffer);
     256             :                 //get timeout if any
     257          23 :                 if (Value[LinePos] == ';') {
     258           0 :                         LinePos += 1;
     259           0 :                         /*LinePos = */gf_token_get(Value, LinePos, ";\r\n", LineBuffer, 400);
     260           0 :                         rsp->SessionTimeOut = 60; //default
     261           0 :                         sscanf(LineBuffer, "timeout=%u", &rsp->SessionTimeOut);
     262             :                 }
     263             :         }
     264             : 
     265             :         //Range
     266          12 :         else if (!stricmp(Header, "Range")) rsp->Range = gf_rtsp_range_parse(Value);
     267             :         //RTP-Info
     268           6 :         else if (!stricmp(Header, "RTP-Info")) {
     269             :                 LinePos = 0;
     270             :                 while (1) {
     271           0 :                         LinePos = gf_token_get(Value, LinePos, ",\r\n", LineBuffer, 400);
     272           0 :                         if (LinePos <= 0) return;
     273             : 
     274           0 :                         GF_SAFEALLOC(info, GF_RTPInfo);
     275           0 :                         if (!info) return;
     276             : 
     277             :                         Pos = 0;
     278             :                         while (1) {
     279           0 :                                 Pos = gf_token_get(LineBuffer, Pos, " ;", buf, 1000);
     280           0 :                                 if (Pos <= 0) break;
     281           0 :                                 if (strstr(buf, "=")) {
     282           0 :                                         nPos = gf_token_get(buf, 0, "=", param_name, 100);
     283           0 :                                         nPos += 1;
     284           0 :                                         /*nPos = */gf_token_get(buf, nPos, "", param_val, 1000);
     285             :                                 } else {
     286             :                                         strcpy(param_name, buf);
     287             :                                 }
     288           0 :                                 if (!stricmp(param_name, "url")) info->url = gf_strdup(param_val);
     289           0 :                                 else if (!stricmp(param_name, "seq")) sscanf(param_val, "%u", &info->seq);
     290           0 :                                 else if (!stricmp(param_name, "rtptime")) {
     291           0 :                                         sscanf(param_val, "%i", &s_val);
     292           0 :                                         info->rtp_time = (s_val>0) ? s_val : 0;
     293             :                                 }
     294           0 :                                 else if (!stricmp(param_name, "ssrc")) {
     295           0 :                                         sscanf(param_val, "%i", &s_val);
     296           0 :                                         info->ssrc = (s_val>0) ? s_val : 0;
     297             :                                 }
     298             :                         }
     299           0 :                         gf_list_add(rsp->RTP_Infos, info);
     300             :                 }
     301             :         }
     302             :         //check for extended attributes
     303           6 :         else if (!strnicmp(Header, "x-", 2)) {
     304           0 :                 x_Att = (GF_X_Attribute*)gf_malloc(sizeof(GF_X_Attribute));
     305           0 :                 x_Att->Name = gf_strdup(Header+2);
     306           0 :                 x_Att->Value = NULL;
     307           0 :                 if (Value && strlen(Value)) x_Att->Value = gf_strdup(Value);
     308           0 :                 gf_list_add(rsp->Xtensions, x_Att);
     309             :         }
     310             :         //unknown field - skip it
     311             : }
     312             : 
     313             : 
     314             : 
     315             : //parse all fields in the header
     316          28 : GF_Err RTSP_ParseResponseHeader(GF_RTSPSession *sess, GF_RTSPResponse *rsp, u32 BodyStart)
     317             : {
     318             :         char LineBuffer[1024];
     319             :         char ValBuf[400];
     320             :         char *buffer;
     321             :         s32 Pos, ret;
     322             :         u32 Size;
     323             : 
     324          28 :         Size = sess->CurrentSize - sess->CurrentPos;
     325          28 :         buffer = sess->tcp_buffer + sess->CurrentPos;
     326             : 
     327             :         //parse first line
     328          28 :         ret = gf_token_get_line(buffer, 0, Size, LineBuffer, 1024);
     329          28 :         if (ret < 0)
     330             :                 return GF_REMOTE_SERVICE_ERROR;
     331             :         //RTSP/1.0
     332          28 :         Pos = gf_token_get(LineBuffer, 0, " \t\r\n", ValBuf, 400);
     333          28 :         if (Pos <= 0)
     334             :                 return GF_REMOTE_SERVICE_ERROR;
     335          28 :         if (strcmp(ValBuf, GF_RTSP_VERSION))
     336             :                 return GF_SERVICE_ERROR;
     337             :         //CODE
     338          28 :         Pos = gf_token_get(LineBuffer, Pos, " \t\r\n", ValBuf, 400);
     339          28 :         if (Pos <= 0)
     340             :                 return GF_REMOTE_SERVICE_ERROR;
     341          28 :         rsp->ResponseCode = atoi(ValBuf);
     342             :         //string info
     343          28 :         Pos = gf_token_get(LineBuffer, Pos, "\t\r\n", ValBuf, 400);
     344          28 :         if (Pos > 0) rsp->ResponseInfo = gf_strdup(ValBuf);
     345             : 
     346          28 :         return gf_rtsp_parse_header(buffer + ret, Size - ret, BodyStart, NULL, rsp);
     347             : }
     348             : 
     349             : 
     350             : 
     351          28 : u32 IsRTSPMessage(char *buffer)
     352             : {
     353          28 :         if (!buffer) return 0;
     354          28 :         if (buffer[0]=='$') return 0;
     355             : 
     356          28 :         if (!strncmp(buffer, "RTSP", 4)) return 1;
     357           0 :         if (!strncmp(buffer, "GET_PARAMETER", strlen("GET_PARAMETER"))) return 1;
     358           0 :         if (!strncmp(buffer, "ANNOUNCE", strlen("ANNOUNCE"))) return 1;
     359           0 :         if (!strncmp(buffer, "SET_PARAMETER", strlen("SET_PARAMETER"))) return 1;
     360           0 :         if (!strncmp(buffer, "REDIRECT", strlen("REDIRECT"))) return 1;
     361           0 :         if (!strncmp(buffer, "OPTIONS", strlen("OPTIONS"))) return 1;
     362           0 :         return 0;
     363             : }
     364             : 
     365             : 
     366             : GF_EXPORT
     367        2007 : GF_Err gf_rtsp_get_response(GF_RTSPSession *sess, GF_RTSPResponse *rsp)
     368             : {
     369             :         GF_Err e;
     370             :         Bool force_reset = GF_FALSE;
     371             :         u32 BodyStart, size;
     372             : 
     373        2007 :         if (!sess || !rsp) return GF_BAD_PARAM;
     374        2007 :         gf_rtsp_response_reset(rsp);
     375             : 
     376        2007 :         e = gf_rtsp_check_connection(sess);
     377        2007 :         if (e)
     378             :                 goto exit;
     379             : 
     380             :         //push data in our queue
     381        2007 :         e = gf_rtsp_fill_buffer(sess);
     382        2007 :         if (e)
     383             :                 goto exit;
     384             : 
     385             :         //this is interleaved data
     386          28 :         if (!IsRTSPMessage(sess->tcp_buffer+sess->CurrentPos) ) {
     387           0 :                 gf_rtsp_session_read(sess);
     388             :                 e = GF_IP_NETWORK_EMPTY;
     389           0 :                 goto exit;
     390             :         }
     391          28 :         e = gf_rtsp_read_reply(sess);
     392          28 :         if (e)
     393             :                 goto exit;
     394             : 
     395             :         //get the reply
     396          28 :         gf_rtsp_get_body_info(sess, &BodyStart, &size);
     397          28 :         e = RTSP_ParseResponseHeader(sess, rsp, BodyStart);
     398             : 
     399             :         //copy the body if any
     400          28 :         if (!e && rsp->Content_Length) {
     401           5 :                 rsp->body = (char *)gf_malloc(sizeof(char) * (rsp->Content_Length));
     402           5 :                 memcpy(rsp->body, sess->tcp_buffer+sess->CurrentPos + BodyStart, rsp->Content_Length);
     403             :         }
     404             : 
     405          28 :         GF_LOG(GF_LOG_INFO, GF_LOG_RTP, ("[RTSP] Got Response:\n%s\n", sess->tcp_buffer+sess->CurrentPos));
     406             : 
     407             :         //reset TCP buffer
     408          28 :         sess->CurrentPos += BodyStart + rsp->Content_Length;
     409             : 
     410          28 :         if (e) goto exit;
     411             : 
     412             :         //update RTSP aggreagation info
     413          28 :         if (sess->NbPending) sess->NbPending -= 1;
     414             : 
     415          28 :         if (sess->RTSP_State == GF_RTSP_STATE_WAITING) sess->RTSP_State = GF_RTSP_STATE_INIT;
     416             :         //control, and everything is received
     417          12 :         else if (sess->RTSP_State == GF_RTSP_STATE_WAIT_FOR_CONTROL) {
     418          12 :                 if (!sess->NbPending) sess->RTSP_State = GF_RTSP_STATE_INIT;
     419             :         }
     420             :         //this is a late reply to an aggregated control - signal nothing
     421          28 :         if (!strcmp(sess->RTSPLastRequest, "RESET") && sess->CSeq > rsp->CSeq) {
     422             :                 e = GF_IP_NETWORK_EMPTY;
     423             :                 goto exit;
     424             :         }
     425             : 
     426             :         //reset last request
     427          28 :         if (sess->RTSP_State == GF_RTSP_STATE_INIT) strcpy(sess->RTSPLastRequest, "");
     428             : 
     429             :         //check the CSeq is in the right range. The server should ALWAYS reply in sequence
     430             :         //to an aggreagated sequence of requests
     431             :         //if we have reseted the connection (due to an APP error) return empty
     432          28 :         if (rsp->CSeq && sess->CSeq > rsp->CSeq + sess->NbPending) {
     433           0 :                 return gf_rtsp_get_response(sess, rsp);
     434             :         }
     435             : 
     436          28 :         if (sess->CSeq != rsp->CSeq + sess->NbPending) {
     437           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[RTSP] Invalid sequence number - got %d but expected %d\n", sess->CSeq, rsp->CSeq + sess->NbPending));
     438             :                 e = GF_REMOTE_SERVICE_ERROR;
     439             :                 goto exit;
     440             :         }
     441             : 
     442             :         /*check session ID*/
     443          28 :         if (rsp->Session && sess->last_session_id && strcmp(sess->last_session_id, rsp->Session)) {
     444             :                 e = GF_REMOTE_SERVICE_ERROR;
     445             :                 goto exit;
     446             :         }
     447             : 
     448             :         //destroy sessionID if needed - real doesn't close the connection when destroying
     449             :         //session
     450          28 :         if (!strcmp(sess->RTSPLastRequest, GF_RTSP_TEARDOWN)) {
     451           0 :                 sess->last_session_id = NULL;
     452             :         }
     453             : 
     454        4014 : exit:
     455        2007 :         if (rsp->Connection && !stricmp(rsp->Connection, "Close"))
     456             :                 force_reset = GF_TRUE;
     457        1983 :         else if (e && (e != GF_IP_NETWORK_EMPTY))
     458             :                 force_reset = GF_TRUE;
     459             : 
     460             :         if (force_reset) {
     461          24 :                 gf_rtsp_session_reset(sess, GF_FALSE);
     462             :                 //destroy the socket
     463          24 :                 if (sess->connection) gf_sk_del(sess->connection);
     464          24 :                 sess->connection = NULL;
     465             : 
     466             :                 //destroy the http tunnel if any
     467          24 :                 if (sess->HasTunnel && sess->http) {
     468           0 :                         gf_sk_del(sess->http);
     469           0 :                         sess->http = NULL;
     470             :                 }
     471             :         }
     472             :         return e;
     473             : }
     474             : 
     475          28 : GF_Err RTSP_WriteResponse(GF_RTSPSession *sess, GF_RTSPResponse *rsp,
     476             :                           unsigned char **out_buffer, u32 *out_size)
     477             : {
     478             :         u32 i, cur_pos, size, count;
     479             :         char *buffer;
     480             : 
     481          28 :         *out_buffer = NULL;
     482             : 
     483             :         size = RTSP_WRITE_STEPALLOC;
     484          28 :         buffer = (char *) gf_malloc(size);
     485             :         cur_pos = 0;
     486             : 
     487             :         //RTSP line
     488             :         RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, GF_RTSP_VERSION);
     489          28 :         RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, " ");
     490          84 :         RTSP_WRITE_INT(buffer, size, cur_pos, rsp->ResponseCode, 0);
     491          56 :         RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, " ");
     492          56 :         RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, gf_rtsp_nc_to_string(rsp->ResponseCode));
     493          56 :         RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, "\r\n");
     494             : 
     495             :         //all headers
     496          28 :         RTSP_WRITE_HEADER(buffer, size, cur_pos, "Accept", rsp->Accept);
     497          28 :         RTSP_WRITE_HEADER(buffer, size, cur_pos, "Accept-Encoding", rsp->Accept_Encoding);
     498          28 :         RTSP_WRITE_HEADER(buffer, size, cur_pos, "Accept-Language", rsp->Accept_Language);
     499          28 :         RTSP_WRITE_HEADER(buffer, size, cur_pos, "Allow", rsp->Allow);
     500          28 :         RTSP_WRITE_HEADER(buffer, size, cur_pos, "Authorization", rsp->Authorization);
     501          28 :         if (rsp->Bandwidth) {
     502           0 :                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, "Bandwidth: ");
     503           0 :                 RTSP_WRITE_INT(buffer, size, cur_pos, rsp->Bandwidth, 0);
     504           0 :                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, "\r\n");
     505             :         }
     506          28 :         if (rsp->Blocksize) {
     507           0 :                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, "Blocksize: ");
     508           0 :                 RTSP_WRITE_INT(buffer, size, cur_pos, rsp->Blocksize, 0);
     509           0 :                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, "\r\n");
     510             :         }
     511          28 :         RTSP_WRITE_HEADER(buffer, size, cur_pos, "Cache-Control", rsp->Cache_Control);
     512          28 :         RTSP_WRITE_HEADER(buffer, size, cur_pos, "Conference", rsp->Conference);
     513         124 :         RTSP_WRITE_HEADER(buffer, size, cur_pos, "Connection", rsp->Connection);
     514          28 :         RTSP_WRITE_HEADER(buffer, size, cur_pos, "Content-Base", rsp->Content_Base);
     515          28 :         RTSP_WRITE_HEADER(buffer, size, cur_pos, "Content-Encoding", rsp->Content_Encoding);
     516          28 :         RTSP_WRITE_HEADER(buffer, size, cur_pos, "Content-Language", rsp->Content_Language);
     517             :         //if we have a body write the content length
     518          28 :         if (rsp->body) {
     519          10 :                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, "Content-Length: ");
     520          15 :                 RTSP_WRITE_INT(buffer, size, cur_pos, (u32) strlen(rsp->body), 0);
     521          10 :                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, "\r\n");
     522             :         }
     523          28 :         RTSP_WRITE_HEADER(buffer, size, cur_pos, "Content-Location", rsp->Content_Location);
     524          28 :         RTSP_WRITE_HEADER(buffer, size, cur_pos, "Content-Type", rsp->Content_Type);
     525             :         //write the CSeq - use the RESPONSE CSeq
     526          56 :         RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, "CSeq: ");
     527          84 :         RTSP_WRITE_INT(buffer, size, cur_pos, rsp->CSeq, 0);
     528          56 :         RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, "\r\n");
     529             : 
     530          28 :         RTSP_WRITE_HEADER(buffer, size, cur_pos, "Date", rsp->Date);
     531          28 :         RTSP_WRITE_HEADER(buffer, size, cur_pos, "Expires", rsp->Expires);
     532          28 :         RTSP_WRITE_HEADER(buffer, size, cur_pos, "From", rsp->From);
     533          28 :         RTSP_WRITE_HEADER(buffer, size, cur_pos, "Host", rsp->Host);
     534          28 :         RTSP_WRITE_HEADER(buffer, size, cur_pos, "If-Match", rsp->If_Match);
     535          28 :         RTSP_WRITE_HEADER(buffer, size, cur_pos, "If-Modified-Since", rsp->If_Modified_Since);
     536          28 :         RTSP_WRITE_HEADER(buffer, size, cur_pos, "Last-Modified", rsp->Last_Modified);
     537          28 :         RTSP_WRITE_HEADER(buffer, size, cur_pos, "Location", rsp->Location);
     538          28 :         RTSP_WRITE_HEADER(buffer, size, cur_pos, "Proxy-Authenticate", rsp->Proxy_Authenticate);
     539          28 :         RTSP_WRITE_HEADER(buffer, size, cur_pos, "Proxy-Require", rsp->Proxy_Require);
     540          28 :         RTSP_WRITE_HEADER(buffer, size, cur_pos, "Public", rsp->Public);
     541             : 
     542             :         //Range, only NPT
     543          28 :         if (rsp->Range && !rsp->Range->UseSMPTE) {
     544          12 :                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, "Range: npt:");
     545          18 :                 RTSP_WRITE_FLOAT_WITHOUT_CHECK(buffer, size, cur_pos, rsp->Range->start);
     546          12 :                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, "-");
     547           6 :                 if (rsp->Range->end > rsp->Range->start) {
     548           0 :                         RTSP_WRITE_FLOAT_WITHOUT_CHECK(buffer, size, cur_pos, rsp->Range->end);
     549             :                 }
     550          12 :                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, "\r\n");
     551             :         }
     552             : 
     553          28 :         RTSP_WRITE_HEADER(buffer, size, cur_pos, "Referer", rsp->Referer);
     554          28 :         RTSP_WRITE_HEADER(buffer, size, cur_pos, "Require", rsp->Require);
     555          28 :         RTSP_WRITE_HEADER(buffer, size, cur_pos, "Retry-After", rsp->Retry_After);
     556             : 
     557             :         //RTP Infos
     558          28 :         count = gf_list_count(rsp->RTP_Infos);
     559          28 :         if (count) {
     560          12 :                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, "RTPInfo: ");
     561             : 
     562          12 :                 for (i=0; i<count; i++) {
     563             :                         GF_RTPInfo *info;
     564             :                         //line separator for headers
     565           6 :                         if (i) RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, "\r\n ,");
     566           6 :                         info = (GF_RTPInfo*)gf_list_get(rsp->RTP_Infos, i);
     567             : 
     568           6 :                         if (info->url) {
     569          12 :                                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, "url=");
     570          12 :                                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, info->url);
     571          12 :                                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, ";");
     572             :                         }
     573          12 :                         RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, "seq=");
     574          18 :                         RTSP_WRITE_INT(buffer, size, cur_pos, info->seq, 0);
     575          12 :                         RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, ";rtptime=");
     576          18 :                         RTSP_WRITE_INT(buffer, size, cur_pos, info->rtp_time, 0);
     577             :                 }
     578          12 :                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, "\r\n");
     579             :         }
     580             : 
     581          28 :         if (rsp->Scale != 0.0) {
     582           0 :                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, "Scale: ");
     583           0 :                 RTSP_WRITE_FLOAT_WITHOUT_CHECK(buffer, size, cur_pos, rsp->Scale);
     584           0 :                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, "\r\n");
     585             :         }
     586          28 :         RTSP_WRITE_HEADER(buffer, size, cur_pos, "Server", rsp->Server);
     587         120 :         RTSP_WRITE_HEADER(buffer, size, cur_pos, "Session", rsp->Session);
     588          28 :         if (rsp->Speed != 0.0) {
     589           0 :                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, "Scale: ");
     590           0 :                 RTSP_WRITE_FLOAT_WITHOUT_CHECK(buffer, size, cur_pos, rsp->Speed);
     591           0 :                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, "\r\n");
     592             :         }
     593          28 :         RTSP_WRITE_HEADER(buffer, size, cur_pos, "Timestamp", rsp->Timestamp);
     594             : 
     595             :         //transport info
     596          28 :         count = gf_list_count(rsp->Transports);
     597          28 :         if (count) {
     598          12 :                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, "Transport: ");
     599          12 :                 for (i=0; i<count; i++) {
     600             :                         GF_RTSPTransport *trans;
     601             :                         //line separator for headers
     602           6 :                         if (i) RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, "\r\n ,");
     603           6 :                         trans = (GF_RTSPTransport*)gf_list_get(rsp->Transports, i);
     604             : 
     605             :                         //then write the structure
     606          12 :                         RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, trans->Profile);
     607          12 :                         RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, (trans->IsUnicast ? ";unicast" : ";multicast"));
     608           6 :                         if (trans->destination) {
     609           2 :                                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, ";destination=");
     610           2 :                                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, trans->destination);
     611             :                         }
     612           6 :                         if (trans->source) {
     613          12 :                                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, ";source=");
     614          12 :                                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, trans->source);
     615             :                         }
     616           6 :                         if (trans->IsRecord) {
     617           0 :                                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, ";mode=RECORD");
     618           0 :                                 if (trans->Append) RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, ";append");
     619             :                         }
     620           6 :                         if (trans->IsInterleaved) {
     621           2 :                                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, ";interleaved=");
     622           3 :                                 RTSP_WRITE_INT(buffer, size, cur_pos, trans->rtpID, 0);
     623           1 :                                 if (trans->rtcpID != trans->rtpID) {
     624           2 :                                         RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, "-");
     625           3 :                                         RTSP_WRITE_INT(buffer, size, cur_pos, trans->rtcpID, 0);
     626             :                                 }
     627             :                         }
     628             :                         //multicast specific
     629           6 :                         if (!trans->IsUnicast) {
     630           1 :                                 if (trans->MulticastLayers) {
     631           0 :                                         RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, ";layers=");
     632           0 :                                         RTSP_WRITE_INT(buffer, size, cur_pos, trans->MulticastLayers, 0);
     633             :                                 }
     634           1 :                                 if (trans->TTL) {
     635           2 :                                         RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, ";ttl=");
     636           3 :                                         RTSP_WRITE_INT(buffer, size, cur_pos, trans->TTL, 0);
     637             :                                 }
     638             :                         }
     639           6 :                         if (trans->port_first) {
     640          10 :                                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, (const char *) (trans->IsUnicast ? ";server_port=" : ";port="));
     641          15 :                                 RTSP_WRITE_INT(buffer, size, cur_pos, trans->port_first, 0);
     642          10 :                                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, "-");
     643          15 :                                 RTSP_WRITE_INT(buffer, size, cur_pos, trans->port_last, 0);
     644             :                         }
     645           6 :                         if (trans->IsUnicast && trans->client_port_first) {
     646           8 :                                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, ";client_port=");
     647          12 :                                 RTSP_WRITE_INT(buffer, size, cur_pos, trans->client_port_first, 0);
     648           8 :                                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, "-");
     649          12 :                                 RTSP_WRITE_INT(buffer, size, cur_pos, trans->client_port_last, 0);
     650             :                         }
     651           6 :                         if (trans->SSRC) {
     652          12 :                                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, ";ssrc=");
     653          18 :                                 RTSP_WRITE_HEX(buffer, size, cur_pos, trans->SSRC, 0);
     654             :                         }
     655             :                 }
     656             :                 //done with transport
     657          12 :                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, "\r\n");
     658             :         }
     659             : 
     660          28 :         RTSP_WRITE_HEADER(buffer, size, cur_pos, "Unsupported", rsp->Unsupported);
     661         140 :         RTSP_WRITE_HEADER(buffer, size, cur_pos, "User-Agent", rsp->User_Agent);
     662          28 :         RTSP_WRITE_HEADER(buffer, size, cur_pos, "Vary", rsp->Vary);
     663          28 :         RTSP_WRITE_HEADER(buffer, size, cur_pos, "Via", rsp->Via);
     664          28 :         RTSP_WRITE_HEADER(buffer, size, cur_pos, "WWW-Authenticate", rsp->WWW_Authenticate);
     665             : 
     666             :         //eXtensions
     667          28 :         count = gf_list_count(rsp->Xtensions);
     668          28 :         for (i=0; i<count; i++) {
     669           0 :                 GF_X_Attribute *att = (GF_X_Attribute*)gf_list_get(rsp->Xtensions, i);
     670           0 :                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, "x-");
     671           0 :                 RTSP_WRITE_HEADER(buffer, size, cur_pos, att->Name, att->Value);
     672             :         }
     673             :         //end of header
     674          56 :         RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, "\r\n");
     675             :         //then body
     676          28 :         RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, rsp->body);
     677             : 
     678          28 :         *out_buffer = (unsigned char *) buffer;
     679          28 :         *out_size = (u32) strlen(buffer);
     680          28 :         return GF_OK;
     681             : }
     682             : 
     683             : 
     684             : GF_EXPORT
     685          28 : GF_Err gf_rtsp_send_response(GF_RTSPSession *sess, GF_RTSPResponse *rsp)
     686             : {
     687             :         u32 size;
     688             :         char *buffer;
     689             :         GF_Err e;
     690             : 
     691          28 :         if (!sess || !rsp || !rsp->CSeq) return GF_BAD_PARAM;
     692             : 
     693             :         //check we're not sending something greater than the current CSeq
     694          28 :         if (rsp->CSeq > sess->CSeq) return GF_BAD_PARAM;
     695             : 
     696          28 :         e = RTSP_WriteResponse(sess, rsp, (unsigned char **) &buffer, &size);
     697          28 :         if (!e) {
     698             :                 //send buffer
     699          28 :                 e = gf_rtsp_send_data(sess, buffer, size);
     700             :         }
     701          28 :         if (buffer) gf_free(buffer);
     702             :         return e;
     703             : }
     704             : 
     705             : #endif /*GPAC_DISABLE_STREAMING*/

Generated by: LCOV version 1.13