]>
git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/network.c
f8fd6b3794a4e7436a8d22101586d52a656c67d3
4 * Network interface functions for the Common UNIX Printing System
7 * Copyright 1997-2005 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 * getifaddrs() - Get a list of network interfaces on the system.
31 * freeifaddrs() - Free an interface list...
35 * Include necessary headers.
42 #ifdef HAVE_GETIFADDRS
44 * Use native getifaddrs() function...
49 * Use getifaddrs() emulation...
52 # include <sys/ioctl.h>
53 # ifdef HAVE_SYS_SOCKIO_H
54 # include <sys/sockio.h>
59 # endif /* ifa_dstaddr */
61 # define ifr_netmask ifr_addr
62 # endif /* !ifr_netmask */
64 struct ifaddrs
/**** Interface Structure ****/
66 struct ifaddrs
*ifa_next
; /* Next interface in list */
67 char *ifa_name
; /* Name of interface */
68 unsigned int ifa_flags
; /* Flags (up, point-to-point, etc.) */
69 struct sockaddr
*ifa_addr
, /* Network address */
70 *ifa_netmask
, /* Address mask */
71 *ifa_dstaddr
; /* Broadcast or destination address */
72 void *ifa_data
; /* Interface statistics */
75 int getifaddrs(struct ifaddrs
**addrs
);
76 void freeifaddrs(struct ifaddrs
*addrs
);
77 #endif /* HAVE_GETIFADDRS */
81 * 'cupsdNetIFFind()' - Find a network interface.
84 cupsd_netif_t
* /* O - Network interface data */
85 cupsdNetIFFind(const char *name
) /* I - Name of interface */
87 cupsd_netif_t
*temp
; /* Current network interface */
91 * Update the interface list as needed...
97 * Search for the named interface...
100 for (temp
= NetIFList
; temp
!= NULL
; temp
= temp
->next
)
101 if (!strcasecmp(name
, temp
->name
))
109 * 'cupsdNetIFFree()' - Free the current network interface list.
115 cupsd_netif_t
*next
; /* Next interface in list */
119 * Loop through the interface list and free all the records...
122 while (NetIFList
!= NULL
)
124 next
= NetIFList
->next
;
134 * 'cupsdNetIFUpdate()' - Update the network interface list as needed...
138 cupsdNetIFUpdate(void)
140 int i
, /* Looping var */
141 match
; /* Matching address? */
142 cupsd_listener_t
*lis
; /* Listen address */
143 cupsd_netif_t
*temp
; /* Current interface */
144 struct ifaddrs
*addrs
, /* Interface address list */
145 *addr
; /* Current interface address */
149 * Update the network interface list no more often than once a
153 if ((time(NULL
) - NetIFTime
) < 60)
156 NetIFTime
= time(NULL
);
159 * Free the old interfaces...
165 * Grab a new list of interfaces...
168 if (getifaddrs(&addrs
) < 0)
171 for (addr
= addrs
; addr
!= NULL
; addr
= addr
->ifa_next
)
174 * See if this interface address is IPv4 or IPv6...
177 if (addr
->ifa_addr
== NULL
||
178 (addr
->ifa_addr
->sa_family
!= AF_INET
180 && addr
->ifa_addr
->sa_family
!= AF_INET6
183 addr
->ifa_netmask
== NULL
|| addr
->ifa_name
== NULL
)
187 * OK, we have an IPv4/6 address, so create a new list node...
190 if ((temp
= calloc(1, sizeof(cupsd_netif_t
))) == NULL
)
193 temp
->next
= NetIFList
;
197 * Then copy all of the information...
200 strlcpy(temp
->name
, addr
->ifa_name
, sizeof(temp
->name
));
202 if (addr
->ifa_addr
->sa_family
== AF_INET
)
205 * Copy IPv4 addresses...
208 memcpy(&(temp
->address
), addr
->ifa_addr
, sizeof(struct sockaddr_in
));
209 memcpy(&(temp
->mask
), addr
->ifa_netmask
, sizeof(struct sockaddr_in
));
211 if (addr
->ifa_dstaddr
)
212 memcpy(&(temp
->broadcast
), addr
->ifa_dstaddr
,
213 sizeof(struct sockaddr_in
));
219 * Copy IPv6 addresses...
222 memcpy(&(temp
->address
), addr
->ifa_addr
, sizeof(struct sockaddr_in6
));
223 memcpy(&(temp
->mask
), addr
->ifa_netmask
, sizeof(struct sockaddr_in6
));
225 if (addr
->ifa_dstaddr
)
226 memcpy(&(temp
->broadcast
), addr
->ifa_dstaddr
,
227 sizeof(struct sockaddr_in6
));
229 #endif /* AF_INET6 */
231 if (!(addr
->ifa_flags
& IFF_POINTOPOINT
) &&
232 !httpAddrLocalhost(&(temp
->address
)))
236 * Determine which port to use when advertising printers...
239 for (i
= NumListeners
, lis
= Listeners
; i
> 0; i
--, lis
++)
243 if (httpAddrAny(&(lis
->address
)))
245 else if (addr
->ifa_addr
->sa_family
== AF_INET
&&
246 lis
->address
.addr
.sa_family
== AF_INET
&&
247 (lis
->address
.ipv4
.sin_addr
.s_addr
&
248 temp
->mask
.ipv4
.sin_addr
.s_addr
) ==
249 temp
->address
.ipv4
.sin_addr
.s_addr
)
252 else if (addr
->ifa_addr
->sa_family
== AF_INET6
&&
253 lis
->address
.addr
.sa_family
== AF_INET6
&&
254 (lis
->address
.ipv6
.sin6_addr
.s6_addr
[0] &
255 temp
->mask
.ipv6
.sin6_addr
.s6_addr
[0]) ==
256 temp
->address
.ipv6
.sin6_addr
.s6_addr
[0] &&
257 (lis
->address
.ipv6
.sin6_addr
.s6_addr
[1] &
258 temp
->mask
.ipv6
.sin6_addr
.s6_addr
[1]) ==
259 temp
->address
.ipv6
.sin6_addr
.s6_addr
[1] &&
260 (lis
->address
.ipv6
.sin6_addr
.s6_addr
[2] &
261 temp
->mask
.ipv6
.sin6_addr
.s6_addr
[2]) ==
262 temp
->address
.ipv6
.sin6_addr
.s6_addr
[2] &&
263 (lis
->address
.ipv6
.sin6_addr
.s6_addr
[3] &
264 temp
->mask
.ipv6
.sin6_addr
.s6_addr
[3]) ==
265 temp
->address
.ipv6
.sin6_addr
.s6_addr
[3])
267 #endif /* AF_INET6 */
271 if (lis
->address
.addr
.sa_family
== AF_INET
)
272 temp
->port
= ntohs(lis
->address
.ipv4
.sin_port
);
274 else if (lis
->address
.addr
.sa_family
== AF_INET6
)
275 temp
->port
= ntohs(lis
->address
.ipv6
.sin6_port
);
276 #endif /* AF_INET6 */
282 * Finally, try looking up the hostname for the address as needed...
286 httpAddrLookup(&(temp
->address
), temp
->hostname
, sizeof(temp
->hostname
));
290 * Map the default server address and localhost to the server name
291 * and localhost, respectively; for all other addresses, use the
295 if (httpAddrLocalhost(&(temp
->address
)))
296 strcpy(temp
->hostname
, "localhost");
297 else if (httpAddrEqual(&(temp
->address
), &ServerAddr
))
298 strlcpy(temp
->hostname
, ServerName
, sizeof(temp
->hostname
));
300 httpAddrString(&(temp
->address
), temp
->hostname
,
301 sizeof(temp
->hostname
));
309 #ifndef HAVE_GETIFADDRS
311 * 'getifaddrs()' - Get a list of network interfaces on the system.
314 int /* O - 0 on success, -1 on error */
315 getifaddrs(struct ifaddrs
**addrs
) /* O - List of interfaces */
317 int sock
; /* Socket */
318 char buffer
[65536], /* Buffer for address info */
319 *bufptr
, /* Pointer into buffer */
320 *bufend
; /* End of buffer */
321 struct ifconf conf
; /* Interface configurations */
322 struct sockaddr addr
; /* Address data */
323 struct ifreq
*ifp
; /* Interface data */
324 int ifpsize
; /* Size of interface data */
325 struct ifaddrs
*temp
; /* Pointer to current interface */
326 struct ifreq request
; /* Interface request */
330 * Start with an empty list...
339 * Create a UDP socket to get the interface data...
342 memset (&addr
, 0, sizeof(addr
));
343 if ((sock
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0)
347 * Try to get the list of interfaces...
350 conf
.ifc_len
= sizeof(buffer
);
351 conf
.ifc_buf
= buffer
;
353 if (ioctl(sock
, SIOCGIFCONF
, &conf
) < 0)
356 * Couldn't get the list of interfaces...
364 * OK, got the list of interfaces, now lets step through the
365 * buffer to pull them out...
368 # ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
369 # define sockaddr_len(a) ((a)->sa_len)
371 # define sockaddr_len(a) (sizeof(struct sockaddr))
372 # endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
374 for (bufptr
= buffer
, bufend
= buffer
+ conf
.ifc_len
;
379 * Get the current interface information...
382 ifp
= (struct ifreq
*)bufptr
;
383 ifpsize
= sizeof(ifp
->ifr_name
) + sockaddr_len(&(ifp
->ifr_addr
));
385 if (ifpsize
< sizeof(struct ifreq
))
386 ifpsize
= sizeof(struct ifreq
);
388 memset(&request
, 0, sizeof(request
));
389 memcpy(request
.ifr_name
, ifp
->ifr_name
, sizeof(ifp
->ifr_name
));
392 * Check the status of the interface...
395 if (ioctl(sock
, SIOCGIFFLAGS
, &request
) < 0)
399 * Allocate memory for a single interface record...
402 if ((temp
= calloc(1, sizeof(struct ifaddrs
))) == NULL
)
405 * Unable to allocate memory...
413 * Add this record to the front of the list and copy the name, flags,
414 * and network address...
417 temp
->ifa_next
= *addrs
;
419 temp
->ifa_name
= strdup(ifp
->ifr_name
);
420 temp
->ifa_flags
= request
.ifr_flags
;
421 if ((temp
->ifa_addr
= calloc(1, sockaddr_len(&(ifp
->ifr_addr
)))) != NULL
)
422 memcpy(temp
->ifa_addr
, &(ifp
->ifr_addr
), sockaddr_len(&(ifp
->ifr_addr
)));
425 * Try to get the netmask for the interface...
428 if (!ioctl(sock
, SIOCGIFNETMASK
, &request
))
431 * Got it, make a copy...
434 if ((temp
->ifa_netmask
= calloc(1, sizeof(request
.ifr_netmask
))) != NULL
)
435 memcpy(temp
->ifa_netmask
, &(request
.ifr_netmask
),
436 sizeof(request
.ifr_netmask
));
440 * Then get the broadcast or point-to-point (destination) address,
444 if (temp
->ifa_flags
& IFF_BROADCAST
)
447 * Have a broadcast address, so get it!
450 if (!ioctl(sock
, SIOCGIFBRDADDR
, &request
))
453 * Got it, make a copy...
456 if ((temp
->ifa_dstaddr
= calloc(1, sizeof(request
.ifr_broadaddr
))) != NULL
)
457 memcpy(temp
->ifa_dstaddr
, &(request
.ifr_broadaddr
),
458 sizeof(request
.ifr_broadaddr
));
461 else if (temp
->ifa_flags
& IFF_POINTOPOINT
)
464 * Point-to-point interface; grab the remote address...
467 if (!ioctl(sock
, SIOCGIFDSTADDR
, &request
))
469 temp
->ifa_dstaddr
= malloc(sizeof(request
.ifr_dstaddr
));
470 memcpy(temp
->ifa_dstaddr
, &(request
.ifr_dstaddr
),
471 sizeof(request
.ifr_dstaddr
));
477 * OK, we're done with the socket, close it and return 0...
487 * 'freeifaddrs()' - Free an interface list...
491 freeifaddrs(struct ifaddrs
*addrs
) /* I - Interface list to free */
493 struct ifaddrs
*next
; /* Next interface in list */
496 while (addrs
!= NULL
)
499 * Make a copy of the next interface pointer...
502 next
= addrs
->ifa_next
;
505 * Free data values as needed...
510 free(addrs
->ifa_name
);
511 addrs
->ifa_name
= NULL
;
516 free(addrs
->ifa_addr
);
517 addrs
->ifa_addr
= NULL
;
520 if (addrs
->ifa_netmask
)
522 free(addrs
->ifa_netmask
);
523 addrs
->ifa_netmask
= NULL
;
526 if (addrs
->ifa_dstaddr
)
528 free(addrs
->ifa_dstaddr
);
529 addrs
->ifa_dstaddr
= NULL
;
533 * Free this node and continue to the next...
541 #endif /* !HAVE_GETIFADDRS */