]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
htsp server: improve the htsp streaming connection limit check, issue #5290
authorJaroslav Kysela <perex@perex.cz>
Tue, 30 Oct 2018 18:55:59 +0000 (19:55 +0100)
committerJaroslav Kysela <perex@perex.cz>
Tue, 30 Oct 2018 18:55:59 +0000 (19:55 +0100)
src/htsp_server.c
src/satip/rtsp.c
src/tcp.c
src/tcp.h
src/webui/static/app/status.js
src/webui/webui.c

index 6d1a7e07d226381acb6f115aca53822959371bdd..bc1ce16ce0001989a974bc5ba000b8ed238b271b 100644 (file)
@@ -3223,7 +3223,7 @@ static int
 htsp_read_loop(htsp_connection_t *htsp)
 {
   htsmsg_t *m = NULL, *reply;
-  int r = 0, i;
+  int run = 1, r = 0, i, streaming = 0;
   const char *method;
   void *tcp_id = NULL;;
 
@@ -3238,7 +3238,7 @@ htsp_read_loop(htsp_connection_t *htsp)
   htsp->htsp_granted_access = access_get_by_addr(htsp->htsp_peer);
   htsp->htsp_granted_access->aa_rights |= ACCESS_HTSP_INTERFACE;
 
-  tcp_id = tcp_connection_launch(htsp->htsp_fd, htsp_server_status,
+  tcp_id = tcp_connection_launch(htsp->htsp_fd, streaming, htsp_server_status,
                                  htsp->htsp_granted_access);
 
   pthread_mutex_unlock(&global_lock);
@@ -3250,7 +3250,7 @@ htsp_read_loop(htsp_connection_t *htsp)
 
   /* Session main loop */
 
-  while(tvheadend_is_running()) {
+  while(run && tvheadend_is_running()) {
 readmsg:
     reply = NULL;
 
@@ -3260,12 +3260,14 @@ readmsg:
     pthread_mutex_lock(&global_lock);
     if (htsp_authenticate(htsp, m)) {
       tcp_connection_land(tcp_id);
-      tcp_id = tcp_connection_launch(htsp->htsp_fd, htsp_server_status,
+      tcp_id = tcp_connection_launch(htsp->htsp_fd, streaming, htsp_server_status,
                                      htsp->htsp_granted_access);
       if (tcp_id == NULL) {
-        htsmsg_destroy(m);
-        pthread_mutex_unlock(&global_lock);
-        return 1;
+        reply = htsmsg_create_map();
+        htsmsg_add_u32(reply, "noaccess", 1);
+        htsmsg_add_u32(reply, "connlimit", 1);
+        run = 0;
+        goto send_reply_with_unlock;
       }
     }
 
@@ -3292,6 +3294,18 @@ readmsg:
             goto readmsg;
 
           } else {
+            if (!strcmp(method, "subscribe") && !streaming) {
+              tcp_connection_land(tcp_id);
+              tcp_id = tcp_connection_launch(htsp->htsp_fd, 1, htsp_server_status,
+                                             htsp->htsp_granted_access);
+              if (tcp_id == NULL) {
+                reply = htsmsg_create_map();
+                htsmsg_add_u32(reply, "noaccess", 1);
+                htsmsg_add_u32(reply, "connlimit", 1);
+                goto send_reply_with_unlock;
+              }
+              streaming = 1;
+            }
             reply = htsp_methods[i].fn(htsp, m);
           }
           break;
@@ -3306,6 +3320,7 @@ readmsg:
       reply = htsp_error(htsp, N_("Invalid arguments"));
     }
 
+send_reply_with_unlock:
     pthread_mutex_unlock(&global_lock);
 
     if(reply != NULL) /* Methods can do all the replying inline */
index d0af82c8b373bd04ecffea41e37604e6241b6ca5..6aa2c7527aeb3098b430f9f032aeed5845d7b1f5 100644 (file)
@@ -1724,7 +1724,7 @@ rtsp_serve(int fd, void **opaque, struct sockaddr_storage *peer,
   tcp_get_str_from_ip(peer, buf + strlen(buf), sizeof(buf) - strlen(buf));
   aa.aa_representative = buf;
 
-  tcp = tcp_connection_launch(fd, rtsp_stream_status, &aa);
+  tcp = tcp_connection_launch(fd, 1, rtsp_stream_status, &aa);
 
   /* Note: global_lock held on entry */
   pthread_mutex_unlock(&global_lock);
index e38f189beeaf115ea4a60013faeca5968db1db55..62256c6137e86d773324c6b4040ddc4c9d8e02a0 100644 (file)
--- a/src/tcp.c
+++ b/src/tcp.c
@@ -530,6 +530,7 @@ typedef struct tcp_server_launch {
   pthread_t tid;
   uint32_t id;
   int fd;
+  int streaming;
   tcp_server_ops_t ops;
   void *opaque;
   char *representative;
@@ -572,10 +573,10 @@ tcp_connection_count(access_t *aa)
  */
 void *
 tcp_connection_launch
-  (int fd, void (*status) (void *opaque, htsmsg_t *m), access_t *aa)
+  (int fd, int streaming, void (*status) (void *opaque, htsmsg_t *m), access_t *aa)
 {
   tcp_server_launch_t *tsl, *res;
-  uint32_t used, used2;
+  uint32_t sused, used2;
   int64_t started = mclk();
   int c1, c2;
 
@@ -588,7 +589,7 @@ tcp_connection_launch
 
 try_again:
   res = NULL;
-  used = 0;
+  sused = 0;
   LIST_FOREACH(tsl, &tcp_server_active, alink) {
     if (tsl->fd == fd) {
       res = tsl;
@@ -597,7 +598,8 @@ try_again:
       continue;
     }
     if (!strcmp(aa->aa_representative ?: "", tsl->representative ?: ""))
-      used++;
+      if (tsl->streaming)
+        sused++;
   }
   if (res == NULL)
     return NULL;
@@ -605,8 +607,8 @@ try_again:
   if (aa->aa_conn_limit || aa->aa_conn_limit_streaming) {
     used2 = aa->aa_conn_limit ? dvr_usage_count(aa) : 0;
     /* the rule is: allow if one condition is OK */
-    c1 = aa->aa_conn_limit ? used + used2 >= aa->aa_conn_limit : -1;
-    c2 = aa->aa_conn_limit_streaming ? used >= aa->aa_conn_limit_streaming : -1;
+    c1 = aa->aa_conn_limit ? sused + used2 >= aa->aa_conn_limit : -1;
+    c2 = aa->aa_conn_limit_streaming ? sused >= aa->aa_conn_limit_streaming : -1;
 
     if (c1 && c2) {
       if (started + sec2mono(5) < mclk()) {
@@ -614,7 +616,7 @@ try_again:
                         "(limit %u, streaming limit %u, active streaming %u, DVR %u)",
                  aa->aa_username ?: "", aa->aa_representative ?: "",
                  aa->aa_conn_limit, aa->aa_conn_limit_streaming,
-                 used, used2);
+                 sused, used2);
         return NULL;
       }
       pthread_mutex_unlock(&global_lock);
@@ -628,6 +630,7 @@ try_again:
 
   res->representative = aa->aa_representative ? strdup(aa->aa_representative) : NULL;
   res->status = status;
+  res->streaming = streaming;
   LIST_INSERT_HEAD(&tcp_server_launches, res, link);
   notify_reload("connections");
   return res;
@@ -1135,6 +1138,7 @@ tcp_server_connections ( void )
     htsmsg_add_str(e, "peer", buf);
     htsmsg_add_u32(e, "peer_port", ntohs(IP_PORT(tsl->peer)));
     htsmsg_add_s64(e, "started", tsl->started);
+    htsmsg_add_u32(e, "streaming", tsl->streaming);
     tsl->status(tsl->opaque, e);
     htsmsg_add_msg(l, NULL, e);
   }
index ad6ef018f2091e93dc873b2c9315e18f8381dc60..c88c3b19baead58784fa848dbc801841a7ab01b9 100644 (file)
--- a/src/tcp.h
+++ b/src/tcp.h
@@ -155,7 +155,8 @@ int tcp_socket_dead(int fd);
 struct access;
 
 uint32_t tcp_connection_count(struct access *aa);
-void *tcp_connection_launch(int fd, void (*status) (void *opaque, htsmsg_t *m),
+void *tcp_connection_launch(int fd, int streaming,
+                            void (*status) (void *opaque, htsmsg_t *m),
                             struct access *aa);
 void tcp_connection_land(void *tcp_id);
 void tcp_connection_cancel(uint32_t id);
index 6842b1d38fd19507c50016054424ccb981405596..8e85646be70157e80ed03bbac36058a2acac00cd 100644 (file)
@@ -655,7 +655,8 @@ tvheadend.status_conns = function(panel, index) {
                     type: 'date',
                     dateFormat: 'U', /* unix time */
                     sortType: Ext.data.SortTypes.asDate
-                }
+                },
+                { name: 'streaming' }
             ],
             url: 'api/status/connections',
             autoLoad: true,
@@ -719,6 +720,12 @@ tvheadend.status_conns = function(panel, index) {
                 dataIndex: 'started',
                 renderer: renderDate,
                 sortable: true
+            }, {
+                width: 50,
+                id: 'streaming',
+                header: _("Streaming"),
+                dataIndex: 'streaming',
+                sortable: true
             }, {
                 width: 50,
                 id: 'server',
index e59cb43764b4c1fb94f84f44dca2bd62cfee079a..feb455096c19f7915bd4649b4d046aaf8c114973 100644 (file)
@@ -327,7 +327,7 @@ http_stream_status ( void *opaque, htsmsg_t *m )
 static inline void *
 http_stream_preop ( http_connection_t *hc )
 {
-  return tcp_connection_launch(hc->hc_fd, http_stream_status, hc->hc_access);
+  return tcp_connection_launch(hc->hc_fd, 1, http_stream_status, hc->hc_access);
 }
 
 static inline void