mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-23 09:04:13 +00:00
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:
parent
32b9892e7b
commit
212c286e3f
6 changed files with 665 additions and 253 deletions
33
ChangeLog
33
ChangeLog
|
@ -1,11 +1,18 @@
|
|||
2006-08-11 Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
||||
* 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>
|
||||
|
||||
* Source\GSStream.m:
|
||||
* Source\win32\NSStreamWin32.m:
|
||||
* Source/GSStream.m:
|
||||
* Source/win32/NSStreamWin32.m:
|
||||
Fix error in pipe read offset. Imitial implementation of local
|
||||
'unix domain sockets' (actually named pipe) stream.
|
||||
|
||||
|
@ -16,10 +23,10 @@
|
|||
|
||||
2006-08-10 Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
||||
* Source\GSStream.h:
|
||||
* Source\GSStream.m:
|
||||
* Source\unix\NSStream.m:
|
||||
* Source\win32\NSStreamWin32.m:
|
||||
* Source/GSStream.h:
|
||||
* Source/GSStream.m:
|
||||
* Source/unix/NSStream.m:
|
||||
* Source/win32/NSStreamWin32.m:
|
||||
Ensure all events are posted. Fixup for winsock write signalling.
|
||||
|
||||
2006-08-09 Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
@ -930,13 +937,13 @@
|
|||
|
||||
* Source/NSUserDefaults.m: Restructure for lazy creation of defaults
|
||||
database ... only create when we attempt to write.
|
||||
* Source\NSSocketPort.m: Include GSPrivate.h
|
||||
* Source\NSRunLoop.m: ditto
|
||||
* Source\unix\GSRunLoopCtxt.m: ditto
|
||||
* Source\GSPrivate.h: ditto
|
||||
* Source\win32\GSFileHandleWin32.m: ditto
|
||||
* Source\win32\GSRunLoopCtxt.m: ditto
|
||||
* Headers\Foundation\NSNotificationQueue.h: Move library internal
|
||||
* Source/NSSocketPort.m: Include GSPrivate.h
|
||||
* Source/NSRunLoop.m: ditto
|
||||
* Source/unix/GSRunLoopCtxt.m: ditto
|
||||
* Source/GSPrivate.h: ditto
|
||||
* Source/win32/GSFileHandleWin32.m: ditto
|
||||
* Source/win32/GSRunLoopCtxt.m: ditto
|
||||
* Headers/Foundation/NSNotificationQueue.h: Move library internal
|
||||
function declarations to GSPrivate.h, thanks to Lloyd Dupont for
|
||||
spotting problem.
|
||||
|
||||
|
|
|
@ -70,7 +70,8 @@ typedef enum {
|
|||
outputStream: (NSOutputStream **)outputStream;
|
||||
|
||||
/**
|
||||
* Closes the receiver.
|
||||
* Closes the receiver.<br />
|
||||
* Repeated calls to this method on the same stream are quietly ignored.
|
||||
*/
|
||||
- (void) close;
|
||||
|
||||
|
@ -80,7 +81,10 @@ typedef enum {
|
|||
- (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;
|
||||
|
||||
|
@ -91,12 +95,17 @@ typedef enum {
|
|||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
|
@ -262,14 +271,17 @@ typedef enum {
|
|||
* that is a stream that binds to a socket and accepts incoming connections
|
||||
*/
|
||||
@interface GSServerStream : NSStream
|
||||
|
||||
/**
|
||||
* Createe a ip (ipv6) server stream
|
||||
*/
|
||||
+ (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;
|
||||
|
||||
/**
|
||||
* This is the method that accepts a connection and generates two streams
|
||||
* as the server side inputStream and OutputStream.
|
||||
|
@ -283,8 +295,10 @@ typedef enum {
|
|||
* the designated initializer for a ip (ipv6) server stream
|
||||
*/
|
||||
- (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;
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
NSStream
|
||||
|-- NSInputStream
|
||||
| `--GSInputStream
|
||||
| |-- GSMemoryInputStream
|
||||
| |-- GSDataInputStream
|
||||
| |-- GSFileInputStream
|
||||
| `-- GSSocketInputStream
|
||||
| |-- GSInetInputStream
|
||||
|
@ -36,7 +36,8 @@
|
|||
| `-- GSInet6InputStream
|
||||
|-- NSOutputStream
|
||||
| `--GSOutputStream
|
||||
| |-- GSMemoryOutputStream
|
||||
| |-- GSBufferOutputStream
|
||||
| |-- GSDataOutputStream
|
||||
| |-- GSFileOutputStream
|
||||
| `-- GSSocketOutputStream
|
||||
| |-- GSInetOutputStream
|
||||
|
@ -144,7 +145,7 @@ IVARS
|
|||
/**
|
||||
* The concrete subclass of NSInputStream that reads from the memory
|
||||
*/
|
||||
@interface GSMemoryInputStream : GSInputStream
|
||||
@interface GSDataInputStream : GSInputStream
|
||||
{
|
||||
@private
|
||||
NSData *_data;
|
||||
|
@ -158,14 +159,30 @@ IVARS
|
|||
@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
|
||||
NSMutableData *_data;
|
||||
unsigned long _pointer;
|
||||
BOOL _fixedSize;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include <Foundation/NSError.h>
|
||||
#include <Foundation/NSValue.h>
|
||||
#include <Foundation/NSHost.h>
|
||||
#include <Foundation/NSDebug.h>
|
||||
|
||||
#include "GSStream.h"
|
||||
|
||||
|
@ -132,9 +133,14 @@ static RunLoopEventType typeForStream(NSStream *aStream)
|
|||
|
||||
- (void) close
|
||||
{
|
||||
NSAssert(_currentStatus != NSStreamStatusNotOpen
|
||||
&& _currentStatus != NSStreamStatusClosed,
|
||||
@"Attempt to close a stream not yet opened.");
|
||||
if (_currentStatus == NSStreamStatusNotOpen)
|
||||
{
|
||||
NSDebugMLog(@"Attempt to close unopened stream %@", self);
|
||||
}
|
||||
if (_currentStatus == NSStreamStatusClosed)
|
||||
{
|
||||
NSDebugMLog(@"Attempt to close already closed stream %@", self);
|
||||
}
|
||||
if (_runloop)
|
||||
{
|
||||
unsigned i = [_modes count];
|
||||
|
@ -186,9 +192,10 @@ static RunLoopEventType typeForStream(NSStream *aStream)
|
|||
|
||||
- (void) open
|
||||
{
|
||||
NSAssert(_currentStatus == NSStreamStatusNotOpen
|
||||
|| _currentStatus == NSStreamStatusOpening,
|
||||
@"Attempt to open a stream already opened.");
|
||||
if (_currentStatus != NSStreamStatusNotOpen)
|
||||
{
|
||||
NSDebugMLog(@"Attempt to re-open stream %@", self);
|
||||
}
|
||||
[self _setStatus: NSStreamStatusOpen];
|
||||
if (_runloop)
|
||||
{
|
||||
|
@ -364,9 +371,6 @@ static RunLoopEventType typeForStream(NSStream *aStream)
|
|||
|
||||
- (void) _sendEvent: (NSStreamEvent)event
|
||||
{
|
||||
NSStreamStatus last = [self streamStatus];
|
||||
NSStreamStatus current;
|
||||
|
||||
if (event == NSStreamEventNone)
|
||||
{
|
||||
return;
|
||||
|
@ -454,21 +458,6 @@ static RunLoopEventType typeForStream(NSStream *aStream)
|
|||
[NSException raise: NSInvalidArgumentException
|
||||
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
|
||||
|
@ -493,18 +482,35 @@ static RunLoopEventType typeForStream(NSStream *aStream)
|
|||
|
||||
- (BOOL) runLoopShouldBlock: (BOOL*)trigger
|
||||
{
|
||||
if ([self _unhandledData] == YES
|
||||
|| _currentStatus == NSStreamStatusError
|
||||
|| _currentStatus == NSStreamStatusAtEnd)
|
||||
if (_events
|
||||
& (NSStreamEventHasBytesAvailable | NSStreamEventHasSpaceAvailable))
|
||||
{
|
||||
/* If we have an unhandled data event, we should not watch for more
|
||||
* or trigger until the appropriate rad or write has been done.
|
||||
* If an error has occurred, we should not watch for any events at all.
|
||||
* or trigger until the appropriate read or write has been done.
|
||||
*/
|
||||
*trigger = 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
|
||||
* input, so it must trigger an event when the loop runs and must not
|
||||
|
@ -522,6 +528,7 @@ static RunLoopEventType typeForStream(NSStream *aStream)
|
|||
@end
|
||||
|
||||
@implementation GSInputStream
|
||||
|
||||
+ (void) initialize
|
||||
{
|
||||
if (self == [GSInputStream class])
|
||||
|
@ -529,9 +536,31 @@ static RunLoopEventType typeForStream(NSStream *aStream)
|
|||
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
|
||||
|
||||
@implementation GSOutputStream
|
||||
|
||||
+ (void) initialize
|
||||
{
|
||||
if (self == [GSOutputStream class])
|
||||
|
@ -539,6 +568,27 @@ static RunLoopEventType typeForStream(NSStream *aStream)
|
|||
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
|
||||
@implementation GSAbstractServerStream
|
||||
+ (void) initialize
|
||||
|
@ -551,7 +601,7 @@ static RunLoopEventType typeForStream(NSStream *aStream)
|
|||
@end
|
||||
|
||||
|
||||
@implementation GSMemoryInputStream
|
||||
@implementation GSDataInputStream
|
||||
|
||||
/**
|
||||
* the designated initializer
|
||||
|
@ -576,10 +626,28 @@ static RunLoopEventType typeForStream(NSStream *aStream)
|
|||
|
||||
- (int) read: (uint8_t *)buffer maxLength: (unsigned int)len
|
||||
{
|
||||
unsigned long dataSize = [_data length];
|
||||
unsigned long dataSize;
|
||||
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;
|
||||
|
||||
if ([self streamStatus] == NSStreamStatusClosed)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
dataSize = [_data length];
|
||||
NSAssert(dataSize >= _pointer, @"Buffer overflow!");
|
||||
if (len + _pointer > dataSize)
|
||||
{
|
||||
|
@ -597,6 +665,7 @@ static RunLoopEventType typeForStream(NSStream *aStream)
|
|||
else
|
||||
{
|
||||
[self _setStatus: NSStreamStatusAtEnd];
|
||||
[self _sendEvent: NSStreamEventEndEncountered];
|
||||
}
|
||||
return copySize;
|
||||
}
|
||||
|
@ -639,71 +708,132 @@ static RunLoopEventType typeForStream(NSStream *aStream)
|
|||
@end
|
||||
|
||||
|
||||
@implementation GSMemoryOutputStream
|
||||
@implementation GSBufferOutputStream
|
||||
|
||||
- (id) initToBuffer: (uint8_t *)buffer capacity: (unsigned int)capacity
|
||||
{
|
||||
if ((self = [super init]) != nil)
|
||||
{
|
||||
if (!buffer)
|
||||
{
|
||||
_data = [NSMutableData new];
|
||||
_fixedSize = NO;
|
||||
}
|
||||
else
|
||||
{
|
||||
_data = [[NSMutableData alloc] initWithBytesNoCopy: buffer
|
||||
length: capacity freeWhenDone: NO];
|
||||
_fixedSize = YES;
|
||||
}
|
||||
_buffer = buffer;
|
||||
_capacity = capacity;
|
||||
_pointer = 0;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
RELEASE(_data);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (int) write: (const uint8_t *)buffer maxLength: (unsigned int)len
|
||||
{
|
||||
_events &= ~NSStreamEventHasBytesAvailable;
|
||||
if (_fixedSize)
|
||||
if (buffer == 0)
|
||||
{
|
||||
unsigned long dataLen = [_data length];
|
||||
uint8_t *origin = (uint8_t *)[_data mutableBytes];
|
||||
|
||||
if (_pointer+len>dataLen)
|
||||
len = dataLen - _pointer;
|
||||
memcpy(origin+_pointer, buffer, len);
|
||||
_pointer = _pointer + len;
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"null pointer for buffer"];
|
||||
}
|
||||
if (len == 0)
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"zero byte length write requested"];
|
||||
}
|
||||
else
|
||||
[_data appendBytes: buffer length: len];
|
||||
return len;
|
||||
}
|
||||
|
||||
- (BOOL) hasSpaceAvailable
|
||||
{
|
||||
if (_fixedSize)
|
||||
return [_data length]>_pointer;
|
||||
else
|
||||
return YES;
|
||||
_events &= ~NSStreamEventHasBytesAvailable;
|
||||
|
||||
if ([self streamStatus] == NSStreamStatusClosed)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
if ([key isEqualToString: NSStreamFileCurrentOffsetKey])
|
||||
{
|
||||
if (_fixedSize)
|
||||
return [NSNumber numberWithLong: _pointer];
|
||||
else
|
||||
return [NSNumber numberWithLong:[_data length]];
|
||||
return [NSNumber numberWithLong: _pointer];
|
||||
}
|
||||
return [super propertyForKey: key];
|
||||
}
|
||||
|
||||
- (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];
|
||||
}
|
||||
|
||||
|
|
|
@ -297,7 +297,24 @@ static void setNonblocking(int fd)
|
|||
{
|
||||
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;
|
||||
|
||||
if ([self streamStatus] == NSStreamStatusClosed)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
readLen = read((intptr_t)_loopID, buffer, len);
|
||||
if (readLen < 0 && errno != EAGAIN && errno != EINTR)
|
||||
[self _recordError];
|
||||
|
@ -475,7 +492,24 @@ static void setNonblocking(int fd)
|
|||
{
|
||||
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;
|
||||
|
||||
if ([self streamStatus] == NSStreamStatusClosed)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
readLen = read((intptr_t)_loopID, buffer, len);
|
||||
if (readLen < 0 && errno != EAGAIN && errno != EINTR)
|
||||
[self _recordError];
|
||||
|
@ -676,7 +710,24 @@ static void setNonblocking(int fd)
|
|||
{
|
||||
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;
|
||||
|
||||
if ([self streamStatus] == NSStreamStatusClosed)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
writeLen = write((intptr_t)_loopID, buffer, len);
|
||||
if (writeLen < 0 && errno != EAGAIN && errno != EINTR)
|
||||
[self _recordError];
|
||||
|
@ -790,7 +841,24 @@ static void setNonblocking(int fd)
|
|||
{
|
||||
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;
|
||||
|
||||
if ([self streamStatus] == NSStreamStatusClosed)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
writeLen = write((intptr_t)_loopID, buffer, len);
|
||||
if (writeLen < 0 && errno != EAGAIN && errno != EINTR)
|
||||
[self _recordError];
|
||||
|
@ -1186,7 +1254,7 @@ static void setNonblocking(int fd)
|
|||
|
||||
+ (id) inputStreamWithData: (NSData *)data
|
||||
{
|
||||
return AUTORELEASE([[GSMemoryInputStream alloc] initWithData: data]);
|
||||
return AUTORELEASE([[GSDataInputStream alloc] initWithData: data]);
|
||||
}
|
||||
|
||||
+ (id) inputStreamWithFileAtPath: (NSString *)path
|
||||
|
@ -1194,24 +1262,6 @@ static void setNonblocking(int fd)
|
|||
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
|
||||
{
|
||||
[self subclassResponsibility: _cmd];
|
||||
|
@ -1224,19 +1274,31 @@ static void setNonblocking(int fd)
|
|||
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
|
||||
|
||||
@implementation NSOutputStream
|
||||
|
||||
+ (id) outputStreamToMemory
|
||||
{
|
||||
return AUTORELEASE([[GSMemoryOutputStream alloc]
|
||||
initToBuffer: NULL capacity: 0]);
|
||||
}
|
||||
|
||||
+ (id) outputStreamToBuffer: (uint8_t *)buffer capacity: (unsigned int)capacity
|
||||
{
|
||||
return AUTORELEASE([[GSMemoryOutputStream alloc]
|
||||
return AUTORELEASE([[GSBufferOutputStream alloc]
|
||||
initToBuffer: buffer capacity: capacity]);
|
||||
}
|
||||
|
||||
|
@ -1246,16 +1308,21 @@ static void setNonblocking(int fd)
|
|||
initToFileAtPath: path append: shouldAppend]);
|
||||
}
|
||||
|
||||
- (id) initToMemory
|
||||
+ (id) outputStreamToMemory
|
||||
{
|
||||
RELEASE(self);
|
||||
return [[GSMemoryOutputStream alloc] initToBuffer: NULL capacity: 0];
|
||||
return AUTORELEASE([[GSDataOutputStream alloc] init]);
|
||||
}
|
||||
|
||||
- (BOOL) hasSpaceAvailable
|
||||
{
|
||||
[self subclassResponsibility: _cmd];
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (id) initToBuffer: (uint8_t *)buffer capacity: (unsigned int)capacity
|
||||
{
|
||||
RELEASE(self);
|
||||
return [[GSMemoryOutputStream alloc] initToBuffer: buffer capacity: capacity];
|
||||
return [[GSBufferOutputStream alloc] initToBuffer: buffer capacity: capacity];
|
||||
}
|
||||
|
||||
- (id) initToFileAtPath: (NSString *)path append: (BOOL)shouldAppend
|
||||
|
@ -1265,18 +1332,18 @@ static void setNonblocking(int fd)
|
|||
append: shouldAppend];
|
||||
}
|
||||
|
||||
- (id) initToMemory
|
||||
{
|
||||
RELEASE(self);
|
||||
return [[GSDataOutputStream alloc] init];
|
||||
}
|
||||
|
||||
- (int) write: (const uint8_t *)buffer maxLength: (unsigned int)len
|
||||
{
|
||||
[self subclassResponsibility: _cmd];
|
||||
return -1;
|
||||
}
|
||||
|
||||
- (BOOL) hasSpaceAvailable
|
||||
{
|
||||
[self subclassResponsibility: _cmd];
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation GSServerStream
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include <Foundation/NSValue.h>
|
||||
#include <Foundation/NSHost.h>
|
||||
#include <Foundation/NSProcessInfo.h>
|
||||
#include <Foundation/NSDebug.h>
|
||||
|
||||
#include "../GSStream.h"
|
||||
|
||||
|
@ -73,6 +74,7 @@ typedef int socklen_t;
|
|||
unsigned want; // Amount of data we want to read.
|
||||
DWORD size; // Number of bytes returned by read.
|
||||
GSPipeOutputStream *_sibling;
|
||||
BOOL hadEOF;
|
||||
}
|
||||
- (NSStreamStatus) _check;
|
||||
- (void) _queue;
|
||||
|
@ -154,6 +156,8 @@ typedef int socklen_t;
|
|||
unsigned want;
|
||||
DWORD size;
|
||||
GSPipeInputStream *_sibling;
|
||||
BOOL closing;
|
||||
BOOL writtenEOF;
|
||||
}
|
||||
- (NSStreamStatus) _check;
|
||||
- (void) _queue;
|
||||
|
@ -298,13 +302,6 @@ static void setNonblocking(SOCKET fd)
|
|||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL) hasBytesAvailable
|
||||
{
|
||||
if ([self _isOpened] && [self streamStatus] != NSStreamStatusAtEnd)
|
||||
return YES;
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (id) initWithFileAtPath: (NSString *)path
|
||||
{
|
||||
if ((self = [super init]) != nil)
|
||||
|
@ -351,7 +348,24 @@ static void setNonblocking(SOCKET fd)
|
|||
{
|
||||
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;
|
||||
|
||||
if ([self streamStatus] == NSStreamStatusClosed)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ReadFile((HANDLE)_loopID, buffer, len, &readLen, NULL) == 0)
|
||||
{
|
||||
[self _recordError];
|
||||
|
@ -360,6 +374,7 @@ static void setNonblocking(SOCKET fd)
|
|||
else if (readLen == 0)
|
||||
{
|
||||
[self _setStatus: NSStreamStatusAtEnd];
|
||||
[self _sendEvent: NSStreamEventEndEncountered];
|
||||
}
|
||||
return (int)readLen;
|
||||
}
|
||||
|
@ -383,26 +398,43 @@ static void setNonblocking(SOCKET fd)
|
|||
|
||||
- (void) close
|
||||
{
|
||||
if (want > 0 && handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
want = 0;
|
||||
CancelIo(handle);
|
||||
}
|
||||
length = offset = 0;
|
||||
if (_loopID != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
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];
|
||||
handle = INVALID_HANDLE_VALUE;
|
||||
_loopID = (void*)INVALID_HANDLE_VALUE;
|
||||
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
|
@ -426,13 +458,6 @@ static void setNonblocking(SOCKET fd)
|
|||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL) hasBytesAvailable
|
||||
{
|
||||
if ([self streamStatus] == NSStreamStatusOpen)
|
||||
return YES;
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (id) init
|
||||
{
|
||||
if ((self = [super init]) != nil)
|
||||
|
@ -459,8 +484,8 @@ static void setNonblocking(SOCKET fd)
|
|||
|
||||
if (GetOverlappedResult(handle, &ov, &size, TRUE) == 0)
|
||||
{
|
||||
errno = GetLastError();
|
||||
if (errno == ERROR_HANDLE_EOF
|
||||
if ((errno = GetLastError()) == ERROR_HANDLE_EOF
|
||||
|| errno == ERROR_PIPE_NOT_CONNECTED
|
||||
|| errno == ERROR_BROKEN_PIPE)
|
||||
{
|
||||
/*
|
||||
|
@ -469,6 +494,7 @@ static void setNonblocking(SOCKET fd)
|
|||
*/
|
||||
offset = length = want = 0;
|
||||
[self _setStatus: NSStreamStatusOpen];
|
||||
hadEOF = YES;
|
||||
}
|
||||
else if (errno != ERROR_IO_PENDING)
|
||||
{
|
||||
|
@ -479,6 +505,12 @@ static void setNonblocking(SOCKET fd)
|
|||
[self _recordError];
|
||||
}
|
||||
}
|
||||
else if (size == 0)
|
||||
{
|
||||
length = want = 0;
|
||||
[self _setStatus: NSStreamStatusOpen];
|
||||
hadEOF = YES;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
|
@ -492,7 +524,7 @@ static void setNonblocking(SOCKET fd)
|
|||
|
||||
- (void) _queue
|
||||
{
|
||||
if ([self streamStatus] == NSStreamStatusOpen)
|
||||
if (hadEOF == NO && [self streamStatus] == NSStreamStatusOpen)
|
||||
{
|
||||
int rc;
|
||||
|
||||
|
@ -508,14 +540,14 @@ static void setNonblocking(SOCKET fd)
|
|||
length = size;
|
||||
if (length == 0)
|
||||
{
|
||||
[self _setStatus: NSStreamStatusAtEnd];
|
||||
hadEOF = YES;
|
||||
}
|
||||
}
|
||||
else if ((errno = GetLastError()) == ERROR_HANDLE_EOF
|
||||
|| errno == ERROR_PIPE_NOT_CONNECTED
|
||||
|| errno == ERROR_BROKEN_PIPE)
|
||||
{
|
||||
offset = length = 0;
|
||||
[self _setStatus: NSStreamStatusOpen]; // Read of zero length
|
||||
hadEOF = YES;
|
||||
}
|
||||
else if (errno != ERROR_IO_PENDING)
|
||||
{
|
||||
|
@ -530,24 +562,38 @@ static void setNonblocking(SOCKET fd)
|
|||
|
||||
- (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;
|
||||
|
||||
myStatus = [self streamStatus];
|
||||
if (myStatus == NSStreamStatusReading)
|
||||
{
|
||||
myStatus = [self _check];
|
||||
}
|
||||
if (myStatus == NSStreamStatusAtEnd)
|
||||
if (myStatus == NSStreamStatusClosed)
|
||||
{
|
||||
return 0; // At EOF
|
||||
}
|
||||
if (len <= 0
|
||||
|| (myStatus != NSStreamStatusReading && myStatus != NSStreamStatusOpen))
|
||||
{
|
||||
return -1; // Bad length or status
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (offset == length)
|
||||
{
|
||||
if (myStatus == NSStreamStatusError)
|
||||
{
|
||||
[self _sendEvent: NSStreamEventErrorOccurred];
|
||||
return -1; // Waiting for read.
|
||||
}
|
||||
if (myStatus == NSStreamStatusOpen)
|
||||
{
|
||||
/*
|
||||
|
@ -555,10 +601,11 @@ static void setNonblocking(SOCKET fd)
|
|||
* so we must be at EOF.
|
||||
*/
|
||||
[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.
|
||||
*/
|
||||
|
@ -775,7 +822,24 @@ static void setNonblocking(SOCKET fd)
|
|||
{
|
||||
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;
|
||||
|
||||
if ([self streamStatus] == NSStreamStatusClosed)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
readLen = recv(_sock, buffer, len, 0);
|
||||
if (readLen == SOCKET_ERROR)
|
||||
{
|
||||
|
@ -806,13 +870,6 @@ static void setNonblocking(SOCKET fd)
|
|||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL) hasBytesAvailable
|
||||
{
|
||||
if ([self streamStatus] == NSStreamStatusOpen)
|
||||
return YES;
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void) _dispatch
|
||||
{
|
||||
/*
|
||||
|
@ -995,13 +1052,6 @@ static void setNonblocking(SOCKET fd)
|
|||
[super dealloc];
|
||||
}
|
||||
|
||||
- (BOOL) hasSpaceAvailable
|
||||
{
|
||||
if ([self streamStatus] == NSStreamStatusOpen)
|
||||
return YES;
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (id) initToFileAtPath: (NSString *)path append: (BOOL)shouldAppend
|
||||
{
|
||||
if ((self = [super init]) != nil)
|
||||
|
@ -1056,7 +1106,24 @@ static void setNonblocking(SOCKET fd)
|
|||
{
|
||||
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;
|
||||
|
||||
if ([self streamStatus] == NSStreamStatusClosed)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (_shouldAppend == YES)
|
||||
{
|
||||
SetFilePointer((HANDLE)_loopID, 0, 0, FILE_END);
|
||||
|
@ -1084,21 +1151,67 @@ static void setNonblocking(SOCKET fd)
|
|||
|
||||
- (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)
|
||||
{
|
||||
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];
|
||||
_loopID = (void*)INVALID_HANDLE_VALUE;
|
||||
handle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
|
@ -1112,13 +1225,6 @@ static void setNonblocking(SOCKET fd)
|
|||
[super dealloc];
|
||||
}
|
||||
|
||||
- (BOOL) hasSpaceAvailable
|
||||
{
|
||||
if ([self streamStatus] == NSStreamStatusOpen)
|
||||
return YES;
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (id) init
|
||||
{
|
||||
if ((self = [super init]) != nil)
|
||||
|
@ -1179,19 +1285,33 @@ static void setNonblocking(SOCKET fd)
|
|||
{
|
||||
NSStreamStatus myStatus = [self streamStatus];
|
||||
|
||||
_events &= ~NSStreamEventHasSpaceAvailable;
|
||||
if (len < 0)
|
||||
if (buffer == 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)
|
||||
{
|
||||
myStatus = [self _check];
|
||||
}
|
||||
if (myStatus == NSStreamStatusClosed)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((myStatus != NSStreamStatusOpen && myStatus != NSStreamStatusWriting))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (len > (sizeof(data) - offset))
|
||||
{
|
||||
len = sizeof(data) - offset;
|
||||
|
@ -1231,6 +1351,10 @@ static void setNonblocking(SOCKET fd)
|
|||
offset = want = 0;
|
||||
}
|
||||
}
|
||||
if (closing == YES && [self streamStatus] != NSStreamStatusWriting)
|
||||
{
|
||||
[self close];
|
||||
}
|
||||
return [self streamStatus];
|
||||
}
|
||||
|
||||
|
@ -1313,7 +1437,7 @@ static void setNonblocking(SOCKET fd)
|
|||
_sibling = sibling;
|
||||
}
|
||||
|
||||
-(void)setPassive: (BOOL)passive
|
||||
-(void) setPassive: (BOOL)passive
|
||||
{
|
||||
_passive = passive;
|
||||
}
|
||||
|
@ -1354,7 +1478,24 @@ static void setNonblocking(SOCKET fd)
|
|||
{
|
||||
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;
|
||||
|
||||
if ([self streamStatus] == NSStreamStatusClosed)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
writeLen = send(_sock, buffer, len, 0);
|
||||
if (writeLen == SOCKET_ERROR)
|
||||
{
|
||||
|
@ -1376,13 +1517,6 @@ static void setNonblocking(SOCKET fd)
|
|||
return writeLen;
|
||||
}
|
||||
|
||||
- (BOOL) hasSpaceAvailable
|
||||
{
|
||||
if ([self streamStatus] == NSStreamStatusOpen)
|
||||
return YES;
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void) open
|
||||
{
|
||||
// could be opened because of sibling
|
||||
|
@ -1691,16 +1825,37 @@ static void setNonblocking(SOCKET fd)
|
|||
SECURITY_ATTRIBUTES saAttr;
|
||||
HANDLE handle;
|
||||
|
||||
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||
saAttr.bInheritHandle = TRUE;
|
||||
saAttr.lpSecurityDescriptor = NULL;
|
||||
if ([path length] == 0)
|
||||
{
|
||||
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
|
||||
*/
|
||||
name = [[@"\\\\.\\pipe\\" stringByAppendingString: path]
|
||||
name = [[@"\\\\.\\pipe\\GSLocal" stringByAppendingString: path]
|
||||
fileSystemRepresentation];
|
||||
|
||||
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||
saAttr.bInheritHandle = TRUE;
|
||||
saAttr.lpSecurityDescriptor = NULL;
|
||||
|
||||
handle = CreateFileW(name,
|
||||
GENERIC_WRITE|GENERIC_READ,
|
||||
0,
|
||||
|
@ -1720,15 +1875,17 @@ static void setNonblocking(SOCKET fd)
|
|||
outs = AUTORELEASE([GSPipeOutputStream new]);
|
||||
|
||||
[ins _setHandle: handle];
|
||||
[ins setSibling: outs];
|
||||
[outs _setHandle: handle];
|
||||
[outs setSibling: ins];
|
||||
|
||||
done:
|
||||
if (inputStream)
|
||||
{
|
||||
[ins setSibling: outs];
|
||||
*inputStream = ins;
|
||||
}
|
||||
if (outputStream)
|
||||
{
|
||||
[outs setSibling: ins];
|
||||
*outputStream = outs;
|
||||
}
|
||||
}
|
||||
|
@ -1875,7 +2032,7 @@ static void setNonblocking(SOCKET fd)
|
|||
|
||||
+ (id) inputStreamWithData: (NSData *)data
|
||||
{
|
||||
return AUTORELEASE([[GSMemoryInputStream alloc] initWithData: data]);
|
||||
return AUTORELEASE([[GSDataInputStream alloc] initWithData: data]);
|
||||
}
|
||||
|
||||
+ (id) inputStreamWithFileAtPath: (NSString *)path
|
||||
|
@ -1883,24 +2040,6 @@ static void setNonblocking(SOCKET fd)
|
|||
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
|
||||
{
|
||||
[self subclassResponsibility: _cmd];
|
||||
|
@ -1913,19 +2052,36 @@ static void setNonblocking(SOCKET fd)
|
|||
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
|
||||
|
||||
@implementation NSOutputStream
|
||||
|
||||
+ (id) outputStreamToMemory
|
||||
{
|
||||
return AUTORELEASE([[GSMemoryOutputStream alloc]
|
||||
initToBuffer: NULL capacity: 0]);
|
||||
return AUTORELEASE([[GSDataOutputStream alloc] init]);
|
||||
}
|
||||
|
||||
+ (id) outputStreamToBuffer: (uint8_t *)buffer capacity: (unsigned int)capacity
|
||||
{
|
||||
return AUTORELEASE([[GSMemoryOutputStream alloc]
|
||||
return AUTORELEASE([[GSBufferOutputStream alloc]
|
||||
initToBuffer: buffer capacity: capacity]);
|
||||
}
|
||||
|
||||
|
@ -1935,16 +2091,16 @@ static void setNonblocking(SOCKET fd)
|
|||
initToFileAtPath: path append: shouldAppend]);
|
||||
}
|
||||
|
||||
- (id) initToMemory
|
||||
- (BOOL) hasSpaceAvailable
|
||||
{
|
||||
RELEASE(self);
|
||||
return [[GSMemoryOutputStream alloc] initToBuffer: NULL capacity: 0];
|
||||
[self subclassResponsibility: _cmd];
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (id) initToBuffer: (uint8_t *)buffer capacity: (unsigned int)capacity
|
||||
{
|
||||
RELEASE(self);
|
||||
return [[GSMemoryOutputStream alloc] initToBuffer: buffer capacity: capacity];
|
||||
return [[GSBufferOutputStream alloc] initToBuffer: buffer capacity: capacity];
|
||||
}
|
||||
|
||||
- (id) initToFileAtPath: (NSString *)path append: (BOOL)shouldAppend
|
||||
|
@ -1954,18 +2110,18 @@ static void setNonblocking(SOCKET fd)
|
|||
append: shouldAppend];
|
||||
}
|
||||
|
||||
- (id) initToMemory
|
||||
{
|
||||
RELEASE(self);
|
||||
return [[GSDataOutputStream alloc] init];
|
||||
}
|
||||
|
||||
- (int) write: (const uint8_t *)buffer maxLength: (unsigned int)len
|
||||
{
|
||||
[self subclassResponsibility: _cmd];
|
||||
return -1;
|
||||
}
|
||||
|
||||
- (BOOL) hasSpaceAvailable
|
||||
{
|
||||
[self subclassResponsibility: _cmd];
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation GSServerStream
|
||||
|
@ -2213,9 +2369,30 @@ static void setNonblocking(SOCKET fd)
|
|||
|
||||
- (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)
|
||||
{
|
||||
path = RETAIN([@"\\\\.\\pipe\\" stringByAppendingString: addr]);
|
||||
path = RETAIN([@"\\\\.\\pipe\\GSLocal" stringByAppendingString: addr]);
|
||||
_loopID = INVALID_HANDLE_VALUE;
|
||||
handle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
@ -2245,7 +2422,7 @@ static void setNonblocking(SOCKET fd)
|
|||
|
||||
handle = CreateNamedPipeW([path fileSystemRepresentation],
|
||||
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
|
||||
PIPE_TYPE_BYTE,
|
||||
PIPE_TYPE_MESSAGE,
|
||||
PIPE_UNLIMITED_INSTANCES,
|
||||
BUFSIZ*64,
|
||||
BUFSIZ*64,
|
||||
|
|
Loading…
Reference in a new issue