]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
iptv: allow to limit UDP ports for unicast inputs
authorArno DUBOIS <arno.du@orange.fr>
Thu, 26 Sep 2024 23:28:08 +0000 (01:28 +0200)
committerFlole <Flole998@users.noreply.github.com>
Tue, 8 Oct 2024 12:58:23 +0000 (14:58 +0200)
src/config.c
src/config.h
src/input/mpegts/iptv/iptv_rtcp.c
src/input/mpegts/iptv/iptv_rtsp.c
src/input/mpegts/iptv/iptv_udp.c
src/input/mpegts/satip/satip_frontend.c
src/satip/rtsp.c
src/udp.c
src/udp.h
src/upnp.c
src/webui/webui.c

index c5bd4ef4dbd86d060b810e91e1f0707680cb803e..a8b853d453b4f9fd68e2b3f79439d57ffbf5b255 100644 (file)
@@ -2199,9 +2199,13 @@ const idclass_t config_class = {
          .number = 6,
       },
       {
-         .name   = N_("Miscellaneous Settings"),
+         .name   = N_("Ports settings"),
          .number = 7,
       },
+      {
+         .name   = N_("Miscellaneous Settings"),
+         .number = 8,
+      },
       {}
   },
   .ic_properties = (const property_t[]){
@@ -2647,6 +2651,28 @@ const idclass_t config_class = {
 ,
       .group  = 6
     },
+    {
+      .type   = PT_INT,
+      .id     = "rtsp_udp_min_port",
+      .name   = N_("RTSP UDP minimum port"),
+      .desc   = N_("When using RTSP IPTV, this correspond to the "
+                   "minimum port bind on the client (this server), "
+                   "sent to the server. This is especially useful "
+                   "when using firewalls and NAT or containers."),
+      .off    = offsetof(config_t, rtsp_udp_min_port),
+      .opts   = PO_EXPERT,
+      .group  = 7,
+    },
+    {
+      .type   = PT_INT,
+      .id     = "rtsp_udp_max_port",
+      .name   = N_("RTSP UDP maximum port"),
+      .desc   = N_("Same as above, but for the maximum allowed "
+                   "port. Note that each stream requires two ports."),
+      .off    = offsetof(config_t, rtsp_udp_max_port),
+      .opts   = PO_EXPERT,
+      .group  = 7,
+    },
     {
       .type   = PT_STR,
       .id     = "http_user_agent",
@@ -2654,7 +2680,7 @@ const idclass_t config_class = {
       .desc   = N_("The user agent string for the build-in HTTP client."),
       .off    = offsetof(config_t, http_user_agent),
       .opts   = PO_HIDDEN | PO_EXPERT,
-      .group  = 7,
+      .group  = 8,
     },
     {
       .type   = PT_INT,
@@ -2663,7 +2689,7 @@ const idclass_t config_class = {
       .desc   = N_("Set the number of threads for IPTV to split load "
                    "across more CPUs."),
       .off    = offsetof(config_t, iptv_tpool_count),
-      .group  = 7,
+      .group  = 8,
     },
     {
       .type   = PT_INT,
@@ -2680,7 +2706,7 @@ const idclass_t config_class = {
       .off    = offsetof(config_t, dscp),
       .list   = config_class_dscp_list,
       .opts   = PO_EXPERT | PO_DOC_NLIST,
-      .group  = 7,
+      .group  = 8,
     },
     {
       .type   = PT_U32,
@@ -2690,7 +2716,7 @@ const idclass_t config_class = {
                    "there is a delay receiving CA keys. "),
       .off    = offsetof(config_t, descrambler_buffer),
       .opts   = PO_EXPERT,
-      .group  = 7,
+      .group  = 8,
     },
     {
       .type   = PT_BOOL,
@@ -2701,7 +2727,7 @@ const idclass_t config_class = {
                    "It may cause issues with some clients / players."),
       .off    = offsetof(config_t, parser_backlog),
       .opts   = PO_EXPERT,
-      .group  = 7,
+      .group  = 8,
     },
     {
       .type   = PT_STR,
@@ -2714,7 +2740,7 @@ const idclass_t config_class = {
       .off    = offsetof(config_t, muxconf_path),
       .notify = config_muxconfpath_notify,
       .opts   = PO_ADVANCED,
-      .group  = 7,
+      .group  = 8,
     },
     {
       .type   = PT_BOOL,
@@ -2722,7 +2748,7 @@ const idclass_t config_class = {
       .name   = N_("Parse HbbTV info"),
       .desc   = N_("Parse HbbTV information from services."),
       .off    = offsetof(config_t, hbbtv),
-      .group  = 7,
+      .group  = 8,
       .def.i  = 1,
     },
     {
@@ -2734,7 +2760,7 @@ const idclass_t config_class = {
                    "the system clock (normally only root)."),
       .off    = offsetof(config_t, tvhtime_update_enabled),
       .opts   = PO_EXPERT,
-      .group  = 7,
+      .group  = 8,
     },
     {
       .type   = PT_BOOL,
@@ -2746,7 +2772,7 @@ const idclass_t config_class = {
                    "performance is not that great."),
       .off    = offsetof(config_t, tvhtime_ntp_enabled),
       .opts   = PO_EXPERT,
-      .group  = 7,
+      .group  = 8,
     },
     {
       .type   = PT_U32,
@@ -2758,7 +2784,7 @@ const idclass_t config_class = {
                    "excessive oscillations on the system clock."),
       .off    = offsetof(config_t, tvhtime_tolerance),
       .opts   = PO_EXPERT,
-      .group  = 7,
+      .group  = 8,
     },
 #if ENABLE_VAAPI
     {
index fe1f9b931e5f77aa0e05be8a46ceab64f316513c..5ae12e8c9b48d85ef4a82b2e307e98d6343696cc 100644 (file)
@@ -75,6 +75,8 @@ typedef struct config {
   char *hdhomerun_ip;
   char *local_ip;
   int local_port;
+  int rtsp_udp_min_port;
+  int rtsp_udp_max_port;
   uint32_t hdhomerun_server_tuner_count;
   char *hdhomerun_server_model_name;
   int hdhomerun_server_enable;
index 5370dc0b9e40da2103073671b711fee75bb4125f..2441cdace212504a3b5ca38886b26c88b774e3e6 100644 (file)
@@ -385,7 +385,7 @@ rtcp_connect(rtcp_t * info, char *url, char *host, int port, char *interface, ch
 
   if (info->connection == NULL) {
     rtcp_conn = udp_bind(LS_IPTV, nicename, NULL, 0, NULL, interface,
-    IPTV_BUF_SIZE, 1024);
+    IPTV_BUF_SIZE, 1024, 0);
     if (rtcp_conn == NULL || rtcp_conn == UDP_FATAL_ERROR) {
       tvhwarn(LS_IPTV, "%s - Unable to bind, RTCP won't be available",
           nicename);
index 66d83c2c717eec1885ba6c2350f41f0904731b77..ec3c3db65d5c0cfc2f7b256ce3dcb5b3b18e69fd 100644 (file)
@@ -18,6 +18,7 @@
  */
 
 #include "tvheadend.h"
+#include "config.h"
 #include "iptv_private.h"
 #include "iptv_rtcp.h"
 #include "http.h"
@@ -263,6 +264,8 @@ iptv_rtsp_start
   http_client_t *hc;
   udp_connection_t *rtp, *rtcp;
   int r;
+  int rtp_port;
+  int max_rtp_port;
 
   if (!(hc = http_client_connect(im, RTSP_VERSION_1_0, u->scheme,
                                  u->host, u->port, NULL)))
@@ -272,15 +275,38 @@ iptv_rtsp_start
     hc->hc_rtsp_user = strdup(u->user);
   if (u->pass)
     hc->hc_rtsp_pass = strdup(u->pass);
+  
+  rtp_port = config.rtsp_udp_min_port;
+  max_rtp_port = config.rtsp_udp_max_port;
 
-  if (udp_bind_double(&rtp, &rtcp,
-                      LS_IPTV, "rtp", "rtcp",
-                      NULL, 0, NULL,
-                      128*1024, 16384, 4*1024, 4*1024) < 0) {
+  if (!max_rtp_port) {
+    rtp_port = 0;
+  }
+
+  if (rtp_port > max_rtp_port)
+  {
+    tvherror(LS_IPTV, "UDP minimum port is set higher than the UDP maximum port");
     http_client_close(hc);
     return SM_CODE_TUNING_FAILED;
   }
 
+  while (udp_bind_double(&rtp, &rtcp,
+                          LS_IPTV, "rtp", "rtcp",
+                          NULL, rtp_port, NULL,
+                          128 * 1024, 16384, 4 * 1024, 4 * 1024, 1) < 0)
+  {
+    if (!rtp_port) {
+      tvherror(LS_IPTV, "could not bind a random UDP port for RTP");
+      http_client_close(hc);
+      return SM_CODE_TUNING_FAILED;
+    } else if (max_rtp_port && rtp_port >= max_rtp_port - 2) {
+      tvherror(LS_IPTV, "all the UDP ports allocated are used, please reduce the number of simultaneous IPTV streams or increase the number of ports in the global settings");
+      http_client_close(hc);
+      return SM_CODE_TUNING_FAILED;
+    }
+    rtp_port += 2;
+  }
+
   hc->hc_hdr_received        = iptv_rtsp_header;
   hc->hc_data_received       = iptv_rtsp_data;
   hc->hc_handle_location     = 1;                      /* allow redirects */
index b2ab863ff79bd8a8cd40199ed884108c2e431c1a..c3bff26213cc6ee310f67278d80abbd57793411b 100644 (file)
@@ -42,7 +42,7 @@ iptv_udp_start
   /* Note: url->user is used for specifying multicast source address (SSM)
      here. The URL format is rtp://<srcaddr>@<grpaddr>:<port> */
   conn = udp_bind(LS_IPTV, im->mm_nicename, url->host, url->port, url->user,
-                  im->mm_iptv_interface, IPTV_BUF_SIZE, 4*1024);
+                  im->mm_iptv_interface, IPTV_BUF_SIZE, 4*1024, 0);
   if (conn == UDP_FATAL_ERROR)
     return SM_CODE_TUNING_FAILED;
   if (conn == NULL)
index 1c414da688f0e60e52ad15d62dfec2750c44b1bb..2d7e7ad28584701ad2e9ad49d5ba74658b202961 100644 (file)
@@ -1729,7 +1729,7 @@ new_tune:
     if (udp_bind_double(&rtp, &rtcp,
                         LS_SATIP, "rtp", "rtcp",
                         satip_frontend_bindaddr(lfe), lfe->sf_udp_rtp_port,
-                        NULL, SATIP_BUF_SIZE, 16384, 4*1024, 4*1024) < 0) {
+                        NULL, SATIP_BUF_SIZE, 16384, 4*1024, 4*1024, 0) < 0) {
       satip_frontend_tuning_error(lfe, tr);
       goto done;
     }
index 98f85724ed5b49d36d3e225dcbcfc5b17afd5a65..24efae9d792c0a1e66deb84eb7d5514ca6b9fc74 100644 (file)
@@ -1562,7 +1562,7 @@ rtsp_process_play(http_connection_t *hc, int cmd)
                         LS_SATIPS, "rtsp", "rtcp",
                         (rtp_src_ip != NULL && rtp_src_ip[0] != '\0') ? rtp_src_ip : rtsp_ip, 0, NULL,
                         4*1024, 4*1024,
-                        RTP_BUFSIZE, RTCP_BUFSIZE)) {
+                        RTP_BUFSIZE, RTCP_BUFSIZE, 0)) {
       errcode = HTTP_STATUS_INTERNAL;
       goto error;
     }
index b0c3c1e5ca588923e31eb5aa18ede901a94130e8..40cb8308b9d9d319dbcd1c83a0427033dc99c07d 100644 (file)
--- a/src/udp.c
+++ b/src/udp.c
@@ -154,7 +154,7 @@ udp_get_solip( void )
 udp_connection_t *
 udp_bind ( int subsystem, const char *name,
            const char *bindaddr, int port, const char *multicast_src,
-           const char *ifname, int rxsize, int txsize )
+           const char *ifname, int rxsize, int txsize, int bind_fail_allowed )
 {
   int fd, ifindex, reuse = 1;
   udp_connection_t *uc;
@@ -186,8 +186,8 @@ udp_bind ( int subsystem, const char *name,
 
   uc->fd = fd;
 
-  /* Mark reuse address */
-  if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse))) {
+  /* Mark reuse address, only wanted and required for Multicast in UDP (and TCP, but not here, then) */
+  if (uc->multicast && setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse))) {
     tvherror(subsystem, "%s - failed to reuse address for socket [%s]",
              name, strerror(errno));
     udp_close(uc);
@@ -207,9 +207,11 @@ udp_bind ( int subsystem, const char *name,
     /* Bind useful for receiver subsystem (not for udp streamer) */
     if (subsystem != LS_UDP) {
     if (bind(fd, (struct sockaddr *)&uc->ip, sizeof(struct sockaddr_in))) {
-      inet_ntop(AF_INET, &IP_AS_V4(&uc->ip, addr), buf, sizeof(buf));
-      tvherror(subsystem, "%s - cannot bind %s:%hu [e=%s]",
-               name, buf, ntohs(IP_AS_V4(&uc->ip, port)), strerror(errno));
+      if (!bind_fail_allowed) {
+        inet_ntop(AF_INET, &IP_AS_V4(&uc->ip, addr), buf, sizeof(buf));
+        tvherror(subsystem, "%s - cannot bind %s:%hu [e=%s]",
+                name, buf, ntohs(IP_AS_V4(&uc->ip, port)), strerror(errno));
+      }
       goto error;
     }
     }  
@@ -280,9 +282,11 @@ udp_bind ( int subsystem, const char *name,
 
     /* Bind */
     if (bind(fd, (struct sockaddr *)&uc->ip, sizeof(struct sockaddr_in6))) {
-      inet_ntop(AF_INET6, &IP_AS_V6(&uc->ip, addr), buf, sizeof(buf));
-      tvherror(subsystem, "%s - cannot bind %s:%hu [e=%s]",
-               name, buf, ntohs(IP_AS_V6(&uc->ip, port)), strerror(errno));
+      if (!bind_fail_allowed) {
+        inet_ntop(AF_INET6, &IP_AS_V6(&uc->ip, addr), buf, sizeof(buf));
+        tvherror(subsystem, "%s - cannot bind %s:%hu [e=%s]",
+                 name, buf, ntohs(IP_AS_V6(&uc->ip, port)), strerror(errno));
+      }
       goto error;
     }
 
@@ -334,7 +338,7 @@ udp_bind_double ( udp_connection_t **_u1, udp_connection_t **_u2,
                   int subsystem, const char *name1,
                   const char *name2, const char *host, int port,
                   const char *ifname, int rxsize1, int rxsize2,
-                  int txsize1, int txsize2 )
+                  int txsize1, int txsize2, int bind_fail_allowed )
 {
   udp_connection_t *u1 = NULL, *u2 = NULL;
   udp_connection_t *ucs[10];
@@ -342,13 +346,13 @@ udp_bind_double ( udp_connection_t **_u1, udp_connection_t **_u2,
 
   memset(&ucs, 0, sizeof(ucs));
   while (1) {
-    u1 = udp_bind(subsystem, name1, host, port, NULL, ifname, rxsize1, txsize1);
+    u1 = udp_bind(subsystem, name1, host, port, NULL, ifname, rxsize1, txsize1, bind_fail_allowed);
     if (u1 == NULL || u1 == UDP_FATAL_ERROR)
       goto fail;
     port2 = ntohs(IP_PORT(u1->ip));
     /* RTP port should be even, RTCP port should be odd */
     if ((port2 % 2) == 0) {
-      u2 = udp_bind(subsystem, name2, host, port2 + 1, NULL, ifname, rxsize2, txsize2);
+      u2 = udp_bind(subsystem, name2, host, port2 + 1, NULL, ifname, rxsize2, txsize2, bind_fail_allowed);
       if (u2 != NULL && u2 != UDP_FATAL_ERROR)
         break;
     }
index 55b6dfad39b9c07a559b477a14bd7df59d73d9d1..75328961a6b3edf9083743f5701ed546d961d727 100644 (file)
--- a/src/udp.h
+++ b/src/udp.h
@@ -45,13 +45,13 @@ typedef struct udp_connection {
 udp_connection_t *
 udp_bind ( int subsystem, const char *name,
            const char *bindaddr, int port, const char *multicast_src,
-           const char *ifname, int rxsize, int txsize );
+           const char *ifname, int rxsize, int txsize, int bind_fail_allowed );
 int
 udp_bind_double ( udp_connection_t **_u1, udp_connection_t **_u2,
                   int subsystem, const char *name1,
                   const char *name2, const char *host, int port,
                   const char *ifname, int rxsize1, int rxsize2,
-                  int txsize1, int txsize2 );
+                  int txsize1, int txsize2, int bind_fail_allowed );
 udp_connection_t *
 udp_sendinit ( int subsystem, const char *name,
                const char *ifname, int txsize );
index f6a3c649f1eb3760604f0c1068116776dc296732..51dac4291c1b1c34a0d7bebef7e53a92fb047d14 100644 (file)
@@ -130,11 +130,11 @@ upnp_thread( void *aux )
 
   multicast = udp_bind(LS_UPNP, "upnp_thread_multicast",
                        "239.255.255.250", 1900, NULL,
-                       NULL, 32*1024, 32*1024);
+                       NULL, 32*1024, 32*1024, 0);
   if (multicast == NULL || multicast == UDP_FATAL_ERROR)
     goto error;
   unicast = udp_bind(LS_UPNP, "upnp_thread_unicast", bindaddr, 0, NULL,
-                     NULL, 32*1024, 32*1024);
+                     NULL, 32*1024, 32*1024, 0);
   if (unicast == NULL || unicast == UDP_FATAL_ERROR)
     goto error;
 
index 51e64351510ad8379479f593096024d5e55e6b63..d2669389d330150b62d8a1e9f4d70796e5ae6bad 100644 (file)
@@ -1245,7 +1245,7 @@ udp_stream_service(http_connection_t *hc, service_t *service, int weight)
 
   if (!(uc = udp_bind(LS_UDP, "udp_streamer",
                        address, port, NULL,
-                       NULL, 1024, 188*7))) {
+                       NULL, 1024, 188*7, 0))) {
     tvhwarn(LS_WEBUI, "Could not create and bind udp socket");
     return res; 
   }  
@@ -1498,7 +1498,7 @@ udp_stream_channel(http_connection_t *hc, channel_t *ch, int weight)
 
   if (!(uc = udp_bind(LS_UDP, "udp_streamer",
                        address, port, NULL,
-                       NULL, 1024, 188*7))) {
+                       NULL, 1024, 188*7, 0))) {
     tvhwarn(LS_WEBUI, "Could not create and bind udp socket");
     return res; 
   }