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