]> git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/network.c
Fix stuck multi-file jobs (Issue #5359, Issue #5413)
[thirdparty/cups.git] / scheduler / network.c
1 /*
2 * Network interface functions for the CUPS scheduler.
3 *
4 * Copyright © 2007-2014 by Apple Inc.
5 * Copyright © 1997-2006 by Easy Software Products, all rights reserved.
6 *
7 * Licensed under Apache License v2.0. See the file "LICENSE" for more
8 * information.
9 */
10
11 /*
12 * Include necessary headers.
13 */
14
15 #include <cups/http-private.h>
16 #include "cupsd.h"
17
18
19 /*
20 * Local functions...
21 */
22
23 static void cupsdNetIFFree(void);
24 static int compare_netif(cupsd_netif_t *a, cupsd_netif_t *b);
25
26
27 /*
28 * 'cupsdNetIFFind()' - Find a network interface.
29 */
30
31 cupsd_netif_t * /* O - Network interface data */
32 cupsdNetIFFind(const char *name) /* I - Name of interface */
33 {
34 cupsd_netif_t key; /* Search key */
35
36
37 /*
38 * Update the interface list as needed...
39 */
40
41 if (NetIFUpdate)
42 cupsdNetIFUpdate();
43
44 /*
45 * Search for the named interface...
46 */
47
48 strlcpy(key.name, name, sizeof(key.name));
49
50 return ((cupsd_netif_t *)cupsArrayFind(NetIFList, &key));
51 }
52
53
54 /*
55 * 'cupsdNetIFFree()' - Free the current network interface list.
56 */
57
58 static void
59 cupsdNetIFFree(void)
60 {
61 cupsd_netif_t *current; /* Current interface in array */
62
63
64 /*
65 * Loop through the interface list and free all the records...
66 */
67
68 for (current = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
69 current;
70 current = (cupsd_netif_t *)cupsArrayNext(NetIFList))
71 {
72 cupsArrayRemove(NetIFList, current);
73 free(current);
74 }
75 }
76
77
78 /*
79 * 'cupsdNetIFUpdate()' - Update the network interface list as needed...
80 */
81
82 void
83 cupsdNetIFUpdate(void)
84 {
85 int match; /* Matching address? */
86 cupsd_listener_t *lis; /* Listen address */
87 cupsd_netif_t *temp; /* New interface */
88 struct ifaddrs *addrs, /* Interface address list */
89 *addr; /* Current interface address */
90 char hostname[1024]; /* Hostname for address */
91 size_t hostlen; /* Length of hostname */
92
93
94 /*
95 * Only update the list if we need to...
96 */
97
98 if (!NetIFUpdate)
99 return;
100
101 NetIFUpdate = 0;
102
103 /*
104 * Free the old interfaces...
105 */
106
107 cupsdNetIFFree();
108
109 /*
110 * Make sure we have an array...
111 */
112
113 if (!NetIFList)
114 NetIFList = cupsArrayNew((cups_array_func_t)compare_netif, NULL);
115
116 if (!NetIFList)
117 return;
118
119 /*
120 * Grab a new list of interfaces...
121 */
122
123 if (getifaddrs(&addrs) < 0)
124 {
125 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdNetIFUpdate: Unable to get interface list - %s", strerror(errno));
126 return;
127 }
128
129 for (addr = addrs; addr != NULL; addr = addr->ifa_next)
130 {
131 /*
132 * See if this interface address is IPv4 or IPv6...
133 */
134
135 if (addr->ifa_addr == NULL ||
136 (addr->ifa_addr->sa_family != AF_INET
137 #ifdef AF_INET6
138 && addr->ifa_addr->sa_family != AF_INET6
139 #endif
140 ) ||
141 addr->ifa_netmask == NULL || addr->ifa_name == NULL)
142 {
143 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdNetIFUpdate: Ignoring \"%s\".", addr->ifa_name);
144 continue;
145 }
146
147 /*
148 * Try looking up the hostname for the address as needed...
149 */
150
151 if (HostNameLookups)
152 httpAddrLookup((http_addr_t *)(addr->ifa_addr), hostname,
153 sizeof(hostname));
154 else
155 {
156 /*
157 * Map the default server address and localhost to the server name
158 * and localhost, respectively; for all other addresses, use the
159 * numeric address...
160 */
161
162 if (httpAddrLocalhost((http_addr_t *)(addr->ifa_addr)))
163 strlcpy(hostname, "localhost", sizeof(hostname));
164 else
165 httpAddrString((http_addr_t *)(addr->ifa_addr), hostname,
166 sizeof(hostname));
167 }
168
169 /*
170 * Create a new address element...
171 */
172
173 hostlen = strlen(hostname);
174 if ((temp = calloc(1, sizeof(cupsd_netif_t) + hostlen)) == NULL)
175 {
176 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdNetIFUpdate: Unable to allocate memory for interface.");
177 break;
178 }
179
180 /*
181 * Copy all of the information...
182 */
183
184 strlcpy(temp->name, addr->ifa_name, sizeof(temp->name));
185 temp->hostlen = hostlen;
186 memcpy(temp->hostname, hostname, hostlen + 1);
187
188 if (addr->ifa_addr->sa_family == AF_INET)
189 {
190 /*
191 * Copy IPv4 addresses...
192 */
193
194 memcpy(&(temp->address), addr->ifa_addr, sizeof(struct sockaddr_in));
195 memcpy(&(temp->mask), addr->ifa_netmask, sizeof(struct sockaddr_in));
196
197 if (addr->ifa_dstaddr)
198 memcpy(&(temp->broadcast), addr->ifa_dstaddr,
199 sizeof(struct sockaddr_in));
200 }
201 #ifdef AF_INET6
202 else
203 {
204 /*
205 * Copy IPv6 addresses...
206 */
207
208 memcpy(&(temp->address), addr->ifa_addr, sizeof(struct sockaddr_in6));
209 memcpy(&(temp->mask), addr->ifa_netmask, sizeof(struct sockaddr_in6));
210
211 if (addr->ifa_dstaddr)
212 memcpy(&(temp->broadcast), addr->ifa_dstaddr,
213 sizeof(struct sockaddr_in6));
214 }
215 #endif /* AF_INET6 */
216
217 if (!(addr->ifa_flags & IFF_POINTOPOINT) &&
218 !httpAddrLocalhost(&(temp->address)))
219 temp->is_local = 1;
220
221 /*
222 * Determine which port to use when advertising printers...
223 */
224
225 for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
226 lis;
227 lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
228 {
229 match = 0;
230
231 if (httpAddrAny(&(lis->address)))
232 match = 1;
233 else if (addr->ifa_addr->sa_family == AF_INET &&
234 lis->address.addr.sa_family == AF_INET &&
235 (lis->address.ipv4.sin_addr.s_addr &
236 temp->mask.ipv4.sin_addr.s_addr) ==
237 (temp->address.ipv4.sin_addr.s_addr &
238 temp->mask.ipv4.sin_addr.s_addr))
239 match = 1;
240 #ifdef AF_INET6
241 else if (addr->ifa_addr->sa_family == AF_INET6 &&
242 lis->address.addr.sa_family == AF_INET6 &&
243 (lis->address.ipv6.sin6_addr.s6_addr[0] &
244 temp->mask.ipv6.sin6_addr.s6_addr[0]) ==
245 (temp->address.ipv6.sin6_addr.s6_addr[0] &
246 temp->mask.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 temp->mask.ipv6.sin6_addr.s6_addr[1]) &&
251 (lis->address.ipv6.sin6_addr.s6_addr[2] &
252 temp->mask.ipv6.sin6_addr.s6_addr[2]) ==
253 (temp->address.ipv6.sin6_addr.s6_addr[2] &
254 temp->mask.ipv6.sin6_addr.s6_addr[2]) &&
255 (lis->address.ipv6.sin6_addr.s6_addr[3] &
256 temp->mask.ipv6.sin6_addr.s6_addr[3]) ==
257 (temp->address.ipv6.sin6_addr.s6_addr[3] &
258 temp->mask.ipv6.sin6_addr.s6_addr[3]))
259 match = 1;
260 #endif /* AF_INET6 */
261
262 if (match)
263 {
264 temp->port = httpAddrPort(&(lis->address));
265 break;
266 }
267 }
268
269 /*
270 * Add it to the array...
271 */
272
273 cupsArrayAdd(NetIFList, temp);
274
275 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdNetIFUpdate: \"%s\" = %s:%d",
276 temp->name, temp->hostname, temp->port);
277 }
278
279 freeifaddrs(addrs);
280 }
281
282
283 /*
284 * 'compare_netif()' - Compare two network interfaces.
285 */
286
287 static int /* O - Result of comparison */
288 compare_netif(cupsd_netif_t *a, /* I - First network interface */
289 cupsd_netif_t *b) /* I - Second network interface */
290 {
291 return (strcmp(a->name, b->name));
292 }