X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Ftcp.c;h=5badf4f4382d4a0556728e3be18d429570896af5;hb=a67b67944aa9e6e794934d15f9fd9a9cf7173e09;hp=bdaab7f806cae6e0a123409c0c4df7dc0fb078e8;hpb=f9a9a148622530cb02dbb81b31d951785f6d331a;p=ffmpeg diff --git a/libavformat/tcp.c b/libavformat/tcp.c index bdaab7f806c..5badf4f4382 100644 --- a/libavformat/tcp.c +++ b/libavformat/tcp.c @@ -20,6 +20,8 @@ */ #include "avformat.h" #include "libavutil/parseutils.h" +#include "libavutil/opt.h" + #include "internal.h" #include "network.h" #include "os_support.h" @@ -29,21 +31,39 @@ #endif typedef struct TCPContext { + const AVClass *class; int fd; + int listen; + int timeout; + int listen_timeout; } TCPContext; +#define OFFSET(x) offsetof(TCPContext, x) +#define D AV_OPT_FLAG_DECODING_PARAM +#define E AV_OPT_FLAG_ENCODING_PARAM +static const AVOption options[] = { + { "listen", "Listen for incoming connections", OFFSET(listen), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, .flags = D|E }, + { "timeout", "Connection timeout (in milliseconds)", OFFSET(timeout), AV_OPT_TYPE_INT, { .i64 = 10000 }, INT_MIN, INT_MAX, .flags = D|E }, + { "listen_timeout", "Bind timeout (in milliseconds)", OFFSET(listen_timeout), AV_OPT_TYPE_INT, { .i64 = -1 }, INT_MIN, INT_MAX, .flags = D|E }, + { NULL } +}; + +static const AVClass tcp_class = { + .class_name = "tcp", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + /* 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; - socklen_t optlen; - int timeout = 100, listen_timeout = -1; char hostname[1024],proto[1024],path[1024]; char portstr[10]; @@ -58,18 +78,18 @@ static int tcp_open(URLContext *h, const char *uri, int flags) p = strchr(uri, '?'); if (p) { if (av_find_info_tag(buf, sizeof(buf), "listen", p)) - listen_socket = 1; + s->listen = 1; if (av_find_info_tag(buf, sizeof(buf), "timeout", p)) { - timeout = strtol(buf, NULL, 10); + s->timeout = strtol(buf, NULL, 10) * 100; } if (av_find_info_tag(buf, sizeof(buf), "listen_timeout", p)) { - listen_timeout = strtol(buf, NULL, 10); + s->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) + if (s->listen) hints.ai_flags |= AI_PASSIVE; if (!hostname[0]) ret = getaddrinfo(NULL, portstr, &hints, &ai); @@ -85,87 +105,31 @@ static int tcp_open(URLContext *h, const char *uri, int flags) cur_ai = ai; restart: - ret = AVERROR(EIO); - fd = socket(cur_ai->ai_family, cur_ai->ai_socktype, cur_ai->ai_protocol); - if (fd < 0) + 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) { - int fd1; - int reuse = 1; - struct pollfd lp = { fd, POLLIN, 0 }; - setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); - ret = bind(fd, cur_ai->ai_addr, cur_ai->ai_addrlen); - if (ret) { - ret = ff_neterrno(); - goto fail1; - } - ret = listen(fd, 1); - if (ret) { - ret = ff_neterrno(); - goto fail1; - } - ret = poll(&lp, 1, listen_timeout >= 0 ? listen_timeout : -1); - if (ret <= 0) { - ret = AVERROR(ETIMEDOUT); + if (s->listen) { + if ((ret = ff_listen_bind(fd, cur_ai->ai_addr, cur_ai->ai_addrlen, + s->listen_timeout, h)) < 0) { goto fail1; } - fd1 = accept(fd, NULL, NULL); - if (fd1 < 0) { - ret = ff_neterrno(); - goto fail1; - } - closesocket(fd); - fd = fd1; - ff_socket_nonblock(fd, 1); + fd = ret; } else { - redo: - ff_socket_nonblock(fd, 1); - ret = connect(fd, cur_ai->ai_addr, cur_ai->ai_addrlen); - } + if ((ret = ff_listen_connect(fd, cur_ai->ai_addr, cur_ai->ai_addrlen, + s->timeout, h, !!cur_ai->ai_next)) < 0) { - if (ret < 0) { - struct pollfd p = {fd, POLLOUT, 0}; - ret = ff_neterrno(); - if (ret == AVERROR(EINTR)) { - if (ff_check_interrupt(&h->interrupt_callback)) { - ret = AVERROR_EXIT; + if (ret == AVERROR_EXIT) goto fail1; - } - goto redo; - } - if (ret != AVERROR(EINPROGRESS) && - ret != AVERROR(EAGAIN)) - goto fail; - - /* wait until we are connected or until abort */ - while(timeout--) { - if (ff_check_interrupt(&h->interrupt_callback)) { - ret = AVERROR_EXIT; - goto fail1; - } - ret = poll(&p, 1, 100); - if (ret > 0) - break; - } - if (ret <= 0) { - ret = AVERROR(ETIMEDOUT); - goto fail; - } - /* test error */ - optlen = sizeof(ret); - if (getsockopt (fd, SOL_SOCKET, SO_ERROR, &ret, &optlen)) - ret = AVUNERROR(ff_neterrno()); - if (ret != 0) { - char errbuf[100]; - ret = AVERROR(ret); - av_strerror(ret, errbuf, sizeof(errbuf)); - av_log(h, AV_LOG_ERROR, - "TCP connection to %s:%d failed: %s\n", - hostname, port, errbuf); - goto fail; + else + goto fail; } } + h->is_streamed = 1; s->fd = fd; freeaddrinfo(ai); @@ -177,6 +141,7 @@ static int tcp_open(URLContext *h, const char *uri, int flags) cur_ai = cur_ai->ai_next; if (fd >= 0) closesocket(fd); + ret = 0; goto restart; } fail1: @@ -210,7 +175,7 @@ static int tcp_write(URLContext *h, const uint8_t *buf, int size) if (ret < 0) return ret; } - ret = send(s->fd, buf, size, 0); + ret = send(s->fd, buf, size, MSG_NOSIGNAL); return ret < 0 ? ff_neterrno() : ret; } @@ -253,4 +218,5 @@ URLProtocol ff_tcp_protocol = { .url_shutdown = tcp_shutdown, .priv_data_size = sizeof(TCPContext), .flags = URL_PROTOCOL_FLAG_NETWORK, + .priv_data_class = &tcp_class, };