1/** Implementation for GSStream for GNUStep 2 Copyright (C) 2006 Free Software Foundation, Inc. 3 4 Written by: Derek Zhou <derekzhou@gmail.com> 5 Written by: Richard Frith-Macdonald <rfm@gnu.org> 6 Date: 2006 7 8 This library is free software; you can redistribute it and/or 9 modify it under the terms of the GNU Lesser General Public 10 License as published by the Free Software Foundation; either 11 version 2 of the License, or (at your option) any later version. 12 13 This library is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 Lesser General Public License for more details. 17 18 You should have received a copy of the GNU Lesser General Public 19 License along with this library; if not, write to the Free 20 Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 21 Boston, MA 02110 USA. 22 23 */ 24 25#import "common.h" 26 27#import "Foundation/NSArray.h" 28#import "Foundation/NSByteOrder.h" 29#import "Foundation/NSData.h" 30#import "Foundation/NSDictionary.h" 31#import "Foundation/NSEnumerator.h" 32#import "Foundation/NSException.h" 33#import "Foundation/NSHost.h" 34#import "Foundation/NSRunLoop.h" 35#import "Foundation/NSValue.h" 36 37#import "GSStream.h" 38#import "GSPrivate.h" 39#import "GSSocketStream.h" 40 41NSString * const NSStreamDataWrittenToMemoryStreamKey 42 = @"NSStreamDataWrittenToMemoryStreamKey"; 43NSString * const NSStreamFileCurrentOffsetKey 44 = @"NSStreamFileCurrentOffsetKey"; 45 46NSString * const NSStreamSocketSecurityLevelKey 47 = @"NSStreamSocketSecurityLevelKey"; 48NSString * const NSStreamSocketSecurityLevelNone 49 = @"NSStreamSocketSecurityLevelNone"; 50NSString * const NSStreamSocketSecurityLevelSSLv2 51 = @"NSStreamSocketSecurityLevelSSLv2"; 52NSString * const NSStreamSocketSecurityLevelSSLv3 53 = @"NSStreamSocketSecurityLevelSSLv3"; 54NSString * const NSStreamSocketSecurityLevelTLSv1 55 = @"NSStreamSocketSecurityLevelTLSv1"; 56NSString * const NSStreamSocketSecurityLevelNegotiatedSSL 57 = @"NSStreamSocketSecurityLevelNegotiatedSSL"; 58NSString * const NSStreamSocketSSLErrorDomain 59 = @"NSStreamSocketSSLErrorDomain"; 60NSString * const NSStreamSOCKSErrorDomain 61 = @"NSStreamSOCKSErrorDomain"; 62NSString * const NSStreamSOCKSProxyConfigurationKey 63 = @"NSStreamSOCKSProxyConfigurationKey"; 64NSString * const NSStreamSOCKSProxyHostKey 65 = @"NSStreamSOCKSProxyHostKey"; 66NSString * const NSStreamSOCKSProxyPasswordKey 67 = @"NSStreamSOCKSProxyPasswordKey"; 68NSString * const NSStreamSOCKSProxyPortKey 69 = @"NSStreamSOCKSProxyPortKey"; 70NSString * const NSStreamSOCKSProxyUserKey 71 = @"NSStreamSOCKSProxyUserKey"; 72NSString * const NSStreamSOCKSProxyVersion4 73 = @"NSStreamSOCKSProxyVersion4"; 74NSString * const NSStreamSOCKSProxyVersion5 75 = @"NSStreamSOCKSProxyVersion5"; 76NSString * const NSStreamSOCKSProxyVersionKey 77 = @"NSStreamSOCKSProxyVersionKey"; 78 79 80/* 81 * Determine the type of event to use when adding a stream to the run loop. 82 * By default add as an 'ET_TRIGGER' so that the stream will be notified 83 * every time the loop runs (the event id/reference must be the address of 84 * the stream itsself to ensure that event/type is unique). 85 * 86 * Streams which actually expect to wait for I/O events must be added with 87 * the appropriate information for the loop to signal them. 88 */ 89static RunLoopEventType typeForStream(NSStream *aStream) 90{ 91 NSStreamStatus status = [aStream streamStatus]; 92 93 if (NSStreamStatusError == status 94 || [aStream _loopID] == (void*)aStream) 95 { 96 return ET_TRIGGER; 97 } 98#if defined(_WIN32) 99 return ET_HANDLE; 100#else 101 if ([aStream isKindOfClass: [NSOutputStream class]] == NO 102 && status != NSStreamStatusOpening) 103 { 104 return ET_RDESC; 105 } 106 return ET_WDESC; 107#endif 108} 109 110@implementation NSRunLoop (NSStream) 111- (void) addStream: (NSStream*)aStream mode: (NSString*)mode 112{ 113 RunLoopEventType type = typeForStream(aStream); 114 void *event = [aStream _loopID]; 115 116 NSDebugMLLog(@"NSStream", 117 @"-addStream:mode: %@ (desc %d,%d) to %@ mode %@", 118 aStream, (int)(intptr_t)event, type, self, mode); 119 [self addEvent: event 120 type: type 121 watcher: (id<RunLoopEvents>)aStream 122 forMode: mode]; 123} 124 125- (void) removeStream: (NSStream*)aStream mode: (NSString*)mode 126{ 127 RunLoopEventType type = typeForStream(aStream); 128 void *event = [aStream _loopID]; 129 130 NSDebugMLLog(@"NSStream", 131 @"-removeStream:mode: %@ (desc %d,%d) from %@ mode %@", 132 aStream, (int)(intptr_t)event, type, self, mode); 133 /* We may have added the stream more than once (eg if the stream -open 134 * method was called more than once, so we need to remove all event 135 * registrations. 136 */ 137 [self removeEvent: event 138 type: type 139 forMode: mode 140 all: YES]; 141} 142@end 143 144@implementation GSStream 145 146+ (void) initialize 147{ 148 GSMakeWeakPointer(self, "delegate"); 149} 150 151- (void) close 152{ 153 if (_currentStatus == NSStreamStatusNotOpen) 154 { 155 NSDebugMLLog(@"NSStream", @"Attempt to close unopened stream %@", self); 156 } 157 [self _unschedule]; 158 [self _setStatus: NSStreamStatusClosed]; 159 /* We don't want to send any events to the delegate after the 160 * stream has been closed. 161 */ 162 _delegateValid = NO; 163} 164 165- (void) finalize 166{ 167 if (_currentStatus != NSStreamStatusNotOpen 168 && _currentStatus != NSStreamStatusClosed) 169 { 170 [self close]; 171 } 172 GSAssignZeroingWeakPointer((void**)&_delegate, (void*)0); 173} 174 175- (void) dealloc 176{ 177 [self finalize]; 178 if (_loops != 0) 179 { 180 NSFreeMapTable(_loops); 181 _loops = 0; 182 } 183 DESTROY(_properties); 184 DESTROY(_lastError); 185 [super dealloc]; 186} 187 188- (id) delegate 189{ 190 return _delegate; 191} 192 193- (id) init 194{ 195 if ((self = [super init]) != nil) 196 { 197 _delegate = self; 198 _properties = nil; 199 _lastError = nil; 200 _loops = NSCreateMapTable(NSObjectMapKeyCallBacks, 201 NSObjectMapValueCallBacks, 1); 202 _currentStatus = NSStreamStatusNotOpen; 203 _loopID = (void*)self; 204 } 205 return self; 206} 207 208- (void) open 209{ 210 if (_currentStatus != NSStreamStatusNotOpen 211 && _currentStatus != NSStreamStatusOpening) 212 { 213 NSDebugMLLog(@"NSStream", @"Attempt to re-open stream %@", self); 214 } 215 [self _setStatus: NSStreamStatusOpen]; 216 [self _schedule]; 217 [self _sendEvent: NSStreamEventOpenCompleted]; 218} 219 220- (id) propertyForKey: (NSString *)key 221{ 222 return [_properties objectForKey: key]; 223} 224 225- (void) receivedEvent: (void*)data 226 type: (RunLoopEventType)type 227 extra: (void*)extra 228 forMode: (NSString*)mode 229{ 230// NSDebugMLLog(@"NSStream", @"receivedEvent for %@ - %d", self, type); 231 [self _dispatch]; 232} 233 234- (void) removeFromRunLoop: (NSRunLoop *)aRunLoop forMode: (NSString *)mode 235{ 236 if (aRunLoop != nil && mode != nil) 237 { 238 NSMutableArray *modes; 239 240 modes = (NSMutableArray*)NSMapGet(_loops, (void*)aRunLoop); 241 if ([modes containsObject: mode]) 242 { 243 [aRunLoop removeStream: self mode: mode]; 244 [modes removeObject: mode]; 245 if ([modes count] == 0) 246 { 247 NSMapRemove(_loops, (void*)aRunLoop); 248 } 249 } 250 } 251} 252 253- (void) scheduleInRunLoop: (NSRunLoop *)aRunLoop forMode: (NSString *)mode 254{ 255 if (aRunLoop != nil && mode != nil) 256 { 257 NSMutableArray *modes; 258 259 modes = (NSMutableArray*)NSMapGet(_loops, (void*)aRunLoop); 260 if (modes == nil) 261 { 262 modes = [[NSMutableArray alloc] initWithCapacity: 1]; 263 NSMapInsert(_loops, (void*)aRunLoop, (void*)modes); 264 RELEASE(modes); 265 } 266 if ([modes containsObject: mode] == NO) 267 { 268 mode = [mode copy]; 269 [modes addObject: mode]; 270 RELEASE(mode); 271 /* We only add open streams to the runloop .. subclasses may add 272 * streams when they are in the process of opening if they need 273 * to do so. 274 */ 275 if ([self _isOpened]) 276 { 277 [aRunLoop addStream: self mode: mode]; 278 } 279 } 280 } 281} 282 283- (void) setDelegate: (id)delegate 284{ 285 if ([self streamStatus] == NSStreamStatusClosed 286 || [self streamStatus] == NSStreamStatusError) 287 { 288 _delegateValid = NO; 289 GSAssignZeroingWeakPointer((void**)&_delegate, (void*)0); 290 } 291 else 292 { 293 if (delegate == nil) 294 { 295 _delegate = self; 296 } 297 if (delegate == self) 298 { 299 if (_delegate != nil && _delegate != self) 300 { 301 GSAssignZeroingWeakPointer((void**)&_delegate, (void*)0); 302 } 303 _delegate = delegate; 304 } 305 else 306 { 307 GSAssignZeroingWeakPointer((void**)&_delegate, (void*)delegate); 308 } 309 /* We don't want to send any events the the delegate after the 310 * stream has been closed. 311 */ 312 _delegateValid 313 = [_delegate respondsToSelector: @selector(stream:handleEvent:)]; 314 } 315} 316 317- (BOOL) setProperty: (id)property forKey: (NSString *)key 318{ 319 if (_properties == nil) 320 { 321 _properties = [NSMutableDictionary new]; 322 } 323 [_properties setObject: property forKey: key]; 324 return YES; 325} 326 327- (NSError *) streamError 328{ 329 return _lastError; 330} 331 332- (NSStreamStatus) streamStatus 333{ 334 return _currentStatus; 335} 336 337- (NSString*) _stringFromEvents 338{ 339 NSMutableString *s = [NSMutableString stringWithCapacity: 100]; 340 341 if (_events & NSStreamEventOpenCompleted) 342 [s appendString: @"|NSStreamEventOpenCompleted"]; 343 if (_events & NSStreamEventHasBytesAvailable) 344 [s appendString: @"|NSStreamEventHasBytesAvailable"]; 345 if (_events & NSStreamEventHasSpaceAvailable) 346 [s appendString: @"|NSStreamEventHasSpaceAvailable"]; 347 if (_events & NSStreamEventErrorOccurred) 348 [s appendString: @"|NSStreamEventErrorOccurred"]; 349 if (_events & NSStreamEventEndEncountered) 350 [s appendString: @"|NSStreamEventEndEncountered"]; 351 return s; 352} 353 354@end 355 356 357@implementation NSStream (Private) 358 359- (void) _dispatch 360{ 361} 362 363- (BOOL) _isOpened 364{ 365 return NO; 366} 367 368- (void*) _loopID 369{ 370 return (void*)self; // By default a stream is a TRIGGER event. 371} 372 373- (void) _recordError 374{ 375} 376 377- (void) _recordError: (NSError*)anError 378{ 379 return; 380} 381 382- (void) _resetEvents: (NSUInteger)mask 383{ 384 return; 385} 386 387- (void) _schedule 388{ 389} 390 391- (void) _sendEvent: (NSStreamEvent)event 392{ 393} 394 395- (void) _sendEvent: (NSStreamEvent)event delegate: (id)delegate 396{ 397} 398 399- (void) _setLoopID: (void *)ref 400{ 401} 402 403- (void) _setStatus: (NSStreamStatus)newStatus 404{ 405} 406 407- (BOOL) _unhandledData 408{ 409 return NO; 410} 411 412- (void) _unschedule 413{ 414} 415 416- (NSString*) stringFromEvent: (NSStreamEvent)e 417{ 418 switch (e) 419 { 420 case NSStreamEventNone: 421 return @"NSStreamEventNone"; 422 case NSStreamEventOpenCompleted: 423 return @"NSStreamEventOpenCompleted"; 424 case NSStreamEventHasBytesAvailable: 425 return @"NSStreamEventHasBytesAvailable"; 426 case NSStreamEventHasSpaceAvailable: 427 return @"NSStreamEventHasSpaceAvailable"; 428 case NSStreamEventErrorOccurred: 429 return @"NSStreamEventErrorOccurred"; 430 case NSStreamEventEndEncountered: 431 return @"NSStreamEventEndEncountered"; 432 default: 433 return [NSString stringWithFormat: 434 @"NSStreamEventValue%ld", (long)e]; 435 } 436} 437 438- (NSString*) stringFromStatus: (NSStreamStatus)s 439{ 440 switch (s) 441 { 442 case NSStreamStatusNotOpen: return @"NSStreamStatusNotOpen"; 443 case NSStreamStatusOpening: return @"NSStreamStatusOpening"; 444 case NSStreamStatusOpen: return @"NSStreamStatusOpen"; 445 case NSStreamStatusReading: return @"NSStreamStatusReading"; 446 case NSStreamStatusWriting: return @"NSStreamStatusWriting"; 447 case NSStreamStatusAtEnd: return @"NSStreamStatusAtEnd"; 448 case NSStreamStatusClosed: return @"NSStreamStatusClosed"; 449 case NSStreamStatusError: return @"NSStreamStatusError"; 450 default: 451 return [NSString stringWithFormat: 452 @"NSStreamStatusValue%ld", (long)s]; 453 } 454} 455 456@end 457 458@implementation GSStream (Private) 459 460- (BOOL) _isOpened 461{ 462 return !(_currentStatus == NSStreamStatusNotOpen 463 || _currentStatus == NSStreamStatusOpening 464 || _currentStatus == NSStreamStatusClosed); 465} 466 467- (void*) _loopID 468{ 469 return _loopID; 470} 471 472- (void) _recordError 473{ 474 NSError *theError; 475 476 theError = [NSError _last]; 477 [self _recordError: theError]; 478} 479 480- (void) _recordError: (NSError*)anError 481{ 482 NSDebugMLLog(@"NSStream", @"record error: %@ - %@", self, anError); 483 ASSIGN(_lastError, anError); 484 [self _setStatus: NSStreamStatusError]; 485} 486 487- (void) _resetEvents: (NSUInteger)mask 488{ 489 _events &= ~mask; 490} 491 492- (void) _schedule 493{ 494 NSMapEnumerator enumerator; 495 NSRunLoop *k; 496 NSMutableArray *v; 497 498 enumerator = NSEnumerateMapTable(_loops); 499 while (NSNextMapEnumeratorPair(&enumerator, (void **)(&k), (void**)&v)) 500 { 501 unsigned i = [v count]; 502 503 while (i-- > 0) 504 { 505 [k addStream: self mode: [v objectAtIndex: i]]; 506 } 507 } 508 NSEndMapTableEnumeration(&enumerator); 509} 510 511- (void) _sendEvent: (NSStreamEvent)event 512{ 513 [self _sendEvent: event delegate: _delegateValid == YES ? _delegate : nil]; 514} 515 516- (void) _sendEvent: (NSStreamEvent)event delegate: (id)delegate 517{ 518 if (event == NSStreamEventNone) 519 { 520 return; 521 } 522 else if (event == NSStreamEventOpenCompleted) 523 { 524 if ((_events & event) == 0) 525 { 526 _events |= NSStreamEventOpenCompleted; 527 if (delegate != nil) 528 { 529 [delegate stream: self 530 handleEvent: NSStreamEventOpenCompleted]; 531 } 532 } 533 } 534 else if (event == NSStreamEventHasBytesAvailable) 535 { 536 if ((_events & NSStreamEventOpenCompleted) == 0) 537 { 538 _events |= NSStreamEventOpenCompleted; 539 if (delegate != nil) 540 { 541 [delegate stream: self 542 handleEvent: NSStreamEventOpenCompleted]; 543 } 544 } 545 if ((_events & NSStreamEventHasBytesAvailable) == 0) 546 { 547 _events |= NSStreamEventHasBytesAvailable; 548 if (delegate != nil) 549 { 550 [delegate stream: self 551 handleEvent: NSStreamEventHasBytesAvailable]; 552 } 553 } 554 } 555 else if (event == NSStreamEventHasSpaceAvailable) 556 { 557 if ((_events & NSStreamEventOpenCompleted) == 0) 558 { 559 _events |= NSStreamEventOpenCompleted; 560 if (delegate != nil) 561 { 562 [delegate stream: self 563 handleEvent: NSStreamEventOpenCompleted]; 564 } 565 } 566 if ((_events & NSStreamEventHasSpaceAvailable) == 0) 567 { 568 _events |= NSStreamEventHasSpaceAvailable; 569 if (delegate != nil) 570 { 571 [delegate stream: self 572 handleEvent: NSStreamEventHasSpaceAvailable]; 573 } 574 } 575 } 576 else if (event == NSStreamEventErrorOccurred) 577 { 578 if ((_events & NSStreamEventErrorOccurred) == 0) 579 { 580 _events |= NSStreamEventErrorOccurred; 581 if (delegate != nil) 582 { 583 [delegate stream: self 584 handleEvent: NSStreamEventErrorOccurred]; 585 } 586 } 587 } 588 else if (event == NSStreamEventEndEncountered) 589 { 590 if ((_events & NSStreamEventEndEncountered) == 0) 591 { 592 _events |= NSStreamEventEndEncountered; 593 if (delegate != nil) 594 { 595 [delegate stream: self 596 handleEvent: NSStreamEventEndEncountered]; 597 } 598 } 599 } 600 else 601 { 602 [NSException raise: NSInvalidArgumentException 603 format: @"Unknown event (%"PRIuPTR") passed to _sendEvent:", 604 event]; 605 } 606} 607 608- (void) _setLoopID: (void *)ref 609{ 610 _loopID = ref; 611} 612 613- (void) _setStatus: (NSStreamStatus)newStatus 614{ 615 if (_currentStatus != newStatus) 616 { 617 if (NSStreamStatusError == newStatus && NSCountMapTable(_loops) > 0) 618 { 619 /* After an error, we are in the run loops only to trigger 620 * errors, not for I/O, sop we must re-schedule in the right mode. 621 */ 622 [self _unschedule]; 623 _currentStatus = newStatus; 624 [self _schedule]; 625 } 626 else 627 { 628 _currentStatus = newStatus; 629 } 630 } 631} 632 633- (BOOL) _unhandledData 634{ 635 if (_events 636 & (NSStreamEventHasBytesAvailable | NSStreamEventHasSpaceAvailable)) 637 { 638 return YES; 639 } 640 return NO; 641} 642 643- (void) _unschedule 644{ 645 NSMapEnumerator enumerator; 646 NSRunLoop *k; 647 NSMutableArray *v; 648 649 enumerator = NSEnumerateMapTable(_loops); 650 while (NSNextMapEnumeratorPair(&enumerator, (void **)(&k), (void**)&v)) 651 { 652 unsigned i = [v count]; 653 654 while (i-- > 0) 655 { 656 [k removeStream: self mode: [v objectAtIndex: i]]; 657 } 658 } 659 NSEndMapTableEnumeration(&enumerator); 660} 661 662- (BOOL) runLoopShouldBlock: (BOOL*)trigger 663{ 664 if (_events 665 & (NSStreamEventHasBytesAvailable | NSStreamEventHasSpaceAvailable)) 666 { 667 /* If we have an unhandled data event, we should not watch for more 668 * or trigger until the appropriate read or write has been done. 669 */ 670 *trigger = NO; 671 return NO; 672 } 673 if (_currentStatus == NSStreamStatusError) 674 { 675 if ((_events & NSStreamEventErrorOccurred) == 0) 676 { 677 /* An error has occurred but not been handled, 678 * so we should trigger an error event at once. 679 */ 680 *trigger = YES; 681 return NO; 682 } 683 else 684 { 685 /* An error has occurred (and been handled), 686 * so we should not watch for any events at all. 687 */ 688 *trigger = NO; 689 return NO; 690 } 691 } 692 if (_currentStatus == NSStreamStatusAtEnd) 693 { 694 if ((_events & NSStreamEventEndEncountered) == 0) 695 { 696 /* An end of stream has occurred but not been handled, 697 * so we should trigger an end of stream event at once. 698 */ 699 *trigger = YES; 700 return NO; 701 } 702 else 703 { 704 /* An end of stream has occurred (and been handled), 705 * so we should not watch for any events at all. 706 */ 707 *trigger = NO; 708 return NO; 709 } 710 } 711 712 if (_loopID == (void*)self) 713 { 714 /* If _loopID is the receiver, the stream is not receiving external 715 * input, so it must trigger an event when the loop runs and must not 716 * block the loop from running. 717 */ 718 *trigger = YES; 719 return NO; 720 } 721 else 722 { 723 *trigger = YES; 724 return YES; 725 } 726} 727@end 728 729@implementation GSInputStream 730 731+ (void) initialize 732{ 733 if (self == [GSInputStream class]) 734 { 735 GSObjCAddClassBehavior(self, [GSStream class]); 736 GSMakeWeakPointer(self, "delegate"); 737 } 738} 739 740- (BOOL) hasBytesAvailable 741{ 742 if (_currentStatus == NSStreamStatusOpen) 743 { 744 return YES; 745 } 746 if (_currentStatus == NSStreamStatusAtEnd) 747 { 748 if ((_events & NSStreamEventEndEncountered) == 0) 749 { 750 /* We have not sent the appropriate event yet, so the 751 * client must not have issued a read:maxLength: 752 * (which is the point at which we should send). 753 */ 754 return YES; 755 } 756 } 757 return NO; 758} 759 760@end 761 762@implementation GSOutputStream 763 764+ (void) initialize 765{ 766 if (self == [GSOutputStream class]) 767 { 768 GSObjCAddClassBehavior(self, [GSStream class]); 769 GSMakeWeakPointer(self, "delegate"); 770 } 771} 772 773- (BOOL) hasSpaceAvailable 774{ 775 if (_currentStatus == NSStreamStatusOpen) 776 { 777 return YES; 778 } 779 return NO; 780} 781 782@end 783 784 785@implementation GSDataInputStream 786 787/** 788 * the designated initializer 789 */ 790- (id) initWithData: (NSData *)data 791{ 792 if ((self = [super init]) != nil) 793 { 794 ASSIGN(_data, data); 795 _pointer = 0; 796 } 797 return self; 798} 799 800- (void) dealloc 801{ 802 if (_currentStatus != NSStreamStatusNotOpen 803 && _currentStatus != NSStreamStatusClosed) 804 { 805 [self close]; 806 } 807 RELEASE(_data); 808 [super dealloc]; 809} 810 811- (NSInteger) read: (uint8_t *)buffer maxLength: (NSUInteger)len 812{ 813 NSUInteger dataSize; 814 815 if (buffer == 0) 816 { 817 [NSException raise: NSInvalidArgumentException 818 format: @"null pointer for buffer"]; 819 } 820 if (len == 0) 821 { 822 [NSException raise: NSInvalidArgumentException 823 format: @"zero byte read write requested"]; 824 } 825 826 if ([self streamStatus] == NSStreamStatusClosed 827 || [self streamStatus] == NSStreamStatusAtEnd) 828 { 829 return 0; 830 } 831 832 /* Mark the data availability event as handled, so we can generate more. 833 */ 834 _events &= ~NSStreamEventHasBytesAvailable; 835 836 dataSize = [_data length]; 837 NSAssert(dataSize >= _pointer, @"Buffer overflow!"); 838 if (len + _pointer >= dataSize) 839 { 840 len = dataSize - _pointer; 841 [self _setStatus: NSStreamStatusAtEnd]; 842 } 843 if (len > 0) 844 { 845 memcpy(buffer, [_data bytes] + _pointer, len); 846 _pointer = _pointer + len; 847 } 848 return len; 849} 850 851- (BOOL) getBuffer: (uint8_t **)buffer length: (NSUInteger *)len 852{ 853 unsigned long dataSize = [_data length]; 854 855 NSAssert(dataSize >= _pointer, @"Buffer overflow!"); 856 *buffer = (uint8_t*)[_data bytes] + _pointer; 857 *len = dataSize - _pointer; 858 return YES; 859} 860 861- (BOOL) hasBytesAvailable 862{ 863 unsigned long dataSize = [_data length]; 864 865 return (dataSize > _pointer); 866} 867 868- (id) propertyForKey: (NSString *)key 869{ 870 if ([key isEqualToString: NSStreamFileCurrentOffsetKey]) 871 return [NSNumber numberWithLong: _pointer]; 872 return [super propertyForKey: key]; 873} 874 875- (void) _dispatch 876{ 877 BOOL av = [self hasBytesAvailable]; 878 NSStreamEvent myEvent = av ? NSStreamEventHasBytesAvailable : 879 NSStreamEventEndEncountered; 880 NSStreamStatus myStatus = av ? NSStreamStatusOpen : NSStreamStatusAtEnd; 881 882 [self _setStatus: myStatus]; 883 [self _sendEvent: myEvent]; 884} 885 886@end 887 888 889@implementation GSBufferOutputStream 890 891- (id) initToBuffer: (uint8_t *)buffer capacity: (NSUInteger)capacity 892{ 893 if ((self = [super init]) != nil) 894 { 895 _buffer = buffer; 896 _capacity = capacity; 897 _pointer = 0; 898 } 899 return self; 900} 901 902- (NSInteger) write: (const uint8_t *)buffer maxLength: (NSUInteger)len 903{ 904 if (buffer == 0) 905 { 906 [NSException raise: NSInvalidArgumentException 907 format: @"null pointer for buffer"]; 908 } 909 if (len == 0) 910 { 911 [NSException raise: NSInvalidArgumentException 912 format: @"zero byte length write requested"]; 913 } 914 915 if ([self streamStatus] == NSStreamStatusClosed 916 || [self streamStatus] == NSStreamStatusAtEnd) 917 { 918 return 0; 919 } 920 921 /* We have consumed the 'writable' event ... mark that so another can 922 * be generated. 923 */ 924 _events &= ~NSStreamEventHasSpaceAvailable; 925 if ((_pointer + len) > _capacity) 926 { 927 len = _capacity - _pointer; 928 [self _setStatus: NSStreamStatusAtEnd]; 929 } 930 931 if (len > 0) 932 { 933 memcpy((_buffer + _pointer), buffer, len); 934 _pointer += len; 935 } 936 return len; 937} 938 939- (id) propertyForKey: (NSString *)key 940{ 941 if ([key isEqualToString: NSStreamFileCurrentOffsetKey]) 942 { 943 return [NSNumber numberWithLong: _pointer]; 944 } 945 return [super propertyForKey: key]; 946} 947 948- (void) _dispatch 949{ 950 BOOL av = [self hasSpaceAvailable]; 951 NSStreamEvent myEvent = av ? NSStreamEventHasSpaceAvailable : 952 NSStreamEventEndEncountered; 953 954 [self _sendEvent: myEvent]; 955} 956 957@end 958 959@implementation GSDataOutputStream 960 961- (id) init 962{ 963 if ((self = [super init]) != nil) 964 { 965 _data = [NSMutableData new]; 966 _pointer = 0; 967 } 968 return self; 969} 970 971- (void) dealloc 972{ 973 RELEASE(_data); 974 [super dealloc]; 975} 976 977- (NSInteger) write: (const uint8_t *)buffer maxLength: (NSUInteger)len 978{ 979 if (buffer == 0) 980 { 981 [NSException raise: NSInvalidArgumentException 982 format: @"null pointer for buffer"]; 983 } 984 if (len == 0) 985 { 986 [NSException raise: NSInvalidArgumentException 987 format: @"zero byte length write requested"]; 988 } 989 990 if ([self streamStatus] == NSStreamStatusClosed) 991 { 992 return 0; 993 } 994 995 /* We have consumed the 'writable' event ... mark that so another can 996 * be generated. 997 */ 998 _events &= ~NSStreamEventHasSpaceAvailable; 999 [_data appendBytes: buffer length: len]; 1000 _pointer += len; 1001 return len; 1002} 1003 1004- (BOOL) hasSpaceAvailable 1005{ 1006 return YES; 1007} 1008 1009- (id) propertyForKey: (NSString *)key 1010{ 1011 if ([key isEqualToString: NSStreamFileCurrentOffsetKey]) 1012 { 1013 return [NSNumber numberWithLong: _pointer]; 1014 } 1015 else if ([key isEqualToString: NSStreamDataWrittenToMemoryStreamKey]) 1016 { 1017 return _data; 1018 } 1019 return [super propertyForKey: key]; 1020} 1021 1022- (void) _dispatch 1023{ 1024 BOOL av = [self hasSpaceAvailable]; 1025 NSStreamEvent myEvent = av ? NSStreamEventHasSpaceAvailable : 1026 NSStreamEventEndEncountered; 1027 1028 [self _sendEvent: myEvent]; 1029} 1030 1031@end 1032 1033@interface GSLocalServerStream : GSServerStream 1034@end 1035 1036@implementation GSServerStream 1037 1038+ (void) initialize 1039{ 1040 GSMakeWeakPointer(self, "delegate"); 1041} 1042 1043+ (id) serverStreamToAddr: (NSString*)addr port: (NSInteger)port 1044{ 1045 GSServerStream *s; 1046 1047 // try inet first, then inet6 1048 s = [[GSInetServerStream alloc] initToAddr: addr port: port]; 1049 if (!s) 1050 s = [[GSInet6ServerStream alloc] initToAddr: addr port: port]; 1051 return AUTORELEASE(s); 1052} 1053 1054+ (id) serverStreamToAddr: (NSString*)addr 1055{ 1056 return AUTORELEASE([[GSLocalServerStream alloc] initToAddr: addr]); 1057} 1058 1059- (id) initToAddr: (NSString*)addr port: (NSInteger)port 1060{ 1061 DESTROY(self); 1062 // try inet first, then inet6 1063 self = [[GSInetServerStream alloc] initToAddr: addr port: port]; 1064 if (!self) 1065 self = [[GSInet6ServerStream alloc] initToAddr: addr port: port]; 1066 return self; 1067} 1068 1069- (id) initToAddr: (NSString*)addr 1070{ 1071 DESTROY(self); 1072 return [[GSLocalServerStream alloc] initToAddr: addr]; 1073} 1074 1075- (void) acceptWithInputStream: (NSInputStream **)inputStream 1076 outputStream: (NSOutputStream **)outputStream 1077{ 1078 [self subclassResponsibility: _cmd]; 1079} 1080 1081@end 1082 1083@implementation GSAbstractServerStream 1084 1085+ (void) initialize 1086{ 1087 if (self == [GSAbstractServerStream class]) 1088 { 1089 GSObjCAddClassBehavior(self, [GSStream class]); 1090 } 1091} 1092 1093@end 1094 1095