Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: master
Fetching contributors…

Cannot retrieve contributors at this time

1111 lines (888 sloc) 23.915 kb
/*
* The Cheat - The legendary universal game trainer for Mac OS X.
* http://www.brokenzipper.com/trac/wiki/TheCheat
*
* Copyright (c) 2003-2011, Charles McGarvey et al.
*
* Distributable under the terms and conditions of the 2-clause BSD
* license; see the file COPYING for the legal text of the license.
*/
#import "MySocket.h"
// CONSTANTS
// this is used to read in unclaimed data
#define MYSOCKET_PACKETLEN (1024)
enum {
kMySocketAddedToManager = 1,
kMySocketConnected = 2,
kMySocketIsListener = 4
};
struct _mySocketGlobals {
BOOL isManagerRunning;
NSMutableArray *sockets;
NSRecursiveLock *readLock;
NSRecursiveLock *writeLock;
int readPipe[2];
int writePipe[2];
int maxreadfd;
int maxwritefd;
fd_set readfds;
fd_set writefds;
} _mySocketGlobals = { NO, nil, nil, nil, { -1, -1 }, { -1, -1 }, 0, 0 };
// HELPER CLASSES
@interface _MySocketPacket : NSObject
{
NSData *_buffer;
unsigned _bytesHandled;
unsigned _bytesRequired;
int _tag;
}
- (id)initWithData:(NSData *)data tag:(int)tag;
- (void *)bytes; // pointer to the current bytes; changes are bytes are handled
- (unsigned)bytesRemaining;
- (void)handledBytes:(unsigned)count;
- (unsigned)bytesRequired;
- (NSData *)data;
- (int)tag;
- (BOOL)isComplete;
@end
// PRIVATE STUFF
@interface MySocket ( PrivateAPI )
- (id)_initWithFileDescriptor:(int)sockfd;
- (void)_connect;
- (void)_addToManager;
- (void)_removeFromManager;
+ (void)_readWithSockFD:(int)fd;
+ (void)_refreshReadThread;
+ (void)_writeWithSockFD:(int)fd;
+ (void)_refreshWriteThread;
+ (void)_lockRead;
+ (void)_unlockRead;
+ (void)_lockWrite;
+ (void)_unlockWrite;
+ (void)_lockReadAndWrite;
+ (void)_unlockReadAndWrite;
/* #### MANAGER METHODS #### */
+ (void)_startManager;
+ (void)_readThread:(id)object;
+ (void)_writeThread:(id)object;
- (int)_accept;
- (int)_read;
- (int)_write;
- (void)_fillReadPacketsWithUnclaimedBytes;
- (void)_handleReadQueue;
- (void)_handleWriteQueue;
- (void)_eventDidAcceptSocket:(MySocket *)newSocket;
- (void)_eventDidDisconnect:(id)dummy;
- (void)_eventDidReadData:(_MySocketPacket *)packet;
- (void)_eventDidWriteData:(_MySocketPacket *)packet;
// utility
- (NSMutableData *)_readBufferWithLength:(unsigned *)len;
// accessors
- (int)_sockfd;
@end
@implementation MySocket
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#pragma mark Initialization
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
- (id)initWithDelegate:(id)delegate
{
if ( self = [super init] ) {
ChazLog( @"SOCKET CREATED" );
[self setDelegate:delegate];
}
return self;
}
- (void)dealloc
{
ChazLog( @"SOCKET DESTROYED" );
[self disconnect];
[super dealloc];
}
- (void)release
{
if ( [self retainCount] == 1 ) {
[self _removeFromManager];
}
[super release];
}
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#pragma mark Connecting/Disconnecting
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
- (BOOL)connectToHost:(NSString *)host port:(int)port
{
return [self connectToAddressWithData:[MySocket addressWithHost:host port:port]];
}
- (BOOL)connectToAddress:(const struct sockaddr *)addr length:(unsigned)addrLen
{
int err = 0;
if ( [self isConnected] ) {
return NO;
}
_sockfd = socket( addr->sa_family, SOCK_STREAM, 0 );
if ( _sockfd == -1 ) {
// can't get file descriptor
return NO;
}
// make the socket NOT block
/*err = fcntl( _sockfd, F_SETFL, O_NONBLOCK );
if ( err == -1 ) {
// can't not block
close( _sockfd );
return NO;
}*/
err = connect( _sockfd, addr, addrLen );
if ( err == -1 ) {
// can't connect
close( _sockfd );
return NO;
}
[self _connect];
return YES;
}
- (BOOL)connectToAddressWithData:(NSData *)addr
{
return [self connectToAddress:[addr bytes] length:[addr length]];
}
- (BOOL)listenOnPort:(int)port
{
struct sockaddr_in addr;
int err = 0;
int yes = 1;
if ( [self isConnected] ) {
return NO;
}
_sockfd = socket( AF_INET, SOCK_STREAM, 0 );
if ( _sockfd == -1 ) {
// can't get file descriptor
return NO;
}
err = setsockopt( _sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes) );
if ( err == -1 ) {
// can't reuse address
close( _sockfd );
return NO;
}
// pack the socket address structure
addr.sin_family = AF_INET;
addr.sin_port = htons( (short)port );
addr.sin_addr.s_addr = INADDR_ANY;
memset( &(addr.sin_zero), NULL, 8 );
err = bind( _sockfd, (struct sockaddr *)(&addr), sizeof(addr) );
if ( err == -1 ) {
// can't bind to this address
close( _sockfd );
return NO;
}
err = listen( _sockfd, 10 );
if ( err == -1 ) {
// can't listen on this address
close( _sockfd );
return NO;
}
_flags |= kMySocketIsListener;
[self _connect];
return YES;
}
- (void)disconnect
{
if ( !(_flags & kMySocketConnected) ) {
// not connected
return;
}
[self _removeFromManager];
close( _sockfd );
_sockfd = -1;
[_readQueue release];
_readQueue = nil;
[_writeQueue release];
_writeQueue = nil;
[_readLock release];
_readLock = nil;
[_writeLock release];
_writeLock = nil;
_startTime = 0.0;
_flags = 0;
}
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#pragma mark Reading/Writing
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
- (void)readDataToLength:(unsigned)len tag:(int)tag
{
_MySocketPacket *packet;
if ( ![self isConnected] || [self isListener] || len == 0 ) {
// must be connected and have a valid length
return;
}
// create a "read" packet
packet = [[_MySocketPacket alloc] initWithData:[NSMutableData dataWithLength:len] tag:tag];
//[packet handledBytes:0];
// add the packet to the queue
[_readLock lock];
[_readQueue addObject:packet];
[packet release];
[_readLock unlock];
// make sure the thread picks up the change
[MySocket _refreshReadThread];
}
- (void)writeData:(NSData *)data tag:(int)tag
{
_MySocketPacket *packet;
BOOL alreadyWriting;
if ( ![self isConnected] || [self isListener] ) {
// must be connected
return;
}
// create a "write" packet
packet = [[_MySocketPacket alloc] initWithData:data tag:tag];
[_writeLock lock];
alreadyWriting = [_writeQueue count] > 0;
[_writeQueue addObject:packet];
[packet release];
[_writeLock unlock];
if ( !alreadyWriting ) {
// make the helper aware the socket has data to write
[MySocket _writeWithSockFD:_sockfd];
}
}
- (void)writeBytes:(void const *)bytes length:(unsigned)len tag:(int)tag
{
[self writeData:[NSData dataWithBytes:bytes length:len] tag:tag];
}
// AsyncSocket compatibility
- (void)readDataToLength:(CFIndex)length withTimeout:(NSTimeInterval)timeout tag:(long)tag
{
[self readDataToLength:length tag:tag];
}
- (void)writeData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag
{
[self writeData:data tag:tag];
}
- (void)writeBytes:(void *)bytes length:(unsigned)len withTimeout:(NSTimeInterval)timeout tag:(long)tag
{
[self writeBytes:bytes length:len tag:tag];
}
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#pragma mark Accesors
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
- (unsigned)bytesRead
{
return _bytesRead;
}
- (unsigned)bytesWritten
{
return _bytesWritten;
}
- (NSTimeInterval)timeConnected
{
return CFAbsoluteTimeGetCurrent() - _startTime;
}
- (double)readSpeed
{
double currentTime = CFAbsoluteTimeGetCurrent();
double speed = (double)( _bytesRead - _lastBytesRead ) / ( currentTime - _lastBytesReadTime );
_lastBytesRead = _bytesRead;
_lastBytesReadTime = currentTime;
return speed;
}
- (double)writeSpeed
{
double currentTime = CFAbsoluteTimeGetCurrent();
double speed = (double)( _bytesWritten - _lastBytesWritten ) / ( currentTime - _lastBytesWrittenTime );
_lastBytesWritten = _bytesWritten;
_lastBytesWrittenTime = currentTime;
return speed;
}
- (NSString *)localHost
{
char host[128];
int err;
err = gethostname( host, sizeof(host) );
if ( err == -1 ) {
return @"";
}
return [NSString stringWithCString:host];
}
- (int)localPort
{
return 0;
}
- (NSString *)remoteHost
{
int err;
struct sockaddr_in addr;
int len = sizeof(addr);
err = getpeername( _sockfd, (struct sockaddr *)(&addr), &len );
if ( err == -1 ) {
return @"Unknown";
}
return [NSString stringWithCString:inet_ntoa(addr.sin_addr)];
}
- (int)remotePort
{
int err;
struct sockaddr_in addr;
int len = sizeof(addr);
err = getpeername( _sockfd, (struct sockaddr *)(&addr), &len );
if ( err == -1 ) {
return -1;
}
return addr.sin_port;
}
- (BOOL)isConnected
{
return _flags & kMySocketConnected;
}
- (BOOL)isListener
{
return _flags & kMySocketIsListener;
}
+ (NSData *)addressWithHost:(NSString *)host port:(int)port
{
struct hostent *h;
struct sockaddr_in addr;
// resolve the host
h = gethostbyname( [host lossyCString] );
if ( h == NULL ) {
// host not found
return nil;
}
// pack the socket address structure
addr.sin_family = AF_INET;
addr.sin_port = htons( (short)port );
memcpy( &(addr.sin_addr), h->h_addr, sizeof(struct in_addr) );
memset( &(addr.sin_zero), NULL, 8 );
return [NSData dataWithBytes:&addr length:sizeof(addr)];
}
- (id)delegate
{
return _delegate;
}
- (void)setDelegate:(id)delegate
{
_delegate = delegate;
}
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#pragma mark PrivateAPI
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
- (id)_initWithFileDescriptor:(int)sockfd
{
if ( self = [super init] ) {
_sockfd = sockfd;
[self _connect];
}
return self;
}
- (void)_connect
{
if ( ![self isListener] ) {
_readQueue = [[NSMutableArray alloc] init];
_writeQueue = [[NSMutableArray alloc] init];
}
// create the locks
_readLock = [[NSRecursiveLock alloc] init];
_writeLock = [[NSRecursiveLock alloc] init];
_startTime = _lastBytesReadTime = _lastBytesWrittenTime = CFAbsoluteTimeGetCurrent();
_bytesRead = _lastBytesRead = _bytesWritten = _lastBytesWritten = 0;
_flags |= kMySocketConnected;
[self _addToManager];
}
- (void)_addToManager
{
if ( _flags & kMySocketAddedToManager ) {
// only add this socket once
return;
}
// start the manager if it is not already started
[MySocket _startManager];
[MySocket _lockReadAndWrite];
// add to global array of sockets
[_mySocketGlobals.sockets addObject:self];
[self release];
[MySocket _readWithSockFD:_sockfd];
[MySocket _unlockReadAndWrite];
// mark as added to manager
_flags |= kMySocketAddedToManager;
}
- (void)_removeFromManager
{
if ( !(_flags & kMySocketAddedToManager) ) {
// only remove if it is added
return;
}
[MySocket _lockReadAndWrite];
// remove from global array
[self retain];
ChazLog( @"REMOVING SOCKET AT INDEX %i", [_mySocketGlobals.sockets indexOfObject:self] );
[_mySocketGlobals.sockets removeObject:self];
FD_CLR( _sockfd, &_mySocketGlobals.readfds );
FD_CLR( _sockfd, &_mySocketGlobals.writefds );
[MySocket _unlockReadAndWrite];
_flags ^= kMySocketAddedToManager;
}
+ (void)_readWithSockFD:(int)fd
{
[MySocket _lockRead];
FD_SET( fd, &_mySocketGlobals.readfds );
_mySocketGlobals.maxreadfd = MAX( _mySocketGlobals.maxreadfd, fd );
[MySocket _unlockRead];
// make sure the thread picks up the change
[MySocket _refreshReadThread];
}
+ (void)_refreshReadThread
{
char b = 'R';
write( _mySocketGlobals.readPipe[1], &b, sizeof(b) );
}
+ (void)_writeWithSockFD:(int)fd
{
[MySocket _lockWrite];
FD_SET( fd, &_mySocketGlobals.writefds );
_mySocketGlobals.maxwritefd = MAX( _mySocketGlobals.maxwritefd, fd );
[MySocket _unlockWrite];
[MySocket _refreshWriteThread];
}
+ (void)_refreshWriteThread
{
char b = 'R';
write( _mySocketGlobals.writePipe[1], &b, sizeof(b) );
}
+ (void)_lockRead
{
[_mySocketGlobals.readLock lock];
}
+ (void)_unlockRead
{
[_mySocketGlobals.readLock unlock];
}
+ (void)_lockWrite
{
[_mySocketGlobals.writeLock lock];
}
+ (void)_unlockWrite
{
[_mySocketGlobals.writeLock unlock];
}
+ (void)_lockReadAndWrite
{
[MySocket _lockRead];
[MySocket _lockWrite];
}
+ (void)_unlockReadAndWrite
{
[MySocket _unlockRead];
[MySocket _unlockWrite];
}
+ (void)_startManager
{
int err;
if ( _mySocketGlobals.isManagerRunning ) {
return;
}
ChazLog( @"MySocketHelper STARTING" );
// zero the descriptor sets
FD_ZERO( &_mySocketGlobals.readfds );
FD_ZERO( &_mySocketGlobals.writefds );
// create the read pipe
err = pipe( _mySocketGlobals.readPipe );
if ( err == -1 ) {
return;
}
FD_SET( _mySocketGlobals.readPipe[0], &_mySocketGlobals.readfds );
_mySocketGlobals.maxreadfd = _mySocketGlobals.readPipe[0];
// create the write pipe
err = pipe( _mySocketGlobals.writePipe );
if ( err == -1 ) {
close( _mySocketGlobals.readPipe[0] );
close( _mySocketGlobals.readPipe[1] );
return;
}
_mySocketGlobals.maxwritefd = _mySocketGlobals.writePipe[0];
// create other global objects
_mySocketGlobals.sockets = [[NSMutableArray alloc] init];
_mySocketGlobals.readLock = [[NSRecursiveLock alloc] init];
_mySocketGlobals.writeLock = [[NSRecursiveLock alloc] init];
// start the threads
[NSThread detachNewThreadSelector:@selector(_readThread:) toTarget:[MySocket class] withObject:nil];
[NSThread detachNewThreadSelector:@selector(_writeThread:) toTarget:[MySocket class] withObject:nil];
_mySocketGlobals.isManagerRunning = YES;
}
+ (void)_readThread:(id)object
{
BOOL breakLoop = NO;
fd_set readfds;
do {
int err;
int i, top;
// create the ever-so-important pool
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[MySocket _lockRead];
//FD_COPY( &_mySocketGlobals.readfds, &readfds );
readfds = _mySocketGlobals.readfds;
[MySocket _unlockRead];
// find the sockets which need processing
err = select( _mySocketGlobals.maxreadfd+1, &readfds, NULL, NULL, NULL );
if ( err == -1 ) {
// trouble, select() is having problems
ChazLog( @"select() failed!, error: %s", strerror(errno) );
goto DONE;
}
// check the pipe
if ( FD_ISSET( _mySocketGlobals.readPipe[0], &readfds ) ) {
char b;
err = read( _mySocketGlobals.readPipe[0], &b, sizeof(b) );
if ( err <= 0 ) {
// our connection to the main thread was severed...
// SELF DESTRUCT
ChazLog( @"readPipe severed, exiting READ thread..." );
breakLoop = YES;
goto DONE;
}
}
// process the sockets
[MySocket _lockRead];
top = [_mySocketGlobals.sockets count];
for ( i = 0; i < top; i++ ) {
MySocket *sock = [_mySocketGlobals.sockets objectAtIndex:i];
int sockfd = [sock _sockfd];
[sock _fillReadPacketsWithUnclaimedBytes];
[sock _handleReadQueue];
if ( FD_ISSET( sockfd, &readfds ) ) {
if ( [sock isListener] ) {
// socket ready for accepting
err = [sock _accept];
}
else {
// socket ready for reading
err = [sock _read];
}
if ( err == -1 ) {
// action returne error, disconnect socket
[sock disconnect];
[sock performSelectorOnMainThread:@selector(_eventDidDisconnect:)
withObject:nil waitUntilDone:NO];
top--;
}
}
}
[MySocket _unlockRead];
DONE:;
[pool release];
}
while ( !breakLoop );
}
+ (void)_writeThread:(id)object
{
BOOL breakLoop = NO;
fd_set pipefds;
fd_set readfds, writefds;
FD_ZERO( &pipefds );
FD_SET( _mySocketGlobals.writePipe[0], &pipefds );
do {
int err;
int i, top;
// create the ever-so-important pool
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
readfds = pipefds;
[MySocket _lockWrite];
//FD_COPY( &_mySocketGlobals.writefds, &writefds );
writefds = _mySocketGlobals.writefds;
[MySocket _unlockWrite];
// find the sockets which need processing
err = select( _mySocketGlobals.maxwritefd+1, &readfds, &writefds, NULL, NULL );
if ( err == -1 ) {
// trouble, select() is having problems
ChazLog( @"select() failed!, error: %s", strerror(errno) );
goto DONE;
}
// check the pipe
if ( FD_ISSET( _mySocketGlobals.writePipe[0], &readfds ) ) {
char b;
err = read( _mySocketGlobals.writePipe[0], &b, sizeof(b) );
if ( err <= 0 ) {
// our connection to the main thread was severed...
// SELF DESTRUCT
ChazLog( @"writePipe severed" );
breakLoop = YES;
goto DONE;
}
}
// process the sockets
[MySocket _lockWrite];
top = [_mySocketGlobals.sockets count];
for ( i = 0; i < top; i++ ) {
MySocket *sock = [_mySocketGlobals.sockets objectAtIndex:i];
int sockfd = [sock _sockfd];
if ( FD_ISSET( sockfd, &writefds ) ) {
// socket ready for accepting
err = [sock _write];
if ( err == -1 ) {
// action returne error, disconnect socket
[sock disconnect];
[sock performSelectorOnMainThread:@selector(_eventDidDisconnect:)
withObject:nil waitUntilDone:NO];
top--;
}
}
}
[MySocket _unlockWrite];
DONE:;
[pool release];
}
while ( !breakLoop );
}
- (int)_accept
{
MySocket *newSocket;
int newsockfd;
struct sockaddr addr;
int addrlen = sizeof(addr);
newsockfd = accept( _sockfd, &addr, &addrlen );
if ( newsockfd >= 0 ) {
// create a new MySocket
newSocket = [[MySocket alloc] _initWithFileDescriptor:newsockfd];
[newSocket setDelegate:_delegate];
[self performSelectorOnMainThread:@selector(_eventDidAcceptSocket:)
withObject:newSocket waitUntilDone:NO];
}
else {
return -1;
}
return 0;
}
- (int)_read
{
_MySocketPacket *packet = nil;
int bytesRead;
[_readLock lock];
if ( [_readQueue count] == 0 ) {
// no packets claiming anything, so just
// read into the unclaimed bytes buffer.
if ( !_unclaimedData ) {
_unclaimedData = [[NSMutableData alloc] init];
}
int len = [_unclaimedData length];
[_unclaimedData increaseLengthBy:MYSOCKET_PACKETLEN];
bytesRead = recv( _sockfd, [_unclaimedData mutableBytes] + len, MYSOCKET_PACKETLEN, 0 );
[_unclaimedData setLength:len+bytesRead];
}
else {
packet = [_readQueue objectAtIndex:0];
bytesRead = recv( _sockfd, [packet bytes], [packet bytesRemaining], 0 );
[packet handledBytes:bytesRead];
}
[_readLock unlock];
if ( bytesRead > 0 ) {
// update total bytes read
_bytesRead += bytesRead;
[self _handleReadQueue];
}
else {
// remove this socket
ChazLog( @"MySocket disconnecting: %i", bytesRead );
return -1;
}
return 0;
}
- (int)_write
{
_MySocketPacket *packet = nil;
int bytesWritten = 0;
[_writeLock lock];
if ( [_writeQueue count] > 0 ) {
int buflen = 0;
int len = sizeof(buflen);
int err;
err = getsockopt( _sockfd, SOL_SOCKET, SO_SNDBUF, &buflen, &len );
// write data
packet = [_writeQueue objectAtIndex:0];
bytesWritten = send( _sockfd, [packet bytes], MIN([packet bytesRemaining],buflen/2), 0 ); //MIN(4096,[packet bytesRemaining]), 0 );
[packet handledBytes:bytesWritten];
}
[_writeLock unlock];
if ( bytesWritten >= 0 ) {
// update total bytes read
_bytesWritten += bytesWritten;
[self _handleWriteQueue];
}
else {
return -1;
}
return 0;
}
- (void)_fillReadPacketsWithUnclaimedBytes
{
int i, top;
void *bytes;
int total;
total = [_unclaimedData length];
if ( total == 0 ) {
return;
}
bytes = [_unclaimedData mutableBytes];
[_readLock lock];
top = [_readQueue count];
for ( i = 0; i < top; i++ ) {
_MySocketPacket *packet = [_readQueue objectAtIndex:i];
int len = MIN( total, [packet bytesRemaining] );
if ( len > 0 ) {
memcpy( [packet bytes], bytes, len );
[packet handledBytes:len];
bytes += len;
total -= len;
}
if ( total == 0 ) {
break;
}
}
[_unclaimedData replaceBytesInRange:NSMakeRange(0,[_unclaimedData length]-total) withBytes:NULL length:0];
[_readLock unlock];
}
- (void)_handleReadQueue
{
int i, top;
[_readLock lock];
top = [_readQueue count];
for ( i = 0; i < top; ) {
_MySocketPacket *packet = [_readQueue objectAtIndex:0];
if ( [packet isComplete] ) {
[self performSelectorOnMainThread:@selector(_eventDidReadData:)
withObject:[packet retain] waitUntilDone:NO];
[_readQueue removeObjectAtIndex:i];
top--;
}
else {
i++;
}
}
[_readLock unlock];
}
- (void)_handleWriteQueue
{
int i, top;
[_writeLock lock];
top = [_writeQueue count];
for ( i = 0; i < top; ) {
_MySocketPacket *packet = [_writeQueue objectAtIndex:0];
if ( [packet isComplete] ) {
[self performSelectorOnMainThread:@selector(_eventDidWriteData:)
withObject:[packet retain] waitUntilDone:NO];
[_writeQueue removeObjectAtIndex:i];
top--;
}
else {
i++;
}
}
if ( [_writeQueue count] == 0 ) {
// no more pending writes
FD_CLR( _sockfd, &_mySocketGlobals.writefds );
}
[_writeLock unlock];
}
- (void)_eventDidAcceptSocket:(MySocket *)newSocket
{
// just report the event back to the delegate
if ( [_delegate respondsToSelector:@selector(socket:didAcceptSocket:)] ) {
[_delegate socket:self didAcceptSocket:newSocket];
}
// release the parameter(s)
// they were not released by the caller because the caller is in another thread.
[newSocket release];
}
- (void)_eventDidDisconnect:(id)dummy
{
[self disconnect];
if ( [_delegate respondsToSelector:@selector(socketDidDisconnect:)] ) {
[_delegate socketDidDisconnect:self];
}
}
- (void)_eventDidReadData:(_MySocketPacket *)packet
{
if ( [_delegate respondsToSelector:@selector(socket:didReadData:tag:)] ) {
[_delegate socket:self didReadData:[packet data] tag:[packet tag]];
}
[packet release];
}
- (void)_eventDidWriteData:(_MySocketPacket *)packet
{
if ( [_delegate respondsToSelector:@selector(socket:didWriteDataWithTag:)] ) {
[_delegate socket:self didWriteDataWithTag:[packet tag]];
}
[packet release];
}
- (NSMutableData *)_readBufferWithLength:(unsigned *)len
{
NSMutableData *buffer;
unsigned packetLen = *len;
if ( buffer = _unclaimedData ) {
// claim the bytes
int unclaimedLen = [_unclaimedData length];
if ( unclaimedLen > packetLen ) {
*len = packetLen;
_unclaimedData = [[NSMutableData alloc] initWithBytes:[buffer bytes]+packetLen length:unclaimedLen-packetLen];
//[[buffer subdataWithRange:NSMakeRange(packetLen,unclaimedLen-packetLen)] retain];
}
else {
*len = unclaimedLen;
_unclaimedData = nil;
}
[buffer setLength:packetLen];
}
else {
buffer = [[NSMutableData alloc] initWithLength:packetLen];
*len = 0;
}
return [buffer autorelease];
}
- (int)_sockfd
{
return _sockfd;
}
@end
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#pragma mark _MySocketPacket
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
@implementation _MySocketPacket
- (id)initWithData:(NSData *)data tag:(int)tag
{
if ( self = [super init] ) {
_buffer = [data retain];
_bytesRequired = [data length];
_tag = tag;
}
return self;
}
- (void)dealloc
{
[_buffer release];
[super dealloc];
}
- (void *)bytes
{
return (void *)[_buffer bytes] + _bytesHandled;
}
- (unsigned)bytesRemaining
{
return _bytesRequired - _bytesHandled;
}
- (void)handledBytes:(unsigned)count
{
_bytesHandled += count;
}
- (unsigned)bytesRequired
{
return _bytesRequired;
}
- (NSData *)data
{
return _buffer;
}
- (int)tag
{
return _tag;
}
- (BOOL)isComplete
{
return [self bytesRemaining] == 0;
}
@end
Jump to Line
Something went wrong with that request. Please try again.