/** * If no filename is given to av_open_input_file because you want to * get the local port first, then you must call this function to set * the remote server address. * * @param s1 media file context * @param uri of the remote server * @return zero if no error. */ int rtp_set_remote_url(URLContext *h, const char *uri) { RTPContext *s = h->priv_data; char hostname[256]; int port; char buf[1024]; char path[1024]; url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, path, sizeof(path), uri); snprintf(buf, sizeof(buf), "udp://%s:%d%s", hostname, port, path); udp_set_remote_url(s->rtp_hd, buf); snprintf(buf, sizeof(buf), "udp://%s:%d%s", hostname, port + 1, path); udp_set_remote_url(s->rtcp_hd, buf); return 0; }
/* return non zero if error */ static int udp_open(URLContext *h, const char *uri, int flags) { char hostname[1024]; int port, udp_fd = -1, tmp, bind_ret = -1; UDPContext *s = NULL; int is_output; const char *p; char buf[256]; #if !CONFIG_IPV6 struct sockaddr_in my_addr; #else struct sockaddr_storage my_addr; #endif int len; h->is_streamed = 1; h->max_packet_size = 1472; is_output = (flags & URL_WRONLY); if(!ff_network_init()) return AVERROR(EIO); s = av_mallocz(sizeof(UDPContext)); if (!s) return AVERROR(ENOMEM); h->priv_data = s; s->ttl = 16; s->buffer_size = is_output ? UDP_TX_BUF_SIZE : UDP_MAX_PKT_SIZE; p = strchr(uri, '?'); if (p) { s->reuse_socket = find_info_tag(buf, sizeof(buf), "reuse", p); if (find_info_tag(buf, sizeof(buf), "ttl", p)) { s->ttl = strtol(buf, NULL, 10); } if (find_info_tag(buf, sizeof(buf), "localport", p)) { s->local_port = strtol(buf, NULL, 10); } if (find_info_tag(buf, sizeof(buf), "pkt_size", p)) { h->max_packet_size = strtol(buf, NULL, 10); } if (find_info_tag(buf, sizeof(buf), "buffer_size", p)) { s->buffer_size = strtol(buf, NULL, 10); } } /* fill the dest addr */ url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri); /* XXX: fix url_split */ if (hostname[0] == '\0' || hostname[0] == '?') { /* only accepts null hostname if input */ if (flags & URL_WRONLY) goto fail; } else { udp_set_remote_url(h, uri); } if (s->is_multicast && !(h->flags & URL_WRONLY)) s->local_port = port; udp_fd = udp_socket_create(s, &my_addr, &len); if (udp_fd < 0) goto fail; if (s->reuse_socket) if (setsockopt (udp_fd, SOL_SOCKET, SO_REUSEADDR, &(s->reuse_socket), sizeof(s->reuse_socket)) != 0) goto fail; /* the bind is needed to give a port to the socket now */ /* if multicast, try the multicast address bind first */ if (s->is_multicast && !(h->flags & URL_WRONLY)) { bind_ret = bind(udp_fd,(struct sockaddr *)&s->dest_addr, len); } /* bind to the local address if not multicast or if the multicast * bind failed */ if (bind_ret < 0 && bind(udp_fd,(struct sockaddr *)&my_addr, len) < 0) goto fail; len = sizeof(my_addr); getsockname(udp_fd, (struct sockaddr *)&my_addr, &len); s->local_port = udp_port(&my_addr, len); if (s->is_multicast) { if (h->flags & URL_WRONLY) { /* output */ if (udp_set_multicast_ttl(udp_fd, s->ttl, (struct sockaddr *)&s->dest_addr) < 0) goto fail; } else { /* input */ if (udp_join_multicast_group(udp_fd, (struct sockaddr *)&s->dest_addr) < 0) goto fail; } } if (is_output) { /* limit the tx buf size to limit latency */ tmp = s->buffer_size; if (setsockopt(udp_fd, SOL_SOCKET, SO_SNDBUF, &tmp, sizeof(tmp)) < 0) { av_log(NULL, AV_LOG_ERROR, "setsockopt(SO_SNDBUF): %s\n", strerror(errno)); goto fail; } } else { /* set udp recv buffer size to the largest possible udp packet size to * avoid losing data on OSes that set this too low by default. */ tmp = s->buffer_size; if (setsockopt(udp_fd, SOL_SOCKET, SO_RCVBUF, &tmp, sizeof(tmp)) < 0) { av_log(NULL, AV_LOG_WARNING, "setsockopt(SO_RECVBUF): %s\n", strerror(errno)); } /* make the socket non-blocking */ ff_socket_nonblock(udp_fd, 1); } s->udp_fd = udp_fd; return 0; fail: if (udp_fd >= 0) closesocket(udp_fd); av_free(s); return AVERROR(EIO); }
/* return non zero if error */ static int udp_open(URLContext *h, const char *uri, int flags) { char hostname[1024]; int port, udp_fd = -1, tmp; UDPContext *s = NULL; int is_output; const char *p; char buf[256]; #ifndef CONFIG_IPV6 struct sockaddr_in my_addr, my_addr1; int len; #endif h->is_streamed = 1; h->max_packet_size = 1472; is_output = (flags & URL_WRONLY); s = av_malloc(sizeof(UDPContext)); if (!s) return -ENOMEM; h->priv_data = s; s->ttl = 16; s->is_multicast = 0; s->local_port = 0; p = strchr(uri, '?'); if (p) { s->is_multicast = find_info_tag(buf, sizeof(buf), "multicast", p); if (find_info_tag(buf, sizeof(buf), "ttl", p)) { s->ttl = strtol(buf, NULL, 10); } if (find_info_tag(buf, sizeof(buf), "localport", p)) { s->local_port = strtol(buf, NULL, 10); } if (find_info_tag(buf, sizeof(buf), "pkt_size", p)) { h->max_packet_size = strtol(buf, NULL, 10); } } /* fill the dest addr */ url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri); /* XXX: fix url_split */ if (hostname[0] == '\0' || hostname[0] == '?') { /* only accepts null hostname if input */ if (s->is_multicast || (flags & URL_WRONLY)) goto fail; } else { udp_set_remote_url(h, uri); } #ifndef CONFIG_IPV6 udp_fd = socket(PF_INET, SOCK_DGRAM, 0); if (udp_fd < 0) goto fail; my_addr.sin_family = AF_INET; my_addr.sin_addr.s_addr = htonl (INADDR_ANY); if (s->is_multicast && !(h->flags & URL_WRONLY)) { /* special case: the bind must be done on the multicast address port */ my_addr.sin_port = s->dest_addr.sin_port; } else { my_addr.sin_port = htons(s->local_port); } /* the bind is needed to give a port to the socket now */ if (bind(udp_fd,(struct sockaddr *)&my_addr, sizeof(my_addr)) < 0) goto fail; len = sizeof(my_addr1); getsockname(udp_fd, (struct sockaddr *)&my_addr1, &len); s->local_port = ntohs(my_addr1.sin_port); #ifndef CONFIG_BEOS_NETSERVER if (s->is_multicast) { if (h->flags & URL_WRONLY) { /* output */ if (setsockopt(udp_fd, IPPROTO_IP, IP_MULTICAST_TTL, &s->ttl, sizeof(s->ttl)) < 0) { perror("IP_MULTICAST_TTL"); goto fail; } } else { /* input */ memset(&s->mreq, 0, sizeof(s->mreq)); s->mreq.imr_multiaddr = s->dest_addr.sin_addr; s->mreq.imr_interface.s_addr = htonl (INADDR_ANY); if (setsockopt(udp_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &s->mreq, sizeof(s->mreq)) < 0) { perror("rtp: IP_ADD_MEMBERSHIP"); goto fail; } } } #endif #else if (s->is_multicast && !(h->flags & URL_WRONLY)) s->local_port = port; udp_fd = udp_ipv6_set_local(h); if (udp_fd < 0) goto fail; #ifndef CONFIG_BEOS_NETSERVER if (s->is_multicast) { if (h->flags & URL_WRONLY) { if (udp_ipv6_set_multicast_ttl(udp_fd, s->ttl, (struct sockaddr *)&s->dest_addr) < 0) goto fail; } else { if (udp_ipv6_join_multicast_group(udp_fd, (struct sockaddr *)&s->dest_addr) < 0) goto fail; } } #endif #endif if (is_output) { /* limit the tx buf size to limit latency */ tmp = UDP_TX_BUF_SIZE; if (setsockopt(udp_fd, SOL_SOCKET, SO_SNDBUF, &tmp, sizeof(tmp)) < 0) { perror("setsockopt sndbuf"); goto fail; } } s->udp_fd = udp_fd; return 0; fail: if (udp_fd >= 0) #ifdef CONFIG_BEOS_NETSERVER closesocket(udp_fd); #else close(udp_fd); #endif av_free(s); return AVERROR_IO; }
int udp_open( hnd_t *p_handle, obe_udp_opts_t *udp_opts ) { int udp_fd = -1, tmp, bind_ret = -1; struct sockaddr_storage my_addr; int len; obe_udp_ctx *s = calloc( 1, sizeof(*s) ); *p_handle = NULL; if( !s ) return -1; strncpy( s->hostname, udp_opts->hostname, sizeof(s->hostname) ); s->port = udp_opts->port; s->local_port = udp_opts->local_port; s->reuse_socket = udp_opts->reuse_socket; s->ttl = udp_opts->ttl; s->buffer_size = udp_opts->buffer_size; s->miface = udp_opts->miface; if( udp_set_remote_url( s ) < 0 ) goto fail; udp_fd = udp_socket_create( s, &my_addr, &len ); if( udp_fd < 0 ) goto fail; if( s->reuse_socket || s->is_multicast ) { s->reuse_socket = 1; if( setsockopt( udp_fd, SOL_SOCKET, SO_REUSEADDR, &(s->reuse_socket), sizeof(s->reuse_socket) ) != 0) goto fail; } /* bind to the local address if not multicast or if the multicast * bind failed */ if( bind_ret < 0 && bind( udp_fd, (struct sockaddr *)&my_addr, len ) < 0 ) goto fail; len = sizeof(my_addr); getsockname( udp_fd, (struct sockaddr *)&my_addr, (socklen_t *) &len ); s->local_port = udp_port( &my_addr, len ); /* set output multicast ttl */ if( s->is_multicast && udp_set_multicast_opts( udp_fd, s ) < 0 ) goto fail; /* limit the tx buf size to limit latency */ tmp = s->buffer_size; if( setsockopt( udp_fd, SOL_SOCKET, SO_SNDBUF, &tmp, sizeof(tmp) ) < 0 ) goto fail; if( s->is_connected && connect( udp_fd, (struct sockaddr *)&s->dest_addr, s->dest_addr_len ) ) goto fail; s->udp_fd = udp_fd; *p_handle = s; return 0; fail: if( udp_fd >= 0 ) close( udp_fd ); free( s ); return -1; }
static int rtp_read(URLContext *h, uint8_t *buf, int size) { RTPContext *s = h->priv_data; struct sockaddr_in from; socklen_t from_len; int len, fd_max, n; fd_set rfds; #if 0 for(;;) { from_len = sizeof(from); len = recvfrom (s->rtp_fd, buf, size, 0, (struct sockaddr *)&from, &from_len); if (len < 0) { if (ff_neterrno() == FF_NETERROR(EAGAIN) || ff_neterrno() == FF_NETERROR(EINTR)) continue; return AVERROR(EIO); } break; } #else for(;;) { /* build fdset to listen to RTP and RTCP packets */ FD_ZERO(&rfds); fd_max = s->rtp_fd; FD_SET(s->rtp_fd, &rfds); if (s->rtcp_fd) { if (s->rtcp_fd > fd_max) fd_max = s->rtcp_fd; FD_SET(s->rtcp_fd, &rfds); } n = select(fd_max + 1, &rfds, NULL, NULL, NULL); if (n > 0) { /* first try RTCP */ if (FD_ISSET(s->rtcp_fd, &rfds)) { from_len = sizeof(from); len = recvfrom (s->rtcp_fd, buf, size, 0, (struct sockaddr *)&from, &from_len); if (len < 0) { if (ff_neterrno() == FF_NETERROR(EAGAIN) || ff_neterrno() == FF_NETERROR(EINTR)) continue; return AVERROR(EIO); } else { /* update remote rtcp address */ char buf[1024]; snprintf(buf, sizeof(buf), "udp://%s:%d", inet_ntoa(from.sin_addr), ntohs(from.sin_port)); udp_set_remote_url(s->rtcp_hd, buf); } break; } /* then RTP */ if (FD_ISSET(s->rtp_fd, &rfds)) { from_len = sizeof(from); len = recvfrom (s->rtp_fd, buf, size, 0, (struct sockaddr *)&from, &from_len); if (len < 0) { if (ff_neterrno() == FF_NETERROR(EAGAIN) || ff_neterrno() == FF_NETERROR(EINTR)) continue; return AVERROR(EIO); } else if (s->rtcp_hd) { /* update remote rtcp address (only if empty) */ typedef struct { int udp_fd; int ttl; int buffer_size; int is_multicast; int local_port; int reuse_socket; #if !CONFIG_IPV6 struct sockaddr_in dest_addr; #else struct sockaddr_storage dest_addr; #endif int dest_addr_len; } UDPContext; URLContext *hd = s->rtcp_hd; UDPContext *h = hd->priv_data; if (h->dest_addr.sin_addr.s_addr == 0) { char buf[1024]; snprintf(buf, sizeof(buf), "udp://%s:%d", inet_ntoa(from.sin_addr), ntohs(from.sin_port)+1); udp_set_remote_url(s->rtcp_hd, buf); } } break; } } } #endif return len; }