Changeset 3103

Show
Ignore:
Timestamp:
12/31/05 04:31:44 (3 years ago)
Author:
timothy
Message:

DCC support complete. More complete than Irssi.

  • 64 bit support, allows file transfers over 4 GB. (Irssi does this, but not the rest.)
  • Turbo mode if the other client supports it. (No acknowledgment packets are sent or needed.)
  • Send ahead, sends data without waiting to the acknowledgment packets. (Fast sends.)
Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • branches/cocoa-networking/Chat Core/MVIRCChatConnection.m

    r3102 r3103  
    14801480                                NSHost *host = [NSHost hostWithAddress:address]; 
    14811481 
    1482                                 MVIRCDownloadFileTransfer *transfer = [(MVIRCDownloadFileTransfer *)[MVIRCDownloadFileTransfer allocWithZone:nil] initWithUser:sender]; 
    1483                                 if( port == 0 && [parameters count] >= 6 ) { 
    1484                                         BOOL turbo = ( [[parameters objectAtIndex:5] rangeOfString:@"T"].location != NSNotFound ); 
    1485                                         [transfer _setTurbo:turbo]; 
    1486                                         [transfer _setPassiveIdentifier:[[parameters objectAtIndex:5] intValue]]; 
    1487                                         [transfer _setPassive:YES]; 
    1488                                 } else if( [parameters count] >= 6 ) { 
    1489                                         [transfer _setTurbo:[[parameters objectAtIndex:5] isEqualToString:@"T"]]; 
     1482                                if( port > 0 && [parameters count] >= 6 && [[parameters objectAtIndex:5] rangeOfCharacterFromSet:[NSCharacterSet decimalDigitCharacterSet]].location != NSNotFound ) { 
     1483                                        // this is a passive reply, look up the original transfer 
     1484                                        MVIRCUploadFileTransfer *transfer = nil; 
     1485                                        unsigned long passiveId = [[parameters objectAtIndex:5] intValue]; 
     1486 
     1487                                        @synchronized( _fileTransfers ) { 
     1488                                                NSEnumerator *enumerator = [_fileTransfers objectEnumerator]; 
     1489                                                while( ( transfer = [enumerator nextObject] ) ) 
     1490                                                        if( [transfer isUpload] && [transfer isPassive] && [[transfer user] isEqualToChatUser:sender] && [(id)transfer _passiveIdentifier] == passiveId ) 
     1491                                                                break; 
     1492                                        } 
     1493 
     1494                                        if( transfer ) { 
     1495                                                [transfer _setHost:host]; 
     1496                                                [transfer _setPort:port]; 
     1497                                                [transfer _setupAndStart]; 
     1498                                        } 
     1499                                } else { 
     1500                                        MVIRCDownloadFileTransfer *transfer = [(MVIRCDownloadFileTransfer *)[MVIRCDownloadFileTransfer allocWithZone:nil] initWithUser:sender]; 
     1501                                        if( port == 0 && [parameters count] >= 6 ) { 
     1502                                                BOOL turbo = ( [[parameters objectAtIndex:5] rangeOfString:@"T"].location != NSNotFound ); 
     1503                                                [transfer _setTurbo:turbo]; 
     1504                                                [transfer _setPassiveIdentifier:[[parameters objectAtIndex:5] intValue]]; 
     1505                                                [transfer _setPassive:YES]; 
     1506                                        } else if( [parameters count] >= 6 ) { 
     1507                                                [transfer _setTurbo:[[parameters objectAtIndex:5] isEqualToString:@"T"]]; 
     1508                                        } 
     1509 
     1510                                        [transfer _setOriginalFileName:[parameters objectAtIndex:1]]; 
     1511                                        [transfer _setFinalSize:(unsigned long long)size]; 
     1512                                        [transfer _setHost:host]; 
     1513                                        [transfer _setPort:port]; 
     1514 
     1515                                        [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadWithName:MVDownloadFileTransferOfferNotification object:transfer]; 
     1516 
     1517                                        [self _addFileTransfer:transfer]; 
     1518                                        [transfer release]; 
    14901519                                } 
    1491  
    1492                                 [transfer _setOriginalFileName:[parameters objectAtIndex:1]]; 
    1493                                 [transfer _setFinalSize:(unsigned long long)size]; 
    1494                                 [transfer _setHost:host]; 
    1495                                 [transfer _setPort:port]; 
    1496  
    1497                                 [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadWithName:MVDownloadFileTransferOfferNotification object:transfer]; 
    1498  
    1499                                 [self _addFileTransfer:transfer]; 
    1500                                 [transfer release]; 
    15011520                        } else if( [parameters count] >= 4 && [[parameters objectAtIndex:0] caseInsensitiveCompare:@"ACCEPT"] == NSOrderedSame ) { 
    15021521                                BOOL passive = NO; 
  • branches/cocoa-networking/Chat Core/MVIRCFileTransfer.h

    r3102 r3103  
    77@interface MVIRCUploadFileTransfer : MVUploadFileTransfer { 
    88        AsyncSocket *_connection; 
    9         AsyncSocket *_clientConnection; 
     9        AsyncSocket *_acceptConnection; 
    1010        NSThread *_connectionThread; 
    1111        NSFileHandle *_fileHandle; 
     
    2626@interface MVIRCDownloadFileTransfer : MVDownloadFileTransfer { 
    2727        AsyncSocket *_connection; 
     28        AsyncSocket *_acceptConnection; 
    2829        NSThread *_connectionThread; 
    2930        NSFileHandle *_fileHandle; 
  • branches/cocoa-networking/Chat Core/MVIRCFileTransfer.m

    r3102 r3103  
    110110                        passiveId = 1; 
    111111                ret->_passiveId = passiveId; 
     112 
     113                if( ret->_fileNameQuoted ) [user sendSubcodeRequest:@"DCC" withArguments:[NSString stringWithFormat:@"SEND \"%@\" 16843009 0 %llu %luT", fileName, [ret finalSize], passiveId]]; 
     114                else [user sendSubcodeRequest:@"DCC" withArguments:[NSString stringWithFormat:@"SEND %@ 16843009 0 %llu %luT", fileName, [ret finalSize], passiveId]]; 
    112115        } else { 
    113116                [ret _setupAndStart]; 
     
    124127 
    125128- (void) dealloc { 
    126         NSLog(@"u/l dealloc" ); 
    127129        id old = _fileHandle; 
    128130        _fileHandle = nil; 
     
    151153 
    152154- (void) socket:(AsyncSocket *) sock didAcceptNewSocket:(AsyncSocket *) newSocket { 
    153         if( ! _clientConnection ) _clientConnection = [newSocket retain]; 
     155        if( ! _connection ) _connection = [newSocket retain]; 
    154156        else [newSocket disconnect]; 
    155157} 
     
    178180 
    179181        [self _sendNextPacket]; 
    180         [_clientConnection readDataToLength:4 withTimeout:-1. tag:0]; 
     182        [_connection readDataToLength:4 withTimeout:-1. tag:0]; 
    181183 
    182184        // now that we are connected deregister with the connection 
     
    202204 
    203205        [self _setTransfered:bytes]; 
    204         [_clientConnection readDataToLength:4 withTimeout:-1. tag:0]; 
     206        [_connection readDataToLength:4 withTimeout:-1. tag:0]; 
    205207 
    206208        if( bytes == ( [self finalSize] & 0xffffffff ) ) { 
     
    232234        while( ! _connectionThread ) sched_yield(); 
    233235 
    234         if( ! [self isPassive] ) [self performSelector:@selector( _waitForConnection ) inThread:_connectionThread];      
     236        if( ! [self isPassive] ) [self performSelector:@selector( _waitForConnection ) inThread:_connectionThread]; 
     237        else [self performSelector:@selector( _connect ) inThread:_connectionThread]; 
    235238} 
    236239 
    237240- (void) _waitForConnection { 
    238         [_connection release]; 
    239         _connection = [[AsyncSocket allocWithZone:nil] initWithDelegate:self]; 
     241        _acceptConnection = [[AsyncSocket allocWithZone:nil] initWithDelegate:self]; 
    240242 
    241243        unsigned int port = portRange.location; 
    242244        BOOL success = NO; 
    243245        while( ! success ) { 
    244                 if( [_connection acceptOnPort:port error:NULL] ) { 
     246                if( [_acceptConnection acceptOnPort:port error:NULL] ) { 
    245247                        success = YES; 
    246248                        break; 
    247249                } else { 
    248                         [_connection disconnect]; 
     250                        [_acceptConnection disconnect]; 
    249251                        if( ++port > NSMaxRange( portRange ) ) 
    250252                                port = 0; // just use a random port since the user defined range is in use 
     
    256258                if( [address rangeOfString:@"."].location != NSNotFound ) 
    257259                        address = [NSNumber numberWithUnsignedLong:ntohl( inet_addr( [address UTF8String] ) )]; 
    258                 [self _setPort:[_connection localPort]]; 
     260                [self _setPort:[_acceptConnection localPort]]; 
    259261 
    260262                NSString *fileName = [[self source] lastPathComponent]; 
     
    264266} 
    265267 
     268- (void) _connect { 
     269        _connection = [[AsyncSocket allocWithZone:nil] initWithDelegate:self]; 
     270 
     271        if( ! [_connection connectToHost:[[self host] address] onPort:[self port] error:NULL] ) { 
     272                NSLog(@"can't connect to DCC" ); 
     273                return; 
     274        } 
     275} 
     276 
    266277- (void) _sendNextPacket { 
    267278        NSData *data = [_fileHandle readDataOfLength:DCCPacketSize]; 
    268         if( [data length] > 0 ) [_clientConnection writeData:data withTimeout:-1 tag:[data length]]; 
     279        if( [data length] > 0 ) [_connection writeData:data withTimeout:-1 tag:[data length]]; 
    269280        else _doneSending = YES; 
    270281} 
     
    273284        [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector( _finish ) object:nil];        
    274285 
    275         id old = _connection; 
    276         _connection = nil; 
     286        id old = _acceptConnection; 
     287        _acceptConnection = nil; 
    277288        [old setDelegate:nil]; 
    278289        [old disconnect]; 
    279290        [old release]; 
    280291 
    281         old = _clientConnection; 
    282         _clientConnection = nil; 
     292        old = _connection; 
     293        _connection = nil; 
    283294        [old setDelegate:nil]; 
    284295        [old disconnect]; 
     
    331342 
    332343- (void) dealloc { 
    333         NSLog(@"d/l dealloc" ); 
    334344        id old = _fileHandle; 
    335345        _fileHandle = nil; 
     
    385395#pragma mark - 
    386396 
     397- (void) socket:(AsyncSocket *) sock didAcceptNewSocket:(AsyncSocket *) newSocket { 
     398        if( ! _connection ) _connection = [newSocket retain]; 
     399        else [newSocket disconnect]; 
     400} 
     401 
    387402- (void) socket:(AsyncSocket *) sock willDisconnectWithError:(NSError *) error { 
    388403        NSLog(@"download DCC willDisconnectWithError: %@", error ); 
     
    460475        while( ! _connectionThread ) sched_yield(); 
    461476 
    462         [self performSelector:@selector( _connect ) inThread:_connectionThread];         
     477        if( ! [self isPassive] ) [self performSelector:@selector( _connect ) inThread:_connectionThread]; 
     478        else [self performSelector:@selector( _waitForConnection ) inThread:_connectionThread]; 
    463479} 
    464480 
     
    472488} 
    473489 
     490- (void) _waitForConnection { 
     491        _acceptConnection = [[AsyncSocket allocWithZone:nil] initWithDelegate:self]; 
     492 
     493        unsigned int port = portRange.location; 
     494        BOOL success = NO; 
     495        while( ! success ) { 
     496                if( [_acceptConnection acceptOnPort:port error:NULL] ) { 
     497                        success = YES; 
     498                        break; 
     499                } else { 
     500                        [_acceptConnection disconnect]; 
     501                        if( ++port > NSMaxRange( portRange ) ) 
     502                                port = 0; // just use a random port since the user defined range is in use 
     503                } 
     504        } 
     505 
     506        if( success ) { 
     507                id address = [[(MVIRCChatConnection *)[[self user] connection] _chatConnection] localHost]; 
     508                if( [address rangeOfString:@"."].location != NSNotFound ) 
     509                        address = [NSNumber numberWithUnsignedLong:ntohl( inet_addr( [address UTF8String] ) )]; 
     510                [self _setPort:[_acceptConnection localPort]]; 
     511 
     512                if( _fileNameQuoted ) [[self user] sendSubcodeRequest:@"DCC" withArguments:[NSString stringWithFormat:@"SEND \"%@\" %@ %hu %llu %lu", [self originalFileName], address, [self port], [self finalSize], [self _passiveIdentifier]]]; 
     513                else [[self user] sendSubcodeRequest:@"DCC" withArguments:[NSString stringWithFormat:@"SEND %@ %@ %hu %llu %lu", [self originalFileName], address, [self port], [self finalSize], [self _passiveIdentifier]]]; 
     514        } else _done = YES; 
     515} 
     516 
    474517- (void) _finish { 
    475518        [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector( _finish ) object:nil];        
     
    477520        id old = _connection; 
    478521        _connection = nil; 
     522        [old setDelegate:nil]; 
     523        [old disconnect]; 
     524        [old release]; 
     525 
     526        old = _acceptConnection; 
     527        _acceptConnection = nil; 
    479528        [old setDelegate:nil]; 
    480529        [old disconnect];