static int udp_socket_create(URLContext *h, struct sockaddr_storage *addr, socklen_t *addr_len, const char *localaddr) { UDPContext *s = h->priv_data; int udp_fd = -1; struct addrinfo *res0, *res; int family = AF_UNSPEC; if (((struct sockaddr *) &s->dest_addr)->sa_family) family = ((struct sockaddr *) &s->dest_addr)->sa_family; res0 = udp_resolve_host(h, (localaddr && localaddr[0]) ? localaddr : NULL, s->local_port, SOCK_DGRAM, family, AI_PASSIVE); if (!res0) goto fail; for (res = res0; res; res=res->ai_next) { if (s->udplite_coverage) udp_fd = ff_socket(res->ai_family, SOCK_DGRAM, IPPROTO_UDPLITE); else udp_fd = ff_socket(res->ai_family, SOCK_DGRAM, 0); if (udp_fd != -1) break; log_net_error(NULL, AV_LOG_ERROR, "socket"); } if (udp_fd < 0) goto fail; memcpy(addr, res->ai_addr, res->ai_addrlen); *addr_len = res->ai_addrlen; freeaddrinfo(res0); return udp_fd; fail: if (udp_fd >= 0) closesocket(udp_fd); if(res0) freeaddrinfo(res0); return -1; }
static int unix_open(URLContext *h, const char *filename, int flags) { UnixContext *s = h->priv_data; int fd, ret; av_strstart(filename, "unix:", &filename); s->addr.sun_family = AF_UNIX; av_strlcpy(s->addr.sun_path, filename, sizeof(s->addr.sun_path)); if ((fd = ff_socket(AF_UNIX, s->type, 0)) < 0) return ff_neterrno(); if (s->timeout < 0 && h->rw_timeout) s->timeout = h->rw_timeout / 1000; if (s->listen) { ret = ff_listen_bind(fd, (struct sockaddr *)&s->addr, sizeof(s->addr), s->timeout, h); if (ret < 0) goto fail; fd = ret; } else { ret = ff_listen_connect(fd, (struct sockaddr *)&s->addr, sizeof(s->addr), s->timeout, h, 0); if (ret < 0) goto fail; } s->fd = fd; return 0; fail: if (s->listen && AVUNERROR(ret) != EADDRINUSE) unlink(s->addr.sun_path); if (fd >= 0) closesocket(fd); return ret; }
static int udp_socket_create(UDPContext *s, struct sockaddr_storage *addr, socklen_t *addr_len, const char *localaddr) { int udp_fd = -1; struct addrinfo *res0 = NULL, *res = NULL; int family = AF_UNSPEC; if (((struct sockaddr *) &s->dest_addr)->sa_family) family = ((struct sockaddr *) &s->dest_addr)->sa_family; res0 = udp_resolve_host(localaddr[0] ? localaddr : NULL, s->local_port, SOCK_DGRAM, family, AI_PASSIVE); if (res0 == 0) goto fail; for (res = res0; res; res=res->ai_next) { udp_fd = ff_socket(res->ai_family, SOCK_DGRAM, 0); if (udp_fd != -1) break; log_net_error(NULL, AV_LOG_ERROR, "socket"); } if (udp_fd < 0) goto fail; memcpy(addr, res->ai_addr, res->ai_addrlen); *addr_len = res->ai_addrlen; freeaddrinfo(res0); return udp_fd; fail: if (udp_fd >= 0) closesocket(udp_fd); if(res0) freeaddrinfo(res0); return -1; }
/* 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; int timeout = 100, 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); } } hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; snprintf(portstr, sizeof(portstr), "%d", port); 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); } cur_ai = ai; restart: fd = ff_socket(cur_ai->ai_family, cur_ai->ai_socktype, cur_ai->ai_protocol); if (fd < 0) { ret = ff_neterrno(); goto fail; } if (listen_socket) { if ((fd = ff_listen_bind(fd, cur_ai->ai_addr, cur_ai->ai_addrlen, listen_timeout, h)) < 0) { ret = fd; goto fail1; } } else { if ((ret = ff_listen_connect(fd, cur_ai->ai_addr, cur_ai->ai_addrlen, timeout * 100, h, !!cur_ai->ai_next)) < 0) { if (ret == AVERROR_EXIT) goto fail1; else 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); ret = 0; 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 = { 0 }, *ai, *cur_ai; int port, fd = -1; TCPContext *s = h->priv_data; const char *p; char buf[256]; int ret; char hostname[1024],proto[1024],path[1024]; char portstr[10]; s->open_timeout = 5000000; 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)) { char *endptr = NULL; s->listen = strtol(buf, &endptr, 10); /* assume if no digits were found it is a request to enable it */ if (buf == endptr) s->listen = 1; } if (av_find_info_tag(buf, sizeof(buf), "timeout", p)) { s->rw_timeout = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "listen_timeout", p)) { s->listen_timeout = strtol(buf, NULL, 10); } } if (s->rw_timeout >= 0) { s->open_timeout = h->rw_timeout = s->rw_timeout; } hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; snprintf(portstr, sizeof(portstr), "%d", port); if (s->listen) 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); } cur_ai = ai; #if HAVE_STRUCT_SOCKADDR_IN6 // workaround for IOS9 getaddrinfo in IPv6 only network use hardcode IPv4 address can not resolve port number. if (cur_ai->ai_family == AF_INET6){ struct sockaddr_in6 * sockaddr_v6 = (struct sockaddr_in6 *)cur_ai->ai_addr; if (!sockaddr_v6->sin6_port){ sockaddr_v6->sin6_port = htons(port); } } #endif if (s->listen > 0) { while (cur_ai && fd < 0) { fd = ff_socket(cur_ai->ai_family, cur_ai->ai_socktype, cur_ai->ai_protocol); if (fd < 0) { ret = ff_neterrno(); cur_ai = cur_ai->ai_next; } } if (fd < 0) goto fail1; customize_fd(s, fd); } if (s->listen == 2) { // multi-client if ((ret = ff_listen(fd, cur_ai->ai_addr, cur_ai->ai_addrlen)) < 0) goto fail1; } else if (s->listen == 1) { // single client if ((ret = ff_listen_bind(fd, cur_ai->ai_addr, cur_ai->ai_addrlen, s->listen_timeout, h)) < 0) goto fail1; // Socket descriptor already closed here. Safe to overwrite to client one. fd = ret; } else { ret = ff_connect_parallel(ai, s->open_timeout / 1000, 3, h, &fd, customize_fd, s); if (ret < 0) goto fail1; } h->is_streamed = 1; s->fd = fd; freeaddrinfo(ai); return 0; 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 = ff_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; }