2 * Copyright (c) 2000-2011, 2013 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 * Modification History
27 * March 9, 2004 Allan Nathanson <ajn@apple.com>
28 * - add DNS configuration server
30 * June 1, 2001 Allan Nathanson <ajn@apple.com>
31 * - public API conversion
33 * March 24, 2000 Allan Nathanson <ajn@apple.com>
37 #include <TargetConditionals.h>
40 #include <sys/types.h>
41 #include <servers/bootstrap.h>
44 #include "configd_server.h"
45 #include "notify_server.h"
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
*);
52 /* configd server port (for new session requests) */
53 static CFMachPortRef configd_port
= NULL
;
57 config_demux(mach_msg_header_t
*request
, mach_msg_header_t
*reply
)
59 Boolean processed
= FALSE
;
62 * (attempt to) process SCDynamicStore requests.
64 processed
= config_server(request
, reply
);
70 * (attempt to) process (NO MORE SENDERS) notification messages.
72 processed
= notify_server(request
, reply
);
78 * unknown message ID, log and return an error.
80 SCLog(TRUE
, LOG_ERR
, CFSTR("config_demux(): 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
;
93 #define MACH_MSG_BUFFER_SIZE 128
98 configdCallback(CFMachPortRef port
, void *msg
, CFIndex size
, void *info
)
100 mig_reply_error_t
* bufRequest
= msg
;
101 uint32_t bufReply_q
[MACH_MSG_BUFFER_SIZE
/sizeof(uint32_t)];
102 mig_reply_error_t
* bufReply
= (mig_reply_error_t
*)bufReply_q
;
103 static CFIndex bufSize
= 0;
104 mach_msg_return_t mr
;
108 // get max size for MiG reply buffers
109 bufSize
= _config_subsystem
.maxsize
;
111 // check if our on-the-stack reply buffer will be big enough
112 if (bufSize
> sizeof(bufReply_q
)) {
113 SCLog(TRUE
, LOG_NOTICE
,
114 CFSTR("configdCallback(): buffer size should be increased > %d"),
115 _config_subsystem
.maxsize
);
119 if (bufSize
> sizeof(bufReply_q
)) {
120 bufReply
= CFAllocatorAllocate(NULL
, _config_subsystem
.maxsize
, 0);
122 bufReply
->RetCode
= 0;
124 /* we have a request message */
125 (void) config_demux(&bufRequest
->Head
, &bufReply
->Head
);
127 if (!(bufReply
->Head
.msgh_bits
& MACH_MSGH_BITS_COMPLEX
)) {
128 if (bufReply
->RetCode
== MIG_NO_REPLY
) {
129 bufReply
->Head
.msgh_remote_port
= MACH_PORT_NULL
;
130 } else if ((bufReply
->RetCode
!= KERN_SUCCESS
) &&
131 (bufRequest
->Head
.msgh_bits
& MACH_MSGH_BITS_COMPLEX
)) {
133 * destroy the request - but not the reply port
135 bufRequest
->Head
.msgh_remote_port
= MACH_PORT_NULL
;
136 mach_msg_destroy(&bufRequest
->Head
);
140 if (bufReply
->Head
.msgh_remote_port
!= MACH_PORT_NULL
) {
144 * We don't want to block indefinitely because the client
145 * isn't receiving messages from the reply port.
146 * If we have a send-once right for the reply port, then
147 * this isn't a concern because the send won't block.
148 * If we have a send right, we need to use MACH_SEND_TIMEOUT.
149 * To avoid falling off the kernel's fast RPC path unnecessarily,
150 * we only supply MACH_SEND_TIMEOUT when absolutely necessary.
153 options
= MACH_SEND_MSG
;
154 if (MACH_MSGH_BITS_REMOTE(bufReply
->Head
.msgh_bits
) != MACH_MSG_TYPE_MOVE_SEND_ONCE
) {
155 options
|= MACH_SEND_TIMEOUT
;
157 mr
= mach_msg(&bufReply
->Head
, /* msg */
158 options
, /* option */
159 bufReply
->Head
.msgh_size
, /* send_size */
161 MACH_PORT_NULL
, /* rcv_name */
162 MACH_MSG_TIMEOUT_NONE
, /* timeout */
163 MACH_PORT_NULL
); /* notify */
165 /* Has a message error occurred? */
167 case MACH_SEND_INVALID_DEST
:
168 case MACH_SEND_TIMED_OUT
:
171 /* Includes success case. */
176 if (bufReply
->Head
.msgh_bits
& MACH_MSGH_BITS_COMPLEX
) {
177 mach_msg_destroy(&bufReply
->Head
);
182 if (bufReply
!= (mig_reply_error_t
*)bufReply_q
)
183 CFAllocatorDeallocate(NULL
, bufReply
);
189 serverMPCopyDescription(const void *info
)
191 return CFStringCreateWithFormat(NULL
, NULL
, CFSTR("<main DynamicStore MP>"));
199 serverSessionRef mySession
;
200 CFRunLoopSourceRef rls
;
202 mach_port_t service_port
= MACH_PORT_NULL
;
203 kern_return_t status
;
205 service_name
= getenv("SCD_SERVER");
207 service_name
= SCD_SERVER
;
210 /* Check "configd" server status */
211 status
= bootstrap_check_in(bootstrap_port
, service_name
, &service_port
);
213 case BOOTSTRAP_SUCCESS
:
214 /* if we are being [re-]started by launchd */
216 case BOOTSTRAP_NOT_PRIVILEGED
:
217 /* if another instance of the server is starting */
218 SCLog(TRUE
, LOG_ERR
, CFSTR("'%s' server already starting"), service_name
);
219 exit (EX_UNAVAILABLE
);
220 case BOOTSTRAP_SERVICE_ACTIVE
:
221 /* if another instance of the server is active */
222 SCLog(TRUE
, LOG_ERR
, CFSTR("'%s' server already active"), service_name
);
223 exit (EX_UNAVAILABLE
);
226 CFSTR("server_init bootstrap_check_in(..., '%s', ...) failed: %s"),
228 bootstrap_strerror(status
));
229 exit (EX_UNAVAILABLE
);
232 /* Create the primary / new connection port and backing session */
233 mySession
= addSession(service_port
, serverMPCopyDescription
);
234 configd_port
= mySession
->serverPort
;
237 * Create and add a run loop source for the port and add this source
238 * to the default run loop mode.
240 rls
= CFMachPortCreateRunLoopSource(NULL
, configd_port
, 0);
241 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls
, kCFRunLoopDefaultMode
);
252 if (configd_port
!= NULL
) {
253 mach_port_t service_port
= CFMachPortGetPort(configd_port
);
255 CFMachPortInvalidate(configd_port
);
256 CFRelease(configd_port
);
259 if (service_port
!= MACH_PORT_NULL
) {
260 (void) mach_port_mod_refs(mach_task_self(),
262 MACH_PORT_RIGHT_RECEIVE
,
275 pthread_setname_np("SCDynamicStore");
279 * process one run loop event
281 CFRunLoopRunInMode(kCFRunLoopDefaultMode
, 1.0e10
, TRUE
);
284 * check for, and if necessary, push out change notifications
285 * to other processes.
287 pushNotifications(_configd_trace
);