X-Git-Url: https://git.saurik.com/apple/configd.git/blobdiff_plain/1e2cbe6aa7461cd7abf510b7c26db26974657962..5e9ce69ef59d7d98ff13748ce18266968031faaf:/libSystemConfiguration/libSystemConfiguration_client.c diff --git a/libSystemConfiguration/libSystemConfiguration_client.c b/libSystemConfiguration/libSystemConfiguration_client.c new file mode 100644 index 0000000..5023329 --- /dev/null +++ b/libSystemConfiguration/libSystemConfiguration_client.c @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2012, 2013 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "libSystemConfiguration_client.h" + + +#pragma mark - +#pragma mark libSC fork handlers + + +__attribute__((weak_import)) bool _dispatch_is_multithreaded(void); + +static boolean_t _has_forked = FALSE; + +// These functions are registered with libSystem to +// handle pthread_atfork callbacks. + +void +_libSC_info_fork_prepare() +{ + return; +} + +void +_libSC_info_fork_parent() +{ + return; +} + +void +_libSC_info_fork_child() +{ + if (_dispatch_is_multithreaded()) { + // if dispatch was active before fork + _has_forked = TRUE; + } + + return; +} + + +#pragma mark - +#pragma mark Support functions + + +static void +log_xpc_object(const char *msg, xpc_object_t obj) +{ + char *desc; + + desc = xpc_copy_description(obj); + asl_log(NULL, NULL, ASL_LEVEL_ERR, "%s = %s", msg, desc); + free(desc); +} + + +__private_extern__ +libSC_info_client_t * +libSC_info_client_create(dispatch_queue_t q, + const char *service_name, + const char *service_description) +{ + xpc_connection_t c; + libSC_info_client_t *client; +#if !TARGET_IPHONE_SIMULATOR + const uint64_t flags = XPC_CONNECTION_MACH_SERVICE_PRIVILEGED; +#else // !TARGET_IPHONE_SIMULATOR + const uint64_t flags = 0; +#endif // !TARGET_IPHONE_SIMULATOR + + if (_has_forked) { + return NULL; + } + + client = malloc(sizeof(libSC_info_client_t)); + client->active = TRUE; + client->service_description = strdup(service_description); + client->service_name = strdup(service_name); + + c = xpc_connection_create_mach_service(service_name, q, flags); + + xpc_connection_set_event_handler(c, ^(xpc_object_t xobj) { + xpc_type_t type; + + type = xpc_get_type(xobj); + if (type == XPC_TYPE_DICTIONARY) { + asl_log(NULL, NULL, ASL_LEVEL_ERR, "%s: unexpected message", client->service_name); + log_xpc_object(" dict = ", xobj); + } else if (type == XPC_TYPE_ERROR) { + if (xobj == XPC_ERROR_CONNECTION_INVALID) { + asl_log(NULL, NULL, ASL_LEVEL_ERR, "%s: server not available", client->service_name); + client->active = FALSE; + } else if (xobj == XPC_ERROR_CONNECTION_INTERRUPTED) { + asl_log(NULL, NULL, ASL_LEVEL_DEBUG, "%s: server failed", client->service_name); + } else { + const char *desc; + + desc = xpc_dictionary_get_string(xobj, XPC_ERROR_KEY_DESCRIPTION); + asl_log(NULL, NULL, ASL_LEVEL_DEBUG, + "%s: connection error: %d : %s", + client->service_name, + xpc_connection_get_pid(c), + desc); + } + + } else { + asl_log(NULL, NULL, ASL_LEVEL_ERR, + "%s: unknown event type : %p", + client->service_name, + type); + } + }); + + client->connection = c; + + xpc_connection_resume(c); + + return client; +} + + +__private_extern__ +void +libSC_info_client_release(libSC_info_client_t *client) +{ + xpc_release(client->connection); + free(client->service_description); + free(client->service_name); + free(client); +} + + +__private_extern__ +xpc_object_t +libSC_send_message_with_reply_sync(libSC_info_client_t *client, + xpc_object_t message) +{ + xpc_object_t reply; + + while (TRUE) { + // send request to the DNS configuration server + reply = xpc_connection_send_message_with_reply_sync(client->connection, message); + if (reply != NULL) { + xpc_type_t type; + + type = xpc_get_type(reply); + if (type == XPC_TYPE_DICTIONARY) { + // reply available + break; + } + + if ((type == XPC_TYPE_ERROR) && (reply == XPC_ERROR_CONNECTION_INTERRUPTED)) { + asl_log(NULL, NULL, ASL_LEVEL_DEBUG, + "%s server failure, retrying", + client->service_description); + // retry request + xpc_release(reply); + continue; + } + + if ((type == XPC_TYPE_ERROR) && (reply == XPC_ERROR_CONNECTION_INVALID)) { + asl_log(NULL, NULL, ASL_LEVEL_ERR, + "%s server not available", + client->service_description); + client->active = FALSE; + } else { + asl_log(NULL, NULL, ASL_LEVEL_ERR, + "%s xpc_connection_send_message_with_reply_sync() with unexpected reply", + client->service_description); + log_xpc_object(" reply", reply); + } + + xpc_release(reply); + reply = NULL; + break; + } + } + + return reply; +}