Added Pong

This commit is contained in:
Jeena Paradies 2011-02-28 14:58:00 +01:00
parent e53c2a82c4
commit cee10d5f75
94 changed files with 12789 additions and 0 deletions

View file

@ -0,0 +1,659 @@
//
// AsyncSocket.h
//
// This class is in the public domain.
// Originally created by Dustin Voss on Wed Jan 29 2003.
// Updated and maintained by Deusty Designs and the Mac development community.
//
// http://code.google.com/p/cocoaasyncsocket/
//
#import <Foundation/Foundation.h>
@class AsyncSocket;
@class AsyncReadPacket;
@class AsyncWritePacket;
extern NSString *const AsyncSocketException;
extern NSString *const AsyncSocketErrorDomain;
enum AsyncSocketError
{
AsyncSocketCFSocketError = kCFSocketError, // From CFSocketError enum.
AsyncSocketNoError = 0, // Never used.
AsyncSocketCanceledError, // onSocketWillConnect: returned NO.
AsyncSocketConnectTimeoutError,
AsyncSocketReadMaxedOutError, // Reached set maxLength without completing
AsyncSocketReadTimeoutError,
AsyncSocketWriteTimeoutError
};
typedef enum AsyncSocketError AsyncSocketError;
@protocol AsyncSocketDelegate
@optional
/**
* In the event of an error, the socket is closed.
* You may call "unreadData" during this call-back to get the last bit of data off the socket.
* When connecting, this delegate method may be called
* before"onSocket:didAcceptNewSocket:" or "onSocket:didConnectToHost:".
**/
- (void)onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err;
/**
* Called when a socket disconnects with or without error. If you want to release a socket after it disconnects,
* do so here. It is not safe to do that during "onSocket:willDisconnectWithError:".
*
* If you call the disconnect method, and the socket wasn't already disconnected,
* this delegate method will be called before the disconnect method returns.
**/
- (void)onSocketDidDisconnect:(AsyncSocket *)sock;
/**
* Called when a socket accepts a connection. Another socket is spawned to handle it. The new socket will have
* the same delegate and will call "onSocket:didConnectToHost:port:".
**/
- (void)onSocket:(AsyncSocket *)sock didAcceptNewSocket:(AsyncSocket *)newSocket;
/**
* Called when a new socket is spawned to handle a connection. This method should return the run-loop of the
* thread on which the new socket and its delegate should operate. If omitted, [NSRunLoop currentRunLoop] is used.
**/
- (NSRunLoop *)onSocket:(AsyncSocket *)sock wantsRunLoopForNewSocket:(AsyncSocket *)newSocket;
/**
* Called when a socket is about to connect. This method should return YES to continue, or NO to abort.
* If aborted, will result in AsyncSocketCanceledError.
*
* If the connectToHost:onPort:error: method was called, the delegate will be able to access and configure the
* CFReadStream and CFWriteStream as desired prior to connection.
*
* If the connectToAddress:error: method was called, the delegate will be able to access and configure the
* CFSocket and CFSocketNativeHandle (BSD socket) as desired prior to connection. You will be able to access and
* configure the CFReadStream and CFWriteStream in the onSocket:didConnectToHost:port: method.
**/
- (BOOL)onSocketWillConnect:(AsyncSocket *)sock;
/**
* Called when a socket connects and is ready for reading and writing.
* The host parameter will be an IP address, not a DNS name.
**/
- (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port;
/**
* Called when a socket has completed reading the requested data into memory.
* Not called if there is an error.
**/
- (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag;
/**
* Called when a socket has read in data, but has not yet completed the read.
* This would occur if using readToData: or readToLength: methods.
* It may be used to for things such as updating progress bars.
**/
- (void)onSocket:(AsyncSocket *)sock didReadPartialDataOfLength:(NSUInteger)partialLength tag:(long)tag;
/**
* Called when a socket has completed writing the requested data. Not called if there is an error.
**/
- (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag;
/**
* Called when a socket has written some data, but has not yet completed the entire write.
* It may be used to for things such as updating progress bars.
**/
- (void)onSocket:(AsyncSocket *)sock didWritePartialDataOfLength:(NSUInteger)partialLength tag:(long)tag;
/**
* Called if a read operation has reached its timeout without completing.
* This method allows you to optionally extend the timeout.
* If you return a positive time interval (> 0) the read's timeout will be extended by the given amount.
* If you don't implement this method, or return a non-positive time interval (<= 0) the read will timeout as usual.
*
* The elapsed parameter is the sum of the original timeout, plus any additions previously added via this method.
* The length parameter is the number of bytes that have been read so far for the read operation.
*
* Note that this method may be called multiple times for a single read if you return positive numbers.
**/
- (NSTimeInterval)onSocket:(AsyncSocket *)sock
shouldTimeoutReadWithTag:(long)tag
elapsed:(NSTimeInterval)elapsed
bytesDone:(NSUInteger)length;
/**
* Called if a write operation has reached its timeout without completing.
* This method allows you to optionally extend the timeout.
* If you return a positive time interval (> 0) the write's timeout will be extended by the given amount.
* If you don't implement this method, or return a non-positive time interval (<= 0) the write will timeout as usual.
*
* The elapsed parameter is the sum of the original timeout, plus any additions previously added via this method.
* The length parameter is the number of bytes that have been written so far for the write operation.
*
* Note that this method may be called multiple times for a single write if you return positive numbers.
**/
- (NSTimeInterval)onSocket:(AsyncSocket *)sock
shouldTimeoutWriteWithTag:(long)tag
elapsed:(NSTimeInterval)elapsed
bytesDone:(NSUInteger)length;
/**
* Called after the socket has successfully completed SSL/TLS negotiation.
* This method is not called unless you use the provided startTLS method.
*
* If a SSL/TLS negotiation fails (invalid certificate, etc) then the socket will immediately close,
* and the onSocket:willDisconnectWithError: delegate method will be called with the specific SSL error code.
**/
- (void)onSocketDidSecure:(AsyncSocket *)sock;
@end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@interface AsyncSocket : NSObject
{
CFSocketNativeHandle theNativeSocket4;
CFSocketNativeHandle theNativeSocket6;
CFSocketRef theSocket4; // IPv4 accept or connect socket
CFSocketRef theSocket6; // IPv6 accept or connect socket
CFReadStreamRef theReadStream;
CFWriteStreamRef theWriteStream;
CFRunLoopSourceRef theSource4; // For theSocket4
CFRunLoopSourceRef theSource6; // For theSocket6
CFRunLoopRef theRunLoop;
CFSocketContext theContext;
NSArray *theRunLoopModes;
NSTimer *theConnectTimer;
NSMutableArray *theReadQueue;
AsyncReadPacket *theCurrentRead;
NSTimer *theReadTimer;
NSMutableData *partialReadBuffer;
NSMutableArray *theWriteQueue;
AsyncWritePacket *theCurrentWrite;
NSTimer *theWriteTimer;
id theDelegate;
UInt16 theFlags;
long theUserData;
}
- (id)init;
- (id)initWithDelegate:(id)delegate;
- (id)initWithDelegate:(id)delegate userData:(long)userData;
/* String representation is long but has no "\n". */
- (NSString *)description;
/**
* Use "canSafelySetDelegate" to see if there is any pending business (reads and writes) with the current delegate
* before changing it. It is, of course, safe to change the delegate before connecting or accepting connections.
**/
- (id)delegate;
- (BOOL)canSafelySetDelegate;
- (void)setDelegate:(id)delegate;
/* User data can be a long, or an id or void * cast to a long. */
- (long)userData;
- (void)setUserData:(long)userData;
/* Don't use these to read or write. And don't close them either! */
- (CFSocketRef)getCFSocket;
- (CFReadStreamRef)getCFReadStream;
- (CFWriteStreamRef)getCFWriteStream;
// Once one of the accept or connect methods are called, the AsyncSocket instance is locked in
// and the other accept/connect methods can't be called without disconnecting the socket first.
// If the attempt fails or times out, these methods either return NO or
// call "onSocket:willDisconnectWithError:" and "onSockedDidDisconnect:".
// When an incoming connection is accepted, AsyncSocket invokes several delegate methods.
// These methods are (in chronological order):
// 1. onSocket:didAcceptNewSocket:
// 2. onSocket:wantsRunLoopForNewSocket:
// 3. onSocketWillConnect:
//
// Your server code will need to retain the accepted socket (if you want to accept it).
// The best place to do this is probably in the onSocket:didAcceptNewSocket: method.
//
// After the read and write streams have been setup for the newly accepted socket,
// the onSocket:didConnectToHost:port: method will be called on the proper run loop.
//
// Multithreading Note: If you're going to be moving the newly accepted socket to another run
// loop by implementing onSocket:wantsRunLoopForNewSocket:, then you should wait until the
// onSocket:didConnectToHost:port: method before calling read, write, or startTLS methods.
// Otherwise read/write events are scheduled on the incorrect runloop, and chaos may ensue.
/**
* Tells the socket to begin listening and accepting connections on the given port.
* When a connection comes in, the AsyncSocket instance will call the various delegate methods (see above).
* The socket will listen on all available interfaces (e.g. wifi, ethernet, etc)
**/
- (BOOL)acceptOnPort:(UInt16)port error:(NSError **)errPtr;
/**
* This method is the same as acceptOnPort:error: with the additional option
* of specifying which interface to listen on. So, for example, if you were writing code for a server that
* has multiple IP addresses, you could specify which address you wanted to listen on. Or you could use it
* to specify that the socket should only accept connections over ethernet, and not other interfaces such as wifi.
* You may also use the special strings "localhost" or "loopback" to specify that
* the socket only accept connections from the local machine.
*
* To accept connections on any interface pass nil, or simply use the acceptOnPort:error: method.
**/
- (BOOL)acceptOnInterface:(NSString *)interface port:(UInt16)port error:(NSError **)errPtr;
/**
* Connects to the given host and port.
* The host may be a domain name (e.g. "deusty.com") or an IP address string (e.g. "192.168.0.2")
**/
- (BOOL)connectToHost:(NSString *)hostname onPort:(UInt16)port error:(NSError **)errPtr;
/**
* This method is the same as connectToHost:onPort:error: with an additional timeout option.
* To not time out use a negative time interval, or simply use the connectToHost:onPort:error: method.
**/
- (BOOL)connectToHost:(NSString *)hostname
onPort:(UInt16)port
withTimeout:(NSTimeInterval)timeout
error:(NSError **)errPtr;
/**
* Connects to the given address, specified as a sockaddr structure wrapped in a NSData object.
* For example, a NSData object returned from NSNetservice's addresses method.
*
* If you have an existing struct sockaddr you can convert it to a NSData object like so:
* struct sockaddr sa -> NSData *dsa = [NSData dataWithBytes:&remoteAddr length:remoteAddr.sa_len];
* struct sockaddr *sa -> NSData *dsa = [NSData dataWithBytes:remoteAddr length:remoteAddr->sa_len];
**/
- (BOOL)connectToAddress:(NSData *)remoteAddr error:(NSError **)errPtr;
/**
* This method is the same as connectToAddress:error: with an additional timeout option.
* To not time out use a negative time interval, or simply use the connectToAddress:error: method.
**/
- (BOOL)connectToAddress:(NSData *)remoteAddr withTimeout:(NSTimeInterval)timeout error:(NSError **)errPtr;
- (BOOL)connectToAddress:(NSData *)remoteAddr
viaInterfaceAddress:(NSData *)interfaceAddr
withTimeout:(NSTimeInterval)timeout
error:(NSError **)errPtr;
/**
* Disconnects immediately. Any pending reads or writes are dropped.
* If the socket is not already disconnected, the onSocketDidDisconnect delegate method
* will be called immediately, before this method returns.
*
* Please note the recommended way of releasing an AsyncSocket instance (e.g. in a dealloc method)
* [asyncSocket setDelegate:nil];
* [asyncSocket disconnect];
* [asyncSocket release];
**/
- (void)disconnect;
/**
* Disconnects after all pending reads have completed.
* After calling this, the read and write methods will do nothing.
* The socket will disconnect even if there are still pending writes.
**/
- (void)disconnectAfterReading;
/**
* Disconnects after all pending writes have completed.
* After calling this, the read and write methods will do nothing.
* The socket will disconnect even if there are still pending reads.
**/
- (void)disconnectAfterWriting;
/**
* Disconnects after all pending reads and writes have completed.
* After calling this, the read and write methods will do nothing.
**/
- (void)disconnectAfterReadingAndWriting;
/* Returns YES if the socket and streams are open, connected, and ready for reading and writing. */
- (BOOL)isConnected;
/**
* Returns the local or remote host and port to which this socket is connected, or nil and 0 if not connected.
* The host will be an IP address.
**/
- (NSString *)connectedHost;
- (UInt16)connectedPort;
- (NSString *)localHost;
- (UInt16)localPort;
/**
* Returns the local or remote address to which this socket is connected,
* specified as a sockaddr structure wrapped in a NSData object.
*
* See also the connectedHost, connectedPort, localHost and localPort methods.
**/
- (NSData *)connectedAddress;
- (NSData *)localAddress;
/**
* Returns whether the socket is IPv4 or IPv6.
* An accepting socket may be both.
**/
- (BOOL)isIPv4;
- (BOOL)isIPv6;
// The readData and writeData methods won't block (they are asynchronous).
//
// When a read is complete the onSocket:didReadData:withTag: delegate method is called.
// When a write is complete the onSocket:didWriteDataWithTag: delegate method is called.
//
// You may optionally set a timeout for any read/write operation. (To not timeout, use a negative time interval.)
// If a read/write opertion times out, the corresponding "onSocket:shouldTimeout..." delegate method
// is called to optionally allow you to extend the timeout.
// Upon a timeout, the "onSocket:willDisconnectWithError:" method is called, followed by "onSocketDidDisconnect".
//
// The tag is for your convenience.
// You can use it as an array index, step number, state id, pointer, etc.
/**
* Reads the first available bytes that become available on the socket.
*
* If the timeout value is negative, the read operation will not use a timeout.
**/
- (void)readDataWithTimeout:(NSTimeInterval)timeout tag:(long)tag;
/**
* Reads the first available bytes that become available on the socket.
* The bytes will be appended to the given byte buffer starting at the given offset.
* The given buffer will automatically be increased in size if needed.
*
* If the timeout value is negative, the read operation will not use a timeout.
* If the buffer if nil, the socket will create a buffer for you.
*
* If the bufferOffset is greater than the length of the given buffer,
* the method will do nothing, and the delegate will not be called.
*
* If you pass a buffer, you must not alter it in any way while AsyncSocket is using it.
* After completion, the data returned in onSocket:didReadData:withTag: will be a subset of the given buffer.
* That is, it will reference the bytes that were appended to the given buffer.
**/
- (void)readDataWithTimeout:(NSTimeInterval)timeout
buffer:(NSMutableData *)buffer
bufferOffset:(NSUInteger)offset
tag:(long)tag;
/**
* Reads the first available bytes that become available on the socket.
* The bytes will be appended to the given byte buffer starting at the given offset.
* The given buffer will automatically be increased in size if needed.
* A maximum of length bytes will be read.
*
* If the timeout value is negative, the read operation will not use a timeout.
* If the buffer if nil, a buffer will automatically be created for you.
* If maxLength is zero, no length restriction is enforced.
*
* If the bufferOffset is greater than the length of the given buffer,
* the method will do nothing, and the delegate will not be called.
*
* If you pass a buffer, you must not alter it in any way while AsyncSocket is using it.
* After completion, the data returned in onSocket:didReadData:withTag: will be a subset of the given buffer.
* That is, it will reference the bytes that were appended to the given buffer.
**/
- (void)readDataWithTimeout:(NSTimeInterval)timeout
buffer:(NSMutableData *)buffer
bufferOffset:(NSUInteger)offset
maxLength:(NSUInteger)length
tag:(long)tag;
/**
* Reads the given number of bytes.
*
* If the timeout value is negative, the read operation will not use a timeout.
*
* If the length is 0, this method does nothing and the delegate is not called.
**/
- (void)readDataToLength:(NSUInteger)length withTimeout:(NSTimeInterval)timeout tag:(long)tag;
/**
* Reads the given number of bytes.
* The bytes will be appended to the given byte buffer starting at the given offset.
* The given buffer will automatically be increased in size if needed.
*
* If the timeout value is negative, the read operation will not use a timeout.
* If the buffer if nil, a buffer will automatically be created for you.
*
* If the length is 0, this method does nothing and the delegate is not called.
* If the bufferOffset is greater than the length of the given buffer,
* the method will do nothing, and the delegate will not be called.
*
* If you pass a buffer, you must not alter it in any way while AsyncSocket is using it.
* After completion, the data returned in onSocket:didReadData:withTag: will be a subset of the given buffer.
* That is, it will reference the bytes that were appended to the given buffer.
**/
- (void)readDataToLength:(NSUInteger)length
withTimeout:(NSTimeInterval)timeout
buffer:(NSMutableData *)buffer
bufferOffset:(NSUInteger)offset
tag:(long)tag;
/**
* Reads bytes until (and including) the passed "data" parameter, which acts as a separator.
*
* If the timeout value is negative, the read operation will not use a timeout.
*
* If you pass nil or zero-length data as the "data" parameter,
* the method will do nothing, and the delegate will not be called.
*
* To read a line from the socket, use the line separator (e.g. CRLF for HTTP, see below) as the "data" parameter.
* Note that this method is not character-set aware, so if a separator can occur naturally as part of the encoding for
* a character, the read will prematurely end.
**/
- (void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag;
/**
* Reads bytes until (and including) the passed "data" parameter, which acts as a separator.
* The bytes will be appended to the given byte buffer starting at the given offset.
* The given buffer will automatically be increased in size if needed.
*
* If the timeout value is negative, the read operation will not use a timeout.
* If the buffer if nil, a buffer will automatically be created for you.
*
* If the bufferOffset is greater than the length of the given buffer,
* the method will do nothing, and the delegate will not be called.
*
* If you pass a buffer, you must not alter it in any way while AsyncSocket is using it.
* After completion, the data returned in onSocket:didReadData:withTag: will be a subset of the given buffer.
* That is, it will reference the bytes that were appended to the given buffer.
*
* To read a line from the socket, use the line separator (e.g. CRLF for HTTP, see below) as the "data" parameter.
* Note that this method is not character-set aware, so if a separator can occur naturally as part of the encoding for
* a character, the read will prematurely end.
**/
- (void)readDataToData:(NSData *)data
withTimeout:(NSTimeInterval)timeout
buffer:(NSMutableData *)buffer
bufferOffset:(NSUInteger)offset
tag:(long)tag;
/**
* Reads bytes until (and including) the passed "data" parameter, which acts as a separator.
*
* If the timeout value is negative, the read operation will not use a timeout.
*
* If maxLength is zero, no length restriction is enforced.
* Otherwise if maxLength bytes are read without completing the read,
* it is treated similarly to a timeout - the socket is closed with a AsyncSocketReadMaxedOutError.
* The read will complete successfully if exactly maxLength bytes are read and the given data is found at the end.
*
* If you pass nil or zero-length data as the "data" parameter,
* the method will do nothing, and the delegate will not be called.
* If you pass a maxLength parameter that is less than the length of the data parameter,
* the method will do nothing, and the delegate will not be called.
*
* To read a line from the socket, use the line separator (e.g. CRLF for HTTP, see below) as the "data" parameter.
* Note that this method is not character-set aware, so if a separator can occur naturally as part of the encoding for
* a character, the read will prematurely end.
**/
- (void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout maxLength:(NSUInteger)length tag:(long)tag;
/**
* Reads bytes until (and including) the passed "data" parameter, which acts as a separator.
* The bytes will be appended to the given byte buffer starting at the given offset.
* The given buffer will automatically be increased in size if needed.
* A maximum of length bytes will be read.
*
* If the timeout value is negative, the read operation will not use a timeout.
* If the buffer if nil, a buffer will automatically be created for you.
*
* If maxLength is zero, no length restriction is enforced.
* Otherwise if maxLength bytes are read without completing the read,
* it is treated similarly to a timeout - the socket is closed with a AsyncSocketReadMaxedOutError.
* The read will complete successfully if exactly maxLength bytes are read and the given data is found at the end.
*
* If you pass a maxLength parameter that is less than the length of the data parameter,
* the method will do nothing, and the delegate will not be called.
* If the bufferOffset is greater than the length of the given buffer,
* the method will do nothing, and the delegate will not be called.
*
* If you pass a buffer, you must not alter it in any way while AsyncSocket is using it.
* After completion, the data returned in onSocket:didReadData:withTag: will be a subset of the given buffer.
* That is, it will reference the bytes that were appended to the given buffer.
*
* To read a line from the socket, use the line separator (e.g. CRLF for HTTP, see below) as the "data" parameter.
* Note that this method is not character-set aware, so if a separator can occur naturally as part of the encoding for
* a character, the read will prematurely end.
**/
- (void)readDataToData:(NSData *)data
withTimeout:(NSTimeInterval)timeout
buffer:(NSMutableData *)buffer
bufferOffset:(NSUInteger)offset
maxLength:(NSUInteger)length
tag:(long)tag;
/**
* Writes data to the socket, and calls the delegate when finished.
*
* If you pass in nil or zero-length data, this method does nothing and the delegate will not be called.
* If the timeout value is negative, the write operation will not use a timeout.
**/
- (void)writeData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag;
/**
* Returns progress of current read or write, from 0.0 to 1.0, or NaN if no read/write (use isnan() to check).
* "tag", "done" and "total" will be filled in if they aren't NULL.
**/
- (float)progressOfReadReturningTag:(long *)tag bytesDone:(NSUInteger *)done total:(NSUInteger *)total;
- (float)progressOfWriteReturningTag:(long *)tag bytesDone:(NSUInteger *)done total:(NSUInteger *)total;
/**
* Secures the connection using SSL/TLS.
*
* This method may be called at any time, and the TLS handshake will occur after all pending reads and writes
* are finished. This allows one the option of sending a protocol dependent StartTLS message, and queuing
* the upgrade to TLS at the same time, without having to wait for the write to finish.
* Any reads or writes scheduled after this method is called will occur over the secured connection.
*
* The possible keys and values for the TLS settings are well documented.
* Some possible keys are:
* - kCFStreamSSLLevel
* - kCFStreamSSLAllowsExpiredCertificates
* - kCFStreamSSLAllowsExpiredRoots
* - kCFStreamSSLAllowsAnyRoot
* - kCFStreamSSLValidatesCertificateChain
* - kCFStreamSSLPeerName
* - kCFStreamSSLCertificates
* - kCFStreamSSLIsServer
*
* Please refer to Apple's documentation for associated values, as well as other possible keys.
*
* If you pass in nil or an empty dictionary, the default settings will be used.
*
* The default settings will check to make sure the remote party's certificate is signed by a
* trusted 3rd party certificate agency (e.g. verisign) and that the certificate is not expired.
* However it will not verify the name on the certificate unless you
* give it a name to verify against via the kCFStreamSSLPeerName key.
* The security implications of this are important to understand.
* Imagine you are attempting to create a secure connection to MySecureServer.com,
* but your socket gets directed to MaliciousServer.com because of a hacked DNS server.
* If you simply use the default settings, and MaliciousServer.com has a valid certificate,
* the default settings will not detect any problems since the certificate is valid.
* To properly secure your connection in this particular scenario you
* should set the kCFStreamSSLPeerName property to "MySecureServer.com".
* If you do not know the peer name of the remote host in advance (for example, you're not sure
* if it will be "domain.com" or "www.domain.com"), then you can use the default settings to validate the
* certificate, and then use the X509Certificate class to verify the issuer after the socket has been secured.
* The X509Certificate class is part of the CocoaAsyncSocket open source project.
**/
- (void)startTLS:(NSDictionary *)tlsSettings;
/**
* For handling readDataToData requests, data is necessarily read from the socket in small increments.
* The performance can be much improved by allowing AsyncSocket to read larger chunks at a time and
* store any overflow in a small internal buffer.
* This is termed pre-buffering, as some data may be read for you before you ask for it.
* If you use readDataToData a lot, enabling pre-buffering will result in better performance, especially on the iPhone.
*
* The default pre-buffering state is controlled by the DEFAULT_PREBUFFERING definition.
* It is highly recommended one leave this set to YES.
*
* This method exists in case pre-buffering needs to be disabled by default for some unforeseen reason.
* In that case, this method exists to allow one to easily enable pre-buffering when ready.
**/
- (void)enablePreBuffering;
/**
* When you create an AsyncSocket, it is added to the runloop of the current thread.
* So for manually created sockets, it is easiest to simply create the socket on the thread you intend to use it.
*
* If a new socket is accepted, the delegate method onSocket:wantsRunLoopForNewSocket: is called to
* allow you to place the socket on a separate thread. This works best in conjunction with a thread pool design.
*
* If, however, you need to move the socket to a separate thread at a later time, this
* method may be used to accomplish the task.
*
* This method must be called from the thread/runloop the socket is currently running on.
*
* Note: After calling this method, all further method calls to this object should be done from the given runloop.
* Also, all delegate calls will be sent on the given runloop.
**/
- (BOOL)moveToRunLoop:(NSRunLoop *)runLoop;
/**
* Allows you to configure which run loop modes the socket uses.
* The default set of run loop modes is NSDefaultRunLoopMode.
*
* If you'd like your socket to continue operation during other modes, you may want to add modes such as
* NSModalPanelRunLoopMode or NSEventTrackingRunLoopMode. Or you may simply want to use NSRunLoopCommonModes.
*
* Accepted sockets will automatically inherit the same run loop modes as the listening socket.
*
* Note: NSRunLoopCommonModes is defined in 10.5. For previous versions one can use kCFRunLoopCommonModes.
**/
- (BOOL)setRunLoopModes:(NSArray *)runLoopModes;
- (BOOL)addRunLoopMode:(NSString *)runLoopMode;
- (BOOL)removeRunLoopMode:(NSString *)runLoopMode;
/**
* Returns the current run loop modes the AsyncSocket instance is operating in.
* The default set of run loop modes is NSDefaultRunLoopMode.
**/
- (NSArray *)runLoopModes;
/**
* In the event of an error, this method may be called during onSocket:willDisconnectWithError: to read
* any data that's left on the socket.
**/
- (NSData *)unreadData;
/* A few common line separators, for use with the readDataToData:... methods. */
+ (NSData *)CRLFData; // 0x0D0A
+ (NSData *)CRData; // 0x0D
+ (NSData *)LFData; // 0x0A
+ (NSData *)ZeroData; // 0x00
@end

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,20 @@
//
// GGSDelegate.h
// Pong
//
// Created by Jeena on 27.02.11.
// Copyright 2011 __MyCompanyName__. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "GGSNetwork.h"
@class GGSNetwork;
@protocol GGSDelegate
- (void)GGSNetwork:(GGSNetwork *)ggsNetwork ready:(BOOL)ready;
- (void)GGSNetwork:(GGSNetwork *)ggsNetwork gotCommand:(NSString *)command withArgs:(NSString *)args;
- (void)GGSNetwork:(GGSNetwork *)ggsNetwork defined:(BOOL)defined;
@end

View file

@ -0,0 +1,31 @@
//
// Network.h
// Pong
//
// Created by Jeena on 27.02.11.
// Copyright 2011 __MyCompanyName__. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "AsyncSocket.h"
#import "GGSDelegate.h"
@protocol GGSDelegate;
@interface GGSNetwork : NSObject {
AsyncSocket *asyncSocket;
id<GGSDelegate> delegate;
NSString *gameToken;
NSString *currentCommand;
}
@property (nonatomic, retain) AsyncSocket *asyncSocket;
@property (nonatomic, retain) id<GGSDelegate> delegate;
@property (nonatomic, retain) NSString *gameToken;
@property (nonatomic, retain) NSString *currentCommand;
- (id)initWithDelegate:(id)delegate;
- (void)define:(NSString *)sourceCode;
- (void)sendCommand:(NSString *)command withArgs:(NSString *)args;
@end

View file

@ -0,0 +1,117 @@
//
// Network.m
// Pong
//
// Created by Jeena on 27.02.11.
// Copyright 2011 __MyCompanyName__. All rights reserved.
//
#import "GGSNetwork.h"
@implementation GGSNetwork
#define GGS_HOST @"jeena.net";
#define GGS_PORT 9000
#define NO_TIMEOUT -1
#define CONNECT_RESPONSE_TAG 9
#define HELLO_REQUEST_TAG 10
#define HELLO_RESPONSE_TAG 11
#define DEFINE_REQUEST_TAG 12
#define DEFINE_RESPONSE_TAG 13
#define COMMAND_REQUEST_TAG 14
#define COMMAND_RESPONSE_TAG 15
#define ARGS_RESPONSE_TAG 16
@synthesize asyncSocket, delegate, gameToken, currentCommand;
- (id)initWithDelegate:(id<GGSDelegate>)_delegate {
if (self = [super init]) {
delegate = _delegate;
asyncSocket = [[AsyncSocket alloc] initWithDelegate:self];
[asyncSocket connectToHost:@"jeena.net" onPort:9000 error:nil];
[asyncSocket readDataToLength:36 withTimeout:NO_TIMEOUT tag:CONNECT_RESPONSE_TAG];
}
return self;
}
- (void)define:(NSString *)sourceCode {
NSString *body = [NSString stringWithFormat:@"Token: %@\nServer-Command: define\nContent-Length: %i\n\n%@",
self.gameToken,
[sourceCode length],
sourceCode];
[asyncSocket writeData:[body dataUsingEncoding:NSUTF8StringEncoding] withTimeout:NO_TIMEOUT tag:DEFINE_REQUEST_TAG];
[asyncSocket readDataToData:[@"\n\n" dataUsingEncoding:NSUTF8StringEncoding] withTimeout:NO_TIMEOUT tag:DEFINE_RESPONSE_TAG];
}
- (void)sendCommand:(NSString *)command withArgs:(NSString *)args {
NSString *body = [NSString stringWithFormat:@"Token: %@\nGame-Command: %@\nContent-Length: %i\n\n%@",
self.gameToken,
command,
[args length]+1,
args];
[asyncSocket writeData:[body dataUsingEncoding:NSUTF8StringEncoding] withTimeout:NO_TIMEOUT tag:COMMAND_REQUEST_TAG];
// [asyncSocket readDataToData:[@"\n\n" dataUsingEncoding:NSUTF8StringEncoding] withTimeout:NO_TIMEOUT tag:COMMAND_RESPONSE_TAG];
[asyncSocket readDataToData:[@"\n" dataUsingEncoding:NSUTF8StringEncoding] withTimeout:NO_TIMEOUT tag:ARGS_RESPONSE_TAG]; // FIXME change to \n\n abd COMMAND_RESPONSE_TAG
}
- (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port {
}
- (void)onSocket:(AsyncSocket *)sender didReadData:(NSData *)data withTag:(long)tag {
if (tag == CONNECT_RESPONSE_TAG) {
NSString *response = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
self.gameToken = response;
[response release];
[delegate GGSNetwork:self ready:YES];
} else if (tag == DEFINE_RESPONSE_TAG) {
[self.delegate GGSNetwork:self defined:YES];
} else if (tag == COMMAND_RESPONSE_TAG) {
NSString *response = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSArray *headers = [response componentsSeparatedByString:@"\n"];
[response release];
for (NSInteger i = 0; i < [headers count]; i++) {
NSString *header = [headers objectAtIndex:i];
if ([header rangeOfString:@"Client-Command: "].location == 0) {
self.currentCommand = [header substringFromIndex:16];
} else if ([header rangeOfString:@"Size: "].location == 0) {
[asyncSocket readDataToLength:[[header substringFromIndex:6] intValue] withTimeout:NO_TIMEOUT tag:ARGS_RESPONSE_TAG];
}
}
} else if (tag == ARGS_RESPONSE_TAG) {
NSString *response = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
[delegate GGSNetwork:self gotCommand:self.currentCommand withArgs:response];
[response release];
//self.currentCommand = nil;
[asyncSocket readDataToData:[@"\n" dataUsingEncoding:NSUTF8StringEncoding] withTimeout:NO_TIMEOUT tag:ARGS_RESPONSE_TAG];
}
}
- (void)dealloc {
[asyncSocket release];
[gameToken release];
[currentCommand release];
[super dealloc];
}
@end

View file

@ -0,0 +1,22 @@
//
// PongAppDelegate.h
// Pong
//
// Created by Jeena on 26.01.11.
// Copyright 2011 __MyCompanyName__. All rights reserved.
//
#import <UIKit/UIKit.h>
@class PongViewController;
@interface PongAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
PongViewController *viewController;
}
@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet PongViewController *viewController;
@end

View file

@ -0,0 +1,88 @@
//
// PongAppDelegate.m
// Pong
//
// Created by Jeena on 26.01.11.
// Copyright 2011 __MyCompanyName__. All rights reserved.
//
#import "PongAppDelegate.h"
#import "PongViewController.h"
@implementation PongAppDelegate
@synthesize window;
@synthesize viewController;
#pragma mark -
#pragma mark Application lifecycle
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
// Add the view controller's view to the window and display.
[self.window addSubview:viewController.view];
[self.window makeKeyAndVisible];
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application {
/*
Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
*/
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
/*
Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
If your application supports background execution, called instead of applicationWillTerminate: when the user quits.
*/
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
/*
Called as part of transition from the background to the inactive state: here you can undo many of the changes made on entering the background.
*/
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
/*
Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
*/
}
- (void)applicationWillTerminate:(UIApplication *)application {
/*
Called when the application is about to terminate.
See also applicationDidEnterBackground:.
*/
}
#pragma mark -
#pragma mark Memory management
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
/*
Free up as much memory as possible by purging cached data objects that can be recreated (or reloaded from disk) later.
*/
}
- (void)dealloc {
[viewController release];
[window release];
[super dealloc];
}
@end

View file

@ -0,0 +1,50 @@
//
// PongViewController.h
// Pong
//
// Created by Jeena on 26.01.11.
// Copyright 2011 __MyCompanyName__. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "GGSDelegate.h"
#import "GGSNetwork.h"
enum GameType {
kGameTypeSinglePlayer = 0,
kGameTypeMultiPlayer,
kGameTypeNetworkMultiPlayer
};
@interface PongViewController : UIViewController <GGSDelegate> {
IBOutlet UIView *ballView;
IBOutlet UIView *player1View;
IBOutlet UIView *player2View;
IBOutlet UILabel *tapToBegin;
CGPoint ballVelocity;
BOOL gamePaused;
IBOutlet UILabel *pointsP1;
IBOutlet UILabel *pointsP2;
GGSNetwork *ggsNetwork;
}
@property (nonatomic, retain) IBOutlet UIView *ballView;
@property (nonatomic, retain) IBOutlet UIView *player1View;
@property (nonatomic, retain) IBOutlet UIView *player2View;
@property (nonatomic, retain) IBOutlet UIView *tapToBegin;
@property (nonatomic, retain) IBOutlet UILabel *pointsP1;
@property (nonatomic, retain) IBOutlet UILabel *pointsP2;
@property (nonatomic, retain) GGSNetwork *ggsNetwork;
- (void)startPositions;
- (void)zeroPoints;
- (void)moveBall;
- (void)positionPlayer:(CGPoint)point;
@end

View file

@ -0,0 +1,241 @@
//
// PongViewController.m
// Pong
//
// Created by Jeena on 26.01.11.
// Copyright 2011 __MyCompanyName__. All rights reserved.
//
#import "PongViewController.h"
#import "GGSNetwork.h"
@implementation PongViewController
#define PLAYER_SPEED 20
#define BALL_SPEED_X 7
#define BALL_SPEED_Y 5
#define INTERVAL 0.05
#define WIDTH 480
#define HEIGHT 320
@synthesize ballView, player1View, player2View, tapToBegin, pointsP1, pointsP2;
/*
// The designated initializer. Override to perform setup that is required before the view is loaded.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
*/
/*
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView {
[super loadView];
}
*/
#pragma mark -
#pragma mark GGSNetwork Delegate
- (void)GGSNetwork:(GGSNetwork *)ggsNetwork ready:(BOOL)ready {
[ggsNetwork sendCommand:@"nick" withArgs:@"jeena"];
[ggsNetwork sendCommand:@"chat" withArgs:@"Hi everybody I'm pong."];
}
- (void)GGSNetwork:(GGSNetwork *)ggsNetwork defined:(BOOL)defined {
if (defined) {
NSLog(@"Defined");
} else {
NSLog(@"Not defined");
}
}
- (void)GGSNetwork:(GGSNetwork *)ggsNetwork gotCommand:(NSString *)command withArgs:(NSString *)args {
NSLog(@"Command: %@; Args: %@", command, args);
}
#pragma mark -
#pragma mark View
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
ggsNetwork = [[GGSNetwork alloc] initWithDelegate:self];
gamePaused = YES;
[self startPositions];
[NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:@selector(moveBall) userInfo:nil repeats:YES];
}
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self becomeFirstResponder];
}
- (void)viewWillDisappear:(BOOL)animated {
[self resignFirstResponder];
[super viewWillDisappear:animated];
}
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft || interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
# pragma mark -
# pragma mark Ball
- (void)moveBall {
if (!gamePaused) {
[UIView beginAnimations:NULL context:NULL];
ballView.center = CGPointMake(ballView.center.x + ballVelocity.x, ballView.center.y + ballVelocity.y );
[UIView commitAnimations];
if (ballView.center.y > HEIGHT || ballView.center.y < 0) {
ballVelocity.y = -ballVelocity.y;
}
if (CGRectIntersectsRect(ballView.frame, player1View.frame) || CGRectIntersectsRect(ballView.frame, player2View.frame)) {
ballVelocity.x = - (ballVelocity.x + 1);
if (arc4random() % 2) {
ballVelocity.y = - (ballVelocity.y + 1);
}
}
if (ballView.center.x > WIDTH || ballView.center.x < 0) {
if (ballView.center.x < 0) {
pointsP1.text = [NSString stringWithFormat:@"%i", [pointsP1.text intValue] + 1];
} else {
pointsP2.text = [NSString stringWithFormat:@"%i", [pointsP2.text intValue] + 1];
}
gamePaused = YES;
[self startPositions];
}
} else {
tapToBegin.hidden = NO;
}
}
# pragma mark -
# pragma mark Positioning
- (void)startPositions {
int s1 = - (arc4random() % 5);
int s2 = - (arc4random() % 5);
int d1 = arc4random() % 2 ? -1 : 1;
int d2 = arc4random() % 2 ? -1 : 1;
ballVelocity = CGPointMake((BALL_SPEED_X + s1) * d1 , (BALL_SPEED_Y + s2) * d2);
ballView.center = CGPointMake(WIDTH/2, HEIGHT/2);
player1View.center = CGPointMake(30, HEIGHT/2);
player2View.center = CGPointMake(WIDTH-30, HEIGHT/2);
}
- (void)positionPlayer:(CGPoint)point {
UIView *p;
NSInteger direction = 0;
if (point.x < WIDTH/2) {
p = player1View;
} else {
p = player2View;
}
if (point.y > HEIGHT/2 && p.frame.origin.y + p.frame.size.height < HEIGHT) {
direction = 1;
} else if (point.y < HEIGHT/2 && p.frame.origin.y > 0) {
direction = -1;
} else {
direction = 0;
}
CGRect f = p.frame;
f.origin.y = f.origin.y + (PLAYER_SPEED * direction);
[UIView beginAnimations:NULL context:NULL];
p.frame = f;
[UIView commitAnimations];
}
#pragma mark -
#pragma mark Input
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
if (gamePaused) {
tapToBegin.hidden = YES;
gamePaused = NO;
} else {
switch ([touches count]) {
case 1:
[self positionPlayer:[[[touches allObjects] objectAtIndex:0] locationInView:self.view]];
break;
default:
[self positionPlayer:[[[touches allObjects] objectAtIndex:0] locationInView:self.view]];
[self positionPlayer:[[[touches allObjects] objectAtIndex:1] locationInView:self.view]];
break;
}
}
}
# pragma mark -
# pragma mark Reset
-(BOOL)canBecomeFirstResponder {
return YES;
}
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event {
if (event.type == UIEventSubtypeMotionShake) {
[self zeroPoints];
}
}
- (void)zeroPoints {
pointsP1.text = @"0";
pointsP2.text = @"0";
}
# pragma mark -
# pragma mark Dealloc
- (void)dealloc {
[ballView release];
[player1View release];
[player2View release];
[tapToBegin release];
[pointsP1 release];
[pointsP2 release];
[ggsNetwork release];
[super dealloc];
}
@end