Show ThreadedOT.c syntax highlighted
/****************************************************************************************
ThreadedOT.c $Revision: 1.2 $
<http://rentzsch.com/redshedthreads>
Copyright © 2000-2002 Red Shed Software. All rights reserved.
by Jonathan 'Wolf' Rentzsch (jon at redshed dot net)
************************************************************************************/
#include "ThreadedOT.h"
#include "WaitRedShedThread.h"
#include "require.h"
#include "OpenTransportProtocol.h"
OTNotifyUPP gNotifyRedShedThread = nil;
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Tue, Feb 22, 2000 Created.
wolf Wed, May 16, 2001 Jason Toffaletti alerted me to the fact I was using
NewOTNotifyUPP() like a non-allocating macro, causing
memory leaks when compiling for Carbon. Fixed.
************************************************************************************/
EndpointRef
TOTOpenEndpoint(
RedShedThread *thread,
OTConfigurationRef cfig,
OTOpenFlags oflag,
TEndpointInfo *info,
OSStatus *err,
long patience )
{
OSStatus err2 = noErr;
EndpointRef result = kOTInvalidEndpointRef;
RequireRedShedThread( thread );
Require( cfig != kOTNoMemoryConfigurationPtr && cfig != kOTInvalidConfigurationPtr );
RequirePtrIfNotNil( info );
RequirePtrIfNotNil( err );
if( gNotifyRedShedThread == nil ) {
gNotifyRedShedThread = NewOTNotifyUPP( NotifyRedShedThread );
if( gNotifyRedShedThread == nil )
err2 = memFullErr;
}
if( !err2 )
err2 = OTAsyncOpenEndpoint( cfig, oflag, info, gNotifyRedShedThread, thread );
if( !err2 ) {
OTEventCode event = T_OPENCOMPLETE;
err2 = WaitOTEvent( thread, &event, (long*) &result, patience );
if( err2 )
result = kOTInvalidEndpointRef;
}
if( !err2 )
err2 = OTSetBlocking( result );
if( err )
*err = err2;
return( result );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Fri, Feb 25, 2000 Created.
wolf Wed, May 16, 2001 Jason Toffaletti alerted me to the fact I was using
NewOTNotifyUPP() like a non-allocating macro, causing
memory leaks when compiling for Carbon. Fixed.
************************************************************************************/
InetSvcRef
TOTOpenInternetServices(
RedShedThread *thread,
OTConfigurationRef cfig,
OSStatus *err,
long patience )
{
InetSvcRef result = kOTInvalidInetSvcRef;
OSStatus err2 = noErr;
RequireRedShedThread( thread );
Require( cfig != kOTNoMemoryConfigurationPtr && cfig != kOTInvalidConfigurationPtr );
RequirePtrIfNotNil( err );
if( gNotifyRedShedThread == nil ) {
gNotifyRedShedThread = NewOTNotifyUPP( NotifyRedShedThread );
if( gNotifyRedShedThread == nil )
err2 = memFullErr;
}
if( !err2 )
err2 = OTAsyncOpenInternetServices( cfig, 0, gNotifyRedShedThread, thread );
if( !err2 ) {
OTEventCode event = T_OPENCOMPLETE;
err2 = WaitOTEvent( thread, &event, (long*) &result, patience );
if( err2 )
result = kOTInvalidInetSvcRef;
}
if( !err2 ) {
err2 = OTSetBlocking( result );
}
if( err )
*err = err2;
return( result );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Tue, Feb 22, 2000 Created.
************************************************************************************/
OSStatus
TOTBind(
RedShedThread *thread,
EndpointRef ref,
TBind *reqAddr,
TBind *retAddr,
long patience )
{
OSStatus err = kOTNoError;
RequireRedShedThread( thread );
Require( ref != kOTInvalidEndpointRef );
RequirePtrIfNotNil( reqAddr );
RequirePtrIfNotNil( retAddr );
err = OTBind( ref, reqAddr, nil );
if( !err ) {
OTEventCode event = T_BINDCOMPLETE;
err = WaitOTEvent( thread, &event, nil, patience );
}
return( err );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Wed, Mar 8, 2000 Created.
************************************************************************************/
OSStatus
TOTUnbind(
RedShedThread *thread,
EndpointRef ref,
long patience )
{
OSStatus err = kOTNoError;
RequireRedShedThread( thread );
Require( ref != kOTInvalidEndpointRef );
err = OTUnbind( ref );
if( !err ) {
OTEventCode event = T_UNBINDCOMPLETE;
err = WaitOTEvent( thread, &event, nil, patience );
}
return( err );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Tue, Feb 22, 2000 Created.
************************************************************************************/
OSStatus
TOTConnect(
RedShedThread *thread,
EndpointRef ref,
TCall *sndCall,
TCall *rcvCall,
long patience )
{
OSStatus err = kOTNoError;
RequireRedShedThread( thread );
Require( ref != kOTInvalidEndpointRef );
RequirePtrIfNotNil( sndCall );
RequirePtrIfNotNil( rcvCall );
err = OTConnect( ref, sndCall, rcvCall );
if( err == kOTNoDataErr )
err = kOTNoError;
if( !err ) {
OTEventCode event = T_CONNECT;
err = WaitOTEvent( thread, &event, nil, patience );
}
if( err == kOTLookErr ) {
err = kECONNREFUSEDErr;
} else if( err == noErr ) {
err = OTRcvConnect( ref, rcvCall );
}
return( err );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Thu, Feb 17, 2000 Created.
************************************************************************************/
OSStatus
TOTRcv(
RedShedThread *thread,
EndpointRef ref,
void *buf,
OTByteCount nbytes,
long patience )
{
OTResult result = kOTNoError;
RequireRedShedThread( thread );
Require( ref != kOTInvalidEndpointRef );
RequirePtr( buf );
while( result == kOTNoError && nbytes > 0 ) {
Boolean leaveNotifier = OTEnterNotifier( ref );
OTFlags flags;
result = OTRcv( ref, buf, nbytes, &flags );
Require( result != 0 );
if( leaveNotifier )
OTLeaveNotifier( ref );
if( result > 0 ) {
nbytes -= result;
buf = ((char*)buf) + result;
result = kOTNoError;
} else if( result == kOTNoDataErr ) {
// No more data in the pipe. Wait for a T_DATA.
OTEventCode event = T_DATA;
result = WaitOTEvent( thread, &event, nil, patience );
}
}
return( result );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Thu, Feb 24, 2000 Created.
************************************************************************************/
OSStatus
TOTRcvUntil(
RedShedThread *thread,
EndpointRef ref,
void *buf,
OTByteCount *size,
const unsigned char *until,
long patience )
{
char c;
char *bufferIt = (char*) buf;
char *bufferEnd = bufferIt + *size;
const char *untilIt = (const char*) until + 1;
const char *untilEnd = (const char*) until + until[ 0 ];
OTResult result = kOTNoError;
RequireRedShedThread( thread );
Require( ref != kOTInvalidEndpointRef );
RequirePtr( buf );
RequirePtr( size );
RequirePtr( until );
*size = 0;
while( !result && bufferIt != bufferEnd && untilIt != untilEnd ) {
result = TOTRcv( thread, ref, &c, 1, patience );
if( result >= 0 ) {
result = 0;
*bufferIt = c;
++bufferIt;
++(*size);
if( *untilIt == c ) {
++untilIt;
} else {
untilIt = (const char*) until + 1;
}
}
}
if( (result == kOTNoError) && (untilIt != untilEnd) )
result = kDelimiterNotFound;
return( result );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Thu, Feb 24, 2000 Created.
wolf Sun, May 28, 2000 Now reads until a kOTNoDataErr error is encountered.
************************************************************************************/
OSStatus
TOTFlushRcv(
EndpointRef ref )
{
OTBuffer *buffer;
OTFlags flags;
OTResult result;
Require( ref != kOTInvalidEndpointRef );
do {
result = OTRcv( ref, &buffer, kOTNetbufDataIsOTBufferStar, &flags );
Require( result != 0 );
if( result > 0 ) {
OTReleaseBuffer( buffer );
}
} while( result != kOTNoDataErr );
return( kOTNoError );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Thu, Feb 17, 2000 Created.
************************************************************************************/
OSStatus
TOTSnd(
RedShedThread *thread,
EndpointRef ref,
const void *buf,
OTByteCount nbytes,
Boolean moreToCome,
long patience )
{
OTResult result = kOTNoError;
RequireRedShedThread( thread );
Require( ref != kOTInvalidEndpointRef );
RequirePtr( buf );
while( result == kOTNoError && nbytes > 0 ) {
Boolean leaveNotifier = OTEnterNotifier( ref );
#ifdef __cplusplus
result = OTSnd( ref, const_cast<void*>( buf ), nbytes, moreToCome ? T_MORE : 0 );
#else
result = OTSnd( ref, (void*) buf, nbytes, moreToCome ? T_MORE : 0 );
#endif
Require( result != 0 );
if( leaveNotifier )
OTLeaveNotifier( ref );
if( result > 0 ) {
nbytes -= result;
buf = ((char*)buf) + result;
result = kOTNoError;
} else if( result == kOTFlowErr ) {
// We need to wait for the other side to catch up.
OTEventCode event = T_GODATA;
result = WaitOTEvent( thread, &event, nil, patience );
} else if( result == kOTOutOfMemoryErr ) {
// We need to wait a little bit.
WaitTimeDeferredTask( thread, 250 );
result = kOTNoError;
}
}
return( result );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Tue, Feb 22, 2000 Created.
************************************************************************************/
OSStatus
TOTSndDisconnect(
RedShedThread *thread,
EndpointRef ref,
TCall *call,
long patience )
{
TCall call2;
OSStatus err = kOTNoError;
RequireRedShedThread( thread );
Require( ref != kOTInvalidEndpointRef );
RequirePtrIfNotNil( call );
if( call ) {
err = OTSndDisconnect( ref, call );
} else {
call2.addr.maxlen = call2.addr.len = 0;
call2.addr.buf = nil;
call2.opt.maxlen = call2.opt.len = 0;
call2.opt.buf = nil;
call2.udata.maxlen = call2.udata.len = 0;
call2.udata.buf = nil;
call2.sequence = 0;
err = OTSndDisconnect( ref, &call2 );
}
if( !err ) {
OTEventCode event = T_DISCONNECTCOMPLETE;
err = WaitOTEvent( thread, &event, nil, patience );
}
return( err );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Wed, Mar 8, 2000 Created.
************************************************************************************/
OSStatus
TOTSndRcvOrderlyDisconnect(
RedShedThread *thread,
EndpointRef ref,
long patience )
{
OSStatus err = kOTNoError;
RequireRedShedThread( thread );
Require( ref != kOTInvalidEndpointRef );
err = OTSndOrderlyDisconnect( ref );
if( !err ) {
OTEventCode event = T_ORDREL;
err = WaitOTEvent( thread, &event, nil, patience );
}
if( !err ) {
err = OTRcvOrderlyDisconnect( ref );
}
return( err );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Fri, Feb 25, 2000 Created.
************************************************************************************/
OSStatus
TOTInetMailExchange(
RedShedThread *thread,
InetSvcRef ref,
char *name,
UInt16 *num,
InetMailExchange *mx,
long patience )
{
OSStatus err = kOTNoError;
RequireRedShedThread( thread );
Require( ref != kOTInvalidInetSvcRef );
RequireCString( name, 1, 1024 );
RequirePtr( num );
Require( *num > 0 && *num < 2048 );
RequirePtr( mx );
err = OTInetMailExchange( ref, name, num, mx );
if( !err ) {
OTEventCode event = T_DNRMAILEXCHANGECOMPLETE;
err = WaitOTEvent( thread, &event, nil, patience );
}
return( err );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Wed, Mar 8, 2000 Created.
wolf Wed, May 16, 2001 Made requirement allow nil for the ret parameter.
(You can thank Jason Toffaletti for this correction.)
************************************************************************************/
OSStatus
TOTOptionManagement(
RedShedThread *thread,
EndpointRef ref,
TOptMgmt *req,
TOptMgmt *ret,
long patience )
{
OSStatus err = kOTNoError;
RequireRedShedThread( thread );
Require( ref != kOTInvalidEndpointRef );
RequirePtr( req );
RequirePtrIfNotNil( ret );
err = OTOptionManagement( ref, req, ret );
if( !err ) {
OTEventCode event = T_OPTMGMTCOMPLETE;
err = WaitOTEvent( thread, &event, nil, patience );
}
return( err );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Wed, Mar 8, 2000 Created.
wolf Sun, May 28, 2000 Made resistent to out-of-order T_PASSCON and T_DATA
events.
************************************************************************************/
OSStatus
TOTAccept(
RedShedThread *thread,
EndpointRef listener,
EndpointRef worker,
TCall *call,
long patience )
{
OTEventCode event;
OSStatus err = kOTNoError;
RequireRedShedThread( thread );
Require( listener != kOTInvalidEndpointRef );
Require( worker != kOTInvalidEndpointRef );
RequirePtr( call );
err = OTAccept( listener, worker, call );
if( !err && listener == worker ) {
// If the user is accepting the connection on the same Endpoint
// as the listener, the Notifier will see both events.
event = T_ACCEPTCOMPLETE;
err = WaitOTEvent( thread, &event, nil, patience );
}
if( !err ) {
// Accept any Open Transport event.
event = 0;
err = WaitOTEvent( thread, &event, nil, patience );
if( !err && event == T_DATA ) {
// Aha! We got the T_DATA before the T_PASSCON. Look for the T_PASSCON, it
// should be next.
event = T_PASSCON;
err = WaitOTEvent( thread, &event, nil, patience );
if( !err ) {
// Excellent, we now have the T_PASSCON. Make up a new T_DATA event
// to replace the one we swallowed.
err = NewRedShedThreadMessage( thread, kOTEventMessage, T_DATA, 0, 0 );
}
}
if( !err && event != T_PASSCON )
err = kOTLookErr;
}
return( err );
}
See more files for this project here