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