[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