/* * 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. */ /* * MySocket is my 24 hour hackjob. There are other classes which would have * done a better job, but I found them to be too slow. This class wraps * around BSD sockets directly. It uses two threads for both asynchronous * reads and writes. Performance still isn't spectacular... I measure about * 58 MB/s average when transfering to localhost. * The way the old The Cheat did networking was by spawning a new thread for * each connection (for both serving and receiving). I thought that this way * would be more efficient, but the old way is noticeably faster. I may go * back to that way eventually, after all it isn't that many threads. */ /* * June 21 2005 - Chaz * I have written a much more robust socket wrapper for another project that * could be re-emplemented into The Cheat. It is cleaner code and has very * nice statistics tracking features. I'm going on my mission tomorrow. This * will have to wait two years or so. ;) */ #import #import "ChazLog.h" #include #include #include #include #include #include #include #include #include /* * This class has a few limitations which may not be obvious. First, it will * only send back delegate methods on the Main thread, not necessarily the * same thread used to create the socket. There is no way to time out a read * or write action. There is no way to just read "all" data possible; you * must specify how much data to receive. */ @interface MySocket : NSObject { int _sockfd; NSMutableArray *_readQueue; NSMutableArray *_writeQueue; NSMutableData *_unclaimedData; NSRecursiveLock *_readLock; NSRecursiveLock *_writeLock; unsigned _flags; unsigned _bytesRead; unsigned _bytesWritten; NSTimeInterval _startTime; unsigned _lastBytesRead; unsigned _lastBytesWritten; NSTimeInterval _lastBytesReadTime; NSTimeInterval _lastBytesWrittenTime; id _delegate; } /* INITIALIZATION */ - (id)initWithDelegate:(id)delegate; /* CONNECTING/ACCEPTING */ - (BOOL)connectToHost:(NSString *)host port:(int)port; - (BOOL)connectToAddress:(const struct sockaddr *)addr length:(unsigned)addrLen; - (BOOL)connectToAddressWithData:(NSData *)addr; - (BOOL)listenOnPort:(int)port; // returns YES on success /* OBVIOUS */ - (void)disconnect; // the disconnect delegate method will NOT be called. // it is only called when the socket is disconnect by remote or by error. // absolutely NO delegate methods are sent after this (until reconnecting). /* READING & WRITING */ - (void)readDataToLength:(unsigned)len tag:(int)tag; - (void)writeData:(NSData *)data tag:(int)tag; - (void)writeBytes:(void const *)bytes length:(unsigned)len tag:(int)tag; /* Nope, there is no way to time out a request. */ /* STATISTICS */ - (unsigned)bytesRead; - (unsigned)bytesWritten; /* the above accessors can be accessed after the socket is disconnected to get the grand total amount of traffic passed through the socket. */ - (NSTimeInterval)timeConnected; - (double)readSpeed; // bytes/sec - (double)writeSpeed; // bytes/sec /* These speeds are averaged out using the last time these methods were called. The more often you call these methods the more accurate they will be. */ - (NSString *)localHost; - (int)localPort; - (NSString *)remoteHost; - (int)remotePort; - (BOOL)isConnected; - (BOOL)isListener; /* CONVENIENCE */ + (NSData *)addressWithHost:(NSString *)host port:(int)port; /* DELEGATION */ - (id)delegate; - (void)setDelegate:(id)delegate; @end @interface NSObject ( MySocketDelegate ) /* DELEGATE METHODS */ - (void)socketDidDisconnect:(MySocket *)mySocket; - (void)socket:(MySocket *)mySocket didAcceptSocket:(MySocket *)newSocket; - (void)socket:(MySocket *)mySocket didReadData:(NSData *)theData tag:(int)tag; - (void)socket:(MySocket *)mySocket didWriteDataWithTag:(int)tag; @end