1/*
2 * Copyright (c) 2000-2013 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 * FDHandler.c
26 * - hides the details of how to get a callback when a file descriptor
27 *   has data available
28 * - wraps the CFSocket run-loop source
29 */
30
31/*
32 * Modification History
33 *
34 * October 26, 2001	Dieter Siegmund (dieter@apple.com)
35 * - created (based on bootp/IPConfiguration.tproj/FDSet.c)
36 */
37
38#include <stdlib.h>
39#include <unistd.h>
40#include <string.h>
41#include <stdio.h>
42#include <sys/types.h>
43#include <sys/wait.h>
44#include <sys/errno.h>
45#include <sys/socket.h>
46#include <net/if_types.h>
47
48#include "FDHandler.h"
49
50#include <CoreFoundation/CFRunLoop.h>
51#include <CoreFoundation/CFSocket.h>
52
53struct FDHandler_s {
54    CFRunLoopSourceRef	rls;
55    CFSocketRef		socket;
56    int			fd;
57    FDHandler_func *	func;
58    void *		arg1;
59    void *		arg2;
60};
61
62static void
63FDHandler_callback(CFSocketRef s, CFSocketCallBackType type,
64		   CFDataRef address, const void * data, void * info)
65{
66    FDHandler * 	handler = (FDHandler *)info;
67
68    if (handler->func) {
69	(*handler->func)(handler->arg1, handler->arg2);
70    }
71    return;
72}
73
74FDHandler *
75FDHandler_create(int fd)
76{
77    CFSocketContext	context = { 0, NULL, NULL, NULL, NULL };
78    FDHandler *	handler;
79
80    handler = malloc(sizeof(*handler));
81    if (handler == NULL)
82	return (NULL);
83    bzero(handler, sizeof(*handler));
84
85    context.info = handler;
86    handler->fd = fd;
87    handler->socket
88	= CFSocketCreateWithNative(NULL, fd, kCFSocketReadCallBack,
89				   FDHandler_callback, &context);
90    handler->rls = CFSocketCreateRunLoopSource(NULL, handler->socket, 0);
91    CFRunLoopAddSource(CFRunLoopGetCurrent(), handler->rls,
92		       kCFRunLoopDefaultMode);
93    return (handler);
94}
95
96void
97FDHandler_free(FDHandler * * handler_p)
98{
99    FDHandler * handler;
100
101    if (handler_p == NULL) {
102	return;
103    }
104    handler = *handler_p;
105    if (handler) {
106	if (handler->rls) {
107	    /* cancel further handlers */
108	    CFRunLoopRemoveSource(CFRunLoopGetCurrent(), handler->rls,
109				  kCFRunLoopDefaultMode);
110
111	    /* remove one socket reference, close the file descriptor */
112	    CFSocketInvalidate(handler->socket);
113
114	    /* release the socket */
115	    CFRelease(handler->socket);
116	    handler->socket = NULL;
117
118	    /* release the run loop source */
119	    CFRelease(handler->rls);
120	    handler->rls = NULL;
121	}
122	free(handler);
123    }
124    *handler_p = NULL;
125    return;
126}
127
128void
129FDHandler_enable(FDHandler * handler, FDHandler_func * func,
130		 void * arg1, void * arg2)
131{
132    handler->func = func;
133    handler->arg1 = arg1;
134    handler->arg2 = arg2;
135    return;
136}
137
138void
139FDHandler_disable(FDHandler * handler)
140{
141    handler->func = NULL;
142    handler->arg1 = NULL;
143    handler->arg2 = NULL;
144    return;
145}
146
147
148int
149FDHandler_fd(FDHandler * handler)
150{
151    return (handler->fd);
152}
153