From: Mark Slee Date: Mon, 24 Sep 2007 19:24:53 +0000 (+0000) Subject: Merging more server support and exception fixes for Cocoa X-Git-Tag: 0.2.0~1191 X-Git-Url: https://source.supwisdom.com/gerrit/gitweb?a=commitdiff_plain;h=77575e69bbb9a8bc4b7d392abec781150c4cb039;p=common%2Fthrift.git Merging more server support and exception fixes for Cocoa Summary: Submitted by Andrew McGeachie. Reviewed By: mcslee git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@665281 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/lib/cocoa/TBinaryProtocol.h b/lib/cocoa/TBinaryProtocol.h index ac8bc579..2c56740a 100644 --- a/lib/cocoa/TBinaryProtocol.h +++ b/lib/cocoa/TBinaryProtocol.h @@ -1,5 +1,7 @@ #import "TProtocol.h" #import "TTransport.h" +#import "TProtocolFactory.h" + @interface TBinaryProtocol : NSObject { id mTransport; @@ -14,3 +16,13 @@ strictWrite: (BOOL) strictWrite; @end; + + +@interface TBinaryProtocolFactory : NSObject { +} + ++ (TBinaryProtocolFactory *) sharedFactory; + +- (TBinaryProtocol *) newProtocolOnTransport: (id ) transport; + +@end \ No newline at end of file diff --git a/lib/cocoa/TBinaryProtocol.m b/lib/cocoa/TBinaryProtocol.m index ba7808c2..19db55f9 100644 --- a/lib/cocoa/TBinaryProtocol.m +++ b/lib/cocoa/TBinaryProtocol.m @@ -5,6 +5,26 @@ int32_t VERSION_1 = 0x80010000; 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 ) transport { + return [[[TBinaryProtocol alloc] initWithTransport: transport] autorelease]; +} + +@end + + + @implementation TBinaryProtocol - (id) initWithTransport: (id ) transport @@ -54,7 +74,8 @@ int32_t VERSION_MASK = 0xffff0000; 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; @@ -69,7 +90,8 @@ int32_t VERSION_MASK = 0xffff0000; } } 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) { @@ -194,8 +216,8 @@ int32_t VERSION_MASK = 0xffff0000; 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]; @@ -348,7 +370,8 @@ int32_t VERSION_MASK = 0xffff0000; [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]; } } diff --git a/lib/cocoa/TException.m b/lib/cocoa/TException.m index 38d00ca2..33ed7b58 100644 --- a/lib/cocoa/TException.m +++ b/lib/cocoa/TException.m @@ -30,4 +30,16 @@ } +- (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 diff --git a/lib/cocoa/THTTPClient.m b/lib/cocoa/THTTPClient.m index 096770d7..45c0b80e 100644 --- a/lib/cocoa/THTTPClient.m +++ b/lib/cocoa/THTTPClient.m @@ -39,6 +39,7 @@ [mURL release]; [mRequest release]; [mRequestData release]; + [mResponseData release]; [super dealloc]; } @@ -75,19 +76,20 @@ [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! diff --git a/lib/cocoa/TNSFileHandleTransport.h b/lib/cocoa/TNSFileHandleTransport.h new file mode 100644 index 00000000..fc03ce3d --- /dev/null +++ b/lib/cocoa/TNSFileHandleTransport.h @@ -0,0 +1,16 @@ + +#import +#import "TTransport.h" + +@interface TNSFileHandleTransport : NSObject { + NSFileHandle * mInputFileHandle; + NSFileHandle * mOutputFileHandle; +} + +- (id) initWithFileHandle: (NSFileHandle *) fileHandle; + +- (id) initWithInputFileHandle: (NSFileHandle *) inputFileHandle + outputFileHandle: (NSFileHandle *) outputFileHandle; + + +@end diff --git a/lib/cocoa/TNSFileHandleTransport.m b/lib/cocoa/TNSFileHandleTransport.m new file mode 100644 index 00000000..7ad1ba7e --- /dev/null +++ b/lib/cocoa/TNSFileHandleTransport.m @@ -0,0 +1,68 @@ + +#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 diff --git a/lib/cocoa/TProcessor.h b/lib/cocoa/TProcessor.h new file mode 100644 index 00000000..01b2a613 --- /dev/null +++ b/lib/cocoa/TProcessor.h @@ -0,0 +1,9 @@ +#import + + +@protocol TProcessor + +- (BOOL) processOnInputProtocol: (id ) inProtocol + outputProtocol: (id ) outProtocol; + +@end diff --git a/lib/cocoa/TProtocolFactory.h b/lib/cocoa/TProtocolFactory.h new file mode 100644 index 00000000..06d62c8f --- /dev/null +++ b/lib/cocoa/TProtocolFactory.h @@ -0,0 +1,10 @@ +#import +#import "TProtocol.h" +#import "TTransport.h" + + +@protocol TProtocolFactory + +- (id ) newProtocolOnTransport: (id ) transport; + +@end diff --git a/lib/cocoa/TSocketClient.h b/lib/cocoa/TSocketClient.h new file mode 100644 index 00000000..8905ed44 --- /dev/null +++ b/lib/cocoa/TSocketClient.h @@ -0,0 +1,13 @@ +#import +#import "TNSStreamTransport.h" + +@interface TSocketClient : TNSStreamTransport { +} + +- (id) initWithHostname: (NSString *) hostname + port: (int) port; + +@end + + + diff --git a/lib/cocoa/TSocketClient.m b/lib/cocoa/TSocketClient.m new file mode 100644 index 00000000..f3acc3bf --- /dev/null +++ b/lib/cocoa/TSocketClient.m @@ -0,0 +1,24 @@ +#import +#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 + + + diff --git a/lib/cocoa/TSocketServer.h b/lib/cocoa/TSocketServer.h new file mode 100644 index 00000000..4b8e8d07 --- /dev/null +++ b/lib/cocoa/TSocketServer.h @@ -0,0 +1,21 @@ +#import +#import "TProtocolFactory.h" +#import "TProcessor.h" + + +@interface TSocketServer : NSObject { + NSSocketPort * mServerSocket; + NSFileHandle * mSocketFileHandle; + id mInputProtocolFactory; + id mOutputProtocolFactory; + id mProcessor; +} + +- (id) initWithPort: (int) port + protocolFactory: (id ) protocolFactory + processor: (id ) processor; + +@end + + + diff --git a/lib/cocoa/TSocketServer.m b/lib/cocoa/TSocketServer.m new file mode 100644 index 00000000..a65d017b --- /dev/null +++ b/lib/cocoa/TSocketServer.m @@ -0,0 +1,80 @@ +#import +#import "TSocketServer.h" +#import "TNSFileHandleTransport.h" +#import "TProtocol.h" + + +@implementation TSocketServer + +- (id) initWithPort: (int) port + protocolFactory: (id ) protocolFactory + processor: (id ) 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 inProtocol = [mInputProtocolFactory newProtocolOnTransport: transport]; + id outProtocol = [mOutputProtocolFactory newProtocolOnTransport: transport]; + + while ([mProcessor processOnInputProtocol: inProtocol outputProtocol: outProtocol]); + + [pool release]; +} + + + +@end + + +