/* * Copyright (c) 2003 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ #include "DASession.h" #include "DACallback.h" #include "DAServer.h" #include #include #include struct __DASession { CFRuntimeBase _base; mach_port_t _client; char * _name; pid_t _pid; DASessionOptions _options; CFMutableArrayRef _queue; CFMutableArrayRef _register; AuthorizationRef _rights; CFMachPortRef _server; CFRunLoopSourceRef _source; DASessionState _state; }; typedef struct __DASession __DASession; static CFStringRef __DASessionCopyDescription( CFTypeRef object ); static CFStringRef __DASessionCopyFormattingDescription( CFTypeRef object, CFDictionaryRef options ); static void __DASessionDeallocate( CFTypeRef object ); static Boolean __DASessionEqual( CFTypeRef object1, CFTypeRef object2 ); static CFHashCode __DASessionHash( CFTypeRef object ); static const CFRuntimeClass __DASessionClass = { 0, "DASession", NULL, NULL, __DASessionDeallocate, __DASessionEqual, __DASessionHash, __DASessionCopyFormattingDescription, __DASessionCopyDescription }; static CFTypeID __kDASessionTypeID = _kCFRuntimeNotATypeID; static CFStringRef __DASessionCopyDescription( CFTypeRef object ) { DASessionRef session = ( DASessionRef ) object; return CFStringCreateWithFormat( CFGetAllocator( object ), NULL, CFSTR( "{id = %s [%d]:%d}" ), object, CFGetAllocator( object ), session->_name, session->_pid, CFMachPortGetPort( session->_server ) ); } static CFStringRef __DASessionCopyFormattingDescription( CFTypeRef object, CFDictionaryRef options ) { DASessionRef session = ( DASessionRef ) object; return CFStringCreateWithFormat( CFGetAllocator( object ), NULL, CFSTR( "%s [%d]:%d" ), session->_name, session->_pid, CFMachPortGetPort( session->_server ) ); } static DASessionRef __DASessionCreate( CFAllocatorRef allocator ) { __DASession * session; session = ( void * ) _CFRuntimeCreateInstance( allocator, __kDASessionTypeID, sizeof( __DASession ) - sizeof( CFRuntimeBase ), NULL ); if ( session ) { session->_client = NULL; session->_name = NULL; session->_pid = 0; session->_options = 0; session->_queue = CFArrayCreateMutable( allocator, 0, &kCFTypeArrayCallBacks ); session->_register = CFArrayCreateMutable( allocator, 0, &kCFTypeArrayCallBacks ); session->_rights = NULL; session->_server = NULL; session->_source = NULL; session->_state = 0; assert( session->_queue ); assert( session->_register ); } return session; } static void __DASessionDeallocate( CFTypeRef object ) { DASessionRef session = ( DASessionRef ) object; if ( session->_client ) mach_port_deallocate( mach_task_self( ), session->_client ); if ( session->_name ) free( session->_name ); if ( session->_queue ) CFRelease( session->_queue ); if ( session->_register ) CFRelease( session->_register ); if ( session->_rights ) AuthorizationFree( session->_rights, kAuthorizationFlagDefaults ); if ( session->_server ) CFMachPortInvalidate( session->_server ); if ( session->_server ) CFRelease( session->_server ); if ( session->_source ) CFRelease( session->_source ); } static Boolean __DASessionEqual( CFTypeRef object1, CFTypeRef object2 ) { DASessionRef session1 = ( DASessionRef ) object1; DASessionRef session2 = ( DASessionRef ) object2; return ( session1->_server == session2->_server ) ? TRUE : FALSE; } static CFHashCode __DASessionHash( CFTypeRef object ) { DASessionRef session = ( DASessionRef ) object; return ( CFHashCode ) CFMachPortGetPort( session->_server ); } ///w:start const char * _DASessionGetName( DASessionRef session ) { return session->_name; } ///w:stop DASessionRef DASessionCreate( CFAllocatorRef allocator, mach_port_t _client, const char * _name, pid_t _pid, AuthorizationExternalForm _rights ) { DASessionRef session; /* * Create the session. */ session = __DASessionCreate( allocator ); if ( session ) { CFMachPortRef server; CFMachPortContext serverContext; serverContext.version = 0; serverContext.info = session; serverContext.retain = NULL; serverContext.release = NULL; serverContext.copyDescription = NULL; /* * Create the session's server port. */ server = CFMachPortCreate( allocator, _DAServerCallback, &serverContext, NULL ); if ( server ) { CFRunLoopSourceRef source; /* * Create the session's server port run loop source. */ source = CFMachPortCreateRunLoopSource( allocator, server, 0 ); if ( source ) { mach_port_t port; kern_return_t status; /* * Set up the session's server port. */ status = mach_port_request_notification( mach_task_self( ), _client, MACH_NOTIFY_DEAD_NAME, TRUE, CFMachPortGetPort( server ), MACH_MSG_TYPE_MAKE_SEND_ONCE, &port ); if ( status == KERN_SUCCESS ) { AuthorizationRef rights; assert( port == NULL ); /* * Create the session's authorization reference. */ status = AuthorizationCreateFromExternalForm( &_rights, &rights ); ///w:start if ( status ) { extern Boolean _gDAAuthorize; if ( _gDAAuthorize == FALSE ) { rights = NULL; status = errAuthorizationSuccess; } } ///w:stop if ( status == errAuthorizationSuccess ) { session->_client = _client; session->_name = strdup( _name ); session->_pid = _pid; session->_rights = rights; session->_server = server; session->_source = source; return session; } } CFRelease( source ); } CFRelease( server ); } CFRelease( session ); } return NULL; } CFMutableArrayRef DASessionGetCallbackQueue( DASessionRef session ) { return session->_queue; } CFMutableArrayRef DASessionGetCallbackRegister( DASessionRef session ) { return session->_register; } mach_port_t DASessionGetClientPort( DASessionRef session ) { return session->_client; } mach_port_t DASessionGetID( DASessionRef session ) { return CFMachPortGetPort( session->_server ); } Boolean DASessionGetOption( DASessionRef session, DASessionOption option ) { return ( session->_options & option ) ? TRUE : FALSE; } DASessionOptions DASessionGetOptions( DASessionRef session ) { return session->_options; } AuthorizationRef DASessionGetRights( DASessionRef session ) { return session->_rights; } mach_port_t DASessionGetServerPort( DASessionRef session ) { return CFMachPortGetPort( session->_server ); } Boolean DASessionGetState( DASessionRef session, DASessionState state ) { return ( session->_state & state ) ? TRUE : FALSE; } CFTypeID DASessionGetTypeID( void ) { return __kDASessionTypeID; } void DASessionInitialize( void ) { __kDASessionTypeID = _CFRuntimeRegisterClass( &__DASessionClass ); } void DASessionQueueCallback( DASessionRef session, DACallbackRef callback ) { session->_state &= ~kDASessionStateIdle; CFArrayAppendValue( session->_queue, callback ); if ( CFArrayGetCount( session->_queue ) == 1 ) { mach_msg_header_t message; message.msgh_bits = MACH_MSGH_BITS( MACH_MSG_TYPE_COPY_SEND, 0 ); message.msgh_id = 0; message.msgh_local_port = MACH_PORT_NULL; message.msgh_remote_port = session->_client; message.msgh_reserved = 0; message.msgh_size = sizeof( message ); mach_msg( &message, MACH_SEND_MSG | MACH_SEND_TIMEOUT, message.msgh_size, 0, MACH_PORT_NULL, 0, MACH_PORT_NULL ); } } void DASessionRegisterCallback( DASessionRef session, DACallbackRef callback ) { CFArrayAppendValue( session->_register, callback ); } void DASessionScheduleWithRunLoop( DASessionRef session, CFRunLoopRef runLoop, CFStringRef runLoopMode ) { CFRunLoopAddSource( runLoop, session->_source, runLoopMode ); } void DASessionSetOption( DASessionRef session, DASessionOption option, Boolean value ) { DASessionSetOptions( session, option, value ); } void DASessionSetOptions( DASessionRef session, DASessionOptions options, Boolean value ) { session->_options &= ~options; session->_options |= value ? options : 0; } void DASessionSetState( DASessionRef session, DASessionState state, Boolean value ) { session->_state &= ~state; session->_state |= value ? state : 0; } void DASessionUnregisterCallback( DASessionRef session, DACallbackRef callback ) { CFIndex count; CFIndex index; count = CFArrayGetCount( session->_register ); for ( index = count - 1; index > -1; index-- ) { DACallbackRef item; item = ( void * ) CFArrayGetValueAtIndex( session->_register, index ); if ( DACallbackGetAddress( item ) == DACallbackGetAddress( callback ) ) { if ( DACallbackGetContext( item ) == DACallbackGetContext( callback ) ) { CFArrayRemoveValueAtIndex( session->_register, index ); } } } count = CFArrayGetCount( session->_queue ); for ( index = count - 1; index > -1; index-- ) { DACallbackRef item; item = ( void * ) CFArrayGetValueAtIndex( session->_queue, index ); if ( DACallbackGetAddress( item ) == DACallbackGetAddress( callback ) ) { if ( DACallbackGetContext( item ) == DACallbackGetContext( callback ) ) { CFArrayRemoveValueAtIndex( session->_queue, index ); } } } } void DASessionUnscheduleFromRunLoop( DASessionRef session, CFRunLoopRef runLoop, CFStringRef runLoopMode ) { CFRunLoopRemoveSource( runLoop, session->_source, runLoopMode ); }