Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
* [FFmpeg-devel] [PATCH] libavformat/tcp: add local_addr/local_port for network option
@ 2023-02-28 10:16 jack
  2023-02-28 10:57 ` Nicolas George
  2023-02-28 15:44 ` jackarain
  0 siblings, 2 replies; 13+ messages in thread
From: jack @ 2023-02-28 10:16 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: jack

Signed-off-by: jack <jack.wgm@gmail.com>
---
 libavformat/tcp.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 44 insertions(+)

diff --git a/libavformat/tcp.c b/libavformat/tcp.c
index a11ccbb913..598d61067e 100644
--- a/libavformat/tcp.c
+++ b/libavformat/tcp.c
@@ -36,6 +36,8 @@ typedef struct TCPContext {
     const AVClass *class;
     int fd;
     int listen;
+    int 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_INT,    { .i64 = -1 },      -1, INT_MAX, .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 },
@@ -73,6 +77,39 @@ static const AVClass tcp_class = {
 static void customize_fd(void *ctx, int fd)
 {
     TCPContext *s = ctx;
+
+    if (s->local_addr) {
+        struct addrinfo hints = { 0 }, *ai;
+        int ret;
+        int port = 0;
+
+        hints.ai_family = AF_UNSPEC;
+        hints.ai_socktype = SOCK_STREAM;
+
+        if (s->local_port > 0)
+            port = s->local_port;
+
+        ret = getaddrinfo(s->local_addr, "0", &hints, &ai);
+        if (ret) {
+            av_log(ctx, AV_LOG_WARNING,
+               "Failed to bind local addr: %s port: %d err: %s\n",
+                s->local_addr, s->local_port, gai_strerror(ret));
+        } else {
+            if (ai->ai_family == AF_INET6) {
+                struct sockaddr_in6 * sockaddr_v6 = (struct sockaddr_in6 *)ai->ai_addr;
+                sockaddr_v6->sin6_port = htons(port);
+            } else {
+                struct sockaddr_in * sockaddr = (struct sockaddr_in *)ai->ai_addr;
+                sockaddr->sin_port = htons(port);
+            }
+            ret = bind(fd, (struct sockaddr *)ai->ai_addr, (int)ai->ai_addrlen);
+            if (ret) {
+                av_log(ctx, AV_LOG_WARNING,
+                "Failed to bind local addr: %s port: %d err: %s\n",
+                    s->local_addr, s->local_port, gai_strerror(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) {
@@ -129,6 +166,13 @@ 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)) {
+            s->local_port = strtol(buf, NULL, 10);
+        }
+        if (av_find_info_tag(buf, sizeof(buf), "local_addr", p)) {
+            av_freep(&s->local_addr);
+            s->local_addr = av_strndup(buf, strlen(buf));
+        }
         if (av_find_info_tag(buf, sizeof(buf), "timeout", p)) {
             s->rw_timeout = strtol(buf, NULL, 10);
         }
-- 
2.39.2

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [FFmpeg-devel] [PATCH] libavformat/tcp: add local_addr/local_port for network option
  2023-02-28 10:16 [FFmpeg-devel] [PATCH] libavformat/tcp: add local_addr/local_port for network option jack
@ 2023-02-28 10:57 ` Nicolas George
  2023-02-28 14:27   ` jackarain
  2023-02-28 15:44 ` jackarain
  1 sibling, 1 reply; 13+ messages in thread
From: Nicolas George @ 2023-02-28 10:57 UTC (permalink / raw)
  To: FFmpeg development discussions and patches; +Cc: jack

jack (12023-02-28):
> Signed-off-by: jack <jack.wgm@gmail.com>
> ---
>  libavformat/tcp.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 44 insertions(+)

Thanks for the patch

You neglected to update the documentation, and a few remarks below.

> 
> diff --git a/libavformat/tcp.c b/libavformat/tcp.c
> index a11ccbb913..598d61067e 100644
> --- a/libavformat/tcp.c
> +++ b/libavformat/tcp.c
> @@ -36,6 +36,8 @@ typedef struct TCPContext {
>      const AVClass *class;
>      int fd;
>      int listen;
> +    int 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_INT,    { .i64 = -1 },      -1, INT_MAX, .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 },
> @@ -73,6 +77,39 @@ static const AVClass tcp_class = {
>  static void customize_fd(void *ctx, int fd)
>  {
>      TCPContext *s = ctx;
> +

> +    if (s->local_addr) {

s->local_addr || s->local_port

> +        struct addrinfo hints = { 0 }, *ai;
> +        int ret;
> +        int port = 0;
> +
> +        hints.ai_family = AF_UNSPEC;
> +        hints.ai_socktype = SOCK_STREAM;
> +
> +        if (s->local_port > 0)
> +            port = s->local_port;
> +

> +        ret = getaddrinfo(s->local_addr, "0", &hints, &ai);

The provided port should be used instead of this "0", and be a string,
and named service.

(The remote port should be a string too, alas.)

> +        if (ret) {

> +            av_log(ctx, AV_LOG_WARNING,
> +               "Failed to bind local addr: %s port: %d err: %s\n",
> +                s->local_addr, s->local_port, gai_strerror(ret));

Should be an error: failing to bind on the specified address can be a
security issue. And the error message is misleading.

> +        } else {

> +            if (ai->ai_family == AF_INET6) {
> +                struct sockaddr_in6 * sockaddr_v6 = (struct sockaddr_in6 *)ai->ai_addr;
> +                sockaddr_v6->sin6_port = htons(port);
> +            } else {
> +                struct sockaddr_in * sockaddr = (struct sockaddr_in *)ai->ai_addr;
> +                sockaddr->sin_port = htons(port);
> +            }

Do not distinguish between protocols: ai_addr already contains all that
is needed.

> +            ret = bind(fd, (struct sockaddr *)ai->ai_addr, (int)ai->ai_addrlen);
> +            if (ret) {
> +                av_log(ctx, AV_LOG_WARNING,
> +                "Failed to bind local addr: %s port: %d err: %s\n",
> +                    s->local_addr, s->local_port, gai_strerror(ret));
> +            }

You should be looping over the returned addresses.

> +        }
> +    }
>      /* 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) {
> @@ -129,6 +166,13 @@ 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)) {
> +            s->local_port = strtol(buf, NULL, 10);
> +        }
> +        if (av_find_info_tag(buf, sizeof(buf), "local_addr", p)) {
> +            av_freep(&s->local_addr);
> +            s->local_addr = av_strndup(buf, strlen(buf));
> +        }
>          if (av_find_info_tag(buf, sizeof(buf), "timeout", p)) {
>              s->rw_timeout = strtol(buf, NULL, 10);
>          }

Regards,

-- 
  Nicolas George
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [FFmpeg-devel] [PATCH] libavformat/tcp: add local_addr/local_port for network option
  2023-02-28 10:57 ` Nicolas George
@ 2023-02-28 14:27   ` jackarain
  0 siblings, 0 replies; 13+ messages in thread
From: jackarain @ 2023-02-28 14:27 UTC (permalink / raw)
  To: ffmpeg-devel

Done.

Nicolas George <george@nsup.org> 于2023年2月28日周二 18:57写道:

> jack (12023-02-28):
> > Signed-off-by: jack <jack.wgm@gmail.com>
> > ---
> >  libavformat/tcp.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 44 insertions(+)
>
> Thanks for the patch
>
> You neglected to update the documentation, and a few remarks below.
>
> >
> > diff --git a/libavformat/tcp.c b/libavformat/tcp.c
> > index a11ccbb913..598d61067e 100644
> > --- a/libavformat/tcp.c
> > +++ b/libavformat/tcp.c
> > @@ -36,6 +36,8 @@ typedef struct TCPContext {
> >      const AVClass *class;
> >      int fd;
> >      int listen;
> > +    int 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_INT,    { .i64 = -1 },      -1,
> INT_MAX, .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 },
> > @@ -73,6 +77,39 @@ static const AVClass tcp_class = {
> >  static void customize_fd(void *ctx, int fd)
> >  {
> >      TCPContext *s = ctx;
> > +
>
> > +    if (s->local_addr) {
>
> s->local_addr || s->local_port
>
> > +        struct addrinfo hints = { 0 }, *ai;
> > +        int ret;
> > +        int port = 0;
> > +
> > +        hints.ai_family = AF_UNSPEC;
> > +        hints.ai_socktype = SOCK_STREAM;
> > +
> > +        if (s->local_port > 0)
> > +            port = s->local_port;
> > +
>
> > +        ret = getaddrinfo(s->local_addr, "0", &hints, &ai);
>
> The provided port should be used instead of this "0", and be a string,
> and named service.
>
> (The remote port should be a string too, alas.)
>
> > +        if (ret) {
>
> > +            av_log(ctx, AV_LOG_WARNING,
> > +               "Failed to bind local addr: %s port: %d err: %s\n",
> > +                s->local_addr, s->local_port, gai_strerror(ret));
>
> Should be an error: failing to bind on the specified address can be a
> security issue. And the error message is misleading.
>
> > +        } else {
>
> > +            if (ai->ai_family == AF_INET6) {
> > +                struct sockaddr_in6 * sockaddr_v6 = (struct
> sockaddr_in6 *)ai->ai_addr;
> > +                sockaddr_v6->sin6_port = htons(port);
> > +            } else {
> > +                struct sockaddr_in * sockaddr = (struct sockaddr_in
> *)ai->ai_addr;
> > +                sockaddr->sin_port = htons(port);
> > +            }
>
> Do not distinguish between protocols: ai_addr already contains all that
> is needed.
>
> > +            ret = bind(fd, (struct sockaddr *)ai->ai_addr,
> (int)ai->ai_addrlen);
> > +            if (ret) {
> > +                av_log(ctx, AV_LOG_WARNING,
> > +                "Failed to bind local addr: %s port: %d err: %s\n",
> > +                    s->local_addr, s->local_port, gai_strerror(ret));
> > +            }
>
> You should be looping over the returned addresses.
>
> > +        }
> > +    }
> >      /* 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) {
> > @@ -129,6 +166,13 @@ 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)) {
> > +            s->local_port = strtol(buf, NULL, 10);
> > +        }
> > +        if (av_find_info_tag(buf, sizeof(buf), "local_addr", p)) {
> > +            av_freep(&s->local_addr);
> > +            s->local_addr = av_strndup(buf, strlen(buf));
> > +        }
> >          if (av_find_info_tag(buf, sizeof(buf), "timeout", p)) {
> >              s->rw_timeout = strtol(buf, NULL, 10);
> >          }
>
> Regards,
>
> --
>   Nicolas George
>
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [FFmpeg-devel] [PATCH] libavformat/tcp: add local_addr/local_port for network option
  2023-02-28 10:16 [FFmpeg-devel] [PATCH] libavformat/tcp: add local_addr/local_port for network option jack
  2023-02-28 10:57 ` Nicolas George
@ 2023-02-28 15:44 ` jackarain
  2023-03-01 14:44   ` Anton Khirnov
  1 sibling, 1 reply; 13+ messages in thread
From: jackarain @ 2023-02-28 15:44 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: george, jackarain

Signed-off-by: jackarain <jack.wgm@gmail.com>
---
 doc/protocols.texi    |  6 ++++++
 libavformat/network.c | 14 +++++++++----
 libavformat/network.h |  2 +-
 libavformat/tcp.c     | 49 ++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 65 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.
 
+@item local_addr=@var{addr}
+Local IP address of a network interface used for tcp socket connect.
+
+@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..f9900c56a7 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;
+        int ret;
+
+        hints.ai_family = AF_UNSPEC;
+        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;
+        } else {
+            struct addrinfo *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,14 @@ 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_strndup(buf, strlen(buf));
+        }
+        if (av_find_info_tag(buf, sizeof(buf), "local_addr", p)) {
+            av_freep(&s->local_addr);
+            s->local_addr = av_strndup(buf, strlen(buf));
+        }
         if (av_find_info_tag(buf, sizeof(buf), "timeout", p)) {
             s->rw_timeout = strtol(buf, NULL, 10);
         }
-- 
2.39.2

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [FFmpeg-devel] [PATCH] libavformat/tcp: add local_addr/local_port for network option
  2023-02-28 15:44 ` jackarain
@ 2023-03-01 14:44   ` Anton Khirnov
  2023-03-01 14:56     ` jackarain
  2023-03-01 15:07     ` jackarain
  0 siblings, 2 replies; 13+ messages in thread
From: Anton Khirnov @ 2023-03-01 14:44 UTC (permalink / raw)
  To: FFmpeg development discussions and patches; +Cc: jackarain

Quoting jackarain (2023-02-28 16:44:20)
> -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;
> +        int ret;
> +
> +        hints.ai_family = AF_UNSPEC;
> +        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;
> +        } else {

nit: the else clause pointlessly adds an indentation level and serves no
useful purpose

> +            struct addrinfo *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,14 @@ 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_strndup(buf, strlen(buf));

This does memory allocation, so the result should be checked. Also, it
av_str_n_dup() gives you no advantages since you call strlen anyway.
Just use av_strdup(). Same below.

-- 
Anton Khirnov
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [FFmpeg-devel] [PATCH] libavformat/tcp: add local_addr/local_port for network option
  2023-03-01 14:44   ` Anton Khirnov
@ 2023-03-01 14:56     ` jackarain
  2023-03-01 15:07     ` jackarain
  1 sibling, 0 replies; 13+ messages in thread
From: jackarain @ 2023-03-01 14:56 UTC (permalink / raw)
  To: FFmpeg development discussions and patches, george, jackarain

Ok, thanks.

Anton Khirnov <anton@khirnov.net> 于2023年3月1日周三 22:44写道:

> Quoting jackarain (2023-02-28 16:44:20)
> > -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;
> > +        int ret;
> > +
> > +        hints.ai_family = AF_UNSPEC;
> > +        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;
> > +        } else {
>
> nit: the else clause pointlessly adds an indentation level and serves no
> useful purpose
>
> > +            struct addrinfo *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,14 @@ 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_strndup(buf, strlen(buf));
>
> This does memory allocation, so the result should be checked. Also, it
> av_str_n_dup() gives you no advantages since you call strlen anyway.
> Just use av_strdup(). Same below.
>
> --
> Anton Khirnov
>
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [FFmpeg-devel] [PATCH] libavformat/tcp: add local_addr/local_port for network option
  2023-03-01 14:44   ` Anton Khirnov
  2023-03-01 14:56     ` jackarain
@ 2023-03-01 15:07     ` jackarain
  2023-03-01 15:44       ` jackarain
  1 sibling, 1 reply; 13+ messages in thread
From: jackarain @ 2023-03-01 15:07 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: jackarain

Signed-off-by: jackarain <jack.wgm@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.
 
+@item local_addr=@var{addr}
+Local IP address of a network interface used for tcp socket connect.
+
+@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..1987861353 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;
+        int ret;
+
+        hints.ai_family = AF_UNSPEC;
+        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;
+        }
+
+        struct addrinfo *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);
         }
-- 
2.39.2

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [FFmpeg-devel] [PATCH] libavformat/tcp: add local_addr/local_port for network option
  2023-03-01 15:07     ` jackarain
@ 2023-03-01 15:44       ` jackarain
  2023-03-02 18:47         ` Rémi Denis-Courmont
  0 siblings, 1 reply; 13+ messages in thread
From: jackarain @ 2023-03-01 15:44 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: jackarain

Signed-off-by: jackarain <jack.wgm@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.
 
+@item local_addr=@var{addr}
+Local IP address of a network interface used for tcp socket connect.
+
+@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;
+        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);
         }
-- 
2.39.2

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [FFmpeg-devel] [PATCH] libavformat/tcp: add local_addr/local_port for network option
  2023-03-01 15:44       ` jackarain
@ 2023-03-02 18:47         ` Rémi Denis-Courmont
  2023-03-02 18:51           ` Nicolas George
  0 siblings, 1 reply; 13+ messages in thread
From: Rémi Denis-Courmont @ 2023-03-02 18:47 UTC (permalink / raw)
  To: ffmpeg-devel

Le keskiviikkona 1. maaliskuuta 2023, 17.44.56 EET jackarain a écrit :
> Signed-off-by: jackarain <jack.wgm@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.
> 
> +@item local_addr=@var{addr}
> +Local IP address of a network interface used for tcp socket connect.
> +
> +@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/



_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [FFmpeg-devel] [PATCH] libavformat/tcp: add local_addr/local_port for network option
  2023-03-02 18:47         ` Rémi Denis-Courmont
@ 2023-03-02 18:51           ` Nicolas George
  2023-03-03  9:49             ` jackarain
  0 siblings, 1 reply; 13+ messages in thread
From: Nicolas George @ 2023-03-02 18:51 UTC (permalink / raw)
  To: FFmpeg development discussions and patches


[-- Attachment #1.1: Type: text/plain, Size: 336 bytes --]

Rémi Denis-Courmont (12023-03-02):
> That needs to match the socket protocol family, or bind() will fail.

Oh, right! The proper way to work with getaddrinfo is to create the
socket afterwards based on its return, but staying within a family is a
good second best choice. Thanks for noticing.

Regards,

-- 
  Nicolas George

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

[-- Attachment #2: Type: text/plain, Size: 251 bytes --]

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [FFmpeg-devel] [PATCH] libavformat/tcp: add local_addr/local_port for network option
  2023-03-02 18:51           ` Nicolas George
@ 2023-03-03  9:49             ` jackarain
  2023-03-30 10:11               ` Anton Khirnov
  0 siblings, 1 reply; 13+ messages in thread
From: jackarain @ 2023-03-03  9:49 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: george, jackarain, remi, anton

Signed-off-by: jackarain <jack.wgm@gmail.com>
---
 doc/protocols.texi    |  6 +++++
 libavformat/network.c | 14 ++++++++----
 libavformat/network.h |  2 +-
 libavformat/tcp.c     | 53 +++++++++++++++++++++++++++++++++++++++++--
 4 files changed, 68 insertions(+), 7 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.
 
+@item local_addr=@var{addr}
+Local IP address of a network interface used for tcp socket connect.
+
+@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..f752efc411 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, 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, ai->ai_family);
+        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, int), void *customize_ctx)
 {
     struct ConnectionAttempt attempts[3];
     struct pollfd pfd[3];
diff --git a/libavformat/network.h b/libavformat/network.h
index 71c49a73fb..ca214087fc 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, int), void *customize_ctx);
 
 #endif /* AVFORMAT_NETWORK_H */
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) {
-- 
2.39.2

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [FFmpeg-devel] [PATCH] libavformat/tcp: add local_addr/local_port for network option
  2023-03-03  9:49             ` jackarain
@ 2023-03-30 10:11               ` Anton Khirnov
  0 siblings, 0 replies; 13+ messages in thread
From: Anton Khirnov @ 2023-03-30 10:11 UTC (permalink / raw)
  To: ffmpeg-devel, jackarain

Pushed with a micro version bump.

-- 
Anton Khirnov
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [FFmpeg-devel] [PATCH] libavformat/tcp: add local_addr/local_port for network option
@ 2023-02-28 14:24 jackarain
  0 siblings, 0 replies; 13+ messages in thread
From: jackarain @ 2023-02-28 14:24 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: jackarain

Signed-off-by: jackarain <jack.wgm@gmail.com>
---
 doc/protocols.texi    |  6 ++++++
 libavformat/network.c | 14 +++++++++----
 libavformat/network.h |  2 +-
 libavformat/tcp.c     | 48 ++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 64 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.
 
+@item local_addr=@var{addr}
+Local IP address of a network interface used for tcp socket connect.
+
+@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..ceb5a10426 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,41 @@ 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;
+        int ret;
+
+        hints.ai_family = AF_UNSPEC;
+        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: %d err: %s\n",
+                s->local_addr, s->local_port, gai_strerror(ret));
+            return ret;
+        } else {
+            struct addrinfo *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;
+            }
+
+            if (ret) {
+                av_log(ctx, AV_LOG_ERROR,
+                    "Failed to bind local addr: %s port: %d 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 +133,8 @@ static void customize_fd(void *ctx, int fd)
         }
     }
 #endif /* !HAVE_WINSOCK2_H */
+
+    return 0;
 }
 
 /* return non zero if error */
@@ -129,6 +167,14 @@ 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_strndup(buf, strlen(buf));
+        }
+        if (av_find_info_tag(buf, sizeof(buf), "local_addr", p)) {
+            av_freep(&s->local_addr);
+            s->local_addr = av_strndup(buf, strlen(buf));
+        }
         if (av_find_info_tag(buf, sizeof(buf), "timeout", p)) {
             s->rw_timeout = strtol(buf, NULL, 10);
         }
-- 
2.39.2

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2023-03-30 10:11 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-02-28 10:16 [FFmpeg-devel] [PATCH] libavformat/tcp: add local_addr/local_port for network option jack
2023-02-28 10:57 ` Nicolas George
2023-02-28 14:27   ` jackarain
2023-02-28 15:44 ` jackarain
2023-03-01 14:44   ` Anton Khirnov
2023-03-01 14:56     ` jackarain
2023-03-01 15:07     ` jackarain
2023-03-01 15:44       ` jackarain
2023-03-02 18:47         ` Rémi Denis-Courmont
2023-03-02 18:51           ` Nicolas George
2023-03-03  9:49             ` jackarain
2023-03-30 10:11               ` Anton Khirnov
2023-02-28 14:24 jackarain

Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
		ffmpegdev@gitmailbox.com
	public-inbox-index ffmpegdev

Example config snippet for mirrors.


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git