dirmngr: Refactor variable-sized array code.
authorJustus Winter <justus@g10code.com>
Tue, 20 Jun 2017 12:54:17 +0000 (14:54 +0200)
committerJustus Winter <justus@g10code.com>
Tue, 20 Jun 2017 14:37:11 +0000 (16:37 +0200)
* dirmngr/ks-engine-hkp.c (struct hostinfo_s): Add explicit length and
size fields.
(MAX_POOL_SIZE): New macro.
(create_new_hostinfo): Initialize new fields.
(host_in_pool_p): Adapt.
(select_random_host): Likewise.
(add_host): Likewise.  Move the resizing logic here.
(hostinfo_sort_pool): New function.
(map_host): Simplify.  Move the resizing logic away from here.
(ks_hkp_mark_host): Adapt.
(ks_hkp_print_hosttable): Likewise.
--

The current code assumes that the pool array is only filled when the
hostinfo object is created.  This patch removes that limitation.

GnuPG-bug-id: 3033
Signed-off-by: Justus Winter <justus@g10code.com>
dirmngr/ks-engine-hkp.c

index 25ec9cb..9a47ca9 100644 (file)
@@ -74,9 +74,11 @@ struct hostinfo_s
 {
   time_t lastfail;   /* Time we tried to connect and failed.  */
   time_t lastused;   /* Time of last use.  */
-  int *pool;         /* A -1 terminated array with indices into
-                        HOSTTABLE or NULL if NAME is not a pool
-                        name.  */
+  int *pool;         /* An array with indices into HOSTTABLE or NULL
+                        if NAME is not a pool name.  */
+  size_t pool_len;   /* Length of POOL.  */
+  size_t pool_size;  /* Allocated size of POOL.  */
+#define MAX_POOL_SIZE  128
   int poolidx;       /* Index into POOL with the used host.  -1 if not set.  */
   unsigned int v4:1; /* Host supports AF_INET.  */
   unsigned int v6:1; /* Host supports AF_INET6.  */
@@ -118,6 +120,8 @@ create_new_hostinfo (const char *name)
     return -1;
   strcpy (hi->name, name);
   hi->pool = NULL;
+  hi->pool_len = 0;
+  hi->pool_size = 0;
   hi->poolidx = -1;
   hi->lastused = (time_t)(-1);
   hi->lastfail = (time_t)(-1);
@@ -187,24 +191,24 @@ sort_hostpool (const void *xa, const void *xb)
 }
 
 
-/* Return true if the host with the hosttable index TBLIDX is in POOL.  */
+/* Return true if the host with the hosttable index TBLIDX is in HI->pool.  */
 static int
-host_in_pool_p (int *pool, int tblidx)
+host_in_pool_p (hostinfo_t hi, int tblidx)
 {
   int i, pidx;
 
-  for (i=0; (pidx = pool[i]) != -1; i++)
+  for (i = 0; i < hi->pool_len && (pidx = hi->pool[i]) != -1; i++)
     if (pidx == tblidx && hosttable[pidx])
       return 1;
   return 0;
 }
 
 
-/* Select a random host.  Consult TABLE which indices into the global
-   hosttable.  Returns index into TABLE or -1 if no host could be
+/* Select a random host.  Consult HI->pool which indices into the global
+   hosttable.  Returns index into HI->pool or -1 if no host could be
    selected.  */
 static int
-select_random_host (int *table)
+select_random_host (hostinfo_t hi)
 {
   int *tbl;
   size_t tblsize;
@@ -212,7 +216,9 @@ select_random_host (int *table)
 
   /* We create a new table so that we randomly select only from
      currently alive hosts.  */
-  for (idx=0, tblsize=0; (pidx = table[idx]) != -1; idx++)
+  for (idx = 0, tblsize = 0;
+       idx < hi->pool_len && (pidx = hi->pool[idx]) != -1;
+       idx++)
     if (hosttable[pidx] && !hosttable[pidx]->dead)
       tblsize++;
   if (!tblsize)
@@ -221,7 +227,9 @@ select_random_host (int *table)
   tbl = xtrymalloc (tblsize * sizeof *tbl);
   if (!tbl)
     return -1;
-  for (idx=0, tblsize=0; (pidx = table[idx]) != -1; idx++)
+  for (idx = 0, tblsize = 0;
+       idx < hi->pool_len && (pidx = hi->pool[idx]) != -1;
+       idx++)
     if (hosttable[pidx] && !hosttable[pidx]->dead)
       tbl[tblsize++] = pidx;
 
@@ -286,15 +294,16 @@ tor_not_running_p (ctrl_t ctrl)
    reference table accordingly.  */
 static void
 add_host (const char *name, int is_pool,
-          const dns_addrinfo_t ai, unsigned short port,
-          int *reftbl, size_t reftblsize, int *refidx)
+          const dns_addrinfo_t ai, unsigned short port)
 {
   gpg_error_t tmperr;
   char *tmphost;
   int idx, tmpidx;
+  hostinfo_t host;
   int i;
 
   idx = find_hostinfo (name);
+  host = hosttable[idx];
 
   if (is_pool)
     {
@@ -325,7 +334,7 @@ add_host (const char *name, int is_pool,
       log_info ("resolve_dns_addr failed while checking '%s': %s\n",
                 name, gpg_strerror (tmperr));
     }
-  else if ((*refidx) + 1 >= reftblsize)
+  else if (host->pool_len + 1 >= MAX_POOL_SIZE)
     {
       log_error ("resolve_dns_addr for '%s': '%s'"
                  " [index table full - ignored]\n", name, tmphost);
@@ -365,17 +374,54 @@ add_host (const char *name, int is_pool,
           else
             BUG ();
 
-          for (i=0; i < *refidx; i++)
-            if (reftbl[i] == tmpidx)
-              break;
-          if (!(i < *refidx) && tmpidx != idx)
-            reftbl[(*refidx)++] = tmpidx;
+          /* If we updated the main entry, we're done.  */
+          if (idx == tmpidx)
+            goto leave;
+
+          /* If we updated an existing entry, we're done.  */
+          for (i = 0; i < host->pool_len; i++)
+            if (host->pool[i] == tmpidx)
+              goto leave;
+
+          /* Otherwise, we need to add it to the pool.  Check if there
+             is space.  */
+          if (host->pool_len + 1 > host->pool_size)
+            {
+              int *new_pool;
+              size_t new_size;
+
+              if (host->pool_size == 0)
+                new_size = 4;
+              else
+                new_size = host->pool_size * 2;
+
+              new_pool = xtryrealloc (host->pool,
+                                      new_size * sizeof *new_pool);
+
+              if (new_pool == NULL)
+                goto leave;
+
+              host->pool = new_pool;
+              host->pool_size = new_size;
+            }
+
+          /* Finally, add it.  */
+          log_assert (host->pool_len < host->pool_size);
+          host->pool[host->pool_len++] = tmpidx;
         }
     }
+ leave:
   xfree (tmphost);
 }
 
 
+/* Sort the pool of the given hostinfo HI.  */
+static void
+hostinfo_sort_pool (hostinfo_t hi)
+{
+  qsort (hi->pool, hi->pool_len, sizeof *hi->pool, sort_hostpool);
+}
+
 /* Map the host name NAME to the actual to be used host name.  This
  * allows us to manage round robin DNS names.  We use our own strategy
  * to choose one of the hosts.  For example we skip those hosts which
@@ -427,25 +473,15 @@ map_host (ctrl_t ctrl, const char *name, const char *srvtag, int force_reselect,
     {
       /* We never saw this host.  Allocate a new entry.  */
       dns_addrinfo_t aibuf, ai;
-      int *reftbl;
-      size_t reftblsize;
-      int refidx;
       int is_pool = 0;
       char *cname;
       struct srventry *srvs;
       unsigned int srvscount;
 
-      reftblsize = 100;
-      reftbl = xtrymalloc (reftblsize * sizeof *reftbl);
-      if (!reftbl)
-        return gpg_error_from_syserror ();
-      refidx = 0;
-
       idx = create_new_hostinfo (name);
       if (idx == -1)
         {
           err = gpg_error_from_syserror ();
-          xfree (reftbl);
           return err;
         }
       hi = hosttable[idx];
@@ -456,7 +492,6 @@ map_host (ctrl_t ctrl, const char *name, const char *srvtag, int force_reselect,
           err = get_dns_srv (name, srvtag, NULL, &srvs, &srvscount);
           if (err)
             {
-              xfree (reftbl);
               if (gpg_err_code (err) == GPG_ERR_ECONNREFUSED)
                 tor_not_running_p (ctrl);
               return err;
@@ -475,8 +510,7 @@ map_host (ctrl_t ctrl, const char *name, const char *srvtag, int force_reselect,
                   if (err)
                     continue;
                   dirmngr_tick (ctrl);
-                  add_host (name, is_pool, ai, srvs[i].port,
-                            reftbl, reftblsize, &refidx);
+                  add_host (name, is_pool, ai, srvs[i].port);
                 }
 
               xfree (srvs);
@@ -516,29 +550,12 @@ map_host (ctrl_t ctrl, const char *name, const char *srvtag, int force_reselect,
                 continue;
               dirmngr_tick (ctrl);
 
-              add_host (name, is_pool, ai, 0, reftbl, reftblsize, &refidx);
+              add_host (name, is_pool, ai, 0);
             }
         }
-      reftbl[refidx] = -1;
       xfree (cname);
       free_dns_addrinfo (aibuf);
-
-      if (refidx && is_pool)
-        {
-          assert (!hi->pool);
-          hi->pool = xtryrealloc (reftbl, (refidx+1) * sizeof *reftbl);
-          if (!hi->pool)
-            {
-              err = gpg_error_from_syserror ();
-              log_error ("shrinking index table in map_host failed: %s\n",
-                         gpg_strerror (err));
-              xfree (reftbl);
-              return err;
-            }
-          qsort (hi->pool, refidx, sizeof *reftbl, sort_hostpool);
-        }
-      else
-        xfree (reftbl);
+      hostinfo_sort_pool (hi);
     }
 
   hi = hosttable[idx];
@@ -563,7 +580,7 @@ map_host (ctrl_t ctrl, const char *name, const char *srvtag, int force_reselect,
       /* Select a host if needed.  */
       if (hi->poolidx == -1)
         {
-          hi->poolidx = select_random_host (hi->pool);
+          hi->poolidx = select_random_host (hi);
           if (hi->poolidx == -1)
             {
               log_error ("no alive host found in pool '%s'\n", name);
@@ -740,7 +757,9 @@ ks_hkp_mark_host (ctrl_t ctrl, const char *name, int alive)
   /* If the host is a pool mark all member hosts. */
   if (!err && hi->pool)
     {
-      for (idx2=0; !err && (n=hi->pool[idx2]) != -1; idx2++)
+      for (idx2 = 0;
+           !err && idx2 < hi->pool_len && (n = hi->pool[idx2]) != -1;
+           idx2++)
         {
           assert (n >= 0 && n < hosttable_size);
 
@@ -753,7 +772,7 @@ ks_hkp_mark_host (ctrl_t ctrl, const char *name, int alive)
                   if (hosttable[idx3]
                       && hosttable[idx3]->pool
                       && idx3 != idx
-                      && host_in_pool_p (hosttable[idx3]->pool, n))
+                      && host_in_pool_p (hosttable[idx3], n))
                     break;
                 }
               if (idx3 < hosttable_size)
@@ -903,7 +922,7 @@ ks_hkp_print_hosttable (ctrl_t ctrl)
           {
             init_membuf (&mb, 256);
             put_membuf_printf (&mb, "  .   -->");
-            for (idx2=0; hi->pool[idx2] != -1; idx2++)
+            for (idx2 = 0; idx2 < hi->pool_len && hi->pool[idx2] != -1; idx2++)
               {
                 put_membuf_printf (&mb, " %d", hi->pool[idx2]);
                 if (hi->poolidx == hi->pool[idx2])