1/* 2 * Copyright (c) 2000-2010 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24/* 25 * FDSet.c 26 * - contains FDCallout, a thin wrapper on CFSocketRef/CFFileDescriptorRef 27 */ 28/* 29 * Modification History 30 * 31 * May 11, 2000 Dieter Siegmund (dieter@apple.com) 32 * - created 33 * June 12, 2000 Dieter Siegmund (dieter@apple.com) 34 * - converted to use CFRunLoop 35 * January 27, 2010 Dieter Siegmund (dieter@apple.com) 36 * - use CFFileDescriptorRef for non-sockets 37 */ 38 39#include <stdlib.h> 40#include <unistd.h> 41#include <string.h> 42#include <stdio.h> 43#include <sys/types.h> 44#include <sys/stat.h> 45#include <sys/errno.h> 46#include <sys/socket.h> 47#include <net/if_types.h> 48#include <syslog.h> 49#include <CoreFoundation/CFRunLoop.h> 50#include <CoreFoundation/CFSocket.h> 51#include <CoreFoundation/CFFileDescriptor.h> 52 53#include "dynarray.h" 54#include "FDSet.h" 55#include "symbol_scope.h" 56 57struct FDCallout { 58 Boolean is_socket; 59 union { 60 CFSocketRef socket; 61 CFFileDescriptorRef fdesc; 62 } u; 63 FDCalloutFuncRef func; 64 void * arg1; 65 void * arg2; 66}; 67 68STATIC void 69FDCalloutSocketReceive(CFSocketRef s, CFSocketCallBackType type, 70 CFDataRef address, const void *data, void *info); 71 72STATIC void 73FDCalloutFileDescriptorReceive(CFFileDescriptorRef f, 74 CFOptionFlags callBackTypes, void *info); 75 76 77STATIC void 78FDCalloutCreateSocket(FDCalloutRef callout, int fd) 79{ 80 CFSocketContext context = { 0, NULL, NULL, NULL, NULL }; 81 CFRunLoopSourceRef rls; 82 83 context.info = callout; 84 callout->is_socket = TRUE; 85 callout->u.socket 86 = CFSocketCreateWithNative(NULL, fd, kCFSocketReadCallBack, 87 FDCalloutSocketReceive, &context); 88 rls = CFSocketCreateRunLoopSource(NULL, callout->u.socket, 0); 89 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, 90 kCFRunLoopDefaultMode); 91 CFRelease(rls); 92 return; 93} 94 95STATIC void 96FDCalloutCreateFileDescriptor(FDCalloutRef callout, int fd) 97{ 98 CFFileDescriptorContext context = { 0, NULL, NULL, NULL, NULL }; 99 CFRunLoopSourceRef rls; 100 101 context.info = callout; 102 callout->is_socket = FALSE; 103 callout->u.fdesc 104 = CFFileDescriptorCreate(NULL, fd, TRUE, 105 FDCalloutFileDescriptorReceive, &context); 106 CFFileDescriptorEnableCallBacks(callout->u.fdesc, 107 kCFFileDescriptorReadCallBack); 108 rls = CFFileDescriptorCreateRunLoopSource(NULL, callout->u.fdesc, 0); 109 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, 110 kCFRunLoopDefaultMode); 111 CFRelease(rls); 112 return; 113} 114 115PRIVATE_EXTERN FDCalloutRef 116FDCalloutCreate(int fd, FDCalloutFuncRef func, 117 void * arg1, void * arg2) 118{ 119 FDCalloutRef callout; 120 struct stat sb; 121 122 if (fstat(fd, &sb) < 0) { 123 return (NULL); 124 } 125 callout = malloc(sizeof(*callout)); 126 if (callout == NULL) { 127 return (NULL); 128 } 129 bzero(callout, sizeof(*callout)); 130 if (S_ISSOCK(sb.st_mode)) { 131 FDCalloutCreateSocket(callout, fd); 132 } 133 else { 134 FDCalloutCreateFileDescriptor(callout, fd); 135 } 136 callout->func = func; 137 callout->arg1 = arg1; 138 callout->arg2 = arg2; 139 return (callout); 140} 141 142STATIC void 143FDCalloutReleaseSocket(FDCalloutRef callout) 144{ 145 if (callout->u.socket != NULL) { 146 CFSocketInvalidate(callout->u.socket); 147 CFRelease(callout->u.socket); 148 callout->u.socket = NULL; 149 } 150 return; 151} 152 153STATIC void 154FDCalloutReleaseFileDescriptor(FDCalloutRef callout) 155{ 156 if (callout->u.fdesc != NULL) { 157 CFFileDescriptorInvalidate(callout->u.fdesc); 158 CFRelease(callout->u.fdesc); 159 callout->u.fdesc = NULL; 160 } 161 return; 162} 163 164PRIVATE_EXTERN void 165FDCalloutRelease(FDCalloutRef * callout_p) 166{ 167 FDCalloutRef callout = *callout_p; 168 169 if (callout == NULL) { 170 return; 171 } 172 if (callout->is_socket) { 173 FDCalloutReleaseSocket(callout); 174 } 175 else { 176 FDCalloutReleaseFileDescriptor(callout); 177 } 178 free(callout); 179 *callout_p = NULL; 180 return; 181} 182 183STATIC void 184FDCalloutSocketReceive(CFSocketRef s, CFSocketCallBackType type, 185 CFDataRef address, const void *data, void *info) 186{ 187 FDCalloutRef callout = (FDCalloutRef)info; 188 189 if (callout->func) { 190 (*callout->func)(callout->arg1, callout->arg2); 191 } 192 return; 193} 194 195STATIC void 196FDCalloutFileDescriptorReceive(CFFileDescriptorRef f, 197 CFOptionFlags callBackTypes, void *info) 198{ 199 FDCalloutRef callout = (FDCalloutRef)info; 200 201 if (callout->func) { 202 (*callout->func)(callout->arg1, callout->arg2); 203 } 204 /* each callback is one-shot, so we need to re-arm */ 205 CFFileDescriptorEnableCallBacks(callout->u.fdesc, 206 kCFFileDescriptorReadCallBack); 207 return; 208} 209 210PRIVATE_EXTERN int 211FDCalloutGetFD(FDCalloutRef callout) 212{ 213 if (callout->is_socket) { 214 return (CFSocketGetNative(callout->u.socket)); 215 } 216 else { 217 return (CFFileDescriptorGetNativeDescriptor(callout->u.fdesc)); 218 } 219} 220