nkeynes@998 | 1 | /**
|
nkeynes@1021 | 2 | * $Id$
|
nkeynes@998 | 3 | *
|
nkeynes@998 | 4 | * OS X networking support functions. Currently this is just for activity callbacks.
|
nkeynes@998 | 5 | *
|
nkeynes@998 | 6 | * Copyright (c) 2009 Nathan Keynes.
|
nkeynes@998 | 7 | *
|
nkeynes@998 | 8 | * This program is free software; you can redistribute it and/or modify
|
nkeynes@998 | 9 | * it under the terms of the GNU General Public License as published by
|
nkeynes@998 | 10 | * the Free Software Foundation; either version 2 of the License, or
|
nkeynes@998 | 11 | * (at your option) any later version.
|
nkeynes@998 | 12 | *
|
nkeynes@998 | 13 | * This program is distributed in the hope that it will be useful,
|
nkeynes@998 | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
nkeynes@998 | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
nkeynes@998 | 16 | * GNU General Public License for more details.
|
nkeynes@998 | 17 | */
|
nkeynes@998 | 18 |
|
nkeynes@998 | 19 | #include <CoreFoundation/CoreFoundation.h>
|
nkeynes@1077 | 20 | #include "ioutil.h"
|
nkeynes@998 | 21 |
|
nkeynes@1077 | 22 | struct io_osx_cbinfo {
|
nkeynes@1077 | 23 | int fd;
|
nkeynes@1077 | 24 | io_callback_t callback;
|
nkeynes@998 | 25 | void * cbdata;
|
nkeynes@998 | 26 | void (*cbdealloc)(void *);
|
nkeynes@1077 | 27 | void *fdRef;
|
nkeynes@998 | 28 | CFRunLoopSourceRef sourceRef;
|
nkeynes@1077 | 29 |
|
nkeynes@1077 | 30 | struct io_osx_cbinfo *next;
|
nkeynes@998 | 31 | };
|
nkeynes@998 | 32 |
|
nkeynes@1077 | 33 | static struct io_osx_cbinfo *cbinfo_list = NULL;
|
nkeynes@1077 | 34 |
|
nkeynes@1077 | 35 | void io_unregister_callback( struct io_osx_cbinfo *cbinfo )
|
nkeynes@998 | 36 | {
|
nkeynes@1077 | 37 | CFRunLoopRemoveSource( CFRunLoopGetCurrent(), cbinfo->sourceRef, kCFRunLoopCommonModes );
|
nkeynes@1077 | 38 | CFRelease(cbinfo->sourceRef);
|
nkeynes@1077 | 39 | cbinfo->sourceRef = NULL;
|
nkeynes@1077 | 40 | CFRelease(cbinfo->fdRef); /* Note this implicitly releases the cbinfo itself as well */
|
nkeynes@1077 | 41 | }
|
nkeynes@1077 | 42 |
|
nkeynes@1077 | 43 | static void io_osx_net_callback( CFSocketRef s, CFSocketCallBackType type, CFDataRef address, const void *unused, void *data )
|
nkeynes@1077 | 44 | {
|
nkeynes@1077 | 45 | struct io_osx_cbinfo *cbinfo = (struct io_osx_cbinfo *)data;
|
nkeynes@998 | 46 | if(!cbinfo->callback( CFSocketGetNative(s), cbinfo->cbdata) ) {
|
nkeynes@1077 | 47 | io_unregister_callback(cbinfo);
|
nkeynes@998 | 48 | }
|
nkeynes@998 | 49 | }
|
nkeynes@998 | 50 |
|
nkeynes@1077 | 51 | static void io_osx_fd_callback( CFFileDescriptorRef f, CFOptionFlags type, void *data )
|
nkeynes@998 | 52 | {
|
nkeynes@1077 | 53 | struct io_osx_cbinfo *cbinfo = (struct io_osx_cbinfo *)data;
|
nkeynes@1077 | 54 | if(!cbinfo->callback( CFFileDescriptorGetNativeDescriptor(f), cbinfo->cbdata) ) {
|
nkeynes@1077 | 55 | io_unregister_callback(cbinfo);
|
nkeynes@1077 | 56 | }
|
nkeynes@1077 | 57 | }
|
nkeynes@1077 | 58 |
|
nkeynes@1077 | 59 | static void io_osx_release( const void *data )
|
nkeynes@1077 | 60 | {
|
nkeynes@1077 | 61 | struct io_osx_cbinfo *cbinfo = (struct io_osx_cbinfo *)data;
|
nkeynes@998 | 62 | if( cbinfo->cbdealloc != NULL ) {
|
nkeynes@998 | 63 | cbinfo->cbdealloc(cbinfo->cbdata);
|
nkeynes@998 | 64 | }
|
nkeynes@998 | 65 | free( cbinfo );
|
nkeynes@998 | 66 | }
|
nkeynes@998 | 67 |
|
nkeynes@998 | 68 | /**
|
nkeynes@998 | 69 | * Register a TCP server socket listener on an already open (and listening)
|
nkeynes@998 | 70 | * socket. The socket must not have been previously registered.
|
nkeynes@998 | 71 | * @return TRUE on success, FALSE on failure.
|
nkeynes@998 | 72 | *
|
nkeynes@998 | 73 | * Defined in netutil.h
|
nkeynes@998 | 74 | */
|
nkeynes@1077 | 75 | io_listener_t io_register_tcp_listener( int fd, io_callback_t callback, void *data, void (*dealloc)(void*) )
|
nkeynes@998 | 76 | {
|
nkeynes@998 | 77 | CFSocketContext socketContext;
|
nkeynes@1077 | 78 | struct io_osx_cbinfo *cbinfo = malloc( sizeof(struct io_osx_cbinfo) );
|
nkeynes@998 | 79 | assert(cbinfo != NULL);
|
nkeynes@998 | 80 |
|
nkeynes@998 | 81 | cbinfo->callback = callback;
|
nkeynes@998 | 82 | cbinfo->cbdata = data;
|
nkeynes@998 | 83 | cbinfo->cbdealloc = dealloc;
|
nkeynes@998 | 84 | socketContext.version = 0;
|
nkeynes@998 | 85 | socketContext.info = cbinfo;
|
nkeynes@998 | 86 | socketContext.retain = NULL;
|
nkeynes@1077 | 87 | socketContext.release = io_osx_release;
|
nkeynes@998 | 88 | socketContext.copyDescription = NULL;
|
nkeynes@998 | 89 |
|
nkeynes@1077 | 90 | CFSocketRef ref = CFSocketCreateWithNative( kCFAllocatorDefault, fd, kCFSocketReadCallBack,
|
nkeynes@1077 | 91 | io_osx_net_callback, &socketContext );
|
nkeynes@1077 | 92 | cbinfo->fdRef = ref;
|
nkeynes@1077 | 93 | cbinfo->sourceRef = CFSocketCreateRunLoopSource( kCFAllocatorDefault, ref, 0 );
|
nkeynes@998 | 94 | CFRunLoopAddSource( CFRunLoopGetCurrent(), cbinfo->sourceRef, kCFRunLoopCommonModes );
|
nkeynes@1071 | 95 |
|
nkeynes@1077 | 96 | return cbinfo;
|
nkeynes@998 | 97 | }
|
nkeynes@1077 | 98 |
|
nkeynes@1077 | 99 | /**
|
nkeynes@1077 | 100 | * Register a file descriptor listener on an already open (and listening)
|
nkeynes@1077 | 101 | * file descriptor. The file descriptor must not have been previously registered.
|
nkeynes@1077 | 102 | * @return TRUE on success, FALSE on failure.
|
nkeynes@1077 | 103 | *
|
nkeynes@1077 | 104 | */
|
nkeynes@1077 | 105 | io_listener_t io_register_listener( int fd, io_callback_t callback, void *data, void (*dealloc)(void *) )
|
nkeynes@1077 | 106 | {
|
nkeynes@1077 | 107 | CFFileDescriptorContext fdContext;
|
nkeynes@1077 | 108 | struct io_osx_cbinfo *cbinfo = malloc( sizeof(struct io_osx_cbinfo) );
|
nkeynes@1077 | 109 | assert(cbinfo != NULL);
|
nkeynes@1077 | 110 |
|
nkeynes@1077 | 111 | cbinfo->callback = callback;
|
nkeynes@1077 | 112 | cbinfo->cbdata = data;
|
nkeynes@1077 | 113 | cbinfo->cbdealloc = dealloc;
|
nkeynes@1077 | 114 | fdContext.version = 0;
|
nkeynes@1077 | 115 | fdContext.retain = NULL;
|
nkeynes@1077 | 116 | fdContext.info = cbinfo;
|
nkeynes@1077 | 117 | fdContext.release = io_osx_release;
|
nkeynes@1077 | 118 | fdContext.copyDescription = NULL;
|
nkeynes@1077 | 119 |
|
nkeynes@1077 | 120 | CFFileDescriptorRef ref = CFFileDescriptorCreate( kCFAllocatorDefault, fd, FALSE,
|
nkeynes@1077 | 121 | io_osx_fd_callback, &fdContext);
|
nkeynes@1077 | 122 | cbinfo->fdRef = ref;
|
nkeynes@1077 | 123 | cbinfo->sourceRef = CFFileDescriptorCreateRunLoopSource( kCFAllocatorDefault, ref, 0 );
|
nkeynes@1077 | 124 | CFRunLoopAddSource( CFRunLoopGetCurrent(), cbinfo->sourceRef, kCFRunLoopCommonModes );
|
nkeynes@1077 | 125 | return cbinfo;
|
nkeynes@1077 | 126 | }
|
nkeynes@1077 | 127 |
|
nkeynes@1077 | 128 | void io_unregister_listener( io_listener_t data )
|
nkeynes@1077 | 129 | {
|
nkeynes@1077 | 130 | struct io_osx_cbinfo *cbinfo = (struct io_osx_cbinfo *)data;
|
nkeynes@1077 | 131 | io_unregister_callback(cbinfo);
|
nkeynes@1077 | 132 | }
|