]> git.ipfire.org Git - thirdparty/cups.git/blame - scheduler/network.c
Rename all types and functions to use cupsd prefix.
[thirdparty/cups.git] / scheduler / network.c
CommitLineData
2123c23a 1/*
c9d3f842 2 * "$Id$"
2123c23a 3 *
4 * Network interface functions for the Common UNIX Printing System
5 * (CUPS) scheduler.
6 *
c9d3f842 7 * Copyright 1997-2005 by Easy Software Products, all rights reserved.
2123c23a 8 *
9 * These coded instructions, statements, and computer programs are the
10 * property of Easy Software Products and are protected by Federal
11 * copyright law. Distribution and use rights are outlined in the file
12 * "LICENSE" which should have been included with this file. If this
13 * file is missing or damaged please contact Easy Software Products
14 * at:
15 *
16 * Attn: CUPS Licensing Information
17 * Easy Software Products
18 * 44141 Airport View Drive, Suite 204
8650fcf2 19 * Hollywood, Maryland 20636 USA
2123c23a 20 *
edfd3c3d 21 * Voice: (301) 373-9600
2123c23a 22 * EMail: cups-info@cups.org
23 * WWW: http://www.cups.org
24 */
25
26/*
27 * Include necessary headers.
28 */
29
30#include "cupsd.h"
31
e23104b4 32#include <net/if.h>
33
2123c23a 34#ifdef HAVE_GETIFADDRS
35/*
36 * Use native getifaddrs() function...
37 */
38# include <ifaddrs.h>
39#else
40/*
41 * Use getifaddrs() emulation...
42 */
43
2123c23a 44# include <sys/ioctl.h>
45# ifdef HAVE_SYS_SOCKIO_H
46# include <sys/sockio.h>
47# endif
48
49# ifdef ifa_dstaddr
50# undef ifa_dstaddr
51# endif /* ifa_dstaddr */
52# ifndef ifr_netmask
53# define ifr_netmask ifr_addr
54# endif /* !ifr_netmask */
55
56struct ifaddrs /**** Interface Structure ****/
57{
58 struct ifaddrs *ifa_next; /* Next interface in list */
59 char *ifa_name; /* Name of interface */
60 unsigned int ifa_flags; /* Flags (up, point-to-point, etc.) */
61 struct sockaddr *ifa_addr, /* Network address */
62 *ifa_netmask, /* Address mask */
63 *ifa_dstaddr; /* Broadcast or destination address */
64 void *ifa_data; /* Interface statistics */
65};
66
67int getifaddrs(struct ifaddrs **addrs);
68void freeifaddrs(struct ifaddrs *addrs);
69#endif /* HAVE_GETIFADDRS */
70
71
72/*
73 * 'NetIFFind()' - Find a network interface.
74 */
75
589eb420 76cupsd_netif_t * /* O - Network interface data */
2123c23a 77NetIFFind(const char *name) /* I - Name of interface */
78{
589eb420 79 cupsd_netif_t *temp; /* Current network interface */
2123c23a 80
81
82 /*
83 * Update the interface list as needed...
84 */
85
589eb420 86 cupsdNetIFUpdate();
2123c23a 87
88 /*
89 * Search for the named interface...
90 */
91
92 for (temp = NetIFList; temp != NULL; temp = temp->next)
93 if (strcasecmp(name, temp->name) == 0)
94 return (temp);
95
96 return (NULL);
97}
98
99
100/*
589eb420 101 * 'cupsdNetIFFree()' - Free the current network interface list.
2123c23a 102 */
103
104void
589eb420 105cupsdNetIFFree(void)
2123c23a 106{
589eb420 107 cupsd_netif_t *next; /* Next interface in list */
2123c23a 108
109
110 /*
111 * Loop through the interface list and free all the records...
112 */
113
114 while (NetIFList != NULL)
115 {
116 next = NetIFList->next;
117
118 free(NetIFList);
119
120 NetIFList = next;
121 }
122}
123
124
125/*
589eb420 126 * 'cupsdNetIFUpdate()' - Update the network interface list as needed...
2123c23a 127 */
128
129void
589eb420 130cupsdNetIFUpdate(void)
2123c23a 131{
edd6ee99 132 int i, /* Looping var */
133 match; /* Matching address? */
589eb420 134 cupsd_listener_t *lis; /* Listen address */
135 cupsd_netif_t *temp; /* Current interface */
2123c23a 136 struct ifaddrs *addrs, /* Interface address list */
137 *addr; /* Current interface address */
138
139
140 /*
141 * Update the network interface list no more often than once a
142 * minute...
143 */
144
145 if ((time(NULL) - NetIFTime) < 60)
146 return;
147
5fe35f41 148 NetIFTime = time(NULL);
149
2123c23a 150 /*
151 * Free the old interfaces...
152 */
153
589eb420 154 cupsdNetIFFree();
2123c23a 155
156 /*
157 * Grab a new list of interfaces...
158 */
159
160 if (getifaddrs(&addrs) < 0)
161 return;
162
163 for (addr = addrs; addr != NULL; addr = addr->ifa_next)
164 {
165 /*
20264b99 166 * See if this interface address is IPv4 or IPv6...
2123c23a 167 */
168
20264b99 169 if (addr->ifa_addr == NULL ||
a09840c5 170 (addr->ifa_addr->sa_family != AF_INET
171#ifdef AF_INET6
172 && addr->ifa_addr->sa_family != AF_INET6
173#endif
174 ) ||
2123c23a 175 addr->ifa_netmask == NULL || addr->ifa_name == NULL)
176 continue;
177
178 /*
20264b99 179 * OK, we have an IPv4/6 address, so create a new list node...
2123c23a 180 */
181
589eb420 182 if ((temp = calloc(1, sizeof(cupsd_netif_t))) == NULL)
2123c23a 183 break;
184
185 temp->next = NetIFList;
186 NetIFList = temp;
187
188 /*
189 * Then copy all of the information...
190 */
191
def978d5 192 strlcpy(temp->name, addr->ifa_name, sizeof(temp->name));
2123c23a 193
20264b99 194 if (addr->ifa_addr->sa_family == AF_INET)
195 {
196 /*
197 * Copy IPv4 addresses...
198 */
199
200 memcpy(&(temp->address), addr->ifa_addr, sizeof(struct sockaddr_in));
201 memcpy(&(temp->mask), addr->ifa_netmask, sizeof(struct sockaddr_in));
202
203 if (addr->ifa_dstaddr)
204 memcpy(&(temp->broadcast), addr->ifa_dstaddr, sizeof(struct sockaddr_in));
205 }
a09840c5 206#ifdef AF_INET6
20264b99 207 else
208 {
209 /*
210 * Copy IPv6 addresses...
211 */
212
213 memcpy(&(temp->address), addr->ifa_addr, sizeof(struct sockaddr_in6));
214 memcpy(&(temp->mask), addr->ifa_netmask, sizeof(struct sockaddr_in6));
215
216 if (addr->ifa_dstaddr)
217 memcpy(&(temp->broadcast), addr->ifa_dstaddr, sizeof(struct sockaddr_in6));
218 }
a09840c5 219#endif /* AF_INET6 */
2123c23a 220
d7a9de63 221 if (!(addr->ifa_flags & IFF_POINTOPOINT) &&
222 !httpAddrLocalhost(&(temp->address)))
2123c23a 223 temp->is_local = 1;
224
edd6ee99 225 /*
226 * Determine which port to use when advertising printers...
227 */
228
229 for (i = NumListeners, lis = Listeners; i > 0; i --, lis ++)
230 {
231 match = 0;
232
233 if (httpAddrAny(&(lis->address)))
234 match = 1;
235 else if (addr->ifa_addr->sa_family == AF_INET &&
236 lis->address.addr.sa_family == AF_INET &&
237 (lis->address.ipv4.sin_addr.s_addr &
238 temp->mask.ipv4.sin_addr.s_addr) ==
239 temp->address.ipv4.sin_addr.s_addr)
240 match = 1;
241#ifdef AF_INET6
242 else if (addr->ifa_addr->sa_family == AF_INET6 &&
243 lis->address.addr.sa_family == AF_INET6 &&
244 (lis->address.ipv6.sin6_addr.s6_addr[0] &
245 temp->mask.ipv6.sin6_addr.s6_addr[0]) ==
246 temp->address.ipv6.sin6_addr.s6_addr[0] &&
247 (lis->address.ipv6.sin6_addr.s6_addr[1] &
248 temp->mask.ipv6.sin6_addr.s6_addr[1]) ==
249 temp->address.ipv6.sin6_addr.s6_addr[1] &&
250 (lis->address.ipv6.sin6_addr.s6_addr[2] &
251 temp->mask.ipv6.sin6_addr.s6_addr[2]) ==
252 temp->address.ipv6.sin6_addr.s6_addr[2] &&
253 (lis->address.ipv6.sin6_addr.s6_addr[3] &
254 temp->mask.ipv6.sin6_addr.s6_addr[3]) ==
255 temp->address.ipv6.sin6_addr.s6_addr[3])
256 match = 1;
257#endif /* AF_INET6 */
258
259 if (match)
260 {
261 if (lis->address.addr.sa_family == AF_INET)
262 temp->port = ntohs(lis->address.ipv4.sin_port);
263#ifdef AF_INET6
264 else if (lis->address.addr.sa_family == AF_INET6)
265 temp->port = ntohs(lis->address.ipv6.sin6_port);
266#endif /* AF_INET6 */
267 break;
268 }
269 }
270
2123c23a 271 /*
272 * Finally, try looking up the hostname for the address as needed...
273 */
274
275 if (HostNameLookups)
d7a9de63 276 httpAddrLookup(&(temp->address), temp->hostname, sizeof(temp->hostname));
2123c23a 277 else
a7811b07 278 {
279 /*
280 * Map the default server address and localhost to the server name
281 * and localhost, respectively; for all other addresses, use the
282 * dotted notation...
283 */
284
285 if (httpAddrLocalhost(&(temp->address)))
286 strcpy(temp->hostname, "localhost");
287 else if (httpAddrEqual(&(temp->address), &ServerAddr))
def978d5 288 strlcpy(temp->hostname, ServerName, sizeof(temp->hostname));
a7811b07 289 else
def978d5 290 httpAddrString(&(temp->address), temp->hostname,
291 sizeof(temp->hostname));
a7811b07 292 }
2123c23a 293 }
294
295 freeifaddrs(addrs);
296}
297
298
299#ifndef HAVE_GETIFADDRS
300/*
301 * 'getifaddrs()' - Get a list of network interfaces on the system.
302 */
303
304int /* O - 0 on success, -1 on error */
305getifaddrs(struct ifaddrs **addrs) /* O - List of interfaces */
306{
307 int sock; /* Socket */
308 char buffer[65536], /* Buffer for address info */
309 *bufptr, /* Pointer into buffer */
310 *bufend; /* End of buffer */
311 struct ifconf conf; /* Interface configurations */
312 struct sockaddr addr; /* Address data */
313 struct ifreq *ifp; /* Interface data */
314 int ifpsize; /* Size of interface data */
315 struct ifaddrs *temp; /* Pointer to current interface */
316 struct ifreq request; /* Interface request */
317
318
319 /*
320 * Start with an empty list...
321 */
322
323 if (addrs == NULL)
324 return (-1);
325
326 *addrs = NULL;
327
328 /*
329 * Create a UDP socket to get the interface data...
330 */
331
332 memset (&addr, 0, sizeof(addr));
333 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
334 return (-1);
335
336 /*
337 * Try to get the list of interfaces...
338 */
339
340 conf.ifc_len = sizeof(buffer);
341 conf.ifc_buf = buffer;
342
343 if (ioctl(sock, SIOCGIFCONF, &conf) < 0)
344 {
345 /*
346 * Couldn't get the list of interfaces...
347 */
348
349 close(sock);
350 return (-1);
351 }
352
353 /*
354 * OK, got the list of interfaces, now lets step through the
355 * buffer to pull them out...
356 */
357
358# ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
359# define sockaddr_len(a) ((a)->sa_len)
360# else
361# define sockaddr_len(a) (sizeof(struct sockaddr))
362# endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
363
364 for (bufptr = buffer, bufend = buffer + conf.ifc_len;
365 bufptr < bufend;
366 bufptr += ifpsize)
367 {
368 /*
369 * Get the current interface information...
370 */
371
372 ifp = (struct ifreq *)bufptr;
373 ifpsize = sizeof(ifp->ifr_name) + sockaddr_len(&(ifp->ifr_addr));
374
375 if (ifpsize < sizeof(struct ifreq))
376 ifpsize = sizeof(struct ifreq);
377
378 memset(&request, 0, sizeof(request));
379 memcpy(request.ifr_name, ifp->ifr_name, sizeof(ifp->ifr_name));
380
381 /*
382 * Check the status of the interface...
383 */
384
385 if (ioctl(sock, SIOCGIFFLAGS, &request) < 0)
386 continue;
387
388 /*
389 * Allocate memory for a single interface record...
390 */
391
392 if ((temp = calloc(1, sizeof(struct ifaddrs))) == NULL)
393 {
394 /*
395 * Unable to allocate memory...
396 */
397
398 close(sock);
399 return (-1);
400 }
401
402 /*
403 * Add this record to the front of the list and copy the name, flags,
404 * and network address...
405 */
406
407 temp->ifa_next = *addrs;
408 *addrs = temp;
409 temp->ifa_name = strdup(ifp->ifr_name);
410 temp->ifa_flags = request.ifr_flags;
411 if ((temp->ifa_addr = calloc(1, sockaddr_len(&(ifp->ifr_addr)))) != NULL)
412 memcpy(temp->ifa_addr, &(ifp->ifr_addr), sockaddr_len(&(ifp->ifr_addr)));
413
414 /*
415 * Try to get the netmask for the interface...
416 */
417
418 if (!ioctl(sock, SIOCGIFNETMASK, &request))
419 {
420 /*
421 * Got it, make a copy...
422 */
423
424 if ((temp->ifa_netmask = calloc(1, sizeof(request.ifr_netmask))) != NULL)
425 memcpy(temp->ifa_netmask, &(request.ifr_netmask),
426 sizeof(request.ifr_netmask));
427 }
428
429 /*
430 * Then get the broadcast or point-to-point (destination) address,
431 * if applicable...
432 */
433
434 if (temp->ifa_flags & IFF_BROADCAST)
435 {
436 /*
437 * Have a broadcast address, so get it!
438 */
439
440 if (!ioctl(sock, SIOCGIFBRDADDR, &request))
441 {
442 /*
443 * Got it, make a copy...
444 */
445
446 if ((temp->ifa_dstaddr = calloc(1, sizeof(request.ifr_broadaddr))) != NULL)
447 memcpy(temp->ifa_dstaddr, &(request.ifr_broadaddr),
448 sizeof(request.ifr_broadaddr));
449 }
450 }
451 else if (temp->ifa_flags & IFF_POINTOPOINT)
452 {
453 /*
454 * Point-to-point interface; grab the remote address...
455 */
456
457 if (!ioctl(sock, SIOCGIFDSTADDR, &request))
458 {
459 temp->ifa_dstaddr = malloc(sizeof(request.ifr_dstaddr));
460 memcpy(temp->ifa_dstaddr, &(request.ifr_dstaddr),
461 sizeof(request.ifr_dstaddr));
462 }
463 }
464 }
465
466 /*
467 * OK, we're done with the socket, close it and return 0...
468 */
469
470 close(sock);
471
472 return (0);
473}
474
475
476/*
477 * 'freeifaddrs()' - Free an interface list...
478 */
479
480void
481freeifaddrs(struct ifaddrs *addrs) /* I - Interface list to free */
482{
483 struct ifaddrs *next; /* Next interface in list */
484
485
486 while (addrs != NULL)
487 {
488 /*
489 * Make a copy of the next interface pointer...
490 */
491
492 next = addrs->ifa_next;
493
494 /*
495 * Free data values as needed...
496 */
497
498 if (addrs->ifa_name)
499 {
500 free(addrs->ifa_name);
501 addrs->ifa_name = NULL;
502 }
503
504 if (addrs->ifa_addr)
505 {
506 free(addrs->ifa_addr);
507 addrs->ifa_addr = NULL;
508 }
509
510 if (addrs->ifa_netmask)
511 {
512 free(addrs->ifa_netmask);
513 addrs->ifa_netmask = NULL;
514 }
515
516 if (addrs->ifa_dstaddr)
517 {
518 free(addrs->ifa_dstaddr);
519 addrs->ifa_dstaddr = NULL;
520 }
521
522 /*
523 * Free this node and continue to the next...
524 */
525
526 free(addrs);
527
528 addrs = next;
529 }
530}
531
532#endif /* !HAVE_GETIFADDRS */
533
534
535/*
c9d3f842 536 * End of "$Id$".
2123c23a 537 */