]> git.saurik.com Git - apple/security.git/blob - cdsa/cdsa_utilities/machrunloopserver.cpp
Security-163.tar.gz
[apple/security.git] / cdsa / cdsa_utilities / machrunloopserver.cpp
1 /*
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
3 *
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
8 * using this file.
9 *
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.
16 */
17
18
19 //
20 // machrunloopserver - C++ shell for writing Mach 3 servers called by CFRunLoop
21 //
22 #include "machrunloopserver.h"
23 #include <Security/cfutilities.h>
24 #include <mach/mach_error.h>
25 #include <Security/debugging.h>
26
27
28 namespace Security {
29 namespace MachPlusPlus {
30
31
32 //
33 // Generic Mach server
34 //
35 MachRunLoopServer::MachRunLoopServer(const char *name) : MachServer(name)
36 {
37 }
38
39 MachRunLoopServer::MachRunLoopServer(const char *name, const Bootstrap &boot)
40 : MachServer(name, boot)
41 {
42 }
43
44 void MachRunLoopServer::run(size_t bufferSize, mach_msg_options_t options)
45 {
46 // allocate reply buffer (well, try)
47 replyBuffer = CssmAllocator::standard().malloc<mach_msg_header_t>(bufferSize);
48
49 // Now do the CFRunLoop tango...
50 runLoop = CFRunLoopGetCurrent();
51 CFRef<CFMachPortRef> cfPort = CFMachPortCreateWithPort(NULL, mServerPort, cfCallback,
52 NULL, NULL);
53 runLoopSource =
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);
58
59 // we are it!
60 perThread().server = this;
61 }
62
63 MachRunLoopServer::~MachRunLoopServer()
64 {
65 // remove our runloop source
66 CFRunLoopRemoveSource(runLoop, runLoopSource, kCFRunLoopDefaultMode);
67 CFRelease(runLoopSource);
68
69 // delete the reply buffer
70 CssmAllocator::standard().free(replyBuffer);
71
72 // no longer tagged
73 perThread().server = NULL;
74
75 // our MachServer parent class will clean up the ports and deregister from our bootstrap
76 }
77
78
79 //
80 // Block/unblock new request reception to serialize the request queue
81 //
82 void MachRunLoopServer::blockNewRequests(bool block)
83 {
84 if (block) {
85 CFRunLoopRemoveSource(runLoop, runLoopSource, kCFRunLoopDefaultMode);
86 secdebug("machsrv", "disabled request reception");
87 } else {
88 CFRunLoopAddSource(runLoop, runLoopSource, kCFRunLoopDefaultMode);
89 secdebug("machsrv", "enabled request reception");
90 }
91 }
92
93
94 //
95 // Add secondary ports to receive on
96 //
97 void MachRunLoopServer::alsoListenOn(Port port)
98 {
99 CFRef<CFMachPortRef> cfPort = CFMachPortCreateWithPort(NULL, port, cfCallback,
100 NULL, NULL);
101 CFRef<CFRunLoopSourceRef> source =
102 CFMachPortCreateRunLoopSource(NULL, cfPort, 10); //@@@ no idea what order is good
103 CFRunLoopAddSource(runLoop, source, kCFRunLoopDefaultMode);
104 secdebug("machsrv", "also receiving from port %d", port.port());
105 }
106
107 void MachRunLoopServer::stopListenOn(Port port)
108 {
109 CFRef<CFMachPortRef> cfPort = CFMachPortCreateWithPort(NULL, port, cfCallback,
110 NULL, NULL);
111 CFRef<CFRunLoopSourceRef> source =
112 CFMachPortCreateRunLoopSource(NULL, cfPort, 10); //@@@ no idea what order is good
113 CFRunLoopRemoveSource(runLoop, source, kCFRunLoopDefaultMode);
114 secdebug("machsrv", "no longer receiving from port %d", port.port());
115 }
116
117
118 //
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.
122 //
123 void MachRunLoopServer::notifyIfDead(Port port) const
124 {
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 if (cfPort != NULL) // check to make sure that we got a valid port reference back
129 {
130 CFMachPortSetInvalidationCallBack(cfPort, cfInvalidateCallback);
131 }
132 }
133
134 void MachRunLoopServer::cfInvalidateCallback(CFMachPortRef cfPort, void *)
135 {
136 active().notifyDeadName(CFMachPortGetPort(cfPort));
137 }
138
139
140 //
141 // The callback triggered from CFRunLoop
142 //
143 void MachRunLoopServer::cfCallback(CFMachPortRef port, void *msg, CFIndex, void *)
144 {
145 active().oneRequest(reinterpret_cast<mach_msg_header_t *>(msg));
146 }
147
148 void MachRunLoopServer::oneRequest(mach_msg_header_t *request)
149 {
150 if (!handle(request, replyBuffer)) {
151 // MIG dispatch did not recognize the request. Ignore/Retry/Fail? :-)
152 //@@@ Should send an error reply back here, I suppose. Later...
153 secdebug("machrls", "MachRunLoopServer dispatch failed");
154 return;
155 }
156
157 // MIG dispatch handled the call. Send reply back to caller.
158 // This boilerplate stolen from mach_msg_server, since MIG can't seem to
159 // generate send-only code for replies (without explicit simpleroutines).
160 if (IFDEBUG(kern_return_t err =) mach_msg_overwrite(replyBuffer,
161 (MACH_MSGH_BITS_REMOTE(replyBuffer->msgh_bits) == MACH_MSG_TYPE_MOVE_SEND_ONCE) ?
162 MACH_SEND_MSG : MACH_SEND_MSG|MACH_SEND_TIMEOUT,
163 replyBuffer->msgh_size, 0, MACH_PORT_NULL,
164 0, MACH_PORT_NULL, (mach_msg_header_t *) 0, 0)) {
165 //@@@ should at least clean up resources here, I suppose.
166 secdebug("machsrv", "RunloopServer cannot post reply: %s", mach_error_string(err));
167 active().releaseDeferredAllocations();
168 return;
169 }
170 active().releaseDeferredAllocations();
171 return;
172 }
173
174
175 } // end namespace MachPlusPlus
176 } // end namespace Security