/ CFMessagePort.c
CFMessagePort.c
1 /* 2 * Copyright (c) 2015 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 /* CFMessagePort.c 25 Copyright (c) 1998-2014, Apple Inc. All rights reserved. 26 Responsibility: Christopher Kane 27 */ 28 29 #include <CoreFoundation/CFMessagePort.h> 30 #include <CoreFoundation/CFRunLoop.h> 31 #include <CoreFoundation/CFMachPort.h> 32 #include <CoreFoundation/CFDictionary.h> 33 #include <CoreFoundation/CFByteOrder.h> 34 #include <limits.h> 35 #include "CFInternal.h" 36 #include <mach/mach.h> 37 #include <mach/message.h> 38 #include <mach/mach_error.h> 39 #include <bootstrap_priv.h> 40 #include <math.h> 41 #include <mach/mach_time.h> 42 #include <dlfcn.h> 43 #include <dispatch/dispatch.h> 44 #include <dispatch/private.h> 45 46 extern pid_t getpid(void); 47 48 #define __kCFMessagePortMaxNameLengthMax 255 49 50 #if defined(BOOTSTRAP_MAX_NAME_LEN) 51 #define __kCFMessagePortMaxNameLength BOOTSTRAP_MAX_NAME_LEN 52 #else 53 #define __kCFMessagePortMaxNameLength 128 54 #endif 55 56 #if __kCFMessagePortMaxNameLengthMax < __kCFMessagePortMaxNameLength 57 #undef __kCFMessagePortMaxNameLength 58 #define __kCFMessagePortMaxNameLength __kCFMessagePortMaxNameLengthMax 59 #endif 60 61 #define __CFMessagePortMaxDataSize 0x60000000L 62 63 static CFLock_t __CFAllMessagePortsLock = CFLockInit; 64 static CFMutableDictionaryRef __CFAllLocalMessagePorts = NULL; 65 static CFMutableDictionaryRef __CFAllRemoteMessagePorts = NULL; 66 67 struct __CFMessagePort { 68 CFRuntimeBase _base; 69 CFLock_t _lock; 70 CFStringRef _name; 71 CFMachPortRef _port; /* immutable; invalidated */ 72 CFMutableDictionaryRef _replies; 73 int32_t _convCounter; 74 int32_t _perPID; /* zero if not per-pid, else pid */ 75 CFMachPortRef _replyPort; /* only used by remote port; immutable once created; invalidated */ 76 CFRunLoopSourceRef _source; /* only used by local port; immutable once created; invalidated */ 77 dispatch_source_t _dispatchSource; /* only used by local port; invalidated */ 78 dispatch_queue_t _dispatchQ; /* only used by local port */ 79 CFMessagePortInvalidationCallBack _icallout; 80 CFMessagePortCallBack _callout; /* only used by local port; immutable */ 81 CFMessagePortCallBackEx _calloutEx; /* only used by local port; immutable */ 82 CFMessagePortContext _context; /* not part of remote port; immutable; invalidated */ 83 }; 84 85 /* Bit 0 in the base reserved bits is used for invalid state */ 86 /* Bit 1 of the base reserved bits is used for has-extra-port-refs state */ 87 /* Bit 2 of the base reserved bits is used for is-remote state */ 88 /* Bit 3 in the base reserved bits is used for is-deallocing state */ 89 90 CF_INLINE Boolean __CFMessagePortIsValid(CFMessagePortRef ms) { 91 return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)ms)->_cfinfo[CF_INFO_BITS], 0, 0); 92 } 93 94 CF_INLINE void __CFMessagePortSetValid(CFMessagePortRef ms) { 95 __CFBitfieldSetValue(((CFRuntimeBase *)ms)->_cfinfo[CF_INFO_BITS], 0, 0, 1); 96 } 97 98 CF_INLINE void __CFMessagePortUnsetValid(CFMessagePortRef ms) { 99 __CFBitfieldSetValue(((CFRuntimeBase *)ms)->_cfinfo[CF_INFO_BITS], 0, 0, 0); 100 } 101 102 CF_INLINE Boolean __CFMessagePortExtraMachRef(CFMessagePortRef ms) { 103 return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)ms)->_cfinfo[CF_INFO_BITS], 1, 1); 104 } 105 106 CF_INLINE void __CFMessagePortSetExtraMachRef(CFMessagePortRef ms) { 107 __CFBitfieldSetValue(((CFRuntimeBase *)ms)->_cfinfo[CF_INFO_BITS], 1, 1, 1); 108 } 109 110 CF_INLINE void __CFMessagePortUnsetExtraMachRef(CFMessagePortRef ms) { 111 __CFBitfieldSetValue(((CFRuntimeBase *)ms)->_cfinfo[CF_INFO_BITS], 1, 1, 0); 112 } 113 114 CF_INLINE Boolean __CFMessagePortIsRemote(CFMessagePortRef ms) { 115 return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)ms)->_cfinfo[CF_INFO_BITS], 2, 2); 116 } 117 118 CF_INLINE void __CFMessagePortSetRemote(CFMessagePortRef ms) { 119 __CFBitfieldSetValue(((CFRuntimeBase *)ms)->_cfinfo[CF_INFO_BITS], 2, 2, 1); 120 } 121 122 CF_INLINE void __CFMessagePortUnsetRemote(CFMessagePortRef ms) { 123 __CFBitfieldSetValue(((CFRuntimeBase *)ms)->_cfinfo[CF_INFO_BITS], 2, 2, 0); 124 } 125 126 CF_INLINE Boolean __CFMessagePortIsDeallocing(CFMessagePortRef ms) { 127 return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)ms)->_cfinfo[CF_INFO_BITS], 3, 3); 128 } 129 130 CF_INLINE void __CFMessagePortSetIsDeallocing(CFMessagePortRef ms) { 131 __CFBitfieldSetValue(((CFRuntimeBase *)ms)->_cfinfo[CF_INFO_BITS], 3, 3, 1); 132 } 133 134 CF_INLINE void __CFMessagePortLock(CFMessagePortRef ms) { 135 __CFLock(&(ms->_lock)); 136 } 137 138 CF_INLINE void __CFMessagePortUnlock(CFMessagePortRef ms) { 139 __CFUnlock(&(ms->_lock)); 140 } 141 142 #if !defined(__LP64__) 143 #define __LP64__ 0 144 #endif 145 146 // Just a heuristic 147 #define __CFMessagePortMaxInlineBytes ((int32_t)4000) 148 149 struct __CFMessagePortMachMessage { 150 mach_msg_base_t base; 151 mach_msg_ool_descriptor_t ool; 152 struct innards { 153 int32_t magic; 154 int32_t msgid; 155 int32_t convid; 156 int32_t byteslen; 157 uint8_t bytes[0]; 158 } innards; 159 }; 160 #define __INNARD_OFFSET (((!(msgp->header.msgh_bits & MACH_MSGH_BITS_COMPLEX) && ((mach_msg_header_t *)msgp)->msgh_id == 0) || ( (msgp->header.msgh_bits & MACH_MSGH_BITS_COMPLEX) && !__LP64__)) ? 40 : 44) 161 162 #define MAGIC 0xF0F2F4F8 163 164 // These 3 macros should ONLY be used on RECEIVED messages, not ones being constructed on the sending side 165 #define MSGP_GET(msgp, ident) (((struct __CFMessagePortMachMessage *)msgp)->ident) 166 #define MSGP_INFO(msgp, ident) ((struct innards *)((void *)msgp + __INNARD_OFFSET))->ident 167 #define MSGP_SIZE(msgp) (__INNARD_OFFSET + sizeof(struct innards)) 168 169 170 static mach_msg_base_t *__CFMessagePortCreateMessage(bool reply, mach_port_t port, mach_port_t replyPort, int32_t convid, int32_t msgid, const uint8_t *bytes, int32_t byteslen) { 171 if (__CFMessagePortMaxDataSize < byteslen) return NULL; 172 if (byteslen < -1) return NULL; 173 int32_t rounded_byteslen = (byteslen < 0) ? 0 : ((byteslen + 7) & ~0x7); 174 int32_t size = (int32_t)sizeof(struct __CFMessagePortMachMessage) + ((rounded_byteslen <= __CFMessagePortMaxInlineBytes) ? rounded_byteslen : 0); 175 struct __CFMessagePortMachMessage *msg = CFAllocatorAllocate(kCFAllocatorSystemDefault, size, 0); 176 if (!msg) return NULL; 177 memset(msg, 0, size); 178 #if __LP64__ 179 msg->base.header.msgh_id = 1; 180 #else 181 msg->base.header.msgh_id = 0; 182 #endif 183 msg->base.header.msgh_size = size; 184 msg->base.header.msgh_remote_port = port; 185 msg->base.header.msgh_local_port = replyPort; 186 msg->base.header.msgh_bits = MACH_MSGH_BITS((reply ? MACH_MSG_TYPE_MOVE_SEND_ONCE : MACH_MSG_TYPE_COPY_SEND), (MACH_PORT_NULL != replyPort ? MACH_MSG_TYPE_MAKE_SEND_ONCE : 0)); 187 msg->base.body.msgh_descriptor_count = 0; 188 msg->innards.magic = MAGIC; 189 msg->innards.msgid = CFSwapInt32HostToLittle(msgid); 190 msg->innards.convid = CFSwapInt32HostToLittle(convid); 191 msg->innards.byteslen = CFSwapInt32HostToLittle(byteslen); 192 if (rounded_byteslen <= __CFMessagePortMaxInlineBytes) { 193 if (NULL != bytes && 0 < byteslen) { 194 memmove(msg->innards.bytes, bytes, byteslen); 195 } 196 } else { 197 msg->base.header.msgh_bits |= MACH_MSGH_BITS_COMPLEX; 198 msg->base.body.msgh_descriptor_count = 1; 199 msg->ool.deallocate = false; 200 msg->ool.copy = MACH_MSG_VIRTUAL_COPY; 201 msg->ool.address = (void *)bytes; 202 msg->ool.size = byteslen; 203 msg->ool.type = MACH_MSG_OOL_DESCRIPTOR; 204 } 205 return (mach_msg_base_t *)msg; 206 } 207 208 static CFStringRef __CFMessagePortCopyDescription(CFTypeRef cf) { 209 CFMessagePortRef ms = (CFMessagePortRef)cf; 210 CFStringRef result; 211 const char *locked; 212 CFStringRef contextDesc = NULL; 213 locked = "Maybe"; 214 if (__CFMessagePortIsRemote(ms)) { 215 result = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<CFMessagePort %p [%p]>{locked = %s, valid = %s, remote = %s, name = %@}"), cf, CFGetAllocator(ms), locked, (__CFMessagePortIsValid(ms) ? "Yes" : "No"), (__CFMessagePortIsRemote(ms) ? "Yes" : "No"), ms->_name); 216 } else { 217 if (NULL != ms->_context.info && NULL != ms->_context.copyDescription) { 218 contextDesc = ms->_context.copyDescription(ms->_context.info); 219 } 220 if (NULL == contextDesc) { 221 contextDesc = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<CFMessagePort context %p>"), ms->_context.info); 222 } 223 void *addr = ms->_callout ? (void *)ms->_callout : (void *)ms->_calloutEx; 224 Dl_info info; 225 const char *name = (dladdr(addr, &info) && info.dli_saddr == addr && info.dli_sname) ? info.dli_sname : "???"; 226 result = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<CFMessagePort %p [%p]>{locked = %s, valid = %s, remote = %s, name = %@, source = %p, callout = %s (%p), context = %@}"), cf, CFGetAllocator(ms), locked, (__CFMessagePortIsValid(ms) ? "Yes" : "No"), (__CFMessagePortIsRemote(ms) ? "Yes" : "No"), ms->_name, ms->_source, name, addr, (NULL != contextDesc ? contextDesc : CFSTR("<no description>"))); 227 } 228 if (NULL != contextDesc) { 229 CFRelease(contextDesc); 230 } 231 return result; 232 } 233 234 static void __CFMessagePortDeallocate(CFTypeRef cf) { 235 CFMessagePortRef ms = (CFMessagePortRef)cf; 236 __CFMessagePortSetIsDeallocing(ms); 237 CFMessagePortInvalidate(ms); 238 // Delay cleanup of _replies until here so that invalidation during 239 // SendRequest does not cause _replies to disappear out from under that function. 240 if (NULL != ms->_replies) { 241 CFRelease(ms->_replies); 242 } 243 if (NULL != ms->_name) { 244 CFRelease(ms->_name); 245 } 246 if (NULL != ms->_port) { 247 if (__CFMessagePortExtraMachRef(ms)) { 248 mach_port_mod_refs(mach_task_self(), CFMachPortGetPort(ms->_port), MACH_PORT_RIGHT_SEND, -1); 249 mach_port_mod_refs(mach_task_self(), CFMachPortGetPort(ms->_port), MACH_PORT_RIGHT_RECEIVE, -1); 250 } 251 CFMachPortInvalidate(ms->_port); 252 CFRelease(ms->_port); 253 } 254 255 // A remote message port for a local message port in the same process will get the 256 // same mach port, and the remote port will keep the mach port from being torn down, 257 // thus keeping the remote port from getting any sort of death notification and 258 // auto-invalidating; so we manually implement the 'auto-invalidation' here by 259 // tickling each remote port to check its state after any message port is destroyed, 260 // but most importantly after local message ports are destroyed. 261 __CFLock(&__CFAllMessagePortsLock); 262 CFMessagePortRef *remotePorts = NULL; 263 CFIndex cnt = 0; 264 if (NULL != __CFAllRemoteMessagePorts) { 265 cnt = CFDictionaryGetCount(__CFAllRemoteMessagePorts); 266 remotePorts = CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(CFMessagePortRef), __kCFAllocatorGCScannedMemory); 267 CFDictionaryGetKeysAndValues(__CFAllRemoteMessagePorts, NULL, (const void **)remotePorts); 268 for (CFIndex idx = 0; idx < cnt; idx++) { 269 CFRetain(remotePorts[idx]); 270 } 271 } 272 __CFUnlock(&__CFAllMessagePortsLock); 273 if (remotePorts) { 274 for (CFIndex idx = 0; idx < cnt; idx++) { 275 // as a side-effect, this will auto-invalidate the CFMessagePort if the CFMachPort is invalid 276 CFMessagePortIsValid(remotePorts[idx]); 277 CFRelease(remotePorts[idx]); 278 } 279 CFAllocatorDeallocate(kCFAllocatorSystemDefault, remotePorts); 280 } 281 } 282 283 static CFTypeID __kCFMessagePortTypeID = _kCFRuntimeNotATypeID; 284 285 static const CFRuntimeClass __CFMessagePortClass = { 286 0, 287 "CFMessagePort", 288 NULL, // init 289 NULL, // copy 290 __CFMessagePortDeallocate, 291 NULL, 292 NULL, 293 NULL, // 294 __CFMessagePortCopyDescription 295 }; 296 297 CFTypeID CFMessagePortGetTypeID(void) { 298 static dispatch_once_t initOnce; 299 dispatch_once(&initOnce, ^{ __kCFMessagePortTypeID = _CFRuntimeRegisterClass(&__CFMessagePortClass); }); 300 return __kCFMessagePortTypeID; 301 } 302 303 static CFStringRef __CFMessagePortSanitizeStringName(CFStringRef name, uint8_t **utfnamep, CFIndex *utfnamelenp) { 304 uint8_t *utfname; 305 CFIndex utflen; 306 CFStringRef result = NULL; 307 utfname = CFAllocatorAllocate(kCFAllocatorSystemDefault, __kCFMessagePortMaxNameLength + 1, 0); 308 CFStringGetBytes(name, CFRangeMake(0, CFStringGetLength(name)), kCFStringEncodingUTF8, 0, false, utfname, __kCFMessagePortMaxNameLength, &utflen); 309 utfname[utflen] = '\0'; 310 if (strlen((const char *)utfname) != utflen) { 311 /* PCA 9194709: refuse to sanitize a string with an embedded nul character */ 312 CFAllocatorDeallocate(kCFAllocatorSystemDefault, utfname); 313 utfname = NULL; 314 utfnamelenp = 0; 315 } else { 316 /* A new string is created, because the original string may have been 317 truncated to the max length, and we want the string name to definitely 318 match the raw UTF-8 chunk that has been created. Also, this is useful 319 to get a constant string in case the original name string was mutable. */ 320 result = CFStringCreateWithBytes(kCFAllocatorSystemDefault, utfname, utflen, kCFStringEncodingUTF8, false); 321 } 322 if (NULL != utfnamep) { 323 *utfnamep = utfname; 324 } else if (NULL != utfname) { 325 CFAllocatorDeallocate(kCFAllocatorSystemDefault, utfname); 326 } 327 if (NULL != utfnamelenp) { 328 *utfnamelenp = utflen; 329 } 330 return result; 331 } 332 333 static void __CFMessagePortDummyCallback(CFMachPortRef port, void *msg, CFIndex size, void *info) { 334 // not supposed to be implemented 335 } 336 337 static void __CFMessagePortInvalidationCallBack(CFMachPortRef port, void *info) { 338 // info has been setup as the CFMessagePort owning the CFMachPort 339 if (info) CFMessagePortInvalidate(info); 340 } 341 342 static CFMessagePortRef __CFMessagePortCreateLocal(CFAllocatorRef allocator, CFStringRef name, CFMessagePortCallBack callout, CFMessagePortContext *context, Boolean *shouldFreeInfo, Boolean perPID, CFMessagePortCallBackEx calloutEx) { 343 CFMessagePortRef memory; 344 uint8_t *utfname = NULL; 345 346 if (shouldFreeInfo) *shouldFreeInfo = true; 347 if (NULL != name) { 348 name = __CFMessagePortSanitizeStringName(name, &utfname, NULL); 349 } 350 __CFLock(&__CFAllMessagePortsLock); 351 if (!perPID && NULL != name) { 352 CFMessagePortRef existing; 353 if (NULL != __CFAllLocalMessagePorts && CFDictionaryGetValueIfPresent(__CFAllLocalMessagePorts, name, (const void **)&existing)) { 354 CFRetain(existing); 355 __CFUnlock(&__CFAllMessagePortsLock); 356 CFRelease(name); 357 CFAllocatorDeallocate(kCFAllocatorSystemDefault, utfname); 358 if (!CFMessagePortIsValid(existing)) { // must do this outside lock to avoid deadlock 359 CFRelease(existing); 360 existing = NULL; 361 } 362 return (CFMessagePortRef)(existing); 363 } 364 } 365 __CFUnlock(&__CFAllMessagePortsLock); 366 CFIndex size = sizeof(struct __CFMessagePort) - sizeof(CFRuntimeBase); 367 memory = (CFMessagePortRef)_CFRuntimeCreateInstance(allocator, CFMessagePortGetTypeID(), size, NULL); 368 if (NULL == memory) { 369 if (NULL != name) { 370 CFRelease(name); 371 } 372 CFAllocatorDeallocate(kCFAllocatorSystemDefault, utfname); 373 return NULL; 374 } 375 __CFMessagePortUnsetValid(memory); 376 __CFMessagePortUnsetExtraMachRef(memory); 377 __CFMessagePortUnsetRemote(memory); 378 memory->_lock = CFLockInit; 379 memory->_name = name; 380 memory->_port = NULL; 381 memory->_replies = NULL; 382 memory->_convCounter = 0; 383 memory->_perPID = perPID ? getpid() : 0; // actual value not terribly useful for local ports 384 memory->_replyPort = NULL; 385 memory->_source = NULL; 386 memory->_dispatchSource = NULL; 387 memory->_dispatchQ = NULL; 388 memory->_icallout = NULL; 389 memory->_callout = callout; 390 memory->_calloutEx = calloutEx; 391 memory->_context.info = NULL; 392 memory->_context.retain = NULL; 393 memory->_context.release = NULL; 394 memory->_context.copyDescription = NULL; 395 396 if (NULL != name) { 397 CFMachPortRef native = NULL; 398 kern_return_t ret; 399 mach_port_t bs, mp; 400 task_get_bootstrap_port(mach_task_self(), &bs); 401 if (!perPID) { 402 ret = bootstrap_check_in(bs, (char *)utfname, &mp); /* If we're started by launchd or the old mach_init */ 403 if (ret == KERN_SUCCESS) { 404 mach_port_type_t type = 0; 405 ret = mach_port_type(mach_task_self(), mp, &type); 406 if (KERN_SUCCESS != ret || (0 == (type & MACH_PORT_TYPE_PORT_RIGHTS))) { 407 CFLog(kCFLogLevelError, CFSTR("*** CFMessagePort: bootstrap_check_in() succeeded, but mach port type is unknown (err %d) or returned invalid type (0x%x); name = '%s'"), ret, type, utfname); 408 ret = KERN_INVALID_RIGHT; 409 } 410 ret = (KERN_SUCCESS == ret) ? mach_port_insert_right(mach_task_self(), mp, mp, MACH_MSG_TYPE_MAKE_SEND) : ret; 411 if (KERN_SUCCESS == ret) { 412 CFMachPortContext ctx = {0, memory, NULL, NULL, NULL}; 413 native = CFMachPortCreateWithPort(allocator, mp, __CFMessagePortDummyCallback, &ctx, NULL); 414 if (!native) { 415 mach_port_destroy(mach_task_self(), mp); 416 CFAllocatorDeallocate(kCFAllocatorSystemDefault, utfname); 417 // name is released by deallocation 418 CFRelease(memory); 419 return NULL; 420 } 421 __CFMessagePortSetExtraMachRef(memory); 422 } else { 423 mach_port_destroy(mach_task_self(), mp); 424 CFAllocatorDeallocate(kCFAllocatorSystemDefault, utfname); 425 // name is released by deallocation 426 CFRelease(memory); 427 return NULL; 428 } 429 } 430 } 431 if (!native) { 432 CFMachPortContext ctx = {0, memory, NULL, NULL, NULL}; 433 native = CFMachPortCreate(allocator, __CFMessagePortDummyCallback, &ctx, NULL); 434 if (!native) { 435 CFAllocatorDeallocate(kCFAllocatorSystemDefault, utfname); 436 // name is released by deallocation 437 CFRelease(memory); 438 return NULL; 439 } 440 mp = CFMachPortGetPort(native); 441 #pragma GCC diagnostic push 442 #pragma GCC diagnostic ignored "-Wdeprecated" 443 ret = bootstrap_register2(bs, (char *)utfname, mp, perPID ? BOOTSTRAP_PER_PID_SERVICE : 0); 444 #pragma GCC diagnostic pop 445 if (ret != KERN_SUCCESS) { 446 CFLog(kCFLogLevelDebug, CFSTR("*** CFMessagePort: bootstrap_register(): failed %d (0x%x) '%s', port = 0x%x, name = '%s'\nSee /usr/include/servers/bootstrap_defs.h for the error codes."), ret, ret, bootstrap_strerror(ret), mp, utfname); 447 CFMachPortInvalidate(native); 448 CFRelease(native); 449 CFAllocatorDeallocate(kCFAllocatorSystemDefault, utfname); 450 // name is released by deallocation 451 CFRelease(memory); 452 return NULL; 453 } 454 } 455 CFMachPortSetInvalidationCallBack(native, __CFMessagePortInvalidationCallBack); 456 memory->_port = native; 457 } 458 459 CFAllocatorDeallocate(kCFAllocatorSystemDefault, utfname); 460 __CFMessagePortSetValid(memory); 461 if (NULL != context) { 462 memmove(&memory->_context, context, sizeof(CFMessagePortContext)); 463 memory->_context.info = context->retain ? (void *)context->retain(context->info) : context->info; 464 } 465 __CFLock(&__CFAllMessagePortsLock); 466 if (!perPID && NULL != name) { 467 CFMessagePortRef existing; 468 if (NULL != __CFAllLocalMessagePorts && CFDictionaryGetValueIfPresent(__CFAllLocalMessagePorts, name, (const void **)&existing)) { 469 CFRetain(existing); 470 __CFUnlock(&__CFAllMessagePortsLock); 471 CFRelease(memory); 472 return (CFMessagePortRef)(existing); 473 } 474 if (NULL == __CFAllLocalMessagePorts) { 475 __CFAllLocalMessagePorts = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, NULL); 476 } 477 CFDictionaryAddValue(__CFAllLocalMessagePorts, name, memory); 478 } 479 __CFUnlock(&__CFAllMessagePortsLock); 480 if (shouldFreeInfo) *shouldFreeInfo = false; 481 return memory; 482 } 483 484 CFMessagePortRef CFMessagePortCreateLocal(CFAllocatorRef allocator, CFStringRef name, CFMessagePortCallBack callout, CFMessagePortContext *context, Boolean *shouldFreeInfo) { 485 return __CFMessagePortCreateLocal(allocator, name, callout, context, shouldFreeInfo, false, NULL); 486 } 487 488 CFMessagePortRef CFMessagePortCreatePerProcessLocal(CFAllocatorRef allocator, CFStringRef name, CFMessagePortCallBack callout, CFMessagePortContext *context, Boolean *shouldFreeInfo) { 489 return __CFMessagePortCreateLocal(allocator, name, callout, context, shouldFreeInfo, true, NULL); 490 } 491 492 CFMessagePortRef _CFMessagePortCreateLocalEx(CFAllocatorRef allocator, CFStringRef name, Boolean perPID, uintptr_t unused, CFMessagePortCallBackEx calloutEx, CFMessagePortContext *context, Boolean *shouldFreeInfo) { 493 return __CFMessagePortCreateLocal(allocator, name, NULL, context, shouldFreeInfo, perPID, calloutEx); 494 } 495 496 static CFMessagePortRef __CFMessagePortCreateRemote(CFAllocatorRef allocator, CFStringRef name, Boolean perPID, CFIndex pid) { 497 CFMessagePortRef memory; 498 CFMachPortRef native; 499 CFMachPortContext ctx; 500 uint8_t *utfname = NULL; 501 CFIndex size; 502 mach_port_t bp, port; 503 kern_return_t ret; 504 505 name = __CFMessagePortSanitizeStringName(name, &utfname, NULL); 506 if (NULL == name) { 507 return NULL; 508 } 509 __CFLock(&__CFAllMessagePortsLock); 510 if (!perPID && NULL != name) { 511 CFMessagePortRef existing; 512 if (NULL != __CFAllRemoteMessagePorts && CFDictionaryGetValueIfPresent(__CFAllRemoteMessagePorts, name, (const void **)&existing)) { 513 CFRetain(existing); 514 __CFUnlock(&__CFAllMessagePortsLock); 515 CFRelease(name); 516 CFAllocatorDeallocate(kCFAllocatorSystemDefault, utfname); 517 if (!CFMessagePortIsValid(existing)) { // must do this outside lock to avoid deadlock 518 CFRelease(existing); 519 existing = NULL; 520 } 521 return (CFMessagePortRef)(existing); 522 } 523 } 524 __CFUnlock(&__CFAllMessagePortsLock); 525 size = sizeof(struct __CFMessagePort) - sizeof(CFMessagePortContext) - sizeof(CFRuntimeBase); 526 memory = (CFMessagePortRef)_CFRuntimeCreateInstance(allocator, CFMessagePortGetTypeID(), size, NULL); 527 if (NULL == memory) { 528 if (NULL != name) { 529 CFRelease(name); 530 } 531 CFAllocatorDeallocate(kCFAllocatorSystemDefault, utfname); 532 return NULL; 533 } 534 __CFMessagePortUnsetValid(memory); 535 __CFMessagePortUnsetExtraMachRef(memory); 536 __CFMessagePortSetRemote(memory); 537 memory->_lock = CFLockInit; 538 memory->_name = name; 539 memory->_port = NULL; 540 memory->_replies = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, NULL); 541 memory->_convCounter = 0; 542 memory->_perPID = perPID ? pid : 0; 543 memory->_replyPort = NULL; 544 memory->_source = NULL; 545 memory->_dispatchSource = NULL; 546 memory->_dispatchQ = NULL; 547 memory->_icallout = NULL; 548 memory->_callout = NULL; 549 memory->_calloutEx = NULL; 550 ctx.version = 0; 551 ctx.info = memory; 552 ctx.retain = NULL; 553 ctx.release = NULL; 554 ctx.copyDescription = NULL; 555 task_get_bootstrap_port(mach_task_self(), &bp); 556 ret = bootstrap_look_up2(bp, (char *)utfname, &port, perPID ? (pid_t)pid : 0, perPID ? BOOTSTRAP_PER_PID_SERVICE : 0); 557 native = (KERN_SUCCESS == ret) ? CFMachPortCreateWithPort(allocator, port, __CFMessagePortDummyCallback, &ctx, NULL) : NULL; 558 CFAllocatorDeallocate(kCFAllocatorSystemDefault, utfname); 559 if (NULL == native) { 560 // name is released by deallocation 561 CFRelease(memory); 562 return NULL; 563 } 564 memory->_port = native; 565 __CFMessagePortSetValid(memory); 566 __CFLock(&__CFAllMessagePortsLock); 567 if (!perPID && NULL != name) { 568 CFMessagePortRef existing; 569 if (NULL != __CFAllRemoteMessagePorts && CFDictionaryGetValueIfPresent(__CFAllRemoteMessagePorts, name, (const void **)&existing)) { 570 CFRetain(existing); 571 __CFUnlock(&__CFAllMessagePortsLock); 572 CFRelease(memory); 573 return (CFMessagePortRef)(existing); 574 } 575 if (NULL == __CFAllRemoteMessagePorts) { 576 __CFAllRemoteMessagePorts = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, NULL); 577 } 578 CFDictionaryAddValue(__CFAllRemoteMessagePorts, name, memory); 579 } 580 CFRetain(native); 581 __CFUnlock(&__CFAllMessagePortsLock); 582 CFMachPortSetInvalidationCallBack(native, __CFMessagePortInvalidationCallBack); 583 // that set-invalidation-callback might have called back into us 584 // if the CFMachPort is already bad, but that was a no-op since 585 // there was no callback setup at the (previous) time the CFMachPort 586 // went invalid; so check for validity manually and react 587 if (!CFMachPortIsValid(native)) { 588 CFRelease(memory); // does the invalidate 589 CFRelease(native); 590 return NULL; 591 } 592 CFRelease(native); 593 return (CFMessagePortRef)memory; 594 } 595 596 CFMessagePortRef CFMessagePortCreateRemote(CFAllocatorRef allocator, CFStringRef name) { 597 return __CFMessagePortCreateRemote(allocator, name, false, 0); 598 } 599 600 CFMessagePortRef CFMessagePortCreatePerProcessRemote(CFAllocatorRef allocator, CFStringRef name, CFIndex pid) { 601 return __CFMessagePortCreateRemote(allocator, name, true, pid); 602 } 603 604 Boolean CFMessagePortIsRemote(CFMessagePortRef ms) { 605 __CFGenericValidateType(ms, CFMessagePortGetTypeID()); 606 return __CFMessagePortIsRemote(ms); 607 } 608 609 CFStringRef CFMessagePortGetName(CFMessagePortRef ms) { 610 __CFGenericValidateType(ms, CFMessagePortGetTypeID()); 611 return ms->_name; 612 } 613 614 Boolean CFMessagePortSetName(CFMessagePortRef ms, CFStringRef name) { 615 CFAllocatorRef allocator = CFGetAllocator(ms); 616 uint8_t *utfname = NULL; 617 618 __CFGenericValidateType(ms, CFMessagePortGetTypeID()); 619 if (ms->_perPID || __CFMessagePortIsRemote(ms)) return false; 620 name = __CFMessagePortSanitizeStringName(name, &utfname, NULL); 621 if (NULL == name) { 622 return false; 623 } 624 __CFLock(&__CFAllMessagePortsLock); 625 if (NULL != name) { 626 CFMessagePortRef existing; 627 if (NULL != __CFAllLocalMessagePorts && CFDictionaryGetValueIfPresent(__CFAllLocalMessagePorts, name, (const void **)&existing)) { 628 __CFUnlock(&__CFAllMessagePortsLock); 629 CFRelease(name); 630 CFAllocatorDeallocate(kCFAllocatorSystemDefault, utfname); 631 return false; 632 } 633 } 634 __CFUnlock(&__CFAllMessagePortsLock); 635 636 if (NULL != name && (NULL == ms->_name || !CFEqual(ms->_name, name))) { 637 CFMachPortRef oldPort = ms->_port; 638 CFMachPortRef native = NULL; 639 kern_return_t ret; 640 mach_port_t bs, mp; 641 task_get_bootstrap_port(mach_task_self(), &bs); 642 ret = bootstrap_check_in(bs, (char *)utfname, &mp); /* If we're started by launchd or the old mach_init */ 643 if (ret == KERN_SUCCESS) { 644 ret = mach_port_insert_right(mach_task_self(), mp, mp, MACH_MSG_TYPE_MAKE_SEND); 645 if (KERN_SUCCESS == ret) { 646 CFMachPortContext ctx = {0, ms, NULL, NULL, NULL}; 647 native = CFMachPortCreateWithPort(allocator, mp, __CFMessagePortDummyCallback, &ctx, NULL); 648 __CFMessagePortSetExtraMachRef(ms); 649 } else { 650 mach_port_destroy(mach_task_self(), mp); 651 CFAllocatorDeallocate(kCFAllocatorSystemDefault, utfname); 652 CFRelease(name); 653 return false; 654 } 655 } 656 if (!native) { 657 CFMachPortContext ctx = {0, ms, NULL, NULL, NULL}; 658 native = CFMachPortCreate(allocator, __CFMessagePortDummyCallback, &ctx, NULL); 659 if (!native) { 660 CFAllocatorDeallocate(kCFAllocatorSystemDefault, utfname); 661 CFRelease(name); 662 return false; 663 } 664 mp = CFMachPortGetPort(native); 665 #pragma GCC diagnostic push 666 #pragma GCC diagnostic ignored "-Wdeprecated" 667 ret = bootstrap_register2(bs, (char *)utfname, mp, 0); 668 #pragma GCC diagnostic pop 669 if (ret != KERN_SUCCESS) { 670 CFLog(kCFLogLevelDebug, CFSTR("*** CFMessagePort: bootstrap_register(): failed %d (0x%x) '%s', port = 0x%x, name = '%s'\nSee /usr/include/servers/bootstrap_defs.h for the error codes."), ret, ret, bootstrap_strerror(ret), mp, utfname); 671 CFMachPortInvalidate(native); 672 CFRelease(native); 673 CFAllocatorDeallocate(kCFAllocatorSystemDefault, utfname); 674 CFRelease(name); 675 return false; 676 } 677 } 678 CFMachPortSetInvalidationCallBack(native, __CFMessagePortInvalidationCallBack); 679 ms->_port = native; 680 if (NULL != oldPort && oldPort != native) { 681 if (__CFMessagePortExtraMachRef(ms)) { 682 mach_port_mod_refs(mach_task_self(), CFMachPortGetPort(oldPort), MACH_PORT_RIGHT_SEND, -1); 683 mach_port_mod_refs(mach_task_self(), CFMachPortGetPort(oldPort), MACH_PORT_RIGHT_RECEIVE, -1); 684 } 685 CFMachPortInvalidate(oldPort); 686 CFRelease(oldPort); 687 } 688 __CFLock(&__CFAllMessagePortsLock); 689 // This relocking without checking to see if something else has grabbed 690 // that name in the cache is rather suspect, but what would that even 691 // mean has happened? We'd expect the bootstrap_* calls above to have 692 // failed for this one and not gotten this far, or failed for all of the 693 // other simultaneous attempts to get the name (and having succeeded for 694 // this one, gotten here). So we're not going to try very hard here 695 // with the thread-safety. 696 if (NULL == __CFAllLocalMessagePorts) { 697 __CFAllLocalMessagePorts = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, NULL); 698 } 699 if (NULL != ms->_name) { 700 CFDictionaryRemoveValue(__CFAllLocalMessagePorts, ms->_name); 701 CFRelease(ms->_name); 702 } 703 ms->_name = name; 704 CFDictionaryAddValue(__CFAllLocalMessagePorts, name, ms); 705 __CFUnlock(&__CFAllMessagePortsLock); 706 } 707 708 CFAllocatorDeallocate(kCFAllocatorSystemDefault, utfname); 709 return true; 710 } 711 712 void CFMessagePortGetContext(CFMessagePortRef ms, CFMessagePortContext *context) { 713 __CFGenericValidateType(ms, CFMessagePortGetTypeID()); 714 //#warning CF: assert that this is a local port 715 CFAssert1(0 == context->version, __kCFLogAssertion, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__); 716 memmove(context, &ms->_context, sizeof(CFMessagePortContext)); 717 } 718 719 void CFMessagePortInvalidate(CFMessagePortRef ms) { 720 __CFGenericValidateType(ms, CFMessagePortGetTypeID()); 721 if (!__CFMessagePortIsDeallocing(ms)) { 722 CFRetain(ms); 723 } 724 __CFMessagePortLock(ms); 725 if (__CFMessagePortIsValid(ms)) { 726 if (ms->_dispatchSource) { 727 dispatch_source_cancel(ms->_dispatchSource); 728 ms->_dispatchSource = NULL; 729 ms->_dispatchQ = NULL; 730 } 731 732 CFMessagePortInvalidationCallBack callout = ms->_icallout; 733 CFRunLoopSourceRef source = ms->_source; 734 CFMachPortRef replyPort = ms->_replyPort; 735 CFMachPortRef port = ms->_port; 736 CFStringRef name = ms->_name; 737 void *info = NULL; 738 739 __CFMessagePortUnsetValid(ms); 740 if (!__CFMessagePortIsRemote(ms)) { 741 info = ms->_context.info; 742 ms->_context.info = NULL; 743 } 744 ms->_source = NULL; 745 ms->_replyPort = NULL; 746 ms->_port = NULL; 747 __CFMessagePortUnlock(ms); 748 749 __CFLock(&__CFAllMessagePortsLock); 750 if (0 == ms->_perPID && NULL != name && NULL != (__CFMessagePortIsRemote(ms) ? __CFAllRemoteMessagePorts : __CFAllLocalMessagePorts)) { 751 CFDictionaryRemoveValue(__CFMessagePortIsRemote(ms) ? __CFAllRemoteMessagePorts : __CFAllLocalMessagePorts, name); 752 } 753 __CFUnlock(&__CFAllMessagePortsLock); 754 if (NULL != callout) { 755 callout(ms, info); 756 } 757 if (!__CFMessagePortIsRemote(ms) && NULL != ms->_context.release) { 758 ms->_context.release(info); 759 } 760 if (NULL != source) { 761 CFRunLoopSourceInvalidate(source); 762 CFRelease(source); 763 } 764 if (NULL != replyPort) { 765 CFMachPortInvalidate(replyPort); 766 CFRelease(replyPort); 767 } 768 if (__CFMessagePortIsRemote(ms)) { 769 // Get rid of our extra ref on the Mach port gotten from bs server 770 mach_port_deallocate(mach_task_self(), CFMachPortGetPort(port)); 771 } 772 if (NULL != port) { 773 // We already know we're going invalid, don't need this callback 774 // anymore; plus, this solves a reentrancy deadlock; also, this 775 // must be done before the deallocate of the Mach port, to 776 // avoid a race between the notification message which could be 777 // handled in another thread, and this NULL'ing out. 778 CFMachPortSetInvalidationCallBack(port, NULL); 779 if (__CFMessagePortExtraMachRef(ms)) { 780 mach_port_mod_refs(mach_task_self(), CFMachPortGetPort(port), MACH_PORT_RIGHT_SEND, -1); 781 mach_port_mod_refs(mach_task_self(), CFMachPortGetPort(port), MACH_PORT_RIGHT_RECEIVE, -1); 782 } 783 CFMachPortInvalidate(port); 784 CFRelease(port); 785 } 786 } else { 787 __CFMessagePortUnlock(ms); 788 } 789 if (!__CFMessagePortIsDeallocing(ms)) { 790 CFRelease(ms); 791 } 792 } 793 794 Boolean CFMessagePortIsValid(CFMessagePortRef ms) { 795 __CFGenericValidateType(ms, CFMessagePortGetTypeID()); 796 if (!__CFMessagePortIsValid(ms)) return false; 797 CFRetain(ms); 798 if (NULL != ms->_port && !CFMachPortIsValid(ms->_port)) { 799 CFMessagePortInvalidate(ms); 800 CFRelease(ms); 801 return false; 802 } 803 if (NULL != ms->_replyPort && !CFMachPortIsValid(ms->_replyPort)) { 804 CFMessagePortInvalidate(ms); 805 CFRelease(ms); 806 return false; 807 } 808 CFRelease(ms); 809 return true; 810 } 811 812 CFMessagePortInvalidationCallBack CFMessagePortGetInvalidationCallBack(CFMessagePortRef ms) { 813 __CFGenericValidateType(ms, CFMessagePortGetTypeID()); 814 return ms->_icallout; 815 } 816 817 void CFMessagePortSetInvalidationCallBack(CFMessagePortRef ms, CFMessagePortInvalidationCallBack callout) { 818 __CFGenericValidateType(ms, CFMessagePortGetTypeID()); 819 if (!__CFMessagePortIsValid(ms) && NULL != callout) { 820 callout(ms, ms->_context.info); 821 } else { 822 ms->_icallout = callout; 823 } 824 } 825 826 static void __CFMessagePortReplyCallBack(CFMachPortRef port, void *msg, CFIndex size, void *info) { 827 CFMessagePortRef ms = info; 828 mach_msg_base_t *msgp = msg; 829 mach_msg_base_t *replymsg; 830 __CFMessagePortLock(ms); 831 if (!__CFMessagePortIsValid(ms)) { 832 __CFMessagePortUnlock(ms); 833 return; 834 } 835 836 int32_t byteslen = 0; 837 838 Boolean wayTooSmall = size < sizeof(mach_msg_header_t) || size < MSGP_SIZE(msgp) || msgp->header.msgh_size < MSGP_SIZE(msgp); 839 Boolean invalidMagic = false; 840 Boolean invalidComplex = false; 841 Boolean wayTooBig = false; 842 if (!wayTooSmall) { 843 invalidMagic = ((MSGP_INFO(msgp, magic) != MAGIC) && (CFSwapInt32(MSGP_INFO(msgp, magic)) != MAGIC)); 844 invalidComplex = (msgp->header.msgh_bits & MACH_MSGH_BITS_COMPLEX) && (1 != msgp->body.msgh_descriptor_count); 845 wayTooBig = ((int32_t)MSGP_SIZE(msgp) + __CFMessagePortMaxInlineBytes) < msgp->header.msgh_size; // also less than a 32-bit signed int can hold 846 } 847 Boolean wrongSize = false; 848 if (!(invalidComplex || wayTooBig || wayTooSmall)) { 849 byteslen = CFSwapInt32LittleToHost(MSGP_INFO(msgp, byteslen)); 850 wrongSize = (byteslen < -1) || (__CFMessagePortMaxDataSize < byteslen); 851 if (msgp->header.msgh_bits & MACH_MSGH_BITS_COMPLEX) { 852 wrongSize = wrongSize || (MSGP_GET(msgp, ool).size != byteslen); 853 } else { 854 wrongSize = wrongSize || ((int32_t)msgp->header.msgh_size - (int32_t)MSGP_SIZE(msgp) < byteslen); 855 } 856 } 857 Boolean invalidMsgID = wayTooSmall ? false : ((0 <= MSGP_INFO(msgp, convid)) && (MSGP_INFO(msgp, convid) <= INT32_MAX)); // conversation id 858 if (invalidMagic || invalidComplex || wayTooBig || wayTooSmall || wrongSize || invalidMsgID) { 859 CFLog(kCFLogLevelWarning, CFSTR("*** CFMessagePort: dropping corrupt reply Mach message (0b%d%d%d%d%d%d)"), invalidMagic, invalidComplex, wayTooBig, wayTooSmall, wrongSize, invalidMsgID); 860 mach_msg_destroy((mach_msg_header_t *)msgp); 861 __CFMessagePortUnlock(ms); 862 return; 863 } 864 865 if (CFDictionaryContainsKey(ms->_replies, (void *)(uintptr_t)MSGP_INFO(msgp, convid))) { 866 CFDataRef reply = NULL; 867 replymsg = (mach_msg_base_t *)msg; 868 if (!(replymsg->header.msgh_bits & MACH_MSGH_BITS_COMPLEX)) { 869 uintptr_t msgp_extent = (uintptr_t)((uint8_t *)msgp + msgp->header.msgh_size); 870 uintptr_t data_extent = (uintptr_t)((uint8_t *)&(MSGP_INFO(replymsg, bytes)) + byteslen); 871 if (byteslen < 0) byteslen = 0; // from here on, treat negative same as zero -- this is historical behavior: a NULL return from the callback on the other side results in empty data to the original requestor 872 if (0 <= byteslen && data_extent <= msgp_extent) { 873 reply = CFDataCreate(kCFAllocatorSystemDefault, MSGP_INFO(replymsg, bytes), byteslen); 874 } else { 875 reply = (void *)~0; // means NULL data 876 } 877 } else { 878 //#warning CF: should create a no-copy data here that has a custom VM-freeing allocator, and not vm_dealloc here 879 reply = CFDataCreate(kCFAllocatorSystemDefault, MSGP_GET(replymsg, ool).address, MSGP_GET(replymsg, ool).size); 880 vm_deallocate(mach_task_self(), (vm_address_t)MSGP_GET(replymsg, ool).address, MSGP_GET(replymsg, ool).size); 881 } 882 CFDictionarySetValue(ms->_replies, (void *)(uintptr_t)MSGP_INFO(msgp, convid), (void *)reply); 883 } else { /* discard message */ 884 if (msgp->header.msgh_bits & MACH_MSGH_BITS_COMPLEX) { 885 vm_deallocate(mach_task_self(), (vm_address_t)MSGP_GET(msgp, ool).address, MSGP_GET(msgp, ool).size); 886 } 887 } 888 __CFMessagePortUnlock(ms); 889 } 890 891 SInt32 CFMessagePortSendRequest(CFMessagePortRef remote, SInt32 msgid, CFDataRef data, CFTimeInterval sendTimeout, CFTimeInterval rcvTimeout, CFStringRef replyMode, CFDataRef *returnDatap) { 892 mach_msg_base_t *sendmsg; 893 CFRunLoopRef currentRL = CFRunLoopGetCurrent(); 894 CFRunLoopSourceRef source = NULL; 895 CFDataRef reply = NULL; 896 uint64_t termTSR; 897 uint32_t sendOpts = 0, sendTimeOut = 0; 898 int32_t desiredReply; 899 Boolean didRegister = false; 900 kern_return_t ret; 901 902 //#warning CF: This should be an assert 903 // if (!__CFMessagePortIsRemote(remote)) return -999; 904 if (data && __CFMessagePortMaxDataSize < CFDataGetLength(data)) { 905 CFLog(kCFLogLevelWarning, CFSTR("*** CFMessagePortSendRequest: CFMessagePort cannot send more than %lu bytes of data"), __CFMessagePortMaxDataSize); 906 return kCFMessagePortTransportError; 907 } 908 __CFMessagePortLock(remote); 909 if (!__CFMessagePortIsValid(remote)) { 910 __CFMessagePortUnlock(remote); 911 return kCFMessagePortIsInvalid; 912 } 913 CFRetain(remote); // retain during run loop to avoid invalidation causing freeing 914 if (NULL == remote->_replyPort) { 915 CFMachPortContext context; 916 context.version = 0; 917 context.info = remote; 918 context.retain = (const void *(*)(const void *))CFRetain; 919 context.release = (void (*)(const void *))CFRelease; 920 context.copyDescription = (CFStringRef (*)(const void *))__CFMessagePortCopyDescription; 921 remote->_replyPort = CFMachPortCreate(CFGetAllocator(remote), __CFMessagePortReplyCallBack, &context, NULL); 922 } 923 remote->_convCounter++; 924 desiredReply = -remote->_convCounter; 925 sendmsg = __CFMessagePortCreateMessage(false, CFMachPortGetPort(remote->_port), (replyMode != NULL ? CFMachPortGetPort(remote->_replyPort) : MACH_PORT_NULL), -desiredReply, msgid, (data ? CFDataGetBytePtr(data) : NULL), (data ? CFDataGetLength(data) : -1)); 926 if (!sendmsg) { 927 __CFMessagePortUnlock(remote); 928 CFRelease(remote); 929 return kCFMessagePortTransportError; 930 } 931 if (replyMode != NULL) { 932 CFDictionarySetValue(remote->_replies, (void *)(uintptr_t)desiredReply, NULL); 933 source = CFMachPortCreateRunLoopSource(CFGetAllocator(remote), remote->_replyPort, -100); 934 didRegister = !CFRunLoopContainsSource(currentRL, source, replyMode); 935 if (didRegister) { 936 CFRunLoopAddSource(currentRL, source, replyMode); 937 } 938 } 939 if (sendTimeout < 10.0*86400) { 940 // anything more than 10 days is no timeout! 941 sendOpts = MACH_SEND_TIMEOUT; 942 sendTimeout *= 1000.0; 943 if (sendTimeout < 1.0) sendTimeout = 0.0; 944 sendTimeOut = floor(sendTimeout); 945 } 946 __CFMessagePortUnlock(remote); 947 ret = mach_msg((mach_msg_header_t *)sendmsg, MACH_SEND_MSG|sendOpts, sendmsg->header.msgh_size, 0, MACH_PORT_NULL, sendTimeOut, MACH_PORT_NULL); 948 __CFMessagePortLock(remote); 949 if (KERN_SUCCESS != ret) { 950 // need to deallocate the send-once right that might have been created 951 if (replyMode != NULL) mach_port_deallocate(mach_task_self(), ((mach_msg_header_t *)sendmsg)->msgh_local_port); 952 if (didRegister) { 953 CFRunLoopRemoveSource(currentRL, source, replyMode); 954 } 955 if (source) CFRelease(source); 956 __CFMessagePortUnlock(remote); 957 CFAllocatorDeallocate(kCFAllocatorSystemDefault, sendmsg); 958 CFRelease(remote); 959 return (MACH_SEND_TIMED_OUT == ret) ? kCFMessagePortSendTimeout : kCFMessagePortTransportError; 960 } 961 __CFMessagePortUnlock(remote); 962 CFAllocatorDeallocate(kCFAllocatorSystemDefault, sendmsg); 963 if (replyMode == NULL) { 964 CFRelease(remote); 965 return kCFMessagePortSuccess; 966 } 967 _CFMachPortInstallNotifyPort(currentRL, replyMode); 968 termTSR = mach_absolute_time() + __CFTimeIntervalToTSR(rcvTimeout); 969 for (;;) { 970 CFRunLoopRunInMode(replyMode, __CFTimeIntervalUntilTSR(termTSR), true); 971 // warning: what, if anything, should be done if remote is now invalid? 972 reply = CFDictionaryGetValue(remote->_replies, (void *)(uintptr_t)desiredReply); 973 if (NULL != reply || termTSR < mach_absolute_time()) { 974 break; 975 } 976 if (!CFMessagePortIsValid(remote)) { 977 // no reason that reply port alone should go invalid so we don't check for that 978 break; 979 } 980 } 981 // Should we uninstall the notify port? A complex question... 982 if (didRegister) { 983 CFRunLoopRemoveSource(currentRL, source, replyMode); 984 } 985 if (source) CFRelease(source); 986 if (NULL == reply) { 987 CFDictionaryRemoveValue(remote->_replies, (void *)(uintptr_t)desiredReply); 988 CFRelease(remote); 989 return CFMessagePortIsValid(remote) ? kCFMessagePortReceiveTimeout : kCFMessagePortBecameInvalidError; 990 } 991 if (NULL != returnDatap) { 992 *returnDatap = ((void *)~0 == reply) ? NULL : reply; 993 } else if ((void *)~0 != reply) { 994 CFRelease(reply); 995 } 996 CFDictionaryRemoveValue(remote->_replies, (void *)(uintptr_t)desiredReply); 997 CFRelease(remote); 998 return kCFMessagePortSuccess; 999 } 1000 1001 static mach_port_t __CFMessagePortGetPort(void *info) { 1002 CFMessagePortRef ms = info; 1003 if (!ms->_port && __CFMessagePortIsValid(ms)) CFLog(kCFLogLevelWarning, CFSTR("*** Warning: A local CFMessagePort (%p) is being put in a run loop or dispatch queue, but it has not been named yet, so this will be a no-op and no messages are going to be received, even if named later."), info); 1004 return ms->_port ? CFMachPortGetPort(ms->_port) : MACH_PORT_NULL; 1005 } 1006 1007 1008 static void *__CFMessagePortPerform(void *msg, CFIndex size, CFAllocatorRef allocator, void *info) { 1009 CFMessagePortRef ms = info; 1010 mach_msg_base_t *msgp = msg; 1011 mach_msg_base_t *replymsg; 1012 void *context_info; 1013 void (*context_release)(const void *); 1014 CFDataRef returnData, data = NULL; 1015 void *return_bytes = NULL; 1016 CFIndex return_len = -1; 1017 int32_t msgid; 1018 1019 __CFMessagePortLock(ms); 1020 if (!__CFMessagePortIsValid(ms)) { 1021 __CFMessagePortUnlock(ms); 1022 return NULL; 1023 } 1024 if (NULL != ms->_context.retain) { 1025 context_info = (void *)ms->_context.retain(ms->_context.info); 1026 context_release = ms->_context.release; 1027 } else { 1028 context_info = ms->_context.info; 1029 context_release = NULL; 1030 } 1031 __CFMessagePortUnlock(ms); 1032 1033 1034 int32_t byteslen = 0; 1035 1036 Boolean wayTooSmall = size < sizeof(mach_msg_header_t) || size < MSGP_SIZE(msgp) || msgp->header.msgh_size < MSGP_SIZE(msgp); 1037 Boolean invalidMagic = false; 1038 Boolean invalidComplex = false; 1039 Boolean wayTooBig = false; 1040 if (!wayTooSmall) { 1041 invalidMagic = ((MSGP_INFO(msgp, magic) != MAGIC) && (CFSwapInt32(MSGP_INFO(msgp, magic)) != MAGIC)); 1042 invalidComplex = (msgp->header.msgh_bits & MACH_MSGH_BITS_COMPLEX) && (1 != msgp->body.msgh_descriptor_count); 1043 wayTooBig = ((int32_t)MSGP_SIZE(msgp) + __CFMessagePortMaxInlineBytes) < msgp->header.msgh_size; // also less than a 32-bit signed int can hold 1044 } 1045 Boolean wrongSize = false; 1046 if (!(invalidComplex || wayTooBig || wayTooSmall)) { 1047 byteslen = CFSwapInt32LittleToHost(MSGP_INFO(msgp, byteslen)); 1048 wrongSize = (byteslen < -1) || (__CFMessagePortMaxDataSize < byteslen); 1049 if (msgp->header.msgh_bits & MACH_MSGH_BITS_COMPLEX) { 1050 wrongSize = wrongSize || (MSGP_GET(msgp, ool).size != byteslen); 1051 } else { 1052 wrongSize = wrongSize || ((int32_t)msgp->header.msgh_size - (int32_t)MSGP_SIZE(msgp) < byteslen); 1053 } 1054 } 1055 Boolean invalidMsgID = wayTooSmall ? false : ((MSGP_INFO(msgp, convid) <= 0) || (INT32_MAX < MSGP_INFO(msgp, convid))); // conversation id 1056 if (invalidMagic || invalidComplex || wayTooBig || wayTooSmall || wrongSize || invalidMsgID) { 1057 CFLog(kCFLogLevelWarning, CFSTR("*** CFMessagePort: dropping corrupt request Mach message (0b%d%d%d%d%d%d)"), invalidMagic, invalidComplex, wayTooBig, wayTooSmall, wrongSize, invalidMsgID); 1058 mach_msg_destroy((mach_msg_header_t *)msgp); 1059 return NULL; 1060 } 1061 1062 if (byteslen < 0) byteslen = 0; // from here on, treat negative same as zero 1063 1064 /* Create no-copy, no-free-bytes wrapper CFData */ 1065 if (!(msgp->header.msgh_bits & MACH_MSGH_BITS_COMPLEX)) { 1066 uintptr_t msgp_extent = (uintptr_t)((uint8_t *)msgp + msgp->header.msgh_size); 1067 uintptr_t data_extent = (uintptr_t)((uint8_t *)&(MSGP_INFO(msgp, bytes)) + byteslen); 1068 msgid = CFSwapInt32LittleToHost(MSGP_INFO(msgp, msgid)); 1069 if (0 <= byteslen && data_extent <= msgp_extent) { 1070 data = CFDataCreateWithBytesNoCopy(allocator, MSGP_INFO(msgp, bytes), byteslen, kCFAllocatorNull); 1071 } 1072 } else { 1073 msgid = CFSwapInt32LittleToHost(MSGP_INFO(msgp, msgid)); 1074 data = CFDataCreateWithBytesNoCopy(allocator, MSGP_GET(msgp, ool).address, MSGP_GET(msgp, ool).size, kCFAllocatorNull); 1075 } 1076 if (ms->_callout) { 1077 returnData = ms->_callout(ms, msgid, data, context_info); 1078 } else { 1079 mach_msg_trailer_t *trailer = (mach_msg_trailer_t *)(((uintptr_t)&(msgp->header) + msgp->header.msgh_size + sizeof(natural_t) - 1) & ~(sizeof(natural_t) - 1)); 1080 returnData = ms->_calloutEx(ms, msgid, data, context_info, trailer, 0); 1081 } 1082 /* Now, returnData could be (1) NULL, (2) an ordinary data < MAX_INLINE, 1083 (3) ordinary data >= MAX_INLINE, (4) a no-copy data < MAX_INLINE, 1084 (5) a no-copy data >= MAX_INLINE. In cases (2) and (4), we send the return 1085 bytes inline in the Mach message, so can release the returnData object 1086 here. In cases (3) and (5), we'll send the data out-of-line, we need to 1087 create a copy of the memory, which we'll have the kernel autodeallocate 1088 for us on send. In case (4) also, the bytes in the return data may be part 1089 of the bytes in "data" that we sent into the callout, so if the incoming 1090 data was received out of line, we wouldn't be able to clean up the out-of-line 1091 wad until the message was sent either, if we didn't make the copy. */ 1092 if (NULL != returnData) { 1093 return_len = CFDataGetLength(returnData); 1094 if (__CFMessagePortMaxDataSize < return_len) { 1095 CFLog(kCFLogLevelWarning, CFSTR("*** CFMessagePort reply: CFMessagePort cannot send more than %lu bytes of data"), __CFMessagePortMaxDataSize); 1096 return_len = 0; 1097 CFRelease(returnData); 1098 returnData = NULL; 1099 } 1100 if (returnData && return_len < __CFMessagePortMaxInlineBytes) { 1101 return_bytes = (void *)CFDataGetBytePtr(returnData); 1102 } else if (returnData) { 1103 return_bytes = NULL; 1104 vm_allocate(mach_task_self(), (vm_address_t *)&return_bytes, return_len, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_MACH_MSG)); 1105 /* vm_copy would only be a win here if the source address 1106 is page aligned; it is a lose in all other cases, since 1107 the kernel will just do the memmove for us (but not in 1108 as simple a way). */ 1109 memmove(return_bytes, CFDataGetBytePtr(returnData), return_len); 1110 } 1111 } 1112 replymsg = __CFMessagePortCreateMessage(true, msgp->header.msgh_remote_port, MACH_PORT_NULL, -1 * (int32_t)MSGP_INFO(msgp, convid), msgid, return_bytes, return_len); 1113 if (replymsg->header.msgh_bits & MACH_MSGH_BITS_COMPLEX) { 1114 MSGP_GET(replymsg, ool).deallocate = true; 1115 } 1116 if (data) CFRelease(data); 1117 if (msgp->header.msgh_bits & MACH_MSGH_BITS_COMPLEX) { 1118 vm_deallocate(mach_task_self(), (vm_address_t)MSGP_GET(msgp, ool).address, MSGP_GET(msgp, ool).size); 1119 } 1120 if (returnData) CFRelease(returnData); 1121 if (context_release) { 1122 context_release(context_info); 1123 } 1124 return replymsg; 1125 } 1126 1127 CFRunLoopSourceRef CFMessagePortCreateRunLoopSource(CFAllocatorRef allocator, CFMessagePortRef ms, CFIndex order) { 1128 CFRunLoopSourceRef result = NULL; 1129 __CFGenericValidateType(ms, CFMessagePortGetTypeID()); 1130 if (!CFMessagePortIsValid(ms)) return NULL; 1131 if (__CFMessagePortIsRemote(ms)) return NULL; 1132 __CFMessagePortLock(ms); 1133 if (NULL != ms->_source && !CFRunLoopSourceIsValid(ms->_source)) { 1134 CFRelease(ms->_source); 1135 ms->_source = NULL; 1136 } 1137 if (NULL == ms->_source && NULL == ms->_dispatchSource && __CFMessagePortIsValid(ms)) { 1138 CFRunLoopSourceContext1 context; 1139 context.version = 1; 1140 context.info = (void *)ms; 1141 context.retain = (const void *(*)(const void *))CFRetain; 1142 context.release = (void (*)(const void *))CFRelease; 1143 context.copyDescription = (CFStringRef (*)(const void *))__CFMessagePortCopyDescription; 1144 context.equal = NULL; 1145 context.hash = NULL; 1146 context.getPort = __CFMessagePortGetPort; 1147 context.perform = __CFMessagePortPerform; 1148 ms->_source = CFRunLoopSourceCreate(allocator, order, (CFRunLoopSourceContext *)&context); 1149 } 1150 if (NULL != ms->_source) { 1151 result = (CFRunLoopSourceRef)CFRetain(ms->_source); 1152 } 1153 __CFMessagePortUnlock(ms); 1154 return result; 1155 } 1156 1157 void CFMessagePortSetDispatchQueue(CFMessagePortRef ms, dispatch_queue_t queue) { 1158 __CFGenericValidateType(ms, CFMessagePortGetTypeID()); 1159 __CFMessagePortLock(ms); 1160 if (!__CFMessagePortIsValid(ms)) { 1161 __CFMessagePortUnlock(ms); 1162 CFLog(kCFLogLevelWarning, CFSTR("*** CFMessagePortSetDispatchQueue(): CFMessagePort is invalid")); 1163 return; 1164 } 1165 if (__CFMessagePortIsRemote(ms)) { 1166 __CFMessagePortUnlock(ms); 1167 CFLog(kCFLogLevelWarning, CFSTR("*** CFMessagePortSetDispatchQueue(): CFMessagePort is not a local port, queue cannot be set")); 1168 return; 1169 } 1170 if (NULL != ms->_source) { 1171 __CFMessagePortUnlock(ms); 1172 CFLog(kCFLogLevelWarning, CFSTR("*** CFMessagePortSetDispatchQueue(): CFMessagePort already has a CFRunLoopSourceRef, queue cannot be set")); 1173 return; 1174 } 1175 1176 if (ms->_dispatchSource) { 1177 dispatch_source_cancel(ms->_dispatchSource); 1178 ms->_dispatchSource = NULL; 1179 ms->_dispatchQ = NULL; 1180 } 1181 1182 if (queue) { 1183 mach_port_t port = __CFMessagePortGetPort(ms); 1184 if (MACH_PORT_NULL != port) { 1185 static dispatch_queue_t mportQueue = NULL; 1186 static dispatch_once_t once; 1187 dispatch_once(&once, ^{ 1188 dispatch_queue_attr_t dqattr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, qos_class_main(), 0); 1189 mportQueue = dispatch_queue_create("com.apple.CFMessagePort", dqattr); 1190 }); 1191 dispatch_source_t theSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, port, 0, mportQueue); 1192 dispatch_source_set_cancel_handler(theSource, ^{ 1193 dispatch_release(queue); 1194 dispatch_release(theSource); 1195 }); 1196 dispatch_source_set_event_handler(theSource, ^{ 1197 CFRetain(ms); 1198 mach_msg_header_t *msg = (mach_msg_header_t *)CFAllocatorAllocate(kCFAllocatorSystemDefault, 2048, 0); 1199 msg->msgh_size = 2048; 1200 1201 for (;;) { 1202 msg->msgh_bits = 0; 1203 msg->msgh_local_port = port; 1204 msg->msgh_remote_port = MACH_PORT_NULL; 1205 msg->msgh_id = 0; 1206 1207 kern_return_t ret = mach_msg(msg, MACH_RCV_MSG|MACH_RCV_LARGE|MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0)|MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AV), 0, msg->msgh_size, port, 0, MACH_PORT_NULL); 1208 if (MACH_MSG_SUCCESS == ret) break; 1209 if (MACH_RCV_TOO_LARGE != ret) HALT; 1210 1211 uint32_t newSize = round_msg(msg->msgh_size + MAX_TRAILER_SIZE); 1212 msg = CFAllocatorReallocate(kCFAllocatorSystemDefault, msg, newSize, 0); 1213 msg->msgh_size = newSize; 1214 } 1215 1216 dispatch_async(queue, ^{ 1217 mach_msg_header_t *reply = __CFMessagePortPerform(msg, msg->msgh_size, kCFAllocatorSystemDefault, ms); 1218 if (NULL != reply) { 1219 kern_return_t ret = mach_msg(reply, MACH_SEND_MSG, reply->msgh_size, 0, MACH_PORT_NULL, 0, MACH_PORT_NULL); 1220 if (KERN_SUCCESS != ret) mach_msg_destroy(reply); 1221 CFAllocatorDeallocate(kCFAllocatorSystemDefault, reply); 1222 } 1223 CFAllocatorDeallocate(kCFAllocatorSystemDefault, msg); 1224 CFRelease(ms); 1225 }); 1226 }); 1227 ms->_dispatchSource = theSource; 1228 } 1229 if (ms->_dispatchSource) { 1230 dispatch_retain(queue); 1231 ms->_dispatchQ = queue; 1232 dispatch_resume(ms->_dispatchSource); 1233 } else { 1234 CFLog(kCFLogLevelWarning, CFSTR("*** CFMessagePortSetDispatchQueue(): dispatch source could not be created")); 1235 } 1236 } 1237 __CFMessagePortUnlock(ms); 1238 } 1239