CtRet ct_udp_multicast_open(int *fd, const char *group, uint16_t port, bool block) { CtRet ret = CT_RET_OK; do { *fd = socket(AF_INET, SOCK_DGRAM, 0); if (*fd < 0) { LOG_E(TAG, "socket failed"); ret = CT_RET_E_SOCKET_FD; #ifdef _WIN32 DWORD e = GetLastError(); LOG_D(TAG, "socket, e = %d", e); #else LOG_D(TAG, "socket: %s", strerror(errno)); #endif break; } ret = udp_join_multicast_group(*fd, group, port); if (RET_FAILED(ret)) { break; } if (!block) { ret = ct_socket_set_nonblock(*fd); if (RET_FAILED(ret)) { break; } } } while (0); 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 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 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); }