]> git.saurik.com Git - apple/configd.git/blob - libSystemConfiguration/libSystemConfiguration_client.c
configd-888.1.2.tar.gz
[apple/configd.git] / libSystemConfiguration / libSystemConfiguration_client.c
1 /*
2 * Copyright (c) 2012, 2013, 2015, 2016 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 #include <Availability.h>
25 #include <TargetConditionals.h>
26 #include <dispatch/dispatch.h>
27 #include <dispatch/private.h>
28 #include <os/log.h>
29 #include <vproc.h>
30 #include <vproc_priv.h>
31 #include <xpc/xpc.h>
32
33 #include "libSystemConfiguration_client.h"
34
35
36 #pragma mark -
37 #pragma mark libSC fork handlers
38
39
40 static boolean_t _available = TRUE;
41
42 // These functions are registered with libSystem to
43 // handle pthread_atfork callbacks.
44
45 void
46 _libSC_info_fork_prepare()
47 {
48 return;
49 }
50
51 void
52 _libSC_info_fork_parent()
53 {
54 return;
55 }
56
57 void
58 _libSC_info_fork_child()
59 {
60 if (_dispatch_is_fork_of_multithreaded_parent()) {
61 _available = FALSE;
62 }
63
64 return;
65 }
66
67
68 #pragma mark -
69 #pragma mark Support functions
70
71
72 static void
73 log_xpc_object(const char *msg, xpc_object_t obj)
74 {
75 char *desc;
76
77 desc = xpc_copy_description(obj);
78 os_log(OS_LOG_DEFAULT, "%s = %s", msg, desc);
79 free(desc);
80 }
81
82
83 __private_extern__
84 _Bool
85 libSC_info_available()
86 {
87 return _available;
88 }
89
90
91 static void
92 libSC_info_client_dealloc(libSC_info_client_t *client)
93 {
94 free(client->service_description);
95 free(client->service_name);
96 free(client);
97 return;
98 }
99
100
101 __private_extern__
102 libSC_info_client_t *
103 libSC_info_client_create(dispatch_queue_t q,
104 const char *service_name,
105 const char *service_description)
106 {
107 xpc_connection_t c;
108 libSC_info_client_t *client;
109 #if !TARGET_OS_SIMULATOR
110 const uint64_t flags = XPC_CONNECTION_MACH_SERVICE_PRIVILEGED;
111 #else // !TARGET_OS_SIMULATOR
112 const uint64_t flags = 0;
113 #endif // !TARGET_OS_SIMULATOR
114
115 if (!_available) {
116 return NULL;
117 }
118
119 client = malloc(sizeof(libSC_info_client_t));
120 client->active = TRUE;
121 client->service_description = strdup(service_description);
122 client->service_name = strdup(service_name);
123
124 c = xpc_connection_create_mach_service(service_name, q, flags);
125
126 xpc_connection_set_event_handler(c, ^(xpc_object_t xobj) {
127 xpc_type_t type;
128
129 type = xpc_get_type(xobj);
130 if (type == XPC_TYPE_DICTIONARY) {
131 os_log(OS_LOG_DEFAULT, "%s: unexpected message", client->service_name);
132 log_xpc_object(" dict = ", xobj);
133 } else if (type == XPC_TYPE_ERROR) {
134 if (xobj == XPC_ERROR_CONNECTION_INVALID) {
135 os_log(OS_LOG_DEFAULT, "%s: server not available", client->service_name);
136 client->active = FALSE;
137 } else if (xobj == XPC_ERROR_CONNECTION_INTERRUPTED) {
138 os_log_debug(OS_LOG_DEFAULT, "%s: server failed", client->service_name);
139 } else {
140 const char *desc;
141
142 desc = xpc_dictionary_get_string(xobj, XPC_ERROR_KEY_DESCRIPTION);
143 os_log_debug(OS_LOG_DEFAULT,
144 "%s: connection error: %d : %s",
145 client->service_name,
146 xpc_connection_get_pid(c),
147 desc);
148 }
149 } else {
150 os_log(OS_LOG_DEFAULT,
151 "%s: unknown event type : %p",
152 client->service_name,
153 type);
154 }
155 });
156
157 client->connection = c;
158
159 xpc_connection_set_context(c, client);
160 xpc_connection_set_finalizer_f(c, (xpc_finalizer_t)libSC_info_client_dealloc);
161
162 xpc_connection_resume(c);
163
164 return client;
165 }
166
167
168 __private_extern__
169 void
170 libSC_info_client_release(libSC_info_client_t *client)
171 {
172 xpc_release(client->connection);
173 return;
174 }
175
176
177 __private_extern__
178 xpc_object_t
179 libSC_send_message_with_reply_sync(libSC_info_client_t *client,
180 xpc_object_t message)
181 {
182 xpc_object_t reply;
183
184 while (TRUE) {
185 // send request to the DNS configuration server
186 reply = xpc_connection_send_message_with_reply_sync(client->connection, message);
187 if (reply != NULL) {
188 xpc_type_t type;
189
190 type = xpc_get_type(reply);
191 if (type == XPC_TYPE_DICTIONARY) {
192 // reply available
193 break;
194 }
195
196 if ((type == XPC_TYPE_ERROR) && (reply == XPC_ERROR_CONNECTION_INTERRUPTED)) {
197 os_log_debug(OS_LOG_DEFAULT,
198 "%s server failure, retrying",
199 client->service_description);
200 // retry request
201 xpc_release(reply);
202 continue;
203 }
204
205 if ((type == XPC_TYPE_ERROR) && (reply == XPC_ERROR_CONNECTION_INVALID)) {
206 os_log(OS_LOG_DEFAULT,
207 "%s server not available",
208 client->service_description);
209 client->active = FALSE;
210 } else {
211 os_log(OS_LOG_DEFAULT,
212 "%s xpc_connection_send_message_with_reply_sync() with unexpected reply",
213 client->service_description);
214 log_xpc_object(" reply", reply);
215 }
216
217 xpc_release(reply);
218 reply = NULL;
219 break;
220 }
221 }
222
223 return reply;
224 }