dirmngr: Refactor variable-sized array code.

* 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>
This commit is contained in:
Justus Winter 2017-06-20 14:54:17 +02:00
parent 794261c4bd
commit fc4834d213
No known key found for this signature in database
GPG Key ID: DD1A52F9DA8C9020
1 changed files with 74 additions and 55 deletions

View 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])