Coverage Report

Created: 2025-11-24 06:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libcups/cups/http-addrlist.c
Line
Count
Source
1
//
2
// HTTP address list routines for CUPS.
3
//
4
// Copyright © 2021-2025 by OpenPrinting.
5
// Copyright © 2007-2021 by Apple Inc.
6
// Copyright © 1997-2007 by Easy Software Products, all rights reserved.
7
//
8
// Licensed under Apache License v2.0.  See the file "LICENSE" for more
9
// information.
10
//
11
12
#include "cups-private.h"
13
#ifdef HAVE_RESOLV_H
14
#  include <resolv.h>
15
#endif // HAVE_RESOLV_H
16
#ifdef _WIN32
17
#  define poll WSAPoll
18
#else
19
#  include <poll.h>
20
#  include <fcntl.h>
21
#endif // _WIN32
22
23
24
//
25
// 'httpAddrConnect()' - Connect to any of the addresses in the list with a
26
//                       timeout and optional cancel.
27
//
28
29
http_addrlist_t *     // O - Connected address or NULL on failure
30
httpAddrConnect(
31
    http_addrlist_t *addrlist,    // I - List of potential addresses
32
    int             *sock,    // O - Socket
33
    int             msec,   // I - Timeout in milliseconds
34
    int             *cancel)    // I - Pointer to "cancel" variable
35
0
{
36
0
  int     val;    // Socket option value
37
0
#ifndef _WIN32
38
0
  int     i, j,   // Looping vars
39
0
      flags,    // Socket flags
40
0
      result;   // Result from select() or poll()
41
0
#endif // !_WIN32
42
0
  int     remaining;  // Remaining timeout
43
0
  int     nfds,   // Number of file descriptors
44
0
      fds[100]; // Socket file descriptors
45
0
  http_addrlist_t *addrs[100];  // Addresses
46
0
#ifdef O_NONBLOCK
47
0
  struct pollfd   pfds[100];  // Polled file descriptors
48
0
#endif // O_NONBLOCK
49
#ifdef DEBUG
50
#  ifndef _WIN32
51
  socklen_t   len;    // Length of value
52
  http_addr_t   peer;   // Peer address
53
#  endif // !_WIN32
54
  char      temp[256];  // Temporary address string
55
#endif // DEBUG
56
57
58
0
  DEBUG_printf("httpAddrConnect2(addrlist=%p, sock=%p, msec=%d, cancel=%p)", (void *)addrlist, (void *)sock, msec, (void *)cancel);
59
60
0
  if (!sock)
61
0
  {
62
0
    errno = EINVAL;
63
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
64
0
    return (NULL);
65
0
  }
66
67
0
  if (cancel && *cancel)
68
0
    return (NULL);
69
70
0
  httpInitialize();
71
72
0
  if (msec <= 0)
73
0
    msec = INT_MAX;
74
75
  // Loop through each address until we connect or run out of addresses...
76
0
  nfds      = 0;
77
0
  remaining = msec;
78
79
0
  while (remaining > 0)
80
0
  {
81
0
    if (cancel && *cancel)
82
0
    {
83
0
      while (nfds > 0)
84
0
      {
85
0
        nfds --;
86
0
  httpAddrClose(NULL, fds[nfds]);
87
0
      }
88
89
0
      return (NULL);
90
0
    }
91
92
0
    if (addrlist && nfds < (int)(sizeof(fds) / sizeof(fds[0])))
93
0
    {
94
      // Create the socket...
95
0
      DEBUG_printf("2httpAddrConnect: Trying %s:%d...", httpAddrGetString(&(addrlist->addr), temp, sizeof(temp)), httpAddrGetPort(&(addrlist->addr)));
96
97
0
      if ((fds[nfds] = (int)socket(httpAddrGetFamily(&(addrlist->addr)), SOCK_STREAM, 0)) < 0)
98
0
      {
99
        // Don't abort yet, as this could just be an issue with the local
100
  // system not being configured with IPv4/IPv6/domain socket enabled.
101
  // Just skip this address.
102
0
        addrlist = addrlist->next;
103
0
  continue;
104
0
      }
105
106
      // Set options...
107
0
      val = 1;
108
0
      if (setsockopt(fds[nfds], SOL_SOCKET, SO_REUSEADDR, CUPS_SOCAST &val, sizeof(val)))
109
0
  DEBUG_printf("httpAddrConnect: setsockopt(SO_REUSEADDR) failed - %s", strerror(errno));
110
111
0
#ifdef SO_REUSEPORT
112
0
      val = 1;
113
0
      if (setsockopt(fds[nfds], SOL_SOCKET, SO_REUSEPORT, CUPS_SOCAST &val, sizeof(val)))
114
0
  DEBUG_printf("httpAddrConnect: setsockopt(SO_REUSEPORT) failed - %s", strerror(errno));
115
0
#endif // SO_REUSEPORT
116
117
#ifdef SO_NOSIGPIPE
118
      val = 1;
119
      if (setsockopt(fds[nfds], SOL_SOCKET, SO_NOSIGPIPE, CUPS_SOCAST &val, sizeof(val)))
120
  DEBUG_printf("httpAddrConnect: setsockopt(SO_NOSIGPIPE) failed - %s", strerror(errno));
121
#endif // SO_NOSIGPIPE
122
123
      // Using TCP_NODELAY improves responsiveness, especially on systems with a
124
      // slow loopback interface.
125
0
      val = 1;
126
0
      if (setsockopt(fds[nfds], IPPROTO_TCP, TCP_NODELAY, CUPS_SOCAST &val, sizeof(val)))
127
0
  DEBUG_printf("httpAddrConnect: setsockopt(TCP_NODELAY) failed - %s", strerror(errno));
128
129
0
#ifdef FD_CLOEXEC
130
      // Close this socket when starting another process...
131
0
      if (fcntl(fds[nfds], F_SETFD, FD_CLOEXEC))
132
0
  DEBUG_printf("httpAddrConnect: fcntl(F_SETFD, FD_CLOEXEC) failed - %s", strerror(errno));
133
0
#endif // FD_CLOEXEC
134
135
0
#ifdef O_NONBLOCK
136
      // Do an asynchronous connect by setting the socket non-blocking...
137
0
      DEBUG_printf("httpAddrConnect: Setting non-blocking connect()");
138
139
0
      flags = fcntl(fds[nfds], F_GETFL, 0);
140
0
      if (fcntl(fds[nfds], F_SETFL, flags | O_NONBLOCK))
141
0
  DEBUG_printf("httpAddrConnect: fcntl(F_SETFL, O_NONBLOCK) failed - %s", strerror(errno));
142
0
#endif // O_NONBLOCK
143
144
      // Then connect...
145
0
      if (!connect(fds[nfds], &(addrlist->addr.addr), (socklen_t)httpAddrGetLength(&(addrlist->addr))))
146
0
      {
147
0
  DEBUG_printf("1httpAddrConnect: Connected to %s:%d...", httpAddrGetString(&(addrlist->addr), temp, sizeof(temp)), httpAddrGetPort(&(addrlist->addr)));
148
149
0
#ifdef O_NONBLOCK
150
0
  if (fcntl(fds[nfds], F_SETFL, flags))
151
0
    DEBUG_printf("httpAddrConnect: fcntl(F_SETFL, 0) failed - %s", strerror(errno));
152
0
#endif // O_NONBLOCK
153
154
0
  *sock = fds[nfds];
155
156
0
  while (nfds > 0)
157
0
  {
158
0
    nfds --;
159
0
    httpAddrClose(NULL, fds[nfds]);
160
0
  }
161
162
0
  return (addrlist);
163
0
      }
164
165
#ifdef _WIN32
166
      if (WSAGetLastError() != WSAEINPROGRESS && WSAGetLastError() != WSAEWOULDBLOCK)
167
#else
168
0
      if (errno != EINPROGRESS && errno != EWOULDBLOCK)
169
0
#endif // _WIN32
170
0
      {
171
0
  DEBUG_printf("1httpAddrConnect: Unable to connect to %s:%d: %s", httpAddrGetString(&(addrlist->addr), temp, sizeof(temp)), httpAddrGetPort(&(addrlist->addr)), strerror(errno));
172
0
  httpAddrClose(NULL, fds[nfds]);
173
0
  addrlist = addrlist->next;
174
0
  continue;
175
0
      }
176
177
0
#ifndef _WIN32
178
0
      if (fcntl(fds[nfds], F_SETFL, flags))
179
0
  DEBUG_printf("httpAddrConnect: fcntl(F_SETFL, 0) failed - %s", strerror(errno));
180
0
#endif // !_WIN32
181
182
0
      addrs[nfds] = addrlist;
183
0
      nfds ++;
184
0
      addrlist = addrlist->next;
185
0
    }
186
187
0
    if (!addrlist && nfds == 0)
188
0
    {
189
#ifdef _WIN32
190
      errno = WSAEHOSTDOWN;
191
#else
192
0
      errno = EHOSTDOWN;
193
0
#endif // _WIN32
194
0
      break;
195
0
    }
196
197
    // See if we can connect to any of the addresses so far...
198
0
#ifdef O_NONBLOCK
199
0
    DEBUG_puts("1httpAddrConnect: Finishing async connect()");
200
201
0
    do
202
0
    {
203
0
      if (cancel && *cancel)
204
0
      {
205
        // Close this socket and return...
206
0
  DEBUG_puts("1httpAddrConnect: Canceled connect()");
207
208
0
  while (nfds > 0)
209
0
  {
210
0
    nfds --;
211
0
    httpAddrClose(NULL, fds[nfds]);
212
0
  }
213
214
0
  *sock = -1;
215
216
0
  return (NULL);
217
0
      }
218
219
0
      for (i = 0; i < nfds; i ++)
220
0
      {
221
0
  pfds[i].fd     = fds[i];
222
0
  pfds[i].events = POLLIN | POLLOUT;
223
0
      }
224
225
0
      result = poll(pfds, (nfds_t)nfds, addrlist ? 100 : remaining > 250 ? 250 : remaining);
226
227
0
      DEBUG_printf("1httpAddrConnect: poll() returned %d (%d)", result, errno);
228
0
    }
229
#  ifdef _WIN32
230
    while (result < 0 && (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEWOULDBLOCK));
231
#  else
232
0
    while (result < 0 && (errno == EINTR || errno == EAGAIN));
233
0
#  endif // _WIN32
234
235
0
    if (result > 0)
236
0
    {
237
0
      http_addrlist_t *connaddr = NULL; // Connected address, if any
238
239
0
      for (i = 0; i < nfds; i ++)
240
0
      {
241
0
  DEBUG_printf("1httpAddrConnect: pfds[%d].revents=%x\n", i, pfds[i].revents);
242
243
#  ifdef _WIN32
244
  if (((WSAGetLastError() == WSAEINPROGRESS) && (pfds[i].revents & POLLIN) && (pfds[i].revents & POLLOUT)) ||
245
#  else
246
0
  if (((errno == EINPROGRESS) && (pfds[i].revents & POLLIN) && (pfds[i].revents & POLLOUT)) ||
247
0
#  endif /* _WIN32 */
248
0
      ((pfds[i].revents & POLLHUP) && (pfds[i].revents & (POLLIN | POLLOUT))))
249
0
  {
250
    // Some systems generate POLLIN or POLLOUT together with POLLHUP when
251
    // doing asynchronous connections.  The solution seems to be to use
252
    // getsockopt to check the SO_ERROR value and ignore the POLLHUP if
253
    // there is no error or the error is EINPROGRESS.
254
0
    int     sres,   // Return value from getsockopt() - 0, or -1 if error
255
0
        serr;   // SO_ERROR value
256
0
    socklen_t slen = sizeof(serr);// Value size
257
258
0
    sres = getsockopt(fds[i], SOL_SOCKET, SO_ERROR, &serr, &slen);
259
260
0
    if (sres || serr)
261
0
    {
262
0
      pfds[i].revents |= POLLERR;
263
#  ifdef DEBUG
264
      DEBUG_printf("1httpAddrConnect: getsockopt returned: %d with error: %s", sres, strerror(serr));
265
#  endif
266
0
    }
267
0
    else if (pfds[i].revents && (pfds[i].revents & POLLHUP) && (pfds[i].revents & (POLLIN | POLLOUT)))
268
0
    {
269
0
      pfds[i].revents &= ~POLLHUP;
270
0
    }
271
0
  }
272
273
0
  if (pfds[i].revents && !(pfds[i].revents & (POLLERR | POLLHUP)))
274
0
  {
275
0
    *sock    = fds[i];
276
0
    connaddr = addrs[i];
277
278
#  ifdef DEBUG
279
    len   = sizeof(peer);
280
    if (!getpeername(fds[i], (struct sockaddr *)&peer, &len))
281
      DEBUG_printf("1httpAddrConnect: Connected to %s:%d...", httpAddrGetString(&peer, temp, sizeof(temp)), httpAddrGetPort(&peer));
282
#  endif // DEBUG
283
284
0
          break;
285
0
  }
286
0
  else if (pfds[i].revents & (POLLERR | POLLHUP))
287
0
        {
288
          // Error on socket, remove from the "pool"...
289
0
    httpAddrClose(NULL, fds[i]);
290
0
          nfds --;
291
0
          if (i < nfds)
292
0
          {
293
0
            memmove(fds + i, fds + i + 1, (size_t)(nfds - i) * (sizeof(fds[0])));
294
0
            memmove(addrs + i, addrs + i + 1, (size_t)(nfds - i) * (sizeof(addrs[0])));
295
0
          }
296
0
          i --;
297
0
        }
298
0
      }
299
300
0
      if (connaddr)
301
0
      {
302
        // Connected on one address, close all of the other sockets we have so
303
        // far and return.
304
0
        for (j = 0; j < i; j ++)
305
0
          httpAddrClose(NULL, fds[j]);
306
307
0
        for (j ++; j < nfds; j ++)
308
0
          httpAddrClose(NULL, fds[j]);
309
310
0
        return (connaddr);
311
0
      }
312
0
    }
313
0
#endif // O_NONBLOCK
314
315
0
    if (addrlist)
316
0
      remaining -= 100;
317
0
    else
318
0
      remaining -= 250;
319
0
  }
320
321
0
  if (remaining <= 0)
322
0
    errno = ETIMEDOUT;
323
324
0
  while (nfds > 0)
325
0
  {
326
0
    nfds --;
327
0
    httpAddrClose(NULL, fds[nfds]);
328
0
  }
329
330
#ifdef _WIN32
331
  _cupsSetError(IPP_STATUS_ERROR_SERVICE_UNAVAILABLE, "Connection failed", 0);
332
#else
333
0
  _cupsSetError(IPP_STATUS_ERROR_SERVICE_UNAVAILABLE, strerror(errno), 0);
334
0
#endif // _WIN32
335
336
0
  return (NULL);
337
0
}
338
339
340
//
341
// 'httpAddrCopyList()' - Copy an address list.
342
//
343
344
http_addrlist_t *     // O - New address list or @code NULL@ on error
345
httpAddrCopyList(
346
    http_addrlist_t *src)   // I - Source address list
347
0
{
348
0
  http_addrlist_t *dst = NULL, // First list entry
349
0
      *prev = NULL, // Previous list entry
350
0
      *current = NULL;// Current list entry
351
352
353
0
  while (src)
354
0
  {
355
0
    if ((current = malloc(sizeof(http_addrlist_t))) == NULL)
356
0
    {
357
0
      current = dst;
358
359
0
      while (current)
360
0
      {
361
0
        prev    = current;
362
0
        current = current->next;
363
364
0
        free(prev);
365
0
      }
366
367
0
      return (NULL);
368
0
    }
369
370
0
    memcpy(current, src, sizeof(http_addrlist_t));
371
372
0
    current->next = NULL;
373
374
0
    if (prev)
375
0
      prev->next = current;
376
0
    else
377
0
      dst = current;
378
379
0
    prev = current;
380
0
    src  = src->next;
381
0
  }
382
383
0
  return (dst);
384
0
}
385
386
387
//
388
// 'httpAddrFreeList()' - Free an address list.
389
//
390
391
void
392
httpAddrFreeList(
393
    http_addrlist_t *addrlist)    // I - Address list to free
394
0
{
395
0
  http_addrlist_t *next;    // Next address in list
396
397
398
  // Free each address in the list...
399
0
  while (addrlist)
400
0
  {
401
0
    next = addrlist->next;
402
403
0
    free(addrlist);
404
405
0
    addrlist = next;
406
0
  }
407
0
}
408
409
410
//
411
// 'httpAddrGetList()' - Get a list of addresses for a hostname.
412
//
413
414
http_addrlist_t *     // O - List of addresses or NULL
415
httpAddrGetList(const char *hostname, // I - Hostname, IP address, or NULL for passive listen address
416
                int        family,  // I - Address family or AF_UNSPEC
417
    const char *service)  // I - Service name or port number
418
0
{
419
0
  http_addrlist_t *first,   // First address in list
420
0
      *addr,    // Current address in list
421
0
      *temp;    // New address
422
0
  char      ipv6[64], // IPv6 address
423
0
      *ipv6zone;  // Pointer to zone separator
424
0
  int     ipv6len;  // Length of IPv6 address
425
0
  _cups_globals_t *cg = _cupsGlobals();
426
          // Global data
427
428
429
#ifdef DEBUG
430
  _cups_debug_printf("httpAddrGetList(hostname=\"%s\", family=AF_%s, "
431
                     "service=\"%s\")\n",
432
         hostname ? hostname : "(nil)",
433
         family == AF_UNSPEC ? "UNSPEC" :
434
#  ifdef AF_LOCAL
435
                   family == AF_LOCAL ? "LOCAL" :
436
#  endif // AF_LOCAL
437
#  ifdef AF_INET6
438
                   family == AF_INET6 ? "INET6" :
439
#  endif // AF_INET6
440
                   family == AF_INET ? "INET" : "???", service);
441
#endif // DEBUG
442
443
0
  httpInitialize();
444
445
0
#ifdef HAVE_RES_INIT
446
  // STR #2920: Initialize resolver after failure in cups-polld
447
  //
448
  // If the previous lookup failed, re-initialize the resolver to prevent
449
  // temporary network errors from persisting.  This *should* be handled by
450
  // the resolver libraries, but apparently the glibc folks do not agree.
451
  //
452
  // We set a flag at the end of this function if we encounter an error that
453
  // requires reinitialization of the resolver functions.  We then call
454
  // res_init() if the flag is set on the next call here or in httpAddrLookup().
455
0
  if (cg->need_res_init)
456
0
  {
457
0
    res_init();
458
459
0
    cg->need_res_init = 0;
460
0
  }
461
0
#endif // HAVE_RES_INIT
462
463
  // Lookup the address the best way we can...
464
0
  first = addr = NULL;
465
466
0
#ifdef AF_LOCAL
467
0
  if (hostname && hostname[0] == '/')
468
0
  {
469
    // Domain socket address...
470
0
    if ((first = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t))) != NULL)
471
0
    {
472
0
      addr = first;
473
0
      first->addr.un.sun_family = AF_LOCAL;
474
0
      cupsCopyString(first->addr.un.sun_path, hostname, sizeof(first->addr.un.sun_path));
475
0
    }
476
0
  }
477
0
  else
478
0
#endif // AF_LOCAL
479
0
  if (!hostname || _cups_strcasecmp(hostname, "localhost"))
480
0
  {
481
0
    struct addrinfo hints,    // Address lookup hints
482
0
      *results, // Address lookup results
483
0
      *current; // Current result
484
0
    int     error;    // getaddrinfo() error
485
486
    // Lookup the address as needed...
487
0
    memset(&hints, 0, sizeof(hints));
488
0
    hints.ai_family   = family;
489
0
    hints.ai_flags    = hostname ? 0 : AI_PASSIVE;
490
0
    hints.ai_socktype = SOCK_STREAM;
491
492
0
    if (hostname && *hostname == '[')
493
0
    {
494
      // Remove brackets from numeric IPv6 address...
495
0
      if (!strncmp(hostname, "[v1.", 4))
496
0
      {
497
        // Copy the newer address format which supports link-local addresses...
498
0
  cupsCopyString(ipv6, hostname + 4, sizeof(ipv6));
499
0
  if ((ipv6len = (int)strlen(ipv6) - 1) >= 0 && ipv6[ipv6len] == ']')
500
0
  {
501
0
          ipv6[ipv6len] = '\0';
502
0
    hostname      = ipv6;
503
504
          // Convert "+zone" in address to "%zone"...
505
0
          if ((ipv6zone = strrchr(ipv6, '+')) != NULL)
506
0
      *ipv6zone = '%';
507
0
  }
508
0
      }
509
0
      else
510
0
      {
511
        // Copy the regular non-link-local IPv6 address...
512
0
  cupsCopyString(ipv6, hostname + 1, sizeof(ipv6));
513
0
  if ((ipv6len = (int)strlen(ipv6) - 1) >= 0 && ipv6[ipv6len] == ']')
514
0
  {
515
0
          ipv6[ipv6len] = '\0';
516
0
    hostname      = ipv6;
517
0
  }
518
0
      }
519
0
    }
520
521
0
    if ((error = getaddrinfo(hostname, service, &hints, &results)) == 0)
522
0
    {
523
      // Copy the results to our own address list structure...
524
0
      for (current = results; current; current = current->ai_next)
525
0
      {
526
0
        if (current->ai_family == AF_INET || current->ai_family == AF_INET6)
527
0
  {
528
    // Copy the address over...
529
0
    temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t));
530
0
    if (!temp)
531
0
    {
532
0
      httpAddrFreeList(first);
533
0
      freeaddrinfo(results);
534
0
      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
535
0
      return (NULL);
536
0
    }
537
538
0
          if (current->ai_family == AF_INET6)
539
0
      memcpy(&(temp->addr.ipv6), current->ai_addr,
540
0
             sizeof(temp->addr.ipv6));
541
0
    else
542
0
      memcpy(&(temp->addr.ipv4), current->ai_addr,
543
0
             sizeof(temp->addr.ipv4));
544
545
          // Append the address to the list...
546
0
    if (!first)
547
0
      first = temp;
548
549
0
    if (addr)
550
0
      addr->next = temp;
551
552
0
    addr = temp;
553
0
  }
554
0
      }
555
556
      // Free the results from getaddrinfo()...
557
0
      freeaddrinfo(results);
558
0
    }
559
0
    else
560
0
    {
561
0
      if (error == EAI_FAIL)
562
0
        cg->need_res_init = 1;
563
564
#  ifdef _WIN32 // Really, Microsoft?!?
565
      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, gai_strerrorA(error), 0);
566
#  else
567
0
      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, gai_strerror(error), 0);
568
0
#  endif // _WIN32
569
0
    }
570
0
  }
571
572
  // Detect some common errors and handle them sanely...
573
0
  if (!addr && (!hostname || !_cups_strcasecmp(hostname, "localhost")))
574
0
  {
575
0
    struct servent  *port;    // Port number for service
576
0
    int     portnum;  // Port number
577
578
579
    // Lookup the service...
580
0
    if (!service)
581
0
    {
582
0
      portnum = 0;
583
0
    }
584
0
    else if (isdigit(*service & 255))
585
0
    {
586
0
      portnum = atoi(service);
587
0
    }
588
0
    else if ((port = getservbyname(service, NULL)) != NULL)
589
0
    {
590
0
      portnum = ntohs(port->s_port);
591
0
    }
592
0
    else if (!strcmp(service, "http"))
593
0
    {
594
0
      portnum = 80;
595
0
    }
596
0
    else if (!strcmp(service, "https"))
597
0
    {
598
0
      portnum = 443;
599
0
    }
600
0
    else if (!strcmp(service, "ipp") || !strcmp(service, "ipps"))
601
0
    {
602
0
      portnum = 631;
603
0
    }
604
0
    else if (!strcmp(service, "lpd"))
605
0
    {
606
0
      portnum = 515;
607
0
    }
608
0
    else if (!strcmp(service, "socket"))
609
0
    {
610
0
      portnum = 9100;
611
0
    }
612
0
    else
613
0
    {
614
0
      httpAddrFreeList(first);
615
616
0
      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unknown service name."), 1);
617
0
      return (NULL);
618
0
    }
619
620
0
    if (hostname && !_cups_strcasecmp(hostname, "localhost"))
621
0
    {
622
      // Unfortunately, some users ignore all of the warnings in the
623
      // /etc/hosts file and delete "localhost" from it. If we get here
624
      // then we were unable to resolve the name, so use the IPv6 and/or
625
      // IPv4 loopback interface addresses...
626
0
#ifdef AF_INET6
627
0
      if (family != AF_INET)
628
0
      {
629
        // Add [::1] to the address list...
630
0
  temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t));
631
0
  if (!temp)
632
0
  {
633
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
634
0
    httpAddrFreeList(first);
635
0
    return (NULL);
636
0
  }
637
638
0
        temp->addr.ipv6.sin6_family            = AF_INET6;
639
0
  temp->addr.ipv6.sin6_port              = htons(portnum);
640
#  ifdef _WIN32
641
  temp->addr.ipv6.sin6_addr.u.Byte[15]   = 1;
642
#  else
643
0
  temp->addr.ipv6.sin6_addr.s6_addr32[3] = htonl(1);
644
0
#  endif // _WIN32
645
646
0
        if (!first)
647
0
          first = temp;
648
649
0
        addr = temp;
650
0
      }
651
652
0
      if (family != AF_INET6)
653
0
#endif // AF_INET6
654
0
      {
655
        // Add 127.0.0.1 to the address list...
656
0
  temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t));
657
0
  if (!temp)
658
0
  {
659
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
660
0
    httpAddrFreeList(first);
661
0
    return (NULL);
662
0
  }
663
664
0
        temp->addr.ipv4.sin_family      = AF_INET;
665
0
  temp->addr.ipv4.sin_port        = htons(portnum);
666
0
  temp->addr.ipv4.sin_addr.s_addr = htonl(0x7f000001);
667
668
0
        if (!first)
669
0
          first = temp;
670
671
0
        if (addr)
672
0
    addr->next = temp;
673
0
      }
674
0
    }
675
0
    else if (!hostname)
676
0
    {
677
      // Provide one or more passive listening addresses...
678
0
#ifdef AF_INET6
679
0
      if (family != AF_INET)
680
0
      {
681
        // Add [::] to the address list...
682
0
  temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t));
683
0
  if (!temp)
684
0
  {
685
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
686
0
    httpAddrFreeList(first);
687
0
    return (NULL);
688
0
  }
689
690
0
        temp->addr.ipv6.sin6_family = AF_INET6;
691
0
  temp->addr.ipv6.sin6_port   = htons(portnum);
692
693
0
        if (!first)
694
0
          first = temp;
695
696
0
        addr = temp;
697
0
      }
698
699
0
      if (family != AF_INET6)
700
0
#endif // AF_INET6
701
0
      {
702
        // Add 0.0.0.0 to the address list...
703
0
  temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t));
704
0
  if (!temp)
705
0
  {
706
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
707
0
    httpAddrFreeList(first);
708
0
    return (NULL);
709
0
  }
710
711
0
        temp->addr.ipv4.sin_family = AF_INET;
712
0
  temp->addr.ipv4.sin_port   = htons(portnum);
713
714
0
        if (!first)
715
0
          first = temp;
716
717
0
        if (addr)
718
0
    addr->next = temp;
719
0
      }
720
0
    }
721
0
  }
722
723
  // Return the address list...
724
0
  return (first);
725
0
}