]> git.saurik.com Git - apple/configd.git/blame - nwi/network_information_server.c
configd-802.20.7.tar.gz
[apple/configd.git] / nwi / network_information_server.c
CommitLineData
5e9ce69e 1/*
9de8ab86 2 * Copyright (c) 2012-2015 Apple Inc. All rights reserved.
5e9ce69e
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
9de8ab86 5 *
5e9ce69e
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
9de8ab86 12 *
5e9ce69e
A
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
9de8ab86 20 *
5e9ce69e
A
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24/*
25 * Modification History
26 *
27 * February 8, 2012 Allan Nathanson <ajn@apple.com>
28 * - initial revision
29 */
30
31#include <notify.h>
32#include <dispatch/dispatch.h>
33#include <xpc/xpc.h>
34#include <CommonCrypto/CommonDigest.h>
35#include <CoreFoundation/CoreFoundation.h>
36#include <SystemConfiguration/SCPrivate.h>
37
38#include "libSystemConfiguration_client.h"
39#include "libSystemConfiguration_server.h"
40
41#include <network_information.h>
42#include "network_information_priv.h"
43#include "network_information_server.h"
44
45
46#pragma mark -
47#pragma mark Globals
48
49
50/*
51 * S_nwi_info
52 *
53 * Note: all accesses should be made while running on the _nwi_server_queue()
54 */
55static libSC_info_server_t S_nwi_info;
56
57
58/*
9de8ab86
A
59 * S_logger
60 * Logging handle.
5e9ce69e 61 */
5e9ce69e
A
62static SCLoggerRef S_logger = NULL;
63
64
65/*
66 * S_sync_handler
67 * ACK (in-sync or not-in-sync) updates should be posted using
68 * this handler
69 *
70 * Note: all accesses should be made while running on the _nwi_server_queue()
71 */
72static _nwi_sync_handler_t S_sync_handler = NULL;
73
74
75#pragma mark -
76#pragma mark Support functions
77
78
5e9ce69e
A
79#pragma mark -
80#pragma mark Network information server "main"
81
82
83static dispatch_queue_t
84_nwi_state_server_queue()
85{
86 static dispatch_once_t once;
87 static dispatch_queue_t q;
88
89 dispatch_once(&once, ^{
90 q = dispatch_queue_create(NWI_SERVICE_NAME ".server", NULL);
91 });
92
93 return q;
94}
95
96
97/*
98 * _nwi_state_copy
99 *
100 * Called when a client wants a copy of the current
101 * Network information
102 *
103 * - caller must be running on the _nwi_server_queue()
104 */
105static void
106_nwi_state_copy(xpc_connection_t connection, xpc_object_t request)
107{
108 CFDataRef data;
109 uint64_t generation;
9de8ab86 110 const char *proc_name;
5e9ce69e
A
111 xpc_connection_t remote;
112 xpc_object_t reply;
113
114 remote = xpc_dictionary_get_remote_connection(request);
115 reply = xpc_dictionary_create_reply(request);
116 if (reply == NULL) {
117 SCLoggerLog(S_logger, LOG_ERR,
118 CFSTR("<%p> _nwi_state_copy: xpc_dictionary_create_reply: failed"),
119 connection);
120 return;
121 }
122
123 // extract data and generation #
124 data = _libSC_info_server_get_data(&S_nwi_info, connection, &generation);
125
9de8ab86
A
126 // extract process name
127 proc_name = xpc_dictionary_get_string(request, NWI_PROC_NAME);
128 if (proc_name == NULL) {
129 proc_name = "???";
5e9ce69e
A
130 }
131
9de8ab86
A
132 SCLoggerLog(S_logger, LOG_DEBUG, CFSTR("<%p:%s[%d]> Network information copy: %llu"),
133 connection,
134 proc_name,
135 xpc_connection_get_pid(connection),
136 generation);
137
5e9ce69e
A
138 // return the Network information (if available)
139 if (data != NULL) {
140 xpc_dictionary_set_data(reply,
141 NWI_CONFIGURATION,
142 CFDataGetBytePtr(data),
143 CFDataGetLength(data));
144 }
145
146 // reply
147 xpc_connection_send_message(remote, reply);
148 xpc_release(reply);
149
150 return;
151}
152
153
154/*
155 * _nwi_state_acknowledge
156 *
157 * Called when a client wants to acknowledge processing
158 * of the Network information
159 *
160 * - caller must be running on the _nwi_server_queue()
161 */
162static void
163_nwi_state_acknowledge(xpc_connection_t connection, xpc_object_t request)
164{
165 Boolean changed;
166 uint64_t generation;
167
168 generation = xpc_dictionary_get_uint64(request, NWI_GENERATION);
169
9de8ab86
A
170 SCLoggerLog(S_logger, LOG_DEBUG, CFSTR("<%p:%d> Network information ack: %llu"),
171 connection,
172 xpc_connection_get_pid(connection),
173 generation);
5e9ce69e
A
174
175 _libSC_info_server_acknowledged(&S_nwi_info, connection, generation);
176 changed = _libSC_info_server_acknowledged(&S_nwi_info, connection, generation);
177 if (changed) {
178 Boolean inSync;
179
180 // report change
181 inSync = _libSC_info_server_in_sync(&S_nwi_info);
182 S_sync_handler(inSync);
183 }
184
185 return;
186}
187
188
189static void
190process_request(xpc_connection_t connection, xpc_object_t request)
191{
192 int64_t op;
193
194 op = xpc_dictionary_get_int64(request, NWI_REQUEST);
195 switch (op) {
196 case NWI_REQUEST_COPY :
197 /*
198 * Return the Network information
199 */
200 _nwi_state_copy(connection, request);
201 break;
202
203 case NWI_REQUEST_ACKNOWLEDGE :
204 /*
205 * Acknowlege a [processed] Network information
206 */
207 _nwi_state_acknowledge(connection, request);
208
209 break;
210 default :
211 SCLoggerLog(S_logger, LOG_ERR,
78403150 212 CFSTR("<%p> unknown request : %lld"),
5e9ce69e
A
213 connection,
214 op);
215
216 break;
217 }
218
219 return;
220}
221
222
223static void
224process_new_connection(xpc_connection_t c)
225{
9de8ab86
A
226 SCLoggerLog(S_logger, LOG_DEBUG, CFSTR("<%p:%d> Network information session: open"),
227 c,
228 xpc_connection_get_pid(c));
5e9ce69e
A
229
230 _libSC_info_server_open(&S_nwi_info, c);
231
232 xpc_connection_set_target_queue(c, _nwi_state_server_queue());
233
234 xpc_connection_set_event_handler(c, ^(xpc_object_t xobj) {
9de8ab86 235 os_activity_t activity_id;
5e9ce69e
A
236 xpc_type_t type;
237
9de8ab86
A
238 activity_id = os_activity_start("processing nwi request",
239 OS_ACTIVITY_FLAG_DEFAULT);
240
5e9ce69e
A
241 type = xpc_get_type(xobj);
242 if (type == XPC_TYPE_DICTIONARY) {
243 // process the request
244 process_request(c, xobj);
245
246 } else if (type == XPC_TYPE_ERROR) {
247 const char *desc;
248
249 desc = xpc_dictionary_get_string(xobj, XPC_ERROR_KEY_DESCRIPTION);
250 if (xobj == XPC_ERROR_CONNECTION_INVALID) {
251 Boolean changed;
252
9de8ab86
A
253 SCLoggerLog(S_logger, LOG_DEBUG, CFSTR("<%p:%d> Network information session: close"),
254 c,
255 xpc_connection_get_pid(c));
5e9ce69e
A
256
257 changed = _libSC_info_server_close(&S_nwi_info, c);
258 if (changed) {
259 Boolean inSync;
260
261 // report change
262 inSync = _libSC_info_server_in_sync(&S_nwi_info);
263 S_sync_handler(inSync);
264 }
265
266 } else if (xobj == XPC_ERROR_CONNECTION_INTERRUPTED) {
267 SCLoggerLog(S_logger, LOG_ERR,
268 CFSTR("<%p:%d> %s"),
269 c,
270 xpc_connection_get_pid(c),
271 desc);
272
273 } else {
274 SCLoggerLog(S_logger, LOG_ERR,
78403150 275 CFSTR("<%p:%d> Connection error: %p : %s"),
5e9ce69e
A
276 c,
277 xpc_connection_get_pid(c),
278 xobj,
279 desc);
280 }
281
282 } else {
283 SCLoggerLog(S_logger, LOG_ERR,
78403150 284 CFSTR("<%p:%d> unknown event type : %p"),
5e9ce69e
A
285 c,
286 xpc_connection_get_pid(c),
287 type);
288 }
9de8ab86
A
289
290 os_activity_end(activity_id);
5e9ce69e
A
291 });
292
293 xpc_connection_resume(c);
294
295 return;
296}
297
298
299#pragma mark -
300#pragma mark Network Information server SPIs
301
302
303__private_extern__
304void
305load_NetworkInformation(CFBundleRef bundle,
306 SCLoggerRef logger,
5e9ce69e
A
307 _nwi_sync_handler_t syncHandler)
308{
309 xpc_connection_t c;
310 const char *name;
311
5e9ce69e
A
312 S_logger = logger;
313
314 /*
315 * keep track of Network information acknowledgements
316 */
317 _libSC_info_server_init(&S_nwi_info);
318
319 /*
320 * save the in-sync/not-in-sync handler
321 */
322 S_sync_handler = Block_copy(syncHandler);
323
324 // create XPC listener
325 name = getenv(NWI_SERVICE_NAME);
326 if (name == NULL) {
327 name = NWI_SERVICE_NAME;
328 }
329
330 c = xpc_connection_create_mach_service(name,
331 _nwi_state_server_queue(),
332 XPC_CONNECTION_MACH_SERVICE_LISTENER);
333
334 xpc_connection_set_event_handler(c, ^(xpc_object_t event) {
9de8ab86 335 os_activity_t activity_id;
5e9ce69e
A
336 xpc_type_t type;
337
9de8ab86
A
338 activity_id = os_activity_start("processing nwi connection",
339 OS_ACTIVITY_FLAG_DEFAULT);
340
5e9ce69e
A
341 type = xpc_get_type(event);
342 if (type == XPC_TYPE_CONNECTION) {
343 process_new_connection(event);
344
345 } else if (type == XPC_TYPE_ERROR) {
346 const char *desc;
347
348 desc = xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION);
349 if (event == XPC_ERROR_CONNECTION_INVALID) {
350 SCLoggerLog(S_logger, LOG_ERR, CFSTR("Network information server: %s"), desc);
351 xpc_release(c);
352 } else if (event == XPC_ERROR_CONNECTION_INTERRUPTED) {
353 SCLoggerLog(S_logger, LOG_ERR, CFSTR("Network information server: %s"), desc);
354 } else {
355 SCLoggerLog(S_logger, LOG_ERR,
78403150 356 CFSTR("Network information server: Connection error: %p : %s"),
5e9ce69e
A
357 event,
358 desc);
359 }
360
361 } else {
362 SCLoggerLog(S_logger, LOG_ERR,
78403150 363 CFSTR("Network information server: unknown event type : %p"),
5e9ce69e
A
364 type);
365
366 }
9de8ab86
A
367
368 os_activity_end(activity_id);
5e9ce69e
A
369 });
370
371 xpc_connection_resume(c);
372
373SCLoggerLog(S_logger, LOG_DEBUG, CFSTR("XPC server \"%s\" started"), name);
374
375 return;
376}
377
378
5e9ce69e
A
379__private_extern__
380_Bool
381_nwi_state_store(nwi_state *state)
382{
383 Boolean in_sync;
384 uint64_t new_generation = 0;
385 CFDataRef new_nwi_info = NULL;
386 const char *notify_key;
387
388 if (state != NULL) {
389 const UInt8 *bytes;
390 CFIndex len;
391
392 new_generation = state->generation_count;
393
9de8ab86
A
394 SCLoggerLog(S_logger, LOG_DEBUG, CFSTR("Network information updated: %llu"),
395 new_generation);
5e9ce69e
A
396
397 bytes = (const UInt8 *)state;
9de8ab86 398 len = nwi_state_size(state);
5e9ce69e
A
399
400 new_nwi_info = CFDataCreate(NULL, bytes, len);
401 }
402
403 dispatch_sync(_nwi_state_server_queue(), ^{
404 _libSC_info_server_set_data(&S_nwi_info, new_nwi_info, new_generation);
405 });
406
407 if (new_nwi_info != NULL) {
408 CFRelease(new_nwi_info);
409 }
410
411 // if anyone is keeping us in sync, they now need to catchup
412 in_sync = _libSC_info_server_in_sync(&S_nwi_info);
413 S_sync_handler(in_sync);
414
415 // and let everyone else know that the configuration has been updated
416 notify_key = nwi_state_get_notify_key();
417 if (notify_key != NULL) {
418 uint32_t status;
419
420 _nwi_state_force_refresh();
421 status = notify_post(notify_key);
422 if (status != NOTIFY_STATUS_OK) {
423 SCLoggerLog(S_logger, LOG_ERR, CFSTR("notify_post() failed: %d"), status);
424 // notification posting failures are non-fatal
425 }
426 }
427
428 return TRUE;
429}
430
431
432#pragma mark -
433#pragma mark Testing
434
435
436#ifdef MAIN
437
438int
439main(int argc, char **argv)
440{
441 static Boolean verbose = (argc > 1) ? TRUE : FALSE;
442 // _sc_log = FALSE;
443 _sc_verbose = (argc > 1) ? TRUE : FALSE;
444 _sc_debug = TRUE;
445
446 load_NetworkInformation(CFBundleGetMainBundle(), // bundle
447 NULL, // SCLogger
5e9ce69e
A
448 ^(Boolean inSync) { // sync handler
449 SCLoggerLog(NULL, LOG_INFO,
9de8ab86
A
450 CFSTR("in sync: %s"),
451 inSync ? "Yes" : "No");
5e9ce69e
A
452 });
453 CFRunLoopRun();
454 /* not reached */
455 exit(0);
456 return 0;
457}
458
459#endif /* MAIN */