2 * Copyright (c) 2000-2011, 2013, 2015 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 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
;
93 #define MACH_MSG_BUFFER_SIZE 128
98 configdCallback(CFMachPortRef port
, void *msg
, CFIndex size
, void *info
)
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
;
108 activity_id
= os_activity_start("processing SCDynamicStore request",
109 OS_ACTIVITY_FLAG_DEFAULT
);
112 // get max size for MiG reply buffers
113 bufSize
= _config_subsystem
.maxsize
;
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
);
122 if (bufSize
> sizeof(bufReply_q
)) {
123 bufReply
= CFAllocatorAllocate(NULL
, _config_subsystem
.maxsize
, 0);
125 bufReply
->RetCode
= 0;
127 /* we have a request message */
128 (void) config_demux(&bufRequest
->Head
, &bufReply
->Head
);
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
)) {
136 * destroy the request - but not the reply port
138 bufRequest
->Head
.msgh_remote_port
= MACH_PORT_NULL
;
139 mach_msg_destroy(&bufRequest
->Head
);
143 if (bufReply
->Head
.msgh_remote_port
!= MACH_PORT_NULL
) {
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.
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
;
160 mr
= mach_msg(&bufReply
->Head
, /* msg */
161 options
, /* option */
162 bufReply
->Head
.msgh_size
, /* send_size */
164 MACH_PORT_NULL
, /* rcv_name */
165 MACH_MSG_TIMEOUT_NONE
, /* timeout */
166 MACH_PORT_NULL
); /* notify */
168 /* Has a message error occurred? */
170 case MACH_SEND_INVALID_DEST
:
171 case MACH_SEND_TIMED_OUT
:
174 /* Includes success case. */
179 if (bufReply
->Head
.msgh_bits
& MACH_MSGH_BITS_COMPLEX
) {
180 mach_msg_destroy(&bufReply
->Head
);
185 if (bufReply
!= (mig_reply_error_t
*)bufReply_q
)
186 CFAllocatorDeallocate(NULL
, bufReply
);
188 os_activity_end(activity_id
);
195 serverMPCopyDescription(const void *info
)
197 return CFStringCreateWithFormat(NULL
, NULL
, CFSTR("<main DynamicStore MP>"));
205 serverSessionRef mySession
;
207 CFRunLoopSourceRef rls
;
209 mach_port_t service_port
= MACH_PORT_NULL
;
210 kern_return_t status
;
212 service_name
= getenv("SCD_SERVER");
214 service_name
= SCD_SERVER
;
217 /* Check "configd" server status */
218 status
= bootstrap_check_in(bootstrap_port
, service_name
, &service_port
);
220 case BOOTSTRAP_SUCCESS
:
221 /* if we are being [re-]started by launchd */
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
);
232 SC_log(LOG_ERR
, "server_init bootstrap_check_in(..., '%s', ...) failed: %s",
234 bootstrap_strerror(status
));
235 exit (EX_UNAVAILABLE
);
238 /* Create the primary / new connection port and backing session */
239 mySession
= addSession(service_port
, serverMPCopyDescription
);
240 configd_port
= mySession
->serverPort
;
243 * Create and add a run loop source for the port and add this source
244 * to the default run loop mode.
246 rls
= CFMachPortCreateRunLoopSource(NULL
, configd_port
, 0);
247 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls
, kCFRunLoopDefaultMode
);
250 // bump thread QoS priority
251 ret
= pthread_set_qos_class_self_np(QOS_CLASS_USER_INITIATED
, 0);
253 SC_log(LOG_ERR
, "pthread_set_qos_class_self_np() failed: %s", strerror(errno
));
264 if (configd_port
!= NULL
) {
265 mach_port_t service_port
= CFMachPortGetPort(configd_port
);
267 CFMachPortInvalidate(configd_port
);
268 CFRelease(configd_port
);
271 if (service_port
!= MACH_PORT_NULL
) {
272 (void) mach_port_mod_refs(mach_task_self(),
274 MACH_PORT_RIGHT_RECEIVE
,
287 pthread_setname_np("SCDynamicStore");
291 * process one run loop event
293 CFRunLoopRunInMode(kCFRunLoopDefaultMode
, 1.0e10
, TRUE
);
296 * check for, and if necessary, push out change notifications
297 * to other processes.
299 pushNotifications(_configd_trace
);