diff options
| author | Teddy Wing | 2012-09-29 17:33:05 -0400 | 
|---|---|---|
| committer | Teddy Wing | 2012-09-29 17:33:05 -0400 | 
| commit | d14fe86d8c411ad41635a4736c2c736027f6b19b (patch) | |
| tree | ee6517a2d2cd22bdd0a067b437a8589a05cfe58c | |
| parent | aaa15ec5beeb3df296b7b0fa6d693f04fd52170b (diff) | |
| download | babblr-iOS-d14fe86d8c411ad41635a4736c2c736027f6b19b.tar.bz2 | |
Got pushing/sending to websockets working. Think I got receiving working too but not sure just yet.
23 files changed, 3371 insertions, 6 deletions
| diff --git a/Classes/ChatMessagesDataSource.h b/Classes/ChatMessagesDataSource.h index b259b9b..51c0ce2 100644 --- a/Classes/ChatMessagesDataSource.h +++ b/Classes/ChatMessagesDataSource.h @@ -7,10 +7,19 @@  //  #import <Foundation/Foundation.h> +#import "WebSocket.h" -@interface ChatMessagesDataSource : NSObject <UITableViewDataSource> { - +@interface ChatMessagesDataSource : NSObject <UITableViewDataSource, WebSocketDelegate> { +	NSMutableArray *messages; +	@private +		WebSocket *ws;  } +@property (nonatomic, retain) NSMutableArray *messages; +@property (nonatomic, readonly) WebSocket *ws; + +- (void)startMyWebSocket; +- (void)sendMessage:(NSString *)message; +  @end diff --git a/Classes/ChatMessagesDataSource.m b/Classes/ChatMessagesDataSource.m index f3a60cb..80f449f 100644 --- a/Classes/ChatMessagesDataSource.m +++ b/Classes/ChatMessagesDataSource.m @@ -11,8 +11,11 @@  @implementation ChatMessagesDataSource +@synthesize ws; +@synthesize messages; +  - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { -	return 5; +	return [messages count];  }  - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { @@ -24,10 +27,110 @@  	}  	// Set up the cell... -	NSString *cellValue = @"test"; +	NSString *cellValue = [messages objectAtIndex:[indexPath row]];  	cell.textLabel.text = cellValue;  	return cell;  } +- (void)sendMessage:(NSString *)message { +	if (WebSocketReadyStateOpen) { +		[self.ws sendText:message]; +	} +} + +#pragma mark WebSocket + +- (void) startMyWebSocket +{ +    [self.ws open]; +     +    //continue processing other stuff +    //... +} + +#pragma mark Lifecycle + +- (id)init +{ +    self = [super init]; +    if (self)  +    { +        //make sure to use the right url, it must point to your specific web socket endpoint or the handshake will fail +        //create a connect config and set all our info here +        WebSocketConnectConfig* config = [WebSocketConnectConfig configWithURLString:@"ws://poddb.com:9394/" origin:nil protocols:nil tlsSettings:nil headers:nil verifySecurityKey:YES extensions:nil ]; +        config.closeTimeout = 15.0; +        config.keepAlive = 15.0; //sends a ws ping every 15s to keep socket alive + +        //open using the connect config, it will be populated with server info, such as selected protocol/etc +        ws = [[WebSocket webSocketWithConfig:config delegate:self] retain]; +		 +		messages = [[NSMutableArray alloc] init]; +    } +    return self; +     +} + +- (void)dealloc  +{ +	[messages release]; +    [ws release]; +    [super dealloc]; +} + +#pragma mark WebSocket Delegate methods + +/** + * Called when the web socket connects and is ready for reading and writing. + **/ +- (void) didOpen +{ +    NSLog(@"Socket is open for business."); +} + +/** + * Called when the web socket closes. aError will be nil if it closes cleanly. + **/ +- (void) didClose:(NSUInteger) aStatusCode message:(NSString*) aMessage error:(NSError*) aError +{ +    NSLog(@"Oops. It closed."); +} + +/** + * Called when the web socket receives an error. Such an error can result in the + socket being closed. + **/ +- (void) didReceiveError:(NSError*) aError +{ +    NSLog(@"Oops. An error occurred."); +} + +/** + * Called when the web socket receives a message. + **/ +- (void) didReceiveTextMessage:(NSString*) aMessage +{ +    //Hooray! I got a message to print. +//    NSLog(@"Did receive message: %@", aMessage); +	 +	[messages addObject:aMessage]; +	NSLog(@"TABLE DATA: %@", [messages description]); +} + +/** + * Called when the web socket receives a message. + **/ +- (void) didReceiveBinaryMessage:(NSData*) aMessage +{ +    //Hooray! I got a binary message. +} + +/** + * Called when pong is sent... For keep-alive optimization. + **/ +- (void) didSendPong:(NSData*) aMessage +{ +    NSLog(@"Yay! Pong was sent!"); +} +  @end diff --git a/Classes/ChatViewController.h b/Classes/ChatViewController.h index c6c517c..1170bd9 100644 --- a/Classes/ChatViewController.h +++ b/Classes/ChatViewController.h @@ -15,9 +15,11 @@  	UITableView *chatTableView;  	UIView *containerView;      HPGrowingTextView *textView; +	ChatMessagesDataSource *dataSource;  }  @property (nonatomic, retain) UITableView *chatTableView; +@property (nonatomic, retain) ChatMessagesDataSource *dataSource;  -(void)resignTextView; diff --git a/Classes/ChatViewController.m b/Classes/ChatViewController.m index b0bd903..971363c 100644 --- a/Classes/ChatViewController.m +++ b/Classes/ChatViewController.m @@ -12,6 +12,7 @@  @implementation ChatViewController  @synthesize chatTableView = _chatTableView; +@synthesize dataSource = _dataSource;  -(id)init  { @@ -39,7 +40,8 @@      self.view.backgroundColor = [UIColor colorWithRed:219.0f/255.0f green:226.0f/255.0f blue:237.0f/255.0f alpha:1];  	chatTableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain]; -	ChatMessagesDataSource *dataSource = [[ChatMessagesDataSource alloc] init]; +	dataSource = [[ChatMessagesDataSource alloc] init]; +	[dataSource startMyWebSocket];  	[chatTableView setDataSource:dataSource];  	[self.view addSubview:chatTableView]; @@ -86,7 +88,7 @@  	UIButton *doneBtn = [UIButton buttonWithType:UIButtonTypeCustom];  	doneBtn.frame = CGRectMake(containerView.frame.size.width - 69, 8, 63, 27);      doneBtn.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin; -	[doneBtn setTitle:@"Done" forState:UIControlStateNormal]; +	[doneBtn setTitle:@"Post" forState:UIControlStateNormal];      [doneBtn setTitleShadowColor:[UIColor colorWithWhite:0 alpha:0.4] forState:UIControlStateNormal];      doneBtn.titleLabel.shadowOffset = CGSizeMake (0.0, -1.0); @@ -102,6 +104,9 @@  -(void)resignTextView  { +	[dataSource sendMessage:textView.text]; +	textView.text = @""; +	[chatTableView reloadData];  	[textView resignFirstResponder];  } diff --git a/NearMe.xcodeproj/project.pbxproj b/NearMe.xcodeproj/project.pbxproj index 83c3ec1..875246c 100755 --- a/NearMe.xcodeproj/project.pbxproj +++ b/NearMe.xcodeproj/project.pbxproj @@ -30,6 +30,9 @@  		D134D80C161781F50098794B /* MessageEntrySendButtonPressed.png in Resources */ = {isa = PBXBuildFile; fileRef = D134D804161781F50098794B /* MessageEntrySendButtonPressed.png */; };  		D134D80D161781F50098794B /* MessageEntrySendButtonPressed@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = D134D805161781F50098794B /* MessageEntrySendButtonPressed@2x.png */; };  		D134D89116178EF10098794B /* ChatMessagesDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = D134D89016178EF10098794B /* ChatMessagesDataSource.m */; }; +		D134D8A8161790470098794B /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D134D8A7161790470098794B /* CFNetwork.framework */; }; +		D134D8AA161790470098794B /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D134D8A9161790470098794B /* Security.framework */; }; +		D134D8C5161793820098794B /* libUnittWebSocketClient.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D134D8C4161793820098794B /* libUnittWebSocketClient.a */; };  /* End PBXBuildFile section */  /* Begin PBXFileReference section */ @@ -66,6 +69,9 @@  		D134D805161781F50098794B /* MessageEntrySendButtonPressed@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "MessageEntrySendButtonPressed@2x.png"; sourceTree = "<group>"; };  		D134D88F16178EF10098794B /* ChatMessagesDataSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ChatMessagesDataSource.h; path = Classes/ChatMessagesDataSource.h; sourceTree = "<group>"; };  		D134D89016178EF10098794B /* ChatMessagesDataSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ChatMessagesDataSource.m; path = Classes/ChatMessagesDataSource.m; sourceTree = "<group>"; }; +		D134D8A7161790470098794B /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = System/Library/Frameworks/CFNetwork.framework; sourceTree = SDKROOT; }; +		D134D8A9161790470098794B /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; +		D134D8C4161793820098794B /* libUnittWebSocketClient.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libUnittWebSocketClient.a; path = "Vendor/UnittWebSocketClient/bin/Debug-iphonesimulator/libUnittWebSocketClient.a"; sourceTree = "<group>"; };  /* End PBXFileReference section */  /* Begin PBXFrameworksBuildPhase section */ @@ -76,6 +82,9 @@  				1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */,  				1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */,  				288765FD0DF74451002DB57D /* CoreGraphics.framework in Frameworks */, +				D134D8A8161790470098794B /* CFNetwork.framework in Frameworks */, +				D134D8AA161790470098794B /* Security.framework in Frameworks */, +				D134D8C5161793820098794B /* libUnittWebSocketClient.a in Frameworks */,  			);  			runOnlyForDeploymentPostprocessing = 0;  		}; @@ -130,6 +139,8 @@  				19C28FACFE9D520D11CA2CBB /* Products */,  				D134D6E91617687A0098794B /* xib */,  				D134D7FD161781F50098794B /* Resources */, +				D134D8A7161790470098794B /* CFNetwork.framework */, +				D134D8A9161790470098794B /* Security.framework */,  			);  			name = CustomTemplate;  			sourceTree = "<group>"; @@ -146,6 +157,7 @@  		29B97323FDCFA39411CA2CEA /* Frameworks */ = {  			isa = PBXGroup;  			children = ( +				D134D8C4161793820098794B /* libUnittWebSocketClient.a */,  				1DF5F4DF0D08C38300B7A737 /* UIKit.framework */,  				1D30AB110D05D00D00671497 /* Foundation.framework */,  				288765FC0DF74451002DB57D /* CoreGraphics.framework */, @@ -289,7 +301,10 @@  				GCC_OPTIMIZATION_LEVEL = 0;  				GCC_PRECOMPILE_PREFIX_HEADER = YES;  				GCC_PREFIX_HEADER = NearMe_Prefix.pch; +				HEADER_SEARCH_PATHS = "$(inherited)";  				INFOPLIST_FILE = "NearMe-Info.plist"; +				LIBRARY_SEARCH_PATHS = "$(inherited)"; +				OTHER_LDFLAGS = "-all_load";  				PRODUCT_NAME = NearMe;  			};  			name = Debug; @@ -301,7 +316,10 @@  				COPY_PHASE_STRIP = YES;  				GCC_PRECOMPILE_PREFIX_HEADER = YES;  				GCC_PREFIX_HEADER = NearMe_Prefix.pch; +				HEADER_SEARCH_PATHS = "$(inherited)";  				INFOPLIST_FILE = "NearMe-Info.plist"; +				LIBRARY_SEARCH_PATHS = "$(inherited)"; +				OTHER_LDFLAGS = "-all_load";  				PRODUCT_NAME = NearMe;  				VALIDATE_PRODUCT = YES;  			}; @@ -315,7 +333,9 @@  				GCC_C_LANGUAGE_STANDARD = c99;  				GCC_WARN_ABOUT_RETURN_TYPE = YES;  				GCC_WARN_UNUSED_VARIABLE = YES; +				HEADER_SEARCH_PATHS = "\"$(SRCROOT)/Vendor/UnittWebSocketClient/include\"";  				IPHONEOS_DEPLOYMENT_TARGET = 3.2; +				LIBRARY_SEARCH_PATHS = "\"$(SRCROOT)/Vendor/UnittWebSocketClient/bin/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)\"";  				PREBINDING = NO;  				SDKROOT = iphoneos4.0;  				TARGETED_DEVICE_FAMILY = "1,2"; @@ -330,7 +350,9 @@  				GCC_C_LANGUAGE_STANDARD = c99;  				GCC_WARN_ABOUT_RETURN_TYPE = YES;  				GCC_WARN_UNUSED_VARIABLE = YES; +				HEADER_SEARCH_PATHS = "\"$(SRCROOT)/Vendor/UnittWebSocketClient/include\"";  				IPHONEOS_DEPLOYMENT_TARGET = 3.2; +				LIBRARY_SEARCH_PATHS = "\"$(SRCROOT)/Vendor/UnittWebSocketClient/bin/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)\"";  				OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1";  				PREBINDING = NO;  				SDKROOT = iphoneos4.0; @@ -1,4 +1,8 @@  Babblr  ====== +# Web Socket  ws://poddb.com:9394/ + +# Growing iOS SMS text field +https://github.com/HansPinckaers/GrowingTextView/commit/d0fc657801244387c935b360e4db955f7da1736d diff --git a/Vendor/UnittWebSocketClient/bin/Debug-iphoneos/libUnittWebSocketClient.a b/Vendor/UnittWebSocketClient/bin/Debug-iphoneos/libUnittWebSocketClient.aBinary files differ new 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.aBinary files differ new 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.aBinary files differ new 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.aBinary files differ new 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 | 
