diff options
Diffstat (limited to 'Vendor/UnittWebSocketClient')
17 files changed, 3220 insertions, 0 deletions
diff --git a/Vendor/UnittWebSocketClient/bin/Debug-iphoneos/libUnittWebSocketClient.a b/Vendor/UnittWebSocketClient/bin/Debug-iphoneos/libUnittWebSocketClient.a Binary files differnew file mode 100644 index 0000000..f6dad21 --- /dev/null +++ b/Vendor/UnittWebSocketClient/bin/Debug-iphoneos/libUnittWebSocketClient.a diff --git a/Vendor/UnittWebSocketClient/bin/Debug-iphonesimulator/libUnittWebSocketClient.a b/Vendor/UnittWebSocketClient/bin/Debug-iphonesimulator/libUnittWebSocketClient.a Binary files differnew file mode 100644 index 0000000..4ea7a37 --- /dev/null +++ b/Vendor/UnittWebSocketClient/bin/Debug-iphonesimulator/libUnittWebSocketClient.a diff --git a/Vendor/UnittWebSocketClient/bin/Release-iphoneos/libUnittWebSocketClient.a b/Vendor/UnittWebSocketClient/bin/Release-iphoneos/libUnittWebSocketClient.a Binary files differnew file mode 100644 index 0000000..5cbabbb --- /dev/null +++ b/Vendor/UnittWebSocketClient/bin/Release-iphoneos/libUnittWebSocketClient.a diff --git a/Vendor/UnittWebSocketClient/bin/Release-iphonesimulator/libUnittWebSocketClient.a b/Vendor/UnittWebSocketClient/bin/Release-iphonesimulator/libUnittWebSocketClient.a Binary files differnew file mode 100644 index 0000000..77fbce6 --- /dev/null +++ b/Vendor/UnittWebSocketClient/bin/Release-iphonesimulator/libUnittWebSocketClient.a diff --git a/Vendor/UnittWebSocketClient/include/AsyncSocket.h b/Vendor/UnittWebSocketClient/include/AsyncSocket.h new file mode 100644 index 0000000..33c1a7f --- /dev/null +++ b/Vendor/UnittWebSocketClient/include/AsyncSocket.h @@ -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 diff --git a/Vendor/UnittWebSocketClient/include/GCDAsyncSocket.h b/Vendor/UnittWebSocketClient/include/GCDAsyncSocket.h new file mode 100644 index 0000000..e53350b --- /dev/null +++ b/Vendor/UnittWebSocketClient/include/GCDAsyncSocket.h @@ -0,0 +1,963 @@ +// +// GCDAsyncSocket.h +// +// This class is in the public domain. +// Originally created by Robbie Hanson in Q3 2010. +// Updated and maintained by Deusty LLC and the Mac development community. +// +// http://code.google.com/p/cocoaasyncsocket/ +// + +#import <Foundation/Foundation.h> +#import <Security/Security.h> +#import <dispatch/dispatch.h> + +@class GCDAsyncReadPacket; +@class GCDAsyncWritePacket; + +extern NSString *const GCDAsyncSocketException; +extern NSString *const GCDAsyncSocketErrorDomain; + +#if !TARGET_OS_IPHONE +extern NSString *const GCDAsyncSocketSSLCipherSuites; +extern NSString *const GCDAsyncSocketSSLDiffieHellmanParameters; +#endif + +enum GCDAsyncSocketError +{ + GCDAsyncSocketNoError = 0, // Never used + GCDAsyncSocketBadConfigError, // Invalid configuration + GCDAsyncSocketBadParamError, // Invalid parameter was passed + GCDAsyncSocketConnectTimeoutError, // A connect operation timed out + GCDAsyncSocketReadTimeoutError, // A read operation timed out + GCDAsyncSocketWriteTimeoutError, // A write operation timed out + GCDAsyncSocketReadMaxedOutError, // Reached set maxLength without completing + GCDAsyncSocketClosedError, // The remote peer closed the connection + GCDAsyncSocketOtherError, // Description provided in userInfo +}; +typedef enum GCDAsyncSocketError GCDAsyncSocketError; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +@interface GCDAsyncSocket : NSObject +{ + uint32_t flags; + uint16_t config; + + id delegate; + dispatch_queue_t delegateQueue; + + int socket4FD; + int socket6FD; + int connectIndex; + NSData * connectInterface4; + NSData * connectInterface6; + + dispatch_queue_t socketQueue; + + dispatch_source_t accept4Source; + dispatch_source_t accept6Source; + dispatch_source_t connectTimer; + dispatch_source_t readSource; + dispatch_source_t writeSource; + dispatch_source_t readTimer; + dispatch_source_t writeTimer; + + NSMutableArray *readQueue; + NSMutableArray *writeQueue; + + GCDAsyncReadPacket *currentRead; + GCDAsyncWritePacket *currentWrite; + + unsigned long socketFDBytesAvailable; + + NSMutableData *partialReadBuffer; + +#if TARGET_OS_IPHONE + CFStreamClientContext streamContext; + CFReadStreamRef readStream; + CFWriteStreamRef writeStream; +#else + SSLContextRef sslContext; + NSMutableData *sslReadBuffer; + size_t sslWriteCachedLength; +#endif + + id userData; +} + +/** + * GCDAsyncSocket uses the standard delegate paradigm, + * but executes all delegate callbacks on a given delegate dispatch queue. + * This allows for maximum concurrency, while at the same time providing easy thread safety. + * + * You MUST set a delegate AND delegate dispatch queue before attempting to + * use the socket, or you will get an error. + * + * The socket queue is optional. + * If you pass NULL, GCDAsyncSocket will automatically create it's own socket queue. + * If you choose to provide a socket queue, the socket queue must not be a concurrent queue. + * + * The delegate queue and socket queue can optionally be the same. +**/ +- (id)init; +- (id)initWithSocketQueue:(dispatch_queue_t)sq; +- (id)initWithDelegate:(id)aDelegate delegateQueue:(dispatch_queue_t)dq; +- (id)initWithDelegate:(id)aDelegate delegateQueue:(dispatch_queue_t)dq socketQueue:(dispatch_queue_t)sq; + +#pragma mark Configuration + +- (id)delegate; +- (void)setDelegate:(id)delegate; +- (void)synchronouslySetDelegate:(id)delegate; + +- (dispatch_queue_t)delegateQueue; +- (void)setDelegateQueue:(dispatch_queue_t)delegateQueue; +- (void)synchronouslySetDelegateQueue:(dispatch_queue_t)delegateQueue; + +- (void)getDelegate:(id *)delegatePtr delegateQueue:(dispatch_queue_t *)delegateQueuePtr; +- (void)setDelegate:(id)delegate delegateQueue:(dispatch_queue_t)delegateQueue; +- (void)synchronouslySetDelegate:(id)delegate delegateQueue:(dispatch_queue_t)delegateQueue; + +/** + * Traditionally sockets are not closed until the conversation is over. + * However, it is technically possible for the remote enpoint to close its write stream. + * Our socket would then be notified that there is no more data to be read, + * but our socket would still be writeable and the remote endpoint could continue to receive our data. + * + * The argument for this confusing functionality stems from the idea that a client could shut down its + * write stream after sending a request to the server, thus notifying the server there are to be no further requests. + * In practice, however, this technique did little to help server developers. + * + * To make matters worse, from a TCP perspective there is no way to tell the difference from a read stream close + * and a full socket close. They both result in the TCP stack receiving a FIN packet. The only way to tell + * is by continuing to write to the socket. If it was only a read stream close, then writes will continue to work. + * Otherwise an error will be occur shortly (when the remote end sends us a RST packet). + * + * In addition to the technical challenges and confusion, many high level socket/stream API's provide + * no support for dealing with the problem. If the read stream is closed, the API immediately declares the + * socket to be closed, and shuts down the write stream as well. In fact, this is what Apple's CFStream API does. + * It might sound like poor design at first, but in fact it simplifies development. + * + * The vast majority of the time if the read stream is closed it's because the remote endpoint closed its socket. + * Thus it actually makes sense to close the socket at this point. + * And in fact this is what most networking developers want and expect to happen. + * However, if you are writing a server that interacts with a plethora of clients, + * you might encounter a client that uses the discouraged technique of shutting down its write stream. + * If this is the case, you can set this property to NO, + * and make use of the socketDidCloseReadStream delegate method. + * + * The default value is YES. +**/ +- (BOOL)autoDisconnectOnClosedReadStream; +- (void)setAutoDisconnectOnClosedReadStream:(BOOL)flag; + +/** + * By default, both IPv4 and IPv6 are enabled. + * + * For accepting incoming connections, this means GCDAsyncSocket automatically supports both protocols, + * and can simulataneously accept incoming connections on either protocol. + * + * For outgoing connections, this means GCDAsyncSocket can connect to remote hosts running either protocol. + * If a DNS lookup returns only IPv4 results, GCDAsyncSocket will automatically use IPv4. + * If a DNS lookup returns only IPv6 results, GCDAsyncSocket will automatically use IPv6. + * If a DNS lookup returns both IPv4 and IPv6 results, the preferred protocol will be chosen. + * By default, the preferred protocol is IPv4, but may be configured as desired. +**/ +- (BOOL)isIPv4Enabled; +- (void)setIPv4Enabled:(BOOL)flag; + +- (BOOL)isIPv6Enabled; +- (void)setIPv6Enabled:(BOOL)flag; + +- (BOOL)isIPv4PreferredOverIPv6; +- (void)setPreferIPv4OverIPv6:(BOOL)flag; + +/** + * User data allows you to associate arbitrary information with the socket. + * This data is not used internally by socket in any way. +**/ +- (id)userData; +- (void)setUserData:(id)arbitraryUserData; + +#pragma mark Accepting + +/** + * Tells the socket to begin listening and accepting connections on the given port. + * When a connection is accepted, a new instance of GCDAsyncSocket will be spawned to handle it, + * and the socket:didAcceptNewSocket: delegate method will be invoked. + * + * The socket will listen on all available interfaces (e.g. wifi, ethernet, etc) +**/ +- (BOOL)acceptOnPort:(uint16_t)port error:(NSError **)errPtr; + +/** + * This method is the same as acceptOnPort:error: with the + * additional option of specifying which interface to listen on. + * + * For example, you could specify that the socket should only accept connections over ethernet, + * and not other interfaces such as wifi. + * + * The interface may be specified by name (e.g. "en1" or "lo0") or by IP address (e.g. "192.168.4.34"). + * You may also use the special strings "localhost" or "loopback" to specify that + * the socket only accept connections from the local machine. + * + * You can see the list of interfaces via the command line utility "ifconfig", + * or programmatically via the getifaddrs() function. + * + * To accept connections on any interface pass nil, or simply use the acceptOnPort:error: method. +**/ +- (BOOL)acceptOnInterface:(NSString *)interface port:(uint16_t)port error:(NSError **)errPtr; + +#pragma mark Connecting + +/** + * Connects to the given host and port. + * + * This method invokes connectToHost:onPort:viaInterface:withTimeout:error: + * and uses the default interface, and no timeout. +**/ +- (BOOL)connectToHost:(NSString *)host onPort:(uint16_t)port error:(NSError **)errPtr; + +/** + * Connects to the given host and port with an optional timeout. + * + * This method invokes connectToHost:onPort:viaInterface:withTimeout:error: and uses the default interface. +**/ +- (BOOL)connectToHost:(NSString *)host + onPort:(uint16_t)port + withTimeout:(NSTimeInterval)timeout + error:(NSError **)errPtr; + +/** + * Connects to the given host & port, via the optional interface, with an optional timeout. + * + * The host may be a domain name (e.g. "deusty.com") or an IP address string (e.g. "192.168.0.2"). + * The host may also be the special strings "localhost" or "loopback" to specify connecting + * to a service on the local machine. + * + * The interface may be a name (e.g. "en1" or "lo0") or the corresponding IP address (e.g. "192.168.4.35"). + * The interface may also be used to specify the local port (see below). + * + * To not time out use a negative time interval. + * + * This method will return NO if an error is detected, and set the error pointer (if one was given). + * Possible errors would be a nil host, invalid interface, or socket is already connected. + * + * If no errors are detected, this method will start a background connect operation and immediately return YES. + * The delegate callbacks are used to notify you when the socket connects, or if the host was unreachable. + * + * Since this class supports queued reads and writes, you can immediately start reading and/or writing. + * All read/write operations will be queued, and upon socket connection, + * the operations will be dequeued and processed in order. + * + * The interface may optionally contain a port number at the end of the string, separated by a colon. + * This allows you to specify the local port that should be used for the outgoing connection. (read paragraph to end) + * To specify both interface and local port: "en1:8082" or "192.168.4.35:2424". + * To specify only local port: ":8082". + * Please note this is an advanced feature, and is somewhat hidden on purpose. + * You should understand that 99.999% of the time you should NOT specify the local port for an outgoing connection. + * If you think you need to, there is a very good chance you have a fundamental misunderstanding somewhere. + * Local ports do NOT need to match remote ports. In fact, they almost never do. + * This feature is here for networking professionals using very advanced techniques. +**/ +- (BOOL)connectToHost:(NSString *)host + onPort:(uint16_t)port + viaInterface:(NSString *)interface + 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]; + * + * This method invokes connectToAdd +**/ +- (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; + +/** + * Connects to the given address, using the specified interface and timeout. + * + * The address is 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]; + * + * The interface may be a name (e.g. "en1" or "lo0") or the corresponding IP address (e.g. "192.168.4.35"). + * The interface may also be used to specify the local port (see below). + * + * The timeout is optional. To not time out use a negative time interval. + * + * This method will return NO if an error is detected, and set the error pointer (if one was given). + * Possible errors would be a nil host, invalid interface, or socket is already connected. + * + * If no errors are detected, this method will start a background connect operation and immediately return YES. + * The delegate callbacks are used to notify you when the socket connects, or if the host was unreachable. + * + * Since this class supports queued reads and writes, you can immediately start reading and/or writing. + * All read/write operations will be queued, and upon socket connection, + * the operations will be dequeued and processed in order. + * + * The interface may optionally contain a port number at the end of the string, separated by a colon. + * This allows you to specify the local port that should be used for the outgoing connection. (read paragraph to end) + * To specify both interface and local port: "en1:8082" or "192.168.4.35:2424". + * To specify only local port: ":8082". + * Please note this is an advanced feature, and is somewhat hidden on purpose. + * You should understand that 99.999% of the time you should NOT specify the local port for an outgoing connection. + * If you think you need to, there is a very good chance you have a fundamental misunderstanding somewhere. + * Local ports do NOT need to match remote ports. In fact, they almost never do. + * This feature is here for networking professionals using very advanced techniques. +**/ +- (BOOL)connectToAddress:(NSData *)remoteAddr + viaInterface:(NSString *)interface + withTimeout:(NSTimeInterval)timeout + error:(NSError **)errPtr; + +#pragma mark Disconnecting + +/** + * Disconnects immediately (synchronously). Any pending reads or writes are dropped. + * + * If the socket is not already disconnected, an invocation to the socketDidDisconnect:withError: delegate method + * will be queued onto the delegateQueue asynchronously (behind any previously queued delegate methods). + * In other words, the disconnected delegate method will be invoked sometime shortly after this method returns. + * + * Please note the recommended way of releasing a GCDAsyncSocket instance (e.g. in a dealloc method) + * [asyncSocket setDelegate:nil]; + * [asyncSocket disconnect]; + * [asyncSocket release]; + * + * If you plan on disconnecting the socket, and then immediately asking it to connect again, + * you'll likely want to do so like this: + * [asyncSocket setDelegate:nil]; + * [asyncSocket disconnect]; + * [asyncSocket setDelegate:self]; + * [asyncSocket connect...]; +**/ +- (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; + +#pragma mark Diagnostics + +/** + * Returns whether the socket is disconnected or connected. + * + * A disconnected socket may be recycled. + * That is, it can used again for connecting or listening. + * + * If a socket is in the process of connecting, it may be neither disconnected nor connected. +**/ +- (BOOL)isDisconnected; +- (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_t)connectedPort; + +- (NSString *)localHost; +- (uint16_t)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; + +/** + * Returns whether or not the socket has been secured via SSL/TLS. + * + * See also the startTLS method. +**/ +- (BOOL)isSecure; + +#pragma mark Reading + +// The readData and writeData methods won't block (they are asynchronous). +// +// When a read is complete the socket:didReadData:withTag: delegate method is dispatched on the delegateQueue. +// When a write is complete the socket:didWriteDataWithTag: delegate method is dispatched on the delegateQueue. +// +// 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 "socket:shouldTimeout..." delegate method +// is called to optionally allow you to extend the timeout. +// Upon a timeout, the "socket:didDisconnectWithError:" method is called +// +// 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 the socket is using it. + * After completion, the data returned in socket:didReadData:withTag: will be a subset of the given buffer. + * That is, it will reference the bytes that were appended to the given buffer via + * the method [NSData dataWithBytesNoCopy:length:freeWhenDone:NO]. +**/ +- (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 the socket is using it. + * After completion, the data returned in socket:didReadData:withTag: will be a subset of the given buffer. + * That is, it will reference the bytes that were appended to the given buffer via + * the method [NSData dataWithBytesNoCopy:length:freeWhenDone:NO]. +**/ +- (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 socket:didReadData:withTag: will be a subset of the given buffer. + * That is, it will reference the bytes that were appended to the given buffer via + * the method [NSData dataWithBytesNoCopy:length:freeWhenDone:NO]. +**/ +- (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 (except maybe print a warning), 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. + * If you're developing your own custom protocol, be sure your separator can not occur naturally as + * part of the data between separators. + * For example, imagine you want to send several small documents over a socket. + * Using CRLF as a separator is likely unwise, as a CRLF could easily exist within the documents. + * In this particular example, it would be better to use a protocol similar to HTTP with + * a header that includes the length of the document. + * Also be careful that your separator cannot occur naturally as part of the encoding for a character. + * + * The given data (separator) parameter should be immutable. + * For performance reasons, the socket will retain it, not copy it. + * So if it is immutable, don't modify it while the socket is using it. +**/ +- (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 (except maybe print a warning), and the delegate will not be called. + * + * If you pass a buffer, you must not alter it in any way while the socket is using it. + * After completion, the data returned in socket:didReadData:withTag: will be a subset of the given buffer. + * That is, it will reference the bytes that were appended to the given buffer via + * the method [NSData dataWithBytesNoCopy:length:freeWhenDone:NO]. + * + * To read a line from the socket, use the line separator (e.g. CRLF for HTTP, see below) as the "data" parameter. + * If you're developing your own custom protocol, be sure your separator can not occur naturally as + * part of the data between separators. + * For example, imagine you want to send several small documents over a socket. + * Using CRLF as a separator is likely unwise, as a CRLF could easily exist within the documents. + * In this particular example, it would be better to use a protocol similar to HTTP with + * a header that includes the length of the document. + * Also be careful that your separator cannot occur naturally as part of the encoding for a character. + * + * The given data (separator) parameter should be immutable. + * For performance reasons, the socket will retain it, not copy it. + * So if it is immutable, don't modify it while the socket is using it. +**/ +- (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 GCDAsyncSocketReadMaxedOutError. + * 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 (except maybe print a warning), 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 (except maybe print a warning), 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. + * If you're developing your own custom protocol, be sure your separator can not occur naturally as + * part of the data between separators. + * For example, imagine you want to send several small documents over a socket. + * Using CRLF as a separator is likely unwise, as a CRLF could easily exist within the documents. + * In this particular example, it would be better to use a protocol similar to HTTP with + * a header that includes the length of the document. + * Also be careful that your separator cannot occur naturally as part of the encoding for a character. + * + * The given data (separator) parameter should be immutable. + * For performance reasons, the socket will retain it, not copy it. + * So if it is immutable, don't modify it while the socket is using it. +**/ +- (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. + * + * 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 GCDAsyncSocketReadMaxedOutError. + * 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 (separator) parameter, + * the method will do nothing (except maybe print a warning), and the delegate will not be called. + * If the bufferOffset is greater than the length of the given buffer, + * the method will do nothing (except maybe print a warning), and the delegate will not be called. + * + * If you pass a buffer, you must not alter it in any way while the socket is using it. + * After completion, the data returned in socket:didReadData:withTag: will be a subset of the given buffer. + * That is, it will reference the bytes that were appended to the given buffer via + * the method [NSData dataWithBytesNoCopy:length:freeWhenDone:NO]. + * + * To read a line from the socket, use the line separator (e.g. CRLF for HTTP, see below) as the "data" parameter. + * If you're developing your own custom protocol, be sure your separator can not occur naturally as + * part of the data between separators. + * For example, imagine you want to send several small documents over a socket. + * Using CRLF as a separator is likely unwise, as a CRLF could easily exist within the documents. + * In this particular example, it would be better to use a protocol similar to HTTP with + * a header that includes the length of the document. + * Also be careful that your separator cannot occur naturally as part of the encoding for a character. + * + * The given data (separator) parameter should be immutable. + * For performance reasons, the socket will retain it, not copy it. + * So if it is immutable, don't modify it while the socket is using it. +**/ +- (void)readDataToData:(NSData *)data + withTimeout:(NSTimeInterval)timeout + buffer:(NSMutableData *)buffer + bufferOffset:(NSUInteger)offset + maxLength:(NSUInteger)length + tag:(long)tag; + +#pragma mark Writing + +/** + * 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. + * + * Thread-Safety Note: + * If the given data parameter is mutable (NSMutableData) then you MUST NOT alter the data while + * the socket is writing it. In other words, it's not safe to alter the data until after the delegate method + * socket:didWriteDataWithTag: is invoked signifying that this particular write operation has completed. + * This is due to the fact that GCDAsyncSocket does NOT copy the data. It simply retains it. + * This is for performance reasons. Often times, if NSMutableData is passed, it is because + * a request/response was built up in memory. Copying this data adds an unwanted/unneeded overhead. + * If you need to write data from an immutable buffer, and you need to alter the buffer before the socket + * completes writing the bytes (which is NOT immediately after this method returns, but rather at a later time + * when the delegate method notifies you), then you should first copy the bytes, and pass the copy to this method. +**/ +- (void)writeData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag; + +#pragma mark Security + +/** + * 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; + +#pragma mark Advanced + +/** + * It's not thread-safe to access certain variables from outside the socket's internal queue. + * + * For example, the socket file descriptor. + * File descriptors are simply integers which reference an index in the per-process file table. + * However, when one requests a new file descriptor (by opening a file or socket), + * the file descriptor returned is guaranteed to be the lowest numbered unused descriptor. + * So if we're not careful, the following could be possible: + * + * - Thread A invokes a method which returns the socket's file descriptor. + * - The socket is closed via the socket's internal queue on thread B. + * - Thread C opens a file, and subsequently receives the file descriptor that was previously the socket's FD. + * - Thread A is now accessing/altering the file instead of the socket. + * + * In addition to this, other variables are not actually objects, + * and thus cannot be retained/released or even autoreleased. + * An example is the sslContext, of type SSLContextRef, which is actually a malloc'd struct. + * + * Although there are internal variables that make it difficult to maintain thread-safety, + * it is important to provide access to these variables + * to ensure this class can be used in a wide array of environments. + * This method helps to accomplish this by invoking the current block on the socket's internal queue. + * The methods below can be invoked from within the block to access + * those generally thread-unsafe internal variables in a thread-safe manner. + * The given block will be invoked synchronously on the socket's internal queue. + * + * If you save references to any protected variables and use them outside the block, you do so at your own peril. +**/ +- (void)performBlock:(dispatch_block_t)block; + +/** + * These methods are only available from within the context of a performBlock: invocation. + * See the documentation for the performBlock: method above. + * + * Provides access to the socket's file descriptor(s). + * If the socket is a server socket (is accepting incoming connections), + * it might actually have multiple internal socket file descriptors - one for IPv4 and one for IPv6. +**/ +- (int)socketFD; +- (int)socket4FD; +- (int)socket6FD; + +#if TARGET_OS_IPHONE + +/** + * These methods are only available from within the context of a performBlock: invocation. + * See the documentation for the performBlock: method above. + * + * Provides access to the socket's internal CFReadStream/CFWriteStream. + * + * These streams are only used as workarounds for specific iOS shortcomings: + * + * - Apple has decided to keep the SecureTransport framework private is iOS. + * This means the only supplied way to do SSL/TLS is via CFStream or some other API layered on top of it. + * Thus, in order to provide SSL/TLS support on iOS we are forced to rely on CFStream, + * instead of the preferred and faster and more powerful SecureTransport. + * + * - If a socket doesn't have backgrounding enabled, and that socket is closed while the app is backgrounded, + * Apple only bothers to notify us via the CFStream API. + * The faster and more powerful GCD API isn't notified properly in this case. + * + * See also: (BOOL)enableBackgroundingOnSocket +**/ +- (CFReadStreamRef)readStream; +- (CFWriteStreamRef)writeStream; + +/** + * This method is only available from within the context of a performBlock: invocation. + * See the documentation for the performBlock: method above. + * + * Configures the socket to allow it to operate when the iOS application has been backgrounded. + * In other words, this method creates a read & write stream, and invokes: + * + * CFReadStreamSetProperty(readStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP); + * CFWriteStreamSetProperty(writeStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP); + * + * Returns YES if successful, NO otherwise. + * + * Note: Apple does not officially support backgrounding server sockets. + * That is, if your socket is accepting incoming connections, Apple does not officially support + * allowing iOS applications to accept incoming connections while an app is backgrounded. + * + * Example usage: + * + * - (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port + * { + * [asyncSocket performBlock:^{ + * [asyncSocket enableBackgroundingOnSocket]; + * }]; + * } +**/ +- (BOOL)enableBackgroundingOnSocket; + +#else + +/** + * This method is only available from within the context of a performBlock: invocation. + * See the documentation for the performBlock: method above. + * + * Provides access to the socket's SSLContext, if SSL/TLS has been started on the socket. +**/ +- (SSLContextRef)sslContext; + +#endif + +#pragma mark Utilities + +/** + * Extracting host and port information from raw address data. +**/ ++ (NSString *)hostFromAddress:(NSData *)address; ++ (uint16_t)portFromAddress:(NSData *)address; ++ (BOOL)getHost:(NSString **)hostPtr port:(uint16_t *)portPtr fromAddress:(NSData *)address; + +/** + * A few common line separators, for use with the readDataToData:... methods. +**/ ++ (NSData *)CRLFData; // 0x0D0A ++ (NSData *)CRData; // 0x0D ++ (NSData *)LFData; // 0x0A ++ (NSData *)ZeroData; // 0x00 + +@end + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +@protocol GCDAsyncSocketDelegate +@optional + +/** + * This method is called immediately prior to socket:didAcceptNewSocket:. + * It optionally allows a listening socket to specify the socketQueue for a new accepted socket. + * If this method is not implemented, or returns NULL, the new accepted socket will create its own default queue. + * + * Since you cannot autorelease a dispatch_queue, + * this method uses the "new" prefix in its name to specify that the returned queue has been retained. + * + * Thus you could do something like this in the implementation: + * return dispatch_queue_create("MyQueue", NULL); + * + * If you are placing multiple sockets on the same queue, + * then care should be taken to increment the retain count each time this method is invoked. + * + * For example, your implementation might look something like this: + * dispatch_retain(myExistingQueue); + * return myExistingQueue; +**/ +- (dispatch_queue_t)newSocketQueueForConnectionFromAddress:(NSData *)address onSocket:(GCDAsyncSocket *)sock; + +/** + * Called when a socket accepts a connection. + * Another socket is automatically spawned to handle it. + * + * You must retain the newSocket if you wish to handle the connection. + * Otherwise the newSocket instance will be released and the spawned connection will be closed. + * + * By default the new socket will have the same delegate and delegateQueue. + * You may, of course, change this at any time. +**/ +- (void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket; + +/** + * 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)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port; + +/** + * Called when a socket has completed reading the requested data into memory. + * Not called if there is an error. +**/ +- (void)socket:(GCDAsyncSocket *)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)socket:(GCDAsyncSocket *)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)socket:(GCDAsyncSocket *)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)socket:(GCDAsyncSocket *)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)socket:(GCDAsyncSocket *)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)socket:(GCDAsyncSocket *)sock shouldTimeoutWriteWithTag:(long)tag + elapsed:(NSTimeInterval)elapsed + bytesDone:(NSUInteger)length; + +/** + * Conditionally called if the read stream closes, but the write stream may still be writeable. + * + * This delegate method is only called if autoDisconnectOnClosedReadStream has been set to NO. + * See the discussion on the autoDisconnectOnClosedReadStream method for more information. +**/ +- (void)socketDidCloseReadStream:(GCDAsyncSocket *)sock; + +/** + * Called when a socket disconnects with or without error. + * + * 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)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err; + +/** + * 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 socketDidDisconnect:withError: delegate method will be called with the specific SSL error code. +**/ +- (void)socketDidSecure:(GCDAsyncSocket *)sock; + +@end diff --git a/Vendor/UnittWebSocketClient/include/HandshakeHeader.h b/Vendor/UnittWebSocketClient/include/HandshakeHeader.h new file mode 100644 index 0000000..32cf78b --- /dev/null +++ b/Vendor/UnittWebSocketClient/include/HandshakeHeader.h @@ -0,0 +1,38 @@ +// +// HandshakeHeader.h +// UnittWebSocketClient +// +// Created by Josh Morris on 10/2/11. +// Copyright 2011 UnitT Software. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +// + +#import <Foundation/Foundation.h> + +@interface HandshakeHeader : NSObject +{ + NSString* key; + NSString* value; +} + +@property (copy) NSString* key; +@property (copy) NSString* value; + ++ (id) header; ++ (id) headerWithValue:(NSString*) aValue forKey:(NSString*) aKey; +- (id) initWithValue:(NSString*) aValue forKey:(NSString*) aKey; + +- (BOOL) keyMatchesCaseInsensitiveString:(NSString*) aStringToCompare; + +@end diff --git a/Vendor/UnittWebSocketClient/include/MutableQueue.h b/Vendor/UnittWebSocketClient/include/MutableQueue.h new file mode 100644 index 0000000..3ad7313 --- /dev/null +++ b/Vendor/UnittWebSocketClient/include/MutableQueue.h @@ -0,0 +1,35 @@ +// +// NSMutableArray+QueueAddition.h +// UnittWebSocketClient +// +// Created by Josh Morris on 6/16/11. +// Copyright 2011 UnitT Software. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +// + +#import <Foundation/Foundation.h> + + +@interface MutableQueue : NSObject +{ + NSMutableArray* items; +} + +- (NSUInteger) count; +- (id) dequeue; +- (void) enqueue:(id) aObject; +- (id) lastObject; +- (void) removeLastObject; + +@end diff --git a/Vendor/UnittWebSocketClient/include/NSData+Base64.h b/Vendor/UnittWebSocketClient/include/NSData+Base64.h new file mode 100644 index 0000000..118c4e1 --- /dev/null +++ b/Vendor/UnittWebSocketClient/include/NSData+Base64.h @@ -0,0 +1,42 @@ +// +// NSData+Base64.h +// base64 +// +// Created by Matt Gallagher on 2009/06/03. +// Copyright 2009 Matt Gallagher. All rights reserved. +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. Permission is granted to anyone to +// use this software for any purpose, including commercial applications, and to +// alter it and redistribute it freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. +// + +#import <Foundation/Foundation.h> + +void *NewBase64Decode( + const char *inputBuffer, + size_t length, + size_t *outputLength); + +char *NewBase64Encode( + const void *inputBuffer, + size_t length, + bool separateLines, + size_t *outputLength); + +@interface NSData (Base64) + ++ (NSData *)dataFromBase64String:(NSString *)aString; +- (NSString *)base64EncodedString; + +@end diff --git a/Vendor/UnittWebSocketClient/include/WebSocket.h b/Vendor/UnittWebSocketClient/include/WebSocket.h new file mode 100644 index 0000000..d23f14a --- /dev/null +++ b/Vendor/UnittWebSocketClient/include/WebSocket.h @@ -0,0 +1,202 @@ +// +// WebSocket.h +// UnittWebSocketClient +// +// Created by Josh Morris on 9/26/11. +// Copyright 2011 UnitT Software. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +// + + +#import <Foundation/Foundation.h> +#import "AsyncSocket.h" +#import "GCDAsyncSocket.h" +#import <Security/Security.h> +#import <CommonCrypto/CommonDigest.h> +#import <CommonCrypto/CommonCryptor.h> +#import "NSData+Base64.h" +#import "MutableQueue.h" +#import "WebSocketConnectConfig.h" + + +enum +{ + WebSocketCloseStatusNormal = 1000, //indicates a normal closure, meaning whatever purpose the + //connection was established for has been fulfilled + WebSocketCloseStatusEndpointGone = 1001, //indicates that an endpoint is "going away", such as a + //server going down, or a browser having navigated away from + //a page + WebSocketCloseStatusProtocolError = 1002, //indicates that an endpoint is terminating the connection + //due to a protocol error + WebSocketCloseStatusInvalidDataType = 1003, //indicates that an endpoint is terminating the connection + //because it has received a type of data it cannot accept + //(e.g. an endpoint that understands only text data MAY + //send this if it receives a binary message) + WebSocketCloseStatusLegacyMessageTooLarge = 1004, //indicates that an endpoint is terminating the connection + //because it has received a message that is too large (prior to rfc6455) + WebSocketCloseStatusNormalButMissingStatus = 1005, //designated for use in applications expecting a status code + //to indicate that no status code was actually present + WebSocketCloseStatusAbnormalButMissingStatus = 1006, //designated for use in applications expecting a status code + //to indicate that the connection was closed abnormally, e.g. + //without sending or receiving a Close control frame. + WebSocketCloseStatusInvalidData = 1007, //indicates that an endpoint is terminating the connection because it has + //received data that is invalid, ex: supposed be UTF-8 (such as in a text frame) + // that was in fact not valid UTF-8 + WebSocketCloseStatusViolatesPolicy = 1008, //indicates that an endpoint is terminating the connection because it has + // received a message that violates its policy. This is a generic status code + // that can be returned when there is no other more suitable status code + // or if there is a need to hide specific details about the policy. + WebSocketCloseStatusMessageTooLarge = 1009, //indicates that an endpoint is terminating the connection + //because it has received a message that is too large + WebSocketCloseStatusMissingExtensions = 1010, //indicates that an endpoint (client) is terminating the connection because + // it has expected the server to negotiate one or more extension, but the + // server didn't return them in the response message of the WebSocket handshake + WebSocketCloseStatusServerError = 1011, //indicates that a server is terminating the connection because it encountered an + // unexpected condition that prevented it from fulfilling the request + WebSocketCloseStatusTlsHandshakeError = 1015 //indicate that the connection was closed due to a failure to perform a TLS handshake +}; +typedef NSUInteger WebSocketCloseStatus; + +enum +{ + WebSocketReadyStateConnecting = 0, //The connection has not yet been established. + WebSocketReadyStateOpen = 1, //The WebSocket connection is established and communication is possible. + WebSocketReadyStateClosing = 2, //The connection is going through the closing handshake. + WebSocketReadyStateClosed = 3 //The connection has been closed or could not be opened +}; +typedef NSUInteger WebSocketReadyState; + + +@protocol WebSocketDelegate <NSObject> + +/** + * Called when the web socket connects and is ready for reading and writing. + **/ +- (void) didOpen; + +/** + * Called when the web socket closes. aError will be nil if it closes cleanly. + **/ +- (void) didClose:(NSUInteger) aStatusCode message:(NSString*) aMessage error:(NSError*) aError; + +/** + * Called when the web socket receives an error. Such an error can result in the + socket being closed. + **/ +- (void) didReceiveError:(NSError*) aError; + +/** + * Called when the web socket receives a message. + **/ +- (void) didReceiveTextMessage:(NSString*) aMessage; + +/** + * Called when the web socket receives a message. + **/ +- (void) didReceiveBinaryMessage:(NSData*) aMessage; + +@optional +/** + * Called when pong is sent... For keep-alive optimization. + **/ +- (void) didSendPong:(NSData*) aMessage; + +@end + + +@interface WebSocket : NSObject +{ +@protected + AsyncSocket* socket; + GCDAsyncSocket *gcdSocket; + NSError* closingError; + NSString* wsSecKey; + NSString* wsSecKeyHandshake; + MutableQueue* pendingFragments; + BOOL isClosing; + NSUInteger closeStatusCode; + NSString* closeMessage; + BOOL sendCloseInfoToListener; + NSMutableData* fragmentBuffer; +@private + id<WebSocketDelegate> delegate; + WebSocketReadyState readystate; + WebSocketConnectConfig* config; + dispatch_queue_t wsQueue; + dispatch_queue_t delegateQueue; + NSTimer* pingTimer; +} + + +/** + * Callback delegate for websocket events. + **/ +@property(nonatomic,retain) id<WebSocketDelegate> delegate; + +/** + * Config info for the websocket connection. + **/ +@property(nonatomic,retain) WebSocketConnectConfig* config; + +/** + * Represents the state of the connection. It can have the following values: + * - WebSocketReadyStateConnecting: The connection has not yet been established. + * - WebSocketReadyStateOpen: The WebSocket connection is established and communication is possible. + * - WebSocketReadyStateClosing: The connection is going through the closing handshake. + * - WebSocketReadyStateClosed: The connection has been closed or could not be opened. + **/ +@property(nonatomic,readonly) WebSocketReadyState readystate; + + ++ (id) webSocketWithConfig:(WebSocketConnectConfig*) aConfig delegate:(id<WebSocketDelegate>) aDelegate; +- (id) initWithConfig:(WebSocketConnectConfig*) aConfig delegate:(id<WebSocketDelegate>) aDelegate; ++ (id) webSocketWithConfig:(WebSocketConnectConfig*) aConfig queue:(dispatch_queue_t) aDispatchQueue delegate:(id<WebSocketDelegate>) aDelegate; +- (id) initWithConfig:(WebSocketConnectConfig*) aConfig queue:(dispatch_queue_t) aDispatchQueue delegate:(id<WebSocketDelegate>) aDelegate; + + +/** + * Connect the websocket and prepare it for reading and writing. + **/ +- (void) open; + +/** + * Finish all reads/writes and close the websocket. Sends a status of WebSocketCloseStatusNormal and no message. + **/ +- (void) close; + +/** + * Finish all reads/writes and close the websocket. Sends the specified status and message. + **/ +- (void) close:(NSUInteger) aStatusCode message:(NSString*) aMessage; + +/** + * Write a UTF-8 encoded NSString message to the websocket. + **/ +- (void) sendText:(NSString*)message; + +/** + * Write a binary message to the websocket. + **/ +- (void) sendBinary:(NSData*)message; + +/** + * Send ping message to the websocket + */ +- (void) sendPing:(NSData*)message; + + +extern NSString *const WebSocketException; +extern NSString *const WebSocketErrorDomain; + +@end diff --git a/Vendor/UnittWebSocketClient/include/WebSocket00.h b/Vendor/UnittWebSocketClient/include/WebSocket00.h new file mode 100644 index 0000000..a3ea68f --- /dev/null +++ b/Vendor/UnittWebSocketClient/include/WebSocket00.h @@ -0,0 +1,190 @@ +// +// WebSocket00.h +// UnittWebSocketClient +// +// Created by Josh Morris on 5/3/11. +// Copyright 2011 UnitT Software. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +// + +#import <Foundation/Foundation.h> +#import "AsyncSocket.h" +#import <Security/Security.h> +#import <CommonCrypto/CommonDigest.h> +#import <CommonCrypto/CommonCryptor.h> +#import "NSData+Base64.h" + + +enum +{ + WebSocketReadyStateConnecting = 0, //The connection has not yet been established. + WebSocketReadyStateOpen = 1, //The WebSocket connection is established and communication is possible. + WebSocketReadyStateClosing = 2, //The connection is going through the closing handshake. + WebSocketReadyStateClosed = 3 //The connection has been closed or could not be opened +}; +typedef NSUInteger WebSocketReadyState; + + +__attribute__((deprecated)) +@protocol WebSocket00Delegate <NSObject> + +/** + * Called when the web socket connects and is ready for reading and writing. + **/ +- (void) didOpen; + +/** + * Called when the web socket closes. aError will be nil if it closes cleanly. + **/ +- (void) didClose: (NSError*) aError; + +/** + * Called when the web socket receives an error. Such an error can result in the + socket being closed. + **/ +- (void) didReceiveError: (NSError*) aError; + +/** + * Called when the web socket receives a message. + **/ +- (void) didReceiveMessage: (NSString*) aMessage; + +@end + + +__attribute__((deprecated)) +@interface WebSocket00 : NSObject +{ +@private + id<WebSocket00Delegate> delegate; + NSURL* url; + NSString* origin; + AsyncSocket* socket; + WebSocketReadyState readystate; + NSError* closingError; + BOOL isSecure; + NSTimeInterval timeout; + NSDictionary* tlsSettings; + NSArray* protocols; + NSString* serverProtocol; + NSString* key1; + NSString* key2; + NSData* key3; + NSData* serverHandshake; + BOOL verifyHandshake; + BOOL useKeys; +} + + +/** + * Callback delegate for websocket events. + **/ +@property(nonatomic,retain) id<WebSocket00Delegate> delegate; + +/** + * Timeout used for sending messages, not establishing the socket connection. A + * value of -1 will result in no timeouts being applied. + **/ +@property(nonatomic,assign) NSTimeInterval timeout; + +/** + * URL of the websocket + **/ +@property(nonatomic,readonly) NSURL* url; + +/** + * True if you want to send the hixie76 keys. Default is false. + **/ +@property(nonatomic,readonly) BOOL useKeys; + +/** + * Origin is used more in a browser setting, but it is intended to prevent cross-site scripting. If + * nil, the client will fill this in using the url provided by the websocket. + **/ +@property(nonatomic,readonly) NSString* origin; + +/** + * Represents the state of the connection. It can have the following values: + * - WebSocketReadyStateConnecting: The connection has not yet been established. + * - WebSocketReadyStateOpen: The WebSocket connection is established and communication is possible. + * - WebSocketReadyStateClosing: The connection is going through the closing handshake. + * - WebSocketReadyStateClosed: The connection has been closed or could not be opened. + **/ +@property(nonatomic,readonly) WebSocketReadyState readystate; + + +/** + * Settings for securing the connection using SSL/TLS. + * + * 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 the value is nil or an empty dictionary, then the websocket cannot be secured. + **/ +@property(nonatomic,readonly) NSDictionary* tlsSettings; + +/** + * The subprotocols supported by the client. Each subprotocol is represented by an NSString. + **/ +@property(nonatomic,readonly) NSArray* protocols; + +/** + * True if the client should verify the handshake values sent by the server. Since many of + * the web socket servers may not have been updated to support this, set to false to ignore + * and simply accept the connection to the server. + **/ +@property(nonatomic,readonly) BOOL verifyHandshake; + +/** + * The subprotocol selected by the server, nil if none was selected + **/ +@property(nonatomic,readonly) NSString* serverProtocol; + + ++ (id) webSocketWithURLString:(NSString*) aUrlString delegate:(id<WebSocket00Delegate>) aDelegate origin:(NSString*) aOrigin protocols:(NSArray*) aProtocols tlsSettings:(NSDictionary*) aTlsSettings verifyHandshake:(BOOL) aVerifyHandshake; ++ (id) webSocketWithURLString:(NSString*) aUrlString delegate:(id<WebSocket00Delegate>) aDelegate origin:(NSString*) aOrigin protocols:(NSArray*) aProtocols tlsSettings:(NSDictionary*) aTlsSettings verifyHandshake:(BOOL) aVerifyHandshake useKeys:(BOOL) aUseKeys; +- (id) initWithURLString:(NSString *) aUrlString delegate:(id<WebSocket00Delegate>) aDelegate origin:(NSString*) aOrigin protocols:(NSArray*) aProtocols tlsSettings:(NSDictionary*) aTlsSettings verifyHandshake:(BOOL) aVerifyHandshake; +- (id) initWithURLString:(NSString *) aUrlString delegate:(id<WebSocket00Delegate>) aDelegate origin:(NSString*) aOrigin protocols:(NSArray*) aProtocols tlsSettings:(NSDictionary*) aTlsSettings verifyHandshake:(BOOL) aVerifyHandshake useKeys:(BOOL) aUseKeys; + + +/** + * Connect the websocket and prepare it for reading and writing. + **/ +- (void)open; + +/** + * Finish all reads/writes and close the websocket. + **/ +- (void)close; + +/** + * Write a UTF-8 encoded NSString message to the websocket. + **/ +- (void)send:(NSString*)message; + + +extern NSString *const WebSocket00Exception; +extern NSString *const WebSocket00ErrorDomain; + +@end diff --git a/Vendor/UnittWebSocketClient/include/WebSocket07.h b/Vendor/UnittWebSocketClient/include/WebSocket07.h new file mode 100644 index 0000000..54398ef --- /dev/null +++ b/Vendor/UnittWebSocketClient/include/WebSocket07.h @@ -0,0 +1,242 @@ +// +// WebSocket07.h +// UnittWebSocketClient +// +// Created by Josh Morris on 5/3/11. +// Copyright 2011 UnitT Software. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +// + +#import <Foundation/Foundation.h> +#import "AsyncSocket.h" +#import <Security/Security.h> +#import <CommonCrypto/CommonDigest.h> +#import <CommonCrypto/CommonCryptor.h> +#import "NSData+Base64.h" +#import "MutableQueue.h" + + +enum +{ + WebSocketCloseStatusNormal = 1000, //indicates a normal closure, meaning whatever purpose the + //connection was established for has been fulfilled + WebSocketCloseStatusEndpointGone = 1001, //indicates that an endpoint is "going away", such as a + //server going down, or a browser having navigated away from + //a page + WebSocketCloseStatusProtocolError = 1002, //indicates that an endpoint is terminating the connection + //due to a protocol error + WebSocketCloseStatusInvalidDataType = 1003, //indicates that an endpoint is terminating the connection + //because it has received a type of data it cannot accept + //(e.g. an endpoint that understands only text data MAY + //send this if it receives a binary message) + WebSocketCloseStatusMessageTooLarge = 1004 //indicates that an endpoint is terminating the connection + //because it has received a message that is too large +}; +typedef NSUInteger WebSocketCloseStatus; + +enum +{ + WebSocketReadyStateConnecting = 0, //The connection has not yet been established. + WebSocketReadyStateOpen = 1, //The WebSocket connection is established and communication is possible. + WebSocketReadyStateClosing = 2, //The connection is going through the closing handshake. + WebSocketReadyStateClosed = 3 //The connection has been closed or could not be opened +}; +typedef NSUInteger WebSocketReadyState; + + +__attribute__((deprecated)) +@protocol WebSocket07Delegate <NSObject> + +/** + * Called when the web socket connects and is ready for reading and writing. + **/ +- (void) didOpen; + +/** + * Called when the web socket closes. aError will be nil if it closes cleanly. + **/ +- (void) didClose:(NSUInteger) aStatusCode message:(NSString*) aMessage error:(NSError*) aError; + +/** + * Called when the web socket receives an error. Such an error can result in the + socket being closed. + **/ +- (void) didReceiveError:(NSError*) aError; + +/** + * Called when the web socket receives a message. + **/ +- (void) didReceiveTextMessage:(NSString*) aMessage; + +/** + * Called when the web socket receives a message. + **/ +- (void) didReceiveBinaryMessage:(NSData*) aMessage; + +@optional +/** + * Called when pong is sent... For keep-alive optimization. + **/ +- (void) didSendPong:(NSData*) aMessage; + +@end + + +__attribute__((deprecated)) +@interface WebSocket07 : NSObject +{ +@private + id<WebSocket07Delegate> delegate; + NSURL* url; + NSString* origin; + AsyncSocket* socket; + WebSocketReadyState readystate; + NSError* closingError; + BOOL isSecure; + NSTimeInterval timeout; + NSDictionary* tlsSettings; + NSArray* protocols; + NSString* serverProtocol; + NSString* wsSecKey; + NSString* wsSecKeyHandshake; + BOOL verifyHandshake; + NSUInteger maxPayloadSize; + MutableQueue* pendingFragments; + BOOL isClosing; + NSUInteger closeStatusCode; + NSString* closeMessage; + BOOL sendCloseInfoToListener; + NSTimeInterval closeTimeout; +} + + +/** + * Callback delegate for websocket events. + **/ +@property(nonatomic,retain) id<WebSocket07Delegate> delegate; + +/** + * Max size of the payload. Any messages larger will be sent as fragments. + **/ +@property(nonatomic,assign) NSUInteger maxPayloadSize; + +/** + * Timeout used for sending messages, not establishing the socket connection. A + * value of -1 will result in no timeouts being applied. + **/ +@property(nonatomic,assign) NSTimeInterval timeout; + +/** + * Timeout used for the closing handshake. If this timeout is exceeded, the socket + * will be forced closed. A value of -1 will result in no timeouts being applied. + **/ +@property(nonatomic,assign) NSTimeInterval closeTimeout; + +/** + * URL of the websocket + **/ +@property(nonatomic,readonly) NSURL* url; + +/** + * Origin is used more in a browser setting, but it is intended to prevent cross-site scripting. If + * nil, the client will fill this in using the url provided by the websocket. + **/ +@property(nonatomic,readonly) NSString* origin; + +/** + * Represents the state of the connection. It can have the following values: + * - WebSocketReadyStateConnecting: The connection has not yet been established. + * - WebSocketReadyStateOpen: The WebSocket connection is established and communication is possible. + * - WebSocketReadyStateClosing: The connection is going through the closing handshake. + * - WebSocketReadyStateClosed: The connection has been closed or could not be opened. + **/ +@property(nonatomic,readonly) WebSocketReadyState readystate; + + +/** + * Settings for securing the connection using SSL/TLS. + * + * 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 the value is nil or an empty dictionary, then the websocket cannot be secured. + **/ +@property(nonatomic,readonly) NSDictionary* tlsSettings; + +/** + * The subprotocols supported by the client. Each subprotocol is represented by an NSString. + **/ +@property(nonatomic,readonly) NSArray* protocols; + +/** + * True if the client should verify the handshake values sent by the server. Since many of + * the web socket servers may not have been updated to support this, set to false to ignore + * and simply accept the connection to the server. + **/ +@property(nonatomic,readonly) BOOL verifyHandshake; + +/** + * The subprotocol selected by the server, nil if none was selected + **/ +@property(nonatomic,readonly) NSString* serverProtocol; + + ++ (id) webSocketWithURLString:(NSString*) aUrlString delegate:(id<WebSocket07Delegate>) aDelegate origin:(NSString*) aOrigin protocols:(NSArray*) aProtocols tlsSettings:(NSDictionary*) aTlsSettings verifyHandshake:(BOOL) aVerifyHandshake; +- (id) initWithURLString:(NSString *) aUrlString delegate:(id<WebSocket07Delegate>) aDelegate origin:(NSString*) aOrigin protocols:(NSArray*) aProtocols tlsSettings:(NSDictionary*) aTlsSettings verifyHandshake:(BOOL) aVerifyHandshake; + + +/** + * Connect the websocket and prepare it for reading and writing. + **/ +- (void) open; + +/** + * Finish all reads/writes and close the websocket. Sends a status of WebSocketCloseStatusNormal and no message. + **/ +- (void) close; + +/** + * Finish all reads/writes and close the websocket. Sends the specified status and message. + **/ +- (void) close:(NSUInteger) aStatusCode message:(NSString*) aMessage; + +/** + * Write a UTF-8 encoded NSString message to the websocket. + **/ +- (void) sendText:(NSString*)message; + +/** + * Write a binary message to the websocket. + **/ +- (void) sendBinary:(NSData*)message; + +/** + * Send ping message to the websocket + */ +- (void) sendPing:(NSData*)message; + +extern NSString *const WebSocket07Exception; +extern NSString *const WebSocket07ErrorDomain; + +@end diff --git a/Vendor/UnittWebSocketClient/include/WebSocket08.h b/Vendor/UnittWebSocketClient/include/WebSocket08.h new file mode 100644 index 0000000..535bb05 --- /dev/null +++ b/Vendor/UnittWebSocketClient/include/WebSocket08.h @@ -0,0 +1,247 @@ +// +// WebSocket08.h +// UnittWebSocketClient +// +// Created by Josh Morris on 5/3/11. +// Copyright 2011 UnitT Software. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +// + +#import <Foundation/Foundation.h> +#import "AsyncSocket.h" +#import <Security/Security.h> +#import <CommonCrypto/CommonDigest.h> +#import <CommonCrypto/CommonCryptor.h> +#import "NSData+Base64.h" +#import "MutableQueue.h" + + +enum +{ + WebSocketCloseStatusNormal = 1000, //indicates a normal closure, meaning whatever purpose the + //connection was established for has been fulfilled + WebSocketCloseStatusEndpointGone = 1001, //indicates that an endpoint is "going away", such as a + //server going down, or a browser having navigated away from + //a page + WebSocketCloseStatusProtocolError = 1002, //indicates that an endpoint is terminating the connection + //due to a protocol error + WebSocketCloseStatusInvalidDataType = 1003, //indicates that an endpoint is terminating the connection + //because it has received a type of data it cannot accept + //(e.g. an endpoint that understands only text data MAY + //send this if it receives a binary message) + WebSocketCloseStatusMessageTooLarge = 1004, //indicates that an endpoint is terminating the connection + //because it has received a message that is too large + WebSocketCloseStatusNormalButMissingStatus = 1005, //designated for use in applications expecting a status code + //to indicate that no status code was actually present + WebSocketCloseStatusAbnormalButMissingStatus = 1006 //designated for use in applications expecting a status code + //to indicate that the connection was closed abnormally, e.g. + //without sending or receiving a Close control frame. +}; +typedef NSUInteger WebSocketCloseStatus; + +enum +{ + WebSocketReadyStateConnecting = 0, //The connection has not yet been established. + WebSocketReadyStateOpen = 1, //The WebSocket connection is established and communication is possible. + WebSocketReadyStateClosing = 2, //The connection is going through the closing handshake. + WebSocketReadyStateClosed = 3 //The connection has been closed or could not be opened +}; +typedef NSUInteger WebSocketReadyState; + + +__attribute__((deprecated)) +@protocol WebSocket08Delegate <NSObject> + +/** + * Called when the web socket connects and is ready for reading and writing. + **/ +- (void) didOpen; + +/** + * Called when the web socket closes. aError will be nil if it closes cleanly. + **/ +- (void) didClose:(NSUInteger) aStatusCode message:(NSString*) aMessage error:(NSError*) aError; + +/** + * Called when the web socket receives an error. Such an error can result in the + socket being closed. + **/ +- (void) didReceiveError:(NSError*) aError; + +/** + * Called when the web socket receives a message. + **/ +- (void) didReceiveTextMessage:(NSString*) aMessage; + +/** + * Called when the web socket receives a message. + **/ +- (void) didReceiveBinaryMessage:(NSData*) aMessage; + +@optional +/** + * Called when pong is sent... For keep-alive optimization. + **/ +- (void) didSendPong:(NSData*) aMessage; + +@end + + +__attribute__((deprecated)) +@interface WebSocket08 : NSObject +{ +@private + id<WebSocket08Delegate> delegate; + NSURL* url; + NSString* origin; + AsyncSocket* socket; + WebSocketReadyState readystate; + NSError* closingError; + BOOL isSecure; + NSTimeInterval timeout; + NSDictionary* tlsSettings; + NSArray* protocols; + NSString* serverProtocol; + NSString* wsSecKey; + NSString* wsSecKeyHandshake; + BOOL verifyHandshake; + NSUInteger maxPayloadSize; + MutableQueue* pendingFragments; + BOOL isClosing; + NSUInteger closeStatusCode; + NSString* closeMessage; + BOOL sendCloseInfoToListener; + NSTimeInterval closeTimeout; +} + + +/** + * Callback delegate for websocket events. + **/ +@property(nonatomic,retain) id<WebSocket08Delegate> delegate; + +/** + * Max size of the payload. Any messages larger will be sent as fragments. + **/ +@property(nonatomic,assign) NSUInteger maxPayloadSize; + +/** + * Timeout used for sending messages, not establishing the socket connection. A + * value of -1 will result in no timeouts being applied. + **/ +@property(nonatomic,assign) NSTimeInterval timeout; + +/** + * Timeout used for the closing handshake. If this timeout is exceeded, the socket + * will be forced closed. A value of -1 will result in no timeouts being applied. + **/ +@property(nonatomic,assign) NSTimeInterval closeTimeout; + +/** + * URL of the websocket + **/ +@property(nonatomic,readonly) NSURL* url; + +/** + * Origin is used more in a browser setting, but it is intended to prevent cross-site scripting. If + * nil, the client will fill this in using the url provided by the websocket. + **/ +@property(nonatomic,readonly) NSString* origin; + +/** + * Represents the state of the connection. It can have the following values: + * - WebSocketReadyStateConnecting: The connection has not yet been established. + * - WebSocketReadyStateOpen: The WebSocket connection is established and communication is possible. + * - WebSocketReadyStateClosing: The connection is going through the closing handshake. + * - WebSocketReadyStateClosed: The connection has been closed or could not be opened. + **/ +@property(nonatomic,readonly) WebSocketReadyState readystate; + + +/** + * Settings for securing the connection using SSL/TLS. + * + * 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 the value is nil or an empty dictionary, then the websocket cannot be secured. + **/ +@property(nonatomic,readonly) NSDictionary* tlsSettings; + +/** + * The subprotocols supported by the client. Each subprotocol is represented by an NSString. + **/ +@property(nonatomic,readonly) NSArray* protocols; + +/** + * True if the client should verify the handshake values sent by the server. Since many of + * the web socket servers may not have been updated to support this, set to false to ignore + * and simply accept the connection to the server. + **/ +@property(nonatomic,readonly) BOOL verifyHandshake; + +/** + * The subprotocol selected by the server, nil if none was selected + **/ +@property(nonatomic,readonly) NSString* serverProtocol; + + ++ (id) webSocketWithURLString:(NSString*) aUrlString delegate:(id<WebSocket08Delegate>) aDelegate origin:(NSString*) aOrigin protocols:(NSArray*) aProtocols tlsSettings:(NSDictionary*) aTlsSettings verifyHandshake:(BOOL) aVerifyHandshake; +- (id) initWithURLString:(NSString *) aUrlString delegate:(id<WebSocket08Delegate>) aDelegate origin:(NSString*) aOrigin protocols:(NSArray*) aProtocols tlsSettings:(NSDictionary*) aTlsSettings verifyHandshake:(BOOL) aVerifyHandshake; + + +/** + * Connect the websocket and prepare it for reading and writing. + **/ +- (void) open; + +/** + * Finish all reads/writes and close the websocket. Sends a status of WebSocketCloseStatusNormal and no message. + **/ +- (void) close; + +/** + * Finish all reads/writes and close the websocket. Sends the specified status and message. + **/ +- (void) close:(NSUInteger) aStatusCode message:(NSString*) aMessage; + +/** + * Write a UTF-8 encoded NSString message to the websocket. + **/ +- (void) sendText:(NSString*)message; + +/** + * Write a binary message to the websocket. + **/ +- (void) sendBinary:(NSData*)message; + +/** + * Send ping message to the websocket + */ +- (void) sendPing:(NSData*)message; + +extern NSString *const WebSocket08Exception; +extern NSString *const WebSocket08ErrorDomain; + +@end diff --git a/Vendor/UnittWebSocketClient/include/WebSocket10.h b/Vendor/UnittWebSocketClient/include/WebSocket10.h new file mode 100644 index 0000000..c821750 --- /dev/null +++ b/Vendor/UnittWebSocketClient/include/WebSocket10.h @@ -0,0 +1,250 @@ +// +// WebSocket10.h +// UnittWebSocketClient +// +// Created by Josh Morris on 5/3/11. +// Copyright 2011 UnitT Software. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +// + +#import <Foundation/Foundation.h> +#import "AsyncSocket.h" +#import <Security/Security.h> +#import <CommonCrypto/CommonDigest.h> +#import <CommonCrypto/CommonCryptor.h> +#import "NSData+Base64.h" +#import "MutableQueue.h" + + +enum +{ + WebSocketCloseStatusNormal = 1000, //indicates a normal closure, meaning whatever purpose the + //connection was established for has been fulfilled + WebSocketCloseStatusEndpointGone = 1001, //indicates that an endpoint is "going away", such as a + //server going down, or a browser having navigated away from + //a page + WebSocketCloseStatusProtocolError = 1002, //indicates that an endpoint is terminating the connection + //due to a protocol error + WebSocketCloseStatusInvalidDataType = 1003, //indicates that an endpoint is terminating the connection + //because it has received a type of data it cannot accept + //(e.g. an endpoint that understands only text data MAY + //send this if it receives a binary message) + WebSocketCloseStatusMessageTooLarge = 1004, //indicates that an endpoint is terminating the connection + //because it has received a message that is too large + WebSocketCloseStatusNormalButMissingStatus = 1005, //designated for use in applications expecting a status code + //to indicate that no status code was actually present + WebSocketCloseStatusAbnormalButMissingStatus = 1006, //designated for use in applications expecting a status code + //to indicate that the connection was closed abnormally, e.g. + //without sending or receiving a Close control frame. + WebSocketCloseStatusInvalidData = 1007 //indicates that an endpoint is terminating the connection because it has + //received data that was supposed to be UTF-8 (such as in a text frame) that + //was in fact not valid UTF-8 +}; +typedef NSUInteger WebSocketCloseStatus; + +enum +{ + WebSocketReadyStateConnecting = 0, //The connection has not yet been established. + WebSocketReadyStateOpen = 1, //The WebSocket connection is established and communication is possible. + WebSocketReadyStateClosing = 2, //The connection is going through the closing handshake. + WebSocketReadyStateClosed = 3 //The connection has been closed or could not be opened +}; +typedef NSUInteger WebSocketReadyState; + + +__attribute__((deprecated)) +@protocol WebSocket10Delegate <NSObject> + +/** + * Called when the web socket connects and is ready for reading and writing. + **/ +- (void) didOpen; + +/** + * Called when the web socket closes. aError will be nil if it closes cleanly. + **/ +- (void) didClose:(NSUInteger) aStatusCode message:(NSString*) aMessage error:(NSError*) aError; + +/** + * Called when the web socket receives an error. Such an error can result in the + socket being closed. + **/ +- (void) didReceiveError:(NSError*) aError; + +/** + * Called when the web socket receives a message. + **/ +- (void) didReceiveTextMessage:(NSString*) aMessage; + +/** + * Called when the web socket receives a message. + **/ +- (void) didReceiveBinaryMessage:(NSData*) aMessage; + +@optional +/** + * Called when pong is sent... For keep-alive optimization. + **/ +- (void) didSendPong:(NSData*) aMessage; + +@end + + +__attribute__((deprecated)) +@interface WebSocket10 : NSObject +{ +@private + id<WebSocket10Delegate> delegate; + NSURL* url; + NSString* origin; + AsyncSocket* socket; + WebSocketReadyState readystate; + NSError* closingError; + BOOL isSecure; + NSTimeInterval timeout; + NSDictionary* tlsSettings; + NSArray* protocols; + NSString* serverProtocol; + NSString* wsSecKey; + NSString* wsSecKeyHandshake; + BOOL verifyHandshake; + NSUInteger maxPayloadSize; + MutableQueue* pendingFragments; + BOOL isClosing; + NSUInteger closeStatusCode; + NSString* closeMessage; + BOOL sendCloseInfoToListener; + NSTimeInterval closeTimeout; +} + + +/** + * Callback delegate for websocket events. + **/ +@property(nonatomic,retain) id<WebSocket10Delegate> delegate; + +/** + * Max size of the payload. Any messages larger will be sent as fragments. + **/ +@property(nonatomic,assign) NSUInteger maxPayloadSize; + +/** + * Timeout used for sending messages, not establishing the socket connection. A + * value of -1 will result in no timeouts being applied. + **/ +@property(nonatomic,assign) NSTimeInterval timeout; + +/** + * Timeout used for the closing handshake. If this timeout is exceeded, the socket + * will be forced closed. A value of -1 will result in no timeouts being applied. + **/ +@property(nonatomic,assign) NSTimeInterval closeTimeout; + +/** + * URL of the websocket + **/ +@property(nonatomic,readonly) NSURL* url; + +/** + * Origin is used more in a browser setting, but it is intended to prevent cross-site scripting. If + * nil, the client will fill this in using the url provided by the websocket. + **/ +@property(nonatomic,readonly) NSString* origin; + +/** + * Represents the state of the connection. It can have the following values: + * - WebSocketReadyStateConnecting: The connection has not yet been established. + * - WebSocketReadyStateOpen: The WebSocket connection is established and communication is possible. + * - WebSocketReadyStateClosing: The connection is going through the closing handshake. + * - WebSocketReadyStateClosed: The connection has been closed or could not be opened. + **/ +@property(nonatomic,readonly) WebSocketReadyState readystate; + + +/** + * Settings for securing the connection using SSL/TLS. + * + * 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 the value is nil or an empty dictionary, then the websocket cannot be secured. + **/ +@property(nonatomic,readonly) NSDictionary* tlsSettings; + +/** + * The subprotocols supported by the client. Each subprotocol is represented by an NSString. + **/ +@property(nonatomic,readonly) NSArray* protocols; + +/** + * True if the client should verify the handshake values sent by the server. Since many of + * the web socket servers may not have been updated to support this, set to false to ignore + * and simply accept the connection to the server. + **/ +@property(nonatomic,readonly) BOOL verifyHandshake; + +/** + * The subprotocol selected by the server, nil if none was selected + **/ +@property(nonatomic,readonly) NSString* serverProtocol; + + ++ (id) webSocketWithURLString:(NSString*) aUrlString delegate:(id<WebSocket10Delegate>) aDelegate origin:(NSString*) aOrigin protocols:(NSArray*) aProtocols tlsSettings:(NSDictionary*) aTlsSettings verifyHandshake:(BOOL) aVerifyHandshake; +- (id) initWithURLString:(NSString *) aUrlString delegate:(id<WebSocket10Delegate>) aDelegate origin:(NSString*) aOrigin protocols:(NSArray*) aProtocols tlsSettings:(NSDictionary*) aTlsSettings verifyHandshake:(BOOL) aVerifyHandshake; + + +/** + * Connect the websocket and prepare it for reading and writing. + **/ +- (void) open; + +/** + * Finish all reads/writes and close the websocket. Sends a status of WebSocketCloseStatusNormal and no message. + **/ +- (void) close; + +/** + * Finish all reads/writes and close the websocket. Sends the specified status and message. + **/ +- (void) close:(NSUInteger) aStatusCode message:(NSString*) aMessage; + +/** + * Write a UTF-8 encoded NSString message to the websocket. + **/ +- (void) sendText:(NSString*)message; + +/** + * Write a binary message to the websocket. + **/ +- (void) sendBinary:(NSData*)message; + +/** + * Send ping message to the websocket + */ +- (void) sendPing:(NSData*)message; + +extern NSString *const WebSocket10Exception; +extern NSString *const WebSocket10ErrorDomain; + +@end diff --git a/Vendor/UnittWebSocketClient/include/WebSocketConnectConfig.h b/Vendor/UnittWebSocketClient/include/WebSocketConnectConfig.h new file mode 100644 index 0000000..b95d10a --- /dev/null +++ b/Vendor/UnittWebSocketClient/include/WebSocketConnectConfig.h @@ -0,0 +1,202 @@ +// +// WebSocketConnectConfig.h +// UnittWebSocketClient +// +// Created by Josh Morris on 9/26/11. +// Copyright 2011 UnitT Software. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +// + +#import <Foundation/Foundation.h> + + +enum +{ + WebSocketVersion07 = 7, + WebSocketVersion08 = 8, + WebSocketVersion10 = 10, + WebSocketVersionRFC6455 = 6455 +}; +typedef NSUInteger WebSocketVersion; + + +@interface WebSocketConnectConfig : NSObject +{ +@private + NSTimeInterval keepAlive; + NSURL* url; + NSString* origin; + NSString* host; + NSTimeInterval timeout; + NSMutableDictionary* tlsSettings; + NSMutableArray* protocols; + NSString* serverProtocol; + BOOL verifySecurityKey; + NSUInteger maxPayloadSize; + NSTimeInterval closeTimeout; + WebSocketVersion version; + BOOL isSecure; + NSMutableArray* headers; + NSMutableArray* serverHeaders; + NSMutableArray* extensions; + NSMutableArray* serverExtensions; + BOOL activeExtensionModifiesReservedBits; +} + +/** + * String name/value pairs to be provided in the websocket handshake as + * http headers. + **/ +@property(nonatomic,retain) NSMutableArray* headers; + +/** + * String name/value pairs provided by the server in the websocket handshake + * as http headers. + **/ +@property(nonatomic,retain) NSMutableArray* serverHeaders; + +/** + * Version of the websocket specification. + **/ +@property(nonatomic,assign) WebSocketVersion version; + +/** + * Max size of the payload. Any messages larger will be sent as fragments. + **/ +@property(nonatomic,assign) NSUInteger maxPayloadSize; + +/** + * Timeout used for sending messages, not establishing the socket connection. A + * value of -1 will result in no timeouts being applied. + **/ +@property(nonatomic,assign) NSTimeInterval timeout; + +/** + * Timeout used for the closing handshake. If this timeout is exceeded, the socket + * will be forced closed. A value of -1 will result in no timeouts being applied. + **/ +@property(nonatomic,assign) NSTimeInterval closeTimeout; + +/** + * URL of the websocket + **/ +@property(nonatomic,retain) NSURL* url; + +/** + * Indicates whether the websocket will be opened over a secure connection + **/ +@property(nonatomic,assign) BOOL isSecure; + +/** + * Indicates whether the websocket will try to reconnect using a different version if the specified + * one is not supported. + **/ +@property(nonatomic,assign) BOOL retryOtherVersion; + +/** + * Origin is used more in a browser setting, but it is intended to prevent cross-site scripting. If + * nil, the client will fill this in using the url provided by the websocket. + **/ +@property(nonatomic,copy) NSString* origin; + +/** +* Specifies whether to include the origin in the handshake request. Defaults to YES. +*/ +@property(nonatomic,assign) BOOL useOrigin; + +/** + * The host string is created from the url. + **/ +@property(nonatomic,copy) NSString* host; + +/** + * The list of extensions accepted by the host. + **/ +@property(nonatomic,retain) NSMutableArray* serverExtensions; + +/** + * The list of extensions supported by the client. An item can contain an ordered list of extensions as + * an array of extensions. To add an ordered list of extensions, add an the array or call the addExtensions: + * operation (unavailable in versions prior to the standard). + **/ +@property(nonatomic,retain) NSMutableArray* extensions; + +/** + * Settings for securing the connection using SSL/TLS. + * + * 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 the value is nil or an empty dictionary, then the websocket cannot be secured. + **/ +@property(nonatomic,retain) NSMutableDictionary* tlsSettings; + +/** + * The subprotocols supported by the client. Each subprotocol is represented by an NSString. + **/ +@property(nonatomic,retain) NSMutableArray* protocols; + +/** + * True if the client should verify the handshake security key sent by the server. Since many of + * the web socket servers may not have been updated to support this, set to false to ignore + * and simply accept the connection to the server. + **/ +@property(nonatomic,assign) BOOL verifySecurityKey; + +/** + * The subprotocol selected by the server, nil if none was selected + **/ +@property(nonatomic,copy) NSString* serverProtocol; + +/** +* The time interval to send pings on. If zero, no automated pings will be sent. Default is zero. +**/ +@property(nonatomic, assign) NSTimeInterval keepAlive; + +/** +* Indicates whether an active extension should be allowed to modify the reserved bits. Default is false; +*/ +@property(nonatomic, assign) BOOL activeExtensionModifiesReservedBits; + + ++ (id) config; ++ (id) configWithURLString:(NSString*) aUrlString origin:(NSString*) aOrigin protocols:(NSArray*) aProtocols tlsSettings:(NSDictionary*) aTlsSettings headers:(NSArray*) aHeaders verifySecurityKey:(BOOL) aVerifySecurityKey extensions:(NSArray*) aExtensions; +- (id) initWithURLString:(NSString *) aUrlString origin:(NSString*) aOrigin protocols:(NSArray*) aProtocols tlsSettings:(NSDictionary*) aTlsSettings headers:(NSArray*) aHeaders verifySecurityKey:(BOOL) aVerifySecurityKey extensions:(NSArray*) aExtensions; + +/** +* Add a supported extension. +*/ +- (void) addExtension:(NSString*) aExtension; + +/** +* Add an ordered set of supported extensions. +*/ +- (void) addExtensions:(NSArray*) aExtensions; + + +@end + +extern NSString *const WebSocketConnectConfigException; +extern NSString *const WebSocketConnectConfigErrorDomain; + diff --git a/Vendor/UnittWebSocketClient/include/WebSocketFragment.h b/Vendor/UnittWebSocketClient/include/WebSocketFragment.h new file mode 100644 index 0000000..857d293 --- /dev/null +++ b/Vendor/UnittWebSocketClient/include/WebSocketFragment.h @@ -0,0 +1,111 @@ +// +// WebSocketFragment.h +// UnittWebSocketClient +// +// Created by Josh Morris on 6/12/11. +// Copyright 2011 UnitT Software. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +// + +#import <Foundation/Foundation.h> + + +enum +{ + MessageOpCodeIllegal = -1, + MessageOpCodeContinuation = 0x0, + MessageOpCodeText = 0x1, + MessageOpCodeBinary = 0x2, + MessageOpCodeClose = 0x8, + MessageOpCodePing = 0x9, + MessageOpCodePong = 0xA +}; +typedef NSInteger MessageOpCode; + +enum +{ + PayloadTypeUnknown = 0, + PayloadTypeText = 1, + PayloadTypeBinary = 2 +}; +typedef NSInteger PayloadType; + +enum +{ + PayloadLengthIllegal = -1, + PayloadLengthMinimum = 0, + PayloadLengthShort = 1, + PayloadLengthLong = 2 +}; +typedef NSInteger PayloadLength; + + +@interface WebSocketFragment : NSObject +{ + BOOL isFinal; + int mask; + int payloadStart; + int payloadLength; + BOOL isRSV1; + BOOL isRSV2; + BOOL isRSV3; + PayloadType payloadType; + NSData* payloadData; + MessageOpCode opCode; + NSMutableData* fragment; +} + +@property (nonatomic,assign) BOOL isFinal; +@property (nonatomic,readonly) BOOL hasMask; +@property (nonatomic,readonly) BOOL isControlFrame; +@property (nonatomic,readonly) BOOL isDataFrame; +@property (nonatomic,readonly) BOOL isValid; +@property (nonatomic,readonly) BOOL canBeParsed; +@property (nonatomic,readonly) BOOL isHeaderValid; +@property (nonatomic,assign) BOOL isRSV1; +@property (nonatomic,assign) BOOL isRSV2; +@property (nonatomic,assign) BOOL isRSV3; +@property (nonatomic,assign) int mask; +@property (nonatomic,assign) MessageOpCode opCode; +@property (nonatomic,retain) NSData* payloadData; +@property (nonatomic,assign) PayloadType payloadType; +@property (nonatomic,retain) NSMutableData* fragment; +@property (nonatomic,readonly) NSUInteger messageLength; +@property (nonatomic,readonly) int payloadLength; +@property (nonatomic,readonly) int payloadStart; + +@property (nonatomic,readonly) BOOL isDataValid; + +- (int) generateMask; +- (NSData*) mask:(int) aMask data:(NSData*) aData; +- (NSData*) mask:(int) aMask data:(NSData*) aData range:(NSRange) aRange; +- (void) maskInPlace:(int) aMask data:(NSMutableData*) aData range:(NSRange) aRange; +- (NSData*) unmask:(int) aMask data:(NSData*) aData; +- (NSData*) unmask:(int) aMask data:(NSData*) aData range:(NSRange) aRange; +- (void) unmaskInPlace:(int) aMask data:(NSMutableData*) aData range:(NSRange) aRange; + +- (void) parseHeader; +- (BOOL) parseHeader:(NSData*) aData from:(NSUInteger) aOffset; +- (void) parseContent; + +- (BOOL) parseContent:(NSData*) aData; + +- (void) buildFragment; + ++ (id) fragmentWithOpCode:(MessageOpCode) aOpCode isFinal:(BOOL) aIsFinal payload:(NSData*) aPayload; ++ (id) fragmentWithData:(NSData*) aData; +- (id) initWithOpCode:(MessageOpCode) aOpCode isFinal:(BOOL) aIsFinal payload:(NSData*) aPayload; +- (id) initWithData:(NSData*) aData; + +@end diff --git a/Vendor/UnittWebSocketClient/include/WebSocketMessage.h b/Vendor/UnittWebSocketClient/include/WebSocketMessage.h new file mode 100644 index 0000000..31b42af --- /dev/null +++ b/Vendor/UnittWebSocketClient/include/WebSocketMessage.h @@ -0,0 +1,39 @@ +// +// WebSocketMessage.h +// UnittWebSocketClient +// +// Created by Josh Morris on 6/12/11. +// Copyright 2011 UnitT Software. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +// + +#import <Foundation/Foundation.h> +#import "WebSocketFragment.h" + + +@interface WebSocketMessage : NSObject +{ +@private + NSMutableArray* fragments; +} + +- (void) pushFragment:(WebSocketFragment*) aFragment; +- (NSData*) parse; +- (void) clear; + ++ (id) messageWithFragment:(WebSocketFragment*) aFragment; +- (id) initWithFragment:(WebSocketFragment*) aFragment; +- (id) init; + +@end |
