00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00027 #define _BSD_SOURCE
00028 #include "avformat.h"
00029 #include <unistd.h>
00030 #include "internal.h"
00031 #include "network.h"
00032 #include "os_support.h"
00033 #if HAVE_SYS_SELECT_H
00034 #include <sys/select.h>
00035 #endif
00036 #include <sys/time.h>
00037
00038 #ifndef IPV6_ADD_MEMBERSHIP
00039 #define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
00040 #define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
00041 #endif
00042 #ifndef IN_MULTICAST
00043 #define IN_MULTICAST(a) ((((uint32_t)(a)) & 0xf0000000) == 0xe0000000)
00044 #endif
00045 #ifndef IN6_IS_ADDR_MULTICAST
00046 #define IN6_IS_ADDR_MULTICAST(a) (((uint8_t *) (a))[0] == 0xff)
00047 #endif
00048
00049 typedef struct {
00050 int udp_fd;
00051 int ttl;
00052 int buffer_size;
00053 int is_multicast;
00054 int local_port;
00055 int reuse_socket;
00056 struct sockaddr_storage dest_addr;
00057 int dest_addr_len;
00058 } UDPContext;
00059
00060 #define UDP_TX_BUF_SIZE 32768
00061 #define UDP_MAX_PKT_SIZE 65536
00062
00063 static int udp_set_multicast_ttl(int sockfd, int mcastTTL,
00064 struct sockaddr *addr)
00065 {
00066 #ifdef IP_MULTICAST_TTL
00067 if (addr->sa_family == AF_INET) {
00068 if (setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_TTL, &mcastTTL, sizeof(mcastTTL)) < 0) {
00069 av_log(NULL, AV_LOG_ERROR, "setsockopt(IP_MULTICAST_TTL): %s\n", strerror(errno));
00070 return -1;
00071 }
00072 }
00073 #endif
00074 #if defined(IPPROTO_IPV6) && defined(IPV6_MULTICAST_HOPS)
00075 if (addr->sa_family == AF_INET6) {
00076 if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &mcastTTL, sizeof(mcastTTL)) < 0) {
00077 av_log(NULL, AV_LOG_ERROR, "setsockopt(IPV6_MULTICAST_HOPS): %s\n", strerror(errno));
00078 return -1;
00079 }
00080 }
00081 #endif
00082 return 0;
00083 }
00084
00085 static int udp_join_multicast_group(int sockfd, struct sockaddr *addr)
00086 {
00087 #ifdef IP_ADD_MEMBERSHIP
00088 if (addr->sa_family == AF_INET) {
00089 struct ip_mreq mreq;
00090
00091 mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
00092 mreq.imr_interface.s_addr= INADDR_ANY;
00093 if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const void *)&mreq, sizeof(mreq)) < 0) {
00094 av_log(NULL, AV_LOG_ERROR, "setsockopt(IP_ADD_MEMBERSHIP): %s\n", strerror(errno));
00095 return -1;
00096 }
00097 }
00098 #endif
00099 #if HAVE_STRUCT_IPV6_MREQ
00100 if (addr->sa_family == AF_INET6) {
00101 struct ipv6_mreq mreq6;
00102
00103 memcpy(&mreq6.ipv6mr_multiaddr, &(((struct sockaddr_in6 *)addr)->sin6_addr), sizeof(struct in6_addr));
00104 mreq6.ipv6mr_interface= 0;
00105 if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
00106 av_log(NULL, AV_LOG_ERROR, "setsockopt(IPV6_ADD_MEMBERSHIP): %s\n", strerror(errno));
00107 return -1;
00108 }
00109 }
00110 #endif
00111 return 0;
00112 }
00113
00114 static int udp_leave_multicast_group(int sockfd, struct sockaddr *addr)
00115 {
00116 #ifdef IP_DROP_MEMBERSHIP
00117 if (addr->sa_family == AF_INET) {
00118 struct ip_mreq mreq;
00119
00120 mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
00121 mreq.imr_interface.s_addr= INADDR_ANY;
00122 if (setsockopt(sockfd, IPPROTO_IP, IP_DROP_MEMBERSHIP, (const void *)&mreq, sizeof(mreq)) < 0) {
00123 av_log(NULL, AV_LOG_ERROR, "setsockopt(IP_DROP_MEMBERSHIP): %s\n", strerror(errno));
00124 return -1;
00125 }
00126 }
00127 #endif
00128 #if HAVE_STRUCT_IPV6_MREQ
00129 if (addr->sa_family == AF_INET6) {
00130 struct ipv6_mreq mreq6;
00131
00132 memcpy(&mreq6.ipv6mr_multiaddr, &(((struct sockaddr_in6 *)addr)->sin6_addr), sizeof(struct in6_addr));
00133 mreq6.ipv6mr_interface= 0;
00134 if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
00135 av_log(NULL, AV_LOG_ERROR, "setsockopt(IPV6_DROP_MEMBERSHIP): %s\n", strerror(errno));
00136 return -1;
00137 }
00138 }
00139 #endif
00140 return 0;
00141 }
00142
00143 static struct addrinfo* udp_resolve_host(const char *hostname, int port,
00144 int type, int family, int flags)
00145 {
00146 struct addrinfo hints, *res = 0;
00147 int error;
00148 char sport[16];
00149 const char *node = 0, *service = "0";
00150
00151 if (port > 0) {
00152 snprintf(sport, sizeof(sport), "%d", port);
00153 service = sport;
00154 }
00155 if ((hostname) && (hostname[0] != '\0') && (hostname[0] != '?')) {
00156 node = hostname;
00157 }
00158 memset(&hints, 0, sizeof(hints));
00159 hints.ai_socktype = type;
00160 hints.ai_family = family;
00161 hints.ai_flags = flags;
00162 if ((error = getaddrinfo(node, service, &hints, &res))) {
00163 res = NULL;
00164 av_log(NULL, AV_LOG_ERROR, "udp_resolve_host: %s\n", gai_strerror(error));
00165 }
00166
00167 return res;
00168 }
00169
00170 static int udp_set_url(struct sockaddr_storage *addr,
00171 const char *hostname, int port)
00172 {
00173 struct addrinfo *res0;
00174 int addr_len;
00175
00176 res0 = udp_resolve_host(hostname, port, SOCK_DGRAM, AF_UNSPEC, 0);
00177 if (res0 == 0) return AVERROR(EIO);
00178 memcpy(addr, res0->ai_addr, res0->ai_addrlen);
00179 addr_len = res0->ai_addrlen;
00180 freeaddrinfo(res0);
00181
00182 return addr_len;
00183 }
00184
00185 static int is_multicast_address(struct sockaddr_storage *addr)
00186 {
00187 if (addr->ss_family == AF_INET) {
00188 return IN_MULTICAST(ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr));
00189 }
00190 #if HAVE_STRUCT_SOCKADDR_IN6
00191 if (addr->ss_family == AF_INET6) {
00192 return IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6 *)addr)->sin6_addr);
00193 }
00194 #endif
00195
00196 return 0;
00197 }
00198
00199 static int udp_socket_create(UDPContext *s,
00200 struct sockaddr_storage *addr, int *addr_len)
00201 {
00202 int udp_fd = -1;
00203 struct addrinfo *res0 = NULL, *res = NULL;
00204 int family = AF_UNSPEC;
00205
00206 if (((struct sockaddr *) &s->dest_addr)->sa_family)
00207 family = ((struct sockaddr *) &s->dest_addr)->sa_family;
00208 res0 = udp_resolve_host(0, s->local_port, SOCK_DGRAM, family, AI_PASSIVE);
00209 if (res0 == 0)
00210 goto fail;
00211 for (res = res0; res; res=res->ai_next) {
00212 udp_fd = socket(res->ai_family, SOCK_DGRAM, 0);
00213 if (udp_fd > 0) break;
00214 av_log(NULL, AV_LOG_ERROR, "socket: %s\n", strerror(errno));
00215 }
00216
00217 if (udp_fd < 0)
00218 goto fail;
00219
00220 memcpy(addr, res->ai_addr, res->ai_addrlen);
00221 *addr_len = res->ai_addrlen;
00222
00223 freeaddrinfo(res0);
00224
00225 return udp_fd;
00226
00227 fail:
00228 if (udp_fd >= 0)
00229 closesocket(udp_fd);
00230 if(res0)
00231 freeaddrinfo(res0);
00232 return -1;
00233 }
00234
00235 static int udp_port(struct sockaddr_storage *addr, int addr_len)
00236 {
00237 char sbuf[sizeof(int)*3+1];
00238
00239 if (getnameinfo((struct sockaddr *)addr, addr_len, NULL, 0, sbuf, sizeof(sbuf), NI_NUMERICSERV) != 0) {
00240 av_log(NULL, AV_LOG_ERROR, "getnameinfo: %s\n", strerror(errno));
00241 return -1;
00242 }
00243
00244 return strtol(sbuf, NULL, 10);
00245 }
00246
00247
00263 int udp_set_remote_url(URLContext *h, const char *uri)
00264 {
00265 UDPContext *s = h->priv_data;
00266 char hostname[256];
00267 int port;
00268
00269 ff_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri);
00270
00271
00272 s->dest_addr_len = udp_set_url(&s->dest_addr, hostname, port);
00273 if (s->dest_addr_len < 0) {
00274 return AVERROR(EIO);
00275 }
00276 s->is_multicast = is_multicast_address(&s->dest_addr);
00277
00278 return 0;
00279 }
00280
00286 int udp_get_local_port(URLContext *h)
00287 {
00288 UDPContext *s = h->priv_data;
00289 return s->local_port;
00290 }
00291
00297 #if (LIBAVFORMAT_VERSION_MAJOR >= 53)
00298 static
00299 #endif
00300 int udp_get_file_handle(URLContext *h)
00301 {
00302 UDPContext *s = h->priv_data;
00303 return s->udp_fd;
00304 }
00305
00306
00307
00308 static int udp_open(URLContext *h, const char *uri, int flags)
00309 {
00310 char hostname[1024];
00311 int port, udp_fd = -1, tmp, bind_ret = -1;
00312 UDPContext *s = NULL;
00313 int is_output;
00314 const char *p;
00315 char buf[256];
00316 struct sockaddr_storage my_addr;
00317 int len;
00318
00319 h->is_streamed = 1;
00320 h->max_packet_size = 1472;
00321
00322 is_output = (flags & URL_WRONLY);
00323
00324 s = av_mallocz(sizeof(UDPContext));
00325 if (!s)
00326 return AVERROR(ENOMEM);
00327
00328 h->priv_data = s;
00329 s->ttl = 16;
00330 s->buffer_size = is_output ? UDP_TX_BUF_SIZE : UDP_MAX_PKT_SIZE;
00331
00332 p = strchr(uri, '?');
00333 if (p) {
00334 s->reuse_socket = find_info_tag(buf, sizeof(buf), "reuse", p);
00335 if (find_info_tag(buf, sizeof(buf), "ttl", p)) {
00336 s->ttl = strtol(buf, NULL, 10);
00337 }
00338 if (find_info_tag(buf, sizeof(buf), "localport", p)) {
00339 s->local_port = strtol(buf, NULL, 10);
00340 }
00341 if (find_info_tag(buf, sizeof(buf), "pkt_size", p)) {
00342 h->max_packet_size = strtol(buf, NULL, 10);
00343 }
00344 if (find_info_tag(buf, sizeof(buf), "buffer_size", p)) {
00345 s->buffer_size = strtol(buf, NULL, 10);
00346 }
00347 }
00348
00349
00350 ff_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri);
00351
00352
00353 if (hostname[0] == '\0' || hostname[0] == '?') {
00354
00355 if (flags & URL_WRONLY)
00356 goto fail;
00357 } else {
00358 udp_set_remote_url(h, uri);
00359 }
00360
00361 if (s->is_multicast && !(h->flags & URL_WRONLY))
00362 s->local_port = port;
00363 udp_fd = udp_socket_create(s, &my_addr, &len);
00364 if (udp_fd < 0)
00365 goto fail;
00366
00367 if (s->reuse_socket)
00368 if (setsockopt (udp_fd, SOL_SOCKET, SO_REUSEADDR, &(s->reuse_socket), sizeof(s->reuse_socket)) != 0)
00369 goto fail;
00370
00371
00372
00373 if (s->is_multicast && !(h->flags & URL_WRONLY)) {
00374 bind_ret = bind(udp_fd,(struct sockaddr *)&s->dest_addr, len);
00375 }
00376
00377
00378 if (bind_ret < 0 && bind(udp_fd,(struct sockaddr *)&my_addr, len) < 0)
00379 goto fail;
00380
00381 len = sizeof(my_addr);
00382 getsockname(udp_fd, (struct sockaddr *)&my_addr, &len);
00383 s->local_port = udp_port(&my_addr, len);
00384
00385 if (s->is_multicast) {
00386 if (h->flags & URL_WRONLY) {
00387
00388 if (udp_set_multicast_ttl(udp_fd, s->ttl, (struct sockaddr *)&s->dest_addr) < 0)
00389 goto fail;
00390 } else {
00391
00392 if (udp_join_multicast_group(udp_fd, (struct sockaddr *)&s->dest_addr) < 0)
00393 goto fail;
00394 }
00395 }
00396
00397 if (is_output) {
00398
00399 tmp = s->buffer_size;
00400 if (setsockopt(udp_fd, SOL_SOCKET, SO_SNDBUF, &tmp, sizeof(tmp)) < 0) {
00401 av_log(NULL, AV_LOG_ERROR, "setsockopt(SO_SNDBUF): %s\n", strerror(errno));
00402 goto fail;
00403 }
00404 } else {
00405
00406
00407 tmp = s->buffer_size;
00408 if (setsockopt(udp_fd, SOL_SOCKET, SO_RCVBUF, &tmp, sizeof(tmp)) < 0) {
00409 av_log(NULL, AV_LOG_WARNING, "setsockopt(SO_RECVBUF): %s\n", strerror(errno));
00410 }
00411
00412 ff_socket_nonblock(udp_fd, 1);
00413 }
00414
00415 s->udp_fd = udp_fd;
00416 return 0;
00417 fail:
00418 if (udp_fd >= 0)
00419 closesocket(udp_fd);
00420 av_free(s);
00421 return AVERROR(EIO);
00422 }
00423
00424 static int udp_read(URLContext *h, uint8_t *buf, int size)
00425 {
00426 UDPContext *s = h->priv_data;
00427 int len;
00428 fd_set rfds;
00429 int ret;
00430 struct timeval tv;
00431
00432 for(;;) {
00433 if (url_interrupt_cb())
00434 return AVERROR(EINTR);
00435 FD_ZERO(&rfds);
00436 FD_SET(s->udp_fd, &rfds);
00437 tv.tv_sec = 0;
00438 tv.tv_usec = 100 * 1000;
00439 ret = select(s->udp_fd + 1, &rfds, NULL, NULL, &tv);
00440 if (ret < 0) {
00441 if (ff_neterrno() == FF_NETERROR(EINTR))
00442 continue;
00443 return AVERROR(EIO);
00444 }
00445 if (!(ret > 0 && FD_ISSET(s->udp_fd, &rfds)))
00446 continue;
00447 len = recv(s->udp_fd, buf, size, 0);
00448 if (len < 0) {
00449 if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
00450 ff_neterrno() != FF_NETERROR(EINTR))
00451 return AVERROR(EIO);
00452 } else {
00453 break;
00454 }
00455 }
00456 return len;
00457 }
00458
00459 static int udp_write(URLContext *h, uint8_t *buf, int size)
00460 {
00461 UDPContext *s = h->priv_data;
00462 int ret;
00463
00464 for(;;) {
00465 ret = sendto (s->udp_fd, buf, size, 0,
00466 (struct sockaddr *) &s->dest_addr,
00467 s->dest_addr_len);
00468 if (ret < 0) {
00469 if (ff_neterrno() != FF_NETERROR(EINTR) &&
00470 ff_neterrno() != FF_NETERROR(EAGAIN))
00471 return AVERROR(EIO);
00472 } else {
00473 break;
00474 }
00475 }
00476 return size;
00477 }
00478
00479 static int udp_close(URLContext *h)
00480 {
00481 UDPContext *s = h->priv_data;
00482
00483 if (s->is_multicast && !(h->flags & URL_WRONLY))
00484 udp_leave_multicast_group(s->udp_fd, (struct sockaddr *)&s->dest_addr);
00485 closesocket(s->udp_fd);
00486 av_free(s);
00487 return 0;
00488 }
00489
00490 URLProtocol udp_protocol = {
00491 "udp",
00492 udp_open,
00493 udp_read,
00494 udp_write,
00495 NULL,
00496 udp_close,
00497 .url_get_file_handle = udp_get_file_handle,
00498 };