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