]> git.saurik.com Git - apple/configd.git/blob - configd.tproj/configd_server.c
configd-395.10.tar.gz
[apple/configd.git] / configd.tproj / configd_server.c
1 /*
2 * Copyright (c) 2000-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 /*
25 * Modification History
26 *
27 * March 9, 2004 Allan Nathanson <ajn@apple.com>
28 * - add DNS configuration server
29 *
30 * June 1, 2001 Allan Nathanson <ajn@apple.com>
31 * - public API conversion
32 *
33 * March 24, 2000 Allan Nathanson <ajn@apple.com>
34 * - initial revision
35 */
36
37 #include <sysexits.h>
38 #include <unistd.h>
39 #include <sys/types.h>
40 #include <servers/bootstrap.h>
41
42 #include "configd.h"
43 #include "configd_server.h"
44 #include "notify_server.h"
45 #include "session.h"
46
47 /* MiG generated externals and functions */
48 extern struct mig_subsystem _config_subsystem;
49 extern boolean_t config_server(mach_msg_header_t *, mach_msg_header_t *);
50
51 #include "shared_dns_info_types.h"
52 #include "dnsinfo_server.h"
53
54 /* MiG generated externals and functions */
55 extern struct mig_subsystem _shared_dns_info_subsystem;
56 extern boolean_t shared_dns_info_server(mach_msg_header_t *, mach_msg_header_t *);
57
58 /* configd server port (for new session requests) */
59 static CFMachPortRef configd_port = NULL;
60
61 __private_extern__
62 boolean_t
63 config_demux(mach_msg_header_t *request, mach_msg_header_t *reply)
64 {
65 Boolean processed = FALSE;
66
67 /*
68 * (attempt to) process SCDynamicStore requests.
69 */
70 processed = config_server(request, reply);
71 if (processed) {
72 return TRUE;
73 }
74
75 /*
76 * (attempt to) process DNS configuration requests.
77 */
78 processed = shared_dns_info_server(request, reply);
79 if (processed) {
80 return TRUE;
81 }
82
83 /*
84 * (attempt to) process (NO MORE SENDERS) notification messages.
85 */
86 processed = notify_server(request, reply);
87 if (processed) {
88 return TRUE;
89 }
90
91 /*
92 * unknown message ID, log and return an error.
93 */
94 SCLog(TRUE, LOG_ERR, CFSTR("config_demux(): unknown message ID (%d) received"), request->msgh_id);
95 reply->msgh_bits = MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(request->msgh_bits), 0);
96 reply->msgh_remote_port = request->msgh_remote_port;
97 reply->msgh_size = sizeof(mig_reply_error_t); /* Minimal size */
98 reply->msgh_local_port = MACH_PORT_NULL;
99 reply->msgh_id = request->msgh_id + 100;
100 ((mig_reply_error_t *)reply)->NDR = NDR_record;
101 ((mig_reply_error_t *)reply)->RetCode = MIG_BAD_ID;
102
103 return FALSE;
104 }
105
106
107 #define MACH_MSG_BUFFER_SIZE 128
108
109
110 __private_extern__
111 void
112 configdCallback(CFMachPortRef port, void *msg, CFIndex size, void *info)
113 {
114 mig_reply_error_t * bufRequest = msg;
115 uint32_t bufReply_q[MACH_MSG_BUFFER_SIZE/sizeof(uint32_t)];
116 mig_reply_error_t * bufReply = (mig_reply_error_t *)bufReply_q;
117 static CFIndex bufSize = 0;
118 mach_msg_return_t mr;
119 int options;
120
121 if (bufSize == 0) {
122 // get max size for MiG reply buffers
123 bufSize = _config_subsystem.maxsize;
124 if (_shared_dns_info_subsystem.maxsize > bufSize) {
125 bufSize = _shared_dns_info_subsystem.maxsize;
126 }
127
128 // check if our on-the-stack reply buffer will be big enough
129 if (bufSize > sizeof(bufReply_q)) {
130 SCLog(TRUE, LOG_NOTICE,
131 CFSTR("configdCallback(): buffer size should be increased > %d"),
132 _config_subsystem.maxsize);
133 }
134 }
135
136 if (bufSize > sizeof(bufReply_q)) {
137 bufReply = CFAllocatorAllocate(NULL, _config_subsystem.maxsize, 0);
138 }
139 bufReply->RetCode = 0;
140
141 /* we have a request message */
142 (void) config_demux(&bufRequest->Head, &bufReply->Head);
143
144 if (!(bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)) {
145 if (bufReply->RetCode == MIG_NO_REPLY) {
146 bufReply->Head.msgh_remote_port = MACH_PORT_NULL;
147 } else if ((bufReply->RetCode != KERN_SUCCESS) &&
148 (bufRequest->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)) {
149 /*
150 * destroy the request - but not the reply port
151 */
152 bufRequest->Head.msgh_remote_port = MACH_PORT_NULL;
153 mach_msg_destroy(&bufRequest->Head);
154 }
155 }
156
157 if (bufReply->Head.msgh_remote_port != MACH_PORT_NULL) {
158 /*
159 * send reply.
160 *
161 * We don't want to block indefinitely because the client
162 * isn't receiving messages from the reply port.
163 * If we have a send-once right for the reply port, then
164 * this isn't a concern because the send won't block.
165 * If we have a send right, we need to use MACH_SEND_TIMEOUT.
166 * To avoid falling off the kernel's fast RPC path unnecessarily,
167 * we only supply MACH_SEND_TIMEOUT when absolutely necessary.
168 */
169
170 options = MACH_SEND_MSG;
171 if (MACH_MSGH_BITS_REMOTE(bufReply->Head.msgh_bits) != MACH_MSG_TYPE_MOVE_SEND_ONCE) {
172 options |= MACH_SEND_TIMEOUT;
173 }
174 mr = mach_msg(&bufReply->Head, /* msg */
175 options, /* option */
176 bufReply->Head.msgh_size, /* send_size */
177 0, /* rcv_size */
178 MACH_PORT_NULL, /* rcv_name */
179 MACH_MSG_TIMEOUT_NONE, /* timeout */
180 MACH_PORT_NULL); /* notify */
181
182 /* Has a message error occurred? */
183 switch (mr) {
184 case MACH_SEND_INVALID_DEST:
185 case MACH_SEND_TIMED_OUT:
186 break;
187 default :
188 /* Includes success case. */
189 goto done;
190 }
191 }
192
193 if (bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) {
194 mach_msg_destroy(&bufReply->Head);
195 }
196
197 done :
198
199 if (bufReply != (mig_reply_error_t *)bufReply_q)
200 CFAllocatorDeallocate(NULL, bufReply);
201 return;
202 }
203
204
205 static CFStringRef
206 serverMPCopyDescription(const void *info)
207 {
208 return CFStringCreateWithFormat(NULL, NULL, CFSTR("<main DynamicStore MP>"));
209 }
210
211
212 __private_extern__
213 void
214 server_init()
215 {
216 serverSessionRef mySession;
217 CFRunLoopSourceRef rls;
218 char *service_name;
219 mach_port_t service_port = MACH_PORT_NULL;
220 kern_return_t status;
221
222 service_name = getenv("SCD_SERVER");
223 if (!service_name) {
224 service_name = SCD_SERVER;
225 }
226
227 /* Check "configd" server status */
228 status = bootstrap_check_in(bootstrap_port, service_name, &service_port);
229 switch (status) {
230 case BOOTSTRAP_SUCCESS :
231 /* if we are being [re-]started by launchd */
232 break;
233 case BOOTSTRAP_NOT_PRIVILEGED :
234 /* if another instance of the server is starting */
235 SCLog(TRUE, LOG_ERR, CFSTR("'%s' server already starting"), service_name);
236 exit (EX_UNAVAILABLE);
237 case BOOTSTRAP_SERVICE_ACTIVE :
238 /* if another instance of the server is active */
239 SCLog(TRUE, LOG_ERR, CFSTR("'%s' server already active"), service_name);
240 exit (EX_UNAVAILABLE);
241 default :
242 SCLog(TRUE, LOG_ERR,
243 CFSTR("server_init bootstrap_check_in() failed: %s"),
244 bootstrap_strerror(status));
245 exit (EX_UNAVAILABLE);
246 }
247
248 /* Create the primary / new connection port and backing session */
249 mySession = addSession(service_port, serverMPCopyDescription);
250 configd_port = mySession->serverPort;
251
252 /*
253 * Create and add a run loop source for the port and add this source
254 * to both the default run loop mode and the "locked" mode. These two
255 * modes will be used for normal (unlocked) communication with the
256 * server and when multiple (locked) updates are requested by a single
257 * session.
258 */
259 rls = CFMachPortCreateRunLoopSource(NULL, configd_port, 0);
260 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
261 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, CFSTR("locked"));
262 CFRelease(rls);
263
264 return;
265 }
266
267
268 __private_extern__
269 int
270 server_shutdown()
271 {
272 if (configd_port != NULL) {
273 mach_port_t service_port = CFMachPortGetPort(configd_port);
274
275 CFMachPortSetInvalidationCallBack(configd_port, NULL);
276 CFMachPortInvalidate(configd_port);
277 CFRelease(configd_port);
278 configd_port = NULL;
279
280 if (service_port != MACH_PORT_NULL) {
281 (void) mach_port_mod_refs(mach_task_self(),
282 service_port,
283 MACH_PORT_RIGHT_RECEIVE,
284 -1);
285 }
286 }
287
288 return EX_OK;
289 }
290
291
292 __private_extern__
293 void
294 server_loop()
295 {
296 CFStringRef rlMode;
297
298 pthread_setname_np("SCDynamicStore");
299
300 while (TRUE) {
301 /*
302 * process one run loop event
303 */
304 rlMode = (storeLocked > 0) ? CFSTR("locked") : kCFRunLoopDefaultMode;
305 CFRunLoopRunInMode(rlMode, 1.0e10, TRUE);
306
307 /*
308 * check for, and if necessary, push out change notifications
309 * to other processes.
310 */
311 pushNotifications(_configd_trace);
312 }
313 }