this repo has no description
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 <TargetConditionals.h>
25#include <dispatch/dispatch.h>
26#include <dispatch/private.h>
27#include <os/log.h>
28#include <vproc.h>
29#include <vproc_priv.h>
30#include <xpc/xpc.h>
31
32#include "libSystemConfiguration_client.h"
33#include "libSystemConfiguration_internal.h"
34
35
36#pragma mark -
37#pragma mark libSC fork handlers
38
39
40static boolean_t _available = TRUE;
41
42// These functions are registered with libSystem to
43// handle pthread_atfork callbacks.
44
45void
46_libSC_info_fork_prepare()
47{
48 return;
49}
50
51void
52_libSC_info_fork_parent()
53{
54 return;
55}
56
57void
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
72static void
73log_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
85libSC_info_available()
86{
87 return _available;
88}
89
90
91static void
92libSC_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__
102libSC_info_client_t *
103libSC_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 || TARGET_OS_IOSMAC
110 const uint64_t flags = XPC_CONNECTION_MACH_SERVICE_PRIVILEGED;
111#else // !TARGET_OS_SIMULATOR || TARGET_OS_IOSMAC
112 const uint64_t flags = 0;
113#endif // !TARGET_OS_SIMULATOR || TARGET_OS_IOSMAC
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__
169void
170libSC_info_client_release(libSC_info_client_t *client)
171{
172 xpc_release(client->connection);
173 return;
174}
175
176
177__private_extern__
178xpc_object_t
179libSC_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}