// // SoulSeekConnection.m // SSNetwork // // Created by Marcelo Alves on 09/03/07. // Copyright 2007 __MyCompanyName__. All rights reserved. // #import "SoulSeekConnection.h" @implementation SoulSeekConnection -(id) init { if (self = [super init]) { outputQueue = [[NSMutableArray alloc] init]; attachedWorker = nil; currentMessageData = nil; messageSize = 0; name = nil; } return self; } +(id) newConnectionTo:(int)type named:(NSString *)name withInputStream:(NSInputStream *)inputStream andOutputStream:(NSOutputStream *)outputStream andWorker:(SoulSeekWorker *)worker { SoulSeekConnection* connection = [[SoulSeekConnection alloc] init]; if (connection) { connection->input = [inputStream retain]; connection->output = [outputStream retain]; connection->name = [name retain]; connection->attachedWorker = [worker retain]; connection->isPeer = (type == soulSeekPeer); } return connection; } -(id) dealloc { [input release]; [output release]; [name release]; [attachedWorker release]; [outputQueue removeAllObjects]; [outputQueue release]; [super dealloc]; return self; } // TODO : make flushQueue a timed event. Nice idea, but not required, since we just put data in the send message. -(void) flushMessageQueue { while ([outputQueue count] > 0) { SoulSeekMessage *message = [[outputQueue objectAtIndex:0] retain]; [outputQueue removeObjectAtIndex:0]; // todo : if you want to limit the upload speed, do it here. [output write:[message bytes] maxLength:[message length]]; // todo : check if stream is ok and can receive more bytes. [message release]; } } -(void)readMessage { /* read all SoulSeek message from input */ uint8_t miniBuf; while ([input hasBytesAvailable]) { if (currentMessageData == nil) { // new message! // read the first 4 bytes. BUG: Should check for data available! uint32_t size; // TODO : Use NSRange, please. [input read:(void *)&size maxLength:sizeof(uint32_t)]; size = CFSwapInt32LittleToHost(size); // BUG : size < 2GiB (NSData limit) currentMessageData = [[NSMutableData alloc] initWithCapacity:size]; messageSize = size; } // TODO : the "max kbps" feature should be done here. [input read:&miniBuf maxLength:1]; // I don't know a way to read n bytes without blocking. [currentMessageData appendBytes:&miniBuf length:1]; if ([currentMessageData length] >= messageSize) { SoulSeekMessage* message = [[SoulSeekMessage alloc] initWithData:currentMessageData]; [attachedWorker handleMessage:[message autorelease] from:self]; [currentMessageData release]; currentMessageData = nil; break; } } } -(void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode { // begin debug NSString *io; if (stream == input) io = @">>"; else io = @"<<"; NSString *event; switch (eventCode){ case NSStreamEventNone: event = @"NSStreamEventNone"; break; case NSStreamEventOpenCompleted: event = @"NSStreamEventOpenCompleted"; break; case NSStreamEventHasBytesAvailable: event = @"NSStreamEventHasBytesAvailable"; break; case NSStreamEventHasSpaceAvailable: event = @"NSStreamEventHasSpaceAvailable"; break; case NSStreamEventErrorOccurred: event = @"NSStreamEventErrorOccurred"; break; case NSStreamEventEndEncountered: event = @"NSStreamEventEndEncountered"; break; default: event = @"** Unknown"; } // if you want to view what is going on with the streams, uncomment the line below NSLog(@"%@ : %@", io, event); // end debugging if ((stream == input) && (eventCode == NSStreamEventHasBytesAvailable)) [self readMessage]; if ((stream == output) && (eventCode == NSStreamEventHasSpaceAvailable)) [self flushMessageQueue]; } -(void) send:(SoulSeekMessage *)message { if (message == NULL) return; [outputQueue addObject:message]; [self flushMessageQueue]; } -(BOOL) isPeer { return isPeer; } -(NSString *) name { return name; } @end