diff options
author | Brad King <brad.king@kitware.com> | 2023-05-30 13:38:38 (GMT) |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2023-05-30 13:39:43 (GMT) |
commit | a6c9b53273eb3ef8b4d9a0a2a0fc6a4822211b9d (patch) | |
tree | 23bfdb5c7a2254a82571a4acb78b5a25c1641898 /Utilities/cmcurl/lib/rtsp.c | |
parent | 7f1abf62e12a261a2fc91a2d527b5c4a30e25d41 (diff) | |
parent | 80cb6a512119ea6f8f8cf480c78e1e32d494e6ca (diff) | |
download | CMake-a6c9b53273eb3ef8b4d9a0a2a0fc6a4822211b9d.zip CMake-a6c9b53273eb3ef8b4d9a0a2a0fc6a4822211b9d.tar.gz CMake-a6c9b53273eb3ef8b4d9a0a2a0fc6a4822211b9d.tar.bz2 |
Merge branch 'upstream-curl' into update-curl
* upstream-curl:
curl 2023-05-30 (7ab9d437)
Diffstat (limited to 'Utilities/cmcurl/lib/rtsp.c')
-rw-r--r-- | Utilities/cmcurl/lib/rtsp.c | 242 |
1 files changed, 158 insertions, 84 deletions
diff --git a/Utilities/cmcurl/lib/rtsp.c b/Utilities/cmcurl/lib/rtsp.c index aef3560..ccd7264 100644 --- a/Utilities/cmcurl/lib/rtsp.c +++ b/Utilities/cmcurl/lib/rtsp.c @@ -45,8 +45,6 @@ #include "curl_memory.h" #include "memdebug.h" -#define RTP_PKT_CHANNEL(p) ((int)((unsigned char)((p)[1]))) - #define RTP_PKT_LENGTH(p) ((((int)((unsigned char)((p)[2]))) << 8) | \ ((int)((unsigned char)((p)[3])))) @@ -91,6 +89,8 @@ static int rtsp_getsock_do(struct Curl_easy *data, struct connectdata *conn, static CURLcode rtp_client_write(struct Curl_easy *data, char *ptr, size_t len); +static +CURLcode rtsp_parse_transport(struct Curl_easy *data, char *transport); /* @@ -119,6 +119,7 @@ const struct Curl_handler Curl_handler_rtsp = { PROTOPT_NONE /* flags */ }; +#define MAX_RTP_BUFFERSIZE 1000000 /* arbitrary */ static CURLcode rtsp_setup_connection(struct Curl_easy *data, struct connectdata *conn) @@ -130,6 +131,7 @@ static CURLcode rtsp_setup_connection(struct Curl_easy *data, if(!rtsp) return CURLE_OUT_OF_MEMORY; + Curl_dyn_init(&conn->proto.rtspc.buf, MAX_RTP_BUFFERSIZE); return CURLE_OK; } @@ -176,7 +178,7 @@ static CURLcode rtsp_disconnect(struct Curl_easy *data, { (void) dead; (void) data; - Curl_safefree(conn->proto.rtspc.rtp_buf); + Curl_dyn_free(&conn->proto.rtspc.buf); return CURLE_OK; } @@ -204,7 +206,7 @@ static CURLcode rtsp_done(struct Curl_easy *data, return CURLE_RTSP_CSEQ_ERROR; } if(data->set.rtspreq == RTSPREQ_RECEIVE && - (data->conn->proto.rtspc.rtp_channel == -1)) { + (data->conn->proto.rtspc.rtp_channel == -1)) { infof(data, "Got an RTP Receive with a CSeq of %ld", CSeq_recv); } } @@ -374,7 +376,6 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done) if(Curl_checkheaders(data, STRCONST("User-Agent")) && data->state.aptr.uagent) { Curl_safefree(data->state.aptr.uagent); - data->state.aptr.uagent = NULL; } else if(!Curl_checkheaders(data, STRCONST("User-Agent")) && data->set.str[STRING_USERAGENT]) { @@ -394,8 +395,6 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done) Curl_safefree(data->state.aptr.ref); if(data->state.referer && !Curl_checkheaders(data, STRCONST("Referer"))) data->state.aptr.ref = aprintf("Referer: %s\r\n", data->state.referer); - else - data->state.aptr.ref = NULL; p_referrer = data->state.aptr.ref; @@ -476,7 +475,6 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done) * with basic and digest, it will be freed anyway by the next request */ Curl_safefree(data->state.aptr.userpwd); - data->state.aptr.userpwd = NULL; if(result) return result; @@ -495,7 +493,7 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done) rtspreq == RTSPREQ_SET_PARAMETER || rtspreq == RTSPREQ_GET_PARAMETER) { - if(data->set.upload) { + if(data->state.upload) { putsize = data->state.infilesize; data->state.httpreq = HTTPREQ_PUT; @@ -514,7 +512,7 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done) result = Curl_dyn_addf(&req_buffer, "Content-Length: %" CURL_FORMAT_CURL_OFF_T"\r\n", - (data->set.upload ? putsize : postsize)); + (data->state.upload ? putsize : postsize)); if(result) return result; } @@ -594,26 +592,20 @@ static CURLcode rtsp_rtp_readwrite(struct Curl_easy *data, bool *readmore) { struct SingleRequest *k = &data->req; struct rtsp_conn *rtspc = &(conn->proto.rtspc); + unsigned char *rtp_channel_mask = data->state.rtp_channel_mask; char *rtp; /* moving pointer to rtp data */ ssize_t rtp_dataleft; /* how much data left to parse in this round */ - char *scratch; CURLcode result; + bool interleaved = false; + size_t skip_size = 0; - if(rtspc->rtp_buf) { - /* There was some leftover data the last time. Merge buffers */ - char *newptr = Curl_saferealloc(rtspc->rtp_buf, - rtspc->rtp_bufsize + *nread); - if(!newptr) { - rtspc->rtp_buf = NULL; - rtspc->rtp_bufsize = 0; + if(Curl_dyn_len(&rtspc->buf)) { + /* There was some leftover data the last time. Append new buffers */ + if(Curl_dyn_addn(&rtspc->buf, k->str, *nread)) return CURLE_OUT_OF_MEMORY; - } - rtspc->rtp_buf = newptr; - memcpy(rtspc->rtp_buf + rtspc->rtp_bufsize, k->str, *nread); - rtspc->rtp_bufsize += *nread; - rtp = rtspc->rtp_buf; - rtp_dataleft = rtspc->rtp_bufsize; + rtp = Curl_dyn_ptr(&rtspc->buf); + rtp_dataleft = Curl_dyn_len(&rtspc->buf); } else { /* Just parse the request buffer directly */ @@ -621,71 +613,107 @@ static CURLcode rtsp_rtp_readwrite(struct Curl_easy *data, rtp_dataleft = *nread; } - while((rtp_dataleft > 0) && - (rtp[0] == '$')) { - if(rtp_dataleft > 4) { - int rtp_length; + while(rtp_dataleft > 0) { + if(rtp[0] == '$') { + if(rtp_dataleft > 4) { + unsigned char rtp_channel; + int rtp_length; + int idx; + int off; + + /* Parse the header */ + /* The channel identifier immediately follows and is 1 byte */ + rtp_channel = (unsigned char)rtp[1]; + idx = rtp_channel / 8; + off = rtp_channel % 8; + if(!(rtp_channel_mask[idx] & (1 << off))) { + /* invalid channel number, maybe not an RTP packet */ + rtp++; + rtp_dataleft--; + skip_size++; + continue; + } + if(skip_size > 0) { + DEBUGF(infof(data, "Skip the malformed interleaved data %lu " + "bytes", skip_size)); + } + skip_size = 0; + rtspc->rtp_channel = rtp_channel; - /* Parse the header */ - /* The channel identifier immediately follows and is 1 byte */ - rtspc->rtp_channel = RTP_PKT_CHANNEL(rtp); + /* The length is two bytes */ + rtp_length = RTP_PKT_LENGTH(rtp); - /* The length is two bytes */ - rtp_length = RTP_PKT_LENGTH(rtp); + if(rtp_dataleft < rtp_length + 4) { + /* Need more - incomplete payload */ + *readmore = TRUE; + break; + } + interleaved = true; + /* We have the full RTP interleaved packet + * Write out the header including the leading '$' */ + DEBUGF(infof(data, "RTP write channel %d rtp_length %d", + rtspc->rtp_channel, rtp_length)); + result = rtp_client_write(data, &rtp[0], rtp_length + 4); + if(result) { + *readmore = FALSE; + return result; + } + + /* Move forward in the buffer */ + rtp_dataleft -= rtp_length + 4; + rtp += rtp_length + 4; - if(rtp_dataleft < rtp_length + 4) { - /* Need more - incomplete payload */ + if(data->set.rtspreq == RTSPREQ_RECEIVE) { + /* If we are in a passive receive, give control back + * to the app as often as we can. + */ + k->keepon &= ~KEEP_RECV; + } + } + else { + /* Need more - incomplete header */ *readmore = TRUE; break; } - /* We have the full RTP interleaved packet - * Write out the header including the leading '$' */ - DEBUGF(infof(data, "RTP write channel %d rtp_length %d", - rtspc->rtp_channel, rtp_length)); - result = rtp_client_write(data, &rtp[0], rtp_length + 4); - if(result) { - failf(data, "Got an error writing an RTP packet"); - *readmore = FALSE; - Curl_safefree(rtspc->rtp_buf); - rtspc->rtp_buf = NULL; - rtspc->rtp_bufsize = 0; - return result; - } - - /* Move forward in the buffer */ - rtp_dataleft -= rtp_length + 4; - rtp += rtp_length + 4; - - if(data->set.rtspreq == RTSPREQ_RECEIVE) { - /* If we are in a passive receive, give control back - * to the app as often as we can. - */ - k->keepon &= ~KEEP_RECV; - } } else { - /* Need more - incomplete header */ - *readmore = TRUE; - break; + /* If the following data begins with 'RTSP/', which might be an RTSP + message, we should stop skipping the data. */ + /* If `k-> headerline> 0 && !interleaved` is true, we are maybe in the + middle of an RTSP message. It is difficult to determine this, so we + stop skipping. */ + size_t prefix_len = (rtp_dataleft < 5) ? rtp_dataleft : 5; + if((k->headerline > 0 && !interleaved) || + strncmp(rtp, "RTSP/", prefix_len) == 0) { + if(skip_size > 0) { + DEBUGF(infof(data, "Skip the malformed interleaved data %lu " + "bytes", skip_size)); + } + break; /* maybe is an RTSP message */ + } + /* Skip incorrect data util the next RTP packet or RTSP message */ + do { + rtp++; + rtp_dataleft--; + skip_size++; + } while(rtp_dataleft > 0 && rtp[0] != '$' && rtp[0] != 'R'); } } if(rtp_dataleft && rtp[0] == '$') { DEBUGF(infof(data, "RTP Rewinding %zd %s", rtp_dataleft, - *readmore ? "(READMORE)" : "")); + *readmore ? "(READMORE)" : "")); /* Store the incomplete RTP packet for a "rewind" */ - scratch = malloc(rtp_dataleft); - if(!scratch) { - Curl_safefree(rtspc->rtp_buf); - rtspc->rtp_buf = NULL; - rtspc->rtp_bufsize = 0; - return CURLE_OUT_OF_MEMORY; + if(!Curl_dyn_len(&rtspc->buf)) { + /* nothing was stored, add this data */ + if(Curl_dyn_addn(&rtspc->buf, rtp, rtp_dataleft)) + return CURLE_OUT_OF_MEMORY; + } + else { + /* keep the remainder */ + Curl_dyn_tail(&rtspc->buf, rtp_dataleft); } - memcpy(scratch, rtp, rtp_dataleft); - Curl_safefree(rtspc->rtp_buf); - rtspc->rtp_buf = scratch; - rtspc->rtp_bufsize = rtp_dataleft; /* As far as the transfer is concerned, this data is consumed */ *nread = 0; @@ -694,20 +722,10 @@ static CURLcode rtsp_rtp_readwrite(struct Curl_easy *data, /* Fix up k->str to point just after the last RTP packet */ k->str += *nread - rtp_dataleft; - /* either all of the data has been read or... - * rtp now points at the next byte to parse - */ - if(rtp_dataleft > 0) - DEBUGASSERT(k->str[0] == rtp[0]); - - DEBUGASSERT(rtp_dataleft <= *nread); /* sanity check */ - *nread = rtp_dataleft; /* If we get here, we have finished with the leftover/merge buffer */ - Curl_safefree(rtspc->rtp_buf); - rtspc->rtp_buf = NULL; - rtspc->rtp_bufsize = 0; + Curl_dyn_free(&rtspc->buf); return CURLE_OK; } @@ -822,7 +840,63 @@ CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, char *header) (data->set.str[STRING_RTSP_SESSION_ID])[idlen] = '\0'; } } + else if(checkprefix("Transport:", header)) { + CURLcode result; + result = rtsp_parse_transport(data, header + 10); + if(result) + return result; + } return CURLE_OK; } +static +CURLcode rtsp_parse_transport(struct Curl_easy *data, char *transport) +{ + /* If we receive multiple Transport response-headers, the linterleaved + channels of each response header is recorded and used together for + subsequent data validity checks.*/ + /* e.g.: ' RTP/AVP/TCP;unicast;interleaved=5-6' */ + char *start; + char *end; + start = transport; + while(start && *start) { + while(*start && ISBLANK(*start) ) + start++; + end = strchr(start, ';'); + if(checkprefix("interleaved=", start)) { + long chan1, chan2, chan; + char *endp; + char *p = start + 12; + chan1 = strtol(p, &endp, 10); + if(p != endp && chan1 >= 0 && chan1 <= 255) { + unsigned char *rtp_channel_mask = data->state.rtp_channel_mask; + chan2 = chan1; + if(*endp == '-') { + p = endp + 1; + chan2 = strtol(p, &endp, 10); + if(p == endp || chan2 < 0 || chan2 > 255) { + infof(data, "Unable to read the interleaved parameter from " + "Transport header: [%s]", transport); + chan2 = chan1; + } + } + for(chan = chan1; chan <= chan2; chan++) { + long idx = chan / 8; + long off = chan % 8; + rtp_channel_mask[idx] |= (unsigned char)(1 << off); + } + } + else { + infof(data, "Unable to read the interleaved parameter from " + "Transport header: [%s]", transport); + } + break; + } + /* skip to next parameter */ + start = (!end) ? end : (end + 1); + } + return CURLE_OK; +} + + #endif /* CURL_DISABLE_RTSP or using Hyper */ |