X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Fudp.c;h=0b62c6da2df0f795fe70681a0716e7b8519cafe0;hb=2afd30bf7ab098f7471d851dc5f7a9adad43d35a;hp=dc896a43f1cd83469643cdc54c734caf1b87bfb0;hpb=e4a9e3cc7cc2a93a8ef666af89cd6885709ff7e0;p=ffmpeg diff --git a/libavformat/udp.c b/libavformat/udp.c index dc896a43f1c..0b62c6da2df 100644 --- a/libavformat/udp.c +++ b/libavformat/udp.c @@ -20,11 +20,12 @@ */ /** - * @file libavformat/udp.c + * @file * UDP protocol */ #define _BSD_SOURCE /* Needed for using struct ip_mreq with recent glibc */ +#define _DARWIN_C_SOURCE /* Needed for using IP_MULTICAST_TTL on OS X */ #include "avformat.h" #include #include "internal.h" @@ -39,12 +40,6 @@ #define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP #define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP #endif -#ifndef IN_MULTICAST -#define IN_MULTICAST(a) ((((uint32_t)(a)) & 0xf0000000) == 0xe0000000) -#endif -#ifndef IN6_IS_ADDR_MULTICAST -#define IN6_IS_ADDR_MULTICAST(a) (((uint8_t *) (a))[0] == 0xff) -#endif typedef struct { int udp_fd; @@ -55,6 +50,7 @@ typedef struct { int reuse_socket; struct sockaddr_storage dest_addr; int dest_addr_len; + int is_connected; } UDPContext; #define UDP_TX_BUF_SIZE 32768 @@ -96,7 +92,7 @@ static int udp_join_multicast_group(int sockfd, struct sockaddr *addr) } } #endif -#if HAVE_STRUCT_IPV6_MREQ +#if HAVE_STRUCT_IPV6_MREQ && defined(IPPROTO_IPV6) if (addr->sa_family == AF_INET6) { struct ipv6_mreq mreq6; @@ -125,7 +121,7 @@ static int udp_leave_multicast_group(int sockfd, struct sockaddr *addr) } } #endif -#if HAVE_STRUCT_IPV6_MREQ +#if HAVE_STRUCT_IPV6_MREQ && defined(IPPROTO_IPV6) if (addr->sa_family == AF_INET6) { struct ipv6_mreq mreq6; @@ -182,20 +178,6 @@ static int udp_set_url(struct sockaddr_storage *addr, return addr_len; } -static int is_multicast_address(struct sockaddr_storage *addr) -{ - if (addr->ss_family == AF_INET) { - return IN_MULTICAST(ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr)); - } -#if HAVE_STRUCT_SOCKADDR_IN6 - if (addr->ss_family == AF_INET6) { - return IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6 *)addr)->sin6_addr); - } -#endif - - return 0; -} - static int udp_socket_create(UDPContext *s, struct sockaddr_storage *addr, int *addr_len) { @@ -256,31 +238,47 @@ static int udp_port(struct sockaddr_storage *addr, int addr_len) * 'pkt_size=n' : set max packet size * 'reuse=1' : enable reusing the socket * - * @param s1 media file context + * @param h media file context * @param uri of the remote server * @return zero if no error. */ int udp_set_remote_url(URLContext *h, const char *uri) { UDPContext *s = h->priv_data; - char hostname[256]; + char hostname[256], buf[10]; int port; + const char *p; - ff_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri); + av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri); /* set the destination address */ s->dest_addr_len = udp_set_url(&s->dest_addr, hostname, port); if (s->dest_addr_len < 0) { return AVERROR(EIO); } - s->is_multicast = is_multicast_address(&s->dest_addr); + s->is_multicast = ff_is_multicast_address((struct sockaddr*) &s->dest_addr); + p = strchr(uri, '?'); + if (p) { + if (find_info_tag(buf, sizeof(buf), "connect", p)) { + int was_connected = s->is_connected; + s->is_connected = strtol(buf, NULL, 10); + if (s->is_connected && !was_connected) { + if (connect(s->udp_fd, (struct sockaddr *) &s->dest_addr, + s->dest_addr_len)) { + s->is_connected = 0; + av_log(NULL, AV_LOG_ERROR, "connect: %s\n", strerror(errno)); + return AVERROR(EIO); + } + } + } + } return 0; } /** - * Return the local port used by the UDP connexion - * @param s1 media file context + * Return the local port used by the UDP connection + * @param h media file context * @return the local port number */ int udp_get_local_port(URLContext *h) @@ -294,7 +292,7 @@ int udp_get_local_port(URLContext *h) * streams at the same time. * @param h media file context */ -#if (LIBAVFORMAT_VERSION_MAJOR >= 53) +#if !FF_API_UDP_GET_FILE static #endif int udp_get_file_handle(URLContext *h) @@ -344,18 +342,22 @@ static int udp_open(URLContext *h, const char *uri, int flags) if (find_info_tag(buf, sizeof(buf), "buffer_size", p)) { s->buffer_size = strtol(buf, NULL, 10); } + if (find_info_tag(buf, sizeof(buf), "connect", p)) { + s->is_connected = strtol(buf, NULL, 10); + } } /* fill the dest addr */ - ff_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri); + av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri); - /* XXX: fix ff_url_split */ + /* XXX: fix av_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 (udp_set_remote_url(h, uri) < 0) + goto fail; } if (s->is_multicast && !(h->flags & URL_WRONLY)) @@ -411,6 +413,12 @@ static int udp_open(URLContext *h, const char *uri, int flags) /* 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(NULL, AV_LOG_ERROR, "connect: %s\n", strerror(errno)); + goto fail; + } + } s->udp_fd = udp_fd; return 0; @@ -437,8 +445,11 @@ static int udp_read(URLContext *h, uint8_t *buf, int size) tv.tv_sec = 0; tv.tv_usec = 100 * 1000; ret = select(s->udp_fd + 1, &rfds, NULL, NULL, &tv); - if (ret < 0) + if (ret < 0) { + if (ff_neterrno() == FF_NETERROR(EINTR)) + continue; return AVERROR(EIO); + } if (!(ret > 0 && FD_ISSET(s->udp_fd, &rfds))) continue; len = recv(s->udp_fd, buf, size, 0); @@ -453,19 +464,22 @@ static int udp_read(URLContext *h, uint8_t *buf, int size) return len; } -static int udp_write(URLContext *h, uint8_t *buf, int size) +static int udp_write(URLContext *h, const uint8_t *buf, int size) { UDPContext *s = h->priv_data; int ret; for(;;) { - ret = sendto (s->udp_fd, buf, size, 0, - (struct sockaddr *) &s->dest_addr, - s->dest_addr_len); + if (!s->is_connected) { + ret = sendto (s->udp_fd, buf, size, 0, + (struct sockaddr *) &s->dest_addr, + s->dest_addr_len); + } else + ret = send(s->udp_fd, buf, size, 0); if (ret < 0) { if (ff_neterrno() != FF_NETERROR(EINTR) && ff_neterrno() != FF_NETERROR(EAGAIN)) - return AVERROR(EIO); + return ff_neterrno(); } else { break; }