#include "DASession.h"
#include "DACallback.h"
#include "DAServer.h"
#include <mach/mach.h>
#include <CoreFoundation/CoreFoundation.h>
#include <CoreFoundation/CFRuntime.h>
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( "<DASession %p [%p]>{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 );
}
const char * _DASessionGetName( DASessionRef session )
{
return session->_name;
}
DASessionRef DASessionCreate( CFAllocatorRef allocator, mach_port_t _client, const char * _name, pid_t _pid, AuthorizationExternalForm _rights )
{
DASessionRef 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;
server = CFMachPortCreate( allocator, _DAServerCallback, &serverContext, NULL );
if ( server )
{
CFRunLoopSourceRef source;
source = CFMachPortCreateRunLoopSource( allocator, server, 0 );
if ( source )
{
mach_port_t port;
kern_return_t status;
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 );
status = AuthorizationCreateFromExternalForm( &_rights, &rights );
if ( status )
{
extern Boolean _gDAAuthorize;
if ( _gDAAuthorize == FALSE )
{
rights = NULL;
status = errAuthorizationSuccess;
}
}
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 );
}