Coverage Report

Created: 2025-11-16 06:16

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