#import "TProtocol.h"
#import "TTransport.h"
+#import "TProtocolFactory.h"
+
@interface TBinaryProtocol : NSObject <TProtocol> {
id <TTransport> mTransport;
strictWrite: (BOOL) strictWrite;
@end;
+
+
+@interface TBinaryProtocolFactory : NSObject <TProtocolFactory> {
+}
+
++ (TBinaryProtocolFactory *) sharedFactory;
+
+- (TBinaryProtocol *) newProtocolOnTransport: (id <TTransport>) transport;
+
+@end
\ No newline at end of file
int32_t VERSION_MASK = 0xffff0000;
+static TBinaryProtocolFactory * gSharedFactory = nil;
+
+@implementation TBinaryProtocolFactory
+
++ (TBinaryProtocolFactory *) sharedFactory {
+ if (gSharedFactory == nil) {
+ gSharedFactory = [[TBinaryProtocolFactory alloc] init];
+ }
+
+ return gSharedFactory;
+}
+
+- (TBinaryProtocol *) newProtocolOnTransport: (id <TTransport>) transport {
+ return [[[TBinaryProtocol alloc] initWithTransport: transport] autorelease];
+}
+
+@end
+
+
+
@implementation TBinaryProtocol
- (id) initWithTransport: (id <TTransport>) transport
if (size < 0) {
int version = size & VERSION_MASK;
if (version != VERSION_1) {
- @throw [TProtocolException exceptionWithName: @"Bad version in readMessageBegin"];
+ @throw [TProtocolException exceptionWithName: @"TProtocolException"
+ reason: @"Bad version in readMessageBegin"];
}
if (type != NULL) {
*type = version & 0x00FF;
}
} else {
if (mStrictRead) {
- @throw [TProtocolException exceptionWithName: @"Missing version in readMessageBegin, old client?"];
+ @throw [TProtocolException exceptionWithName: @"TProtocolException"
+ reason: @"Missing version in readMessageBegin, old client?"];
}
NSString * messageName = [self readStringBody: size];
if (name != NULL) {
uint8_t * buff = malloc(size);
if (buff == NULL) {
@throw [TProtocolException
- exceptionWithName: @"Out of memory"
- reason: [NSString stringWithFormat: @"Unable to allocate %d bytes trying to read binary data.",
+ exceptionWithName: @"TProtocolException"
+ reason: [NSString stringWithFormat: @"Out of memory. Unable to allocate %d bytes trying to read binary data.",
size]];
}
[mTransport readAll: buff offset: 0 length: size];
[self writeI32: length];
[mTransport write: (uint8_t *) utf8Bytes offset: 0 length: length];
} else {
- // instead of crashing when we get null, let's write out a zero length string
+ // instead of crashing when we get null, let's write out a zero
+ // length string
[self writeI32: 0];
}
}
}
+- (NSString *) description
+{
+ NSMutableString * result = [NSMutableString stringWithString: [self name]];
+ [result appendFormat: @": %@", [self reason]];
+ if ([self userInfo] != nil) {
+ [result appendFormat: @"\n userInfo = %@", [self userInfo]];
+ }
+
+ return result;
+}
+
+
@end
[mURL release];
[mRequest release];
[mRequestData release];
+ [mResponseData release];
[super dealloc];
}
[mRequestData setLength: 0];
if (responseData == nil) {
- @throw [TTransportException exceptionWithName: @"Could not make HTTP request"
- reason: @"unknown"
+ @throw [TTransportException exceptionWithName: @"TTransportException"
+ reason: @"Could not make HTTP request"
error: error];
}
if (![response isKindOfClass: [NSHTTPURLResponse class]]) {
- @throw [TTransportException exceptionWithName: @"Unexpected NSURLResponse type"];
+ @throw [TTransportException exceptionWithName: @"TTransportException"
+ reason: @"Unexpected NSURLResponse type"];
}
NSHTTPURLResponse * httpResponse = (NSHTTPURLResponse *) response;
if ([httpResponse statusCode] != 200) {
- @throw [TTransportException exceptionWithName:
- [NSString stringWithFormat: @"Bad response from HTTP server: %d",
- [httpResponse statusCode]]];
+ @throw [TTransportException exceptionWithName: @"TTransportException"
+ reason: [NSString stringWithFormat: @"Bad response from HTTP server: %d",
+ [httpResponse statusCode]]];
}
// phew!
--- /dev/null
+
+#import <Cocoa/Cocoa.h>
+#import "TTransport.h"
+
+@interface TNSFileHandleTransport : NSObject <TTransport> {
+ NSFileHandle * mInputFileHandle;
+ NSFileHandle * mOutputFileHandle;
+}
+
+- (id) initWithFileHandle: (NSFileHandle *) fileHandle;
+
+- (id) initWithInputFileHandle: (NSFileHandle *) inputFileHandle
+ outputFileHandle: (NSFileHandle *) outputFileHandle;
+
+
+@end
--- /dev/null
+
+#import "TNSFileHandleTransport.h"
+
+
+@implementation TNSFileHandleTransport
+
+- (id) initWithFileHandle: (NSFileHandle *) fileHandle
+{
+ return [self initWithInputFileHandle: fileHandle
+ outputFileHandle: fileHandle];
+}
+
+
+- (id) initWithInputFileHandle: (NSFileHandle *) inputFileHandle
+ outputFileHandle: (NSFileHandle *) outputFileHandle
+{
+ self = [super init];
+
+ mInputFileHandle = [inputFileHandle retain];
+ mOutputFileHandle = [outputFileHandle retain];
+
+ return self;
+}
+
+
+- (void) dealloc {
+ [mInputFileHandle release];
+ [mOutputFileHandle release];
+ [super dealloc];
+}
+
+
+- (int) readAll: (uint8_t *) buf offset: (int) off length: (int) len
+{
+ int got = 0;
+ while (got < len) {
+ NSData * d = [mInputFileHandle readDataOfLength: len-got];
+ if ([d length] == 0) {
+ @throw [NSException exceptionWithName: @"TTransportException"
+ reason: @"Cannot read. No more data."
+ userInfo: nil];
+ }
+ [d getBytes: buf+got];
+ got += [d length];
+ }
+ return got;
+}
+
+
+- (void) write: (uint8_t *) data offset: (unsigned int) offset length: (unsigned int) length
+{
+ NSData * dataObject = [[NSData alloc] initWithBytesNoCopy: data+offset
+ length: length
+ freeWhenDone: NO];
+
+ [mOutputFileHandle writeData: dataObject];
+
+
+ [dataObject release];
+}
+
+
+- (void) flush
+{
+ [mOutputFileHandle synchronizeFile]; // ?
+}
+
+@end
--- /dev/null
+#import <Cocoa/Cocoa.h>
+
+
+@protocol TProcessor <NSObject>
+
+- (BOOL) processOnInputProtocol: (id <TProtocol>) inProtocol
+ outputProtocol: (id <TProtocol>) outProtocol;
+
+@end
--- /dev/null
+#import <Cocoa/Cocoa.h>
+#import "TProtocol.h"
+#import "TTransport.h"
+
+
+@protocol TProtocolFactory <NSObject>
+
+- (id <TProtocol>) newProtocolOnTransport: (id <TTransport>) transport;
+
+@end
--- /dev/null
+#import <Cocoa/Cocoa.h>
+#import "TNSStreamTransport.h"
+
+@interface TSocketClient : TNSStreamTransport {
+}
+
+- (id) initWithHostname: (NSString *) hostname
+ port: (int) port;
+
+@end
+
+
+
--- /dev/null
+#import <Cocoa/Cocoa.h>
+#import "TSocketClient.h"
+
+@implementation TSocketClient
+
+- (id) initWithHostname: (NSString *) hostname
+ port: (int) port
+{
+ NSInputStream * input = nil;
+ NSOutputStream * output = nil;
+
+ [NSStream getStreamsToHost: [NSHost hostWithName: hostname]
+ port: port
+ inputStream: &input
+ outputStream: &output];
+
+ return [super initWithInputStream: input outputStream: output];
+}
+
+
+@end
+
+
+
--- /dev/null
+#import <Cocoa/Cocoa.h>
+#import "TProtocolFactory.h"
+#import "TProcessor.h"
+
+
+@interface TSocketServer : NSObject {
+ NSSocketPort * mServerSocket;
+ NSFileHandle * mSocketFileHandle;
+ id <TProtocolFactory> mInputProtocolFactory;
+ id <TProtocolFactory> mOutputProtocolFactory;
+ id <TProcessor> mProcessor;
+}
+
+- (id) initWithPort: (int) port
+ protocolFactory: (id <TProtocolFactory>) protocolFactory
+ processor: (id <TProcessor>) processor;
+
+@end
+
+
+
--- /dev/null
+#import <Cocoa/Cocoa.h>
+#import "TSocketServer.h"
+#import "TNSFileHandleTransport.h"
+#import "TProtocol.h"
+
+
+@implementation TSocketServer
+
+- (id) initWithPort: (int) port
+ protocolFactory: (id <TProtocolFactory>) protocolFactory
+ processor: (id <TProcessor>) processor;
+{
+ self = [super init];
+
+ mInputProtocolFactory = [protocolFactory retain];
+ mOutputProtocolFactory = [protocolFactory retain];
+ mProcessor = [processor retain];
+
+ // create a socket
+ mServerSocket = [[NSSocketPort alloc] initWithTCPPort: 8081];
+ // wrap it in a file handle so we can get messages from it
+ mSocketFileHandle = [[NSFileHandle alloc] initWithFileDescriptor: [mServerSocket socket]
+ closeOnDealloc: YES];
+
+ // register for notifications of accepted incoming connections
+ [[NSNotificationCenter defaultCenter] addObserver: self
+ selector: @selector(connectionAccepted:)
+ name: NSFileHandleConnectionAcceptedNotification
+ object: mSocketFileHandle];
+
+ // tell socket to listen
+ [mSocketFileHandle acceptConnectionInBackgroundAndNotify];
+
+ return self;
+}
+
+
+- (void) dealloc {
+ [mInputProtocolFactory release];
+ [mOutputProtocolFactory release];
+ [mProcessor release];
+ [mSocketFileHandle release];
+ [mServerSocket release];
+ [super dealloc];
+}
+
+
+- (void) connentionAccepted: (NSNotification *) aNotification
+{
+ NSFileHandle * socket = [[aNotification userInfo] objectForKey: NSFileHandleNotificationFileHandleItem];
+
+ // now that we have a client connected, spin off a thread to handle activity
+ [NSThread detachNewThreadSelector: @selector(handleClientConnection:)
+ toTarget: self
+ withObject: socket];
+
+ [[aNotification object] acceptConnectionInBackgroundAndNotify];
+}
+
+
+- (void) handleClientConnection: (NSFileHandle *) clientSocket
+{
+ NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
+
+ TNSFileHandleTransport * transport = [[TNSFileHandleTransport alloc] initWithFileHandle: clientSocket];
+
+ id <TProtocol> inProtocol = [mInputProtocolFactory newProtocolOnTransport: transport];
+ id <TProtocol> outProtocol = [mOutputProtocolFactory newProtocolOnTransport: transport];
+
+ while ([mProcessor processOnInputProtocol: inProtocol outputProtocol: outProtocol]);
+
+ [pool release];
+}
+
+
+
+@end
+
+
+