]> git.saurik.com Git - apple/configd.git/blob - configd.tproj/_notifyviafd.c
configd-42.tar.gz
[apple/configd.git] / configd.tproj / _notifyviafd.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 * April 5, 2000 Allan Nathanson <ajn@apple.com>
30 * - initial revision
31 */
32
33 #include <unistd.h>
34 #include <sys/ioctl.h>
35 #include <sys/types.h>
36 #include <sys/socket.h>
37 #include <sys/un.h>
38
39 #include "configd.h"
40 #include "session.h"
41
42
43 int
44 __SCDynamicStoreNotifyFileDescriptor(SCDynamicStoreRef store,
45 int32_t identifier,
46 int *fd)
47 {
48 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store;
49 int sock;
50 CFStringRef sessionKey;
51 CFDictionaryRef info;
52
53 SCLog(_configd_verbose, LOG_DEBUG, CFSTR("__SCDynamicStoreNotifyFileDescriptor:"));
54
55 if (!store || (storePrivate->server == MACH_PORT_NULL)) {
56 return kSCStatusNoStoreSession; /* you must have an open session to play */
57 }
58
59 if (storePrivate->notifyStatus != NotifierNotRegistered) {
60 /* sorry, you can only have one notification registered at once */
61 return kSCStatusNotifierActive;
62 }
63
64 if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
65 SCLog(_configd_verbose, LOG_NOTICE, CFSTR("socket: %s"), strerror(errno));
66 return kSCStatusFailed;
67 }
68
69 *fd = sock;
70
71 /* push out a notification if any changes are pending */
72 sessionKey = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), storePrivate->server);
73 info = CFDictionaryGetValue(sessionData, sessionKey);
74 CFRelease(sessionKey);
75 if (info && CFDictionaryContainsKey(info, kSCDChangedKeys)) {
76 CFNumberRef sessionNum;
77
78 if (needsNotification == NULL)
79 needsNotification = CFSetCreateMutable(NULL,
80 0,
81 &kCFTypeSetCallBacks);
82
83 sessionNum = CFNumberCreate(NULL, kCFNumberIntType, &storePrivate->server);
84 CFSetAddValue(needsNotification, sessionNum);
85 CFRelease(sessionNum);
86 }
87
88 return kSCStatusOK;
89 }
90
91
92 kern_return_t
93 _notifyviafd(mach_port_t server,
94 xmlData_t pathRef,
95 mach_msg_type_number_t pathLen,
96 int identifier,
97 int *sc_status
98 )
99 {
100 kern_return_t status;
101 serverSessionRef mySession = getSession(server);
102 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)mySession->store;
103 struct sockaddr_un un;
104 int sock;
105 int bufSiz = sizeof(storePrivate->notifyFileIdentifier);
106 int nbioYes = 1;
107
108 SCLog(_configd_verbose, LOG_DEBUG, CFSTR("Send message via UNIX domain socket when a notification key changes."));
109 SCLog(_configd_verbose, LOG_DEBUG, CFSTR(" server = %d"), server);
110 SCLog(_configd_verbose, LOG_DEBUG, CFSTR(" path = %s"), pathRef);
111
112 /*
113 * if socket currently open, close it!
114 */
115 /* validate the UNIX domain socket path */
116 if (pathLen > (sizeof(un.sun_path) - 1)) {
117 SCLog(_configd_verbose, LOG_NOTICE, CFSTR("domain socket path length too long!"));
118 status = vm_deallocate(mach_task_self(), (vm_address_t)pathRef, pathLen);
119 if (status != KERN_SUCCESS) {
120 SCLog(_configd_verbose, LOG_DEBUG, CFSTR("vm_deallocate(): %s"), mach_error_string(status));
121 /* non-fatal???, proceed */
122 }
123 *sc_status = kSCStatusFailed;
124 return KERN_SUCCESS;
125 }
126
127 /* un-serialize the UNIX domain socket path */
128 un.sun_family = AF_UNIX;
129 bcopy(pathRef, un.sun_path, pathLen);
130 un.sun_path[pathLen] = '\0';
131 status = vm_deallocate(mach_task_self(), (vm_address_t)pathRef, pathLen);
132 if (status != KERN_SUCCESS) {
133 SCLog(_configd_verbose, LOG_DEBUG, CFSTR("vm_deallocate(): %s"), mach_error_string(status));
134 /* non-fatal???, proceed */
135 }
136
137 /* do common sanity checks, get socket */
138 *sc_status = __SCDynamicStoreNotifyFileDescriptor(mySession->store, identifier, &sock);
139
140 /* check status of __SCDynamicStoreNotifyFileDescriptor() */
141 if (*sc_status != kSCStatusOK) {
142 return KERN_SUCCESS;
143 }
144
145 /* establish the connection, get ready for a read() */
146 if (connect(sock, (struct sockaddr *)&un, sizeof(un)) == -1) {
147 SCLog(_configd_verbose, LOG_DEBUG, CFSTR("connect: %s"), strerror(errno));
148 (void) close(sock);
149 storePrivate->notifyStatus = NotifierNotRegistered;
150 storePrivate->notifyFile = -1;
151 *sc_status = kSCStatusFailed;
152 return KERN_SUCCESS;
153 }
154
155 SCLog(_configd_verbose, LOG_NOTICE, CFSTR(" fd = %d"), sock);
156 (void) unlink(un.sun_path);
157
158 if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &bufSiz, sizeof(bufSiz)) < 0) {
159 SCLog(_configd_verbose, LOG_DEBUG, CFSTR("setsockopt: %s"), strerror(errno));
160 (void) close(sock);
161 *sc_status = kSCStatusFailed;
162 return KERN_SUCCESS;
163 }
164
165 if (ioctl(sock, FIONBIO, &nbioYes) == -1) {
166 SCLog(_configd_verbose, LOG_DEBUG, CFSTR("ioctl(,FIONBIO,): %s"), strerror(errno));
167 (void) close(sock);
168 *sc_status = kSCStatusFailed;
169 return KERN_SUCCESS;
170 }
171
172 /* set notifier active */
173 storePrivate->notifyStatus = Using_NotifierInformViaFD;
174 storePrivate->notifyFile = sock;
175 storePrivate->notifyFileIdentifier = identifier;
176
177 return KERN_SUCCESS;
178 }