From 3a0ed88812cfb254bd179aebaa8e02b25ef4f013 Mon Sep 17 00:00:00 2001 From: Robert Sesek Date: Tue, 16 Feb 2010 10:54:07 -0500 Subject: [PATCH] Remove SocketWrapper and start using CFSocket with CFStreams in GDBpConnection. This compiles but not much else. --- MacGDBp.xcodeproj/project.pbxproj | 6 - Source/GDBpConnection.h | 17 +- Source/GDBpConnection.m | 330 ++++++++++++++++++++++++++++-- Source/SocketWrapper.h | 51 ----- Source/SocketWrapper.m | 217 -------------------- 5 files changed, 329 insertions(+), 292 deletions(-) delete mode 100644 Source/SocketWrapper.h delete mode 100644 Source/SocketWrapper.m diff --git a/MacGDBp.xcodeproj/project.pbxproj b/MacGDBp.xcodeproj/project.pbxproj index 09d32bf..ab0742c 100644 --- a/MacGDBp.xcodeproj/project.pbxproj +++ b/MacGDBp.xcodeproj/project.pbxproj @@ -37,7 +37,6 @@ 1EEBFD090D3599E8008F835B /* BSSplitView.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EEBFD070D3599E8008F835B /* BSSplitView.m */; }; 1EEBFD120D359A9F008F835B /* dimple.png in Resources */ = {isa = PBXBuildFile; fileRef = 1EEBFD110D359A9F008F835B /* dimple.png */; }; 1EEE875D0D9DE4B4009CBA7C /* MacGDBp.icns in Resources */ = {isa = PBXBuildFile; fileRef = 1EEE875C0D9DE4B4009CBA7C /* MacGDBp.icns */; }; - 1EEEE9400C618B70000C0732 /* SocketWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EEEE93F0C618B70000C0732 /* SocketWrapper.m */; }; 1EFF70C30DFDC018006B9D33 /* BreakpointController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EFF70C20DFDC018006B9D33 /* BreakpointController.m */; }; 8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; }; 8D11072D0486CEB800E47090 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; }; @@ -105,8 +104,6 @@ 1EEBFD080D3599E8008F835B /* BSSplitView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BSSplitView.h; path = Source/BSSplitView.h; sourceTree = ""; }; 1EEBFD110D359A9F008F835B /* dimple.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = dimple.png; sourceTree = ""; }; 1EEE875C0D9DE4B4009CBA7C /* MacGDBp.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = MacGDBp.icns; path = Icons/MacGDBp.icns; sourceTree = ""; }; - 1EEEE93E0C618B70000C0732 /* SocketWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SocketWrapper.h; path = Source/SocketWrapper.h; sourceTree = ""; }; - 1EEEE93F0C618B70000C0732 /* SocketWrapper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SocketWrapper.m; path = Source/SocketWrapper.m; sourceTree = ""; }; 1EFF70C10DFDC018006B9D33 /* BreakpointController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BreakpointController.h; path = Source/BreakpointController.h; sourceTree = ""; }; 1EFF70C20DFDC018006B9D33 /* BreakpointController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BreakpointController.m; path = Source/BreakpointController.m; sourceTree = ""; }; 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; @@ -202,8 +199,6 @@ children = ( 1E02C56F0C610158006F1752 /* GDBpConnection.h */, 1E02C5700C610158006F1752 /* GDBpConnection.m */, - 1EEEE93E0C618B70000C0732 /* SocketWrapper.h */, - 1EEEE93F0C618B70000C0732 /* SocketWrapper.m */, 1E35FFB00C65A74C0030F527 /* NSXMLElementAdditions.h */, 1E35FC750C6579CA0030F527 /* NSXMLElementAdditions.m */, ); @@ -395,7 +390,6 @@ 1E02C3D50C60EC2C006F1752 /* AppDelegate.m in Sources */, 1E02C5710C610158006F1752 /* GDBpConnection.m in Sources */, 1E02C5F60C610724006F1752 /* DebuggerController.m in Sources */, - 1EEEE9400C618B70000C0732 /* SocketWrapper.m in Sources */, 1E35FC760C6579CA0030F527 /* NSXMLElementAdditions.m in Sources */, 1E35FEA10C6599040030F527 /* base64.c in Sources */, 1EEBFD090D3599E8008F835B /* BSSplitView.m in Sources */, diff --git a/Source/GDBpConnection.h b/Source/GDBpConnection.h index d943345..443338b 100644 --- a/Source/GDBpConnection.h +++ b/Source/GDBpConnection.h @@ -15,13 +15,13 @@ */ #import -#import "SocketWrapper.h" + #import "Breakpoint.h" #import "StackFrame.h" @protocol GDBpConnectionDelegate; -@interface GDBpConnection : NSObject +@interface GDBpConnection : NSObject { int port; BOOL connected; @@ -37,13 +37,22 @@ */ NSString* status; - SocketWrapper* socket; + // The raw CFSocket on which the two streams are based. Strong. + CFSocketRef socket_; + + // The read stream that is scheduled on the main run loop. Weak. + CFReadStreamRef readStream_; + NSMutableString* currentPacket_; + int packetSize_; + int currentPacketIndex_; + + // The write stream. Weak. + CFWriteStreamRef writeStream_; id delegate; } @property (readonly, copy) NSString* status; -@property (readonly) SocketWrapper* socket; @property (assign) id delegate; // initializer diff --git a/Source/GDBpConnection.m b/Source/GDBpConnection.m index d0f00c1..e4e59ea 100644 --- a/Source/GDBpConnection.m +++ b/Source/GDBpConnection.m @@ -14,11 +14,29 @@ * write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ +#import +#import + #import "GDBpConnection.h" + #import "AppDelegate.h" -@interface GDBpConnection() +// GDBpConnection (Private) //////////////////////////////////////////////////// + +@interface GDBpConnection () @property(readwrite, copy) NSString* status; +@property (assign) CFSocketRef socket; +@property (assign) CFReadStreamRef readStream; +@property (retain) NSMutableString* currentPacket; +@property (assign) CFWriteStreamRef writeStream; + +- (void)connect; +- (void)close; +- (void)socketDidAccept; +- (void)socketDisconnected; +- (void)readStreamHasData; +- (void)send:(NSString*)command; +- (void)errorEncountered:(NSString*)error; - (NSString*)createCommand:(NSString*)cmd, ...; - (NSXMLDocument*)processData:(NSString*)data; @@ -29,8 +47,149 @@ - (void)doSocketAccept:_nil; @end +// CFNetwork Callbacks ///////////////////////////////////////////////////////// + +void ReadStreamCallback(CFReadStreamRef stream, CFStreamEventType eventType, void* connectionRaw) +{ + NSLog(@"ReadStreamCallback()"); + GDBpConnection* connection = (GDBpConnection*)connectionRaw; + switch (eventType) + { + case kCFStreamEventHasBytesAvailable: + [connection readStreamHasData]; + break; + + case kCFStreamEventErrorOccurred: + { + CFErrorRef error = CFReadStreamCopyError(stream); + CFReadStreamUnscheduleFromRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes); + CFReadStreamClose(stream); + CFRelease(stream); + [connection errorEncountered:[[(NSError*)error autorelease] description]]; + break; + } + + case kCFStreamEventEndEncountered: + CFReadStreamUnscheduleFromRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes); + CFReadStreamClose(stream); + CFRelease(stream); + [connection socketDisconnected]; + break; + }; +} + +void WriteStreamCallback(CFWriteStreamRef stream, CFStreamEventType eventType, void* connectionRaw) +{ + NSLog(@"WriteStreamCallback()"); + GDBpConnection* connection = (GDBpConnection*)connectionRaw; + switch (eventType) + { + case kCFStreamEventErrorOccurred: + { + CFErrorRef error = CFWriteStreamCopyError(stream); + CFWriteStreamUnscheduleFromRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes); + CFWriteStreamClose(stream); + CFRelease(stream); + [connection errorEncountered:[[(NSError*)error autorelease] description]]; + break; + } + + case kCFStreamEventEndEncountered: + CFWriteStreamUnscheduleFromRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes); + CFWriteStreamClose(stream); + CFRelease(stream); + [connection socketDisconnected]; + break; + } +} + +void SocketAcceptCallback(CFSocketRef socket, + CFSocketCallBackType callbackType, + CFDataRef address, + const void* data, + void* connectionRaw) +{ + assert(callbackType == kCFSocketAcceptCallBack); + NSLog(@"SocketAcceptCallback()"); + + GDBpConnection* connection = (GDBpConnection*)connectionRaw; + + CFReadStreamRef readStream; + CFWriteStreamRef writeStream; + + // Create the streams on the socket. + CFStreamCreatePairWithSocket(kCFAllocatorDefault, + *(CFSocketNativeHandle*)data, // Socket handle. + &readStream, // Read stream in-pointer. + &writeStream); // Write stream in-pointer. + + // Create struct to register callbacks for the stream. + CFStreamClientContext context; + context.version = 0; + context.info = connection; + context.retain = NULL; + context.release = NULL; + context.copyDescription = NULL; + + // Set the client of the read stream. + CFOptionFlags readFlags = + kCFStreamEventOpenCompleted | + kCFStreamEventHasBytesAvailable | + kCFStreamEventErrorOccurred | + kCFStreamEventEndEncountered; + if (CFReadStreamSetClient(readStream, readFlags, ReadStreamCallback, &context)) + // Schedule in run loop to do asynchronous communication with the engine. + CFReadStreamScheduleWithRunLoop(readStream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes); + else + return; + + NSLog(@"Read stream scheduled"); + + // Open the stream now that it's scheduled on the run loop. + if (!CFReadStreamOpen(readStream)) + { + CFStreamError error = CFReadStreamGetError(readStream); + NSLog(@"error! %@", error); + return; + } + + NSLog(@"Read stream opened"); + + // Set the client of the write stream. + CFOptionFlags writeFlags = + kCFStreamEventOpenCompleted | + kCFStreamEventErrorOccurred | + kCFStreamEventEndEncountered; + if (CFWriteStreamSetClient(writeStream, writeFlags, WriteStreamCallback, &context)) + // Schedule it in the run loop to receive error information. + CFWriteStreamScheduleWithRunLoop(writeStream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes); + else + return; + + NSLog(@"Write stream scheduled"); + + // Open the write stream. + if (!CFWriteStreamOpen(writeStream)) + { + CFStreamError error = CFWriteStreamGetError(writeStream); + NSLog(@"error! %@", error); + return; + } + + NSLog(@"Write stream opened"); + + connection.readStream = readStream; + connection.writeStream = writeStream; + [connection socketDidAccept]; +} + +// GDBpConnection ////////////////////////////////////////////////////////////// + @implementation GDBpConnection -@synthesize socket; +@synthesize socket = socket_; +@synthesize readStream = readStream_; +@synthesize currentPacket = currentPacket_; +@synthesize writeStream = writeStream_; @synthesize status; @synthesize delegate; @@ -45,14 +204,9 @@ port = aPort; connected = NO; - // now that we have our host information, open the socket - socket = [[SocketWrapper alloc] initWithPort:port]; - socket.delegate = self; - [socket connect]; - - self.status = @"Connecting"; - [[BreakpointManager sharedManager] setConnection:self]; + + [self connect]; } return self; } @@ -62,7 +216,9 @@ */ - (void)dealloc { - [socket release]; + [self close]; + self.currentPacket = nil; + [super dealloc]; } @@ -83,7 +239,8 @@ { return @"(DISCONNECTED)"; } - return [socket remoteHost]; + // TODO: Either impl or remove. + return @""; } /** @@ -118,9 +275,9 @@ */ - (void)reconnect { - [socket close]; + [self close]; self.status = @"Connecting"; - [socket connect]; + [self connect]; } /** @@ -246,6 +403,151 @@ #pragma mark Private +/** + * Creates, connects to, and schedules a CFSocket. + */ +- (void)connect +{ + // Pass ourselves to the callback so we don't have to use ugly globals. + CFSocketContext context; + context.version = 0; + context.info = self; + context.retain = NULL; + context.release = NULL; + context.copyDescription = NULL; + + // Create the address structure. + struct sockaddr_in address; + memset(&address, 0, sizeof(address)); + address.sin_len = sizeof(address); + address.sin_family = AF_INET; + address.sin_port = htons(port); + address.sin_addr.s_addr = htonl(INADDR_ANY); + + // Create the socket signature. + CFSocketSignature signature; + signature.protocolFamily = PF_INET; + signature.socketType = SOCK_STREAM; + signature.protocol = IPPROTO_TCP; + signature.address = (CFDataRef)[NSData dataWithBytes:&address length:sizeof(address)]; + + socket_ = CFSocketCreateWithSocketSignature(kCFAllocatorDefault, + &signature, // Socket signature. + kCFSocketAcceptCallBack, // Callback types. + SocketAcceptCallback, // Callout function pointer. + &context); // Context to pass to callout. + if (!socket_) + { + [self errorEncountered:@"Could not open socket."]; + return; + } + + // Allow old, yet-to-be recycled sockets to be reused. + BOOL yes = YES; + setsockopt(CFSocketGetNative(socket_), SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(BOOL)); + + // Schedule the socket on the run loop. + CFRunLoopSourceRef source = CFSocketCreateRunLoopSource(kCFAllocatorDefault, socket_, 0); + CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopCommonModes); + CFRelease(source); + + self.status = @"Connecting"; +} + +/** + * Closes a socket and releases the ref. + */ +- (void)close +{ + // The socket goes down, so do the streams, which clean themselves up. + CFSocketInvalidate(socket_); + CFRelease(socket_); +} + +/** + * Notification that the socket disconnected. + */ +- (void)socketDisconnected +{ + [self close]; + [delegate debuggerDisconnected]; +} + +/** + * Callback from the CFReadStream that there is data waiting to be read. + */ +- (void)readStreamHasData +{ + UInt8 buffer[1024]; + CFIndex bytesRead = CFReadStreamRead(readStream_, buffer, 1024); + const char* charBuffer = (const char*)buffer; + + // We haven't finished reading a packet, so just read more data in. + if (currentPacketIndex_ < packetSize_) + { + [currentPacket_ appendFormat:@"%s", buffer]; + currentPacketIndex_ += bytesRead; + } + // Time to read a new packet. + else + { + // Read the message header: the size. + packetSize_ = atoi(charBuffer); + currentPacketIndex_ = bytesRead - strlen(charBuffer); + self.currentPacket = [NSMutableString stringWithFormat:@"%s", buffer + strlen(charBuffer) + 1]; + } + + // We have finished reading the packet. + if (currentPacketIndex_ >= packetSize_) + { + packetSize_ = 0; + currentPacketIndex_ = 0; + + // Test if we can convert it into an NSXMLDocument. + NSError* error = nil; + NSXMLDocument* xmlTest = [[NSXMLDocument alloc] initWithXMLString:currentPacket_ options:NSXMLDocumentTidyXML error:&error]; + if (error) + NSLog(@"FAILED XML TEST: %@", error); + [xmlTest release]; + } +} + +/** + * Writes a command into the write stream. This does use blocking IO. + */ +- (void)send:(NSString*)command +{ + BOOL done = NO; + + char* string = (char*)[command UTF8String]; + int stringLength = strlen(string); + + // Busy wait while writing. BAADD. Should background this operation. + while (!done) + { + if (CFWriteStreamCanAcceptBytes(writeStream_)) + { + // Include the NULL byte in the string when we write. + int bytesWritten = CFWriteStreamWrite(writeStream_, (UInt8*)string, stringLength + 1); + if (bytesWritten < 0) + { + NSLog(@"write error"); + } + // Incomplete write. + else if (bytesWritten < strlen(string)) + { + // Adjust the buffer and wait for another chance to write. + stringLength -= bytesWritten; + memmove(string, string + bytesWritten, stringLength); + } + else + { + done = YES; + } + } + } +} + /** * Helper method to create a string command with the -i automatically tacked on. Takes * a variable number of arguments and parses the given command with +[NSString stringWithFormat:] @@ -365,7 +667,7 @@ if (status == nil || [status isEqualToString:@"Stopped"] || [status isEqualToString:@"Stopping"]) { connected = NO; - [socket close]; + [self close]; [delegate debuggerDisconnected]; diff --git a/Source/SocketWrapper.h b/Source/SocketWrapper.h deleted file mode 100644 index 81d82dc..0000000 --- a/Source/SocketWrapper.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * MacGDBp - * Copyright (c) 2007 - 2009, Blue Static - * - * This program is free software; you can redistribute it and/or modify it under the terms of the GNU - * General Public License as published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; if not, - * write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#import - -@protocol SocketWrapperDelegate; - -@interface SocketWrapper : NSObject -{ - int port; - int sock; - NSString* hostname; - - id delegate; -} -@property (assign) id delegate; - -- (id)initWithPort:(int)aPort; - -- (void)connect; -- (void)close; -- (NSString*)receive; -- (BOOL)send:(NSString*)data; - -- (NSString*)remoteHost; - -@end - -@protocol SocketWrapperDelegate - -// Returns a human-readable error message when an error occurred. -- (void)errorEncountered:(NSString*)error; - -// Called after the socket is ready for reading and writing. This is not called -// from the main thread. -- (void)socketDidAccept; - -@end diff --git a/Source/SocketWrapper.m b/Source/SocketWrapper.m deleted file mode 100644 index 30d78bd..0000000 --- a/Source/SocketWrapper.m +++ /dev/null @@ -1,217 +0,0 @@ -/* - * MacGDBp - * Copyright (c) 2007 - 2009, Blue Static - * - * This program is free software; you can redistribute it and/or modify it under the terms of the GNU - * General Public License as published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; if not, - * write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#import "SocketWrapper.h" -#include -#include -#include -#include -#include - -@interface SocketWrapper () -@property (copy, readwrite, getter=remoteHost) NSString* hostname; - -- (void)error:(NSString*)msg; -@end - -@implementation SocketWrapper -@synthesize hostname; -@synthesize delegate; - -/** - * Initializes the socket wrapper with a port - */ -- (id)initWithPort:(int)aPort; -{ - if (self = [super init]) - { - port = aPort; - } - return self; -} - -/** - * Dealloc - */ -- (void)dealloc -{ - [hostname release]; - [super dealloc]; -} - -/** - * Close our socket and clean up anything else - */ -- (void)close -{ - close(sock); -} - -/** - * Connects to a socket on the port specified during init. This will dispatch another thread to do the - * actual waiting. Delegate notifications are posted along the way to let the client know what is going on. - */ -- (void)connect -{ - [NSThread detachNewThreadSelector:@selector(connect:) toTarget:self withObject:nil]; -} - -/** - * This does the actual dirty work (in a separate thread) of connecting to a socket - */ -- (void)connect:(id)obj -{ - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - - // create an INET socket that we'll be listen()ing on - int socketOpen = socket(PF_INET, SOCK_STREAM, 0); - - // create our address given the port - struct sockaddr_in address; - address.sin_family = AF_INET; - address.sin_port = htons(port); - address.sin_addr.s_addr = htonl(INADDR_ANY); - memset(address.sin_zero, '\0', sizeof(address.sin_zero)); - - // allow an already-opened socket to be reused - int yes = 1; - setsockopt(socketOpen, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)); - - // bind the socket... and don't give up until we've tried for a while - int tries = 0; - while (bind(socketOpen, (struct sockaddr*)&address, sizeof(address)) < 0) - { - if (tries >= 5) - { - close(socketOpen); - [self error:@"Could not bind to socket"]; - [pool release]; - return; - } - NSLog(@"couldn't bind to the socket... trying again in 5"); - sleep(5); - tries++; - } - - // now we just have to keep our ears open - if (listen(socketOpen, 0) == -1) - { - [self error:@"Could not use bound socket for listening"]; - } - - // accept a connection - struct sockaddr_in remoteAddress; - socklen_t remoteAddressLen = sizeof(remoteAddress); - sock = accept(socketOpen, (struct sockaddr*)&remoteAddress, &remoteAddressLen); - if (sock < 0) - { - close(socketOpen); - [self error:@"Client failed to accept remote socket"]; - [pool release]; - return; - } - - // we're done listening now that we have a connection - close(socketOpen); - - struct sockaddr_in addr; - socklen_t addrLength; - if (getpeername(sock, (struct sockaddr*)&addr, &addrLength) < 0) - { - [self error:@"Could not get remote hostname."]; - } - char* name = inet_ntoa(addr.sin_addr); - [self setHostname:[NSString stringWithUTF8String:name]]; - - [delegate socketDidAccept]; - - [pool release]; -} - -/** - * Reads from the socket and returns the result as a NSString (because it's always going to be XML). Be aware - * that the underlying socket recv() call will *wait* for the server to send a message, so be sure that this - * is used either in a threaded environment so the interface does not hang, or when you *know* the server - * will return something (which we almost always do). Returns the data that was received from the socket. - */ -- (NSString*)receive -{ - // Read the first part of the response, the length of the packet. - char packetLength[8]; - memset(&packetLength, 0x0, 8); - char c; - int i = 0; - while (recv(sock, &c, 1, 0) == 1 && c != 0x0) - packetLength[i++] = c; - int length = atoi(packetLength); - - // Our final output. - NSMutableString* string = [[NSMutableString alloc] initWithCapacity:length]; - - // Create a buffer that we will move data from the network into. - char buffer[1024]; - - // The total amount of data we have currently read. - int received = 0; - - // Loop until we have the entire packet. - while (received < length) - { - int size = recv(sock, &buffer, sizeof(buffer), 0); - if (size < 1) - { - [self error:@"Socket closed or could not be read"]; - return nil; - } - NSString* temp = [NSString stringWithUTF8String:buffer]; - [string appendString:temp]; - received += [temp length]; - } - - return [string autorelease]; -} - -/** - * Sends a given NSString over the socket. Returns YES on complete submission. - */ -- (BOOL)send:(NSString*)data -{ - data = [NSString stringWithFormat:@"%@\0", data]; - int sent = send(sock, [data UTF8String], [data length], 0); - if (sent < 0) - { - [self error:@"Failed to write data to socket"]; - return NO; - } - if (sent < [data length]) - { - // TODO - do we really need to worry about partial sends with the lenght of our commands? - NSLog(@"FAIL: only partial packet was sent; sent %d bytes", sent); - return NO; - } - - return YES; -} - -/** - * Helper method that just calls |-errorEncountered:| - */ -- (void)error:(NSString*)msg -{ - [delegate errorEncountered:msg]; -} - -@end -- 2.22.5