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