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