]>
git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/network.c
2 * "$Id: network.c 5069 2006-02-04 05:24:35Z mike $"
4 * Network interface functions for the Common UNIX Printing System
7 * Copyright 1997-2006 by Easy Software Products, all rights reserved.
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
16 * Attn: CUPS Licensing Information
17 * Easy Software Products
18 * 44141 Airport View Drive, Suite 204
19 * Hollywood, Maryland 20636 USA
21 * Voice: (301) 373-9600
22 * EMail: cups-info@cups.org
23 * WWW: http://www.cups.org
27 * cupsdNetIFFind() - Find a network interface.
28 * cupsdNetIFFree() - Free the current network interface list.
29 * cupsdNetIFUpdate() - Update the network interface list as needed...
30 * compare_netif() - Compare two network interfaces.
31 * getifaddrs() - Get a list of network interfaces on the system.
32 * freeifaddrs() - Free an interface list...
36 * Include necessary headers.
48 static void cupsdNetIFFree(void);
49 static int compare_netif(cupsd_netif_t
*a
, cupsd_netif_t
*b
);
52 #ifdef HAVE_GETIFADDRS
54 * Use native getifaddrs() function...
59 * Use getifaddrs() emulation...
62 # include <sys/ioctl.h>
63 # ifdef HAVE_SYS_SOCKIO_H
64 # include <sys/sockio.h>
69 # endif /* ifa_dstaddr */
71 # define ifr_netmask ifr_addr
72 # endif /* !ifr_netmask */
74 struct ifaddrs
/**** Interface Structure ****/
76 struct ifaddrs
*ifa_next
; /* Next interface in list */
77 char *ifa_name
; /* Name of interface */
78 unsigned int ifa_flags
; /* Flags (up, point-to-point, etc.) */
79 struct sockaddr
*ifa_addr
, /* Network address */
80 *ifa_netmask
, /* Address mask */
81 *ifa_dstaddr
; /* Broadcast or destination address */
82 void *ifa_data
; /* Interface statistics */
85 static int getifaddrs(struct ifaddrs
**addrs
);
86 static void freeifaddrs(struct ifaddrs
*addrs
);
87 #endif /* HAVE_GETIFADDRS */
91 * 'cupsdNetIFFind()' - Find a network interface.
94 cupsd_netif_t
* /* O - Network interface data */
95 cupsdNetIFFind(const char *name
) /* I - Name of interface */
97 cupsd_netif_t key
; /* Search key */
101 * Update the interface list as needed...
107 * Search for the named interface...
110 strlcpy(key
.name
, name
, sizeof(key
.name
));
112 return ((cupsd_netif_t
*)cupsArrayFind(NetIFList
, &key
));
117 * 'cupsdNetIFFree()' - Free the current network interface list.
123 cupsd_netif_t
*current
; /* Current interface in array */
127 * Loop through the interface list and free all the records...
130 for (current
= (cupsd_netif_t
*)cupsArrayFirst(NetIFList
);
132 current
= (cupsd_netif_t
*)cupsArrayNext(NetIFList
))
134 cupsArrayRemove(NetIFList
, current
);
141 * 'cupsdNetIFUpdate()' - Update the network interface list as needed...
145 cupsdNetIFUpdate(void)
147 int match
; /* Matching address? */
148 cupsd_listener_t
*lis
; /* Listen address */
149 cupsd_netif_t
*temp
; /* New interface */
150 struct ifaddrs
*addrs
, /* Interface address list */
151 *addr
; /* Current interface address */
152 http_addrlist_t
*saddr
; /* Current server address */
153 char hostname
[1024]; /* Hostname for address */
157 * Update the network interface list no more often than once a
161 if ((time(NULL
) - NetIFTime
) < 60)
164 NetIFTime
= time(NULL
);
167 * Free the old interfaces...
173 * Make sure we have an array...
177 NetIFList
= cupsArrayNew((cups_array_func_t
)compare_netif
, NULL
);
183 * Grab a new list of interfaces...
186 if (getifaddrs(&addrs
) < 0)
189 for (addr
= addrs
; addr
!= NULL
; addr
= addr
->ifa_next
)
192 * See if this interface address is IPv4 or IPv6...
195 if (addr
->ifa_addr
== NULL
||
196 (addr
->ifa_addr
->sa_family
!= AF_INET
198 && addr
->ifa_addr
->sa_family
!= AF_INET6
201 addr
->ifa_netmask
== NULL
|| addr
->ifa_name
== NULL
)
205 * Try looking up the hostname for the address as needed...
209 httpAddrLookup((http_addr_t
*)(addr
->ifa_addr
), hostname
,
214 * Map the default server address and localhost to the server name
215 * and localhost, respectively; for all other addresses, use the
219 if (httpAddrLocalhost((http_addr_t
*)(addr
->ifa_addr
)))
220 strcpy(hostname
, "localhost");
223 for (saddr
= ServerAddrs
; saddr
; saddr
= saddr
->next
)
224 if (httpAddrEqual((http_addr_t
*)(addr
->ifa_addr
), &(saddr
->addr
)))
228 strlcpy(hostname
, ServerName
, sizeof(hostname
));
230 httpAddrString((http_addr_t
*)(addr
->ifa_addr
), hostname
,
236 * Create a new address element...
239 if ((temp
= calloc(1, sizeof(cupsd_netif_t
) +
240 strlen(hostname
))) == NULL
)
244 * Copy all of the information...
247 strlcpy(temp
->name
, addr
->ifa_name
, sizeof(temp
->name
));
248 strcpy(temp
->hostname
, hostname
); /* Safe because hostname is allocated */
250 if (addr
->ifa_addr
->sa_family
== AF_INET
)
253 * Copy IPv4 addresses...
256 memcpy(&(temp
->address
), addr
->ifa_addr
, sizeof(struct sockaddr_in
));
257 memcpy(&(temp
->mask
), addr
->ifa_netmask
, sizeof(struct sockaddr_in
));
259 if (addr
->ifa_dstaddr
)
260 memcpy(&(temp
->broadcast
), addr
->ifa_dstaddr
,
261 sizeof(struct sockaddr_in
));
267 * Copy IPv6 addresses...
270 memcpy(&(temp
->address
), addr
->ifa_addr
, sizeof(struct sockaddr_in6
));
271 memcpy(&(temp
->mask
), addr
->ifa_netmask
, sizeof(struct sockaddr_in6
));
273 if (addr
->ifa_dstaddr
)
274 memcpy(&(temp
->broadcast
), addr
->ifa_dstaddr
,
275 sizeof(struct sockaddr_in6
));
277 #endif /* AF_INET6 */
279 if (!(addr
->ifa_flags
& IFF_POINTOPOINT
) &&
280 !httpAddrLocalhost(&(temp
->address
)))
284 * Determine which port to use when advertising printers...
287 for (lis
= (cupsd_listener_t
*)cupsArrayFirst(Listeners
);
289 lis
= (cupsd_listener_t
*)cupsArrayNext(Listeners
))
293 if (httpAddrAny(&(lis
->address
)))
295 else if (addr
->ifa_addr
->sa_family
== AF_INET
&&
296 lis
->address
.addr
.sa_family
== AF_INET
&&
297 (lis
->address
.ipv4
.sin_addr
.s_addr
&
298 temp
->mask
.ipv4
.sin_addr
.s_addr
) ==
299 temp
->address
.ipv4
.sin_addr
.s_addr
)
302 else if (addr
->ifa_addr
->sa_family
== AF_INET6
&&
303 lis
->address
.addr
.sa_family
== AF_INET6
&&
304 (lis
->address
.ipv6
.sin6_addr
.s6_addr
[0] &
305 temp
->mask
.ipv6
.sin6_addr
.s6_addr
[0]) ==
306 temp
->address
.ipv6
.sin6_addr
.s6_addr
[0] &&
307 (lis
->address
.ipv6
.sin6_addr
.s6_addr
[1] &
308 temp
->mask
.ipv6
.sin6_addr
.s6_addr
[1]) ==
309 temp
->address
.ipv6
.sin6_addr
.s6_addr
[1] &&
310 (lis
->address
.ipv6
.sin6_addr
.s6_addr
[2] &
311 temp
->mask
.ipv6
.sin6_addr
.s6_addr
[2]) ==
312 temp
->address
.ipv6
.sin6_addr
.s6_addr
[2] &&
313 (lis
->address
.ipv6
.sin6_addr
.s6_addr
[3] &
314 temp
->mask
.ipv6
.sin6_addr
.s6_addr
[3]) ==
315 temp
->address
.ipv6
.sin6_addr
.s6_addr
[3])
317 #endif /* AF_INET6 */
321 if (lis
->address
.addr
.sa_family
== AF_INET
)
322 temp
->port
= ntohs(lis
->address
.ipv4
.sin_port
);
324 else if (lis
->address
.addr
.sa_family
== AF_INET6
)
325 temp
->port
= ntohs(lis
->address
.ipv6
.sin6_port
);
326 #endif /* AF_INET6 */
332 * Add it to the array...
335 cupsArrayAdd(NetIFList
, temp
);
337 cupsdLogMessage(CUPSD_LOG_DEBUG
, "cupsdNetIFUpdate: \"%s\" = %s...",
338 temp
->name
, temp
->hostname
);
346 * 'compare_netif()' - Compare two network interfaces.
349 static int /* O - Result of comparison */
350 compare_netif(cupsd_netif_t
*a
, /* I - First network interface */
351 cupsd_netif_t
*b
) /* I - Second network interface */
353 return (strcmp(a
->name
, b
->name
));
357 #ifndef HAVE_GETIFADDRS
359 * 'getifaddrs()' - Get a list of network interfaces on the system.
362 static int /* O - 0 on success, -1 on error */
363 getifaddrs(struct ifaddrs
**addrs
) /* O - List of interfaces */
365 int sock
; /* Socket */
366 char buffer
[65536], /* Buffer for address info */
367 *bufptr
, /* Pointer into buffer */
368 *bufend
; /* End of buffer */
369 struct ifconf conf
; /* Interface configurations */
370 struct sockaddr addr
; /* Address data */
371 struct ifreq
*ifp
; /* Interface data */
372 int ifpsize
; /* Size of interface data */
373 struct ifaddrs
*temp
; /* Pointer to current interface */
374 struct ifreq request
; /* Interface request */
378 * Start with an empty list...
387 * Create a UDP socket to get the interface data...
390 memset (&addr
, 0, sizeof(addr
));
391 if ((sock
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0)
395 * Try to get the list of interfaces...
398 conf
.ifc_len
= sizeof(buffer
);
399 conf
.ifc_buf
= buffer
;
401 if (ioctl(sock
, SIOCGIFCONF
, &conf
) < 0)
404 * Couldn't get the list of interfaces...
412 * OK, got the list of interfaces, now lets step through the
413 * buffer to pull them out...
416 # ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
417 # define sockaddr_len(a) ((a)->sa_len)
419 # define sockaddr_len(a) (sizeof(struct sockaddr))
420 # endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
422 for (bufptr
= buffer
, bufend
= buffer
+ conf
.ifc_len
;
427 * Get the current interface information...
430 ifp
= (struct ifreq
*)bufptr
;
431 ifpsize
= sizeof(ifp
->ifr_name
) + sockaddr_len(&(ifp
->ifr_addr
));
433 if (ifpsize
< sizeof(struct ifreq
))
434 ifpsize
= sizeof(struct ifreq
);
436 memset(&request
, 0, sizeof(request
));
437 memcpy(request
.ifr_name
, ifp
->ifr_name
, sizeof(ifp
->ifr_name
));
440 * Check the status of the interface...
443 if (ioctl(sock
, SIOCGIFFLAGS
, &request
) < 0)
447 * Allocate memory for a single interface record...
450 if ((temp
= calloc(1, sizeof(struct ifaddrs
))) == NULL
)
453 * Unable to allocate memory...
461 * Add this record to the front of the list and copy the name, flags,
462 * and network address...
465 temp
->ifa_next
= *addrs
;
467 temp
->ifa_name
= strdup(ifp
->ifr_name
);
468 temp
->ifa_flags
= request
.ifr_flags
;
469 if ((temp
->ifa_addr
= calloc(1, sockaddr_len(&(ifp
->ifr_addr
)))) != NULL
)
470 memcpy(temp
->ifa_addr
, &(ifp
->ifr_addr
), sockaddr_len(&(ifp
->ifr_addr
)));
473 * Try to get the netmask for the interface...
476 if (!ioctl(sock
, SIOCGIFNETMASK
, &request
))
479 * Got it, make a copy...
482 if ((temp
->ifa_netmask
= calloc(1, sizeof(request
.ifr_netmask
))) != NULL
)
483 memcpy(temp
->ifa_netmask
, &(request
.ifr_netmask
),
484 sizeof(request
.ifr_netmask
));
488 * Then get the broadcast or point-to-point (destination) address,
492 if (temp
->ifa_flags
& IFF_BROADCAST
)
495 * Have a broadcast address, so get it!
498 if (!ioctl(sock
, SIOCGIFBRDADDR
, &request
))
501 * Got it, make a copy...
504 if ((temp
->ifa_dstaddr
= calloc(1, sizeof(request
.ifr_broadaddr
))) != NULL
)
505 memcpy(temp
->ifa_dstaddr
, &(request
.ifr_broadaddr
),
506 sizeof(request
.ifr_broadaddr
));
509 else if (temp
->ifa_flags
& IFF_POINTOPOINT
)
512 * Point-to-point interface; grab the remote address...
515 if (!ioctl(sock
, SIOCGIFDSTADDR
, &request
))
517 temp
->ifa_dstaddr
= malloc(sizeof(request
.ifr_dstaddr
));
518 memcpy(temp
->ifa_dstaddr
, &(request
.ifr_dstaddr
),
519 sizeof(request
.ifr_dstaddr
));
525 * OK, we're done with the socket, close it and return 0...
535 * 'freeifaddrs()' - Free an interface list...
539 freeifaddrs(struct ifaddrs
*addrs
) /* I - Interface list to free */
541 struct ifaddrs
*next
; /* Next interface in list */
544 while (addrs
!= NULL
)
547 * Make a copy of the next interface pointer...
550 next
= addrs
->ifa_next
;
553 * Free data values as needed...
558 free(addrs
->ifa_name
);
559 addrs
->ifa_name
= NULL
;
564 free(addrs
->ifa_addr
);
565 addrs
->ifa_addr
= NULL
;
568 if (addrs
->ifa_netmask
)
570 free(addrs
->ifa_netmask
);
571 addrs
->ifa_netmask
= NULL
;
574 if (addrs
->ifa_dstaddr
)
576 free(addrs
->ifa_dstaddr
);
577 addrs
->ifa_dstaddr
= NULL
;
581 * Free this node and continue to the next...
589 #endif /* !HAVE_GETIFADDRS */
593 * End of "$Id: network.c 5069 2006-02-04 05:24:35Z mike $".