diff options
author | jackarain <jack.wgm@gmail.com> | 2023-03-03 17:49:26 +0800 |
---|---|---|
committer | Anton Khirnov <anton@khirnov.net> | 2023-03-30 12:09:49 +0200 |
commit | 4d216654ca72dfd23fcafcc5195db0eb9bdd483b (patch) | |
tree | ba3078191d7f2f2a1b8fc373768563befe4b2406 /libavformat/tcp.c | |
parent | 0684e58886881a998f1a7b510d73600ff1df2b90 (diff) | |
download | ffmpeg-4d216654ca72dfd23fcafcc5195db0eb9bdd483b.tar.gz |
libavformat/tcp: add local_addr/local_port for network option
Signed-off-by: jackarain <jack.wgm@gmail.com>
Signed-off-by: Anton Khirnov <anton@khirnov.net>
Diffstat (limited to 'libavformat/tcp.c')
-rw-r--r-- | libavformat/tcp.c | 53 |
1 files changed, 51 insertions, 2 deletions
diff --git a/libavformat/tcp.c b/libavformat/tcp.c index a11ccbb913..a889633457 100644 --- a/libavformat/tcp.c +++ b/libavformat/tcp.c @@ -36,6 +36,8 @@ typedef struct TCPContext { const AVClass *class; int fd; int listen; + char *local_port; + char *local_addr; int open_timeout; int rw_timeout; int listen_timeout; @@ -52,6 +54,8 @@ typedef struct TCPContext { #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, 2, .flags = D|E }, + { "local_port", "Local port", OFFSET(local_port), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, .flags = D|E }, + { "local_addr", "Local address", OFFSET(local_addr), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, .flags = D|E }, { "timeout", "set timeout (in microseconds) of socket I/O operations", OFFSET(rw_timeout), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E }, { "listen_timeout", "Connection awaiting timeout (in milliseconds)", OFFSET(listen_timeout), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E }, { "send_buffer_size", "Socket send buffer size (in bytes)", OFFSET(send_buffer_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E }, @@ -70,9 +74,40 @@ static const AVClass tcp_class = { .version = LIBAVUTIL_VERSION_INT, }; -static void customize_fd(void *ctx, int fd) +static int customize_fd(void *ctx, int fd, int family) { TCPContext *s = ctx; + + if (s->local_addr || s->local_port) { + struct addrinfo hints = { 0 }, *ai, *cur_ai; + int ret; + + hints.ai_family = family; + hints.ai_socktype = SOCK_STREAM; + + ret = getaddrinfo(s->local_addr, s->local_port, &hints, &ai); + if (ret) { + av_log(ctx, AV_LOG_ERROR, + "Failed to getaddrinfo local addr: %s port: %s err: %s\n", + s->local_addr, s->local_port, gai_strerror(ret)); + return ret; + } + + cur_ai = ai; + while (cur_ai) { + ret = bind(fd, (struct sockaddr *)cur_ai->ai_addr, (int)cur_ai->ai_addrlen); + if (ret) + cur_ai = cur_ai->ai_next; + else + break; + } + freeaddrinfo(ai); + + if (ret) { + ff_log_net_error(ctx, AV_LOG_ERROR, "bind local failed"); + return ret; + } + } /* Set the socket's send or receive buffer sizes, if specified. If unspecified or setting fails, system default is used. */ if (s->recv_buffer_size > 0) { @@ -97,6 +132,8 @@ static void customize_fd(void *ctx, int fd) } } #endif /* !HAVE_WINSOCK2_H */ + + return 0; } /* return non zero if error */ @@ -129,6 +166,18 @@ static int tcp_open(URLContext *h, const char *uri, int flags) if (buf == endptr) s->listen = 1; } + if (av_find_info_tag(buf, sizeof(buf), "local_port", p)) { + av_freep(&s->local_port); + s->local_port = av_strdup(buf); + if (!s->local_addr) + return AVERROR(ENOMEM); + } + if (av_find_info_tag(buf, sizeof(buf), "local_addr", p)) { + av_freep(&s->local_addr); + s->local_addr = av_strdup(buf); + if (!s->local_addr) + return AVERROR(ENOMEM); + } if (av_find_info_tag(buf, sizeof(buf), "timeout", p)) { s->rw_timeout = strtol(buf, NULL, 10); } @@ -183,7 +232,7 @@ static int tcp_open(URLContext *h, const char *uri, int flags) } if (fd < 0) goto fail1; - customize_fd(s, fd); + customize_fd(s, fd, cur_ai->ai_family); } if (s->listen == 2) { |