diff options
author | Alexander Smirnov <alex@ydb.tech> | 2024-10-16 12:11:24 +0000 |
---|---|---|
committer | Alexander Smirnov <alex@ydb.tech> | 2024-10-16 12:11:24 +0000 |
commit | 40811e93f3fdf9342a9295369994012420fac548 (patch) | |
tree | a8d85e094a9c21e10aa250f537c101fc2016a049 /contrib/libs/curl/lib/rtsp.c | |
parent | 30ebe5357bb143648c6be4d151ecd4944af81ada (diff) | |
parent | 28a0c4a9f297064538a018c512cd9bbd00a1a35d (diff) | |
download | ydb-40811e93f3fdf9342a9295369994012420fac548.tar.gz |
Merge branch 'rightlib' into mergelibs-241016-1210
Diffstat (limited to 'contrib/libs/curl/lib/rtsp.c')
-rw-r--r-- | contrib/libs/curl/lib/rtsp.c | 318 |
1 files changed, 140 insertions, 178 deletions
diff --git a/contrib/libs/curl/lib/rtsp.c b/contrib/libs/curl/lib/rtsp.c index c9b1bc0d67..e673bb8dc0 100644 --- a/contrib/libs/curl/lib/rtsp.c +++ b/contrib/libs/curl/lib/rtsp.c @@ -58,19 +58,21 @@ static int rtsp_getsock_do(struct Curl_easy *data, struct connectdata *conn, curl_socket_t *socks); /* - * Parse and write out an RTSP response. + * Parse and write out any available RTP data. * @param data the transfer * @param conn the connection * @param buf data read from connection * @param blen amount of data in buf - * @param is_eos TRUE iff this is the last write + * @param consumed out, number of blen consumed * @param readmore out, TRUE iff complete buf was consumed and more data * is needed */ -static CURLcode rtsp_rtp_write_resp(struct Curl_easy *data, - const char *buf, - size_t blen, - bool is_eos); +static CURLcode rtsp_rtp_readwrite(struct Curl_easy *data, + struct connectdata *conn, + const char *buf, + size_t blen, + size_t *pconsumed, + bool *readmore); static CURLcode rtsp_setup_connection(struct Curl_easy *data, struct connectdata *conn); @@ -79,7 +81,7 @@ static unsigned int rtsp_conncheck(struct Curl_easy *data, unsigned int checks_to_perform); /* this returns the socket to wait for in the DO and DOING state for the multi - interface and then we are always _sending_ a request and thus we wait for + interface and then we're always _sending_ a request and thus we wait for the single socket to become writable only */ static int rtsp_getsock_do(struct Curl_easy *data, struct connectdata *conn, curl_socket_t *socks) @@ -93,14 +95,14 @@ static int rtsp_getsock_do(struct Curl_easy *data, struct connectdata *conn, static CURLcode rtp_client_write(struct Curl_easy *data, const char *ptr, size_t len); static -CURLcode rtsp_parse_transport(struct Curl_easy *data, const char *transport); +CURLcode rtsp_parse_transport(struct Curl_easy *data, char *transport); /* * RTSP handler interface. */ const struct Curl_handler Curl_handler_rtsp = { - "rtsp", /* scheme */ + "RTSP", /* scheme */ rtsp_setup_connection, /* setup_connection */ rtsp_do, /* do_it */ rtsp_done, /* done */ @@ -113,8 +115,7 @@ const struct Curl_handler Curl_handler_rtsp = { ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ rtsp_disconnect, /* disconnect */ - rtsp_rtp_write_resp, /* write_resp */ - ZERO_NULL, /* write_resp_hd */ + rtsp_rtp_readwrite, /* readwrite */ rtsp_conncheck, /* connection_check */ ZERO_NULL, /* attach connection */ PORT_RTSP, /* defport */ @@ -225,6 +226,8 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done) Curl_RtspReq rtspreq = data->set.rtspreq; struct RTSP *rtsp = data->req.p.rtsp; struct dynbuf req_buffer; + curl_off_t postsize = 0; /* for ANNOUNCE and SET_PARAMETER */ + curl_off_t putsize = 0; /* for ANNOUNCE and SET_PARAMETER */ const char *p_request = NULL; const char *p_session_id = NULL; @@ -239,8 +242,6 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done) const char *p_userpwd = NULL; *done = TRUE; - /* Initialize a dynamic send buffer */ - Curl_dyn_init(&req_buffer, DYN_RTSP_REQ_HEADER); rtsp->CSeq_sent = data->state.rtsp_next_client_CSeq; rtsp->CSeq_recv = 0; @@ -261,7 +262,7 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done) * Since all RTSP requests are included here, there is no need to * support custom requests like HTTP. **/ - data->req.no_body = TRUE; /* most requests do not contain a body */ + data->req.no_body = TRUE; /* most requests don't contain a body */ switch(rtspreq) { default: failf(data, "Got invalid RTSP request"); @@ -310,19 +311,17 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done) } if(rtspreq == RTSPREQ_RECEIVE) { - Curl_xfer_setup1(data, CURL_XFER_RECV, -1, TRUE); - goto out; + Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, -1); + + return result; } p_session_id = data->set.str[STRING_RTSP_SESSION_ID]; if(!p_session_id && - (rtspreq & ~(Curl_RtspReq)(RTSPREQ_OPTIONS | - RTSPREQ_DESCRIBE | - RTSPREQ_SETUP))) { + (rtspreq & ~(RTSPREQ_OPTIONS | RTSPREQ_DESCRIBE | RTSPREQ_SETUP))) { failf(data, "Refusing to issue an RTSP request [%s] without a session ID.", p_request); - result = CURLE_BAD_FUNCTION_ARGUMENT; - goto out; + return CURLE_BAD_FUNCTION_ARGUMENT; } /* Stream URI. Default to server '*' if not specified */ @@ -349,8 +348,7 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done) else { failf(data, "Refusing to issue an RTSP SETUP without a Transport: header."); - result = CURLE_BAD_FUNCTION_ARGUMENT; - goto out; + return CURLE_BAD_FUNCTION_ARGUMENT; } p_transport = data->state.aptr.rtsp_transport; @@ -369,10 +367,9 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done) data->state.aptr.accept_encoding = aprintf("Accept-Encoding: %s\r\n", data->set.str[STRING_ENCODING]); - if(!data->state.aptr.accept_encoding) { - result = CURLE_OUT_OF_MEMORY; - goto out; - } + if(!data->state.aptr.accept_encoding) + return CURLE_OUT_OF_MEMORY; + p_accept_encoding = data->state.aptr.accept_encoding; } } @@ -394,11 +391,9 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done) result = Curl_http_output_auth(data, conn, p_request, HTTPREQ_GET, p_stream_uri, FALSE); if(result) - goto out; + return result; -#ifndef CURL_DISABLE_PROXY p_proxyuserpwd = data->state.aptr.proxyuserpwd; -#endif p_userpwd = data->state.aptr.userpwd; /* Referrer */ @@ -430,22 +425,23 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done) */ if(Curl_checkheaders(data, STRCONST("CSeq"))) { failf(data, "CSeq cannot be set as a custom header."); - result = CURLE_RTSP_CSEQ_ERROR; - goto out; + return CURLE_RTSP_CSEQ_ERROR; } if(Curl_checkheaders(data, STRCONST("Session"))) { failf(data, "Session ID cannot be set as a custom header."); - result = CURLE_BAD_FUNCTION_ARGUMENT; - goto out; + return CURLE_BAD_FUNCTION_ARGUMENT; } + /* Initialize a dynamic send buffer */ + Curl_dyn_init(&req_buffer, DYN_RTSP_REQ_HEADER); + result = Curl_dyn_addf(&req_buffer, "%s %s RTSP/1.0\r\n" /* Request Stream-URI RTSP/1.0 */ "CSeq: %ld\r\n", /* CSeq */ p_request, p_stream_uri, rtsp->CSeq_sent); if(result) - goto out; + return result; /* * Rather than do a normal alloc line, keep the session_id unformatted @@ -454,7 +450,7 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done) if(p_session_id) { result = Curl_dyn_addf(&req_buffer, "Session: %s\r\n", p_session_id); if(result) - goto out; + return result; } /* @@ -486,57 +482,44 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done) Curl_safefree(data->state.aptr.userpwd); if(result) - goto out; + return result; if((rtspreq == RTSPREQ_SETUP) || (rtspreq == RTSPREQ_DESCRIBE)) { result = Curl_add_timecondition(data, &req_buffer); if(result) - goto out; + return result; } result = Curl_add_custom_headers(data, FALSE, &req_buffer); if(result) - goto out; + return result; if(rtspreq == RTSPREQ_ANNOUNCE || rtspreq == RTSPREQ_SET_PARAMETER || rtspreq == RTSPREQ_GET_PARAMETER) { - curl_off_t req_clen; /* request content length */ if(data->state.upload) { - req_clen = data->state.infilesize; + putsize = data->state.infilesize; data->state.httpreq = HTTPREQ_PUT; - result = Curl_creader_set_fread(data, req_clen); - if(result) - goto out; + } else { - if(data->set.postfields) { - size_t plen = strlen(data->set.postfields); - req_clen = (curl_off_t)plen; - result = Curl_creader_set_buf(data, data->set.postfields, plen); - } - else if(data->state.infilesize >= 0) { - req_clen = data->state.infilesize; - result = Curl_creader_set_fread(data, req_clen); - } - else { - req_clen = 0; - result = Curl_creader_set_null(data); - } - if(result) - goto out; + postsize = (data->state.infilesize != -1)? + data->state.infilesize: + (data->set.postfields? (curl_off_t)strlen(data->set.postfields):0); + data->state.httpreq = HTTPREQ_POST; } - if(req_clen > 0) { + if(putsize > 0 || postsize > 0) { /* As stated in the http comments, it is probably not wise to * actually set a custom Content-Length in the headers */ if(!Curl_checkheaders(data, STRCONST("Content-Length"))) { result = - Curl_dyn_addf(&req_buffer, "Content-Length: %" FMT_OFF_T"\r\n", - req_clen); + Curl_dyn_addf(&req_buffer, + "Content-Length: %" CURL_FORMAT_CURL_OFF_T"\r\n", + (data->state.upload ? putsize : postsize)); if(result) - goto out; + return result; } if(rtspreq == RTSPREQ_SET_PARAMETER || @@ -546,7 +529,7 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done) STRCONST("Content-Type: " "text/parameters\r\n")); if(result) - goto out; + return result; } } @@ -556,9 +539,11 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done) STRCONST("Content-Type: " "application/sdp\r\n")); if(result) - goto out; + return result; } } + + data->state.expect100header = FALSE; /* RTSP posts are simple/small */ } else if(rtspreq == RTSPREQ_GET_PARAMETER) { /* Check for an empty GET_PARAMETER (heartbeat) request */ @@ -566,26 +551,31 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done) data->req.no_body = TRUE; } } - else { - result = Curl_creader_set_null(data); - if(result) - goto out; - } + /* RTSP never allows chunked transfer */ + data->req.forbidchunk = TRUE; /* Finish the request buffer */ result = Curl_dyn_addn(&req_buffer, STRCONST("\r\n")); if(result) - goto out; + return result; - Curl_xfer_setup1(data, CURL_XFER_SENDRECV, -1, TRUE); + if(postsize > 0) { + result = Curl_dyn_addn(&req_buffer, data->set.postfields, + (size_t)postsize); + if(result) + return result; + } /* issue the request */ - result = Curl_req_send(data, &req_buffer); + result = Curl_buffer_send(&req_buffer, data, data->req.p.http, + &data->info.request_size, 0, FIRSTSOCKET); if(result) { failf(data, "Failed sending RTSP request"); - goto out; + return result; } + Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, putsize?FIRSTSOCKET:-1); + /* Increment the CSeq on success */ data->state.rtsp_next_client_CSeq++; @@ -596,53 +586,30 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done) if(Curl_pgrsUpdate(data)) result = CURLE_ABORTED_BY_CALLBACK; } -out: - Curl_dyn_free(&req_buffer); - return result; -} - -/** - * write any BODY bytes missing to the client, ignore the rest. - */ -static CURLcode rtp_write_body_junk(struct Curl_easy *data, - const char *buf, - size_t blen) -{ - struct rtsp_conn *rtspc = &(data->conn->proto.rtspc); - curl_off_t body_remain; - bool in_body; - in_body = (data->req.headerline && !rtspc->in_header) && - (data->req.size >= 0) && - (data->req.bytecount < data->req.size); - body_remain = in_body? (data->req.size - data->req.bytecount) : 0; - DEBUGASSERT(body_remain >= 0); - if(body_remain) { - if((curl_off_t)blen > body_remain) - blen = (size_t)body_remain; - return Curl_client_write(data, CLIENTWRITE_BODY, (char *)buf, blen); - } - return CURLE_OK; + return result; } static CURLcode rtsp_filter_rtp(struct Curl_easy *data, + struct connectdata *conn, const char *buf, size_t blen, + bool in_body, size_t *pconsumed) { - struct rtsp_conn *rtspc = &(data->conn->proto.rtspc); + struct rtsp_conn *rtspc = &(conn->proto.rtspc); CURLcode result = CURLE_OK; - size_t skip_len = 0; *pconsumed = 0; while(blen) { - bool in_body = (data->req.headerline && !rtspc->in_header) && - (data->req.size >= 0) && - (data->req.bytecount < data->req.size); switch(rtspc->state) { case RTP_PARSE_SKIP: { DEBUGASSERT(Curl_dyn_len(&rtspc->buf) == 0); + if(in_body && buf[0] != '$') { + /* in BODY and no valid start, do not consume and return */ + goto out; + } while(blen && buf[0] != '$') { if(!in_body && buf[0] == 'R' && data->set.rtspreq != RTSPREQ_RECEIVE) { @@ -657,22 +624,13 @@ static CURLcode rtsp_filter_rtp(struct Curl_easy *data, goto out; } } - /* junk/BODY, consume without buffering */ + /* junk, consume without buffering */ *pconsumed += 1; ++buf; --blen; - ++skip_len; } if(blen && buf[0] == '$') { /* possible start of an RTP message, buffer */ - if(skip_len) { - /* end of junk/BODY bytes, flush */ - result = rtp_write_body_junk(data, - (char *)(buf - skip_len), skip_len); - skip_len = 0; - if(result) - goto out; - } if(Curl_dyn_addn(&rtspc->buf, buf, 1)) { result = CURLE_OUT_OF_MEMORY; goto out; @@ -692,22 +650,35 @@ static CURLcode rtsp_filter_rtp(struct Curl_easy *data, if(!(data->state.rtp_channel_mask[idx] & (1 << off))) { /* invalid channel number, junk or BODY data */ rtspc->state = RTP_PARSE_SKIP; - DEBUGASSERT(skip_len == 0); - /* we do not consume this byte, it is BODY data */ - DEBUGF(infof(data, "RTSP: invalid RTP channel %d, skipping", idx)); - if(*pconsumed == 0) { - /* We did not consume the initial '$' in our buffer, but had - * it from an earlier call. We cannot un-consume it and have - * to write it directly as BODY data */ - result = rtp_write_body_junk(data, Curl_dyn_ptr(&rtspc->buf), 1); - if(result) + if(in_body) { + /* we do not consume this byte, it is BODY data */ + DEBUGF(infof(data, "RTSP: invalid RTP channel %d in BODY, " + "treating as BODY data", idx)); + if(*pconsumed == 0) { + /* We did not consume the initial '$' in our buffer, but had + * it from an earlier call. We cannot un-consume it and have + * to write it directly as BODY data */ + result = Curl_client_write(data, CLIENTWRITE_BODY, + Curl_dyn_ptr(&rtspc->buf), 1); + Curl_dyn_free(&rtspc->buf); + if(result) + goto out; + } + else { + /* un-consume the '$' and leave */ + Curl_dyn_free(&rtspc->buf); + *pconsumed -= 1; + --buf; + ++blen; goto out; + } } else { - /* count the '$' as skip and continue */ - skip_len = 1; + /* not BODY, forget the junk '$'. Do not consume this byte, + * it might be a start */ + infof(data, "RTSP: invalid RTP channel %d, skipping", idx); + Curl_dyn_free(&rtspc->buf); } - Curl_dyn_free(&rtspc->buf); break; } /* a valid channel, so we expect this to be a real RTP message */ @@ -783,49 +754,52 @@ static CURLcode rtsp_filter_rtp(struct Curl_easy *data, } } out: - if(!result && skip_len) - result = rtp_write_body_junk(data, (char *)(buf - skip_len), skip_len); return result; } -static CURLcode rtsp_rtp_write_resp(struct Curl_easy *data, - const char *buf, - size_t blen, - bool is_eos) +static CURLcode rtsp_rtp_readwrite(struct Curl_easy *data, + struct connectdata *conn, + const char *buf, + size_t blen, + size_t *pconsumed, + bool *readmore) { - struct rtsp_conn *rtspc = &(data->conn->proto.rtspc); + struct rtsp_conn *rtspc = &(conn->proto.rtspc); CURLcode result = CURLE_OK; size_t consumed = 0; + bool in_body; if(!data->req.header) rtspc->in_header = FALSE; + in_body = (data->req.headerline && !rtspc->in_header) && + (data->req.size >= 0) && + (data->req.bytecount < data->req.size); + + *readmore = FALSE; + *pconsumed = 0; if(!blen) { goto out; } - DEBUGF(infof(data, "rtsp_rtp_write_resp(len=%zu, in_header=%d, eos=%d)", - blen, rtspc->in_header, is_eos)); - - /* If header parsing is not ongoing, extract RTP messages */ + /* If header parsing is not onging, extract RTP messages */ if(!rtspc->in_header) { - result = rtsp_filter_rtp(data, buf, blen, &consumed); + result = rtsp_filter_rtp(data, conn, buf, blen, in_body, &consumed); if(result) goto out; + *pconsumed += consumed; buf += consumed; blen -= consumed; - /* either we consumed all or are at the start of header parsing */ - if(blen && !data->req.header) - DEBUGF(infof(data, "RTSP: %zu bytes, possibly excess in response body", - blen)); } /* we want to parse headers, do so */ if(data->req.header && blen) { rtspc->in_header = TRUE; - result = Curl_http_write_resp_hds(data, buf, blen, &consumed); + result = Curl_http_readwrite_headers(data, conn, buf, blen, + &consumed); if(result) goto out; + *pconsumed += consumed; buf += consumed; blen -= consumed; @@ -833,42 +807,26 @@ static CURLcode rtsp_rtp_write_resp(struct Curl_easy *data, rtspc->in_header = FALSE; if(!rtspc->in_header) { - /* If header parsing is done, extract interleaved RTP messages */ - if(data->req.size <= -1) { - /* Respect section 4.4 of rfc2326: If the Content-Length header is - absent, a length 0 must be assumed. */ - data->req.size = 0; - data->req.download_done = TRUE; - } - result = rtsp_filter_rtp(data, buf, blen, &consumed); + /* If header parsing is done and data left, extract RTP messages */ + in_body = (data->req.headerline && !rtspc->in_header) && + (data->req.size >= 0) && + (data->req.bytecount < data->req.size); + result = rtsp_filter_rtp(data, conn, buf, blen, in_body, &consumed); if(result) goto out; - blen -= consumed; + *pconsumed += consumed; } } if(rtspc->state != RTP_PARSE_SKIP) - data->req.done = FALSE; - /* we SHOULD have consumed all bytes, unless the response is borked. - * In which case we write out the left over bytes, letting the client - * writer deal with it (it will report EXCESS and fail the transfer). */ - DEBUGF(infof(data, "rtsp_rtp_write_resp(len=%zu, in_header=%d, done=%d " - " rtspc->state=%d, req.size=%" FMT_OFF_T ")", - blen, rtspc->in_header, data->req.done, rtspc->state, - data->req.size)); - if(!result && (is_eos || blen)) { - result = Curl_client_write(data, CLIENTWRITE_BODY| - (is_eos? CLIENTWRITE_EOS:0), - (char *)buf, blen); - } + *readmore = TRUE; out: - if((data->set.rtspreq == RTSPREQ_RECEIVE) && - (rtspc->state == RTP_PARSE_SKIP)) { + if(!*readmore && data->set.rtspreq == RTSPREQ_RECEIVE) { /* In special mode RECEIVE, we just process one chunk of network * data, so we stop the transfer here, if we have no incomplete * RTP message pending. */ - data->req.download_done = TRUE; + data->req.keepon &= ~KEEP_RECV; } return result; } @@ -915,12 +873,12 @@ CURLcode rtp_client_write(struct Curl_easy *data, const char *ptr, size_t len) return CURLE_OK; } -CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, const char *header) +CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, char *header) { if(checkprefix("CSeq:", header)) { long CSeq = 0; char *endp; - const char *p = &header[5]; + char *p = &header[5]; while(ISBLANK(*p)) p++; CSeq = strtol(p, &endp, 10); @@ -935,7 +893,8 @@ CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, const char *header) } } else if(checkprefix("Session:", header)) { - const char *start, *end; + char *start; + char *end; size_t idlen; /* Find the first non-space letter */ @@ -951,7 +910,7 @@ CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, const char *header) /* Find the end of Session ID * * Allow any non whitespace content, up to the field separator or end of - * line. RFC 2326 is not 100% clear on the session ID and for example + * line. RFC 2326 isn't 100% clear on the session ID and for example * gstreamer does url-encoded session ID's not covered by the standard. */ end = start; @@ -963,7 +922,7 @@ CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, const char *header) /* If the Session ID is set, then compare */ if(strlen(data->set.str[STRING_RTSP_SESSION_ID]) != idlen || - strncmp(start, data->set.str[STRING_RTSP_SESSION_ID], idlen)) { + strncmp(start, data->set.str[STRING_RTSP_SESSION_ID], idlen) != 0) { failf(data, "Got RTSP Session ID Line [%s], but wanted ID [%s]", start, data->set.str[STRING_RTSP_SESSION_ID]); return CURLE_RTSP_SESSION_ERROR; @@ -975,9 +934,11 @@ CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, const char *header) */ /* Copy the id substring into a new buffer */ - data->set.str[STRING_RTSP_SESSION_ID] = Curl_memdup0(start, idlen); + data->set.str[STRING_RTSP_SESSION_ID] = malloc(idlen + 1); if(!data->set.str[STRING_RTSP_SESSION_ID]) return CURLE_OUT_OF_MEMORY; + memcpy(data->set.str[STRING_RTSP_SESSION_ID], start, idlen); + (data->set.str[STRING_RTSP_SESSION_ID])[idlen] = '\0'; } } else if(checkprefix("Transport:", header)) { @@ -990,13 +951,14 @@ CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, const char *header) } static -CURLcode rtsp_parse_transport(struct Curl_easy *data, const char *transport) +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' */ - const char *start, *end; + char *start; + char *end; start = transport; while(start && *start) { while(*start && ISBLANK(*start) ) @@ -1005,7 +967,7 @@ CURLcode rtsp_parse_transport(struct Curl_easy *data, const char *transport) if(checkprefix("interleaved=", start)) { long chan1, chan2, chan; char *endp; - const char *p = start + 12; + 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; |