static int socket_open_listen(struct sockaddr_in *my_addr) { int server_fd, tmp; server_fd = socket(AF_INET,SOCK_STREAM,0); if (server_fd < 0) { perror ("socket"); return -1; } tmp = 1; if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp))) av_log(NULL, AV_LOG_WARNING, "setsockopt SO_REUSEADDR failed\n"); my_addr->sin_family = AF_INET; if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) { char bindmsg[32]; snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port)); perror (bindmsg); closesocket(server_fd); return -1; } if (listen (server_fd, 50) < 0) { perror ("listen"); closesocket(server_fd); return -1; } if (ff_socket_nonblock(server_fd, 1) < 0) av_log(NULL, AV_LOG_WARNING, "ff_socket_nonblock failed\n"); return server_fd; }
int ff_listen_bind(int fd, const struct sockaddr *addr, socklen_t addrlen, int timeout, URLContext *h) { int ret; int reuse = 1; struct pollfd lp = { fd, POLLIN, 0 }; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse))) { av_log(NULL, AV_LOG_WARNING, "setsockopt(SO_REUSEADDR) failed\n"); } ret = bind(fd, addr, addrlen); if (ret) return ff_neterrno(); ret = listen(fd, 1); if (ret) return ff_neterrno(); ret = ff_poll_interrupt(&lp, 1, timeout, &h->interrupt_callback); if (ret < 0) return ret; ret = accept(fd, NULL, NULL); if (ret < 0) return ff_neterrno(); closesocket(fd); ff_socket_nonblock(ret, 1); return ret; }
static void *circular_buffer_task( void *_URLContext) { URLContext *h = _URLContext; UDPContext *s = h->priv_data; int old_cancelstate; pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_cancelstate); pthread_mutex_lock(&s->mutex); if (ff_socket_nonblock(s->udp_fd, 0) < 0) { av_log(h, AV_LOG_ERROR, "Failed to set blocking mode"); s->circular_buffer_error = AVERROR(EIO); goto end; } while(1) { int len; pthread_mutex_unlock(&s->mutex); /* Blocking operations are always cancellation points; see "General Information" / "Thread Cancelation Overview" in Single Unix. */ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old_cancelstate); len = recv(s->udp_fd, s->tmp+4, sizeof(s->tmp)-4, 0); pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_cancelstate); pthread_mutex_lock(&s->mutex); if (len < 0) { if (ff_neterrno() != AVERROR(EAGAIN) && ff_neterrno() != AVERROR(EINTR)) { s->circular_buffer_error = ff_neterrno(); goto end; } continue; } AV_WL32(s->tmp, len); if(av_fifo_space(s->fifo) < len + 4) { /* No Space left */ if (s->overrun_nonfatal) { av_log(h, AV_LOG_WARNING, "Circular buffer overrun. " "Surviving due to overrun_nonfatal option\n"); continue; } else { av_log(h, AV_LOG_ERROR, "Circular buffer overrun. " "To avoid, increase fifo_size URL option. " "To survive in such case, use overrun_nonfatal option\n"); s->circular_buffer_error = AVERROR(EIO); goto end; } } av_fifo_generic_write(s->fifo, s->tmp, len+4, NULL); pthread_cond_signal(&s->cond); } end: pthread_cond_signal(&s->cond); pthread_mutex_unlock(&s->mutex); return NULL; }
int ff_listen_connect(int fd, const struct sockaddr *addr, socklen_t addrlen, int timeout, URLContext *h, int will_try_next) { struct pollfd p = {fd, POLLOUT, 0}; int ret; socklen_t optlen; if (ff_socket_nonblock(fd, 1) < 0) av_log(NULL, AV_LOG_DEBUG, "ff_socket_nonblock failed\n"); while ((ret = connect(fd, addr, addrlen))) { ret = ff_neterrno(); switch (ret) { case AVERROR(EINTR): if (ff_check_interrupt(&h->interrupt_callback)) return AVERROR_EXIT; continue; case AVERROR(EINPROGRESS): case AVERROR(EAGAIN): ret = ff_poll_interrupt(&p, 1, timeout, &h->interrupt_callback); if (ret < 0) return ret; optlen = sizeof(ret); if (getsockopt (fd, SOL_SOCKET, SO_ERROR, &ret, &optlen)) ret = AVUNERROR(ff_neterrno()); if (ret != 0) { char errbuf[100]; ret = AVERROR(ret); av_strerror(ret, errbuf, sizeof(errbuf)); if (will_try_next) av_log(h, AV_LOG_WARNING, "Connection to %s failed (%s), trying next address\n", h->filename, errbuf); else av_log(h, AV_LOG_ERROR, "Connection to %s failed: %s\n", h->filename, errbuf); } default: return ret; } } return ret; }
/* 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, bind_ret = -1; UDPContext *s = NULL; int is_output; const char *p; char buf[256]; struct sockaddr_storage my_addr; int len; int reuse_specified = 0; h->is_streamed = 1; h->max_packet_size = 1472; is_output = !(flags & AVIO_FLAG_READ); 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; s->circular_buffer_size = 7*188*4096; p = strchr(uri, '?'); if (p) { if (av_find_info_tag(buf, sizeof(buf), "reuse", p)) { char *endptr=NULL; s->reuse_socket = strtol(buf, &endptr, 10); /* assume if no digits were found it is a request to enable it */ if (buf == endptr) s->reuse_socket = 1; reuse_specified = 1; } if (av_find_info_tag(buf, sizeof(buf), "ttl", p)) { s->ttl = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "localport", p)) { s->local_port = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "pkt_size", p)) { h->max_packet_size = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "buffer_size", p)) { s->buffer_size = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "connect", p)) { s->is_connected = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "buf_size", p)) { s->circular_buffer_size = strtol(buf, NULL, 10)*188; } } /* fill the dest addr */ av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri); /* XXX: fix av_url_split */ if (hostname[0] == '\0' || hostname[0] == '?') { /* only accepts null hostname if input */ if (!(flags & AVIO_FLAG_READ)) goto fail; } else { if (ff_udp_set_remote_url(h, uri) < 0) goto fail; } if (s->is_multicast && (h->flags & AVIO_FLAG_READ)) s->local_port = port; udp_fd = udp_socket_create(s, &my_addr, &len); if (udp_fd < 0) goto fail; /* Follow the requested reuse option, unless it's multicast in which * case enable reuse unless explicitely disabled. */ if (s->reuse_socket || (s->is_multicast && !reuse_specified)) { s->reuse_socket = 1; 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 & AVIO_FLAG_READ)) { 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 & AVIO_FLAG_READ)) { /* 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(h, 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(h, AV_LOG_WARNING, "setsockopt(SO_RECVBUF): %s\n", strerror(errno)); } /* make the socket non-blocking */ ff_socket_nonblock(udp_fd, 1); } if (s->is_connected) { if (connect(udp_fd, (struct sockaddr *) &s->dest_addr, s->dest_addr_len)) { av_log(h, AV_LOG_ERROR, "connect: %s\n", strerror(errno)); goto fail; } } s->udp_fd = udp_fd; #if 0 && HAVE_PTHREADS if (!is_output && s->circular_buffer_size) { /* start the task going */ s->fifo = av_fifo_alloc(s->circular_buffer_size); if (pthread_create(&s->circular_buffer_thread, NULL, circular_buffer_task, h)) { av_log(h, AV_LOG_ERROR, "pthread_create failed\n"); goto fail; } } #endif return 0; fail: if (udp_fd >= 0) closesocket(udp_fd); av_fifo_free(s->fifo); av_free(s); return AVERROR(EIO); }
/* return non zero if error */ static int tcp_open(URLContext *h, const char *uri, int flags) { struct addrinfo hints, *ai, *cur_ai; int port, fd = -1; TCPContext *s = NULL; int listen_socket = 0; const char *p; char buf[256]; int ret; socklen_t optlen; char hostname[1024],proto[1024],path[1024]; char portstr[10]; av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), &port, path, sizeof(path), uri); if (strcmp(proto,"tcp") || port <= 0 || port >= 65536) return AVERROR(EINVAL); p = strchr(uri, '?'); if (p) { if (av_find_info_tag(buf, sizeof(buf), "listen", p)) listen_socket = 1; } memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; snprintf(portstr, sizeof(portstr), "%d", port); ret = getaddrinfo(hostname, portstr, &hints, &ai); if (ret) { av_log(NULL, AV_LOG_ERROR, "Failed to resolve hostname %s: %s\n", hostname, gai_strerror(ret)); return AVERROR(EIO); } cur_ai = ai; restart: fd = socket(cur_ai->ai_family, cur_ai->ai_socktype, cur_ai->ai_protocol); if (fd < 0) goto fail; if (listen_socket) { int fd1; ret = bind(fd, cur_ai->ai_addr, cur_ai->ai_addrlen); listen(fd, 1); fd1 = accept(fd, NULL, NULL); closesocket(fd); fd = fd1; } else { redo: ff_socket_nonblock(fd, 1); //av_log (NULL, AV_LOG_INFO, "connecting....\n"); ret = connect(fd, cur_ai->ai_addr, cur_ai->ai_addrlen); //av_log (NULL, AV_LOG_INFO, "connecting done.\n"); } if (ret < 0) { int timeout = 10; //1s timeout struct pollfd p = {fd, POLLOUT, 0}; if (ff_neterrno() == AVERROR(EINTR)) { if (url_interrupt_cb()) { ret = AVERROR_EXIT; goto fail1; } goto redo; } if (ff_neterrno() != AVERROR(EINPROGRESS) && ff_neterrno() != AVERROR(EAGAIN)) goto fail; /* wait until we are connected or until abort */ for(;;) { if (url_interrupt_cb()) { ret = AVERROR_EXIT; goto fail1; } ret = poll(&p, 1, 100); if (ret > 0) break; if(!--timeout){ av_log(NULL, AV_LOG_ERROR, "TCP open %s:%d timeout\n", hostname, port); goto fail; } } /* test error */ optlen = sizeof(ret); getsockopt (fd, SOL_SOCKET, SO_ERROR, &ret, &optlen); if (ret != 0) { av_log(NULL, AV_LOG_ERROR, "TCP connection to %s:%d failed: %s\n", hostname, port, strerror(ret)); goto fail; } } s = av_malloc(sizeof(TCPContext)); if (!s) { ret = AVERROR(ENOMEM); goto fail1; } h->priv_data = s; h->is_streamed = 1; s->fd = fd; freeaddrinfo(ai); return 0; fail: if (cur_ai->ai_next) { /* Retry with the next sockaddr */ cur_ai = cur_ai->ai_next; if (fd >= 0) closesocket(fd); goto restart; } ret = AVERROR(EIO); fail1: if (fd >= 0) closesocket(fd); freeaddrinfo(ai); return ret; }
/* return non zero if error */ static int udp_open(URLContext *h, const char *uri, int flags) { char hostname[1024], localaddr[1024] = ""; int port, udp_fd = -1, tmp, bind_ret = -1, dscp = -1; UDPContext *s = h->priv_data; int is_output; const char *p; char buf[256]; struct sockaddr_storage my_addr; socklen_t len; int i, num_include_sources = 0, num_exclude_sources = 0; char *include_sources[32], *exclude_sources[32]; h->is_streamed = 1; is_output = !(flags & AVIO_FLAG_READ); if (s->buffer_size < 0) s->buffer_size = is_output ? UDP_TX_BUF_SIZE : UDP_MAX_PKT_SIZE; if (s->sources) { if (parse_source_list(s->sources, include_sources, &num_include_sources, FF_ARRAY_ELEMS(include_sources))) goto fail; } if (s->block) { if (parse_source_list(s->block, exclude_sources, &num_exclude_sources, FF_ARRAY_ELEMS(exclude_sources))) goto fail; } if (s->pkt_size > 0) h->max_packet_size = s->pkt_size; p = strchr(uri, '?'); if (p) { if (av_find_info_tag(buf, sizeof(buf), "reuse", p)) { char *endptr = NULL; s->reuse_socket = strtol(buf, &endptr, 10); /* assume if no digits were found it is a request to enable it */ if (buf == endptr) s->reuse_socket = 1; } if (av_find_info_tag(buf, sizeof(buf), "overrun_nonfatal", p)) { char *endptr = NULL; s->overrun_nonfatal = strtol(buf, &endptr, 10); /* assume if no digits were found it is a request to enable it */ if (buf == endptr) s->overrun_nonfatal = 1; if (!HAVE_PTHREAD_CANCEL) av_log(h, AV_LOG_WARNING, "'overrun_nonfatal' option was set but it is not supported " "on this build (pthread support is required)\n"); } if (av_find_info_tag(buf, sizeof(buf), "ttl", p)) { s->ttl = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "udplite_coverage", p)) { s->udplite_coverage = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "localport", p)) { s->local_port = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "pkt_size", p)) { s->pkt_size = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "buffer_size", p)) { s->buffer_size = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "connect", p)) { s->is_connected = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "dscp", p)) { dscp = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "fifo_size", p)) { s->circular_buffer_size = strtol(buf, NULL, 10); if (!HAVE_PTHREAD_CANCEL) av_log(h, AV_LOG_WARNING, "'circular_buffer_size' option was set but it is not supported " "on this build (pthread support is required)\n"); } if (av_find_info_tag(buf, sizeof(buf), "localaddr", p)) { av_strlcpy(localaddr, buf, sizeof(localaddr)); } if (av_find_info_tag(buf, sizeof(buf), "sources", p)) { if (parse_source_list(buf, include_sources, &num_include_sources, FF_ARRAY_ELEMS(include_sources))) goto fail; } if (av_find_info_tag(buf, sizeof(buf), "block", p)) { if (parse_source_list(buf, exclude_sources, &num_exclude_sources, FF_ARRAY_ELEMS(exclude_sources))) goto fail; } if (!is_output && av_find_info_tag(buf, sizeof(buf), "timeout", p)) s->timeout = strtol(buf, NULL, 10); if (is_output && av_find_info_tag(buf, sizeof(buf), "broadcast", p)) s->is_broadcast = strtol(buf, NULL, 10); } /* handling needed to support options picking from both AVOption and URL */ s->circular_buffer_size *= 188; if (flags & AVIO_FLAG_WRITE) { h->max_packet_size = s->pkt_size; } else { h->max_packet_size = UDP_MAX_PKT_SIZE; } h->rw_timeout = s->timeout; /* fill the dest addr */ av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri); /* XXX: fix av_url_split */ if (hostname[0] == '\0' || hostname[0] == '?') { /* only accepts null hostname if input */ if (!(flags & AVIO_FLAG_READ)) goto fail; } else { if (ff_udp_set_remote_url(h, uri) < 0) goto fail; } if ((s->is_multicast || s->local_port <= 0) && (h->flags & AVIO_FLAG_READ)) s->local_port = port; if (localaddr[0]) udp_fd = udp_socket_create(s, &my_addr, &len, localaddr); else udp_fd = udp_socket_create(s, &my_addr, &len, s->localaddr); if (udp_fd < 0) goto fail; s->local_addr_storage=my_addr; //store for future multicast join /* Follow the requested reuse option, unless it's multicast in which * case enable reuse unless explicitly disabled. */ if (s->reuse_socket > 0 || (s->is_multicast && s->reuse_socket < 0)) { s->reuse_socket = 1; if (setsockopt (udp_fd, SOL_SOCKET, SO_REUSEADDR, &(s->reuse_socket), sizeof(s->reuse_socket)) != 0) goto fail; } if (s->is_broadcast) { #ifdef SO_BROADCAST if (setsockopt (udp_fd, SOL_SOCKET, SO_BROADCAST, &(s->is_broadcast), sizeof(s->is_broadcast)) != 0) #endif goto fail; } /* Set the checksum coverage for UDP-Lite (RFC 3828) for sending and receiving. * The receiver coverage has to be less than or equal to the sender coverage. * Otherwise, the receiver will drop all packets. */ if (s->udplite_coverage) { if (setsockopt (udp_fd, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV, &(s->udplite_coverage), sizeof(s->udplite_coverage)) != 0) av_log(h, AV_LOG_WARNING, "socket option UDPLITE_SEND_CSCOV not available"); if (setsockopt (udp_fd, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV, &(s->udplite_coverage), sizeof(s->udplite_coverage)) != 0) av_log(h, AV_LOG_WARNING, "socket option UDPLITE_RECV_CSCOV not available"); } if (dscp >= 0) { dscp <<= 2; if (setsockopt (udp_fd, IPPROTO_IP, IP_TOS, &dscp, sizeof(dscp)) != 0) goto fail; } /* If multicast, try binding the multicast address first, to avoid * receiving UDP packets from other sources aimed at the same UDP * port. This fails on windows. This makes sending to the same address * using sendto() fail, so only do it if we're opened in read-only mode. */ if (s->is_multicast && !(h->flags & AVIO_FLAG_WRITE)) { 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 */ /* the bind is needed to give a port to the socket now */ if (bind_ret < 0 && bind(udp_fd,(struct sockaddr *)&my_addr, len) < 0) { log_net_error(h, AV_LOG_ERROR, "bind failed"); 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 & AVIO_FLAG_WRITE) { /* output */ if (udp_set_multicast_ttl(udp_fd, s->ttl, (struct sockaddr *)&s->dest_addr) < 0) goto fail; } if (h->flags & AVIO_FLAG_READ) { /* input */ if (num_include_sources && num_exclude_sources) { av_log(h, AV_LOG_ERROR, "Simultaneously including and excluding multicast sources is not supported\n"); goto fail; } if (num_include_sources) { if (udp_set_multicast_sources(udp_fd, (struct sockaddr *)&s->dest_addr, s->dest_addr_len, include_sources, num_include_sources, 1) < 0) goto fail; } else { if (udp_join_multicast_group(udp_fd, (struct sockaddr *)&s->dest_addr,(struct sockaddr *)&s->local_addr_storage) < 0) goto fail; } if (num_exclude_sources) { if (udp_set_multicast_sources(udp_fd, (struct sockaddr *)&s->dest_addr, s->dest_addr_len, exclude_sources, num_exclude_sources, 0) < 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) { log_net_error(h, AV_LOG_ERROR, "setsockopt(SO_SNDBUF)"); goto fail; } } else { /* set udp recv buffer size to the requested value (default 64K) */ tmp = s->buffer_size; if (setsockopt(udp_fd, SOL_SOCKET, SO_RCVBUF, &tmp, sizeof(tmp)) < 0) { log_net_error(h, AV_LOG_WARNING, "setsockopt(SO_RECVBUF)"); } len = sizeof(tmp); if (getsockopt(udp_fd, SOL_SOCKET, SO_RCVBUF, &tmp, &len) < 0) { log_net_error(h, AV_LOG_WARNING, "getsockopt(SO_RCVBUF)"); } else { av_log(h, AV_LOG_DEBUG, "end receive buffer size reported is %d\n", tmp); if(tmp < s->buffer_size) av_log(h, AV_LOG_WARNING, "attempted to set receive buffer to size %d but it only ended up set as %d", s->buffer_size, tmp); } /* make the socket non-blocking */ ff_socket_nonblock(udp_fd, 1); } if (s->is_connected) { if (connect(udp_fd, (struct sockaddr *) &s->dest_addr, s->dest_addr_len)) { log_net_error(h, AV_LOG_ERROR, "connect"); goto fail; } } for (i = 0; i < num_include_sources; i++) av_freep(&include_sources[i]); for (i = 0; i < num_exclude_sources; i++) av_freep(&exclude_sources[i]); s->udp_fd = udp_fd; #if HAVE_PTHREAD_CANCEL if (!is_output && s->circular_buffer_size) { int ret; /* start the task going */ s->fifo = av_fifo_alloc(s->circular_buffer_size); ret = pthread_mutex_init(&s->mutex, NULL); if (ret != 0) { av_log(h, AV_LOG_ERROR, "pthread_mutex_init failed : %s\n", strerror(ret)); goto fail; } ret = pthread_cond_init(&s->cond, NULL); if (ret != 0) { av_log(h, AV_LOG_ERROR, "pthread_cond_init failed : %s\n", strerror(ret)); goto cond_fail; } ret = pthread_create(&s->circular_buffer_thread, NULL, circular_buffer_task, h); if (ret != 0) { av_log(h, AV_LOG_ERROR, "pthread_create failed : %s\n", strerror(ret)); goto thread_fail; } s->thread_started = 1; } #endif return 0; #if HAVE_PTHREAD_CANCEL thread_fail: pthread_cond_destroy(&s->cond); cond_fail: pthread_mutex_destroy(&s->mutex); #endif fail: if (udp_fd >= 0) closesocket(udp_fd); av_fifo_freep(&s->fifo); for (i = 0; i < num_include_sources; i++) av_freep(&include_sources[i]); for (i = 0; i < num_exclude_sources; i++) av_freep(&exclude_sources[i]); return AVERROR(EIO); }
/* return non zero if error */ static int tcp_open(URLContext *h, const char *uri, int flags) { struct sockaddr_in dest_addr; int port, fd = -1; TCPContext *s = NULL; fd_set wfds; int fd_max, ret; struct timeval tv; socklen_t optlen; char hostname[1024],proto[1024],path[1024]; if(!ff_network_init()) return AVERROR(EIO); url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), &port, path, sizeof(path), uri); if (strcmp(proto,"tcp") || port <= 0 || port >= 65536) return AVERROR(EINVAL); dest_addr.sin_family = AF_INET; dest_addr.sin_port = htons(port); if (resolve_host(&dest_addr.sin_addr, hostname) < 0) return AVERROR(EIO); fd = socket(AF_INET, SOCK_STREAM, 0); if (fd < 0) return AVERROR(EIO); ff_socket_nonblock(fd, 1); redo: ret = connect(fd, (struct sockaddr *)&dest_addr, sizeof(dest_addr)); if (ret < 0) { if (ff_neterrno() == FF_NETERROR(EINTR)) goto redo; if (ff_neterrno() != FF_NETERROR(EINPROGRESS) && ff_neterrno() != FF_NETERROR(EAGAIN)) goto fail; /* wait until we are connected or until abort */ for(;;) { if (url_interrupt_cb()) { ret = AVERROR(EINTR); goto fail1; } fd_max = fd; FD_ZERO(&wfds); FD_SET(fd, &wfds); tv.tv_sec = 0; tv.tv_usec = 100 * 1000; ret = select(fd_max + 1, NULL, &wfds, NULL, &tv); if (ret > 0 && FD_ISSET(fd, &wfds)) break; } /* test error */ optlen = sizeof(ret); getsockopt (fd, SOL_SOCKET, SO_ERROR, &ret, &optlen); if (ret != 0) goto fail; } s = av_malloc(sizeof(TCPContext)); if (!s) return AVERROR(ENOMEM); h->priv_data = s; h->is_streamed = 1; s->fd = fd; return 0; fail: ret = AVERROR(EIO); fail1: if (fd >= 0) closesocket(fd); return ret; }
/* return non zero if error */ static int tcp_open(URLContext *h, const char *uri, int flags) { struct addrinfo hints, *ai, *cur_ai; int port, fd = -1; TCPContext *s = NULL; int listen_socket = 0; const char *p; char buf[256]; int ret; socklen_t optlen; int timeout = 500, listen_timeout = -1; char hostname[1024],proto[1024],path[1024]; char portstr[10]; av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), &port, path, sizeof(path), uri); if (strcmp(proto, "tcp")) return AVERROR(EINVAL); if (port <= 0 || port >= 65536) { av_log(h, AV_LOG_ERROR, "Port missing in uri\n"); return AVERROR(EINVAL); } p = strchr(uri, '?'); if (p) { if (av_find_info_tag(buf, sizeof(buf), "listen", p)) listen_socket = 1; if (av_find_info_tag(buf, sizeof(buf), "timeout", p)) { timeout = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "listen_timeout", p)) { listen_timeout = strtol(buf, NULL, 10); } } memset(&hints, 0, sizeof(hints)); if(am_getconfig_bool_def("media.libplayer.ipv4only",1)) hints.ai_family = AF_INET; else hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; snprintf(portstr, sizeof(portstr), "%d", port); av_log(h, AV_LOG_INFO,"tcp will get address from dns!\n"); if (listen_socket) hints.ai_flags |= AI_PASSIVE; if (!hostname[0]) ret = getaddrinfo(NULL, portstr, &hints, &ai); else ret = getaddrinfo(hostname, portstr, &hints, &ai); if (ret) { av_log(h, AV_LOG_ERROR, "Failed to resolve hostname %s: %s\n", hostname, gai_strerror(ret)); return AVERROR(EIO); } av_log(h, AV_LOG_INFO,"resolved %s's ipaddress \n",hostname); cur_ai = ai; restart: ret = AVERROR(EIO); fd = socket(cur_ai->ai_family, cur_ai->ai_socktype, cur_ai->ai_protocol); if (fd < 0) goto fail; if (listen_socket) { int fd1; int reuse = 1; struct pollfd lp = { fd, POLLIN, 0 }; setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); ret = bind(fd, cur_ai->ai_addr, cur_ai->ai_addrlen); if (ret) { ret = ff_neterrno(); goto fail1; } ret = listen(fd, 1); if (ret) { ret = ff_neterrno(); goto fail1; } ret = poll(&lp, 1, listen_timeout >= 0 ? listen_timeout : -1); if (ret <= 0) { ret = AVERROR(ETIMEDOUT); goto fail1; } fd1 = accept(fd, NULL, NULL); if (fd1 < 0) { ret = ff_neterrno(); goto fail1; } closesocket(fd); fd = fd1; ff_socket_nonblock(fd, 1); } else { redo: ff_socket_nonblock(fd, 1); ret = connect(fd, cur_ai->ai_addr, cur_ai->ai_addrlen); } if (ret < 0) { struct pollfd p = {fd, POLLOUT, 0}; ret = ff_neterrno(); if (ret == AVERROR(EINTR)) { if (url_interrupt_cb()) { ret = AVERROR_EXIT; goto fail1; } goto redo; } if (ret != AVERROR(EINPROGRESS) && ret != AVERROR(EAGAIN)) goto fail; /* wait until we are connected or until abort */ while(timeout--) { if (url_interrupt_cb()) { ret = AVERROR_EXIT; goto fail1; } ret = poll(&p, 1, 100); if (ret > 0) break; } if (ret <= 0) { av_log(h, AV_LOG_ERROR, "TCP connection to %s:%d timeout failed!\n", hostname, port); ret = AVERROR(ETIMEDOUT); goto fail; } /* test error */ optlen = sizeof(ret); if (getsockopt (fd, SOL_SOCKET, SO_ERROR, &ret, &optlen)) ret = AVUNERROR(ff_neterrno()); if (ret != 0) { char errbuf[100]; ret = AVERROR(ret); av_strerror(ret, errbuf, sizeof(errbuf)); av_log(h, AV_LOG_ERROR, "TCP connection to %s:%d failed: %s, ret = %d\n", hostname, port, errbuf, ret); ret = AVERROR(ret); if(ret>0) ret = AVERROR(EIO); goto fail; } } av_log(h, AV_LOG_INFO,"tcp connect %s ok!\n",hostname); s = av_malloc(sizeof(TCPContext)); if (!s) { freeaddrinfo(ai); return AVERROR(ENOMEM); } h->priv_data = s; h->is_streamed = 1; s->fd = fd; freeaddrinfo(ai); return 0; fail: if (cur_ai->ai_next) { /* Retry with the next sockaddr */ cur_ai = cur_ai->ai_next; if (fd >= 0) closesocket(fd); goto restart; } fail1: if (fd >= 0) closesocket(fd); freeaddrinfo(ai); return ret; }
/* return non zero if error */ static int tcp_open(URLContext *h, const char *uri, int flags) { struct addrinfo hints, *ai, *cur_ai; int port, fd = -1; TCPContext *s = NULL; fd_set wfds; int fd_max, ret; struct timeval tv; socklen_t optlen; char hostname[1024],proto[1024],path[1024]; char portstr[10]; ff_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), &port, path, sizeof(path), uri); if (strcmp(proto,"tcp") || port <= 0 || port >= 65536) return AVERROR(EINVAL); memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; snprintf(portstr, sizeof(portstr), "%d", port); if (getaddrinfo(hostname, portstr, &hints, &ai)) return AVERROR(EIO); cur_ai = ai; restart: fd = socket(cur_ai->ai_family, cur_ai->ai_socktype, cur_ai->ai_protocol); if (fd < 0) goto fail; ff_socket_nonblock(fd, 1); redo: ret = connect(fd, cur_ai->ai_addr, cur_ai->ai_addrlen); if (ret < 0) { if (ff_neterrno() == FF_NETERROR(EINTR)) goto redo; if (ff_neterrno() != FF_NETERROR(EINPROGRESS) && ff_neterrno() != FF_NETERROR(EAGAIN)) goto fail; /* wait until we are connected or until abort */ for(;;) { if (url_interrupt_cb()) { ret = AVERROR(EINTR); goto fail1; } fd_max = fd; FD_ZERO(&wfds); FD_SET(fd, &wfds); tv.tv_sec = 0; tv.tv_usec = 100 * 1000; ret = select(fd_max + 1, NULL, &wfds, NULL, &tv); if (ret > 0 && FD_ISSET(fd, &wfds)) break; } /* test error */ optlen = sizeof(ret); getsockopt (fd, SOL_SOCKET, SO_ERROR, &ret, &optlen); if (ret != 0) goto fail; } s = av_malloc(sizeof(TCPContext)); if (!s) { freeaddrinfo(ai); return AVERROR(ENOMEM); } h->priv_data = s; h->is_streamed = 1; s->fd = fd; freeaddrinfo(ai); return 0; fail: if (cur_ai->ai_next) { /* Retry with the next sockaddr */ cur_ai = cur_ai->ai_next; if (fd >= 0) closesocket(fd); goto restart; } ret = AVERROR(EIO); fail1: if (fd >= 0) closesocket(fd); freeaddrinfo(ai); return ret; }
static int sctp_open(URLContext *h, const char *uri, int flags) { struct addrinfo *ai, *cur_ai; struct addrinfo hints = { 0 }; struct sctp_event_subscribe event = { 0 }; struct sctp_initmsg initparams = { 0 }; int port; int fd = -1; SCTPContext *s = h->priv_data; const char *p; char buf[256]; int ret, listen_socket = 0; char hostname[1024], proto[1024], path[1024]; char portstr[10]; av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), &port, path, sizeof(path), uri); if (strcmp(proto, "sctp")) return AVERROR(EINVAL); if (port <= 0 || port >= 65536) { av_log(s, AV_LOG_ERROR, "Port missing in uri\n"); return AVERROR(EINVAL); } s->max_streams = 0; p = strchr(uri, '?'); if (p) { if (av_find_info_tag(buf, sizeof(buf), "listen", p)) listen_socket = 1; if (av_find_info_tag(buf, sizeof(buf), "max_streams", p)) s->max_streams = strtol(buf, NULL, 10); } hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; snprintf(portstr, sizeof(portstr), "%d", port); ret = getaddrinfo(hostname, portstr, &hints, &ai); if (ret) { av_log(h, AV_LOG_ERROR, "Failed to resolve hostname %s: %s\n", hostname, gai_strerror(ret)); return AVERROR(EIO); } cur_ai = ai; fd = socket(cur_ai->ai_family, SOCK_STREAM, IPPROTO_SCTP); if (fd < 0) goto fail; s->dest_addr_len = sizeof(s->dest_addr); if (listen_socket) { int fd1; ret = bind(fd, cur_ai->ai_addr, cur_ai->ai_addrlen); listen(fd, 100); fd1 = accept(fd, NULL, NULL); closesocket(fd); fd = fd1; } else ret = connect(fd, cur_ai->ai_addr, cur_ai->ai_addrlen); ff_socket_nonblock(fd, 1); event.sctp_data_io_event = 1; /* TODO: Subscribe to more event types and handle them */ if (setsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS, &event, sizeof(event)) != 0) { av_log(h, AV_LOG_ERROR, "SCTP ERROR: Unable to subscribe to events\n"); goto fail; } if (s->max_streams) { initparams.sinit_max_instreams = s->max_streams; initparams.sinit_num_ostreams = s->max_streams; if (setsockopt(fd, IPPROTO_SCTP, SCTP_INITMSG, &initparams, sizeof(initparams)) < 0) av_log(h, AV_LOG_ERROR, "SCTP ERROR: Unable to initialize socket max streams %d\n", s->max_streams); } h->priv_data = s; h->is_streamed = 1; s->fd = fd; freeaddrinfo(ai); return 0; fail: ret = AVERROR(EIO); freeaddrinfo(ai); return ret; }
/* return non zero if error */ static int tcp_open(URLContext *h, const char *uri, int flags) { struct addrinfo hints = { 0 }, *ai, *cur_ai; int port, fd = -1; TCPContext *s = h->priv_data; int listen_socket = 0; const char *p; char buf[256]; int ret; socklen_t optlen; int timeout = 50; char hostname[1024],proto[1024],path[1024]; char portstr[10]; av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), &port, path, sizeof(path), uri); if (strcmp(proto,"tcp") || port <= 0 || port >= 65536) return AVERROR(EINVAL); p = strchr(uri, '?'); if (p) { if (av_find_info_tag(buf, sizeof(buf), "listen", p)) listen_socket = 1; if (av_find_info_tag(buf, sizeof(buf), "timeout", p)) { timeout = strtol(buf, NULL, 10); } } hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; snprintf(portstr, sizeof(portstr), "%d", port); ret = getaddrinfo(hostname, portstr, &hints, &ai); if (ret) { av_log(h, AV_LOG_ERROR, "Failed to resolve hostname %s: %s\n", hostname, gai_strerror(ret)); return AVERROR(EIO); } cur_ai = ai; restart: ret = AVERROR(EIO); fd = socket(cur_ai->ai_family, cur_ai->ai_socktype, cur_ai->ai_protocol); if (fd < 0) goto fail; if (listen_socket) { int fd1; int reuse = 1; setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); ret = bind(fd, cur_ai->ai_addr, cur_ai->ai_addrlen); if (ret) { ret = ff_neterrno(); goto fail1; } ret = listen(fd, 1); if (ret) { ret = ff_neterrno(); goto fail1; } fd1 = accept(fd, NULL, NULL); if (fd1 < 0) { ret = ff_neterrno(); goto fail1; } closesocket(fd); fd = fd1; ff_socket_nonblock(fd, 1); } else { redo: ff_socket_nonblock(fd, 1); ret = connect(fd, cur_ai->ai_addr, cur_ai->ai_addrlen); } if (ret < 0) { struct pollfd p = {fd, POLLOUT, 0}; ret = ff_neterrno(); if (ret == AVERROR(EINTR)) { if (ff_check_interrupt(&h->interrupt_callback)) { ret = AVERROR_EXIT; goto fail1; } goto redo; } if (ret != AVERROR(EINPROGRESS) && ret != AVERROR(EAGAIN)) goto fail; /* wait until we are connected or until abort */ while(timeout--) { if (ff_check_interrupt(&h->interrupt_callback)) { ret = AVERROR_EXIT; goto fail1; } ret = poll(&p, 1, 100); if (ret > 0) break; } if (ret <= 0) { ret = AVERROR(ETIMEDOUT); goto fail; } /* test error */ optlen = sizeof(ret); if (getsockopt (fd, SOL_SOCKET, SO_ERROR, &ret, &optlen)) ret = AVUNERROR(ff_neterrno()); if (ret != 0) { char errbuf[100]; ret = AVERROR(ret); av_strerror(ret, errbuf, sizeof(errbuf)); av_log(h, AV_LOG_ERROR, "TCP connection to %s:%d failed: %s\n", hostname, port, errbuf); goto fail; } } h->is_streamed = 1; s->fd = fd; freeaddrinfo(ai); return 0; fail: if (cur_ai->ai_next) { /* Retry with the next sockaddr */ cur_ai = cur_ai->ai_next; if (fd >= 0) closesocket(fd); goto restart; } fail1: if (fd >= 0) closesocket(fd); freeaddrinfo(ai); return ret; }
static void new_connection(int server_fd, int is_rtsp) { struct sockaddr_in from_addr; socklen_t len; int fd; HTTPContext *c = NULL; int val; val = 0; len = sizeof(from_addr); memset(&from_addr, 0, len); fd = accept(server_fd, (struct sockaddr *)&from_addr, &len); if (fd < 0) { http_log("error during accept %s\n", strerror(errno)); return; } if (ff_socket_nonblock(fd, 1) < 0) av_log(NULL, AV_LOG_WARNING, "ff_socket_nonblock failed\n"); #if 0 /*prevent myself close_wait*/ val = 1; setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)); val = 5; setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &val, sizeof(val)); val = 3; setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &val, sizeof(val)); val = 2; setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &val, sizeof(val)); #endif if (nb_connections >= nb_max_connections) { http_send_too_busy_reply(fd); goto fail; } /* add a new connection */ c = av_mallocz(sizeof(HTTPContext)); if (!c) goto fail; c->fd = fd; c->poll_entry = NULL; c->from_addr = from_addr; c->buffer_size = IOBUFFER_INIT_SIZE; c->buffer = av_malloc(c->buffer_size); if (!c->buffer) goto fail; c->next = first_http_ctx; first_http_ctx = c; nb_connections++; c->buffer_ptr = c->buffer; c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */ c->timeout = cur_time + HTTP_REQUEST_TIMEOUT; c->state = HTTPSTATE_WAIT_REQUEST; c->hls_idx = -1; return; fail: if (c) { av_free(c->buffer); av_free(c); } closesocket(fd); }
/* return non zero if error */ static int udp_open(URLContext *h, const char *uri, int flags) { char hostname[1024], localaddr[1024] = ""; int port, udp_fd = -1, tmp, bind_ret = -1; UDPContext *s = h->priv_data; int is_output; const char *p; char buf[256]; struct sockaddr_storage my_addr; socklen_t len; int reuse_specified = 0; int i, num_include_sources = 0, num_exclude_sources = 0; char *include_sources[32], *exclude_sources[32]; h->is_streamed = 1; h->max_packet_size = 1472; is_output = !(flags & AVIO_FLAG_READ); s->ttl = 16; s->buffer_size = is_output ? UDP_TX_BUF_SIZE : UDP_MAX_PKT_SIZE; p = strchr(uri, '?'); if (p) { if (av_find_info_tag(buf, sizeof(buf), "reuse", p)) { char *endptr = NULL; s->reuse_socket = strtol(buf, &endptr, 10); /* assume if no digits were found it is a request to enable it */ if (buf == endptr) s->reuse_socket = 1; reuse_specified = 1; } if (av_find_info_tag(buf, sizeof(buf), "ttl", p)) { s->ttl = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "localport", p)) { s->local_port = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "pkt_size", p)) { h->max_packet_size = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "buffer_size", p)) { s->buffer_size = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "connect", p)) { s->is_connected = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "localaddr", p)) { av_strlcpy(localaddr, buf, sizeof(localaddr)); } if (av_find_info_tag(buf, sizeof(buf), "sources", p)) { if (parse_source_list(buf, include_sources, &num_include_sources, FF_ARRAY_ELEMS(include_sources))) goto fail; } if (av_find_info_tag(buf, sizeof(buf), "block", p)) { if (parse_source_list(buf, exclude_sources, &num_exclude_sources, FF_ARRAY_ELEMS(exclude_sources))) goto fail; } } /* fill the dest addr */ av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri); /* XXX: fix av_url_split */ if (hostname[0] == '\0' || hostname[0] == '?') { /* only accepts null hostname if input */ if (!(flags & AVIO_FLAG_READ)) goto fail; } else { if (ff_udp_set_remote_url(h, uri) < 0) goto fail; } if ((s->is_multicast || !s->local_port) && (h->flags & AVIO_FLAG_READ)) s->local_port = port; udp_fd = udp_socket_create(s, &my_addr, &len, localaddr); if (udp_fd < 0) goto fail; /* Follow the requested reuse option, unless it's multicast in which * case enable reuse unless explicitly disabled. */ if (s->reuse_socket || (s->is_multicast && !reuse_specified)) { s->reuse_socket = 1; if (setsockopt (udp_fd, SOL_SOCKET, SO_REUSEADDR, &(s->reuse_socket), sizeof(s->reuse_socket)) != 0) goto fail; } /* If multicast, try binding the multicast address first, to avoid * receiving UDP packets from other sources aimed at the same UDP * port. This fails on windows. This makes sending to the same address * using sendto() fail, so only do it if we're opened in read-only mode. */ if (s->is_multicast && !(h->flags & AVIO_FLAG_WRITE)) { 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 */ /* the bind is needed to give a port to the socket now */ if (bind_ret < 0 && bind(udp_fd,(struct sockaddr *)&my_addr, len) < 0) { log_net_error(h, AV_LOG_ERROR, "bind failed"); 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 & AVIO_FLAG_WRITE) { /* output */ if (udp_set_multicast_ttl(udp_fd, s->ttl, (struct sockaddr *)&s->dest_addr) < 0) goto fail; } if (h->flags & AVIO_FLAG_READ) { /* input */ if (num_include_sources && num_exclude_sources) { av_log(h, AV_LOG_ERROR, "Simultaneously including and excluding multicast sources is not supported\n"); goto fail; } if (num_include_sources) { if (udp_set_multicast_sources(udp_fd, (struct sockaddr *)&s->dest_addr, s->dest_addr_len, include_sources, num_include_sources, 1) < 0) goto fail; } else { if (udp_join_multicast_group(udp_fd, (struct sockaddr *)&s->dest_addr) < 0) goto fail; } if (num_exclude_sources) { if (udp_set_multicast_sources(udp_fd, (struct sockaddr *)&s->dest_addr, s->dest_addr_len, exclude_sources, num_exclude_sources, 0) < 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) { log_net_error(h, AV_LOG_ERROR, "setsockopt(SO_SNDBUF)"); 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) { log_net_error(h, AV_LOG_WARNING, "setsockopt(SO_RECVBUF)"); } /* make the socket non-blocking */ ff_socket_nonblock(udp_fd, 1); } if (s->is_connected) { if (connect(udp_fd, (struct sockaddr *) &s->dest_addr, s->dest_addr_len)) { log_net_error(h, AV_LOG_ERROR, "connect"); goto fail; } } for (i = 0; i < num_include_sources; i++) av_freep(&include_sources[i]); for (i = 0; i < num_exclude_sources; i++) av_freep(&exclude_sources[i]); s->udp_fd = udp_fd; return 0; fail: if (udp_fd >= 0) closesocket(udp_fd); for (i = 0; i < num_include_sources; i++) av_freep(&include_sources[i]); for (i = 0; i < num_exclude_sources; i++) av_freep(&exclude_sources[i]); return AVERROR(EIO); }