]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCDNotifierWait.c
configd-42.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / SCDNotifierWait.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22
23 /*
24 * Modification History
25 *
26 * June 1, 2001 Allan Nathanson <ajn@apple.com>
27 * - public API conversion
28 *
29 * March 31, 2000 Allan Nathanson <ajn@apple.com>
30 * - initial revision
31 */
32
33 #include <mach/mach.h>
34 #include <mach/mach_error.h>
35
36 #include <SystemConfiguration/SystemConfiguration.h>
37 #include <SystemConfiguration/SCPrivate.h>
38 #include "SCDynamicStoreInternal.h"
39 #include "config.h" /* MiG generated file */
40
41 static mach_msg_id_t
42 waitForMachMessage(mach_port_t port)
43 {
44 kern_return_t status;
45 mach_msg_empty_rcv_t *buf;
46
47 mach_msg_size_t size = sizeof(mach_msg_empty_t) + MAX_TRAILER_SIZE;
48
49 status = vm_allocate(mach_task_self(), (vm_address_t *)&buf, size, TRUE);
50 if (status != KERN_SUCCESS) {
51 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("vm_allocate(): %s"), mach_error_string(status));
52 return -1;
53 }
54
55 status = mach_msg(&buf->header, /* msg */
56 MACH_RCV_MSG, /* options */
57 0, /* send_size */
58 size, /* rcv_size */
59 port, /* rcv_name */
60 MACH_MSG_TIMEOUT_NONE, /* timeout */
61 MACH_PORT_NULL); /* notify */
62 if (status != KERN_SUCCESS) {
63 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("mach_msg(): %s"), mach_error_string(status));
64 return -1;
65 }
66
67 return buf->header.msgh_id;
68 }
69
70
71 Boolean
72 SCDynamicStoreNotifyWait(SCDynamicStoreRef store)
73 {
74 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store;
75 kern_return_t status;
76 mach_port_t port;
77 mach_port_t oldNotify;
78 int sc_status;
79 mach_msg_id_t msgid;
80
81 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("SCDynamicStoreNotifyWait:"));
82
83 if (!store) {
84 /* sorry, you must provide a session */
85 _SCErrorSet(kSCStatusNoStoreSession);
86 return FALSE;
87 }
88
89 if (storePrivate->server == MACH_PORT_NULL) {
90 /* sorry, you must have an open session to play */
91 _SCErrorSet(kSCStatusNoStoreServer);
92 return FALSE;
93 }
94
95 if (storePrivate->notifyStatus != NotifierNotRegistered) {
96 /* sorry, you can only have one notification registered at once */
97 _SCErrorSet(kSCStatusNotifierActive);
98 return FALSE;
99 }
100
101 /* Allocating port (for server response) */
102 status = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port);
103 if (status != KERN_SUCCESS) {
104 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("mach_port_allocate(): %s"), mach_error_string(status));
105 _SCErrorSet(status);
106 return FALSE;
107 }
108 SCLog(_sc_verbose, LOG_DEBUG, CFSTR(" port = %d"), port);
109
110 status = mach_port_insert_right(mach_task_self(),
111 port,
112 port,
113 MACH_MSG_TYPE_MAKE_SEND);
114 if (status != KERN_SUCCESS) {
115 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("mach_port_insert_right(): %s"), mach_error_string(status));
116 (void) mach_port_destroy(mach_task_self(), port);
117 _SCErrorSet(status);
118 return FALSE;
119 }
120
121 /* Request a notification when/if the server dies */
122 status = mach_port_request_notification(mach_task_self(),
123 port,
124 MACH_NOTIFY_NO_SENDERS,
125 1,
126 port,
127 MACH_MSG_TYPE_MAKE_SEND_ONCE,
128 &oldNotify);
129 if (status != KERN_SUCCESS) {
130 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("mach_port_request_notification(): %s"), mach_error_string(status));
131 (void) mach_port_destroy(mach_task_self(), port);
132 _SCErrorSet(status);
133 return FALSE;
134 }
135
136 if (oldNotify != MACH_PORT_NULL) {
137 SCLog(_sc_verbose, LOG_ERR, CFSTR("SCDynamicStoreNotifyWait(): why is oldNotify != MACH_PORT_NULL?"));
138 }
139
140 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("Requesting notification via mach port %d"), port);
141 status = notifyviaport(storePrivate->server,
142 port,
143 0,
144 (int *)&sc_status);
145
146 if (status != KERN_SUCCESS) {
147 if (status != MACH_SEND_INVALID_DEST)
148 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("notifyviaport(): %s"), mach_error_string(status));
149 (void) mach_port_destroy(mach_task_self(), storePrivate->server);
150 storePrivate->server = MACH_PORT_NULL;
151 _SCErrorSet(status);
152 return FALSE;
153 }
154
155 if (sc_status != kSCStatusOK) {
156 _SCErrorSet(sc_status);
157 return FALSE;
158 }
159
160 /* set notifier active */
161 storePrivate->notifyStatus = Using_NotifierWait;
162
163 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("Waiting..."));
164
165 msgid = waitForMachMessage(port);
166
167 /* set notifier inactive */
168 storePrivate->notifyStatus = NotifierNotRegistered;
169
170 if (msgid == MACH_NOTIFY_NO_SENDERS) {
171 /* the server closed the notifier port */
172 SCLog(_sc_verbose, LOG_DEBUG, CFSTR(" notifier port closed, destroying port %d"), port);
173 _SCErrorSet(kSCStatusNoStoreServer);
174 return FALSE;
175 }
176
177 if (msgid == -1) {
178 /* one of the mach routines returned an error */
179 SCLog(_sc_verbose, LOG_DEBUG, CFSTR(" communication with server failed, destroying port %d"), port);
180 (void) mach_port_destroy(mach_task_self(), port);
181 _SCErrorSet(kSCStatusNoStoreServer);
182 return FALSE;
183 }
184
185 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("Something changed, cancelling notification request"));
186 status = notifycancel(storePrivate->server,
187 (int *)&sc_status);
188
189 if (status != KERN_SUCCESS) {
190 if (status != MACH_SEND_INVALID_DEST)
191 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("notifycancel(): %s"), mach_error_string(status));
192 (void) mach_port_destroy(mach_task_self(), storePrivate->server);
193 storePrivate->server = MACH_PORT_NULL;
194 _SCErrorSet(status);
195 return FALSE;
196 }
197
198 (void) mach_port_destroy(mach_task_self(), port);
199
200 return TRUE;
201 }