• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

c-ares / c-ares / 12601789402

03 Jan 2025 05:55PM UTC coverage: 91.526% (+0.09%) from 91.439%
12601789402

push

github

web-flow
tests: Convert some live tests to Mock tests (#954)

In Issue #953 `GetTCPSock` and `VerifySocketFunctionCallback` tests
might rely on the fact that `connect()` doesn't return an immediate
failure. If `connect()` returned `EWOULDBLOCK`/`EAGAIN` the test would
succeed, but on systems that check on the call for available routes or
listening servers on localhost the `connect()` function would return an
immediate failure.

These functions were not actually tagged with a `Live` prefix so they
would run even callers exclude Live tests. These are testing functions
that shouldn't be limited to live scenarios so we need to move them to
the Mock frameworks and test appropriately.

Fixes #953
Signed-off-by: Brad House (@bradh352)

94 of 94 new or added lines in 2 files covered. (100.0%)

2 existing lines in 2 files now uncovered.

22413 of 24488 relevant lines covered (91.53%)

11841.3 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.56
/src/lib/ares_init.c
1
/* MIT License
2
 *
3
 * Copyright (c) 1998 Massachusetts Institute of Technology
4
 * Copyright (c) 2007 Daniel Stenberg
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7
 * of this software and associated documentation files (the "Software"), to deal
8
 * in the Software without restriction, including without limitation the rights
9
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
 * copies of the Software, and to permit persons to whom the Software is
11
 * furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice (including the next
14
 * paragraph) shall be included in all copies or substantial portions of the
15
 * Software.
16
 *
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
 * SOFTWARE.
24
 *
25
 * SPDX-License-Identifier: MIT
26
 */
27

28
#include "ares_private.h"
29

30
#ifdef HAVE_SYS_PARAM_H
31
#  include <sys/param.h>
32
#endif
33

34
#ifdef HAVE_NETINET_IN_H
35
#  include <netinet/in.h>
36
#endif
37

38
#ifdef HAVE_NETDB_H
39
#  include <netdb.h>
40
#endif
41

42
#ifdef HAVE_ARPA_INET_H
43
#  include <arpa/inet.h>
44
#endif
45

46
#include "ares_nameser.h"
47

48
#if defined(ANDROID) || defined(__ANDROID__)
49
#  include <sys/system_properties.h>
50
#  include "ares_android.h"
51
/* From the Bionic sources */
52
#  define DNS_PROP_NAME_PREFIX "net.dns"
53
#  define MAX_DNS_PROPERTIES   8
54
#endif
55

56
#if defined(CARES_USE_LIBRESOLV)
57
#  include <resolv.h>
58
#endif
59

60
#if defined(USE_WINSOCK) && defined(HAVE_IPHLPAPI_H)
61
#  include <iphlpapi.h>
62
#endif
63

64
#include "ares_inet_net_pton.h"
65
#include "event/ares_event.h"
66

67
int ares_init(ares_channel_t **channelptr)
51✔
68
{
69
  return ares_init_options(channelptr, NULL, 0);
51✔
70
}
71

72
static int ares_query_timeout_cmp_cb(const void *arg1, const void *arg2)
16,976✔
73
{
74
  const ares_query_t *q1 = arg1;
16,976✔
75
  const ares_query_t *q2 = arg2;
16,976✔
76

77
  if (q1->timeout.sec > q2->timeout.sec) {
16,976✔
UNCOV
78
    return 1;
×
79
  }
80
  if (q1->timeout.sec < q2->timeout.sec) {
16,976✔
81
    return -1;
×
82
  }
83

84
  if (q1->timeout.usec > q2->timeout.usec) {
16,976✔
85
    return 1;
16,976✔
86
  }
87
  if (q1->timeout.usec < q2->timeout.usec) {
×
88
    return -1;
×
89
  }
90

91
  return 0;
×
92
}
93

94
static int server_sort_cb(const void *data1, const void *data2)
6,891✔
95
{
96
  const ares_server_t *s1 = data1;
6,891✔
97
  const ares_server_t *s2 = data2;
6,891✔
98

99
  if (s1->consec_failures < s2->consec_failures) {
6,891✔
100
    return -1;
647✔
101
  }
102
  if (s1->consec_failures > s2->consec_failures) {
6,244✔
103
    return 1;
475✔
104
  }
105
  if (s1->idx < s2->idx) {
5,769✔
106
    return -1;
570✔
107
  }
108
  if (s1->idx > s2->idx) {
5,199✔
109
    return 1;
636✔
110
  }
111
  return 0;
4,563✔
112
}
113

114
static void server_destroy_cb(void *data)
935✔
115
{
116
  if (data == NULL) {
935✔
117
    return; /* LCOV_EXCL_LINE: DefensiveCoding */
118
  }
119
  ares_destroy_server(data);
935✔
120
}
121

122
static ares_status_t init_by_defaults(ares_channel_t *channel)
1,067✔
123
{
124
  char         *hostname = NULL;
1,067✔
125
  ares_status_t rc       = ARES_SUCCESS;
1,067✔
126
#ifdef HAVE_GETHOSTNAME
127
  const char *dot;
128
#endif
129
  struct ares_addr addr;
130
  ares_llist_t    *sconfig = NULL;
1,067✔
131

132
  /* Enable EDNS by default */
133
  if (!(channel->optmask & ARES_OPT_FLAGS)) {
1,067✔
134
    channel->flags = ARES_FLAG_EDNS;
148✔
135
  }
136
  if (channel->ednspsz == 0) {
1,067✔
137
    channel->ednspsz = EDNSPACKETSZ;
1,064✔
138
  }
139

140
  if (channel->timeout == 0) {
1,067✔
141
    channel->timeout = DEFAULT_TIMEOUT;
192✔
142
  }
143

144
  if (channel->tries == 0) {
1,067✔
145
    channel->tries = DEFAULT_TRIES;
192✔
146
  }
147

148
  if (ares_slist_len(channel->servers) == 0) {
1,067✔
149
    /* Add a default local named server to the channel unless configured not
150
     * to (in which case return an error).
151
     */
152
    if (channel->flags & ARES_FLAG_NO_DFLT_SVR) {
10✔
153
      rc = ARES_ENOSERVER;
1✔
154
      goto error;
1✔
155
    }
156

157
    addr.family            = AF_INET;
9✔
158
    addr.addr.addr4.s_addr = htonl(INADDR_LOOPBACK);
9✔
159

160
    rc = ares_sconfig_append(channel, &sconfig, &addr, 0, 0, NULL);
9✔
161
    if (rc != ARES_SUCCESS) {
9✔
162
      goto error; /* LCOV_EXCL_LINE: OutOfMemory */
163
    }
164

165
    rc = ares_servers_update(channel, sconfig, ARES_FALSE);
9✔
166
    ares_llist_destroy(sconfig);
9✔
167

168
    if (rc != ARES_SUCCESS) {
9✔
169
      goto error;
×
170
    }
171
  }
172

173
  if (channel->ndomains == 0) {
1,066✔
174
    /* Derive a default domain search list from the kernel hostname,
175
     * or set it to empty if the hostname isn't helpful.
176
     */
177
#ifndef HAVE_GETHOSTNAME
178
    channel->ndomains = 0; /* default to none */
179
#else
180
    size_t len        = 256;
10✔
181
    channel->ndomains = 0; /* default to none */
10✔
182

183
    hostname = ares_malloc(len);
10✔
184
    if (!hostname) {
10✔
185
      rc = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */
186
      goto error;       /* LCOV_EXCL_LINE: OutOfMemory */
187
    }
188

189
    if (gethostname(hostname, (GETHOSTNAME_TYPE_ARG2)len) != 0) {
10✔
190
      /* Lets not treat a gethostname failure as critical, since we
191
       * are ok if gethostname doesn't even exist */
192
      *hostname = '\0';
×
193
    }
194

195
    dot = strchr(hostname, '.');
10✔
196
    if (dot) {
10✔
197
      /* a dot was found */
198
      channel->domains = ares_malloc(sizeof(char *));
1✔
199
      if (!channel->domains) {
1✔
200
        rc = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */
201
        goto error;       /* LCOV_EXCL_LINE: OutOfMemory */
202
      }
203
      channel->domains[0] = ares_strdup(dot + 1);
1✔
204
      if (!channel->domains[0]) {
1✔
205
        rc = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */
206
        goto error;       /* LCOV_EXCL_LINE: OutOfMemory */
207
      }
208
      channel->ndomains = 1;
1✔
209
    }
210
#endif
211
  }
212

213
  if (channel->nsort == 0) {
1,066✔
214
    channel->sortlist = NULL;
1,062✔
215
  }
216

217
  if (!channel->lookups) {
1,066✔
218
    channel->lookups = ares_strdup("fb");
12✔
219
    if (!channel->lookups) {
12✔
220
      rc = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */
221
    }
222
  }
223

224
  /* Set default fields for server failover behavior */
225
  if (!(channel->optmask & ARES_OPT_SERVER_FAILOVER)) {
1,066✔
226
    channel->server_retry_chance = DEFAULT_SERVER_RETRY_CHANCE;
1,050✔
227
    channel->server_retry_delay  = DEFAULT_SERVER_RETRY_DELAY;
1,050✔
228
  }
229

230
error:
16✔
231
  if (hostname) {
1,067✔
232
    ares_free(hostname);
10✔
233
  }
234

235
  return rc;
1,067✔
236
}
237

238
int ares_init_options(ares_channel_t           **channelptr,
1,117✔
239
                      const struct ares_options *options, int optmask)
240
{
241
  ares_channel_t *channel;
242
  ares_status_t   status = ARES_SUCCESS;
1,117✔
243

244
  if (ares_library_initialized() != ARES_SUCCESS) {
1,117✔
245
    return ARES_ENOTINITIALIZED; /* LCOV_EXCL_LINE: n/a on non-WinSock */
246
  }
247

248
  channel = ares_malloc_zero(sizeof(*channel));
1,117✔
249
  if (!channel) {
1,117✔
250
    *channelptr = NULL;
5✔
251
    return ARES_ENOMEM;
5✔
252
  }
253

254
  /* We are in a good state */
255
  channel->sys_up = ARES_TRUE;
1,112✔
256

257
  /* One option where zero is valid, so set default value here */
258
  channel->ndots = 1;
1,112✔
259

260
  status = ares_channel_threading_init(channel);
1,112✔
261
  if (status != ARES_SUCCESS) {
1,112✔
262
    goto done;
8✔
263
  }
264

265
  /* Generate random key */
266
  channel->rand_state = ares_init_rand_state();
1,104✔
267
  if (channel->rand_state == NULL) {
1,104✔
268
    status = ARES_ENOMEM;
4✔
269
    DEBUGF(fprintf(stderr, "Error: init_id_key failed: %s\n",
270
                   ares_strerror(status)));
271
    goto done;
4✔
272
  }
273

274
  /* Initialize Server List */
275
  channel->servers =
1,100✔
276
    ares_slist_create(channel->rand_state, server_sort_cb, server_destroy_cb);
1,100✔
277
  if (channel->servers == NULL) {
1,100✔
278
    status = ARES_ENOMEM;
8✔
279
    goto done;
8✔
280
  }
281

282
  /* Initialize our lists of queries */
283
  channel->all_queries = ares_llist_create(NULL);
1,092✔
284
  if (channel->all_queries == NULL) {
1,092✔
285
    status = ARES_ENOMEM;
4✔
286
    goto done;
4✔
287
  }
288

289
  channel->queries_by_qid = ares_htable_szvp_create(NULL);
1,088✔
290
  if (channel->queries_by_qid == NULL) {
1,088✔
291
    status = ARES_ENOMEM;
10✔
292
    goto done;
10✔
293
  }
294

295
  channel->queries_by_timeout =
1,078✔
296
    ares_slist_create(channel->rand_state, ares_query_timeout_cmp_cb, NULL);
1,078✔
297
  if (channel->queries_by_timeout == NULL) {
1,078✔
298
    status = ARES_ENOMEM;
2✔
299
    goto done;
2✔
300
  }
301

302
  channel->connnode_by_socket = ares_htable_asvp_create(NULL);
1,076✔
303
  if (channel->connnode_by_socket == NULL) {
1,076✔
304
    status = ARES_ENOMEM;
3✔
305
    goto done;
3✔
306
  }
307

308
  /* Initialize configuration by each of the four sources, from highest
309
   * precedence to lowest.
310
   */
311

312
  status = ares_init_by_options(channel, options, optmask);
1,073✔
313
  if (status != ARES_SUCCESS) {
1,073✔
314
    DEBUGF(fprintf(stderr, "Error: init_by_options failed: %s\n",
315
                   ares_strerror(status)));
316
    /* If we fail to apply user-specified options, fail the whole init process
317
     */
318
    goto done;
×
319
  }
320

321
  /* Go ahead and let it initialize the query cache even if the ttl is 0 and
322
   * completely unused.  This reduces the number of different code paths that
323
   * might be followed even if there is a minor performance hit. */
324
  status = ares_qcache_create(channel->rand_state, channel->qcache_max_ttl,
1,073✔
325
                              &channel->qcache);
326
  if (status != ARES_SUCCESS) {
1,073✔
327
    goto done; /* LCOV_EXCL_LINE: OutOfMemory */
328
  }
329

330
  if (status == ARES_SUCCESS) {
1,067✔
331
    status = ares_init_by_sysconfig(channel);
1,067✔
332
    if (status != ARES_SUCCESS) {
333
      DEBUGF(fprintf(stderr, "Error: init_by_sysconfig failed: %s\n",
334
                     ares_strerror(status)));
335
    }
336
  }
337

338
  /*
339
   * No matter what failed or succeeded, seed defaults to provide
340
   * useful behavior for things that we missed.
341
   */
342
  status = init_by_defaults(channel);
1,067✔
343
  if (status != ARES_SUCCESS) {
1,067✔
344
    DEBUGF(fprintf(stderr, "Error: init_by_defaults failed: %s\n",
345
                   ares_strerror(status)));
346
    goto done;
1✔
347
  }
348

349
  ares_set_socket_functions_def(channel);
1,066✔
350

351
  /* Initialize the event thread */
352
  if (channel->optmask & ARES_OPT_EVENT_THREAD) {
1,066✔
353
    ares_event_thread_t *e = NULL;
522✔
354

355
    status = ares_event_thread_init(channel);
522✔
356
    if (status != ARES_SUCCESS) {
522✔
357
      goto done; /* LCOV_EXCL_LINE: UntestablePath */
358
    }
359

360
    /* Initialize monitor for configuration changes.  In some rare cases,
361
     * ARES_ENOTIMP may occur (OpenWatcom), ignore this. */
362
    e      = channel->sock_state_cb_data;
522✔
363
    status = ares_event_configchg_init(&e->configchg, e);
522✔
364
    if (status != ARES_SUCCESS && status != ARES_ENOTIMP) {
522✔
365
      goto done; /* LCOV_EXCL_LINE: UntestablePath */
366
    }
367
    status = ARES_SUCCESS;
522✔
368
  }
369

370
done:
544✔
371
  if (status != ARES_SUCCESS) {
1,112✔
372
    ares_destroy(channel);
46✔
373
    return (int)status;
46✔
374
  }
375

376
  *channelptr = channel;
1,066✔
377
  return ARES_SUCCESS;
1,066✔
378
}
379

380
static void *ares_reinit_thread(void *arg)
60✔
381
{
382
  ares_channel_t *channel = arg;
60✔
383
  ares_status_t   status;
384

385
  /* ares_init_by_sysconfig() will lock when applying the config, but not
386
   * when retrieving. */
387
  status = ares_init_by_sysconfig(channel);
60✔
388
  if (status != ARES_SUCCESS) {
389
    DEBUGF(fprintf(stderr, "Error: init_by_sysconfig failed: %s\n",
390
                   ares_strerror(status)));
391
  }
392

393
  ares_channel_lock(channel);
60✔
394

395
  /* Flush cached queries on reinit */
396
  if (status == ARES_SUCCESS && channel->qcache) {
60✔
397
    ares_qcache_flush(channel->qcache);
60✔
398
  }
399

400
  channel->reinit_pending = ARES_FALSE;
60✔
401
  ares_channel_unlock(channel);
60✔
402

403
  return NULL;
60✔
404
}
405

406
ares_status_t ares_reinit(ares_channel_t *channel)
61✔
407
{
408
  ares_status_t status = ARES_SUCCESS;
61✔
409

410
  if (channel == NULL) {
61✔
411
    return ARES_EFORMERR;
1✔
412
  }
413

414
  ares_channel_lock(channel);
60✔
415

416
  /* If a reinit is already in process, lets not do it again. Or if we are
417
   * shutting down, skip. */
418
  if (!channel->sys_up || channel->reinit_pending) {
60✔
419
    ares_channel_unlock(channel);
×
420
    return ARES_SUCCESS;
×
421
  }
422
  channel->reinit_pending = ARES_TRUE;
60✔
423
  ares_channel_unlock(channel);
60✔
424

425
  if (ares_threadsafety()) {
60✔
426
    /* clean up the prior reinit process's thread.  We know the thread isn't
427
     * running since reinit_pending was false */
428
    if (channel->reinit_thread != NULL) {
60✔
429
      void *rv;
430
      ares_thread_join(channel->reinit_thread, &rv);
×
431
      channel->reinit_thread = NULL;
×
432
    }
433

434
    /* Spawn a new thread */
435
    status =
436
      ares_thread_create(&channel->reinit_thread, ares_reinit_thread, channel);
60✔
437
    if (status != ARES_SUCCESS) {
60✔
438
      /* LCOV_EXCL_START: UntestablePath */
439
      ares_channel_lock(channel);
440
      channel->reinit_pending = ARES_FALSE;
441
      ares_channel_unlock(channel);
442
      /* LCOV_EXCL_STOP */
443
    }
444
  } else {
445
    /* Threading support not available, call directly */
446
    ares_reinit_thread(channel);
×
447
  }
448

449
  return status;
60✔
450
}
451

452
/* ares_dup() duplicates a channel handle with all its options and returns a
453
   new channel handle */
454
int ares_dup(ares_channel_t **dest, const ares_channel_t *src)
25✔
455
{
456
  struct ares_options opts;
457
  ares_status_t       rc;
458
  int                 optmask;
459

460
  if (dest == NULL || src == NULL) {
25✔
461
    return ARES_EFORMERR;
1✔
462
  }
463

464
  *dest = NULL; /* in case of failure return NULL explicitly */
24✔
465

466
  /* First get the options supported by the old ares_save_options() function,
467
     which is most of them */
468
  rc = (ares_status_t)ares_save_options(src, &opts, &optmask);
24✔
469
  if (rc != ARES_SUCCESS) {
24✔
470
    ares_destroy_options(&opts);
8✔
471
    goto done;
8✔
472
  }
473

474
  /* Then create the new channel with those options */
475
  rc = (ares_status_t)ares_init_options(dest, &opts, optmask);
16✔
476

477
  /* destroy the options copy to not leak any memory */
478
  ares_destroy_options(&opts);
16✔
479

480
  if (rc != ARES_SUCCESS) {
16✔
481
    goto done;
10✔
482
  }
483

484
  ares_channel_lock(src);
6✔
485
  /* Now clone the options that ares_save_options() doesn't support, but are
486
   * user-provided */
487
  (*dest)->sock_create_cb            = src->sock_create_cb;
6✔
488
  (*dest)->sock_create_cb_data       = src->sock_create_cb_data;
6✔
489
  (*dest)->sock_config_cb            = src->sock_config_cb;
6✔
490
  (*dest)->sock_config_cb_data       = src->sock_config_cb_data;
6✔
491
  memcpy(&(*dest)->sock_funcs, &(src->sock_funcs), sizeof((*dest)->sock_funcs));
6✔
492
  (*dest)->sock_func_cb_data         = src->sock_func_cb_data;
6✔
493
  (*dest)->legacy_sock_funcs         = src->legacy_sock_funcs;
6✔
494
  (*dest)->legacy_sock_funcs_cb_data = src->legacy_sock_funcs_cb_data;
6✔
495
  (*dest)->server_state_cb           = src->server_state_cb;
6✔
496
  (*dest)->server_state_cb_data      = src->server_state_cb_data;
6✔
497

498
  ares_strcpy((*dest)->local_dev_name, src->local_dev_name,
6✔
499
              sizeof((*dest)->local_dev_name));
500
  (*dest)->local_ip4 = src->local_ip4;
6✔
501
  memcpy((*dest)->local_ip6, src->local_ip6, sizeof(src->local_ip6));
6✔
502
  ares_channel_unlock(src);
6✔
503

504
  /* Servers are a bit unique as ares_init_options() only allows ipv4 servers
505
   * and not a port per server, but there are other user specified ways, that
506
   * too will toggle the optmask ARES_OPT_SERVERS to let us know.  If that's
507
   * the case, pull them in.
508
   *
509
   * We don't want to clone system-configuration servers though.
510
   *
511
   * We must use the "csv" format to get things like link-local address support
512
   */
513

514
  if (optmask & ARES_OPT_SERVERS) {
6✔
515
    char *csv = ares_get_servers_csv(src);
6✔
516
    if (csv == NULL) {
6✔
517
      /* LCOV_EXCL_START: OutOfMemory */
518
      ares_destroy(*dest);
519
      *dest = NULL;
520
      rc    = ARES_ENOMEM;
521
      goto done;
522
      /* LCOV_EXCL_STOP */
523
    }
524

525
    rc = (ares_status_t)ares_set_servers_ports_csv(*dest, csv);
6✔
526
    ares_free_string(csv);
6✔
527
    if (rc != ARES_SUCCESS) {
6✔
528
      /* LCOV_EXCL_START: OutOfMemory */
529
      ares_destroy(*dest);
530
      *dest = NULL;
531
      goto done;
532
      /* LCOV_EXCL_STOP */
533
    }
534
  }
535

536
  rc = ARES_SUCCESS;
6✔
537
done:
24✔
538
  return (int)rc; /* everything went fine */
24✔
539
}
540

541
void ares_set_local_ip4(ares_channel_t *channel, unsigned int local_ip)
26✔
542
{
543
  if (channel == NULL) {
26✔
544
    return;
1✔
545
  }
546
  ares_channel_lock(channel);
25✔
547
  channel->local_ip4 = local_ip;
25✔
548
  ares_channel_unlock(channel);
25✔
549
}
550

551
/* local_ip6 should be 16 bytes in length */
552
void ares_set_local_ip6(ares_channel_t *channel, const unsigned char *local_ip6)
26✔
553
{
554
  if (channel == NULL) {
26✔
555
    return;
1✔
556
  }
557
  ares_channel_lock(channel);
25✔
558
  memcpy(&channel->local_ip6, local_ip6, sizeof(channel->local_ip6));
25✔
559
  ares_channel_unlock(channel);
25✔
560
}
561

562
/* local_dev_name should be null terminated. */
563
void ares_set_local_dev(ares_channel_t *channel, const char *local_dev_name)
26✔
564
{
565
  if (channel == NULL) {
26✔
566
    return;
1✔
567
  }
568

569
  ares_channel_lock(channel);
25✔
570
  ares_strcpy(channel->local_dev_name, local_dev_name,
25✔
571
              sizeof(channel->local_dev_name));
572
  channel->local_dev_name[sizeof(channel->local_dev_name) - 1] = 0;
25✔
573
  ares_channel_unlock(channel);
25✔
574
}
575

576
int ares_set_sortlist(ares_channel_t *channel, const char *sortstr)
83✔
577
{
578
  size_t           nsort    = 0;
83✔
579
  struct apattern *sortlist = NULL;
83✔
580
  ares_status_t    status;
581

582
  if (!channel) {
83✔
583
    return ARES_ENODATA;
1✔
584
  }
585
  ares_channel_lock(channel);
82✔
586

587
  status = ares_parse_sortlist(&sortlist, &nsort, sortstr);
82✔
588
  if (status == ARES_SUCCESS && sortlist) {
82✔
589
    if (channel->sortlist) {
73✔
590
      ares_free(channel->sortlist);
39✔
591
    }
592
    channel->sortlist = sortlist;
73✔
593
    channel->nsort    = nsort;
73✔
594

595
    /* Save sortlist as if it was passed in as an option */
596
    channel->optmask |= ARES_OPT_SORTLIST;
73✔
597
  }
598
  ares_channel_unlock(channel);
82✔
599
  return (int)status;
82✔
600
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc