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

c-ares / c-ares / 14332039557

08 Apr 2025 11:11AM UTC coverage: 92.274% (-0.01%) from 92.287%
14332039557

push

github

bradh352
Windows build fix

1 of 1 new or added line in 1 file covered. (100.0%)

4 existing lines in 2 files now uncovered.

21009 of 22768 relevant lines covered (92.27%)

99252.52 hits per line

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

92.31
/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 "ares_platform.h"
66
#include "event/ares_event.h"
67

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

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

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

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

92
  return 0;
×
93
}
94

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

100
  if (s1->consec_failures < s2->consec_failures) {
6,154✔
101
    return -1;
467✔
102
  }
103
  if (s1->consec_failures > s2->consec_failures) {
5,687✔
104
    return 1;
402✔
105
  }
106
  if (s1->idx < s2->idx) {
5,285✔
107
    return -1;
383✔
108
  }
109
  if (s1->idx > s2->idx) {
4,902✔
110
    return 1;
462✔
111
  }
112
  return 0;
4,440✔
113
}
114

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

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

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

141
  if (channel->timeout == 0) {
1,070✔
142
    channel->timeout = DEFAULT_TIMEOUT;
197✔
143
  }
144

145
  if (channel->tries == 0) {
1,070✔
146
    channel->tries = DEFAULT_TRIES;
197✔
147
  }
148

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

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

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

166
    rc = ares__servers_update(channel, sconfig, ARES_FALSE);
9✔
167
    ares__llist_destroy(sconfig);
9✔
168

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

174
#if defined(USE_WINSOCK)
175
#  define toolong(x) (x == -1) && (SOCKERRNO == WSAEFAULT)
176
#elif defined(ENAMETOOLONG)
177
#  define toolong(x) \
178
    (x == -1) && ((SOCKERRNO == ENAMETOOLONG) || (SOCKERRNO == EINVAL))
179
#else
180
#  define toolong(x) (x == -1) && (SOCKERRNO == EINVAL)
181
#endif
182

183
  if (channel->ndomains == 0) {
1,069✔
184
    /* Derive a default domain search list from the kernel hostname,
185
     * or set it to empty if the hostname isn't helpful.
186
     */
187
#ifndef HAVE_GETHOSTNAME
188
    channel->ndomains = 0; /* default to none */
189
#else
190
    GETHOSTNAME_TYPE_ARG2 lenv = 64;
10✔
191
    size_t                len  = 64;
10✔
192
    int                   res;
193
    channel->ndomains = 0; /* default to none */
10✔
194

195
    hostname = ares_malloc(len);
10✔
196
    if (!hostname) {
10✔
197
      rc = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */
198
      goto error;       /* LCOV_EXCL_LINE: OutOfMemory */
199
    }
200

201
    do {
202
      res = gethostname(hostname, lenv);
10✔
203

204
      if (toolong(res)) {
10✔
205
        char *p;
206
        len  *= 2;
×
207
        lenv *= 2;
×
208
        p     = ares_realloc(hostname, len);
×
209
        if (!p) {
×
210
          rc = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */
211
          goto error;       /* LCOV_EXCL_LINE: OutOfMemory */
212
        }
213
        hostname = p;
×
214
        continue;
×
215
      } else if (res) {
10✔
216
        /* Lets not treat a gethostname failure as critical, since we
217
         * are ok if gethostname doesn't even exist */
218
        *hostname = '\0';
×
219
        break;
×
220
      }
221

222
    } while (res != 0);
10✔
223

224
    dot = strchr(hostname, '.');
10✔
225
    if (dot) {
10✔
226
      /* a dot was found */
227
      channel->domains = ares_malloc(sizeof(char *));
1✔
228
      if (!channel->domains) {
1✔
229
        rc = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */
230
        goto error;       /* LCOV_EXCL_LINE: OutOfMemory */
231
      }
232
      channel->domains[0] = ares_strdup(dot + 1);
1✔
233
      if (!channel->domains[0]) {
1✔
234
        rc = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */
235
        goto error;       /* LCOV_EXCL_LINE: OutOfMemory */
236
      }
237
      channel->ndomains = 1;
1✔
238
    }
239
#endif
240
  }
241

242
  if (channel->nsort == 0) {
1,069✔
243
    channel->sortlist = NULL;
1,065✔
244
  }
245

246
  if (!channel->lookups) {
1,069✔
247
    channel->lookups = ares_strdup("fb");
12✔
248
    if (!channel->lookups) {
12✔
249
      rc = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */
250
    }
251
  }
252

253
  /* Set default fields for server failover behavior */
254
  if (!(channel->optmask & ARES_OPT_SERVER_FAILOVER)) {
1,069✔
255
    channel->server_retry_chance = DEFAULT_SERVER_RETRY_CHANCE;
1,053✔
256
    channel->server_retry_delay  = DEFAULT_SERVER_RETRY_DELAY;
1,053✔
257
  }
258

259
error:
16✔
260
  if (hostname) {
1,070✔
261
    ares_free(hostname);
10✔
262
  }
263

264
  return rc;
1,070✔
265
}
266

267
int ares_init_options(ares_channel_t           **channelptr,
1,120✔
268
                      const struct ares_options *options, int optmask)
269
{
270
  ares_channel_t *channel;
271
  ares_status_t   status = ARES_SUCCESS;
1,120✔
272

273
  if (ares_library_initialized() != ARES_SUCCESS) {
1,120✔
274
    return ARES_ENOTINITIALIZED; /* LCOV_EXCL_LINE: n/a on non-WinSock */
275
  }
276

277
  channel = ares_malloc_zero(sizeof(*channel));
1,120✔
278
  if (!channel) {
1,120✔
279
    *channelptr = NULL;
5✔
280
    return ARES_ENOMEM;
5✔
281
  }
282

283
  /* We are in a good state */
284
  channel->sys_up = ARES_TRUE;
1,115✔
285

286
  /* One option where zero is valid, so set default value here */
287
  channel->ndots = 1;
1,115✔
288

289
  status = ares__channel_threading_init(channel);
1,115✔
290
  if (status != ARES_SUCCESS) {
1,115✔
291
    goto done;
8✔
292
  }
293

294
  /* Generate random key */
295
  channel->rand_state = ares__init_rand_state();
1,107✔
296
  if (channel->rand_state == NULL) {
1,107✔
297
    status = ARES_ENOMEM;
4✔
298
    DEBUGF(fprintf(stderr, "Error: init_id_key failed: %s\n",
299
                   ares_strerror(status)));
300
    goto done;
4✔
301
  }
302

303
  /* Initialize Server List */
304
  channel->servers =
1,103✔
305
    ares__slist_create(channel->rand_state, server_sort_cb, server_destroy_cb);
1,103✔
306
  if (channel->servers == NULL) {
1,103✔
307
    status = ARES_ENOMEM;
8✔
308
    goto done;
8✔
309
  }
310

311
  /* Initialize our lists of queries */
312
  channel->all_queries = ares__llist_create(NULL);
1,095✔
313
  if (channel->all_queries == NULL) {
1,095✔
314
    status = ARES_ENOMEM;
4✔
315
    goto done;
4✔
316
  }
317

318
  channel->queries_by_qid = ares__htable_szvp_create(NULL);
1,091✔
319
  if (channel->queries_by_qid == NULL) {
1,091✔
320
    status = ARES_ENOMEM;
10✔
321
    goto done;
10✔
322
  }
323

324
  channel->queries_by_timeout =
1,081✔
325
    ares__slist_create(channel->rand_state, ares_query_timeout_cmp_cb, NULL);
1,081✔
326
  if (channel->queries_by_timeout == NULL) {
1,081✔
327
    status = ARES_ENOMEM;
2✔
328
    goto done;
2✔
329
  }
330

331
  channel->connnode_by_socket = ares__htable_asvp_create(NULL);
1,079✔
332
  if (channel->connnode_by_socket == NULL) {
1,079✔
333
    status = ARES_ENOMEM;
3✔
334
    goto done;
3✔
335
  }
336

337
  /* Initialize configuration by each of the four sources, from highest
338
   * precedence to lowest.
339
   */
340

341
  status = ares__init_by_options(channel, options, optmask);
1,076✔
342
  if (status != ARES_SUCCESS) {
1,076✔
343
    DEBUGF(fprintf(stderr, "Error: init_by_options failed: %s\n",
344
                   ares_strerror(status)));
345
    /* If we fail to apply user-specified options, fail the whole init process
346
     */
347
    goto done;
×
348
  }
349

350
  /* Go ahead and let it initialize the query cache even if the ttl is 0 and
351
   * completely unused.  This reduces the number of different code paths that
352
   * might be followed even if there is a minor performance hit. */
353
  status = ares__qcache_create(channel->rand_state, channel->qcache_max_ttl,
1,076✔
354
                               &channel->qcache);
355
  if (status != ARES_SUCCESS) {
1,076✔
356
    goto done; /* LCOV_EXCL_LINE: OutOfMemory */
357
  }
358

359
  if (status == ARES_SUCCESS) {
1,070✔
360
    status = ares__init_by_sysconfig(channel);
1,070✔
361
    if (status != ARES_SUCCESS) {
362
      DEBUGF(fprintf(stderr, "Error: init_by_sysconfig failed: %s\n",
363
                     ares_strerror(status)));
364
    }
365
  }
366

367
  /*
368
   * No matter what failed or succeeded, seed defaults to provide
369
   * useful behavior for things that we missed.
370
   */
371
  status = init_by_defaults(channel);
1,070✔
372
  if (status != ARES_SUCCESS) {
1,070✔
373
    DEBUGF(fprintf(stderr, "Error: init_by_defaults failed: %s\n",
374
                   ares_strerror(status)));
375
    goto done;
1✔
376
  }
377

378
  /* Initialize the event thread */
379
  if (channel->optmask & ARES_OPT_EVENT_THREAD) {
1,069✔
380
    ares_event_thread_t *e = NULL;
522✔
381

382
    status = ares_event_thread_init(channel);
522✔
383
    if (status != ARES_SUCCESS) {
522✔
384
      goto done; /* LCOV_EXCL_LINE: UntestablePath */
385
    }
386

387
    /* Initialize monitor for configuration changes.  In some rare cases,
388
     * ARES_ENOTIMP may occur (OpenWatcom), ignore this. */
389
    e      = channel->sock_state_cb_data;
522✔
390
    status = ares_event_configchg_init(&e->configchg, e);
522✔
391
    if (status != ARES_SUCCESS && status != ARES_ENOTIMP) {
522✔
392
      goto done; /* LCOV_EXCL_LINE: UntestablePath */
393
    }
394
    status = ARES_SUCCESS;
522✔
395
  }
396

397
done:
547✔
398
  if (status != ARES_SUCCESS) {
1,115✔
399
    ares_destroy(channel);
46✔
400
    return (int)status;
46✔
401
  }
402

403
  *channelptr = channel;
1,069✔
404
  return ARES_SUCCESS;
1,069✔
405
}
406

407
static void *ares_reinit_thread(void *arg)
60✔
408
{
409
  ares_channel_t *channel = arg;
60✔
410
  ares_status_t   status;
411

412
  /* ares__init_by_sysconfig() will lock when applying the config, but not
413
   * when retrieving. */
414
  status = ares__init_by_sysconfig(channel);
60✔
415
  if (status != ARES_SUCCESS) {
416
    DEBUGF(fprintf(stderr, "Error: init_by_sysconfig failed: %s\n",
417
                   ares_strerror(status)));
418
  }
419

420
  ares__channel_lock(channel);
60✔
421

422
  /* Flush cached queries on reinit */
423
  if (status == ARES_SUCCESS && channel->qcache) {
60✔
424
    ares__qcache_flush(channel->qcache);
60✔
425
  }
426

427
  channel->reinit_pending = ARES_FALSE;
60✔
428
  ares__channel_unlock(channel);
60✔
429

430
  return NULL;
60✔
431
}
432

433
ares_status_t ares_reinit(ares_channel_t *channel)
61✔
434
{
435
  ares_status_t status = ARES_SUCCESS;
61✔
436

437
  if (channel == NULL) {
61✔
438
    return ARES_EFORMERR;
1✔
439
  }
440

441
  ares__channel_lock(channel);
60✔
442

443
  /* If a reinit is already in process, lets not do it again. Or if we are
444
   * shutting down, skip. */
445
  if (!channel->sys_up || channel->reinit_pending) {
60✔
446
    ares__channel_unlock(channel);
×
447
    return ARES_SUCCESS;
×
448
  }
449
  channel->reinit_pending = ARES_TRUE;
60✔
450
  ares__channel_unlock(channel);
60✔
451

452
  if (ares_threadsafety()) {
60✔
453
    /* clean up the prior reinit process's thread.  We know the thread isn't
454
     * running since reinit_pending was false */
455
    if (channel->reinit_thread != NULL) {
60✔
456
      void *rv;
457
      ares__thread_join(channel->reinit_thread, &rv);
×
458
      channel->reinit_thread = NULL;
×
459
    }
460

461
    /* Spawn a new thread */
462
    status =
463
      ares__thread_create(&channel->reinit_thread, ares_reinit_thread, channel);
60✔
464
    if (status != ARES_SUCCESS) {
60✔
465
      /* LCOV_EXCL_START: UntestablePath */
466
      ares__channel_lock(channel);
467
      channel->reinit_pending = ARES_FALSE;
468
      ares__channel_unlock(channel);
469
      /* LCOV_EXCL_STOP */
470
    }
471
  } else {
472
    /* Threading support not available, call directly */
473
    ares_reinit_thread(channel);
×
474
  }
475

476
  return status;
60✔
477
}
478

479
/* ares_dup() duplicates a channel handle with all its options and returns a
480
   new channel handle */
481
int ares_dup(ares_channel_t **dest, const ares_channel_t *src)
22✔
482
{
483
  struct ares_options opts;
484
  ares_status_t       rc;
485
  int                 optmask;
486

487
  if (dest == NULL || src == NULL) {
22✔
488
    return ARES_EFORMERR;
1✔
489
  }
490

491
  *dest = NULL; /* in case of failure return NULL explicitly */
21✔
492

493
  /* First get the options supported by the old ares_save_options() function,
494
     which is most of them */
495
  rc = (ares_status_t)ares_save_options(src, &opts, &optmask);
21✔
496
  if (rc != ARES_SUCCESS) {
21✔
497
    ares_destroy_options(&opts);
8✔
498
    goto done;
8✔
499
  }
500

501
  /* Then create the new channel with those options */
502
  rc = (ares_status_t)ares_init_options(dest, &opts, optmask);
13✔
503

504
  /* destroy the options copy to not leak any memory */
505
  ares_destroy_options(&opts);
13✔
506

507
  if (rc != ARES_SUCCESS) {
13✔
508
    goto done;
10✔
509
  }
510

511
  ares__channel_lock(src);
3✔
512
  /* Now clone the options that ares_save_options() doesn't support, but are
513
   * user-provided */
514
  (*dest)->sock_create_cb       = src->sock_create_cb;
3✔
515
  (*dest)->sock_create_cb_data  = src->sock_create_cb_data;
3✔
516
  (*dest)->sock_config_cb       = src->sock_config_cb;
3✔
517
  (*dest)->sock_config_cb_data  = src->sock_config_cb_data;
3✔
518
  (*dest)->sock_funcs           = src->sock_funcs;
3✔
519
  (*dest)->sock_func_cb_data    = src->sock_func_cb_data;
3✔
520
  (*dest)->server_state_cb      = src->server_state_cb;
3✔
521
  (*dest)->server_state_cb_data = src->server_state_cb_data;
3✔
522

523
  ares_strcpy((*dest)->local_dev_name, src->local_dev_name,
3✔
524
              sizeof((*dest)->local_dev_name));
525
  (*dest)->local_ip4 = src->local_ip4;
3✔
526
  memcpy((*dest)->local_ip6, src->local_ip6, sizeof(src->local_ip6));
3✔
527
  ares__channel_unlock(src);
3✔
528

529
  /* Servers are a bit unique as ares_init_options() only allows ipv4 servers
530
   * and not a port per server, but there are other user specified ways, that
531
   * too will toggle the optmask ARES_OPT_SERVERS to let us know.  If that's
532
   * the case, pull them in.
533
   *
534
   * We don't want to clone system-configuration servers though.
535
   *
536
   * We must use the "csv" format to get things like link-local address support
537
   */
538

539
  if (optmask & ARES_OPT_SERVERS) {
3✔
540
    char *csv = ares_get_servers_csv(src);
2✔
541
    if (csv == NULL) {
2✔
542
      /* LCOV_EXCL_START: OutOfMemory */
543
      ares_destroy(*dest);
544
      *dest = NULL;
545
      rc    = ARES_ENOMEM;
546
      goto done;
547
      /* LCOV_EXCL_STOP */
548
    }
549

550
    rc = (ares_status_t)ares_set_servers_ports_csv(*dest, csv);
2✔
551
    ares_free_string(csv);
2✔
552
    if (rc != ARES_SUCCESS) {
2✔
553
      /* LCOV_EXCL_START: OutOfMemory */
554
      ares_destroy(*dest);
555
      *dest = NULL;
556
      goto done;
557
      /* LCOV_EXCL_STOP */
558
    }
559
  }
560

561
  rc = ARES_SUCCESS;
3✔
562
done:
21✔
563
  return (int)rc; /* everything went fine */
21✔
564
}
565

566
void ares_set_local_ip4(ares_channel_t *channel, unsigned int local_ip)
26✔
567
{
568
  if (channel == NULL) {
26✔
569
    return;
1✔
570
  }
571
  ares__channel_lock(channel);
25✔
572
  channel->local_ip4 = local_ip;
25✔
573
  ares__channel_unlock(channel);
25✔
574
}
575

576
/* local_ip6 should be 16 bytes in length */
577
void ares_set_local_ip6(ares_channel_t *channel, const unsigned char *local_ip6)
26✔
578
{
579
  if (channel == NULL) {
26✔
580
    return;
1✔
581
  }
582
  ares__channel_lock(channel);
25✔
583
  memcpy(&channel->local_ip6, local_ip6, sizeof(channel->local_ip6));
25✔
584
  ares__channel_unlock(channel);
25✔
585
}
586

587
/* local_dev_name should be null terminated. */
588
void ares_set_local_dev(ares_channel_t *channel, const char *local_dev_name)
26✔
589
{
590
  if (channel == NULL) {
26✔
591
    return;
1✔
592
  }
593

594
  ares__channel_lock(channel);
25✔
595
  ares_strcpy(channel->local_dev_name, local_dev_name,
25✔
596
              sizeof(channel->local_dev_name));
597
  channel->local_dev_name[sizeof(channel->local_dev_name) - 1] = 0;
25✔
598
  ares__channel_unlock(channel);
25✔
599
}
600

601
int ares_set_sortlist(ares_channel_t *channel, const char *sortstr)
83✔
602
{
603
  size_t           nsort    = 0;
83✔
604
  struct apattern *sortlist = NULL;
83✔
605
  ares_status_t    status;
606

607
  if (!channel) {
83✔
608
    return ARES_ENODATA;
1✔
609
  }
610
  ares__channel_lock(channel);
82✔
611

612
  status = ares__parse_sortlist(&sortlist, &nsort, sortstr);
82✔
613
  if (status == ARES_SUCCESS && sortlist) {
82✔
614
    if (channel->sortlist) {
73✔
615
      ares_free(channel->sortlist);
39✔
616
    }
617
    channel->sortlist = sortlist;
73✔
618
    channel->nsort    = nsort;
73✔
619

620
    /* Save sortlist as if it was passed in as an option */
621
    channel->optmask |= ARES_OPT_SORTLIST;
73✔
622
  }
623
  ares__channel_unlock(channel);
82✔
624
  return (int)status;
82✔
625
}
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