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