]> git.saurik.com Git - apple/configd.git/blob - configd.tproj/_notifyviafd.c
configd-84.tar.gz
[apple/configd.git] / configd.tproj / _notifyviafd.c
1 /*
2 * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25
26 /*
27 * Modification History
28 *
29 * June 1, 2001 Allan Nathanson <ajn@apple.com>
30 * - public API conversion
31 *
32 * April 5, 2000 Allan Nathanson <ajn@apple.com>
33 * - initial revision
34 */
35
36 #include <unistd.h>
37 #include <sys/ioctl.h>
38 #include <sys/types.h>
39 #include <sys/socket.h>
40 #include <sys/un.h>
41
42 #include "configd.h"
43 #include "session.h"
44
45
46 __private_extern__
47 int
48 __SCDynamicStoreNotifyFileDescriptor(SCDynamicStoreRef store,
49 int32_t identifier,
50 int *fd)
51 {
52 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store;
53 int sock;
54 CFStringRef sessionKey;
55 CFDictionaryRef info;
56
57 SCLog(_configd_verbose, LOG_DEBUG, CFSTR("__SCDynamicStoreNotifyFileDescriptor:"));
58
59 if (!store || (storePrivate->server == MACH_PORT_NULL)) {
60 return kSCStatusNoStoreSession; /* you must have an open session to play */
61 }
62
63 if (storePrivate->notifyStatus != NotifierNotRegistered) {
64 /* sorry, you can only have one notification registered at once */
65 return kSCStatusNotifierActive;
66 }
67
68 if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
69 SCLog(_configd_verbose, LOG_NOTICE, CFSTR("socket: %s"), strerror(errno));
70 return kSCStatusFailed;
71 }
72
73 *fd = sock;
74
75 /* push out a notification if any changes are pending */
76 sessionKey = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), storePrivate->server);
77 info = CFDictionaryGetValue(sessionData, sessionKey);
78 CFRelease(sessionKey);
79 if (info && CFDictionaryContainsKey(info, kSCDChangedKeys)) {
80 CFNumberRef sessionNum;
81
82 if (needsNotification == NULL)
83 needsNotification = CFSetCreateMutable(NULL,
84 0,
85 &kCFTypeSetCallBacks);
86
87 sessionNum = CFNumberCreate(NULL, kCFNumberIntType, &storePrivate->server);
88 CFSetAddValue(needsNotification, sessionNum);
89 CFRelease(sessionNum);
90 }
91
92 return kSCStatusOK;
93 }
94
95
96 __private_extern__
97 kern_return_t
98 _notifyviafd(mach_port_t server,
99 xmlData_t pathRef,
100 mach_msg_type_number_t pathLen,
101 int identifier,
102 int *sc_status
103 )
104 {
105 kern_return_t status;
106 serverSessionRef mySession = getSession(server);
107 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)mySession->store;
108 struct sockaddr_un un;
109 int sock;
110 int bufSiz = sizeof(storePrivate->notifyFileIdentifier);
111 int nbioYes = 1;
112
113 if (_configd_verbose) {
114 SCLog(TRUE, LOG_DEBUG, CFSTR("Send message via UNIX domain socket when a notification key changes."));
115 SCLog(TRUE, LOG_DEBUG, CFSTR(" server = %d"), server);
116 SCLog(TRUE, LOG_DEBUG, CFSTR(" path = %s"), pathRef);
117 }
118
119 /*
120 * if socket currently open, close it!
121 */
122 /* validate the UNIX domain socket path */
123 if (pathLen > (sizeof(un.sun_path) - 1)) {
124 SCLog(_configd_verbose, LOG_NOTICE, CFSTR("domain socket path length too long!"));
125 status = vm_deallocate(mach_task_self(), (vm_address_t)pathRef, pathLen);
126 if (status != KERN_SUCCESS) {
127 SCLog(_configd_verbose, LOG_DEBUG, CFSTR("vm_deallocate(): %s"), mach_error_string(status));
128 /* non-fatal???, proceed */
129 }
130 *sc_status = kSCStatusFailed;
131 return KERN_SUCCESS;
132 }
133
134 /* un-serialize the UNIX domain socket path */
135 un.sun_family = AF_UNIX;
136 bcopy(pathRef, un.sun_path, pathLen);
137 un.sun_path[pathLen] = '\0';
138 status = vm_deallocate(mach_task_self(), (vm_address_t)pathRef, pathLen);
139 if (status != KERN_SUCCESS) {
140 SCLog(_configd_verbose, LOG_DEBUG, CFSTR("vm_deallocate(): %s"), mach_error_string(status));
141 /* non-fatal???, proceed */
142 }
143
144 if (!mySession) {
145 *sc_status = kSCStatusNoStoreSession; /* you must have an open session to play */
146 return KERN_SUCCESS;
147 }
148
149 /* do common sanity checks, get socket */
150 *sc_status = __SCDynamicStoreNotifyFileDescriptor(mySession->store, identifier, &sock);
151
152 /* check status of __SCDynamicStoreNotifyFileDescriptor() */
153 if (*sc_status != kSCStatusOK) {
154 return KERN_SUCCESS;
155 }
156
157 /* establish the connection, get ready for a read() */
158 if (connect(sock, (struct sockaddr *)&un, sizeof(un)) == -1) {
159 SCLog(_configd_verbose, LOG_DEBUG, CFSTR("connect: %s"), strerror(errno));
160 (void) close(sock);
161 storePrivate->notifyStatus = NotifierNotRegistered;
162 storePrivate->notifyFile = -1;
163 *sc_status = kSCStatusFailed;
164 return KERN_SUCCESS;
165 }
166
167 SCLog(_configd_verbose, LOG_NOTICE, CFSTR(" fd = %d"), sock);
168 (void) unlink(un.sun_path);
169
170 if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &bufSiz, sizeof(bufSiz)) < 0) {
171 SCLog(_configd_verbose, LOG_DEBUG, CFSTR("setsockopt: %s"), strerror(errno));
172 (void) close(sock);
173 *sc_status = kSCStatusFailed;
174 return KERN_SUCCESS;
175 }
176
177 if (ioctl(sock, FIONBIO, &nbioYes) == -1) {
178 SCLog(_configd_verbose, LOG_DEBUG, CFSTR("ioctl(,FIONBIO,): %s"), strerror(errno));
179 (void) close(sock);
180 *sc_status = kSCStatusFailed;
181 return KERN_SUCCESS;
182 }
183
184 /* set notifier active */
185 storePrivate->notifyStatus = Using_NotifierInformViaFD;
186 storePrivate->notifyFile = sock;
187 storePrivate->notifyFileIdentifier = identifier;
188
189 return KERN_SUCCESS;
190 }