Stream debug and event handling improvements

This commit is contained in:
rfm 2024-01-30 15:08:31 +00:00
parent 3bc0a58531
commit 46e7064393
5 changed files with 108 additions and 52 deletions

View file

@ -1,8 +1,20 @@
2024-01-08 Richard Frith-Macdonald <rfm@gnu.org>
2024-01-30 Richard Frith-Macdonald <rfm@gnu.org>
* Source/GSFileHandle.m:
* Source/GSPrivate.h:
* Source/GSSocketStream.m:
* Source/GSStream.m:
* Source/unix/GSRunLoopCtxt.m:
Make GSTcpTune options available to streams as well as file handles.
Improve debug logging for streasm operations.
Schedule streams in run loop on conclusion of TLS handshake (so we get
events telling us to start again after a blocked write).
2024-01-29 Richard Frith-Macdonald <rfm@gnu.org>
* Source/NSOperation.m: patch for issue #366 by Larry Campbell.
2024-01-08 Richard Frith-Macdonald <rfm@gnu.org>
2024-01-28 Richard Frith-Macdonald <rfm@gnu.org>
* Source/NSJSONSerialization.m: Fix for issue #365 ... don't try to
create a string ending with the first half of a unicode surrogate pair.

View file

@ -35,6 +35,7 @@
#import "Foundation/NSHost.h"
#import "Foundation/NSByteOrder.h"
#import "Foundation/NSProcessInfo.h"
#import "Foundation/NSStream.h"
#import "Foundation/NSUserDefaults.h"
#import "GSPrivate.h"
#import "GSNetwork.h"
@ -100,21 +101,14 @@ static GSFileHandle *fh_stdin = nil;
static GSFileHandle *fh_stdout = nil;
static GSFileHandle *fh_stderr = nil;
@interface GSTcpTune : NSObject
- (int) delay;
- (int) recvSize;
- (int) sendSize: (int)bytesToSend;
- (void) tune: (void*)handle;
@end
@implementation GSTcpTune
static int tuneDelay = 0;
static int tuneLinger = -1;
static int tuneReceive = 0;
static BOOL tuneSendAll = NO;
static int tuneRBuf = 0;
static int tuneSBuf = 0;
static int tuneRcvBuf = 0;
static int tuneSndBuf = 0;
+ (void) defaultsChanged: (NSNotification*)n
{
@ -134,8 +128,8 @@ static int tuneSBuf = 0;
{
tuneLinger = [str intValue];
}
tuneRBuf = (int)[defs integerForKey: @"GSTcpRcvBuf"];
tuneSBuf = (int)[defs integerForKey: @"GSTcpSndBuf"];
tuneRcvBuf = (int)[defs integerForKey: @"GSTcpRcvBuf"];
tuneSndBuf = (int)[defs integerForKey: @"GSTcpSndBuf"];
tuneReceive = (int)[defs integerForKey: @"GSTcpReceive"];
tuneSendAll = [defs boolForKey: @"GSTcpSendAll"];
tuneDelay = [defs boolForKey: @"GSTcpDelay"];
@ -161,33 +155,33 @@ static int tuneSBuf = 0;
}
}
- (int) delay
+ (int) delay
{
return tuneDelay; // Milliseconds to delay close
}
- (int) recvSize
+ (int) recvSize
{
if (tuneReceive > 0)
{
return tuneReceive; // Return receive buffer size
}
if (tuneRBuf > 0)
if (tuneRcvBuf > 0)
{
return tuneRBuf; // Return socket receive buffer size
return tuneRcvBuf; // Return socket receive buffer size
}
return READ_SIZE; // Return hard-coded default
}
- (int) sendSize: (int)bytesToSend
+ (int) sendSize: (int)bytesToSend
{
if (YES == tuneSendAll)
{
return bytesToSend; // Try to send all in one go
}
if (tuneSBuf > 0 && tuneSBuf <= bytesToSend)
if (tuneSndBuf > 0 && tuneSndBuf <= bytesToSend)
{
return tuneSBuf; // Limit to socket send buffer
return tuneSndBuf; // Limit to socket send buffer
}
if (NETBUF_SIZE <= bytesToSend)
{
@ -196,10 +190,25 @@ static int tuneSBuf = 0;
return bytesToSend;
}
- (void) tune: (void*)handle
+ (void) tune: (void*)handle with: (id)opts
{
int desc = (int)(intptr_t)handle;
int value;
id o;
#ifndef BROKEN_SO_REUSEADDR
/*
* Under decent systems, SO_REUSEADDR means that the port can be reused
* immediately that this process exits. Under some it means
* that multiple processes can serve the same port simultaneously.
* We don't want that broken behavior!
*/
if (setsockopt(desc, SOL_SOCKET, SO_REUSEADDR, (char*)&value, sizeof(value))
< 0)
{
NSDebugMLLog(@"GSTcpTune", @"setsockopt reuseaddr failed for %d", desc);
}
#endif
/*
* Enable tcp-level tracking of whether connection is alive.
@ -208,10 +217,17 @@ static int tuneSBuf = 0;
if (setsockopt(desc, SOL_SOCKET, SO_KEEPALIVE, (char *)&value, sizeof(value))
< 0)
{
NSDebugMLLog(@"GSTcpTune", @"setsockopt keepalive failed");
NSDebugMLLog(@"GSTcpTune", @"setsockopt keepalive failed for %d", desc);
}
if (tuneLinger >= 0)
#define OPTS(X) ([opts isKindOfClass: [NSStream class]] \
? [(NSStream*)opts propertyForKey: X] \
: [(NSDictionary*)opts objectForKey: X])
o = OPTS(@"GSTcpLinger");
value = (o ? [o intValue] : tuneLinger);
if (value >= 0)
{
struct linger l;
@ -219,40 +235,55 @@ static int tuneSBuf = 0;
l.l_linger = tuneLinger;
if (setsockopt(desc, SOL_SOCKET, SO_LINGER, (char *)&l, sizeof(l)) < 0)
{
NSLog(@"Failed to set GSTcpLinger %d: %@",
tuneLinger, [NSError _last]);
NSLog(@"Failed to set GSTcpLinger for %d to %d: %@",
desc, value, [NSError _last]);
}
else
{
NSDebugMLLog(@"GSTcpTune", @"Set GSTcpLinger for %d to %d",
desc, value);
}
}
if (tuneRBuf > 0)
o = OPTS(@"GSTcpRcvBuf");
value = (o ? [o intValue] : tuneRcvBuf);
if (value > 0)
{
/* Set the receive buffer for the socket.
*/
if (setsockopt(desc, SOL_SOCKET, SO_RCVBUF,
(char *)&tuneRBuf, sizeof(tuneRBuf)) < 0)
(char *)&value, sizeof(value)) < 0)
{
NSLog(@"Failed to set GSTcpRcvBuf %d: %@", tuneRBuf, [NSError _last]);
NSLog(@"Failed to set GSTcpRcvBuf for %d to %d: %@",
desc, value, [NSError _last]);
}
else
{
NSDebugMLLog(@"GSTcpTune", @"Set GSTcpRcvBuf %d", tuneRBuf);
NSDebugMLLog(@"GSTcpTune", @"Set GSTcpRcvBuf for %d to %d",
desc, value);
}
}
if (tuneSBuf > 0)
o = OPTS(@"GSTcpSndBuf");
value = (o ? [o intValue] : tuneSndBuf);
if (value > 0)
{
/* Set the send buffer for the socket.
*/
if (setsockopt(desc, SOL_SOCKET, SO_SNDBUF,
(char *)&tuneSBuf, sizeof(tuneSBuf)) < 0)
(char *)&value, sizeof(value)) < 0)
{
NSLog(@"Failed to set GSTcpSndBuf %d: %@", tuneSBuf, [NSError _last]);
NSLog(@"Failed to set GSTcpSndBuf for %d to %d: %@",
desc, value, [NSError _last]);
}
else
{
NSDebugMLLog(@"GSTcpTune", @"Set GSTcpSndBuf %d", tuneSBuf);
NSDebugMLLog(@"GSTcpTune", @"Set GSTcpSndBuf for %d to %d",
desc, value);
}
}
}
@end
// Key to info dictionary for operation mode.
@ -265,14 +296,9 @@ static NSString* NotificationKey = @"NSFileHandleNotificationKey";
@implementation GSFileHandle
static GSTcpTune *tune = nil;
+ (void) initialize
{
if (nil == tune)
{
tune = [GSTcpTune new];
}
[GSTcpTune class];
}
/**
@ -949,7 +975,7 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
return nil;
}
[tune tune: (void*)(intptr_t)net];
[GSTcpTune tune: (void*)(intptr_t)net with: nil];
if (lhost != nil)
{
@ -1431,7 +1457,7 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
- (NSData*) availableData
{
int rmax = [tune recvSize];
int rmax = [GSTcpTune recvSize];
char buf[rmax];
NSMutableData* d;
int len;
@ -1501,7 +1527,7 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
- (NSData*) readDataToEndOfFile
{
int rmax = [tune recvSize];
int rmax = [GSTcpTune recvSize];
char buf[rmax];
NSMutableData* d;
int len;
@ -1529,7 +1555,7 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
{
NSMutableData *d;
int got;
int rmax = [tune recvSize];
int rmax = [GSTcpTune recvSize];
char buf[rmax];
[self checkRead];
@ -1577,7 +1603,7 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
{
int toWrite = len - pos;
toWrite = [tune sendSize: toWrite];
toWrite = [GSTcpTune sendSize: toWrite];
rval = [self write: (char*)ptr+pos length: toWrite];
if (rval < 0)
{
@ -1807,7 +1833,7 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
#endif
if (YES == isSocket)
{
int milli = [tune delay];
int milli = [GSTcpTune delay];
shutdown(descriptor, SHUT_WR);
if (milli > 0)
@ -2168,7 +2194,7 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
struct sockaddr sin;
unsigned int size = sizeof(sin);
[tune tune: (void*)(intptr_t)desc];
[GSTcpTune tune: (void*)(intptr_t)desc with: nil];
h = [[[self class] alloc] initWithFileDescriptor: desc
closeOnDealloc: YES];
@ -2192,7 +2218,7 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
NSMutableData *item;
int length;
int received = 0;
int rmax = [tune recvSize];
int rmax = [GSTcpTune recvSize];
char buf[rmax];
item = [readInfo objectForKey: NSFileHandleNotificationDataItem];

View file

@ -546,6 +546,15 @@ GSPrivateUnloadModule(FILE *errorStream,
- (void) setFrame: (id)aFrame;
@end
/* For tuning socket connections
*/
@interface GSTcpTune : NSObject
+ (int) delay;
+ (int) recvSize;
+ (int) sendSize: (int)bytesToSend;
+ (void) tune: (void*)handle with: (id)opts;
@end
BOOL
GSPrivateIsCollectable(const void *ptr) GS_ATTRIB_PRIVATE;

View file

@ -451,14 +451,14 @@ GSTLSPush(gnutls_transport_ptr_t handle, const void *buffer, size_t len)
{
e = [[[tls ostream] streamError] code];
NSDebugFLLog(@"NSStream",
@"GSTLSPush write for %p error %d (%s)",
@"GSTLSPush write for %@ error %d (%s)",
[tls ostream], e, strerror(e));
}
else
{
e = EAGAIN; // Tell GNUTLS this would block.
NSDebugFLLog(@"NSStream",
@"GSTLSPush write for %p of %lu would block",
@"GSTLSPush write for %@ of %lu would block",
[tls ostream], (unsigned long)len);
}
#if HAVE_GNUTLS_TRANSPORT_SET_ERRNO
@ -470,12 +470,12 @@ GSTLSPush(gnutls_transport_ptr_t handle, const void *buffer, size_t len)
}
if (len != result)
{
NSDebugFLLog(@"NSStream", @"GSTLSPush write for %p of %ld (tried %lu)",
NSDebugFLLog(@"NSStream", @"GSTLSPush write for %@ of %ld (tried %lu)",
[tls ostream], (long)result, (unsigned long)len);
}
else
{
NSDebugFLLog(@"NSStream", @"GSTLSPush write for %p of %ld success",
NSDebugFLLog(@"NSStream", @"GSTLSPush write for %@ of %ld success",
[tls ostream], (long)result);
}
return result;
@ -768,6 +768,7 @@ static NSArray *keys = nil;
{
[istream _resetEvents: NSStreamEventOpenCompleted];
[istream _sendEvent: NSStreamEventOpenCompleted];
[istream _schedule];
}
else
{
@ -780,6 +781,7 @@ static NSArray *keys = nil;
| NSStreamEventHasSpaceAvailable];
[ostream _sendEvent: NSStreamEventOpenCompleted];
[ostream _sendEvent: NSStreamEventHasSpaceAvailable];
[ostream _schedule];
}
else
{
@ -1853,6 +1855,7 @@ setNonBlocking(SOCKET fd)
}
else
{
[GSTcpTune tune: (void*)(intptr_t)s with: self];
[self _setSock: s];
[_sibling _setSock: s];
}
@ -2374,6 +2377,7 @@ setNonBlocking(SOCKET fd)
}
else
{
[GSTcpTune tune: (void*)(intptr_t)s with: self];
[self _setSock: s];
[_sibling _setSock: s];
}
@ -2779,6 +2783,7 @@ setNonBlocking(SOCKET fd)
}
else
{
[GSTcpTune tune: (void*)(intptr_t)s with: self];
[(GSSocketStream*)self _setSock: s];
}

View file

@ -255,6 +255,7 @@ static void setPollfd(int fd, int event, GSRunLoopCtxt *ctxt)
unsigned count;
unsigned int i;
BOOL immediate = NO;
BOOL debug = GSDebugSet(@"NSRunLoop");
i = GSIArrayCount(watchers);
@ -319,18 +320,21 @@ static void setPollfd(int fd, int event, GSRunLoopCtxt *ctxt)
fd = (int)(intptr_t)info->data;
setPollfd(fd, POLLPRI, self);
NSMapInsert(_efdMap, (void*)(intptr_t)fd, info);
if (debug) NSLog(@"listening for EDESC %d", fd);
break;
case ET_RDESC:
fd = (int)(intptr_t)info->data;
setPollfd(fd, POLLIN, self);
NSMapInsert(_rfdMap, (void*)(intptr_t)fd, info);
if (debug) NSLog(@"listening for RDESC %d", fd);
break;
case ET_WDESC:
fd = (int)(intptr_t)info->data;
setPollfd(fd, POLLOUT, self);
NSMapInsert(_wfdMap, (void*)(intptr_t)fd, info);
if (debug) NSLog(@"listening for WDESC %d", fd);
break;
case ET_TRIGGER:
@ -353,7 +357,7 @@ static void setPollfd(int fd, int event, GSRunLoopCtxt *ctxt)
port_fd_array = malloc(sizeof(NSInteger)*port_fd_size);
[port getFds: port_fd_array count: &port_fd_count];
}
NSDebugMLLog(@"NSRunLoop",
if (debug) NSLog(
@"listening to %"PRIdPTR" port handles\n", port_fd_count);
while (port_fd_count--)
{