]> git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/network.c
Remove svn:keywords since they cause svn_load_dirs.pl to complain about every file.
[thirdparty/cups.git] / scheduler / network.c
1 /*
2 * "$Id: network.c 177 2006-06-21 00:20:03Z jlovell $"
3 *
4 * Network interface functions for the Common UNIX Printing System
5 * (CUPS) scheduler.
6 *
7 * Copyright 1997-2006 by Easy Software Products, all rights reserved.
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
19 * Hollywood, Maryland 20636 USA
20 *
21 * Voice: (301) 373-9600
22 * EMail: cups-info@cups.org
23 * WWW: http://www.cups.org
24 *
25 * Contents:
26 *
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 */
32
33 /*
34 * Include necessary headers.
35 */
36
37 #include <cups/http-private.h>
38 #include "cupsd.h"
39
40
41 /*
42 * Local functions...
43 */
44
45 static void cupsdNetIFFree(void);
46 static int compare_netif(cupsd_netif_t *a, cupsd_netif_t *b);
47
48
49 /*
50 * 'cupsdNetIFFind()' - Find a network interface.
51 */
52
53 cupsd_netif_t * /* O - Network interface data */
54 cupsdNetIFFind(const char *name) /* I - Name of interface */
55 {
56 cupsd_netif_t key; /* Search key */
57
58
59 /*
60 * Update the interface list as needed...
61 */
62
63 cupsdNetIFUpdate();
64
65 /*
66 * Search for the named interface...
67 */
68
69 strlcpy(key.name, name, sizeof(key.name));
70
71 return ((cupsd_netif_t *)cupsArrayFind(NetIFList, &key));
72 }
73
74
75 /*
76 * 'cupsdNetIFFree()' - Free the current network interface list.
77 */
78
79 static void
80 cupsdNetIFFree(void)
81 {
82 cupsd_netif_t *current; /* Current interface in array */
83
84
85 /*
86 * Loop through the interface list and free all the records...
87 */
88
89 for (current = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
90 current;
91 current = (cupsd_netif_t *)cupsArrayNext(NetIFList))
92 {
93 cupsArrayRemove(NetIFList, current);
94 free(current);
95 }
96 }
97
98
99 /*
100 * 'cupsdNetIFUpdate()' - Update the network interface list as needed...
101 */
102
103 void
104 cupsdNetIFUpdate(void)
105 {
106 int match; /* Matching address? */
107 cupsd_listener_t *lis; /* Listen address */
108 cupsd_netif_t *temp; /* New interface */
109 struct ifaddrs *addrs, /* Interface address list */
110 *addr; /* Current interface address */
111 http_addrlist_t *saddr; /* Current server address */
112 char hostname[1024]; /* Hostname for address */
113
114
115 /*
116 * Update the network interface list no more often than once a
117 * minute...
118 */
119
120 if ((time(NULL) - NetIFTime) < 60)
121 return;
122
123 NetIFTime = time(NULL);
124
125 /*
126 * Free the old interfaces...
127 */
128
129 cupsdNetIFFree();
130
131 /*
132 * Make sure we have an array...
133 */
134
135 if (!NetIFList)
136 NetIFList = cupsArrayNew((cups_array_func_t)compare_netif, NULL);
137
138 if (!NetIFList)
139 return;
140
141 /*
142 * Grab a new list of interfaces...
143 */
144
145 if (getifaddrs(&addrs) < 0)
146 return;
147
148 for (addr = addrs; addr != NULL; addr = addr->ifa_next)
149 {
150 /*
151 * See if this interface address is IPv4 or IPv6...
152 */
153
154 if (addr->ifa_addr == NULL ||
155 (addr->ifa_addr->sa_family != AF_INET
156 #ifdef AF_INET6
157 && addr->ifa_addr->sa_family != AF_INET6
158 #endif
159 ) ||
160 addr->ifa_netmask == NULL || addr->ifa_name == NULL)
161 continue;
162
163 /*
164 * Try looking up the hostname for the address as needed...
165 */
166
167 if (HostNameLookups)
168 httpAddrLookup((http_addr_t *)(addr->ifa_addr), hostname,
169 sizeof(hostname));
170 else
171 {
172 /*
173 * Map the default server address and localhost to the server name
174 * and localhost, respectively; for all other addresses, use the
175 * dotted notation...
176 */
177
178 if (httpAddrLocalhost((http_addr_t *)(addr->ifa_addr)))
179 strcpy(hostname, "localhost");
180 else
181 {
182 for (saddr = ServerAddrs; saddr; saddr = saddr->next)
183 if (httpAddrEqual((http_addr_t *)(addr->ifa_addr), &(saddr->addr)))
184 break;
185
186 if (saddr)
187 strlcpy(hostname, ServerName, sizeof(hostname));
188 else
189 httpAddrString((http_addr_t *)(addr->ifa_addr), hostname,
190 sizeof(hostname));
191 }
192 }
193
194 /*
195 * Create a new address element...
196 */
197
198 if ((temp = calloc(1, sizeof(cupsd_netif_t) +
199 strlen(hostname))) == NULL)
200 break;
201
202 /*
203 * Copy all of the information...
204 */
205
206 strlcpy(temp->name, addr->ifa_name, sizeof(temp->name));
207 strcpy(temp->hostname, hostname); /* Safe because hostname is allocated */
208
209 if (addr->ifa_addr->sa_family == AF_INET)
210 {
211 /*
212 * Copy IPv4 addresses...
213 */
214
215 memcpy(&(temp->address), addr->ifa_addr, sizeof(struct sockaddr_in));
216 memcpy(&(temp->mask), addr->ifa_netmask, sizeof(struct sockaddr_in));
217
218 if (addr->ifa_dstaddr)
219 memcpy(&(temp->broadcast), addr->ifa_dstaddr,
220 sizeof(struct sockaddr_in));
221 }
222 #ifdef AF_INET6
223 else
224 {
225 /*
226 * Copy IPv6 addresses...
227 */
228
229 memcpy(&(temp->address), addr->ifa_addr, sizeof(struct sockaddr_in6));
230 memcpy(&(temp->mask), addr->ifa_netmask, sizeof(struct sockaddr_in6));
231
232 if (addr->ifa_dstaddr)
233 memcpy(&(temp->broadcast), addr->ifa_dstaddr,
234 sizeof(struct sockaddr_in6));
235 }
236 #endif /* AF_INET6 */
237
238 if (!(addr->ifa_flags & IFF_POINTOPOINT) &&
239 !httpAddrLocalhost(&(temp->address)))
240 temp->is_local = 1;
241
242 /*
243 * Determine which port to use when advertising printers...
244 */
245
246 for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
247 lis;
248 lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
249 {
250 match = 0;
251
252 if (httpAddrAny(&(lis->address)))
253 match = 1;
254 else if (addr->ifa_addr->sa_family == AF_INET &&
255 lis->address.addr.sa_family == AF_INET &&
256 (lis->address.ipv4.sin_addr.s_addr &
257 temp->mask.ipv4.sin_addr.s_addr) ==
258 temp->address.ipv4.sin_addr.s_addr)
259 match = 1;
260 #ifdef AF_INET6
261 else if (addr->ifa_addr->sa_family == AF_INET6 &&
262 lis->address.addr.sa_family == AF_INET6 &&
263 (lis->address.ipv6.sin6_addr.s6_addr[0] &
264 temp->mask.ipv6.sin6_addr.s6_addr[0]) ==
265 temp->address.ipv6.sin6_addr.s6_addr[0] &&
266 (lis->address.ipv6.sin6_addr.s6_addr[1] &
267 temp->mask.ipv6.sin6_addr.s6_addr[1]) ==
268 temp->address.ipv6.sin6_addr.s6_addr[1] &&
269 (lis->address.ipv6.sin6_addr.s6_addr[2] &
270 temp->mask.ipv6.sin6_addr.s6_addr[2]) ==
271 temp->address.ipv6.sin6_addr.s6_addr[2] &&
272 (lis->address.ipv6.sin6_addr.s6_addr[3] &
273 temp->mask.ipv6.sin6_addr.s6_addr[3]) ==
274 temp->address.ipv6.sin6_addr.s6_addr[3])
275 match = 1;
276 #endif /* AF_INET6 */
277
278 if (match)
279 {
280 if (lis->address.addr.sa_family == AF_INET)
281 temp->port = ntohs(lis->address.ipv4.sin_port);
282 #ifdef AF_INET6
283 else if (lis->address.addr.sa_family == AF_INET6)
284 temp->port = ntohs(lis->address.ipv6.sin6_port);
285 #endif /* AF_INET6 */
286 break;
287 }
288 }
289
290 /*
291 * Add it to the array...
292 */
293
294 cupsArrayAdd(NetIFList, temp);
295
296 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdNetIFUpdate: \"%s\" = %s...",
297 temp->name, temp->hostname);
298 }
299
300 freeifaddrs(addrs);
301 }
302
303
304 /*
305 * 'compare_netif()' - Compare two network interfaces.
306 */
307
308 static int /* O - Result of comparison */
309 compare_netif(cupsd_netif_t *a, /* I - First network interface */
310 cupsd_netif_t *b) /* I - Second network interface */
311 {
312 return (strcmp(a->name, b->name));
313 }
314
315
316 /*
317 * End of "$Id: network.c 177 2006-06-21 00:20:03Z jlovell $".
318 */