this repo has no description
at fixPythonPipStalling 591 lines 14 kB view raw
1/* 2 * Copyright (c) 2012-2018 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 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. 12 * 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. 20 * 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 <os/state_private.h> 35#include <CommonCrypto/CommonDigest.h> 36#include <CoreFoundation/CoreFoundation.h> 37#include <SystemConfiguration/SCPrivate.h> 38 39#include "libSystemConfiguration_client.h" 40#include "libSystemConfiguration_server.h" 41 42#include <network_information.h> 43#include "network_information_internal.h" 44#include "network_information_server.h" 45#include "network_state_information_priv.h" 46 47#if !TARGET_OS_SIMULATOR 48#include "agent-monitor.h" 49#include "configAgentDefines.h" 50#include "network_config_agent_info_priv.h" 51#endif // !TARGET_OS_SIMULATOR 52 53#ifdef SC_LOG_HANDLE 54#include <os/log.h> 55os_log_t SC_LOG_HANDLE(void); 56#endif //SC_LOG_HANDLE 57 58 59#pragma mark - 60#pragma mark Globals 61 62 63/* 64 * S_nwi_info 65 * 66 * Note: all accesses should be made while running on the _nwi_server_queue() 67 */ 68static libSC_info_server_t S_nwi_info; 69 70 71/* 72 * S_sync_handler 73 * ACK (in-sync or not-in-sync) updates should be posted using 74 * this handler 75 * 76 * Note: all accesses should be made while running on the _nwi_server_queue() 77 */ 78static _nwi_sync_handler_t S_sync_handler = NULL; 79 80 81#pragma mark - 82#pragma mark Support functions 83 84 85#pragma mark - 86#pragma mark Network information server "main" 87 88 89static dispatch_queue_t 90_nwi_state_server_queue() 91{ 92 static dispatch_once_t once; 93 static dispatch_queue_t q; 94 95 dispatch_once(&once, ^{ 96 q = dispatch_queue_create(NWI_SERVICE_NAME ".server", NULL); 97 }); 98 99 return q; 100} 101 102 103/* 104 * _nwi_state_copy 105 * 106 * Called when a client wants a copy of the current 107 * Network information 108 * 109 * - caller must be running on the _nwi_server_queue() 110 */ 111static void 112_nwi_state_copy(xpc_connection_t connection, xpc_object_t request) 113{ 114 CFDataRef data; 115 uint64_t generation; 116 const char *proc_name; 117 xpc_connection_t remote; 118 xpc_object_t reply; 119 120 remote = xpc_dictionary_get_remote_connection(request); 121 reply = xpc_dictionary_create_reply(request); 122 if (reply == NULL) { 123 SC_log(LOG_ERR, "<%p> _nwi_state_copy: xpc_dictionary_create_reply: failed", 124 connection); 125 return; 126 } 127 128 // extract data and generation # 129 data = _libSC_info_server_get_data(&S_nwi_info, connection, &generation); 130 131 // extract process name 132 proc_name = xpc_dictionary_get_string(request, NWI_PROC_NAME); 133 if (proc_name == NULL) { 134 proc_name = "???"; 135 } 136 137 SC_log(LOG_DEBUG, "<%p:%s[%d]> Network information copy: %llu", 138 connection, 139 proc_name, 140 xpc_connection_get_pid(connection), 141 generation); 142 143 // return the Network information (if available) 144 if (data != NULL) { 145 xpc_dictionary_set_data(reply, 146 NWI_CONFIGURATION, 147 CFDataGetBytePtr(data), 148 CFDataGetLength(data)); 149 } 150 151 // reply 152 xpc_connection_send_message(remote, reply); 153 xpc_release(reply); 154 155 return; 156} 157 158 159/* 160 * _nwi_state_acknowledge 161 * 162 * Called when a client wants to acknowledge processing 163 * of the Network information 164 * 165 * - caller must be running on the _nwi_server_queue() 166 */ 167static void 168_nwi_state_acknowledge(xpc_connection_t connection, xpc_object_t request) 169{ 170 Boolean changed; 171 uint64_t generation; 172 173 generation = xpc_dictionary_get_uint64(request, NWI_GENERATION); 174 175 SC_log(LOG_DEBUG, "<%p:%d> Network information ack: %llu", 176 connection, 177 xpc_connection_get_pid(connection), 178 generation); 179 180 changed = _libSC_info_server_acknowledged(&S_nwi_info, connection, generation); 181 if (changed) { 182 Boolean inSync; 183 184 // report change 185 inSync = _libSC_info_server_in_sync(&S_nwi_info); 186 if (S_sync_handler != NULL) { 187 S_sync_handler(inSync); 188 } 189 } 190 191 return; 192} 193 194#if !TARGET_OS_SIMULATOR 195/* 196 * _nwi_config_agent_copy 197 * 198 * Called when a client wants a copy of the agent data 199 * 200 * - caller must be running on the _nwi_server_queue() 201 */ 202static void 203_nwi_config_agent_copy(xpc_connection_t connection, xpc_object_t request) 204{ 205 const void *buffer = NULL; 206 const char *proc_name = NULL; 207 uint64_t length = 0; 208 xpc_connection_t remote; 209 xpc_object_t reply = NULL; 210 211 remote = xpc_dictionary_get_remote_connection(request); 212 reply = xpc_dictionary_create_reply(request); 213 214 uuid_t agent_uuid; 215 const uint8_t *agent_uuid_value = xpc_dictionary_get_uuid(request, kConfigAgentAgentUUID); 216 if (agent_uuid_value != NULL) { 217 uuid_copy(agent_uuid, agent_uuid_value); 218 } else { 219 goto done; 220 } 221 222 const char *agent_type = xpc_dictionary_get_string(request, kConfigAgentType); 223 if (agent_type == NULL) { 224 goto done; 225 } 226 227 proc_name = xpc_dictionary_get_string(request, NWI_PROC_NAME); 228 if (proc_name == NULL) { 229 proc_name = "???"; 230 } 231 232 SC_log(LOG_DEBUG, "<%p:%s[%d]> Config agent information copy", 233 connection, 234 proc_name, 235 xpc_connection_get_pid(connection)); 236 237 if (strcmp(agent_type, kConfigAgentTypeDNS) == 0) { 238 buffer = copy_dns_information_for_agent_uuid(agent_uuid, &length); 239 } else if (strcmp(agent_type, kConfigAgentTypeProxy) == 0) { 240 buffer = copy_proxy_information_for_agent_uuid(agent_uuid, &length); 241 } 242 243 if (buffer != NULL && length > 0) { 244 xpc_dictionary_set_data(reply, 245 kConfigAgentAgentData, 246 buffer, 247 (size_t)length); 248 } 249 250 xpc_connection_send_message(remote, reply); 251 252done: 253 if (reply != NULL) { 254 xpc_release(reply); 255 } 256 257 if (buffer != NULL) { 258 free((void *)buffer); 259 } 260 261 return; 262} 263#endif // !TARGET_OS_SIMULATOR 264 265 266static void 267process_request(xpc_connection_t connection, xpc_object_t request) 268{ 269 int64_t op; 270 271 op = xpc_dictionary_get_int64(request, NWI_REQUEST); 272 switch (op) { 273 case NWI_STATE_REQUEST_COPY : 274 /* 275 * Return the Network information 276 */ 277 _nwi_state_copy(connection, request); 278 break; 279 280 case NWI_STATE_REQUEST_ACKNOWLEDGE : 281 /* 282 * Acknowlege a [processed] Network information 283 */ 284 _nwi_state_acknowledge(connection, request); 285 286 break; 287#if !TARGET_OS_SIMULATOR 288 case NWI_CONFIG_AGENT_REQUEST_COPY : 289 /* 290 * Return the agent information 291 */ 292 _nwi_config_agent_copy(connection, request); 293 294 break; 295#endif // !TARGET_OS_SIMULATOR 296 default : 297 SC_log(LOG_ERR, "<%p> unknown request : %lld", 298 connection, 299 op); 300 301 break; 302 } 303 304 return; 305} 306 307 308static void 309process_new_connection(xpc_connection_t c) 310{ 311 SC_log(LOG_DEBUG, "<%p:%d> Network information session: open", 312 c, 313 xpc_connection_get_pid(c)); 314 315 _libSC_info_server_open(&S_nwi_info, c); 316 317 xpc_connection_set_target_queue(c, _nwi_state_server_queue()); 318 319 xpc_connection_set_event_handler(c, ^(xpc_object_t xobj) { 320 xpc_type_t type; 321 322 type = xpc_get_type(xobj); 323 if (type == XPC_TYPE_DICTIONARY) { 324 // process the request 325 process_request(c, xobj); 326 327 } else if (type == XPC_TYPE_ERROR) { 328 const char *desc; 329 330 desc = xpc_dictionary_get_string(xobj, XPC_ERROR_KEY_DESCRIPTION); 331 if (xobj == XPC_ERROR_CONNECTION_INVALID) { 332 Boolean changed; 333 334 SC_log(LOG_DEBUG, "<%p:%d> Network information session: close", 335 c, 336 xpc_connection_get_pid(c)); 337 338 changed = _libSC_info_server_close(&S_nwi_info, c); 339 if (changed) { 340 Boolean inSync; 341 342 // report change 343 inSync = _libSC_info_server_in_sync(&S_nwi_info); 344 if (S_sync_handler != NULL) { 345 S_sync_handler(inSync); 346 } 347 } 348 349 } else if (xobj == XPC_ERROR_CONNECTION_INTERRUPTED) { 350 SC_log(LOG_ERR, "<%p:%d> %s", 351 c, 352 xpc_connection_get_pid(c), 353 desc); 354 355 } else { 356 SC_log(LOG_ERR, "<%p:%d> Connection error: %p : %s", 357 c, 358 xpc_connection_get_pid(c), 359 xobj, 360 desc); 361 } 362 363 } else { 364 SC_log(LOG_ERR, "<%p:%d> unknown event type : %p", 365 c, 366 xpc_connection_get_pid(c), 367 type); 368 } 369 }); 370 371 xpc_connection_resume(c); 372 373 return; 374} 375 376 377#pragma mark - 378#pragma mark Network information state 379 380 381static void 382add_state_handler() 383{ 384#if !TARGET_OS_SIMULATOR 385 os_state_block_t state_block; 386 os_state_handle_t state_handle; 387 388 state_block = ^os_state_data_t(os_state_hints_t hints) { 389#pragma unused(hints) 390 os_state_data_t state_data; 391 size_t state_data_size; 392 CFIndex state_len; 393 394 state_len = (S_nwi_info.data != NULL) ? CFDataGetLength(S_nwi_info.data) : 0; 395 state_data_size = OS_STATE_DATA_SIZE_NEEDED(state_len); 396 if (state_data_size > MAX_STATEDUMP_SIZE) { 397 SC_log(LOG_ERR, "Network information : state data too large (%zd > %zd)", 398 state_data_size, 399 (size_t)MAX_STATEDUMP_SIZE); 400 return NULL; 401 } 402 403 state_data = calloc(1, state_data_size); 404 if (state_data == NULL) { 405 SC_log(LOG_ERR, "Network information: could not allocate state data"); 406 return NULL; 407 } 408 409 state_data->osd_type = OS_STATE_DATA_CUSTOM; 410 state_data->osd_data_size = (uint32_t)state_len; 411 strlcpy(state_data->osd_decoder.osdd_library, 412 "SystemConfiguration", 413 sizeof(state_data->osd_decoder.osdd_library)); 414 strlcpy(state_data->osd_decoder.osdd_type, 415 "nwi", 416 sizeof(state_data->osd_decoder.osdd_type)); 417 strlcpy(state_data->osd_title, "Network information", sizeof(state_data->osd_title)); 418 if (state_len > 0) { 419 memcpy(state_data->osd_data, CFDataGetBytePtr(S_nwi_info.data), state_len); 420 } 421 422 return state_data; 423 }; 424 425 state_handle = os_state_add_handler(_nwi_state_server_queue(), state_block); 426 if (state_handle == 0) { 427 SC_log(LOG_ERR, "Network information: os_state_add_handler() failed"); 428 } 429#endif // !TARGET_OS_SIMULATOR 430 431 432 return; 433} 434 435 436#pragma mark - 437#pragma mark Network information server SPIs 438 439 440__private_extern__ 441void 442load_NetworkInformation(CFBundleRef bundle, 443 _nwi_sync_handler_t syncHandler) 444{ 445#pragma unused(bundle) 446 xpc_connection_t c; 447 const char *name; 448 449 /* 450 * keep track of Network information acknowledgements 451 */ 452 _libSC_info_server_init(&S_nwi_info); 453 454 /* 455 * add a state dump handler 456 */ 457 add_state_handler(); 458 459 /* 460 * save the in-sync/not-in-sync handler 461 */ 462 S_sync_handler = Block_copy(syncHandler); 463 464 // create XPC listener 465 name = getenv(NWI_SERVICE_NAME); 466 if (name == NULL) { 467 name = NWI_SERVICE_NAME; 468 } 469 470 c = xpc_connection_create_mach_service(name, 471 _nwi_state_server_queue(), 472 XPC_CONNECTION_MACH_SERVICE_LISTENER); 473 474 xpc_connection_set_event_handler(c, ^(xpc_object_t event) { 475 xpc_type_t type; 476 477 type = xpc_get_type(event); 478 if (type == XPC_TYPE_CONNECTION) { 479 process_new_connection(event); 480 481 } else if (type == XPC_TYPE_ERROR) { 482 const char *desc; 483 484 desc = xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION); 485 if (event == XPC_ERROR_CONNECTION_INVALID) { 486 SC_log(LOG_ERR, "Network information server: %s", desc); 487 xpc_release(c); 488 } else if (event == XPC_ERROR_CONNECTION_INTERRUPTED) { 489 SC_log(LOG_ERR, "Network information server: %s", desc); 490 } else { 491 SC_log(LOG_ERR, "Network information server: Connection error: %p : %s", 492 event, 493 desc); 494 } 495 496 } else { 497 SC_log(LOG_ERR, "Network information server: unknown event type : %p", type); 498 499 } 500 }); 501 502 xpc_connection_resume(c); 503 504SC_log(LOG_DEBUG, "XPC server \"%s\" started", name); 505 506 return; 507} 508 509 510__private_extern__ 511_Bool 512_nwi_state_store(nwi_state *state) 513{ 514 Boolean in_sync; 515 uint64_t new_generation = 0; 516 CFDataRef new_nwi_info = NULL; 517 const char *notify_key; 518 519 if (state != NULL) { 520 const UInt8 *bytes; 521 CFIndex len; 522 523 new_generation = state->generation_count; 524 525 SC_log(LOG_DEBUG, "Network information updated: %llu", 526 new_generation); 527 528 bytes = (const UInt8 *)state; 529 len = nwi_state_size(state); 530 531 new_nwi_info = CFDataCreate(NULL, bytes, len); 532 } 533 534 dispatch_sync(_nwi_state_server_queue(), ^{ 535 _libSC_info_server_set_data(&S_nwi_info, new_nwi_info, new_generation); 536 }); 537 538 if (new_nwi_info != NULL) { 539 CFRelease(new_nwi_info); 540 } 541 542 // if anyone is keeping us in sync, they now need to catchup 543 in_sync = _libSC_info_server_in_sync(&S_nwi_info); 544 if (S_sync_handler != NULL) { 545 S_sync_handler(in_sync); 546 } 547 548 // and let everyone else know that the configuration has been updated 549 notify_key = nwi_state_get_notify_key(); 550 if (notify_key != NULL) { 551 uint32_t status; 552 553 _nwi_state_force_refresh(); 554 status = notify_post(notify_key); 555 if (status != NOTIFY_STATUS_OK) { 556 SC_log(LOG_ERR, "notify_post() failed: %d", status); 557 // notification posting failures are non-fatal 558 } 559 } 560 561 return TRUE; 562} 563 564 565#pragma mark - 566#pragma mark Testing 567 568 569#ifdef MAIN 570 571int 572main(int argc, char **argv) 573{ 574 static Boolean verbose = (argc > 1) ? TRUE : FALSE; 575// _sc_log = FALSE; 576 _sc_verbose = (argc > 1) ? TRUE : FALSE; 577 _sc_debug = TRUE; 578 579 load_NetworkInformation(CFBundleGetMainBundle(), // bundle 580 ^(Boolean inSync) { // sync handler 581 SC_log(LOG_INFO, 582 "in sync: %s", 583 inSync ? "Yes" : "No") 584 }); 585 CFRunLoopRun(); 586 /* not reached */ 587 exit(0); 588 return 0; 589} 590 591#endif /* MAIN */