]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
IPTV: fix memory leaks
authorJaroslav Kysela <perex@perex.cz>
Wed, 14 Oct 2015 07:54:56 +0000 (09:54 +0200)
committerJaroslav Kysela <perex@perex.cz>
Wed, 14 Oct 2015 07:54:56 +0000 (09:54 +0200)
src/http.c
src/http.h
src/input/mpegts.h
src/input/mpegts/iptv/iptv.c
src/input/mpegts/iptv/iptv_auto.c
src/input/mpegts/iptv/iptv_http.c
src/input/mpegts/mpegts_network.c

index 370f1903e25bdd6820156adb4064e8e4026b033c..211a63dceadc97fd63903eb22703b476f64c9419 100644 (file)
@@ -822,6 +822,19 @@ process_request(http_connection_t *hc, htsbuf_queue_t *spill)
 
 
 
+/*
+ * Delete one argument
+ */
+void
+http_arg_remove(struct http_arg_list *list, struct http_arg *arg)
+{
+  TAILQ_REMOVE(list, arg, link);
+  free(arg->key);
+  free(arg->val);
+  free(arg);
+}
+
+
 /*
  * Delete all arguments associated with a connection
  */
@@ -829,12 +842,8 @@ void
 http_arg_flush(struct http_arg_list *list)
 {
   http_arg_t *ra;
-  while((ra = TAILQ_FIRST(list)) != NULL) {
-    TAILQ_REMOVE(list, ra, link);
-    free(ra->key);
-    free(ra->val);
-    free(ra);
-  }
+  while((ra = TAILQ_FIRST(list)) != NULL)
+    http_arg_remove(list, ra);
 }
 
 
index fb53aebaf9af0c8e106f52154cd6bf4dcfe080a6..6633856e6ab590a12bc9c993f82e1dbaa795e9ec 100644 (file)
@@ -173,6 +173,7 @@ static inline void http_arg_init(struct http_arg_list *list)
   TAILQ_INIT(list);
 }
 
+void http_arg_remove(struct http_arg_list *list, struct http_arg *arg);
 void http_arg_flush(struct http_arg_list *list);
 
 char *http_arg_get(struct http_arg_list *list, const char *name);
index b5ff390f2306bdd4c0cd3d0c5ef9f44fcc707bde..283ecb7207f0d38646bf9f873af65266a93194b9 100644 (file)
@@ -307,6 +307,7 @@ struct mpegts_network
   /*
    * Functions
    */
+  void              (*mn_delete)       (mpegts_network_t*, int delconf);
   void              (*mn_display_name) (mpegts_network_t*, char *buf, size_t len);
   void              (*mn_config_save)  (mpegts_network_t*);
   mpegts_mux_t*     (*mn_create_mux)
index d5bb165c0cbd2278feaf802b7e676f5d09a5afcf..46475a2128d5fd699668b3bcf339b2d3b068ff6b 100644 (file)
@@ -477,30 +477,37 @@ iptv_input_mux_started ( iptv_mux_t *im )
                        im->mm_iptv_atsc ? DVB_SYS_ATSC_ALL : DVB_SYS_DVBT);
 }
 
-/* **************************************************************************
- * IPTV network
- * *************************************************************************/
-
 static void
-iptv_network_class_delete ( idnode_t *in )
+iptv_network_delete ( mpegts_network_t *mn, int delconf )
 {
-  iptv_network_t *mn = (iptv_network_t*)in;
-  char *s = mn->in_url;
+  iptv_network_t *in = (iptv_network_t*)mn;
+  char *s = in->in_url;
 
-  if (in->in_class == &iptv_auto_network_class)
-    iptv_auto_network_done((iptv_network_t *)in);
+  if (in->mn_id.in_class == &iptv_auto_network_class)
+    iptv_auto_network_done(in);
 
   /* Remove config */
-  hts_settings_remove("input/iptv/networks/%s",
-                      idnode_uuid_as_sstr(in));
+  if (delconf)
+    hts_settings_remove("input/iptv/networks/%s",
+                        idnode_uuid_as_sstr(&in->mn_id));
 
   /* delete */
-  free(mn->in_remove_args);
-  mpegts_network_delete((mpegts_network_t *)mn, 1);
+  free(in->in_remove_args);
+  mpegts_network_delete(mn, delconf);
 
   free(s);
 }
 
+/* **************************************************************************
+ * IPTV network
+ * *************************************************************************/
+
+static void
+iptv_network_class_delete ( idnode_t *in )
+{
+  return iptv_network_delete((mpegts_network_t *)in, 1);
+}
+
 extern const idclass_t mpegts_network_class;
 const idclass_t iptv_network_class = {
   .ic_super      = &mpegts_network_class,
@@ -640,6 +647,7 @@ iptv_network_create0
     free(in);
     return NULL;
   }
+  in->mn_delete         = iptv_network_delete;
   in->mn_create_service = iptv_network_create_service;
   in->mn_mux_class      = iptv_network_mux_class;
   in->mn_mux_create2    = iptv_network_create_mux2;
@@ -747,7 +755,9 @@ void iptv_done ( void )
   pthread_join(iptv_thread, NULL);
   tvhpoll_destroy(iptv_poll);
   pthread_mutex_lock(&global_lock);
+  mpegts_network_unregister_builder(&iptv_auto_network_class);
   mpegts_network_unregister_builder(&iptv_network_class);
+  mpegts_network_class_delete(&iptv_auto_network_class, 0);
   mpegts_network_class_delete(&iptv_network_class, 0);
   mpegts_input_stop_all((mpegts_input_t*)iptv_input);
   mpegts_input_delete((mpegts_input_t *)iptv_input, 0);
index 5af2a9b852c72e63164f13c92a98f1ce7352a78e..aa89685ea139ee8fa2d8f6669070b4660b173aba 100644 (file)
@@ -63,7 +63,7 @@ iptv_auto_network_process_m3u_item(iptv_network_t *in,
   if (urlparse(url, &u))
     return;
   if (u.host == NULL || u.host[0] == '\0')
-    return;
+    goto end;
 
   /* remove requested arguments */
   if (!http_args_empty(remove_args)) {
@@ -73,7 +73,7 @@ iptv_auto_network_process_m3u_item(iptv_network_t *in,
       for (ra2 = TAILQ_FIRST(&args); ra2; ra2 = ra2_next) {
         ra2_next = TAILQ_NEXT(ra2, link);
         if (strcmp(ra1->key, ra2->key) == 0)
-          TAILQ_REMOVE(&args, ra2, link);
+          http_arg_remove(&args, ra2);
       }
     free(u.query);
     u.query = NULL;
@@ -90,6 +90,7 @@ iptv_auto_network_process_m3u_item(iptv_network_t *in,
       u.query = htsbuf_to_string(&q);
       htsbuf_queue_flush(&q);
     }
+    http_arg_flush(&args);
     tvh_strlcatf(url2, sizeof(url2), l, "%s://", u.scheme);
     if (u.user && u.user[0] && u.pass && u.pass[0])
       tvh_strlcatf(url2, sizeof(url2), l, "%s:%s@", u.user, u.pass);
@@ -129,7 +130,7 @@ iptv_auto_network_process_m3u_item(iptv_network_t *in,
       if (change)
         idnode_notify_changed(&im->mm_id);
       (*total)++;
-      return;
+      goto end;
     }
   }
 
@@ -146,6 +147,9 @@ iptv_auto_network_process_m3u_item(iptv_network_t *in,
     (*total)++;
     (*count)++;
   }
+
+end:
+  urlreset(&u);
 }
 
 /*
@@ -224,6 +228,8 @@ iptv_auto_network_process(iptv_network_t *in, const char *last_url, char *data,
   if (!strncmp(data, "#EXTM3U", 7))
     r = iptv_auto_network_process_m3u(in, data, last_url, &remove_args, in->in_channel_number);
 
+  http_arg_flush(&remove_args);
+
   if (r == 0) {
     count = 0;
     LIST_FOREACH(mm, &in->mn_muxes, mm_network_link)
@@ -247,7 +253,7 @@ iptv_auto_network_process(iptv_network_t *in, const char *last_url, char *data,
 static int
 iptv_auto_network_file(iptv_network_t *in, const char *filename)
 {
-  int fd;
+  int fd, res;
   struct stat st;
   char *data, *last_url;
   size_t r;
@@ -283,9 +289,12 @@ iptv_auto_network_file(iptv_network_t *in, const char *filename)
     last_url = strrchr(filename, '/');
     if (last_url)
       last_url++;
-    return iptv_auto_network_process(in, last_url, data, off);
+    res = iptv_auto_network_process(in, last_url, data, off);
+  } else {
+    res = -1;
   }
-  return -1;
+  free(data);
+  return res;
 }
 
 /*
@@ -329,6 +338,9 @@ iptv_auto_network_fetch_complete(http_client_t *hc)
 
   pthread_mutex_lock(&global_lock);
 
+  if (in->in_http_client == NULL)
+    goto out;
+
   if (hc->hc_code == HTTP_STATUS_OK && hc->hc_result == 0 && hc->hc_data_size > 0)
     iptv_auto_network_process(in, last_url, hc->hc_data, hc->hc_data_size);
   else
@@ -338,8 +350,10 @@ iptv_auto_network_fetch_complete(http_client_t *hc)
   /* note: http_client_close must be called outside http_client callbacks */
   gtimer_arm(&in->in_fetch_timer, iptv_auto_network_fetch_done, hc, 0);
 
+out:
   pthread_mutex_unlock(&global_lock);
 
+  urlreset(&u);
   return 0;
 }
 
@@ -353,6 +367,8 @@ iptv_auto_network_fetch(void *aux)
   http_client_t *hc;
   url_t u;
 
+  memset(&u, 0, sizeof(u));
+
   if (strncmp(in->in_url, "file://", 7) == 0) {
     iptv_auto_network_file(in, in->in_url + 7);
     goto arm;
@@ -364,7 +380,6 @@ iptv_auto_network_fetch(void *aux)
     in->in_http_client = NULL;
   }
 
-  memset(&u, 0, sizeof(u));
   if (urlparse(in->in_url, &u) < 0) {
     tvherror("iptv", "wrong url for network '%s'", in->mn_network_name);
     goto arm;
@@ -388,6 +403,7 @@ iptv_auto_network_fetch(void *aux)
   in->in_http_client = hc;
 
 arm:
+  urlreset(&u);
   gtimer_arm(&in->in_auto_timer, iptv_auto_network_fetch, in,
              MAX(1, in->in_refetch_period) * 60);
 }
@@ -407,10 +423,10 @@ iptv_auto_network_init( iptv_network_t *in )
 void
 iptv_auto_network_done( iptv_network_t *in )
 {
-  gtimer_disarm(&in->in_auto_timer);
-  gtimer_disarm(&in->in_fetch_timer);
   if (in->in_http_client) {
     http_client_close(in->in_http_client);
     in->in_http_client = NULL;
   }
+  gtimer_disarm(&in->in_auto_timer);
+  gtimer_disarm(&in->in_fetch_timer);
 }
index 4f78fb89c94328fdaff63d9528a2d226ce74bdbf..8ca7a566a67a248ef749a7ae416021424164c2c4 100644 (file)
@@ -146,6 +146,7 @@ iptv_http_complete
     } else {
       tvherror("iptv", "m3u url invalid '%s'", url);
     }
+    urlreset(&u);
     free(url);
     return 0;
   }
index 98ae3ad0ca7fce436081b32dc2b7b3a873cc8e77..f98418ee2c36a3a79467fb9256edc88b2c88f2d3 100644 (file)
@@ -357,6 +357,7 @@ mpegts_network_create0
   mn->mn_create_service = mpegts_network_create_service;
   mn->mn_mux_class      = mpegts_network_mux_class;
   mn->mn_mux_create2    = mpegts_network_mux_create2;
+  mn->mn_delete         = mpegts_network_delete;
 
   /* Add to global list */
   LIST_INSERT_HEAD(&mpegts_network_all, mn, mn_global_link);
@@ -389,7 +390,7 @@ mpegts_network_class_delete(const idclass_t *idc, int delconf)
   for (mn = LIST_FIRST(&mpegts_network_all); mn != NULL; mn = n) {
     n = LIST_NEXT(mn, mn_global_link);
     if (mn->mn_id.in_class == idc)
-      mpegts_network_delete(mn, delconf);
+      mn->mn_delete(mn, delconf);
   }
 }