1/* 2 * Copyright (c) 2000-2004 Apple Computer, 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// 26// cfmach++ - a marriage of CoreFoundation with Mach/C++ 27// 28#include <security_utilities/cfmach++.h> 29 30 31namespace Security { 32namespace MachPlusPlus { 33 34 35// 36// Construct CFAutoPorts 37// 38CFAutoPort::CFAutoPort() 39 : mEnabled(false) 40{ } 41 42CFAutoPort::CFAutoPort(mach_port_t p) 43 : Port(p), mEnabled(false) 44{ } 45 46 47// 48// On destruction, make sure we're disengaged from the CFRunLoop 49// 50CFAutoPort::~CFAutoPort() 51{ 52 disable(); 53 54 // invalidate everything 55 if (mPort) 56 { 57 CFMachPortInvalidate(mPort); 58 CFRunLoopSourceInvalidate(mSource); 59 } 60} 61 62 63// 64// enable() will lazily allocate needed resources, then click into the runloop 65// 66void CFAutoPort::enable() 67{ 68 if (!mEnabled) { 69 if (!*this) 70 allocate(); 71 if (!mPort) { 72 // first-time creation of CF resources 73 CFMachPortContext ctx = { 1, this, NULL, NULL, NULL }; 74 CFMachPortRef machPort = CFMachPortCreateWithPort(NULL, port(), cfCallback, &ctx, NULL); 75 if (machPort != NULL) 76 { 77 // using take here because "assignment" causes an extra retain, which will make the 78 // CF objects leak when this data structure goes away. 79 mPort.take(machPort); 80 81 CFRunLoopSourceRef sr = CFMachPortCreateRunLoopSource(NULL, mPort, 10); 82 mSource.take(sr); 83 } 84 if (!mPort || !mSource) 85 CFError::throwMe(); // CF won't tell us why... 86 } 87 CFRunLoopAddSource(CFRunLoopGetCurrent(), mSource, kCFRunLoopCommonModes); 88 mEnabled = true; 89 secdebug("autoport", "%p enabled", this); 90 } 91} 92 93 94// 95// Disable() just removes us from the runloop. All the other resources stay 96// around, ready to be re-enable()d. 97// 98void CFAutoPort::disable() 99{ 100 if (mEnabled) { 101 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), mSource, kCFRunLoopCommonModes); 102 mEnabled = false; 103 secdebug("autoport", "%p disabled", this); 104 } 105} 106 107 108// 109// The CF-sponsored port callback. 110// We pass this to our receive() virtual and eat all exceptions. 111// 112static int gNumTimesCalled = 0; 113 114void CFAutoPort::cfCallback(CFMachPortRef cfPort, void *msg, CFIndex size, void *context) 115{ 116 ++gNumTimesCalled; 117 secdebug("adhoc", "Callback was called %d times.", gNumTimesCalled); 118 119#warning Cast to mach_msg_size_t may loose precision 120 Message message(msg, (mach_msg_size_t)size); 121 try { 122 reinterpret_cast<CFAutoPort *>(context)->receive(message); 123 } catch (...) { 124 secdebug("autoport", "%p receive handler failed with exception", context); 125 } 126} 127 128 129} // end namespace MachPlusPlus 130} // end namespace Security 131