]> git.ipfire.org Git - thirdparty/cups.git/blame - scheduler/network.c
Merge pull request #5410 from AOSC-Dev/master
[thirdparty/cups.git] / scheduler / network.c
CommitLineData
ef416fc2 1/*
84ec3a84 2 * Network interface functions for the CUPS scheduler.
ef416fc2 3 *
53f8d64f
MS
4 * Copyright © 2007-2014 by Apple Inc.
5 * Copyright © 1997-2006 by Easy Software Products, all rights reserved.
ef416fc2 6 *
53f8d64f
MS
7 * Licensed under Apache License v2.0. See the file "LICENSE" for more
8 * information.
ef416fc2 9 */
10
11/*
12 * Include necessary headers.
13 */
14
89d46774 15#include <cups/http-private.h>
ef416fc2 16#include "cupsd.h"
17
e00b005a 18
19/*
20 * Local functions...
21 */
22
23static void cupsdNetIFFree(void);
24static int compare_netif(cupsd_netif_t *a, cupsd_netif_t *b);
25
26
ef416fc2 27/*
28 * 'cupsdNetIFFind()' - Find a network interface.
29 */
30
31cupsd_netif_t * /* O - Network interface data */
32cupsdNetIFFind(const char *name) /* I - Name of interface */
33{
e00b005a 34 cupsd_netif_t key; /* Search key */
ef416fc2 35
36
37 /*
38 * Update the interface list as needed...
39 */
40
411affcf 41 if (NetIFUpdate)
42 cupsdNetIFUpdate();
ef416fc2 43
44 /*
45 * Search for the named interface...
46 */
47
e00b005a 48 strlcpy(key.name, name, sizeof(key.name));
ef416fc2 49
e00b005a 50 return ((cupsd_netif_t *)cupsArrayFind(NetIFList, &key));
ef416fc2 51}
52
53
54/*
55 * 'cupsdNetIFFree()' - Free the current network interface list.
56 */
57
e00b005a 58static void
ef416fc2 59cupsdNetIFFree(void)
60{
e00b005a 61 cupsd_netif_t *current; /* Current interface in array */
ef416fc2 62
63
64 /*
65 * Loop through the interface list and free all the records...
66 */
67
e00b005a 68 for (current = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
69 current;
70 current = (cupsd_netif_t *)cupsArrayNext(NetIFList))
ef416fc2 71 {
e00b005a 72 cupsArrayRemove(NetIFList, current);
73 free(current);
ef416fc2 74 }
75}
76
77
78/*
79 * 'cupsdNetIFUpdate()' - Update the network interface list as needed...
80 */
81
82void
83cupsdNetIFUpdate(void)
84{
bd7854cb 85 int match; /* Matching address? */
ef416fc2 86 cupsd_listener_t *lis; /* Listen address */
e00b005a 87 cupsd_netif_t *temp; /* New interface */
ef416fc2 88 struct ifaddrs *addrs, /* Interface address list */
89 *addr; /* Current interface address */
e00b005a 90 char hostname[1024]; /* Hostname for address */
e07d4801 91 size_t hostlen; /* Length of hostname */
ef416fc2 92
93
94 /*
411affcf 95 * Only update the list if we need to...
ef416fc2 96 */
97
411affcf 98 if (!NetIFUpdate)
ef416fc2 99 return;
100
411affcf 101 NetIFUpdate = 0;
ef416fc2 102
103 /*
104 * Free the old interfaces...
105 */
106
107 cupsdNetIFFree();
108
e00b005a 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
ef416fc2 119 /*
120 * Grab a new list of interfaces...
121 */
122
123 if (getifaddrs(&addrs) < 0)
84ec3a84
MS
124 {
125 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdNetIFUpdate: Unable to get interface list - %s", strerror(errno));
ef416fc2 126 return;
84ec3a84 127 }
ef416fc2 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)
84ec3a84
MS
142 {
143 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdNetIFUpdate: Ignoring \"%s\".", addr->ifa_name);
ef416fc2 144 continue;
84ec3a84 145 }
ef416fc2 146
147 /*
e00b005a 148 * Try looking up the hostname for the address as needed...
ef416fc2 149 */
150
ba55dc12 151 if (HostNameLookups)
e00b005a 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
cc754834 159 * numeric address...
e00b005a 160 */
ef416fc2 161
e00b005a 162 if (httpAddrLocalhost((http_addr_t *)(addr->ifa_addr)))
82cc1f9a 163 strlcpy(hostname, "localhost", sizeof(hostname));
e00b005a 164 else
d1c13e16
MS
165 httpAddrString((http_addr_t *)(addr->ifa_addr), hostname,
166 sizeof(hostname));
e00b005a 167 }
ef416fc2 168
e00b005a 169 /*
170 * Create a new address element...
171 */
ef416fc2 172
e07d4801
MS
173 hostlen = strlen(hostname);
174 if ((temp = calloc(1, sizeof(cupsd_netif_t) + hostlen)) == NULL)
84ec3a84
MS
175 {
176 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdNetIFUpdate: Unable to allocate memory for interface.");
e00b005a 177 break;
84ec3a84 178 }
ef416fc2 179
180 /*
e00b005a 181 * Copy all of the information...
ef416fc2 182 */
183
184 strlcpy(temp->name, addr->ifa_name, sizeof(temp->name));
e07d4801 185 temp->hostlen = hostlen;
82cc1f9a 186 memcpy(temp->hostname, hostname, hostlen + 1);
ef416fc2 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
bd7854cb 225 for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
226 lis;
227 lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
ef416fc2 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 &
06d4e77b
MS
236 temp->mask.ipv4.sin_addr.s_addr) ==
237 (temp->address.ipv4.sin_addr.s_addr &
238 temp->mask.ipv4.sin_addr.s_addr))
ef416fc2 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] &
06d4e77b
MS
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]) &&
ef416fc2 247 (lis->address.ipv6.sin6_addr.s6_addr[1] &
06d4e77b
MS
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]) &&
ef416fc2 251 (lis->address.ipv6.sin6_addr.s6_addr[2] &
06d4e77b
MS
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]) &&
ef416fc2 255 (lis->address.ipv6.sin6_addr.s6_addr[3] &
06d4e77b
MS
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]))
ef416fc2 259 match = 1;
260#endif /* AF_INET6 */
261
262 if (match)
263 {
a469f8a5 264 temp->port = httpAddrPort(&(lis->address));
ef416fc2 265 break;
266 }
267 }
268
269 /*
e00b005a 270 * Add it to the array...
ef416fc2 271 */
272
e00b005a 273 cupsArrayAdd(NetIFList, temp);
ef416fc2 274
06d4e77b
MS
275 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdNetIFUpdate: \"%s\" = %s:%d",
276 temp->name, temp->hostname, temp->port);
ef416fc2 277 }
278
279 freeifaddrs(addrs);
280}
281
282
e00b005a 283/*
284 * 'compare_netif()' - Compare two network interfaces.
285 */
286
287static int /* O - Result of comparison */
288compare_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}