Changeset 3102
- Timestamp:
- 12/31/05 03:01:21 (3 years ago)
- Files:
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
branches/cocoa-networking/Chat Core/MVIRCChatConnection.m
r3101 r3102 1465 1465 NSString *msg = [[NSString allocWithZone:nil] initWithData:arguments encoding:[self encoding]]; 1466 1466 NSArray *parameters = [msg componentsSeparatedByString:@" "]; 1467 [msg release];1468 1467 1469 1468 if( [parameters count] >= 5 && [[parameters objectAtIndex:0] caseInsensitiveCompare:@"SEND"] == NSOrderedSame ) { … … 1482 1481 1483 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"]]; 1490 } 1491 1484 1492 [transfer _setOriginalFileName:[parameters objectAtIndex:1]]; 1485 1493 [transfer _setFinalSize:(unsigned long long)size]; 1486 1494 [transfer _setHost:host]; 1487 1495 [transfer _setPort:port]; 1496 1488 1497 [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadWithName:MVDownloadFileTransferOfferNotification object:transfer]; 1498 1489 1499 [self _addFileTransfer:transfer]; 1490 1500 [transfer release]; 1491 1501 } else if( [parameters count] >= 4 && [[parameters objectAtIndex:0] caseInsensitiveCompare:@"ACCEPT"] == NSOrderedSame ) { 1502 BOOL passive = NO; 1492 1503 long long size = 0; 1493 1504 unsigned int port = [[parameters objectAtIndex:2] intValue]; … … 1495 1506 [scanner scanLongLong:&size]; 1496 1507 1508 if( [parameters count] >= 5 ) { 1509 passive = YES; 1510 port = [[parameters objectAtIndex:4] intValue]; 1511 } 1512 1497 1513 @synchronized( _fileTransfers ) { 1498 1514 NSEnumerator *enumerator = [_fileTransfers objectEnumerator]; 1499 1515 MVFileTransfer *transfer = nil; 1500 1516 while( ( transfer = [enumerator nextObject] ) ) { 1501 if( [transfer isDownload] && [[transfer user] isEqualToChatUser:sender] && [transfer port] == port ) { 1517 if( [transfer isDownload] && [transfer isPassive] == passive && [[transfer user] isEqualToChatUser:sender] && 1518 ( ! passive ? [transfer port] == port : [(id)transfer _passiveIdentifier] == port ) ) { 1502 1519 [transfer _setTransfered:(unsigned long long)size]; 1503 1520 [transfer _setStartOffset:(unsigned long long)size]; … … 1506 1523 } 1507 1524 } 1525 } else if( [parameters count] >= 4 && [[parameters objectAtIndex:0] caseInsensitiveCompare:@"RESUME"] == NSOrderedSame ) { 1526 BOOL passive = NO; 1527 long long size = 0; 1528 unsigned int port = [[parameters objectAtIndex:2] intValue]; 1529 NSScanner *scanner = [NSScanner scannerWithString:[parameters objectAtIndex:3]]; 1530 [scanner scanLongLong:&size]; 1531 1532 if( [parameters count] >= 5 ) { 1533 passive = YES; 1534 port = [[parameters objectAtIndex:4] intValue]; 1535 } 1536 1537 @synchronized( _fileTransfers ) { 1538 NSEnumerator *enumerator = [_fileTransfers objectEnumerator]; 1539 MVFileTransfer *transfer = nil; 1540 while( ( transfer = [enumerator nextObject] ) ) { 1541 if( [transfer isUpload] && [transfer isPassive] == passive && [[transfer user] isEqualToChatUser:sender] && 1542 ( ! passive ? [transfer port] == port : [(id)transfer _passiveIdentifier] == port ) ) { 1543 [transfer _setTransfered:(unsigned long long)size]; 1544 [transfer _setStartOffset:(unsigned long long)size]; 1545 [sender sendSubcodeRequest:@"DCC ACCEPT" withArguments:[msg substringFromIndex:7]]; 1546 } 1547 } 1548 } 1508 1549 } 1550 1551 [msg release]; 1509 1552 } else if( [command caseInsensitiveCompare:@"CLIENTINFO"] == NSOrderedSame ) { 1510 1553 // make this extnesible later with a plugin registration method branches/cocoa-networking/Chat Core/MVIRCFileTransfer.h
r3101 r3102 11 11 NSFileHandle *_fileHandle; 12 12 BOOL _fileNameQuoted; 13 BOOL _readData; 14 BOOL _doneSending; 13 15 BOOL _done; 14 16 unsigned int _passiveId; … … 17 19 - (void) _sendNextPacket; 18 20 - (void) _finish; 21 - (unsigned int) _passiveIdentifier; 19 22 @end 20 23 … … 27 30 BOOL _fileNameQuoted; 28 31 BOOL _done; 32 BOOL _turbo; 29 33 unsigned int _passiveId; 30 34 } 31 35 - (void) _setupAndStart; 32 36 - (void) _finish; 37 - (void) _setTurbo:(BOOL) turbo; 38 - (void) _setPassiveIdentifier:(unsigned int) identifier; 39 - (unsigned int) _passiveIdentifier; 33 40 @end branches/cocoa-networking/Chat Core/MVIRCFileTransfer.m
r3101 r3102 124 124 125 125 - (void) dealloc { 126 NSLog(@"u/l dealloc" ); 126 127 id old = _fileHandle; 127 128 _fileHandle = nil; … … 137 138 [self _setStatus:MVFileTransferStoppedStatus]; 138 139 139 [self performSelector:@selector( _finish ) inThread:_connectionThread];140 _done = YES; // the thread will disconnect when it ends 140 141 141 142 id old = _fileHandle; … … 156 157 - (void) socket:(AsyncSocket *) sock willDisconnectWithError:(NSError *) error { 157 158 NSLog(@"upload DCC willDisconnectWithError: %@", error ); 158 [self _setStatus:MVFileTransferErrorStatus]; 159 if( [self status] != MVFileTransferDoneStatus && [self status] != MVFileTransferStoppedStatus ) 160 [self _setStatus:MVFileTransferErrorStatus]; 159 161 } 160 162 … … 168 170 [old release]; 169 171 170 [self _finish];172 _done = YES; 171 173 } 172 174 … … 174 176 [self _setStatus:MVFileTransferNormalStatus]; 175 177 [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadWithName:MVFileTransferStartedNotification object:self]; 178 176 179 [self _sendNextPacket]; 180 [_clientConnection readDataToLength:4 withTimeout:-1. tag:0]; 177 181 178 182 // now that we are connected deregister with the connection … … 182 186 183 187 - (void) socket:(AsyncSocket *) sock didWriteDataWithTag:(long) tag { 184 unsigned long long progress = [self transfered] + tag; 185 [self _setTransfered:progress]; 186 187 [_clientConnection readDataToLength:4 withTimeout:-1. tag:( progress == [self finalSize] )]; 188 if( progress < [self finalSize] ) [self _sendNextPacket]; 188 if( ! _readData || [_fileHandle offsetInFile] > 0xffffffff ) { 189 unsigned long long progress = [self transfered] + tag; 190 [self _setTransfered:progress]; 191 if( progress == [self finalSize] ) { 192 [self _setStatus:MVFileTransferDoneStatus]; 193 [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadWithName:MVFileTransferFinishedNotification object:self]; 194 } 195 } 196 197 if( ! _doneSending ) [self _sendNextPacket]; 189 198 } 190 199 191 200 - (void) socket:(AsyncSocket *) sock didReadData:(NSData *) data withTag:(long) tag { 192 if( tag ) { 201 unsigned long bytes = ntohl( *( (unsigned long *) [data bytes] ) ); 202 203 [self _setTransfered:bytes]; 204 [_clientConnection readDataToLength:4 withTimeout:-1. tag:0]; 205 206 if( bytes == ( [self finalSize] & 0xffffffff ) ) { 193 207 [self _setStatus:MVFileTransferDoneStatus]; 194 208 [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadWithName:MVFileTransferFinishedNotification object:self]; 195 [self _finish]; 196 } 209 [_connection disconnectAfterWriting]; 210 _done = YES; 211 } 212 213 _readData = YES; 197 214 } 198 215 … … 200 217 201 218 - (void) _setupAndStart { 219 if( _connectionThread ) return; 220 202 221 BOOL directory = NO; 203 222 BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:[self source] isDirectory:&directory]; 204 223 if( directory || ! fileExists ) return; 205 224 206 id old = _fileHandle;225 [_fileHandle release]; 207 226 _fileHandle = [[NSFileHandle fileHandleForReadingAtPath:[self source]] retain]; 208 [old release];209 210 227 if( ! _fileHandle ) return; 211 228 [_fileHandle seekToFileOffset:[self startOffset]]; 212 229 213 old = _connection; 230 [NSThread prepareForInterThreadMessages]; 231 [NSThread detachNewThreadSelector:@selector( _dccRunloop ) toTarget:self withObject:nil]; 232 while( ! _connectionThread ) sched_yield(); 233 234 if( ! [self isPassive] ) [self performSelector:@selector( _waitForConnection ) inThread:_connectionThread]; 235 } 236 237 - (void) _waitForConnection { 238 [_connection release]; 214 239 _connection = [[AsyncSocket allocWithZone:nil] initWithDelegate:self]; 215 [old release]; 216 217 if( ! _connectionThread ) { 218 [NSThread prepareForInterThreadMessages]; 219 [NSThread detachNewThreadSelector:@selector( _dccRunloop ) toTarget:self withObject:nil]; 220 while( ! _connectionThread ) sched_yield(); 221 } 222 223 if( ! [self isPassive] ) [self performSelector:@selector( _waitForConnection ) inThread:_connectionThread]; 224 } 225 226 - (void) _waitForConnection { 240 227 241 unsigned int port = portRange.location; 228 242 BOOL success = NO; … … 245 259 246 260 NSString *fileName = [[self source] lastPathComponent]; 247 if( _fileNameQuoted ) [[self user] sendSubcodeRequest:@"DCC" withArguments:[NSString stringWithFormat:@"SEND \"%@\" %@ %hu %llu ", fileName, address, [self port], [self finalSize]]];248 else [[self user] sendSubcodeRequest:@"DCC" withArguments:[NSString stringWithFormat:@"SEND %@ %@ %hu %llu ", fileName, address, [self port], [self finalSize]]];249 } 261 if( _fileNameQuoted ) [[self user] sendSubcodeRequest:@"DCC" withArguments:[NSString stringWithFormat:@"SEND \"%@\" %@ %hu %llu T", fileName, address, [self port], [self finalSize]]]; 262 else [[self user] sendSubcodeRequest:@"DCC" withArguments:[NSString stringWithFormat:@"SEND %@ %@ %hu %llu T", fileName, address, [self port], [self finalSize]]]; 263 } else _done = YES; 250 264 } 251 265 252 266 - (void) _sendNextPacket { 253 267 NSData *data = [_fileHandle readDataOfLength:DCCPacketSize]; 254 255 if( [data length] > 0 ) { 256 [_clientConnection writeData:data withTimeout:-1 tag:[data length]]; 257 } else { 258 [self _setStatus:MVFileTransferErrorStatus]; 259 [self _finish]; 260 } 268 if( [data length] > 0 ) [_clientConnection writeData:data withTimeout:-1 tag:[data length]]; 269 else _doneSending = YES; 261 270 } 262 271 263 272 - (void) _finish { 273 [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector( _finish ) object:nil]; 274 264 275 id old = _connection; 265 276 _connection = nil; 266 277 [old setDelegate:nil]; 278 [old disconnect]; 267 279 [old release]; 268 280 … … 270 282 _clientConnection = nil; 271 283 [old setDelegate:nil]; 284 [old disconnect]; 272 285 [old release]; 273 286 … … 290 303 } 291 304 292 _connectionThread = nil;293 294 305 [self _finish]; 295 306 [self release]; 296 307 308 _connectionThread = nil; 309 297 310 [pool release]; 311 } 312 313 - (unsigned int) _passiveIdentifier { 314 return _passiveId; 315 } 316 317 - (void) _setStartOffset:(unsigned long long) startOffset { 318 [_fileHandle seekToFileOffset:startOffset]; 319 [super _setStartOffset:startOffset]; 298 320 } 299 321 @end … … 309 331 310 332 - (void) dealloc { 333 NSLog(@"d/l dealloc" ); 311 334 id old = _fileHandle; 312 335 _fileHandle = nil; … … 329 352 [self _setStatus:MVFileTransferStoppedStatus]; 330 353 331 [self performSelector:@selector( _finish ) inThread:_connectionThread];354 _done = YES; // the thread will disconnect when it ends 332 355 333 356 id old = _fileHandle; 334 357 _fileHandle = nil; 358 [old synchronizeFile]; 335 359 [old closeFile]; 336 360 [old release]; … … 363 387 - (void) socket:(AsyncSocket *) sock willDisconnectWithError:(NSError *) error { 364 388 NSLog(@"download DCC willDisconnectWithError: %@", error ); 365 [self _setStatus:MVFileTransferErrorStatus]; 389 if( [self status] != MVFileTransferDoneStatus && [self status] != MVFileTransferStoppedStatus ) 390 [self _setStatus:MVFileTransferErrorStatus]; 366 391 } 367 392 … … 384 409 [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadWithName:MVFileTransferStartedNotification object:self]; 385 410 386 unsigned long long progress = [self transfered]; 387 unsigned long long packet = DCCPacketSize; 388 if( ( progress + packet ) > [self finalSize] ) 389 packet = [self finalSize] - progress; 390 [_connection readDataToLength:packet withTimeout:-1. tag:0]; 411 [_connection readDataWithTimeout:-1. tag:0]; 391 412 392 413 // now that we are connected deregister with the connection … … 399 420 [self _setTransfered:progress]; 400 421 401 // dcc only supports a 2 GB limit with these acknowledgment packets, we will acknowledge402 // that we have all the bytes but keep reading if the file is over 2 GB403 unsigned long progressToSend = htonl( progress & 0xffffffff );404 NSData *length = [[NSData allocWithZone:nil] initWithBytes:&progressToSend length:4];405 [_connection writeData:length withTimeout:-1 tag:0];406 [length release];407 408 422 [_fileHandle writeData:data]; 409 423 410 if( progress < [self finalSize] ) { 411 unsigned long long packet = DCCPacketSize; 412 if( ( progress + packet ) > [self finalSize] ) 413 packet = [self finalSize] - progress; 414 [_connection readDataToLength:packet withTimeout:-1. tag:0]; 415 } else { 424 if( ! _turbo ) { 425 // dcc only supports a 4 GB limit with these acknowledgment packets, we will acknowledge 426 // that we have all the bytes but keep reading if the file is over 4 GB 427 unsigned long progressToSend = htonl( progress & 0xffffffff ); 428 NSData *length = [[NSData allocWithZone:nil] initWithBytes:&progressToSend length:4]; 429 [_connection writeData:length withTimeout:-1 tag:0]; 430 [length release]; 431 } 432 433 if( progress == [self finalSize] ) { 416 434 [self _setStatus:MVFileTransferDoneStatus]; 417 435 [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadWithName:MVFileTransferFinishedNotification object:self]; 418 [_connection disconnect ];436 [_connection disconnectAfterWriting]; 419 437 _done = YES; 420 } 438 } else [_connection readDataWithTimeout:-1. tag:0]; 421 439 } 422 440 … … 424 442 425 443 - (void) _setupAndStart { 444 if( _connectionThread ) return; 445 426 446 BOOL directory = NO; 427 447 BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:[self destination] isDirectory:&directory]; … … 431 451 if( ! fileExists ) return; 432 452 433 id old = _fileHandle;453 [_fileHandle release]; 434 454 _fileHandle = [[NSFileHandle fileHandleForWritingAtPath:[self destination]] retain]; 435 [old release];436 437 455 if( ! _fileHandle ) return; 438 456 [_fileHandle truncateFileAtOffset:[self startOffset]]; 439 457 440 old = _connection; 458 [NSThread prepareForInterThreadMessages]; 459 [NSThread detachNewThreadSelector:@selector( _dccRunloop ) toTarget:self withObject:nil]; 460 while( ! _connectionThread ) sched_yield(); 461 462 [self performSelector:@selector( _connect ) inThread:_connectionThread]; 463 } 464 465 - (void) _connect { 441 466 _connection = [[AsyncSocket allocWithZone:nil] initWithDelegate:self]; 442 [old release]; 443 444 if( ! _connectionThread ) { 445 [NSThread prepareForInterThreadMessages]; 446 [NSThread detachNewThreadSelector:@selector( _dccRunloop ) toTarget:self withObject:nil]; 447 while( ! _connectionThread ) sched_yield(); 448 } 449 450 [self performSelector:@selector( _connect ) inThread:_connectionThread]; 451 } 452 453 - (void) _connect { 467 454 468 if( ! [_connection connectToHost:[[self host] address] onPort:[self port] error:NULL] ) { 455 469 NSLog(@"can't connect to DCC" ); … … 459 473 460 474 - (void) _finish { 475 [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector( _finish ) object:nil]; 476 461 477 id old = _connection; 462 478 _connection = nil; 463 479 [old setDelegate:nil]; 480 [old disconnect]; 464 481 [old release]; 465 482 … … 482 499 } 483 500 484 _connectionThread = nil;485 486 501 [self _finish]; 487 502 [self release]; 488 503 504 _connectionThread = nil; 505 489 506 [pool release]; 490 507 } 508 509 - (void) _setTurbo:(BOOL) turbo { 510 _turbo = turbo; 511 } 512 513 - (void) _setPassiveIdentifier:(unsigned int) identifier { 514 _passiveId = identifier; 515 } 516 517 - (unsigned int) _passiveIdentifier { 518 return _passiveId; 519 } 491 520 @end
