mingw stream improvements

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@23254 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
rfm 2006-08-11 13:27:10 +00:00
parent 068ca34b74
commit d0852086a5
6 changed files with 665 additions and 253 deletions

View file

@ -1,11 +1,18 @@
2006-08-11 Richard Frith-Macdonald <rfm@gnu.org> 2006-08-11 Richard Frith-Macdonald <rfm@gnu.org>
* Source/NSTask.m: Fixup for path validation error on mingw32 * Source/NSTask.m: Fixup for path validation error on mingw32
* Headers/Foundation/NSStream.h: improve documentation.
* Source/GSStream.h:
* Source/GSStream.m:
* Source/unix/NSStream.m:
* Source/win32/NSStreamWin32.m:
Add lots of error checking, simplify a little, get local streams on
mingw to close down properly.
2006-08-10 Richard Frith-Macdonald <rfm@gnu.org> 2006-08-10 Richard Frith-Macdonald <rfm@gnu.org>
* Source\GSStream.m: * Source/GSStream.m:
* Source\win32\NSStreamWin32.m: * Source/win32/NSStreamWin32.m:
Fix error in pipe read offset. Imitial implementation of local Fix error in pipe read offset. Imitial implementation of local
'unix domain sockets' (actually named pipe) stream. 'unix domain sockets' (actually named pipe) stream.
@ -16,10 +23,10 @@
2006-08-10 Richard Frith-Macdonald <rfm@gnu.org> 2006-08-10 Richard Frith-Macdonald <rfm@gnu.org>
* Source\GSStream.h: * Source/GSStream.h:
* Source\GSStream.m: * Source/GSStream.m:
* Source\unix\NSStream.m: * Source/unix/NSStream.m:
* Source\win32\NSStreamWin32.m: * Source/win32/NSStreamWin32.m:
Ensure all events are posted. Fixup for winsock write signalling. Ensure all events are posted. Fixup for winsock write signalling.
2006-08-09 Richard Frith-Macdonald <rfm@gnu.org> 2006-08-09 Richard Frith-Macdonald <rfm@gnu.org>
@ -930,13 +937,13 @@
* Source/NSUserDefaults.m: Restructure for lazy creation of defaults * Source/NSUserDefaults.m: Restructure for lazy creation of defaults
database ... only create when we attempt to write. database ... only create when we attempt to write.
* Source\NSSocketPort.m: Include GSPrivate.h * Source/NSSocketPort.m: Include GSPrivate.h
* Source\NSRunLoop.m: ditto * Source/NSRunLoop.m: ditto
* Source\unix\GSRunLoopCtxt.m: ditto * Source/unix/GSRunLoopCtxt.m: ditto
* Source\GSPrivate.h: ditto * Source/GSPrivate.h: ditto
* Source\win32\GSFileHandleWin32.m: ditto * Source/win32/GSFileHandleWin32.m: ditto
* Source\win32\GSRunLoopCtxt.m: ditto * Source/win32/GSRunLoopCtxt.m: ditto
* Headers\Foundation\NSNotificationQueue.h: Move library internal * Headers/Foundation/NSNotificationQueue.h: Move library internal
function declarations to GSPrivate.h, thanks to Lloyd Dupont for function declarations to GSPrivate.h, thanks to Lloyd Dupont for
spotting problem. spotting problem.

View file

@ -70,7 +70,8 @@ typedef enum {
outputStream: (NSOutputStream **)outputStream; outputStream: (NSOutputStream **)outputStream;
/** /**
* Closes the receiver. * Closes the receiver.<br />
* Repeated calls to this method on the same stream are quietly ignored.
*/ */
- (void) close; - (void) close;
@ -80,7 +81,10 @@ typedef enum {
- (id) delegate; - (id) delegate;
/** /**
* Opens the receiving stream. * Opens the receiving stream.<br />
* Upon completion of the open operation, an NSStreamEventOpenCompleted
* event is sent to the recevier's delegate.<br />
* Repeated calls to this method on the same stream are quietly ignored.
*/ */
- (void) open; - (void) open;
@ -91,12 +95,17 @@ typedef enum {
/** /**
* Removes the receiver from the NSRunLoop specified by aRunLoop * Removes the receiver from the NSRunLoop specified by aRunLoop
* running in the mode. * running in the mode.<br />
* Attempts to remove the receiver from a run loop or a mode in
* which it has not been scheduled are quietly ignored.
*/ */
- (void) removeFromRunLoop: (NSRunLoop *)aRunLoop forMode: (NSString *)mode; - (void) removeFromRunLoop: (NSRunLoop *)aRunLoop forMode: (NSString *)mode;
/** /**
* Schedules the receiver on aRunLoop using the specified mode. * Schedules the receiver on aRunLoop using the specified mode.<br />
* You must not attempt to add a stream to more than one run loop,
* but you may call this method multiple times to add the receiver
* in different modes for the same run loop.
*/ */
- (void) scheduleInRunLoop: (NSRunLoop *)aRunLoop forMode: (NSString *)mode; - (void) scheduleInRunLoop: (NSRunLoop *)aRunLoop forMode: (NSString *)mode;
@ -262,14 +271,17 @@ typedef enum {
* that is a stream that binds to a socket and accepts incoming connections * that is a stream that binds to a socket and accepts incoming connections
*/ */
@interface GSServerStream : NSStream @interface GSServerStream : NSStream
/** /**
* Createe a ip (ipv6) server stream * Createe a ip (ipv6) server stream
*/ */
+ (id) serverStreamToAddr: (NSString*)addr port: (int)port; + (id) serverStreamToAddr: (NSString*)addr port: (int)port;
/** /**
* Create a local (unix domain) server stream * Create a local (unix domain or named pipe) server stream
*/ */
+ (id) serverStreamToAddr: (NSString*)addr; + (id) serverStreamToAddr: (NSString*)addr;
/** /**
* This is the method that accepts a connection and generates two streams * This is the method that accepts a connection and generates two streams
* as the server side inputStream and OutputStream. * as the server side inputStream and OutputStream.
@ -283,8 +295,10 @@ typedef enum {
* the designated initializer for a ip (ipv6) server stream * the designated initializer for a ip (ipv6) server stream
*/ */
- (id) initToAddr: (NSString*)addr port: (int)port; - (id) initToAddr: (NSString*)addr port: (int)port;
/** /**
* the designated initializer for a local (unix domain) server stream * the designated initializer for a local (unix domain or named pipe)
* server stream
*/ */
- (id) initToAddr: (NSString*)addr; - (id) initToAddr: (NSString*)addr;

View file

@ -28,7 +28,7 @@
NSStream NSStream
|-- NSInputStream |-- NSInputStream
| `--GSInputStream | `--GSInputStream
| |-- GSMemoryInputStream | |-- GSDataInputStream
| |-- GSFileInputStream | |-- GSFileInputStream
| `-- GSSocketInputStream | `-- GSSocketInputStream
| |-- GSInetInputStream | |-- GSInetInputStream
@ -36,7 +36,8 @@
| `-- GSInet6InputStream | `-- GSInet6InputStream
|-- NSOutputStream |-- NSOutputStream
| `--GSOutputStream | `--GSOutputStream
| |-- GSMemoryOutputStream | |-- GSBufferOutputStream
| |-- GSDataOutputStream
| |-- GSFileOutputStream | |-- GSFileOutputStream
| `-- GSSocketOutputStream | `-- GSSocketOutputStream
| |-- GSInetOutputStream | |-- GSInetOutputStream
@ -144,7 +145,7 @@ IVARS
/** /**
* The concrete subclass of NSInputStream that reads from the memory * The concrete subclass of NSInputStream that reads from the memory
*/ */
@interface GSMemoryInputStream : GSInputStream @interface GSDataInputStream : GSInputStream
{ {
@private @private
NSData *_data; NSData *_data;
@ -158,14 +159,30 @@ IVARS
@end @end
/** /**
* The concrete subclass of NSOutputStream that writes to memory * The concrete subclass of NSOutputStream that writes to a buffer
*/ */
@interface GSMemoryOutputStream : GSOutputStream @interface GSBufferOutputStream : GSOutputStream
{
@private
uint8_t *_buffer;
unsigned _capacity;
unsigned long _pointer;
}
/**
* this is the bridge method for asynchronized operation. Do not call.
*/
- (void) _dispatch;
@end
/**
* The concrete subclass of NSOutputStream that writes to a variable sise buffer
*/
@interface GSDataOutputStream : GSOutputStream
{ {
@private @private
NSMutableData *_data; NSMutableData *_data;
unsigned long _pointer; unsigned long _pointer;
BOOL _fixedSize;
} }
/** /**

View file

@ -31,6 +31,7 @@
#include <Foundation/NSError.h> #include <Foundation/NSError.h>
#include <Foundation/NSValue.h> #include <Foundation/NSValue.h>
#include <Foundation/NSHost.h> #include <Foundation/NSHost.h>
#include <Foundation/NSDebug.h>
#include "GSStream.h" #include "GSStream.h"
@ -132,9 +133,14 @@ static RunLoopEventType typeForStream(NSStream *aStream)
- (void) close - (void) close
{ {
NSAssert(_currentStatus != NSStreamStatusNotOpen if (_currentStatus == NSStreamStatusNotOpen)
&& _currentStatus != NSStreamStatusClosed, {
@"Attempt to close a stream not yet opened."); NSDebugMLog(@"Attempt to close unopened stream %@", self);
}
if (_currentStatus == NSStreamStatusClosed)
{
NSDebugMLog(@"Attempt to close already closed stream %@", self);
}
if (_runloop) if (_runloop)
{ {
unsigned i = [_modes count]; unsigned i = [_modes count];
@ -186,9 +192,10 @@ static RunLoopEventType typeForStream(NSStream *aStream)
- (void) open - (void) open
{ {
NSAssert(_currentStatus == NSStreamStatusNotOpen if (_currentStatus != NSStreamStatusNotOpen)
|| _currentStatus == NSStreamStatusOpening, {
@"Attempt to open a stream already opened."); NSDebugMLog(@"Attempt to re-open stream %@", self);
}
[self _setStatus: NSStreamStatusOpen]; [self _setStatus: NSStreamStatusOpen];
if (_runloop) if (_runloop)
{ {
@ -364,9 +371,6 @@ static RunLoopEventType typeForStream(NSStream *aStream)
- (void) _sendEvent: (NSStreamEvent)event - (void) _sendEvent: (NSStreamEvent)event
{ {
NSStreamStatus last = [self streamStatus];
NSStreamStatus current;
if (event == NSStreamEventNone) if (event == NSStreamEventNone)
{ {
return; return;
@ -454,21 +458,6 @@ static RunLoopEventType typeForStream(NSStream *aStream)
[NSException raise: NSInvalidArgumentException [NSException raise: NSInvalidArgumentException
format: @"Unknown event (%d) passed to _sendEvent:", event]; format: @"Unknown event (%d) passed to _sendEvent:", event];
} }
/* If our status changed while the handler was dealing with an
* event, we may need to send it the new event to let it know.
*/
if ((current = [self streamStatus]) != last)
{
if (current == NSStreamStatusAtEnd)
{
[self _sendEvent: NSStreamEventEndEncountered];
}
else if (current == NSStreamStatusError)
{
[self _sendEvent: NSStreamEventErrorOccurred];
}
}
} }
- (void) _setLoopID: (void *)ref - (void) _setLoopID: (void *)ref
@ -493,18 +482,35 @@ static RunLoopEventType typeForStream(NSStream *aStream)
- (BOOL) runLoopShouldBlock: (BOOL*)trigger - (BOOL) runLoopShouldBlock: (BOOL*)trigger
{ {
if ([self _unhandledData] == YES if (_events
|| _currentStatus == NSStreamStatusError & (NSStreamEventHasBytesAvailable | NSStreamEventHasSpaceAvailable))
|| _currentStatus == NSStreamStatusAtEnd)
{ {
/* If we have an unhandled data event, we should not watch for more /* If we have an unhandled data event, we should not watch for more
* or trigger until the appropriate rad or write has been done. * or trigger until the appropriate read or write has been done.
* If an error has occurred, we should not watch for any events at all.
*/ */
*trigger = NO; *trigger = NO;
return NO; return NO;
} }
else if (_loopID == (void*)self) if (_currentStatus == NSStreamStatusError &&
(_events & NSStreamEventErrorOccurred) == NSStreamEventErrorOccurred)
{
/* If an error has occurred (and been handled),
* we should not watch for any events at all.
*/
*trigger = NO;
return NO;
}
if (_currentStatus == NSStreamStatusAtEnd &&
(_events & NSStreamEventEndEncountered) == NSStreamEventEndEncountered)
{
/* If an error has occurred (and been handled),
* we should not watch for any events at all.
*/
*trigger = NO;
return NO;
}
if (_loopID == (void*)self)
{ {
/* If _loopID is the receiver, the stream is not receiving external /* If _loopID is the receiver, the stream is not receiving external
* input, so it must trigger an event when the loop runs and must not * input, so it must trigger an event when the loop runs and must not
@ -522,6 +528,7 @@ static RunLoopEventType typeForStream(NSStream *aStream)
@end @end
@implementation GSInputStream @implementation GSInputStream
+ (void) initialize + (void) initialize
{ {
if (self == [GSInputStream class]) if (self == [GSInputStream class])
@ -529,9 +536,31 @@ static RunLoopEventType typeForStream(NSStream *aStream)
GSObjCAddClassBehavior(self, [GSStream class]); GSObjCAddClassBehavior(self, [GSStream class]);
} }
} }
- (BOOL) hasBytesAvailable
{
if (_currentStatus == NSStreamStatusOpen)
{
return YES;
}
if (_currentStatus == NSStreamStatusAtEnd)
{
if ((_events & NSStreamEventEndEncountered) == 0)
{
/* We have not sent the appropriate event yet, so the
* client must not have issued a read:maxLength:
* (which is the point at which we should send).
*/
return YES;
}
}
return NO;
}
@end @end
@implementation GSOutputStream @implementation GSOutputStream
+ (void) initialize + (void) initialize
{ {
if (self == [GSOutputStream class]) if (self == [GSOutputStream class])
@ -539,6 +568,27 @@ static RunLoopEventType typeForStream(NSStream *aStream)
GSObjCAddClassBehavior(self, [GSStream class]); GSObjCAddClassBehavior(self, [GSStream class]);
} }
} }
- (BOOL) hasSpaceAvailable
{
if (_currentStatus == NSStreamStatusOpen)
{
return YES;
}
if (_currentStatus == NSStreamStatusAtEnd)
{
if ((_events & NSStreamEventEndEncountered) == 0)
{
/* We have not sent the appropriate event yet, so the
* client must not have issued a write:maxLength:
* (which is the point at which we should send).
*/
return YES;
}
}
return NO;
}
@end @end
@implementation GSAbstractServerStream @implementation GSAbstractServerStream
+ (void) initialize + (void) initialize
@ -551,7 +601,7 @@ static RunLoopEventType typeForStream(NSStream *aStream)
@end @end
@implementation GSMemoryInputStream @implementation GSDataInputStream
/** /**
* the designated initializer * the designated initializer
@ -576,10 +626,28 @@ static RunLoopEventType typeForStream(NSStream *aStream)
- (int) read: (uint8_t *)buffer maxLength: (unsigned int)len - (int) read: (uint8_t *)buffer maxLength: (unsigned int)len
{ {
unsigned long dataSize = [_data length]; unsigned long dataSize;
unsigned long copySize; unsigned long copySize;
if (buffer == 0)
{
[NSException raise: NSInvalidArgumentException
format: @"null pointer for buffer"];
}
if (len == 0)
{
[NSException raise: NSInvalidArgumentException
format: @"zero byte read write requested"];
}
_events &= ~NSStreamEventHasSpaceAvailable; _events &= ~NSStreamEventHasSpaceAvailable;
if ([self streamStatus] == NSStreamStatusClosed)
{
return 0;
}
dataSize = [_data length];
NSAssert(dataSize >= _pointer, @"Buffer overflow!"); NSAssert(dataSize >= _pointer, @"Buffer overflow!");
if (len + _pointer > dataSize) if (len + _pointer > dataSize)
{ {
@ -597,6 +665,7 @@ static RunLoopEventType typeForStream(NSStream *aStream)
else else
{ {
[self _setStatus: NSStreamStatusAtEnd]; [self _setStatus: NSStreamStatusAtEnd];
[self _sendEvent: NSStreamEventEndEncountered];
} }
return copySize; return copySize;
} }
@ -639,71 +708,132 @@ static RunLoopEventType typeForStream(NSStream *aStream)
@end @end
@implementation GSMemoryOutputStream @implementation GSBufferOutputStream
- (id) initToBuffer: (uint8_t *)buffer capacity: (unsigned int)capacity - (id) initToBuffer: (uint8_t *)buffer capacity: (unsigned int)capacity
{ {
if ((self = [super init]) != nil) if ((self = [super init]) != nil)
{ {
if (!buffer) _buffer = buffer;
{ _capacity = capacity;
_data = [NSMutableData new];
_fixedSize = NO;
}
else
{
_data = [[NSMutableData alloc] initWithBytesNoCopy: buffer
length: capacity freeWhenDone: NO];
_fixedSize = YES;
}
_pointer = 0; _pointer = 0;
} }
return self; return self;
} }
- (void) dealloc
{
RELEASE(_data);
[super dealloc];
}
- (int) write: (const uint8_t *)buffer maxLength: (unsigned int)len - (int) write: (const uint8_t *)buffer maxLength: (unsigned int)len
{ {
_events &= ~NSStreamEventHasBytesAvailable; if (buffer == 0)
if (_fixedSize)
{ {
unsigned long dataLen = [_data length]; [NSException raise: NSInvalidArgumentException
uint8_t *origin = (uint8_t *)[_data mutableBytes]; format: @"null pointer for buffer"];
}
if (_pointer+len>dataLen) if (len == 0)
len = dataLen - _pointer; {
memcpy(origin+_pointer, buffer, len); [NSException raise: NSInvalidArgumentException
_pointer = _pointer + len; format: @"zero byte length write requested"];
} }
else
[_data appendBytes: buffer length: len];
return len;
}
- (BOOL) hasSpaceAvailable _events &= ~NSStreamEventHasBytesAvailable;
{
if (_fixedSize) if ([self streamStatus] == NSStreamStatusClosed)
return [_data length]>_pointer; {
else return 0;
return YES; }
if ((_pointer + len) > _capacity)
{
len = _capacity - _pointer;
if (len == 0)
{
[self _setStatus: NSStreamStatusAtEnd];
[self _sendEvent: NSStreamEventEndEncountered];
return 0;
}
}
memcpy((_buffer + _pointer), buffer, len);
_pointer += len;
return len;
} }
- (id) propertyForKey: (NSString *)key - (id) propertyForKey: (NSString *)key
{ {
if ([key isEqualToString: NSStreamFileCurrentOffsetKey]) if ([key isEqualToString: NSStreamFileCurrentOffsetKey])
{ {
if (_fixedSize) return [NSNumber numberWithLong: _pointer];
return [NSNumber numberWithLong: _pointer]; }
else return [super propertyForKey: key];
return [NSNumber numberWithLong:[_data length]]; }
- (void) _dispatch
{
BOOL av = [self hasSpaceAvailable];
NSStreamEvent myEvent = av ? NSStreamEventHasSpaceAvailable :
NSStreamEventEndEncountered;
[self _sendEvent: myEvent];
}
@end
@implementation GSDataOutputStream
- (id) init
{
if ((self = [super init]) != nil)
{
_data = [NSMutableData new];
_pointer = 0;
}
return self;
}
- (void) dealloc
{
RELEASE(_data);
[super dealloc];
}
- (int) write: (const uint8_t *)buffer maxLength: (unsigned int)len
{
if (buffer == 0)
{
[NSException raise: NSInvalidArgumentException
format: @"null pointer for buffer"];
}
if (len == 0)
{
[NSException raise: NSInvalidArgumentException
format: @"zero byte length write requested"];
}
_events &= ~NSStreamEventHasBytesAvailable;
if ([self streamStatus] == NSStreamStatusClosed)
{
return 0;
}
[_data appendBytes: buffer length: len];
_pointer += len;
return len;
}
- (BOOL) hasSpaceAvailable
{
return YES;
}
- (id) propertyForKey: (NSString *)key
{
if ([key isEqualToString: NSStreamFileCurrentOffsetKey])
{
return [NSNumber numberWithLong: _pointer];
}
else if ([key isEqualToString: NSStreamDataWrittenToMemoryStreamKey])
{
return _data;
} }
else if ([key isEqualToString: NSStreamDataWrittenToMemoryStreamKey])
return _data;
return [super propertyForKey: key]; return [super propertyForKey: key];
} }

View file

@ -297,7 +297,24 @@ static void setNonblocking(int fd)
{ {
int readLen; int readLen;
if (buffer == 0)
{
[NSException raise: NSInvalidArgumentException
format: @"null pointer for buffer"];
}
if (len == 0)
{
[NSException raise: NSInvalidArgumentException
format: @"zero byte read write requested"];
}
_events &= ~NSStreamEventHasBytesAvailable; _events &= ~NSStreamEventHasBytesAvailable;
if ([self streamStatus] == NSStreamStatusClosed)
{
return 0;
}
readLen = read((intptr_t)_loopID, buffer, len); readLen = read((intptr_t)_loopID, buffer, len);
if (readLen < 0 && errno != EAGAIN && errno != EINTR) if (readLen < 0 && errno != EAGAIN && errno != EINTR)
[self _recordError]; [self _recordError];
@ -475,7 +492,24 @@ static void setNonblocking(int fd)
{ {
int readLen; int readLen;
if (buffer == 0)
{
[NSException raise: NSInvalidArgumentException
format: @"null pointer for buffer"];
}
if (len == 0)
{
[NSException raise: NSInvalidArgumentException
format: @"zero byte read write requested"];
}
_events &= ~NSStreamEventHasBytesAvailable; _events &= ~NSStreamEventHasBytesAvailable;
if ([self streamStatus] == NSStreamStatusClosed)
{
return 0;
}
readLen = read((intptr_t)_loopID, buffer, len); readLen = read((intptr_t)_loopID, buffer, len);
if (readLen < 0 && errno != EAGAIN && errno != EINTR) if (readLen < 0 && errno != EAGAIN && errno != EINTR)
[self _recordError]; [self _recordError];
@ -676,7 +710,24 @@ static void setNonblocking(int fd)
{ {
int writeLen; int writeLen;
if (buffer == 0)
{
[NSException raise: NSInvalidArgumentException
format: @"null pointer for buffer"];
}
if (len == 0)
{
[NSException raise: NSInvalidArgumentException
format: @"zero byte length write requested"];
}
_events &= ~NSStreamEventHasSpaceAvailable; _events &= ~NSStreamEventHasSpaceAvailable;
if ([self streamStatus] == NSStreamStatusClosed)
{
return 0;
}
writeLen = write((intptr_t)_loopID, buffer, len); writeLen = write((intptr_t)_loopID, buffer, len);
if (writeLen < 0 && errno != EAGAIN && errno != EINTR) if (writeLen < 0 && errno != EAGAIN && errno != EINTR)
[self _recordError]; [self _recordError];
@ -790,7 +841,24 @@ static void setNonblocking(int fd)
{ {
int writeLen; int writeLen;
if (buffer == 0)
{
[NSException raise: NSInvalidArgumentException
format: @"null pointer for buffer"];
}
if (len == 0)
{
[NSException raise: NSInvalidArgumentException
format: @"zero byte length write requested"];
}
_events &= ~NSStreamEventHasSpaceAvailable; _events &= ~NSStreamEventHasSpaceAvailable;
if ([self streamStatus] == NSStreamStatusClosed)
{
return 0;
}
writeLen = write((intptr_t)_loopID, buffer, len); writeLen = write((intptr_t)_loopID, buffer, len);
if (writeLen < 0 && errno != EAGAIN && errno != EINTR) if (writeLen < 0 && errno != EAGAIN && errno != EINTR)
[self _recordError]; [self _recordError];
@ -1186,7 +1254,7 @@ static void setNonblocking(int fd)
+ (id) inputStreamWithData: (NSData *)data + (id) inputStreamWithData: (NSData *)data
{ {
return AUTORELEASE([[GSMemoryInputStream alloc] initWithData: data]); return AUTORELEASE([[GSDataInputStream alloc] initWithData: data]);
} }
+ (id) inputStreamWithFileAtPath: (NSString *)path + (id) inputStreamWithFileAtPath: (NSString *)path
@ -1194,24 +1262,6 @@ static void setNonblocking(int fd)
return AUTORELEASE([[GSFileInputStream alloc] initWithFileAtPath: path]); return AUTORELEASE([[GSFileInputStream alloc] initWithFileAtPath: path]);
} }
- (id) initWithData: (NSData *)data
{
RELEASE(self);
return [[GSMemoryInputStream alloc] initWithData: data];
}
- (id) initWithFileAtPath: (NSString *)path
{
RELEASE(self);
return [[GSFileInputStream alloc] initWithFileAtPath: path];
}
- (int) read: (uint8_t *)buffer maxLength: (unsigned int)len
{
[self subclassResponsibility: _cmd];
return -1;
}
- (BOOL) getBuffer: (uint8_t **)buffer length: (unsigned int *)len - (BOOL) getBuffer: (uint8_t **)buffer length: (unsigned int *)len
{ {
[self subclassResponsibility: _cmd]; [self subclassResponsibility: _cmd];
@ -1224,19 +1274,31 @@ static void setNonblocking(int fd)
return NO; return NO;
} }
- (id) initWithData: (NSData *)data
{
RELEASE(self);
return [[GSDataInputStream alloc] initWithData: data];
}
- (id) initWithFileAtPath: (NSString *)path
{
RELEASE(self);
return [[GSFileInputStream alloc] initWithFileAtPath: path];
}
- (int) read: (uint8_t *)buffer maxLength: (unsigned int)len
{
[self subclassResponsibility: _cmd];
return -1;
}
@end @end
@implementation NSOutputStream @implementation NSOutputStream
+ (id) outputStreamToMemory
{
return AUTORELEASE([[GSMemoryOutputStream alloc]
initToBuffer: NULL capacity: 0]);
}
+ (id) outputStreamToBuffer: (uint8_t *)buffer capacity: (unsigned int)capacity + (id) outputStreamToBuffer: (uint8_t *)buffer capacity: (unsigned int)capacity
{ {
return AUTORELEASE([[GSMemoryOutputStream alloc] return AUTORELEASE([[GSBufferOutputStream alloc]
initToBuffer: buffer capacity: capacity]); initToBuffer: buffer capacity: capacity]);
} }
@ -1246,16 +1308,21 @@ static void setNonblocking(int fd)
initToFileAtPath: path append: shouldAppend]); initToFileAtPath: path append: shouldAppend]);
} }
- (id) initToMemory + (id) outputStreamToMemory
{ {
RELEASE(self); return AUTORELEASE([[GSDataOutputStream alloc] init]);
return [[GSMemoryOutputStream alloc] initToBuffer: NULL capacity: 0]; }
- (BOOL) hasSpaceAvailable
{
[self subclassResponsibility: _cmd];
return NO;
} }
- (id) initToBuffer: (uint8_t *)buffer capacity: (unsigned int)capacity - (id) initToBuffer: (uint8_t *)buffer capacity: (unsigned int)capacity
{ {
RELEASE(self); RELEASE(self);
return [[GSMemoryOutputStream alloc] initToBuffer: buffer capacity: capacity]; return [[GSBufferOutputStream alloc] initToBuffer: buffer capacity: capacity];
} }
- (id) initToFileAtPath: (NSString *)path append: (BOOL)shouldAppend - (id) initToFileAtPath: (NSString *)path append: (BOOL)shouldAppend
@ -1265,18 +1332,18 @@ static void setNonblocking(int fd)
append: shouldAppend]; append: shouldAppend];
} }
- (id) initToMemory
{
RELEASE(self);
return [[GSDataOutputStream alloc] init];
}
- (int) write: (const uint8_t *)buffer maxLength: (unsigned int)len - (int) write: (const uint8_t *)buffer maxLength: (unsigned int)len
{ {
[self subclassResponsibility: _cmd]; [self subclassResponsibility: _cmd];
return -1; return -1;
} }
- (BOOL) hasSpaceAvailable
{
[self subclassResponsibility: _cmd];
return NO;
}
@end @end
@implementation GSServerStream @implementation GSServerStream

View file

@ -41,6 +41,7 @@
#include <Foundation/NSValue.h> #include <Foundation/NSValue.h>
#include <Foundation/NSHost.h> #include <Foundation/NSHost.h>
#include <Foundation/NSProcessInfo.h> #include <Foundation/NSProcessInfo.h>
#include <Foundation/NSDebug.h>
#include "../GSStream.h" #include "../GSStream.h"
@ -73,6 +74,7 @@ typedef int socklen_t;
unsigned want; // Amount of data we want to read. unsigned want; // Amount of data we want to read.
DWORD size; // Number of bytes returned by read. DWORD size; // Number of bytes returned by read.
GSPipeOutputStream *_sibling; GSPipeOutputStream *_sibling;
BOOL hadEOF;
} }
- (NSStreamStatus) _check; - (NSStreamStatus) _check;
- (void) _queue; - (void) _queue;
@ -154,6 +156,8 @@ typedef int socklen_t;
unsigned want; unsigned want;
DWORD size; DWORD size;
GSPipeInputStream *_sibling; GSPipeInputStream *_sibling;
BOOL closing;
BOOL writtenEOF;
} }
- (NSStreamStatus) _check; - (NSStreamStatus) _check;
- (void) _queue; - (void) _queue;
@ -298,13 +302,6 @@ static void setNonblocking(SOCKET fd)
return NO; return NO;
} }
- (BOOL) hasBytesAvailable
{
if ([self _isOpened] && [self streamStatus] != NSStreamStatusAtEnd)
return YES;
return NO;
}
- (id) initWithFileAtPath: (NSString *)path - (id) initWithFileAtPath: (NSString *)path
{ {
if ((self = [super init]) != nil) if ((self = [super init]) != nil)
@ -351,7 +348,24 @@ static void setNonblocking(SOCKET fd)
{ {
DWORD readLen; DWORD readLen;
if (buffer == 0)
{
[NSException raise: NSInvalidArgumentException
format: @"null pointer for buffer"];
}
if (len == 0)
{
[NSException raise: NSInvalidArgumentException
format: @"zero byte length read requested"];
}
_events &= ~NSStreamEventHasBytesAvailable; _events &= ~NSStreamEventHasBytesAvailable;
if ([self streamStatus] == NSStreamStatusClosed)
{
return 0;
}
if (ReadFile((HANDLE)_loopID, buffer, len, &readLen, NULL) == 0) if (ReadFile((HANDLE)_loopID, buffer, len, &readLen, NULL) == 0)
{ {
[self _recordError]; [self _recordError];
@ -360,6 +374,7 @@ static void setNonblocking(SOCKET fd)
else if (readLen == 0) else if (readLen == 0)
{ {
[self _setStatus: NSStreamStatusAtEnd]; [self _setStatus: NSStreamStatusAtEnd];
[self _sendEvent: NSStreamEventEndEncountered];
} }
return (int)readLen; return (int)readLen;
} }
@ -383,26 +398,43 @@ static void setNonblocking(SOCKET fd)
- (void) close - (void) close
{ {
if (want > 0 && handle != INVALID_HANDLE_VALUE) length = offset = 0;
{
want = 0;
CancelIo(handle);
}
if (_loopID != INVALID_HANDLE_VALUE) if (_loopID != INVALID_HANDLE_VALUE)
{ {
CloseHandle((HANDLE)_loopID); CloseHandle((HANDLE)_loopID);
} }
if (handle != INVALID_HANDLE_VALUE && [_sibling _isOpened] == NO) if (handle != INVALID_HANDLE_VALUE)
{ {
if (CloseHandle(handle) == 0) /* If we have an outstanding read in progess, we must cancel it
* before closing the pipe.
*/
if (want > 0)
{ {
[self _recordError]; want = 0;
CancelIo(handle);
} }
/* We can only close the pipe if there is no sibling using it.
*/
if ([_sibling _isOpened] == NO)
{
if (DisconnectNamedPipe(handle) == 0)
{
if ((errno = GetLastError()) != ERROR_PIPE_NOT_CONNECTED)
{
[self _recordError];
}
}
if (CloseHandle(handle) == 0)
{
[self _recordError];
}
}
handle = INVALID_HANDLE_VALUE;
} }
length = offset = 0;
[super close]; [super close];
handle = INVALID_HANDLE_VALUE;
_loopID = (void*)INVALID_HANDLE_VALUE; _loopID = (void*)INVALID_HANDLE_VALUE;
} }
- (void) dealloc - (void) dealloc
@ -426,13 +458,6 @@ static void setNonblocking(SOCKET fd)
return NO; return NO;
} }
- (BOOL) hasBytesAvailable
{
if ([self streamStatus] == NSStreamStatusOpen)
return YES;
return NO;
}
- (id) init - (id) init
{ {
if ((self = [super init]) != nil) if ((self = [super init]) != nil)
@ -459,8 +484,8 @@ static void setNonblocking(SOCKET fd)
if (GetOverlappedResult(handle, &ov, &size, TRUE) == 0) if (GetOverlappedResult(handle, &ov, &size, TRUE) == 0)
{ {
errno = GetLastError(); if ((errno = GetLastError()) == ERROR_HANDLE_EOF
if (errno == ERROR_HANDLE_EOF || errno == ERROR_PIPE_NOT_CONNECTED
|| errno == ERROR_BROKEN_PIPE) || errno == ERROR_BROKEN_PIPE)
{ {
/* /*
@ -469,6 +494,7 @@ static void setNonblocking(SOCKET fd)
*/ */
offset = length = want = 0; offset = length = want = 0;
[self _setStatus: NSStreamStatusOpen]; [self _setStatus: NSStreamStatusOpen];
hadEOF = YES;
} }
else if (errno != ERROR_IO_PENDING) else if (errno != ERROR_IO_PENDING)
{ {
@ -479,6 +505,12 @@ static void setNonblocking(SOCKET fd)
[self _recordError]; [self _recordError];
} }
} }
else if (size == 0)
{
length = want = 0;
[self _setStatus: NSStreamStatusOpen];
hadEOF = YES;
}
else else
{ {
/* /*
@ -492,7 +524,7 @@ static void setNonblocking(SOCKET fd)
- (void) _queue - (void) _queue
{ {
if ([self streamStatus] == NSStreamStatusOpen) if (hadEOF == NO && [self streamStatus] == NSStreamStatusOpen)
{ {
int rc; int rc;
@ -508,14 +540,14 @@ static void setNonblocking(SOCKET fd)
length = size; length = size;
if (length == 0) if (length == 0)
{ {
[self _setStatus: NSStreamStatusAtEnd]; hadEOF = YES;
} }
} }
else if ((errno = GetLastError()) == ERROR_HANDLE_EOF else if ((errno = GetLastError()) == ERROR_HANDLE_EOF
|| errno == ERROR_PIPE_NOT_CONNECTED
|| errno == ERROR_BROKEN_PIPE) || errno == ERROR_BROKEN_PIPE)
{ {
offset = length = 0; hadEOF = YES;
[self _setStatus: NSStreamStatusOpen]; // Read of zero length
} }
else if (errno != ERROR_IO_PENDING) else if (errno != ERROR_IO_PENDING)
{ {
@ -530,24 +562,38 @@ static void setNonblocking(SOCKET fd)
- (int) read: (uint8_t *)buffer maxLength: (unsigned int)len - (int) read: (uint8_t *)buffer maxLength: (unsigned int)len
{ {
NSStreamStatus myStatus = [self streamStatus]; NSStreamStatus myStatus;
if (buffer == 0)
{
[NSException raise: NSInvalidArgumentException
format: @"null pointer for buffer"];
}
if (len == 0)
{
[NSException raise: NSInvalidArgumentException
format: @"zero byte length read requested"];
}
_events &= ~NSStreamEventHasBytesAvailable; _events &= ~NSStreamEventHasBytesAvailable;
myStatus = [self streamStatus];
if (myStatus == NSStreamStatusReading) if (myStatus == NSStreamStatusReading)
{ {
myStatus = [self _check]; myStatus = [self _check];
} }
if (myStatus == NSStreamStatusAtEnd) if (myStatus == NSStreamStatusClosed)
{ {
return 0; // At EOF return 0;
}
if (len <= 0
|| (myStatus != NSStreamStatusReading && myStatus != NSStreamStatusOpen))
{
return -1; // Bad length or status
} }
if (offset == length) if (offset == length)
{ {
if (myStatus == NSStreamStatusError)
{
[self _sendEvent: NSStreamEventErrorOccurred];
return -1; // Waiting for read.
}
if (myStatus == NSStreamStatusOpen) if (myStatus == NSStreamStatusOpen)
{ {
/* /*
@ -555,10 +601,11 @@ static void setNonblocking(SOCKET fd)
* so we must be at EOF. * so we must be at EOF.
*/ */
[self _setStatus: NSStreamStatusAtEnd]; [self _setStatus: NSStreamStatusAtEnd];
return 0; [self _sendEvent: NSStreamEventEndEncountered];
} }
return -1; // Waiting for read. return 0;
} }
/* /*
* We already have data buffered ... return some or all of it. * We already have data buffered ... return some or all of it.
*/ */
@ -775,7 +822,24 @@ static void setNonblocking(SOCKET fd)
{ {
int readLen; int readLen;
if (buffer == 0)
{
[NSException raise: NSInvalidArgumentException
format: @"null pointer for buffer"];
}
if (len == 0)
{
[NSException raise: NSInvalidArgumentException
format: @"zero byte length read requested"];
}
_events &= ~NSStreamEventHasBytesAvailable; _events &= ~NSStreamEventHasBytesAvailable;
if ([self streamStatus] == NSStreamStatusClosed)
{
return 0;
}
readLen = recv(_sock, buffer, len, 0); readLen = recv(_sock, buffer, len, 0);
if (readLen == SOCKET_ERROR) if (readLen == SOCKET_ERROR)
{ {
@ -806,13 +870,6 @@ static void setNonblocking(SOCKET fd)
return NO; return NO;
} }
- (BOOL) hasBytesAvailable
{
if ([self streamStatus] == NSStreamStatusOpen)
return YES;
return NO;
}
- (void) _dispatch - (void) _dispatch
{ {
/* /*
@ -995,13 +1052,6 @@ static void setNonblocking(SOCKET fd)
[super dealloc]; [super dealloc];
} }
- (BOOL) hasSpaceAvailable
{
if ([self streamStatus] == NSStreamStatusOpen)
return YES;
return NO;
}
- (id) initToFileAtPath: (NSString *)path append: (BOOL)shouldAppend - (id) initToFileAtPath: (NSString *)path append: (BOOL)shouldAppend
{ {
if ((self = [super init]) != nil) if ((self = [super init]) != nil)
@ -1056,7 +1106,24 @@ static void setNonblocking(SOCKET fd)
{ {
DWORD writeLen; DWORD writeLen;
if (buffer == 0)
{
[NSException raise: NSInvalidArgumentException
format: @"null pointer for buffer"];
}
if (len == 0)
{
[NSException raise: NSInvalidArgumentException
format: @"zero byte length write requested"];
}
_events &= ~NSStreamEventHasSpaceAvailable; _events &= ~NSStreamEventHasSpaceAvailable;
if ([self streamStatus] == NSStreamStatusClosed)
{
return 0;
}
if (_shouldAppend == YES) if (_shouldAppend == YES)
{ {
SetFilePointer((HANDLE)_loopID, 0, 0, FILE_END); SetFilePointer((HANDLE)_loopID, 0, 0, FILE_END);
@ -1084,21 +1151,67 @@ static void setNonblocking(SOCKET fd)
- (void) close - (void) close
{ {
/* If we have a write in progress, we must wait for it to complete,
* so we just set a flag to close as soon as the write finishes.
*/
if ([self streamStatus] == NSStreamStatusWriting)
{
closing = YES;
return;
}
/* Where we have a sibling, we can't close the pipe handle, so the
* only way to tell the remote end we have finished is to write a
* zero length packet to it.
*/
if ([_sibling _isOpened] == YES && writtenEOF == NO)
{
int rc;
writtenEOF = YES;
ov.Offset = 0;
ov.OffsetHigh = 0;
ov.hEvent = (HANDLE)_loopID;
size = 0;
rc = WriteFile(handle, "", 0, &size, &ov);
if (rc == 0)
{
if ((errno = GetLastError()) == ERROR_IO_PENDING)
{
[self _setStatus: NSStreamStatusWriting];
return; // Wait for write to complete
}
[self _recordError]; // Failed to write EOF
}
}
offset = want = 0;
if (_loopID != INVALID_HANDLE_VALUE) if (_loopID != INVALID_HANDLE_VALUE)
{ {
CloseHandle((HANDLE)_loopID); CloseHandle((HANDLE)_loopID);
} }
if (handle != INVALID_HANDLE_VALUE && [_sibling _isOpened] == NO) if (handle != INVALID_HANDLE_VALUE)
{ {
if (CloseHandle(handle) == 0) if ([_sibling _isOpened] == NO)
{ {
[self _recordError]; if (DisconnectNamedPipe(handle) == 0)
{
if ((errno = GetLastError()) != ERROR_PIPE_NOT_CONNECTED)
{
[self _recordError];
}
[self _recordError];
}
if (CloseHandle(handle) == 0)
{
[self _recordError];
}
} }
handle = INVALID_HANDLE_VALUE;
} }
offset = want = 0;
[super close]; [super close];
_loopID = (void*)INVALID_HANDLE_VALUE; _loopID = (void*)INVALID_HANDLE_VALUE;
handle = INVALID_HANDLE_VALUE;
} }
- (void) dealloc - (void) dealloc
@ -1112,13 +1225,6 @@ static void setNonblocking(SOCKET fd)
[super dealloc]; [super dealloc];
} }
- (BOOL) hasSpaceAvailable
{
if ([self streamStatus] == NSStreamStatusOpen)
return YES;
return NO;
}
- (id) init - (id) init
{ {
if ((self = [super init]) != nil) if ((self = [super init]) != nil)
@ -1179,19 +1285,33 @@ static void setNonblocking(SOCKET fd)
{ {
NSStreamStatus myStatus = [self streamStatus]; NSStreamStatus myStatus = [self streamStatus];
_events &= ~NSStreamEventHasSpaceAvailable; if (buffer == 0)
if (len < 0)
{ {
return -1; [NSException raise: NSInvalidArgumentException
format: @"null pointer for buffer"];
} }
if (len == 0)
{
[NSException raise: NSInvalidArgumentException
format: @"zero byte length write requested"];
}
_events &= ~NSStreamEventHasSpaceAvailable;
if (myStatus == NSStreamStatusWriting) if (myStatus == NSStreamStatusWriting)
{ {
myStatus = [self _check]; myStatus = [self _check];
} }
if (myStatus == NSStreamStatusClosed)
{
return 0;
}
if ((myStatus != NSStreamStatusOpen && myStatus != NSStreamStatusWriting)) if ((myStatus != NSStreamStatusOpen && myStatus != NSStreamStatusWriting))
{ {
return -1; return -1;
} }
if (len > (sizeof(data) - offset)) if (len > (sizeof(data) - offset))
{ {
len = sizeof(data) - offset; len = sizeof(data) - offset;
@ -1231,6 +1351,10 @@ static void setNonblocking(SOCKET fd)
offset = want = 0; offset = want = 0;
} }
} }
if (closing == YES && [self streamStatus] != NSStreamStatusWriting)
{
[self close];
}
return [self streamStatus]; return [self streamStatus];
} }
@ -1313,7 +1437,7 @@ static void setNonblocking(SOCKET fd)
_sibling = sibling; _sibling = sibling;
} }
-(void)setPassive: (BOOL)passive -(void) setPassive: (BOOL)passive
{ {
_passive = passive; _passive = passive;
} }
@ -1354,7 +1478,24 @@ static void setNonblocking(SOCKET fd)
{ {
int writeLen; int writeLen;
if (buffer == 0)
{
[NSException raise: NSInvalidArgumentException
format: @"null pointer for buffer"];
}
if (len == 0)
{
[NSException raise: NSInvalidArgumentException
format: @"zero byte length write requested"];
}
_events &= ~NSStreamEventHasSpaceAvailable; _events &= ~NSStreamEventHasSpaceAvailable;
if ([self streamStatus] == NSStreamStatusClosed)
{
return 0;
}
writeLen = send(_sock, buffer, len, 0); writeLen = send(_sock, buffer, len, 0);
if (writeLen == SOCKET_ERROR) if (writeLen == SOCKET_ERROR)
{ {
@ -1376,13 +1517,6 @@ static void setNonblocking(SOCKET fd)
return writeLen; return writeLen;
} }
- (BOOL) hasSpaceAvailable
{
if ([self streamStatus] == NSStreamStatusOpen)
return YES;
return NO;
}
- (void) open - (void) open
{ {
// could be opened because of sibling // could be opened because of sibling
@ -1691,16 +1825,37 @@ static void setNonblocking(SOCKET fd)
SECURITY_ATTRIBUTES saAttr; SECURITY_ATTRIBUTES saAttr;
HANDLE handle; HANDLE handle;
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); if ([path length] == 0)
saAttr.bInheritHandle = TRUE; {
saAttr.lpSecurityDescriptor = NULL; NSDebugMLog(@"address nil or empty");
goto done;
}
if ([path length] > 240)
{
NSDebugMLog(@"address (%@) too long", path);
goto done;
}
if ([path rangeOfString: @"\\"].length > 0)
{
NSDebugMLog(@"illegal backslash in (%@)", path);
goto done;
}
if ([path rangeOfString: @"/"].length > 0)
{
NSDebugMLog(@"illegal slash in (%@)", path);
goto done;
}
/* /*
* We allocate a new within the local pipe area * We allocate a new within the local pipe area
*/ */
name = [[@"\\\\.\\pipe\\" stringByAppendingString: path] name = [[@"\\\\.\\pipe\\GSLocal" stringByAppendingString: path]
fileSystemRepresentation]; fileSystemRepresentation];
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
handle = CreateFileW(name, handle = CreateFileW(name,
GENERIC_WRITE|GENERIC_READ, GENERIC_WRITE|GENERIC_READ,
0, 0,
@ -1720,15 +1875,17 @@ static void setNonblocking(SOCKET fd)
outs = AUTORELEASE([GSPipeOutputStream new]); outs = AUTORELEASE([GSPipeOutputStream new]);
[ins _setHandle: handle]; [ins _setHandle: handle];
[ins setSibling: outs];
[outs _setHandle: handle]; [outs _setHandle: handle];
[outs setSibling: ins];
done:
if (inputStream) if (inputStream)
{ {
[ins setSibling: outs];
*inputStream = ins; *inputStream = ins;
} }
if (outputStream) if (outputStream)
{ {
[outs setSibling: ins];
*outputStream = outs; *outputStream = outs;
} }
} }
@ -1875,7 +2032,7 @@ static void setNonblocking(SOCKET fd)
+ (id) inputStreamWithData: (NSData *)data + (id) inputStreamWithData: (NSData *)data
{ {
return AUTORELEASE([[GSMemoryInputStream alloc] initWithData: data]); return AUTORELEASE([[GSDataInputStream alloc] initWithData: data]);
} }
+ (id) inputStreamWithFileAtPath: (NSString *)path + (id) inputStreamWithFileAtPath: (NSString *)path
@ -1883,24 +2040,6 @@ static void setNonblocking(SOCKET fd)
return AUTORELEASE([[GSFileInputStream alloc] initWithFileAtPath: path]); return AUTORELEASE([[GSFileInputStream alloc] initWithFileAtPath: path]);
} }
- (id) initWithData: (NSData *)data
{
RELEASE(self);
return [[GSMemoryInputStream alloc] initWithData: data];
}
- (id) initWithFileAtPath: (NSString *)path
{
RELEASE(self);
return [[GSFileInputStream alloc] initWithFileAtPath: path];
}
- (int) read: (uint8_t *)buffer maxLength: (unsigned int)len
{
[self subclassResponsibility: _cmd];
return -1;
}
- (BOOL) getBuffer: (uint8_t **)buffer length: (unsigned int *)len - (BOOL) getBuffer: (uint8_t **)buffer length: (unsigned int *)len
{ {
[self subclassResponsibility: _cmd]; [self subclassResponsibility: _cmd];
@ -1913,19 +2052,36 @@ static void setNonblocking(SOCKET fd)
return NO; return NO;
} }
- (id) initWithData: (NSData *)data
{
RELEASE(self);
return [[GSDataInputStream alloc] initWithData: data];
}
- (id) initWithFileAtPath: (NSString *)path
{
RELEASE(self);
return [[GSFileInputStream alloc] initWithFileAtPath: path];
}
- (int) read: (uint8_t *)buffer maxLength: (unsigned int)len
{
[self subclassResponsibility: _cmd];
return -1;
}
@end @end
@implementation NSOutputStream @implementation NSOutputStream
+ (id) outputStreamToMemory + (id) outputStreamToMemory
{ {
return AUTORELEASE([[GSMemoryOutputStream alloc] return AUTORELEASE([[GSDataOutputStream alloc] init]);
initToBuffer: NULL capacity: 0]);
} }
+ (id) outputStreamToBuffer: (uint8_t *)buffer capacity: (unsigned int)capacity + (id) outputStreamToBuffer: (uint8_t *)buffer capacity: (unsigned int)capacity
{ {
return AUTORELEASE([[GSMemoryOutputStream alloc] return AUTORELEASE([[GSBufferOutputStream alloc]
initToBuffer: buffer capacity: capacity]); initToBuffer: buffer capacity: capacity]);
} }
@ -1935,16 +2091,16 @@ static void setNonblocking(SOCKET fd)
initToFileAtPath: path append: shouldAppend]); initToFileAtPath: path append: shouldAppend]);
} }
- (id) initToMemory - (BOOL) hasSpaceAvailable
{ {
RELEASE(self); [self subclassResponsibility: _cmd];
return [[GSMemoryOutputStream alloc] initToBuffer: NULL capacity: 0]; return NO;
} }
- (id) initToBuffer: (uint8_t *)buffer capacity: (unsigned int)capacity - (id) initToBuffer: (uint8_t *)buffer capacity: (unsigned int)capacity
{ {
RELEASE(self); RELEASE(self);
return [[GSMemoryOutputStream alloc] initToBuffer: buffer capacity: capacity]; return [[GSBufferOutputStream alloc] initToBuffer: buffer capacity: capacity];
} }
- (id) initToFileAtPath: (NSString *)path append: (BOOL)shouldAppend - (id) initToFileAtPath: (NSString *)path append: (BOOL)shouldAppend
@ -1954,18 +2110,18 @@ static void setNonblocking(SOCKET fd)
append: shouldAppend]; append: shouldAppend];
} }
- (id) initToMemory
{
RELEASE(self);
return [[GSDataOutputStream alloc] init];
}
- (int) write: (const uint8_t *)buffer maxLength: (unsigned int)len - (int) write: (const uint8_t *)buffer maxLength: (unsigned int)len
{ {
[self subclassResponsibility: _cmd]; [self subclassResponsibility: _cmd];
return -1; return -1;
} }
- (BOOL) hasSpaceAvailable
{
[self subclassResponsibility: _cmd];
return NO;
}
@end @end
@implementation GSServerStream @implementation GSServerStream
@ -2213,9 +2369,30 @@ static void setNonblocking(SOCKET fd)
- (id) initToAddr: (NSString*)addr - (id) initToAddr: (NSString*)addr
{ {
if ([addr length] == 0)
{
NSDebugMLog(@"address nil or empty");
DESTROY(self);
}
if ([addr length] > 246)
{
NSDebugMLog(@"address (%@) too long", addr);
DESTROY(self);
}
if ([addr rangeOfString: @"\\"].length > 0)
{
NSDebugMLog(@"illegal backslash in (%@)", addr);
DESTROY(self);
}
if ([addr rangeOfString: @"/"].length > 0)
{
NSDebugMLog(@"illegal slash in (%@)", addr);
DESTROY(self);
}
if ((self = [super init]) != nil) if ((self = [super init]) != nil)
{ {
path = RETAIN([@"\\\\.\\pipe\\" stringByAppendingString: addr]); path = RETAIN([@"\\\\.\\pipe\\GSLocal" stringByAppendingString: addr]);
_loopID = INVALID_HANDLE_VALUE; _loopID = INVALID_HANDLE_VALUE;
handle = INVALID_HANDLE_VALUE; handle = INVALID_HANDLE_VALUE;
} }
@ -2245,7 +2422,7 @@ static void setNonblocking(SOCKET fd)
handle = CreateNamedPipeW([path fileSystemRepresentation], handle = CreateNamedPipeW([path fileSystemRepresentation],
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_BYTE, PIPE_TYPE_MESSAGE,
PIPE_UNLIMITED_INSTANCES, PIPE_UNLIMITED_INSTANCES,
BUFSIZ*64, BUFSIZ*64,
BUFSIZ*64, BUFSIZ*64,