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