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