2 * Copyright (c) 2012-2016 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 * Modification History
27 * February 8, 2012 Allan Nathanson <ajn@apple.com>
32 #include <dispatch/dispatch.h>
34 #include <CommonCrypto/CommonDigest.h>
35 #include <CoreFoundation/CoreFoundation.h>
36 #include <SystemConfiguration/SCPrivate.h>
38 #include "libSystemConfiguration_client.h"
39 #include "libSystemConfiguration_server.h"
41 #include <network_information.h>
42 #include "network_state_information_priv.h"
43 #include "network_information_server.h"
45 #if !TARGET_OS_SIMULATOR
46 #include "agent-monitor.h"
47 #include "configAgentDefines.h"
48 #include "network_config_agent_info_priv.h"
49 #endif // !TARGET_OS_SIMULATOR
53 os_log_t SC_LOG_HANDLE
;
54 #endif //SC_LOG_HANDLE
64 * Note: all accesses should be made while running on the _nwi_server_queue()
66 static libSC_info_server_t S_nwi_info
;
71 * ACK (in-sync or not-in-sync) updates should be posted using
74 * Note: all accesses should be made while running on the _nwi_server_queue()
76 static _nwi_sync_handler_t S_sync_handler
= NULL
;
80 #pragma mark Support functions
84 #pragma mark Network information server "main"
87 static dispatch_queue_t
88 _nwi_state_server_queue()
90 static dispatch_once_t once
;
91 static dispatch_queue_t q
;
93 dispatch_once(&once
, ^{
94 q
= dispatch_queue_create(NWI_SERVICE_NAME
".server", NULL
);
104 * Called when a client wants a copy of the current
105 * Network information
107 * - caller must be running on the _nwi_server_queue()
110 _nwi_state_copy(xpc_connection_t connection
, xpc_object_t request
)
114 const char *proc_name
;
115 xpc_connection_t remote
;
118 remote
= xpc_dictionary_get_remote_connection(request
);
119 reply
= xpc_dictionary_create_reply(request
);
121 SC_log(LOG_ERR
, "<%p> _nwi_state_copy: xpc_dictionary_create_reply: failed",
126 // extract data and generation #
127 data
= _libSC_info_server_get_data(&S_nwi_info
, connection
, &generation
);
129 // extract process name
130 proc_name
= xpc_dictionary_get_string(request
, NWI_PROC_NAME
);
131 if (proc_name
== NULL
) {
135 SC_log(LOG_DEBUG
, "<%p:%s[%d]> Network information copy: %llu",
138 xpc_connection_get_pid(connection
),
141 // return the Network information (if available)
143 xpc_dictionary_set_data(reply
,
145 CFDataGetBytePtr(data
),
146 CFDataGetLength(data
));
150 xpc_connection_send_message(remote
, reply
);
158 * _nwi_state_acknowledge
160 * Called when a client wants to acknowledge processing
161 * of the Network information
163 * - caller must be running on the _nwi_server_queue()
166 _nwi_state_acknowledge(xpc_connection_t connection
, xpc_object_t request
)
171 generation
= xpc_dictionary_get_uint64(request
, NWI_GENERATION
);
173 SC_log(LOG_DEBUG
, "<%p:%d> Network information ack: %llu",
175 xpc_connection_get_pid(connection
),
178 changed
= _libSC_info_server_acknowledged(&S_nwi_info
, connection
, generation
);
183 inSync
= _libSC_info_server_in_sync(&S_nwi_info
);
184 if (S_sync_handler
!= NULL
) {
185 S_sync_handler(inSync
);
192 #if !TARGET_OS_SIMULATOR
194 * _nwi_config_agent_copy
196 * Called when a client wants a copy of the agent data
198 * - caller must be running on the _nwi_server_queue()
201 _nwi_config_agent_copy(xpc_connection_t connection
, xpc_object_t request
)
203 const void *buffer
= NULL
;
204 const char *proc_name
= NULL
;
206 xpc_connection_t remote
;
207 xpc_object_t reply
= NULL
;
209 remote
= xpc_dictionary_get_remote_connection(request
);
210 reply
= xpc_dictionary_create_reply(request
);
213 const uint8_t *agent_uuid_value
= xpc_dictionary_get_uuid(request
, kConfigAgentAgentUUID
);
214 if (agent_uuid_value
!= NULL
) {
215 uuid_copy(agent_uuid
, agent_uuid_value
);
220 const char *agent_type
= xpc_dictionary_get_string(request
, kConfigAgentType
);
221 if (agent_type
== NULL
) {
225 proc_name
= xpc_dictionary_get_string(request
, NWI_PROC_NAME
);
226 if (proc_name
== NULL
) {
230 SC_log(LOG_DEBUG
, "<%p:%s[%d]> Config agent information copy",
233 xpc_connection_get_pid(connection
));
235 if (strcmp(agent_type
, kConfigAgentTypeDNS
) == 0) {
236 buffer
= copy_dns_information_for_agent_uuid(agent_uuid
, &length
);
237 } else if (strcmp(agent_type
, kConfigAgentTypeProxy
) == 0) {
238 buffer
= copy_proxy_information_for_agent_uuid(agent_uuid
, &length
);
241 if (buffer
!= NULL
&& length
> 0) {
242 xpc_dictionary_set_data(reply
,
243 kConfigAgentAgentData
,
248 xpc_connection_send_message(remote
, reply
);
255 if (buffer
!= NULL
) {
256 free((void *)buffer
);
261 #endif // !TARGET_OS_SIMULATOR
265 process_request(xpc_connection_t connection
, xpc_object_t request
)
269 op
= xpc_dictionary_get_int64(request
, NWI_REQUEST
);
271 case NWI_STATE_REQUEST_COPY
:
273 * Return the Network information
275 _nwi_state_copy(connection
, request
);
278 case NWI_STATE_REQUEST_ACKNOWLEDGE
:
280 * Acknowlege a [processed] Network information
282 _nwi_state_acknowledge(connection
, request
);
285 #if !TARGET_OS_SIMULATOR
286 case NWI_CONFIG_AGENT_REQUEST_COPY
:
288 * Return the agent information
290 _nwi_config_agent_copy(connection
, request
);
293 #endif // !TARGET_OS_SIMULATOR
295 SC_log(LOG_ERR
, "<%p> unknown request : %lld",
307 process_new_connection(xpc_connection_t c
)
309 SC_log(LOG_DEBUG
, "<%p:%d> Network information session: open",
311 xpc_connection_get_pid(c
));
313 _libSC_info_server_open(&S_nwi_info
, c
);
315 xpc_connection_set_target_queue(c
, _nwi_state_server_queue());
317 xpc_connection_set_event_handler(c
, ^(xpc_object_t xobj
) {
320 type
= xpc_get_type(xobj
);
321 if (type
== XPC_TYPE_DICTIONARY
) {
322 // process the request
323 process_request(c
, xobj
);
325 } else if (type
== XPC_TYPE_ERROR
) {
328 desc
= xpc_dictionary_get_string(xobj
, XPC_ERROR_KEY_DESCRIPTION
);
329 if (xobj
== XPC_ERROR_CONNECTION_INVALID
) {
332 SC_log(LOG_DEBUG
, "<%p:%d> Network information session: close",
334 xpc_connection_get_pid(c
));
336 changed
= _libSC_info_server_close(&S_nwi_info
, c
);
341 inSync
= _libSC_info_server_in_sync(&S_nwi_info
);
342 if (S_sync_handler
!= NULL
) {
343 S_sync_handler(inSync
);
347 } else if (xobj
== XPC_ERROR_CONNECTION_INTERRUPTED
) {
348 SC_log(LOG_ERR
, "<%p:%d> %s",
350 xpc_connection_get_pid(c
),
354 SC_log(LOG_ERR
, "<%p:%d> Connection error: %p : %s",
356 xpc_connection_get_pid(c
),
362 SC_log(LOG_ERR
, "<%p:%d> unknown event type : %p",
364 xpc_connection_get_pid(c
),
369 xpc_connection_resume(c
);
376 #pragma mark Network Information server SPIs
381 load_NetworkInformation(CFBundleRef bundle
,
382 _nwi_sync_handler_t syncHandler
)
388 * keep track of Network information acknowledgements
390 _libSC_info_server_init(&S_nwi_info
);
393 * save the in-sync/not-in-sync handler
395 S_sync_handler
= Block_copy(syncHandler
);
397 // create XPC listener
398 name
= getenv(NWI_SERVICE_NAME
);
400 name
= NWI_SERVICE_NAME
;
403 c
= xpc_connection_create_mach_service(name
,
404 _nwi_state_server_queue(),
405 XPC_CONNECTION_MACH_SERVICE_LISTENER
);
407 xpc_connection_set_event_handler(c
, ^(xpc_object_t event
) {
410 type
= xpc_get_type(event
);
411 if (type
== XPC_TYPE_CONNECTION
) {
412 process_new_connection(event
);
414 } else if (type
== XPC_TYPE_ERROR
) {
417 desc
= xpc_dictionary_get_string(event
, XPC_ERROR_KEY_DESCRIPTION
);
418 if (event
== XPC_ERROR_CONNECTION_INVALID
) {
419 SC_log(LOG_ERR
, "Network information server: %s", desc
);
421 } else if (event
== XPC_ERROR_CONNECTION_INTERRUPTED
) {
422 SC_log(LOG_ERR
, "Network information server: %s", desc
);
424 SC_log(LOG_ERR
, "Network information server: Connection error: %p : %s",
430 SC_log(LOG_ERR
, "Network information server: unknown event type : %p", type
);
435 xpc_connection_resume(c
);
437 SC_log(LOG_DEBUG
, "XPC server \"%s\" started", name
);
445 _nwi_state_store(nwi_state
*state
)
448 uint64_t new_generation
= 0;
449 CFDataRef new_nwi_info
= NULL
;
450 const char *notify_key
;
456 new_generation
= state
->generation_count
;
458 SC_log(LOG_DEBUG
, "Network information updated: %llu",
461 bytes
= (const UInt8
*)state
;
462 len
= nwi_state_size(state
);
464 new_nwi_info
= CFDataCreate(NULL
, bytes
, len
);
467 dispatch_sync(_nwi_state_server_queue(), ^{
468 _libSC_info_server_set_data(&S_nwi_info
, new_nwi_info
, new_generation
);
471 if (new_nwi_info
!= NULL
) {
472 CFRelease(new_nwi_info
);
475 // if anyone is keeping us in sync, they now need to catchup
476 in_sync
= _libSC_info_server_in_sync(&S_nwi_info
);
477 if (S_sync_handler
!= NULL
) {
478 S_sync_handler(in_sync
);
481 // and let everyone else know that the configuration has been updated
482 notify_key
= nwi_state_get_notify_key();
483 if (notify_key
!= NULL
) {
486 _nwi_state_force_refresh();
487 status
= notify_post(notify_key
);
488 if (status
!= NOTIFY_STATUS_OK
) {
489 SC_log(LOG_ERR
, "notify_post() failed: %d", status
);
490 // notification posting failures are non-fatal
505 main(int argc
, char **argv
)
507 static Boolean verbose
= (argc
> 1) ? TRUE
: FALSE
;
509 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
512 load_NetworkInformation(CFBundleGetMainBundle(), // bundle
513 ^(Boolean inSync
) { // sync handler
516 inSync
? "Yes" : "No")