this repo has no description
at fixPythonPipStalling 349 lines 8.8 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#include <TargetConditionals.h> 25#include <dispatch/dispatch.h> 26#include <vproc.h> 27#include <vproc_priv.h> 28#include <xpc/xpc.h> 29#include <xpc/private.h> 30 31#include <CoreFoundation/CoreFoundation.h> 32#include <SystemConfiguration/SCPrivate.h> 33#include "libSystemConfiguration_server.h" 34 35#define kTrailingEdgeAgentEntitlement "com.apple.SystemConfiguration.trailing-edge-agent" 36 37#ifdef SC_LOG_HANDLE 38#include <os/log.h> 39os_log_t SC_LOG_HANDLE(void); 40#endif //SC_LOG_HANDLE 41 42 43#pragma mark - 44#pragma mark client connection trackng 45 46 47typedef struct { 48 xpc_connection_t connection; 49} client_key_t; 50 51typedef struct { 52 pid_t pid; 53 uint64_t generation_pushed; 54 uint64_t generation_acknowledged; 55} client_val_t; 56 57 58static __inline__ CF_RETURNS_RETAINED CFDataRef 59_client_key(xpc_connection_t c) 60{ 61 client_key_t key; 62 CFDataRef client_key; 63 64 key.connection = c; 65 client_key = CFDataCreate(NULL, (UInt8 *)&key, sizeof(key)); 66 return client_key; 67} 68 69 70static void 71_handle_entitlement_check_failure(pid_t pid) 72{ 73 static Boolean cleanupScheduled = FALSE; 74 static dispatch_once_t initializer = 0; 75 static CFMutableArrayRef pids = NULL; 76 static dispatch_queue_t queue = NULL; 77 78 dispatch_once(&initializer, ^{ 79 pids = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); 80 queue = dispatch_queue_create("handle unentitled ack", NULL); 81 }); 82 83 dispatch_sync(queue, ^{ 84 CFNumberRef pidNumber = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &pid); 85 86 if (!CFArrayContainsValue(pids, CFRangeMake(0, CFArrayGetCount(pids)), pidNumber)) { 87 CFArrayAppendValue(pids, pidNumber); 88 89 SC_log(LOG_INFO, "DNS/nwi dropping ack w/no entitlement, pid = %d", pid); 90 91 if (!cleanupScheduled) { 92 cleanupScheduled = TRUE; 93 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 180LL * NSEC_PER_SEC), queue, ^{ 94 CFArrayRemoveAllValues(pids); 95 cleanupScheduled = FALSE; 96 }); 97 } 98 } 99 100 CFRelease(pidNumber); 101 }); 102} 103 104 105/* 106 * libSystemConfiguraiton_client 107 * 108 * - all APIs must be called from the same [serial] dispatch queue 109 */ 110 111 112__private_extern__ 113void 114_libSC_info_server_init(libSC_info_server_t *server_info) { 115 memset(server_info, 0, sizeof(*server_info)); 116 server_info->info = CFDictionaryCreateMutable(NULL, 117 0, 118 &kCFTypeDictionaryKeyCallBacks, 119 &kCFTypeDictionaryValueCallBacks); 120 return; 121} 122 123 124__private_extern__ 125void 126_libSC_info_server_set_data(libSC_info_server_t *server_info, 127 CFDataRef data, 128 uint64_t generation) 129{ 130 // update stored configuration 131 if (server_info->data != NULL) { 132 CFRelease(server_info->data); 133 server_info->data = NULL; 134 } 135 if (data != NULL) { 136 CFRetain(data); 137 server_info->data = data; 138 } 139 140 // update generation 141 if (generation == 0) { 142 // generation must be non-zero 143 generation = 1; 144 } 145 server_info->generation = generation; 146 147 // new configuration, all ack'ing clients need to 148 // check-in again 149 server_info->inSync_NO += server_info->inSync_YES; 150 server_info->inSync_YES = 0; 151 152 return; 153} 154 155 156/* 157 * _libSC_info_server_in_sync 158 * 159 * Called to check if all of the "active" configuration [XPC] connection 160 * are in sync with the requested generation. 161 */ 162__private_extern__ 163Boolean 164_libSC_info_server_in_sync(libSC_info_server_t *server_info) 165{ 166 return (server_info->inSync_NO == 0) ? TRUE : FALSE; 167} 168 169 170/* 171 * _libSC_info_server_open 172 * 173 * Called when a new configuration [XPC] connection 174 * is established. 175 * 176 * - tracks the last generation pushed to the caller and 177 * the last generation ack'd by the caller 178 */ 179__private_extern__ 180void 181_libSC_info_server_open(libSC_info_server_t *server_info, 182 xpc_connection_t c) 183{ 184 CFDataRef client_key; 185 CFMutableDataRef client_val; 186 client_val_t *val; 187 188 client_key = _client_key(c); 189 190 client_val = CFDataCreateMutable(NULL, sizeof(*val)); 191 CFDataSetLength(client_val, sizeof(*val)); 192 193 val = (client_val_t *)(void *)CFDataGetMutableBytePtr(client_val); 194 val->pid = xpc_connection_get_pid(c); 195 val->generation_pushed = 0; 196 val->generation_acknowledged = 0; 197 198 CFDictionarySetValue(server_info->info, client_key, client_val); 199 CFRelease(client_key); 200 CFRelease(client_val); 201 202 return; 203} 204 205 206/* 207 * _libSC_info_server_get_data 208 * 209 * Called when a [XPC] connection wants the current configuration. 210 * 211 * - updates the last generation pushed to the caller 212 */ 213__private_extern__ 214CFDataRef 215_libSC_info_server_get_data(libSC_info_server_t *server_info, 216 xpc_connection_t c, 217 uint64_t *generation) 218{ 219 CFDataRef client_key; 220 CFMutableDataRef client_val; 221 client_val_t *val; 222 223 // update last generation pushed to client 224 client_key = _client_key(c); 225 client_val = (CFMutableDataRef)CFDictionaryGetValue(server_info->info, client_key); 226 CFRelease(client_key); 227 228 val = (client_val_t *)(void *)CFDataGetMutableBytePtr(client_val); 229 val->generation_pushed = server_info->generation; 230 231 // return generation 232 *generation = server_info->generation; 233 if (*generation == 1) { 234 *generation = 0; 235 } 236 237 // return data 238 return server_info->data; 239} 240 241 242/* 243 * _libSC_info_server_acknowledged 244 * 245 * Called when a [XPC] connection wants to acknowledge a 246 * processed configuration. 247 * 248 * - updates the last generation ack'd by the caller 249 * - updates the count of [XPC] connections that are / not in sync 250 */ 251__private_extern__ 252Boolean 253_libSC_info_server_acknowledged(libSC_info_server_t *server_info, 254 xpc_connection_t c, 255 uint64_t generation) 256{ 257 CFDataRef client_key; 258 CFMutableDataRef client_val; 259 xpc_object_t ent_value; 260 Boolean entitled = FALSE; 261 Boolean sync_updated = FALSE; 262 client_val_t *val; 263 264 ent_value = xpc_connection_copy_entitlement_value(c, kTrailingEdgeAgentEntitlement); 265 if (ent_value != NULL) { 266 if (xpc_get_type(ent_value) == XPC_TYPE_BOOL) { 267 entitled = xpc_bool_get_value(ent_value); 268 } 269 xpc_release(ent_value); 270 } 271 272 if (!entitled) { 273 _handle_entitlement_check_failure(xpc_connection_get_pid(c)); 274 return FALSE; 275 } 276 277 client_key = _client_key(c); 278 client_val = (CFMutableDataRef)CFDictionaryGetValue(server_info->info, client_key); 279 CFRelease(client_key); 280 281 val = (client_val_t *)(void *)CFDataGetMutableBytePtr(client_val); 282 283 if (val->generation_acknowledged == 0) { 284 // if first ack 285 if (generation == server_info->generation) { 286 server_info->inSync_YES++; 287 } else { 288 server_info->inSync_NO++; 289 sync_updated = TRUE; 290 } 291 } else if ((generation != val->generation_acknowledged) && 292 (generation == server_info->generation)) { 293 // if we've previously ack'd a configuration 294 // ... and if we are ack'ing a configuration 295 // that we have not previously ack'd 296 // ... and if we're ack'ing the current stored 297 // configuration 298 server_info->inSync_NO--; 299 server_info->inSync_YES++; 300 sync_updated = TRUE; 301 } 302 303 val->generation_acknowledged = generation; 304 305 return sync_updated; 306} 307 308 309/* 310 * _libSC_info_server_close 311 * 312 * Called when a configuration [XPC] connection is closed. 313 */ 314__private_extern__ 315Boolean 316_libSC_info_server_close(libSC_info_server_t *server_info, 317 xpc_connection_t c) 318{ 319 CFDataRef client_key; 320 CFMutableDataRef client_val; 321 Boolean sync_updated = FALSE; 322 323 client_key = _client_key(c); 324 325 // get client info, remove ack'd info 326 client_val = (CFMutableDataRef)CFDictionaryGetValue(server_info->info, client_key); 327 if (client_val != NULL) { 328 client_val_t *val; 329 330 val = (client_val_t *)(void *)CFDataGetMutableBytePtr(client_val); 331 if (val->generation_acknowledged > 0) { 332 // if we've previously ack'd a configuration 333 if (val->generation_acknowledged == server_info->generation) { 334 // if currently in sync 335 server_info->inSync_YES--; 336 } else { 337 // if currently NOT in sync 338 server_info->inSync_NO--; 339 sync_updated = TRUE; 340 } 341 } 342 } 343 344 CFDictionaryRemoveValue(server_info->info, client_key); 345 CFRelease(client_key); 346 347 return sync_updated; 348} 349