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