Coverage Report

Created: 2025-07-14 06:27

/src/libcups/cups/http-addrlist.c
Line
Count
Source (jump to first uncovered line)
1
//
2
// HTTP address list routines for CUPS.
3
//
4
// Copyright © 2021-2023 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 <fcntl.h>
20
#  include <poll.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
#  ifdef __sun
289
          // Solaris incorrectly returns errors when you poll() a socket that is
290
          // still connecting.  This check prevents us from removing the socket
291
          // from the pool if the "error" is EINPROGRESS...
292
          int   sockerr;  // Current error on socket
293
          socklen_t socklen = sizeof(sockerr);
294
          // Size of error variable
295
296
          if (!getsockopt(fds[i], SOL_SOCKET, SO_ERROR, &sockerr, &socklen) && (!sockerr || sockerr == EINPROGRESS))
297
            continue;     // Not an error
298
#  endif // __sun
299
300
          // Error on socket, remove from the "pool"...
301
0
    httpAddrClose(NULL, fds[i]);
302
0
          nfds --;
303
0
          if (i < nfds)
304
0
          {
305
0
            memmove(fds + i, fds + i + 1, (size_t)(nfds - i) * (sizeof(fds[0])));
306
0
            memmove(addrs + i, addrs + i + 1, (size_t)(nfds - i) * (sizeof(addrs[0])));
307
0
          }
308
0
          i --;
309
0
        }
310
0
      }
311
312
0
      if (connaddr)
313
0
      {
314
        // Connected on one address, close all of the other sockets we have so
315
        // far and return.
316
0
        for (j = 0; j < i; j ++)
317
0
          httpAddrClose(NULL, fds[j]);
318
319
0
        for (j ++; j < nfds; j ++)
320
0
          httpAddrClose(NULL, fds[j]);
321
322
0
        return (connaddr);
323
0
      }
324
0
    }
325
0
#endif // O_NONBLOCK
326
327
0
    if (addrlist)
328
0
      remaining -= 100;
329
0
    else
330
0
      remaining -= 250;
331
0
  }
332
333
0
  if (remaining <= 0)
334
0
    errno = ETIMEDOUT;
335
336
0
  while (nfds > 0)
337
0
  {
338
0
    nfds --;
339
0
    httpAddrClose(NULL, fds[nfds]);
340
0
  }
341
342
#ifdef _WIN32
343
  _cupsSetError(IPP_STATUS_ERROR_SERVICE_UNAVAILABLE, "Connection failed", 0);
344
#else
345
0
  _cupsSetError(IPP_STATUS_ERROR_SERVICE_UNAVAILABLE, strerror(errno), 0);
346
0
#endif // _WIN32
347
348
0
  return (NULL);
349
0
}
350
351
352
//
353
// 'httpAddrCopyList()' - Copy an address list.
354
//
355
356
http_addrlist_t *     // O - New address list or @code NULL@ on error
357
httpAddrCopyList(
358
    http_addrlist_t *src)   // I - Source address list
359
0
{
360
0
  http_addrlist_t *dst = NULL,  // First list entry
361
0
      *prev = NULL, // Previous list entry
362
0
      *current = NULL;// Current list entry
363
364
365
0
  while (src)
366
0
  {
367
0
    if ((current = malloc(sizeof(http_addrlist_t))) == NULL)
368
0
    {
369
0
      current = dst;
370
371
0
      while (current)
372
0
      {
373
0
        prev    = current;
374
0
        current = current->next;
375
376
0
        free(prev);
377
0
      }
378
379
0
      return (NULL);
380
0
    }
381
382
0
    memcpy(current, src, sizeof(http_addrlist_t));
383
384
0
    current->next = NULL;
385
386
0
    if (prev)
387
0
      prev->next = current;
388
0
    else
389
0
      dst = current;
390
391
0
    prev = current;
392
0
    src  = src->next;
393
0
  }
394
395
0
  return (dst);
396
0
}
397
398
399
//
400
// 'httpAddrFreeList()' - Free an address list.
401
//
402
403
void
404
httpAddrFreeList(
405
    http_addrlist_t *addrlist)    // I - Address list to free
406
0
{
407
0
  http_addrlist_t *next;    // Next address in list
408
409
410
  // Free each address in the list...
411
0
  while (addrlist)
412
0
  {
413
0
    next = addrlist->next;
414
415
0
    free(addrlist);
416
417
0
    addrlist = next;
418
0
  }
419
0
}
420
421
422
//
423
// 'httpAddrGetList()' - Get a list of addresses for a hostname.
424
//
425
426
http_addrlist_t *     // O - List of addresses or NULL
427
httpAddrGetList(const char *hostname, // I - Hostname, IP address, or NULL for passive listen address
428
                int        family,  // I - Address family or AF_UNSPEC
429
    const char *service)  // I - Service name or port number
430
0
{
431
0
  http_addrlist_t *first,   // First address in list
432
0
      *addr,    // Current address in list
433
0
      *temp;    // New address
434
0
  char      ipv6[64], // IPv6 address
435
0
      *ipv6zone;  // Pointer to zone separator
436
0
  int     ipv6len;  // Length of IPv6 address
437
0
  _cups_globals_t *cg = _cupsGlobals();
438
          // Global data
439
440
441
#ifdef DEBUG
442
  _cups_debug_printf("httpAddrGetList(hostname=\"%s\", family=AF_%s, "
443
                     "service=\"%s\")\n",
444
         hostname ? hostname : "(nil)",
445
         family == AF_UNSPEC ? "UNSPEC" :
446
#  ifdef AF_LOCAL
447
                   family == AF_LOCAL ? "LOCAL" :
448
#  endif // AF_LOCAL
449
#  ifdef AF_INET6
450
                   family == AF_INET6 ? "INET6" :
451
#  endif // AF_INET6
452
                   family == AF_INET ? "INET" : "???", service);
453
#endif // DEBUG
454
455
0
  httpInitialize();
456
457
0
#ifdef HAVE_RES_INIT
458
  // STR #2920: Initialize resolver after failure in cups-polld
459
  //
460
  // If the previous lookup failed, re-initialize the resolver to prevent
461
  // temporary network errors from persisting.  This *should* be handled by
462
  // the resolver libraries, but apparently the glibc folks do not agree.
463
  //
464
  // We set a flag at the end of this function if we encounter an error that
465
  // requires reinitialization of the resolver functions.  We then call
466
  // res_init() if the flag is set on the next call here or in httpAddrLookup().
467
0
  if (cg->need_res_init)
468
0
  {
469
0
    res_init();
470
471
0
    cg->need_res_init = 0;
472
0
  }
473
0
#endif // HAVE_RES_INIT
474
475
  // Lookup the address the best way we can...
476
0
  first = addr = NULL;
477
478
0
#ifdef AF_LOCAL
479
0
  if (hostname && hostname[0] == '/')
480
0
  {
481
    // Domain socket address...
482
0
    if ((first = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t))) != NULL)
483
0
    {
484
0
      addr = first;
485
0
      first->addr.un.sun_family = AF_LOCAL;
486
0
      cupsCopyString(first->addr.un.sun_path, hostname, sizeof(first->addr.un.sun_path));
487
0
    }
488
0
  }
489
0
  else
490
0
#endif // AF_LOCAL
491
0
  if (!hostname || _cups_strcasecmp(hostname, "localhost"))
492
0
  {
493
0
    struct addrinfo hints,    // Address lookup hints
494
0
      *results, // Address lookup results
495
0
      *current; // Current result
496
0
    int     error;    // getaddrinfo() error
497
498
    // Lookup the address as needed...
499
0
    memset(&hints, 0, sizeof(hints));
500
0
    hints.ai_family   = family;
501
0
    hints.ai_flags    = hostname ? 0 : AI_PASSIVE;
502
0
    hints.ai_socktype = SOCK_STREAM;
503
504
0
    if (hostname && *hostname == '[')
505
0
    {
506
      // Remove brackets from numeric IPv6 address...
507
0
      if (!strncmp(hostname, "[v1.", 4))
508
0
      {
509
        // Copy the newer address format which supports link-local addresses...
510
0
  cupsCopyString(ipv6, hostname + 4, sizeof(ipv6));
511
0
  if ((ipv6len = (int)strlen(ipv6) - 1) >= 0 && ipv6[ipv6len] == ']')
512
0
  {
513
0
          ipv6[ipv6len] = '\0';
514
0
    hostname      = ipv6;
515
516
          // Convert "+zone" in address to "%zone"...
517
0
          if ((ipv6zone = strrchr(ipv6, '+')) != NULL)
518
0
      *ipv6zone = '%';
519
0
  }
520
0
      }
521
0
      else
522
0
      {
523
        // Copy the regular non-link-local IPv6 address...
524
0
  cupsCopyString(ipv6, hostname + 1, sizeof(ipv6));
525
0
  if ((ipv6len = (int)strlen(ipv6) - 1) >= 0 && ipv6[ipv6len] == ']')
526
0
  {
527
0
          ipv6[ipv6len] = '\0';
528
0
    hostname      = ipv6;
529
0
  }
530
0
      }
531
0
    }
532
533
0
    if ((error = getaddrinfo(hostname, service, &hints, &results)) == 0)
534
0
    {
535
      // Copy the results to our own address list structure...
536
0
      for (current = results; current; current = current->ai_next)
537
0
      {
538
0
        if (current->ai_family == AF_INET || current->ai_family == AF_INET6)
539
0
  {
540
    // Copy the address over...
541
0
    temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t));
542
0
    if (!temp)
543
0
    {
544
0
      httpAddrFreeList(first);
545
0
      freeaddrinfo(results);
546
0
      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
547
0
      return (NULL);
548
0
    }
549
550
0
          if (current->ai_family == AF_INET6)
551
0
      memcpy(&(temp->addr.ipv6), current->ai_addr,
552
0
             sizeof(temp->addr.ipv6));
553
0
    else
554
0
      memcpy(&(temp->addr.ipv4), current->ai_addr,
555
0
             sizeof(temp->addr.ipv4));
556
557
          // Append the address to the list...
558
0
    if (!first)
559
0
      first = temp;
560
561
0
    if (addr)
562
0
      addr->next = temp;
563
564
0
    addr = temp;
565
0
  }
566
0
      }
567
568
      // Free the results from getaddrinfo()...
569
0
      freeaddrinfo(results);
570
0
    }
571
0
    else
572
0
    {
573
0
      if (error == EAI_FAIL)
574
0
        cg->need_res_init = 1;
575
576
#  ifdef _WIN32 // Really, Microsoft?!?
577
      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, gai_strerrorA(error), 0);
578
#  else
579
0
      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, gai_strerror(error), 0);
580
0
#  endif // _WIN32
581
0
    }
582
0
  }
583
584
  // Detect some common errors and handle them sanely...
585
0
  if (!addr && (!hostname || !_cups_strcasecmp(hostname, "localhost")))
586
0
  {
587
0
    struct servent  *port;    // Port number for service
588
0
    int     portnum;  // Port number
589
590
591
    // Lookup the service...
592
0
    if (!service)
593
0
    {
594
0
      portnum = 0;
595
0
    }
596
0
    else if (isdigit(*service & 255))
597
0
    {
598
0
      portnum = atoi(service);
599
0
    }
600
0
    else if ((port = getservbyname(service, NULL)) != NULL)
601
0
    {
602
0
      portnum = ntohs(port->s_port);
603
0
    }
604
0
    else if (!strcmp(service, "http"))
605
0
    {
606
0
      portnum = 80;
607
0
    }
608
0
    else if (!strcmp(service, "https"))
609
0
    {
610
0
      portnum = 443;
611
0
    }
612
0
    else if (!strcmp(service, "ipp") || !strcmp(service, "ipps"))
613
0
    {
614
0
      portnum = 631;
615
0
    }
616
0
    else if (!strcmp(service, "lpd"))
617
0
    {
618
0
      portnum = 515;
619
0
    }
620
0
    else if (!strcmp(service, "socket"))
621
0
    {
622
0
      portnum = 9100;
623
0
    }
624
0
    else
625
0
    {
626
0
      httpAddrFreeList(first);
627
628
0
      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unknown service name."), 1);
629
0
      return (NULL);
630
0
    }
631
632
0
    if (hostname && !_cups_strcasecmp(hostname, "localhost"))
633
0
    {
634
      // Unfortunately, some users ignore all of the warnings in the
635
      // /etc/hosts file and delete "localhost" from it. If we get here
636
      // then we were unable to resolve the name, so use the IPv6 and/or
637
      // IPv4 loopback interface addresses...
638
0
#ifdef AF_INET6
639
0
      if (family != AF_INET)
640
0
      {
641
        // Add [::1] to the address list...
642
0
  temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t));
643
0
  if (!temp)
644
0
  {
645
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
646
0
    httpAddrFreeList(first);
647
0
    return (NULL);
648
0
  }
649
650
0
        temp->addr.ipv6.sin6_family            = AF_INET6;
651
0
  temp->addr.ipv6.sin6_port              = htons(portnum);
652
#  ifdef _WIN32
653
  temp->addr.ipv6.sin6_addr.u.Byte[15]   = 1;
654
#  else
655
0
  temp->addr.ipv6.sin6_addr.s6_addr32[3] = htonl(1);
656
0
#  endif // _WIN32
657
658
0
        if (!first)
659
0
          first = temp;
660
661
0
        addr = temp;
662
0
      }
663
664
0
      if (family != AF_INET6)
665
0
#endif // AF_INET6
666
0
      {
667
        // Add 127.0.0.1 to the address list...
668
0
  temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t));
669
0
  if (!temp)
670
0
  {
671
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
672
0
    httpAddrFreeList(first);
673
0
    return (NULL);
674
0
  }
675
676
0
        temp->addr.ipv4.sin_family      = AF_INET;
677
0
  temp->addr.ipv4.sin_port        = htons(portnum);
678
0
  temp->addr.ipv4.sin_addr.s_addr = htonl(0x7f000001);
679
680
0
        if (!first)
681
0
          first = temp;
682
683
0
        if (addr)
684
0
    addr->next = temp;
685
0
      }
686
0
    }
687
0
    else if (!hostname)
688
0
    {
689
      // Provide one or more passive listening addresses...
690
0
#ifdef AF_INET6
691
0
      if (family != AF_INET)
692
0
      {
693
        // Add [::] to the address list...
694
0
  temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t));
695
0
  if (!temp)
696
0
  {
697
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
698
0
    httpAddrFreeList(first);
699
0
    return (NULL);
700
0
  }
701
702
0
        temp->addr.ipv6.sin6_family = AF_INET6;
703
0
  temp->addr.ipv6.sin6_port   = htons(portnum);
704
705
0
        if (!first)
706
0
          first = temp;
707
708
0
        addr = temp;
709
0
      }
710
711
0
      if (family != AF_INET6)
712
0
#endif // AF_INET6
713
0
      {
714
        // Add 0.0.0.0 to the address list...
715
0
  temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t));
716
0
  if (!temp)
717
0
  {
718
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
719
0
    httpAddrFreeList(first);
720
0
    return (NULL);
721
0
  }
722
723
0
        temp->addr.ipv4.sin_family = AF_INET;
724
0
  temp->addr.ipv4.sin_port   = htons(portnum);
725
726
0
        if (!first)
727
0
          first = temp;
728
729
0
        if (addr)
730
0
    addr->next = temp;
731
0
      }
732
0
    }
733
0
  }
734
735
  // Return the address list...
736
0
  return (first);
737
0
}