static int rtsp_send_reply(AVFormatContext *s, enum RTSPStatusCode code, const char *extracontent, uint16_t seq) { RTSPState *rt = s->priv_data; char message[4096]; int index = 0; while (status_messages[index].code) { if (status_messages[index].code == code) { snprintf(message, sizeof(message), "RTSP/1.0 %d %s\r\n", code, status_messages[index].message); break; } index++; } if (!status_messages[index].code) return AVERROR(EINVAL); av_strlcatf(message, sizeof(message), "CSeq: %d\r\n", seq); av_strlcatf(message, sizeof(message), "Server: %s\r\n", LIBAVFORMAT_IDENT); if (extracontent) av_strlcat(message, extracontent, sizeof(message)); av_strlcat(message, "\r\n", sizeof(message)); av_log(s, AV_LOG_TRACE, "Sending response:\n%s", message); ffurl_write(rt->rtsp_hd_out, message, strlen(message)); return 0; }
static int http_listen(URLContext *h, const char *uri, int flags, AVDictionary **options) { HTTPContext *s = h->priv_data; int ret; static const char header[] = "HTTP/1.1 200 OK\r\nContent-Type: application/octet-stream\r\nTransfer-Encoding: chunked\r\n\r\n"; char hostname[1024]; char lower_url[100]; int port, new_location; av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri); ff_url_join(lower_url, sizeof(lower_url), "tcp", NULL, hostname, port, NULL); av_dict_set(options, "listen", "1", 0); if ((ret = ffurl_open(&s->hd, lower_url, AVIO_FLAG_READ_WRITE, &h->interrupt_callback, options)) < 0) goto fail; if ((ret = ffurl_write(s->hd, header, strlen(header))) < 0) goto fail; if ((ret = http_read_header(h, &new_location)) < 0) goto fail; return 0; fail: av_dict_free(&s->chained_options); return ret; }
static int sap_write_close(AVFormatContext *s) { struct SAPState *sap = s->priv_data; int i; for (i = 0; i < s->nb_streams; i++) { AVFormatContext *rtpctx = s->streams[i]->priv_data; if (!rtpctx) continue; av_write_trailer(rtpctx); avio_close(rtpctx->pb); avformat_free_context(rtpctx); s->streams[i]->priv_data = NULL; } if (sap->last_time && sap->ann && sap->ann_fd) { sap->ann[0] |= 4; /* Session deletion*/ ffurl_write(sap->ann_fd, sap->ann, sap->ann_size); } av_freep(&sap->ann); if (sap->ann_fd) ffurl_close(sap->ann_fd); ff_network_close(); return 0; }
/** Send a prepared MMST command packet. */ static int send_command_packet(MMSTContext *mmst) { MMSContext *mms = &mmst->mms; int len= mms->write_out_ptr - mms->out_buffer; int exact_length = FFALIGN(len, 8); int first_length= exact_length - 16; int len8= first_length/8; int write_result; // update packet length fields. AV_WL32(mms->out_buffer + 8, first_length); AV_WL32(mms->out_buffer + 16, len8); AV_WL32(mms->out_buffer + 32, len8-2); memset(mms->write_out_ptr, 0, exact_length - len); // write it out. write_result= ffurl_write(mms->mms_hd, mms->out_buffer, exact_length); if(write_result != exact_length) { av_log(NULL, AV_LOG_ERROR, "Failed to write data of length %d: %d (%s)\n", exact_length, write_result, write_result < 0 ? strerror(AVUNERROR(write_result)) : "The server closed the connection"); return AVERROR(EIO); } return 0; }
static int rtp_write(URLContext *h, const uint8_t *buf, int size) { RTPContext *s = h->priv_data; int ret; URLContext *hd; if (buf[1] >= RTCP_SR && buf[1] <= RTCP_APP) { /* RTCP payload type */ hd = s->rtcp_hd; } else { /* RTP payload type */ hd = s->rtp_hd; } ret = ffurl_write(hd, buf, size); #if 0 { struct timespec ts; ts.tv_sec = 0; ts.tv_nsec = 10 * 1000000; nanosleep(&ts, NULL); } #endif return ret; }
static int tls_write(URLContext *h, const uint8_t *buf, int len) { TLSContext *c = h->priv_data; TLSShared *s = &c->tls_shared; SECURITY_STATUS sspi_ret; int ret = 0, data_size; uint8_t *data = NULL; SecBuffer outbuf[4]; SecBufferDesc outbuf_desc; if (c->sizes.cbMaximumMessage == 0) { sspi_ret = QueryContextAttributes(&c->ctxt_handle, SECPKG_ATTR_STREAM_SIZES, &c->sizes); if (sspi_ret != SEC_E_OK) return AVERROR_UNKNOWN; } /* limit how much data we can consume */ len = FFMIN(len, c->sizes.cbMaximumMessage); data_size = c->sizes.cbHeader + len + c->sizes.cbTrailer; data = av_malloc(data_size); if (data == NULL) return AVERROR(ENOMEM); init_sec_buffer(&outbuf[0], SECBUFFER_STREAM_HEADER, data, c->sizes.cbHeader); init_sec_buffer(&outbuf[1], SECBUFFER_DATA, data + c->sizes.cbHeader, len); init_sec_buffer(&outbuf[2], SECBUFFER_STREAM_TRAILER, data + c->sizes.cbHeader + len, c->sizes.cbTrailer); init_sec_buffer(&outbuf[3], SECBUFFER_EMPTY, NULL, 0); init_sec_buffer_desc(&outbuf_desc, outbuf, 4); memcpy(outbuf[1].pvBuffer, buf, len); sspi_ret = EncryptMessage(&c->ctxt_handle, 0, &outbuf_desc, 0); if (sspi_ret == SEC_E_OK) { len = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer; ret = ffurl_write(s->tcp, data, len); if (ret < 0 || ret != len) { ret = AVERROR(EIO); av_log(h, AV_LOG_ERROR, "Writing encrypted data to socket failed\n"); goto done; } } else { av_log(h, AV_LOG_ERROR, "Encrypting data failed\n"); if (sspi_ret == SEC_E_INSUFFICIENT_MEMORY) ret = AVERROR(ENOMEM); else ret = AVERROR(EIO); goto done; } done: av_freep(&data); return ret < 0 ? ret : outbuf[1].cbBuffer; }
/**************************************************************************************************************** * Function: DSWrite * Desc: Writes data to the connection * Params: * h - Pointer to URLContext struct used to store all connection info associated with this connection * buf - Buffer from which data will be written * size - Number of bytes to write from buf * Return: * 0 on success, non 0 on failure ****************************************************************************************************************/ static int DSWrite( URLContext *h, const uint8_t *buf, int size ) { /* All we need to do in here is call the generic write function on our underlying TCP connection */ DSContext * context = (DSContext *)h->priv_data; if( context != NULL ) return ffurl_write( context->TCPContext, buf, size ); return AVERROR(EIO); }
static int url_bio_bwrite(BIO *b, const char *buf, int len) { URLContext *h = b->ptr; int ret = ffurl_write(h, buf, len); if (ret >= 0) return ret; BIO_clear_retry_flags(b); if (ret == AVERROR_EXIT) return 0; return -1; }
static ssize_t gnutls_url_push(gnutls_transport_ptr_t transport, const void *buf, size_t len) { URLContext *h = (URLContext*) transport; int ret = ffurl_write(h, buf, len); if (ret >= 0) return ret; if (ret == AVERROR_EXIT) return 0; errno = EIO; return -1; }
static int url_bio_bwrite(BIO *b, const char *buf, int len) { URLContext *h = GET_BIO_DATA(b); int ret = ffurl_write(h, buf, len); if (ret >= 0) return ret; BIO_clear_retry_flags(b); if (ret == AVERROR(EAGAIN)) BIO_set_retry_write(b); if (ret == AVERROR_EXIT) return 0; return -1; }
void ff_rtp_send_punch_packets(URLContext *rtp_handle) { AVIOContext *pb; uint8_t *buf; int len; /* Send a small RTP packet */ if (avio_open_dyn_buf(&pb) < 0) return; avio_w8(pb, (RTP_VERSION << 6)); avio_w8(pb, 0); /* Payload type */ avio_wb16(pb, 0); /* Seq */ avio_wb32(pb, 0); /* Timestamp */ avio_wb32(pb, 0); /* SSRC */ avio_flush(pb); len = avio_close_dyn_buf(pb, &buf); if ((len > 0) && buf) ffurl_write(rtp_handle, buf, len); av_free(buf); /* Send a minimal RTCP RR */ if (avio_open_dyn_buf(&pb) < 0) return; avio_w8(pb, (RTP_VERSION << 6)); avio_w8(pb, RTCP_RR); /* receiver report */ avio_wb16(pb, 1); /* length in words - 1 */ avio_wb32(pb, 0); /* our own SSRC */ avio_flush(pb); len = avio_close_dyn_buf(pb, &buf); if ((len > 0) && buf) ffurl_write(rtp_handle, buf, len); av_free(buf); }
static int rtmpe_write(URLContext *h, const uint8_t *buf, int size) { RTMPEContext *rt = h->priv_data; int ret; if (rt->handshaked) { /* encrypt data to send to the server */ av_rc4_crypt(&rt->key_out, buf, buf, size, NULL, 1); } if ((ret = ffurl_write(rt->stream, buf, size)) < 0) return ret; return size; }
static int http_shutdown(URLContext *h, int flags) { int ret = 0; char footer[] = "0\r\n\r\n"; HTTPContext *s = h->priv_data; /* signal end of chunked encoding if used */ if ((flags & AVIO_FLAG_WRITE) && s->chunked_post) { ret = ffurl_write(s->hd, footer, sizeof(footer) - 1); ret = ret > 0 ? 0 : ret; s->end_chunked_post = 1; } return ret; }
static int ftp_send_command(FTPContext *s, const char *command, const int response_codes[], char **response) { int err; if ((err = ffurl_write(s->conn_control, command, strlen(command))) < 0) return err; if (!err) return -1; /* return status */ if (response_codes) { return ftp_status(s, response, response_codes); } return 0; }
static int sap_write_packet(AVFormatContext *s, AVPacket *pkt) { AVFormatContext *rtpctx; struct SAPState *sap = s->priv_data; int64_t now = av_gettime(); if (!sap->last_time || now - sap->last_time > 5000000) { int ret = ffurl_write(sap->ann_fd, sap->ann, sap->ann_size); /* Don't abort even if we get "Destination unreachable" */ if (ret < 0 && ret != AVERROR(ECONNREFUSED)) return ret; sap->last_time = now; } rtpctx = s->streams[pkt->stream_index]->priv_data; return ff_write_chained(rtpctx, 0, pkt, s); }
static int rtp_write(URLContext *h, const uint8_t *buf, int size) { RTPContext *s = h->priv_data; int ret; URLContext *hd; if (RTP_PT_IS_RTCP(buf[1])) { /* RTCP payload type */ hd = s->rtcp_hd; } else { /* RTP payload type */ hd = s->rtp_hd; } ret = ffurl_write(hd, buf, size); return ret; }
static OSStatus tls_write_cb(SSLConnectionRef connection, const void *data, size_t *dataLength) { URLContext *h = (URLContext*)connection; TLSContext *c = h->priv_data; int written = ffurl_write(c->tls_shared.tcp, data, *dataLength); if (written <= 0) { *dataLength = 0; switch(AVUNERROR(written)) { case EAGAIN: return errSSLWouldBlock; default: c->lastErr = written; return ioErr; } } else { *dataLength = written; return noErr; } }
static int crypto_close(URLContext *h) { CryptoContext *c = h->priv_data; uint8_t out_buf[BLOCKSIZE]; int ret, pad; if (c->aes_encrypt) { pad = BLOCKSIZE - c->pad_len; memset(&c->pad[c->pad_len], pad, pad); av_aes_crypt(c->aes_encrypt, out_buf, c->pad, 1, c->encrypt_iv, 0); if ((ret = ffurl_write(c->hd, out_buf, BLOCKSIZE)) < 0) return ret; } if (c->hd) ffurl_close(c->hd); av_freep(&c->aes_decrypt); av_freep(&c->aes_encrypt); return 0; }
static int crypto_write(URLContext *h, const unsigned char *buf, int size) { CryptoContext *c = h->priv_data; int total_size, blocks, pad_len, out_size; uint8_t *out_buf; int ret = 0; total_size = size + c->pad_len; pad_len = total_size % BLOCKSIZE; out_size = total_size - pad_len; blocks = out_size / BLOCKSIZE; if (out_size) { out_buf = av_malloc(out_size); if (!out_buf) return AVERROR(ENOMEM); if (c->pad_len) { memcpy(&c->pad[c->pad_len], buf, BLOCKSIZE - c->pad_len); av_aes_crypt(c->aes_encrypt, out_buf, c->pad, 1, c->encrypt_iv, 0); blocks--; } av_aes_crypt(c->aes_encrypt, &out_buf[c->pad_len ? BLOCKSIZE : 0], &buf[c->pad_len ? BLOCKSIZE - c->pad_len: 0], blocks, c->encrypt_iv, 0); ret = ffurl_write(c->hd, out_buf, out_size); av_free(out_buf); if (ret < 0) return ret; memcpy(c->pad, &buf[size - pad_len], pad_len); } else memcpy(&c->pad[c->pad_len], buf, size); c->pad_len = pad_len; return size; }
static int tls_client_handshake(URLContext *h) { TLSContext *c = h->priv_data; TLSShared *s = &c->tls_shared; SecBuffer outbuf; SecBufferDesc outbuf_desc; SECURITY_STATUS sspi_ret; int ret; init_sec_buffer(&outbuf, SECBUFFER_EMPTY, NULL, 0); init_sec_buffer_desc(&outbuf_desc, &outbuf, 1); c->request_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT | ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM; sspi_ret = InitializeSecurityContext(&c->cred_handle, NULL, s->host, c->request_flags, 0, 0, NULL, 0, &c->ctxt_handle, &outbuf_desc, &c->context_flags, &c->ctxt_timestamp); if (sspi_ret != SEC_I_CONTINUE_NEEDED) { av_log(h, AV_LOG_ERROR, "Unable to create initial security context (0x%lx)\n", sspi_ret); ret = AVERROR_UNKNOWN; goto fail; } ret = ffurl_write(s->tcp, outbuf.pvBuffer, outbuf.cbBuffer); FreeContextBuffer(outbuf.pvBuffer); if (ret < 0 || ret != outbuf.cbBuffer) { av_log(h, AV_LOG_ERROR, "Failed to send initial handshake data\n"); ret = AVERROR(EIO); goto fail; } return tls_client_handshake_loop(h, 1); fail: DeleteSecurityContext(&c->ctxt_handle); return ret; }
static int tls_shutdown_client(URLContext *h) { TLSContext *c = h->priv_data; TLSShared *s = &c->tls_shared; int ret; if (c->connected) { SecBufferDesc BuffDesc; SecBuffer Buffer; SECURITY_STATUS sspi_ret; SecBuffer outbuf; SecBufferDesc outbuf_desc; DWORD dwshut = SCHANNEL_SHUTDOWN; init_sec_buffer(&Buffer, SECBUFFER_TOKEN, &dwshut, sizeof(dwshut)); init_sec_buffer_desc(&BuffDesc, &Buffer, 1); sspi_ret = ApplyControlToken(&c->ctxt_handle, &BuffDesc); if (sspi_ret != SEC_E_OK) av_log(h, AV_LOG_ERROR, "ApplyControlToken failed\n"); init_sec_buffer(&outbuf, SECBUFFER_EMPTY, NULL, 0); init_sec_buffer_desc(&outbuf_desc, &outbuf, 1); sspi_ret = InitializeSecurityContext(&c->cred_handle, &c->ctxt_handle, s->host, c->request_flags, 0, 0, NULL, 0, &c->ctxt_handle, &outbuf_desc, &c->context_flags, &c->ctxt_timestamp); if (sspi_ret == SEC_E_OK || sspi_ret == SEC_I_CONTEXT_EXPIRED) { ret = ffurl_write(s->tcp, outbuf.pvBuffer, outbuf.cbBuffer); FreeContextBuffer(outbuf.pvBuffer); if (ret < 0 || ret != outbuf.cbBuffer) av_log(h, AV_LOG_ERROR, "Failed to send close message\n"); } c->connected = 0; } return 0; }
static int tcp_write_packet(AVFormatContext *s, RTSPStream *rtsp_st) { RTSPState *rt = s->priv_data; AVFormatContext *rtpctx = rtsp_st->transport_priv; uint8_t *buf, *ptr; int size; uint8_t *interleave_header, *interleaved_packet; size = avio_close_dyn_buf(rtpctx->pb, &buf); ptr = buf; while (size > 4) { uint32_t packet_len = AV_RB32(ptr); int id; /* The interleaving header is exactly 4 bytes, which happens to be * the same size as the packet length header from * ffio_open_dyn_packet_buf. So by writing the interleaving header * over these bytes, we get a consecutive interleaved packet * that can be written in one call. */ interleaved_packet = interleave_header = ptr; ptr += 4; size -= 4; if (packet_len > size || packet_len < 2) break; if (ptr[1] >= RTCP_SR && ptr[1] <= RTCP_APP) id = rtsp_st->interleaved_max; /* RTCP */ else id = rtsp_st->interleaved_min; /* RTP */ interleave_header[0] = '$'; interleave_header[1] = id; AV_WB16(interleave_header + 2, packet_len); ffurl_write(rt->rtsp_hd_out, interleaved_packet, 4 + packet_len); ptr += packet_len; size -= packet_len; } av_free(buf); ffio_open_dyn_packet_buf(&rtpctx->pb, RTSP_TCP_MAX_PACKET_SIZE); return 0; }
static int tls_client_handshake_loop(URLContext *h, int initial) { TLSContext *c = h->priv_data; TLSShared *s = &c->tls_shared; SECURITY_STATUS sspi_ret; SecBuffer outbuf[3]; SecBufferDesc outbuf_desc; SecBuffer inbuf[2]; SecBufferDesc inbuf_desc; int i, ret = 0, read_data = initial; if (c->enc_buf == NULL) { c->enc_buf_offset = 0; ret = av_reallocp(&c->enc_buf, SCHANNEL_INITIAL_BUFFER_SIZE); if (ret < 0) goto fail; c->enc_buf_size = SCHANNEL_INITIAL_BUFFER_SIZE; } if (c->dec_buf == NULL) { c->dec_buf_offset = 0; ret = av_reallocp(&c->dec_buf, SCHANNEL_INITIAL_BUFFER_SIZE); if (ret < 0) goto fail; c->dec_buf_size = SCHANNEL_INITIAL_BUFFER_SIZE; } while (1) { if (c->enc_buf_size - c->enc_buf_offset < SCHANNEL_FREE_BUFFER_SIZE) { c->enc_buf_size = c->enc_buf_offset + SCHANNEL_FREE_BUFFER_SIZE; ret = av_reallocp(&c->enc_buf, c->enc_buf_size); if (ret < 0) { c->enc_buf_size = c->enc_buf_offset = 0; goto fail; } } if (read_data) { ret = ffurl_read(c->tls_shared.tcp, c->enc_buf + c->enc_buf_offset, c->enc_buf_size - c->enc_buf_offset); if (ret < 0) { av_log(h, AV_LOG_ERROR, "Failed to read handshake response\n"); goto fail; } c->enc_buf_offset += ret; } /* input buffers */ init_sec_buffer(&inbuf[0], SECBUFFER_TOKEN, av_malloc(c->enc_buf_offset), c->enc_buf_offset); init_sec_buffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0); init_sec_buffer_desc(&inbuf_desc, inbuf, 2); if (inbuf[0].pvBuffer == NULL) { av_log(h, AV_LOG_ERROR, "Failed to allocate input buffer\n"); ret = AVERROR(ENOMEM); goto fail; } memcpy(inbuf[0].pvBuffer, c->enc_buf, c->enc_buf_offset); /* output buffers */ init_sec_buffer(&outbuf[0], SECBUFFER_TOKEN, NULL, 0); init_sec_buffer(&outbuf[1], SECBUFFER_ALERT, NULL, 0); init_sec_buffer(&outbuf[2], SECBUFFER_EMPTY, NULL, 0); init_sec_buffer_desc(&outbuf_desc, outbuf, 3); sspi_ret = InitializeSecurityContext(&c->cred_handle, &c->ctxt_handle, s->host, c->request_flags, 0, 0, &inbuf_desc, 0, NULL, &outbuf_desc, &c->context_flags, &c->ctxt_timestamp); av_freep(&inbuf[0].pvBuffer); if (sspi_ret == SEC_E_INCOMPLETE_MESSAGE) { av_log(h, AV_LOG_DEBUG, "Received incomplete handshake, need more data\n"); read_data = 1; continue; } /* remote requests a client certificate - attempt to continue without one anyway */ if (sspi_ret == SEC_I_INCOMPLETE_CREDENTIALS && !(c->request_flags & ISC_REQ_USE_SUPPLIED_CREDS)) { av_log(h, AV_LOG_VERBOSE, "Client certificate has been requested, ignoring\n"); c->request_flags |= ISC_REQ_USE_SUPPLIED_CREDS; read_data = 0; continue; } /* continue handshake */ if (sspi_ret == SEC_I_CONTINUE_NEEDED || sspi_ret == SEC_E_OK) { for (i = 0; i < 3; i++) { if (outbuf[i].BufferType == SECBUFFER_TOKEN && outbuf[i].cbBuffer > 0) { ret = ffurl_write(c->tls_shared.tcp, outbuf[i].pvBuffer, outbuf[i].cbBuffer); if (ret < 0 || ret != outbuf[i].cbBuffer) { av_log(h, AV_LOG_VERBOSE, "Failed to send handshake data\n"); ret = AVERROR(EIO); goto fail; } } if (outbuf[i].pvBuffer != NULL) { FreeContextBuffer(outbuf[i].pvBuffer); outbuf[i].pvBuffer = NULL; } } } else { if (sspi_ret == SEC_E_WRONG_PRINCIPAL) av_log(h, AV_LOG_ERROR, "SNI or certificate check failed\n"); else av_log(h, AV_LOG_ERROR, "Creating security context failed (0x%lx)\n", sspi_ret); ret = AVERROR_UNKNOWN; goto fail; } if (inbuf[1].BufferType == SECBUFFER_EXTRA && inbuf[1].cbBuffer > 0) { if (c->enc_buf_offset > inbuf[1].cbBuffer) { memmove(c->enc_buf, (c->enc_buf + c->enc_buf_offset) - inbuf[1].cbBuffer, inbuf[1].cbBuffer); c->enc_buf_offset = inbuf[1].cbBuffer; if (sspi_ret == SEC_I_CONTINUE_NEEDED) { read_data = 0; continue; } } } else { c->enc_buf_offset = 0; } if (sspi_ret == SEC_I_CONTINUE_NEEDED) { read_data = 1; continue; } break; } return 0; fail: /* free any remaining output data */ for (i = 0; i < 3; i++) { if (outbuf[i].pvBuffer != NULL) { FreeContextBuffer(outbuf[i].pvBuffer); outbuf[i].pvBuffer = NULL; } } return ret; }
int url_write(URLContext *h, const unsigned char *buf, int size) { return ffurl_write(h, buf, size); }
static int rtp_write(URLContext *h, const uint8_t *buf, int size) { RTPContext *s = h->priv_data; int ret; URLContext *hd; if (size < 2) return AVERROR(EINVAL); if (s->write_to_source) { int fd; struct sockaddr_storage *source, temp_source; socklen_t *source_len, temp_len; if (!s->last_rtp_source.ss_family && !s->last_rtcp_source.ss_family) { av_log(h, AV_LOG_ERROR, "Unable to send packet to source, no packets received yet\n"); // Intentionally not returning an error here return size; } if (RTP_PT_IS_RTCP(buf[1])) { fd = s->rtcp_fd; source = &s->last_rtcp_source; source_len = &s->last_rtcp_source_len; } else { fd = s->rtp_fd; source = &s->last_rtp_source; source_len = &s->last_rtp_source_len; } if (!source->ss_family) { source = &temp_source; source_len = &temp_len; if (RTP_PT_IS_RTCP(buf[1])) { temp_source = s->last_rtp_source; temp_len = s->last_rtp_source_len; set_port(source, get_port(source) + 1); av_log(h, AV_LOG_INFO, "Not received any RTCP packets yet, inferring peer port " "from the RTP port\n"); } else { temp_source = s->last_rtcp_source; temp_len = s->last_rtcp_source_len; set_port(source, get_port(source) - 1); av_log(h, AV_LOG_INFO, "Not received any RTP packets yet, inferring peer port " "from the RTCP port\n"); } } if (!(h->flags & AVIO_FLAG_NONBLOCK)) { ret = ff_network_wait_fd(fd, 1); if (ret < 0) return ret; } ret = sendto(fd, buf, size, 0, (struct sockaddr *) source, *source_len); return ret < 0 ? ff_neterrno() : ret; } if (RTP_PT_IS_RTCP(buf[1])) { /* RTCP payload type */ hd = s->rtcp_hd; } else { /* RTP payload type */ hd = s->rtp_hd; } ret = ffurl_write(hd, buf, size); return ret; }
int ff_rtp_check_and_send_back_rr(RTPDemuxContext *s, int count) { AVIOContext *pb; uint8_t *buf; int len; int rtcp_bytes; RTPStatistics *stats = &s->statistics; uint32_t lost; uint32_t extended_max; uint32_t expected_interval; uint32_t received_interval; uint32_t lost_interval; uint32_t expected; uint32_t fraction; uint64_t ntp_time = s->last_rtcp_ntp_time; // TODO: Get local ntp time? if (!s->rtp_ctx || (count < 1)) return -1; /* TODO: I think this is way too often; RFC 1889 has algorithm for this */ /* XXX: MPEG pts hardcoded. RTCP send every 0.5 seconds */ s->octet_count += count; rtcp_bytes = ((s->octet_count - s->last_octet_count) * RTCP_TX_RATIO_NUM) / RTCP_TX_RATIO_DEN; rtcp_bytes /= 50; // mmu_man: that's enough for me... VLC sends much less btw !? if (rtcp_bytes < 28) return -1; s->last_octet_count = s->octet_count; if (avio_open_dyn_buf(&pb) < 0) return -1; // Receiver Report avio_w8(pb, (RTP_VERSION << 6) + 1); /* 1 report block */ avio_w8(pb, RTCP_RR); avio_wb16(pb, 7); /* length in words - 1 */ // our own SSRC: we use the server's SSRC + 1 to avoid conflicts avio_wb32(pb, s->ssrc + 1); avio_wb32(pb, s->ssrc); // server SSRC // some placeholders we should really fill... // RFC 1889/p64 extended_max = stats->cycles + stats->max_seq; expected = extended_max - stats->base_seq + 1; lost = expected - stats->received; lost = FFMIN(lost, 0xffffff); // clamp it since it's only 24 bits... expected_interval = expected - stats->expected_prior; stats->expected_prior = expected; received_interval = stats->received - stats->received_prior; stats->received_prior = stats->received; lost_interval = expected_interval - received_interval; if (expected_interval == 0 || lost_interval <= 0) fraction = 0; else fraction = (lost_interval << 8) / expected_interval; fraction = (fraction << 24) | lost; avio_wb32(pb, fraction); /* 8 bits of fraction, 24 bits of total packets lost */ avio_wb32(pb, extended_max); /* max sequence received */ avio_wb32(pb, stats->jitter >> 4); /* jitter */ if (s->last_rtcp_ntp_time == AV_NOPTS_VALUE) { avio_wb32(pb, 0); /* last SR timestamp */ avio_wb32(pb, 0); /* delay since last SR */ } else { uint32_t middle_32_bits = s->last_rtcp_ntp_time >> 16; // this is valid, right? do we need to handle 64 bit values special? uint32_t delay_since_last = ntp_time - s->last_rtcp_ntp_time; avio_wb32(pb, middle_32_bits); /* last SR timestamp */ avio_wb32(pb, delay_since_last); /* delay since last SR */ } // CNAME avio_w8(pb, (RTP_VERSION << 6) + 1); /* 1 report block */ avio_w8(pb, RTCP_SDES); len = strlen(s->hostname); avio_wb16(pb, (6 + len + 3) / 4); /* length in words - 1 */ avio_wb32(pb, s->ssrc + 1); avio_w8(pb, 0x01); avio_w8(pb, len); avio_write(pb, s->hostname, len); // padding for (len = (6 + len) % 4; len % 4; len++) avio_w8(pb, 0); avio_flush(pb); len = avio_close_dyn_buf(pb, &buf); if ((len > 0) && buf) { int av_unused result; av_dlog(s->ic, "sending %d bytes of RR\n", len); result = ffurl_write(s->rtp_ctx, buf, len); av_dlog(s->ic, "result from ffurl_write: %d\n", result); av_free(buf); } return 0; }
int ff_rtmp_packet_write(URLContext *h, RTMPPacket *pkt, int chunk_size, RTMPPacket *prev_pkt) { uint8_t pkt_hdr[16], *p = pkt_hdr; int mode = RTMP_PS_TWELVEBYTES; int off = 0; int size = 0; pkt->ts_delta = pkt->timestamp - prev_pkt[pkt->channel_id].timestamp; //if channel_id = 0, this is first presentation of prev_pkt, send full hdr. if (prev_pkt[pkt->channel_id].channel_id && pkt->extra == prev_pkt[pkt->channel_id].extra) { if (pkt->type == prev_pkt[pkt->channel_id].type && pkt->data_size == prev_pkt[pkt->channel_id].data_size) { mode = RTMP_PS_FOURBYTES; if (pkt->ts_delta == prev_pkt[pkt->channel_id].ts_delta) mode = RTMP_PS_ONEBYTE; } else { mode = RTMP_PS_EIGHTBYTES; } } if (pkt->channel_id < 64) { bytestream_put_byte(&p, pkt->channel_id | (mode << 6)); } else if (pkt->channel_id < 64 + 256) { bytestream_put_byte(&p, 0 | (mode << 6)); bytestream_put_byte(&p, pkt->channel_id - 64); } else { bytestream_put_byte(&p, 1 | (mode << 6)); bytestream_put_le16(&p, pkt->channel_id - 64); } if (mode != RTMP_PS_ONEBYTE) { uint32_t timestamp = pkt->timestamp; if (mode != RTMP_PS_TWELVEBYTES) timestamp = pkt->ts_delta; bytestream_put_be24(&p, timestamp >= 0xFFFFFF ? 0xFFFFFF : timestamp); if (mode != RTMP_PS_FOURBYTES) { bytestream_put_be24(&p, pkt->data_size); bytestream_put_byte(&p, pkt->type); if (mode == RTMP_PS_TWELVEBYTES) bytestream_put_le32(&p, pkt->extra); } if (timestamp >= 0xFFFFFF) bytestream_put_be32(&p, timestamp); } // save history prev_pkt[pkt->channel_id].channel_id = pkt->channel_id; prev_pkt[pkt->channel_id].type = pkt->type; prev_pkt[pkt->channel_id].data_size = pkt->data_size; prev_pkt[pkt->channel_id].timestamp = pkt->timestamp; if (mode != RTMP_PS_TWELVEBYTES) { prev_pkt[pkt->channel_id].ts_delta = pkt->ts_delta; } else { prev_pkt[pkt->channel_id].ts_delta = pkt->timestamp; } prev_pkt[pkt->channel_id].extra = pkt->extra; ffurl_write(h, pkt_hdr, p-pkt_hdr); size = p - pkt_hdr + pkt->data_size; while (off < pkt->data_size) { int towrite = FFMIN(chunk_size, pkt->data_size - off); ffurl_write(h, pkt->data + off, towrite); off += towrite; if (off < pkt->data_size) { uint8_t marker = 0xC0 | pkt->channel_id; ffurl_write(h, &marker, 1); size++; } } return size; }
static int gopher_write(URLContext *h, const uint8_t *buf, int size) { GopherContext *s = h->priv_data; return ffurl_write(s->hd, buf, size); }
static int http_proxy_write(URLContext *h, const uint8_t *buf, int size) { HTTPContext *s = h->priv_data; return ffurl_write(s->hd, buf, size); }
static int http_connect(URLContext *h, const char *path, const char *local_path, const char *hoststr, const char *auth, const char *proxyauth, int *new_location) { HTTPContext *s = h->priv_data; int post, err; char headers[HTTP_HEADERS_SIZE] = ""; char *authstr = NULL, *proxyauthstr = NULL; int64_t off = s->off; int len = 0; const char *method; int send_expect_100 = 0; /* send http header */ post = h->flags & AVIO_FLAG_WRITE; if (s->post_data) { /* force POST method and disable chunked encoding when * custom HTTP post data is set */ post = 1; s->chunked_post = 0; } if (s->method) method = s->method; else method = post ? "POST" : "GET"; authstr = ff_http_auth_create_response(&s->auth_state, auth, local_path, method); proxyauthstr = ff_http_auth_create_response(&s->proxy_auth_state, proxyauth, local_path, method); if (post && !s->post_data) { send_expect_100 = s->send_expect_100; /* The user has supplied authentication but we don't know the auth type, * send Expect: 100-continue to get the 401 response including the * WWW-Authenticate header, or an 100 continue if no auth actually * is needed. */ if (auth && *auth && s->auth_state.auth_type == HTTP_AUTH_NONE && s->http_code != 401) send_expect_100 = 1; } /* set default headers if needed */ if (!has_header(s->headers, "\r\nUser-Agent: ")) len += av_strlcatf(headers + len, sizeof(headers) - len, "User-Agent: %s\r\n", s->user_agent); if (!has_header(s->headers, "\r\nAccept: ")) len += av_strlcpy(headers + len, "Accept: */*\r\n", sizeof(headers) - len); // Note: we send this on purpose even when s->off is 0 when we're probing, // since it allows us to detect more reliably if a (non-conforming) // server supports seeking by analysing the reply headers. if (!has_header(s->headers, "\r\nRange: ") && !post && (s->off > 0 || s->end_off || s->seekable == -1)) { len += av_strlcatf(headers + len, sizeof(headers) - len, "Range: bytes=%"PRId64"-", s->off); if (s->end_off) len += av_strlcatf(headers + len, sizeof(headers) - len, "%"PRId64, s->end_off - 1); len += av_strlcpy(headers + len, "\r\n", sizeof(headers) - len); } if (send_expect_100 && !has_header(s->headers, "\r\nExpect: ")) len += av_strlcatf(headers + len, sizeof(headers) - len, "Expect: 100-continue\r\n"); if (!has_header(s->headers, "\r\nConnection: ")) { if (s->multiple_requests) len += av_strlcpy(headers + len, "Connection: keep-alive\r\n", sizeof(headers) - len); else len += av_strlcpy(headers + len, "Connection: close\r\n", sizeof(headers) - len); } if (!has_header(s->headers, "\r\nHost: ")) len += av_strlcatf(headers + len, sizeof(headers) - len, "Host: %s\r\n", hoststr); if (!has_header(s->headers, "\r\nContent-Length: ") && s->post_data) len += av_strlcatf(headers + len, sizeof(headers) - len, "Content-Length: %d\r\n", s->post_datalen); if (!has_header(s->headers, "\r\nContent-Type: ") && s->content_type) len += av_strlcatf(headers + len, sizeof(headers) - len, "Content-Type: %s\r\n", s->content_type); if (!has_header(s->headers, "\r\nCookie: ") && s->cookies) { char *cookies = NULL; if (!get_cookies(s, &cookies, path, hoststr) && cookies) { len += av_strlcatf(headers + len, sizeof(headers) - len, "Cookie: %s\r\n", cookies); av_free(cookies); } } if (!has_header(s->headers, "\r\nIcy-MetaData: ") && s->icy) len += av_strlcatf(headers + len, sizeof(headers) - len, "Icy-MetaData: %d\r\n", 1); /* now add in custom headers */ if (s->headers) av_strlcpy(headers + len, s->headers, sizeof(headers) - len); snprintf(s->buffer, sizeof(s->buffer), "%s %s HTTP/1.1\r\n" "%s" "%s" "%s" "%s%s" "\r\n", method, path, post && s->chunked_post ? "Transfer-Encoding: chunked\r\n" : "", headers, authstr ? authstr : "", proxyauthstr ? "Proxy-" : "", proxyauthstr ? proxyauthstr : ""); av_log(h, AV_LOG_DEBUG, "request: %s\n", s->buffer); if ((err = ffurl_write(s->hd, s->buffer, strlen(s->buffer))) < 0) goto done; if (s->post_data) if ((err = ffurl_write(s->hd, s->post_data, s->post_datalen)) < 0) goto done; /* init input buffer */ s->buf_ptr = s->buffer; s->buf_end = s->buffer; s->line_count = 0; s->off = 0; s->icy_data_read = 0; s->filesize = -1; s->willclose = 0; s->end_chunked_post = 0; s->end_header = 0; if (post && !s->post_data && !send_expect_100) { /* Pretend that it did work. We didn't read any header yet, since * we've still to send the POST data, but the code calling this * function will check http_code after we return. */ s->http_code = 200; err = 0; goto done; } /* wait for header */ err = http_read_header(h, new_location); if (err < 0) goto done; if (*new_location) s->off = off; err = (off == s->off) ? 0 : -1; done: av_freep(&authstr); av_freep(&proxyauthstr); return err; }