]>
git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/network.c
2 * "$Id: network.c 5043 2006-02-01 18:55:16Z 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 i
, /* Looping var */
148 match
; /* Matching address? */
149 cupsd_listener_t
*lis
; /* Listen address */
150 cupsd_netif_t
*temp
; /* New interface */
151 struct ifaddrs
*addrs
, /* Interface address list */
152 *addr
; /* Current interface address */
153 http_addrlist_t
*saddr
; /* Current server address */
154 char hostname
[1024]; /* Hostname for address */
158 * Update the network interface list no more often than once a
162 if ((time(NULL
) - NetIFTime
) < 60)
165 NetIFTime
= time(NULL
);
168 * Free the old interfaces...
174 * Make sure we have an array...
178 NetIFList
= cupsArrayNew((cups_array_func_t
)compare_netif
, NULL
);
184 * Grab a new list of interfaces...
187 if (getifaddrs(&addrs
) < 0)
190 for (addr
= addrs
; addr
!= NULL
; addr
= addr
->ifa_next
)
193 * See if this interface address is IPv4 or IPv6...
196 if (addr
->ifa_addr
== NULL
||
197 (addr
->ifa_addr
->sa_family
!= AF_INET
199 && addr
->ifa_addr
->sa_family
!= AF_INET6
202 addr
->ifa_netmask
== NULL
|| addr
->ifa_name
== NULL
)
206 * Try looking up the hostname for the address as needed...
210 httpAddrLookup((http_addr_t
*)(addr
->ifa_addr
), hostname
,
215 * Map the default server address and localhost to the server name
216 * and localhost, respectively; for all other addresses, use the
220 if (httpAddrLocalhost((http_addr_t
*)(addr
->ifa_addr
)))
221 strcpy(hostname
, "localhost");
224 for (saddr
= ServerAddrs
; saddr
; saddr
= saddr
->next
)
225 if (httpAddrEqual((http_addr_t
*)(addr
->ifa_addr
), &(saddr
->addr
)))
229 strlcpy(hostname
, ServerName
, sizeof(hostname
));
231 httpAddrString((http_addr_t
*)(addr
->ifa_addr
), hostname
,
237 * Create a new address element...
240 if ((temp
= calloc(1, sizeof(cupsd_netif_t
) +
241 strlen(hostname
))) == NULL
)
245 * Copy all of the information...
248 strlcpy(temp
->name
, addr
->ifa_name
, sizeof(temp
->name
));
249 strcpy(temp
->hostname
, hostname
); /* Safe because hostname is allocated */
251 if (addr
->ifa_addr
->sa_family
== AF_INET
)
254 * Copy IPv4 addresses...
257 memcpy(&(temp
->address
), addr
->ifa_addr
, sizeof(struct sockaddr_in
));
258 memcpy(&(temp
->mask
), addr
->ifa_netmask
, sizeof(struct sockaddr_in
));
260 if (addr
->ifa_dstaddr
)
261 memcpy(&(temp
->broadcast
), addr
->ifa_dstaddr
,
262 sizeof(struct sockaddr_in
));
268 * Copy IPv6 addresses...
271 memcpy(&(temp
->address
), addr
->ifa_addr
, sizeof(struct sockaddr_in6
));
272 memcpy(&(temp
->mask
), addr
->ifa_netmask
, sizeof(struct sockaddr_in6
));
274 if (addr
->ifa_dstaddr
)
275 memcpy(&(temp
->broadcast
), addr
->ifa_dstaddr
,
276 sizeof(struct sockaddr_in6
));
278 #endif /* AF_INET6 */
280 if (!(addr
->ifa_flags
& IFF_POINTOPOINT
) &&
281 !httpAddrLocalhost(&(temp
->address
)))
285 * Determine which port to use when advertising printers...
288 for (i
= NumListeners
, lis
= Listeners
; i
> 0; i
--, lis
++)
292 if (httpAddrAny(&(lis
->address
)))
294 else if (addr
->ifa_addr
->sa_family
== AF_INET
&&
295 lis
->address
.addr
.sa_family
== AF_INET
&&
296 (lis
->address
.ipv4
.sin_addr
.s_addr
&
297 temp
->mask
.ipv4
.sin_addr
.s_addr
) ==
298 temp
->address
.ipv4
.sin_addr
.s_addr
)
301 else if (addr
->ifa_addr
->sa_family
== AF_INET6
&&
302 lis
->address
.addr
.sa_family
== AF_INET6
&&
303 (lis
->address
.ipv6
.sin6_addr
.s6_addr
[0] &
304 temp
->mask
.ipv6
.sin6_addr
.s6_addr
[0]) ==
305 temp
->address
.ipv6
.sin6_addr
.s6_addr
[0] &&
306 (lis
->address
.ipv6
.sin6_addr
.s6_addr
[1] &
307 temp
->mask
.ipv6
.sin6_addr
.s6_addr
[1]) ==
308 temp
->address
.ipv6
.sin6_addr
.s6_addr
[1] &&
309 (lis
->address
.ipv6
.sin6_addr
.s6_addr
[2] &
310 temp
->mask
.ipv6
.sin6_addr
.s6_addr
[2]) ==
311 temp
->address
.ipv6
.sin6_addr
.s6_addr
[2] &&
312 (lis
->address
.ipv6
.sin6_addr
.s6_addr
[3] &
313 temp
->mask
.ipv6
.sin6_addr
.s6_addr
[3]) ==
314 temp
->address
.ipv6
.sin6_addr
.s6_addr
[3])
316 #endif /* AF_INET6 */
320 if (lis
->address
.addr
.sa_family
== AF_INET
)
321 temp
->port
= ntohs(lis
->address
.ipv4
.sin_port
);
323 else if (lis
->address
.addr
.sa_family
== AF_INET6
)
324 temp
->port
= ntohs(lis
->address
.ipv6
.sin6_port
);
325 #endif /* AF_INET6 */
331 * Add it to the array...
334 cupsArrayAdd(NetIFList
, temp
);
336 cupsdLogMessage(CUPSD_LOG_DEBUG
, "cupsdNetIFUpdate: \"%s\" = %s...",
337 temp
->name
, temp
->hostname
);
345 * 'compare_netif()' - Compare two network interfaces.
348 static int /* O - Result of comparison */
349 compare_netif(cupsd_netif_t
*a
, /* I - First network interface */
350 cupsd_netif_t
*b
) /* I - Second network interface */
352 return (strcmp(a
->name
, b
->name
));
356 #ifndef HAVE_GETIFADDRS
358 * 'getifaddrs()' - Get a list of network interfaces on the system.
361 static int /* O - 0 on success, -1 on error */
362 getifaddrs(struct ifaddrs
**addrs
) /* O - List of interfaces */
364 int sock
; /* Socket */
365 char buffer
[65536], /* Buffer for address info */
366 *bufptr
, /* Pointer into buffer */
367 *bufend
; /* End of buffer */
368 struct ifconf conf
; /* Interface configurations */
369 struct sockaddr addr
; /* Address data */
370 struct ifreq
*ifp
; /* Interface data */
371 int ifpsize
; /* Size of interface data */
372 struct ifaddrs
*temp
; /* Pointer to current interface */
373 struct ifreq request
; /* Interface request */
377 * Start with an empty list...
386 * Create a UDP socket to get the interface data...
389 memset (&addr
, 0, sizeof(addr
));
390 if ((sock
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0)
394 * Try to get the list of interfaces...
397 conf
.ifc_len
= sizeof(buffer
);
398 conf
.ifc_buf
= buffer
;
400 if (ioctl(sock
, SIOCGIFCONF
, &conf
) < 0)
403 * Couldn't get the list of interfaces...
411 * OK, got the list of interfaces, now lets step through the
412 * buffer to pull them out...
415 # ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
416 # define sockaddr_len(a) ((a)->sa_len)
418 # define sockaddr_len(a) (sizeof(struct sockaddr))
419 # endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
421 for (bufptr
= buffer
, bufend
= buffer
+ conf
.ifc_len
;
426 * Get the current interface information...
429 ifp
= (struct ifreq
*)bufptr
;
430 ifpsize
= sizeof(ifp
->ifr_name
) + sockaddr_len(&(ifp
->ifr_addr
));
432 if (ifpsize
< sizeof(struct ifreq
))
433 ifpsize
= sizeof(struct ifreq
);
435 memset(&request
, 0, sizeof(request
));
436 memcpy(request
.ifr_name
, ifp
->ifr_name
, sizeof(ifp
->ifr_name
));
439 * Check the status of the interface...
442 if (ioctl(sock
, SIOCGIFFLAGS
, &request
) < 0)
446 * Allocate memory for a single interface record...
449 if ((temp
= calloc(1, sizeof(struct ifaddrs
))) == NULL
)
452 * Unable to allocate memory...
460 * Add this record to the front of the list and copy the name, flags,
461 * and network address...
464 temp
->ifa_next
= *addrs
;
466 temp
->ifa_name
= strdup(ifp
->ifr_name
);
467 temp
->ifa_flags
= request
.ifr_flags
;
468 if ((temp
->ifa_addr
= calloc(1, sockaddr_len(&(ifp
->ifr_addr
)))) != NULL
)
469 memcpy(temp
->ifa_addr
, &(ifp
->ifr_addr
), sockaddr_len(&(ifp
->ifr_addr
)));
472 * Try to get the netmask for the interface...
475 if (!ioctl(sock
, SIOCGIFNETMASK
, &request
))
478 * Got it, make a copy...
481 if ((temp
->ifa_netmask
= calloc(1, sizeof(request
.ifr_netmask
))) != NULL
)
482 memcpy(temp
->ifa_netmask
, &(request
.ifr_netmask
),
483 sizeof(request
.ifr_netmask
));
487 * Then get the broadcast or point-to-point (destination) address,
491 if (temp
->ifa_flags
& IFF_BROADCAST
)
494 * Have a broadcast address, so get it!
497 if (!ioctl(sock
, SIOCGIFBRDADDR
, &request
))
500 * Got it, make a copy...
503 if ((temp
->ifa_dstaddr
= calloc(1, sizeof(request
.ifr_broadaddr
))) != NULL
)
504 memcpy(temp
->ifa_dstaddr
, &(request
.ifr_broadaddr
),
505 sizeof(request
.ifr_broadaddr
));
508 else if (temp
->ifa_flags
& IFF_POINTOPOINT
)
511 * Point-to-point interface; grab the remote address...
514 if (!ioctl(sock
, SIOCGIFDSTADDR
, &request
))
516 temp
->ifa_dstaddr
= malloc(sizeof(request
.ifr_dstaddr
));
517 memcpy(temp
->ifa_dstaddr
, &(request
.ifr_dstaddr
),
518 sizeof(request
.ifr_dstaddr
));
524 * OK, we're done with the socket, close it and return 0...
534 * 'freeifaddrs()' - Free an interface list...
538 freeifaddrs(struct ifaddrs
*addrs
) /* I - Interface list to free */
540 struct ifaddrs
*next
; /* Next interface in list */
543 while (addrs
!= NULL
)
546 * Make a copy of the next interface pointer...
549 next
= addrs
->ifa_next
;
552 * Free data values as needed...
557 free(addrs
->ifa_name
);
558 addrs
->ifa_name
= NULL
;
563 free(addrs
->ifa_addr
);
564 addrs
->ifa_addr
= NULL
;
567 if (addrs
->ifa_netmask
)
569 free(addrs
->ifa_netmask
);
570 addrs
->ifa_netmask
= NULL
;
573 if (addrs
->ifa_dstaddr
)
575 free(addrs
->ifa_dstaddr
);
576 addrs
->ifa_dstaddr
= NULL
;
580 * Free this node and continue to the next...
588 #endif /* !HAVE_GETIFADDRS */
592 * End of "$Id: network.c 5043 2006-02-01 18:55:16Z mike $".