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