[FFmpeg-devel] [PATCH] libavformat/tcp: add local_addr/local_port for network option
Rémi Denis-Courmont
remi at remlab.net
Thu Mar 2 20:47:52 EET 2023
Le keskiviikkona 1. maaliskuuta 2023, 17.44.56 EET jackarain a écrit :
> Signed-off-by: jackarain <jack.wgm at gmail.com>
> ---
> doc/protocols.texi | 6 +++++
> libavformat/network.c | 14 ++++++++----
> libavformat/network.h | 2 +-
> libavformat/tcp.c | 53 ++++++++++++++++++++++++++++++++++++++++++-
> 4 files changed, 69 insertions(+), 6 deletions(-)
>
> diff --git a/doc/protocols.texi b/doc/protocols.texi
> index 21ae6181a0..b3fad55591 100644
> --- a/doc/protocols.texi
> +++ b/doc/protocols.texi
> @@ -1882,6 +1882,12 @@ The list of supported options follows.
> Listen for an incoming connection. 0 disables listen, 1 enables listen in
> single client mode, 2 enables listen in multi-client mode. Default value is
> 0.
>
> + at item local_addr=@var{addr}
> +Local IP address of a network interface used for tcp socket connect.
> +
> + at item local_port=@var{port}
> +Local port used for tcp socket connect.
> +
> @item timeout=@var{microseconds}
> Set raise error timeout, expressed in microseconds.
>
> diff --git a/libavformat/network.c b/libavformat/network.c
> index 21e20b3e9a..de8b14be82 100644
> --- a/libavformat/network.c
> +++ b/libavformat/network.c
> @@ -356,7 +356,7 @@ struct ConnectionAttempt {
> static int start_connect_attempt(struct ConnectionAttempt *attempt,
> struct addrinfo **ptr, int timeout_ms,
> URLContext *h,
> - void (*customize_fd)(void *, int), void
> *customize_ctx) + int (*customize_fd)(void
> *, int), void *customize_ctx) {
> struct addrinfo *ai = *ptr;
> int ret;
> @@ -371,8 +371,14 @@ static int start_connect_attempt(struct
> ConnectionAttempt *attempt,
>
> ff_socket_nonblock(attempt->fd, 1);
>
> - if (customize_fd)
> - customize_fd(customize_ctx, attempt->fd);
> + if (customize_fd) {
> + ret = customize_fd(customize_ctx, attempt->fd);
> + if (ret) {
> + closesocket(attempt->fd);
> + attempt->fd = -1;
> + return ret;
> + }
> + }
>
> while ((ret = connect(attempt->fd, ai->ai_addr, ai->ai_addrlen))) {
> ret = ff_neterrno();
> @@ -402,7 +408,7 @@ static int start_connect_attempt(struct
> ConnectionAttempt *attempt,
>
> int ff_connect_parallel(struct addrinfo *addrs, int timeout_ms_per_address,
> int parallel, URLContext *h, int *fd,
> - void (*customize_fd)(void *, int), void
> *customize_ctx) + int (*customize_fd)(void *, int),
> void *customize_ctx) {
> struct ConnectionAttempt attempts[3];
> struct pollfd pfd[3];
> diff --git a/libavformat/network.h b/libavformat/network.h
> index 71c49a73fb..8a8cbe672e 100644
> --- a/libavformat/network.h
> +++ b/libavformat/network.h
> @@ -336,6 +336,6 @@ void ff_log_net_error(void *ctx, int level, const char*
> prefix); */
> int ff_connect_parallel(struct addrinfo *addrs, int timeout_ms_per_address,
> int parallel, URLContext *h, int *fd,
> - void (*customize_fd)(void *, int), void
> *customize_ctx); + int (*customize_fd)(void *, int),
> void *customize_ctx);
>
> #endif /* AVFORMAT_NETWORK_H */
> diff --git a/libavformat/tcp.c b/libavformat/tcp.c
> index a11ccbb913..a897174f6c 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,42 @@ 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)
> {
> TCPContext *s = ctx;
> +
> + if (s->local_addr || s->local_port) {
> + struct addrinfo hints = { 0 }, *ai, *cur_ai;
> + int ret;
> +
> + hints.ai_family = AF_UNSPEC;
That needs to match the socket protocol family, or bind() will fail.
> + 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) {
> + av_log(ctx, AV_LOG_ERROR,
> + "Failed to bind local addr: %s port: %s err: %s\n",
> + s->local_addr, s->local_port, gai_strerror(ret));
> + 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 +134,8 @@ static void customize_fd(void *ctx, int fd)
> }
> }
> #endif /* !HAVE_WINSOCK2_H */
> +
> + return 0;
> }
>
> /* return non zero if error */
> @@ -129,6 +168,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);
> }
--
レミ・デニ-クールモン
http://www.remlab.net/
More information about the ffmpeg-devel
mailing list