2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
20 // machrunloopserver - C++ shell for writing Mach 3 servers called by CFRunLoop
22 #include "machrunloopserver.h"
23 #include <Security/cfutilities.h>
24 #include <mach/mach_error.h>
25 #include <Security/debugging.h>
29 namespace MachPlusPlus
{
33 // Generic Mach server
35 MachRunLoopServer::MachRunLoopServer(const char *name
) : MachServer(name
)
39 MachRunLoopServer::MachRunLoopServer(const char *name
, const Bootstrap
&boot
)
40 : MachServer(name
, boot
)
44 void MachRunLoopServer::run(size_t bufferSize
, mach_msg_options_t options
)
46 // allocate reply buffer (well, try)
47 replyBuffer
= CssmAllocator::standard().malloc
<mach_msg_header_t
>(bufferSize
);
49 // Now do the CFRunLoop tango...
50 runLoop
= CFRunLoopGetCurrent();
51 CFRef
<CFMachPortRef
> cfPort
= CFMachPortCreateWithPort(NULL
, mServerPort
, cfCallback
,
54 CFMachPortCreateRunLoopSource(NULL
, cfPort
, 10); //@@@ no idea what order is good
55 if (!runLoop
|| !runLoopSource
|| !cfPort
)
56 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR
); //@@@ $#!!& CF non-diagnostics!
57 CFRunLoopAddSource(runLoop
, runLoopSource
, kCFRunLoopDefaultMode
);
60 perThread().server
= this;
63 MachRunLoopServer::~MachRunLoopServer()
65 // remove our runloop source
66 CFRunLoopRemoveSource(runLoop
, runLoopSource
, kCFRunLoopDefaultMode
);
67 CFRelease(runLoopSource
);
69 // delete the reply buffer
70 CssmAllocator::standard().free(replyBuffer
);
73 perThread().server
= NULL
;
75 // our MachServer parent class will clean up the ports and deregister from our bootstrap
80 // Block/unblock new request reception to serialize the request queue
82 void MachRunLoopServer::blockNewRequests(bool block
)
85 CFRunLoopRemoveSource(runLoop
, runLoopSource
, kCFRunLoopDefaultMode
);
86 debug("machsrv", "disabled request reception");
88 CFRunLoopAddSource(runLoop
, runLoopSource
, kCFRunLoopDefaultMode
);
89 debug("machsrv", "enabled request reception");
95 // Add secondary ports to receive on
97 void MachRunLoopServer::alsoListenOn(Port port
)
99 CFRef
<CFMachPortRef
> cfPort
= CFMachPortCreateWithPort(NULL
, port
, cfCallback
,
101 CFRef
<CFRunLoopSourceRef
> source
=
102 CFMachPortCreateRunLoopSource(NULL
, cfPort
, 10); //@@@ no idea what order is good
103 CFRunLoopAddSource(runLoop
, source
, kCFRunLoopDefaultMode
);
104 debug("machsrv", "also receiving from port %d", port
.port());
107 void MachRunLoopServer::stopListenOn(Port port
)
109 CFRef
<CFMachPortRef
> cfPort
= CFMachPortCreateWithPort(NULL
, port
, cfCallback
,
111 CFRef
<CFRunLoopSourceRef
> source
=
112 CFMachPortCreateRunLoopSource(NULL
, cfPort
, 10); //@@@ no idea what order is good
113 CFRunLoopRemoveSource(runLoop
, source
, kCFRunLoopDefaultMode
);
114 debug("machsrv", "no longer receiving from port %d", port
.port());
119 // Handle dead-port notifications.
120 // Since we don't actually run our own runloop here, we can't well use standard
121 // notifications to our own server port. So we use a CFMachPort facility instead.
123 void MachRunLoopServer::notifyIfDead(Port port
) const
125 //@@@ not clear how to deal with CFRetainCount of cfPort here
126 // will CF clean up the cfPort when it dies? Or do we have to keep a set?
127 CFMachPortRef cfPort
= CFMachPortCreateWithPort(NULL
, port
, NULL
, NULL
, NULL
);
128 CFMachPortSetInvalidationCallBack(cfPort
, cfInvalidateCallback
);
131 void MachRunLoopServer::cfInvalidateCallback(CFMachPortRef cfPort
, void *)
133 active().notifyDeadName(CFMachPortGetPort(cfPort
));
138 // The callback triggered from CFRunLoop
140 void MachRunLoopServer::cfCallback(CFMachPortRef port
, void *msg
, CFIndex
, void *)
142 active().oneRequest(reinterpret_cast<mach_msg_header_t
*>(msg
));
145 void MachRunLoopServer::oneRequest(mach_msg_header_t
*request
)
147 if (!handle(request
, replyBuffer
)) {
148 // MIG dispatch did not recognize the request. Ignore/Retry/Fail? :-)
149 //@@@ Should send an error reply back here, I suppose. Later...
150 debug("machrls", "MachRunLoopServer dispatch failed");
154 // MIG dispatch handled the call. Send reply back to caller.
155 // This boilerplate stolen from mach_msg_server, since MIG can't seem to
156 // generate send-only code for replies (without explicit simpleroutines).
157 if (kern_return_t err
= mach_msg_overwrite(replyBuffer
,
158 (MACH_MSGH_BITS_REMOTE(replyBuffer
->msgh_bits
) == MACH_MSG_TYPE_MOVE_SEND_ONCE
) ?
159 MACH_SEND_MSG
: MACH_SEND_MSG
|MACH_SEND_TIMEOUT
,
160 replyBuffer
->msgh_size
, 0, MACH_PORT_NULL
,
161 0, MACH_PORT_NULL
, (mach_msg_header_t
*) 0, 0)) {
162 //@@@ should at least clean up resources here, I suppose.
163 debug("machsrv", "RunloopServer cannot post reply: %s", mach_error_string(err
));
164 active().releaseDeferredAllocations();
167 active().releaseDeferredAllocations();
172 } // end namespace MachPlusPlus
173 } // end namespace Security