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