2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
20 * @APPLE_LICENSE_HEADER_END@
24 #include <sys/ioctl.h>
25 #include <sys/types.h>
26 #include <sys/socket.h>
34 _SCDNotifierInformViaFD(SCDSessionRef session
,
38 SCDSessionPrivateRef sessionPrivate
= (SCDSessionPrivateRef
)session
;
40 CFStringRef sessionKey
;
43 SCDLog(LOG_DEBUG
, CFSTR("_SCDNotifierInformViaFD:"));
45 if ((session
== NULL
) || (sessionPrivate
->server
== MACH_PORT_NULL
)) {
46 return SCD_NOSESSION
; /* you must have an open session to play */
49 if (sessionPrivate
->notifyStatus
!= NotifierNotRegistered
) {
50 /* sorry, you can only have one notification registered at once */
51 return SCD_NOTIFIERACTIVE
;
54 if ((sock
= socket(AF_UNIX
, SOCK_STREAM
, 0)) == -1) {
55 SCDLog(LOG_NOTICE
, CFSTR("socket: %s"), strerror(errno
));
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
;
68 if (needsNotification
== NULL
)
69 needsNotification
= CFSetCreateMutable(NULL
,
71 &kCFTypeSetCallBacks
);
73 sessionNum
= CFNumberCreate(NULL
, kCFNumberIntType
, &sessionPrivate
->server
);
74 CFSetAddValue(needsNotification
, sessionNum
);
75 CFRelease(sessionNum
);
83 _notifyviafd(mach_port_t server
,
85 mach_msg_type_number_t pathLen
,
91 serverSessionRef mySession
= getSession(server
);
92 SCDSessionPrivateRef sessionPrivate
= (SCDSessionPrivateRef
)mySession
->session
;
93 struct sockaddr_un un
;
95 int bufSiz
= sizeof(sessionPrivate
->notifyFileIdentifier
);
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
);
103 * if socket currently open, close it!
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 */
113 *scd_status
= SCD_FAILED
;
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 */
127 /* do common sanity checks, get socket */
128 *scd_status
= _SCDNotifierInformViaFD(mySession
->session
, identifier
, &sock
);
130 /* check status of _SCDNotifierInformViaFD() */
131 if (*scd_status
!= SCD_OK
) {
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
));
139 sessionPrivate
->notifyStatus
= NotifierNotRegistered
;
140 sessionPrivate
->notifyFile
= -1;
141 *scd_status
= SCD_FAILED
;
145 SCDLog(LOG_NOTICE
, CFSTR(" fd = %d"), sock
);
146 (void) unlink(un
.sun_path
);
148 if (setsockopt(sock
, SOL_SOCKET
, SO_SNDBUF
, &bufSiz
, sizeof(bufSiz
)) < 0) {
149 SCDLog(LOG_DEBUG
, CFSTR("setsockopt: %s"), strerror(errno
));
151 *scd_status
= SCD_FAILED
;
155 if (ioctl(sock
, FIONBIO
, &nbioYes
) == -1) {
156 SCDLog(LOG_DEBUG
, CFSTR("ioctl(,FIONBIO,): %s"), strerror(errno
));
158 *scd_status
= SCD_FAILED
;
162 /* set notifier active */
163 sessionPrivate
->notifyStatus
= Using_NotifierInformViaFD
;
164 sessionPrivate
->notifyFile
= sock
;
165 sessionPrivate
->notifyFileIdentifier
= identifier
;