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