mirror of
https://github.com/gnustep/libs-base.git
synced 2025-05-31 08:41:03 +00:00
try to ensure all data is written on socket shutdown
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@37402 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
0ace917077
commit
ce3811fd7a
1 changed files with 189 additions and 58 deletions
|
@ -95,13 +95,156 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Maximum data in single I/O operation
|
// Maximum data in single I/O operation
|
||||||
#define NETBUF_SIZE 4096
|
#define NETBUF_SIZE (1024 * 16)
|
||||||
#define READ_SIZE NETBUF_SIZE*10
|
#define READ_SIZE NETBUF_SIZE*10
|
||||||
|
|
||||||
static GSFileHandle* fh_stdin = nil;
|
static GSFileHandle* fh_stdin = nil;
|
||||||
static GSFileHandle* fh_stdout = nil;
|
static GSFileHandle* fh_stdout = nil;
|
||||||
static GSFileHandle* fh_stderr = nil;
|
static GSFileHandle* fh_stderr = nil;
|
||||||
|
|
||||||
|
@interface GSTcpTune : NSObject
|
||||||
|
- (int) recvSize;
|
||||||
|
- (int) sendSize: (int)bytesToSend;
|
||||||
|
- (void) tune: (void*)handle;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation GSTcpTune
|
||||||
|
|
||||||
|
static int tuneLinger = -1;
|
||||||
|
static int tuneReceive = 0;
|
||||||
|
static BOOL tuneSendAll = NO;
|
||||||
|
static int tuneRBuf = 0;
|
||||||
|
static int tuneSBuf = 0;
|
||||||
|
|
||||||
|
+ (void) defaultsChanged: (NSNotification*)n
|
||||||
|
{
|
||||||
|
NSUserDefaults *defs = (NSUserDefaults*)[n object];
|
||||||
|
NSString *str;
|
||||||
|
|
||||||
|
if (nil == defs)
|
||||||
|
{
|
||||||
|
defs = [NSUserDefaults standardUserDefaults];
|
||||||
|
}
|
||||||
|
str = [defs stringForKey: @"GSTcpLinger"];
|
||||||
|
if (nil == str)
|
||||||
|
{
|
||||||
|
tuneLinger = -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tuneLinger = [str intValue];
|
||||||
|
}
|
||||||
|
tuneRBuf = (int)[defs integerForKey: @"GSTcpRcvBuf"];
|
||||||
|
tuneSBuf = (int)[defs integerForKey: @"GSTcpSndBuf"];
|
||||||
|
tuneReceive = (int)[defs integerForKey: @"GSTcpReceive"];
|
||||||
|
tuneSendAll = [defs boolForKey: @"GSTcpSendAll"];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void) initialize
|
||||||
|
{
|
||||||
|
static BOOL beenHere = NO;
|
||||||
|
|
||||||
|
if (NO == beenHere)
|
||||||
|
{
|
||||||
|
NSNotificationCenter *nc;
|
||||||
|
NSUserDefaults *defs;
|
||||||
|
|
||||||
|
beenHere = YES;
|
||||||
|
nc = [NSNotificationCenter defaultCenter];
|
||||||
|
defs = [NSUserDefaults standardUserDefaults];
|
||||||
|
[nc addObserver: self
|
||||||
|
selector: @selector(defaultsChanged:)
|
||||||
|
name: NSUserDefaultsDidChangeNotification
|
||||||
|
object: defs];
|
||||||
|
[self defaultsChanged: nil];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (int) recvSize
|
||||||
|
{
|
||||||
|
if (tuneReceive > 0)
|
||||||
|
{
|
||||||
|
return tuneReceive; // Return receive buffer size
|
||||||
|
}
|
||||||
|
if (tuneRBuf > 0)
|
||||||
|
{
|
||||||
|
return tuneRBuf; // Return socket receive buffer size
|
||||||
|
}
|
||||||
|
return READ_SIZE; // Return hard-coded default
|
||||||
|
}
|
||||||
|
|
||||||
|
- (int) sendSize: (int)bytesToSend
|
||||||
|
{
|
||||||
|
if (YES == tuneSendAll)
|
||||||
|
{
|
||||||
|
return bytesToSend; // Try to send all in one go
|
||||||
|
}
|
||||||
|
if (tuneSBuf > 0 && tuneSBuf <= bytesToSend)
|
||||||
|
{
|
||||||
|
return tuneSBuf; // Limit to socket send buffer
|
||||||
|
}
|
||||||
|
if (NETBUF_SIZE <= bytesToSend)
|
||||||
|
{
|
||||||
|
return NETBUF_SIZE; // Limit to hard coded default
|
||||||
|
}
|
||||||
|
return bytesToSend;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) tune: (void*)handle
|
||||||
|
{
|
||||||
|
int desc = (int)(intptr_t)handle;
|
||||||
|
int value;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enable tcp-level tracking of whether connection is alive.
|
||||||
|
*/
|
||||||
|
value = 1;
|
||||||
|
setsockopt(desc, SOL_SOCKET, SO_KEEPALIVE, (char *)&value, sizeof(value));
|
||||||
|
|
||||||
|
if (tuneLinger >= 0)
|
||||||
|
{
|
||||||
|
struct linger l;
|
||||||
|
|
||||||
|
l.l_onoff = 1;
|
||||||
|
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]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tuneRBuf > 0)
|
||||||
|
{
|
||||||
|
/* Set the receive buffer for the socket.
|
||||||
|
*/
|
||||||
|
if (setsockopt(desc, SOL_SOCKET, SO_RCVBUF,
|
||||||
|
(char *)&tuneRBuf, sizeof(tuneRBuf)) < 0)
|
||||||
|
{
|
||||||
|
NSLog(@"Failed to set GSTcpRcvBuf %d: %@", tuneRBuf, [NSError _last]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
NSDebugMLLog(@"GSTcpTune", @"Set GSTcpRcvBuf %d", tuneRBuf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tuneSBuf > 0)
|
||||||
|
{
|
||||||
|
/* Set the send buffer for the socket.
|
||||||
|
*/
|
||||||
|
if (setsockopt(desc, SOL_SOCKET, SO_SNDBUF,
|
||||||
|
(char *)&tuneSBuf, sizeof(tuneSBuf)) < 0)
|
||||||
|
{
|
||||||
|
NSLog(@"Failed to set GSTcpSndBuf %d: %@", tuneSBuf, [NSError _last]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
NSDebugMLLog(@"GSTcpTune", @"Set GSTcpSndBuf %d", tuneSBuf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
// Key to info dictionary for operation mode.
|
// Key to info dictionary for operation mode.
|
||||||
static NSString* NotificationKey = @"NSFileHandleNotificationKey";
|
static NSString* NotificationKey = @"NSFileHandleNotificationKey";
|
||||||
|
|
||||||
|
@ -112,6 +255,16 @@ static NSString* NotificationKey = @"NSFileHandleNotificationKey";
|
||||||
|
|
||||||
@implementation GSFileHandle
|
@implementation GSFileHandle
|
||||||
|
|
||||||
|
static GSTcpTune *tune = nil;
|
||||||
|
|
||||||
|
+ (void) initialize
|
||||||
|
{
|
||||||
|
if (nil == tune)
|
||||||
|
{
|
||||||
|
tune = [GSTcpTune new];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encapsulates low level read operation to get data from the operating
|
* Encapsulates low level read operation to get data from the operating
|
||||||
* system.
|
* system.
|
||||||
|
@ -608,8 +761,6 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
|
||||||
{
|
{
|
||||||
static NSString *esocks = nil;
|
static NSString *esocks = nil;
|
||||||
static NSString *dsocks = nil;
|
static NSString *dsocks = nil;
|
||||||
static int rbuf = 0;
|
|
||||||
static int sbuf = 0;
|
|
||||||
static BOOL beenHere = NO;
|
static BOOL beenHere = NO;
|
||||||
int net;
|
int net;
|
||||||
struct sockaddr sin;
|
struct sockaddr sin;
|
||||||
|
@ -617,7 +768,6 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
|
||||||
NSString *lhost = nil;
|
NSString *lhost = nil;
|
||||||
NSString *shost = nil;
|
NSString *shost = nil;
|
||||||
NSString *sport = nil;
|
NSString *sport = nil;
|
||||||
int status;
|
|
||||||
|
|
||||||
if (beenHere == NO)
|
if (beenHere == NO)
|
||||||
{
|
{
|
||||||
|
@ -638,8 +788,6 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
|
||||||
}
|
}
|
||||||
esocks = [esocks copy];
|
esocks = [esocks copy];
|
||||||
}
|
}
|
||||||
rbuf = (int)[defs integerForKey: @"GSTcpRcvBuf"];
|
|
||||||
sbuf = (int)[defs integerForKey: @"GSTcpSndBuf"];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (a == nil || [a isEqualToString: @""])
|
if (a == nil || [a isEqualToString: @""])
|
||||||
|
@ -752,40 +900,8 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
|
||||||
DESTROY(self);
|
DESTROY(self);
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
* Enable tcp-level tracking of whether connection is alive.
|
|
||||||
*/
|
|
||||||
status = 1;
|
|
||||||
setsockopt(net, SOL_SOCKET, SO_KEEPALIVE, (char *)&status, sizeof(status));
|
|
||||||
|
|
||||||
if (rbuf > 0)
|
[tune tune: (void*)(intptr_t)net];
|
||||||
{
|
|
||||||
/* Set the receive buffer for the socket.
|
|
||||||
*/
|
|
||||||
if (setsockopt(net, SOL_SOCKET, SO_RCVBUF,
|
|
||||||
(char *)&rbuf, sizeof(rbuf)) < 0)
|
|
||||||
{
|
|
||||||
NSLog(@"Failed to set GSTcpRcvBuf %d: %@", rbuf, [NSError _last]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
NSLog(@"Set GSTcpRcvBuf %d", rbuf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (sbuf > 0)
|
|
||||||
{
|
|
||||||
/* Set the send buffer for the socket.
|
|
||||||
*/
|
|
||||||
if (setsockopt(net, SOL_SOCKET, SO_SNDBUF,
|
|
||||||
(char *)&sbuf, sizeof(sbuf)) < 0)
|
|
||||||
{
|
|
||||||
NSLog(@"Failed to set GSTcpSndBuf %d: %@", sbuf, [NSError _last]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
NSLog(@"Set GSTcpSndBuf %d", sbuf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lhost != nil)
|
if (lhost != nil)
|
||||||
{
|
{
|
||||||
|
@ -1254,7 +1370,8 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
|
||||||
|
|
||||||
- (NSData*) availableData
|
- (NSData*) availableData
|
||||||
{
|
{
|
||||||
char buf[READ_SIZE];
|
int rmax = [tune recvSize];
|
||||||
|
char buf[rmax];
|
||||||
NSMutableData* d;
|
NSMutableData* d;
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
|
@ -1323,7 +1440,8 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
|
||||||
|
|
||||||
- (NSData*) readDataToEndOfFile
|
- (NSData*) readDataToEndOfFile
|
||||||
{
|
{
|
||||||
char buf[READ_SIZE];
|
int rmax = [tune recvSize];
|
||||||
|
char buf[rmax];
|
||||||
NSMutableData* d;
|
NSMutableData* d;
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
|
@ -1350,7 +1468,8 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
|
||||||
{
|
{
|
||||||
NSMutableData *d;
|
NSMutableData *d;
|
||||||
int got;
|
int got;
|
||||||
char buf[READ_SIZE];
|
int rmax = [tune recvSize];
|
||||||
|
char buf[rmax];
|
||||||
|
|
||||||
[self checkRead];
|
[self checkRead];
|
||||||
if (isNonBlocking == YES)
|
if (isNonBlocking == YES)
|
||||||
|
@ -1358,7 +1477,7 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
|
||||||
[self setNonBlocking: NO];
|
[self setNonBlocking: NO];
|
||||||
}
|
}
|
||||||
|
|
||||||
d = [NSMutableData dataWithCapacity: len < READ_SIZE ? len : READ_SIZE];
|
d = [NSMutableData dataWithCapacity: len < sizeof(buf) ? len : sizeof(buf)];
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
int chunk = len > sizeof(buf) ? sizeof(buf) : len;
|
int chunk = len > sizeof(buf) ? sizeof(buf) : len;
|
||||||
|
@ -1397,10 +1516,7 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
|
||||||
{
|
{
|
||||||
int toWrite = len - pos;
|
int toWrite = len - pos;
|
||||||
|
|
||||||
if (toWrite > NETBUF_SIZE)
|
toWrite = [tune sendSize: toWrite];
|
||||||
{
|
|
||||||
toWrite = NETBUF_SIZE;
|
|
||||||
}
|
|
||||||
rval = [self write: (char*)ptr+pos length: toWrite];
|
rval = [self write: (char*)ptr+pos length: toWrite];
|
||||||
if (rval < 0)
|
if (rval < 0)
|
||||||
{
|
{
|
||||||
|
@ -1590,7 +1706,7 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
|
||||||
[self ignoreReadDescriptor];
|
[self ignoreReadDescriptor];
|
||||||
[self ignoreWriteDescriptor];
|
[self ignoreWriteDescriptor];
|
||||||
|
|
||||||
[self setNonBlocking: wasNonBlocking];
|
[self setNonBlocking: NO];
|
||||||
#if USE_ZLIB
|
#if USE_ZLIB
|
||||||
if (gzDescriptor != 0)
|
if (gzDescriptor != 0)
|
||||||
{
|
{
|
||||||
|
@ -1598,6 +1714,26 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
|
||||||
gzDescriptor = 0;
|
gzDescriptor = 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
if (YES == isSocket)
|
||||||
|
{
|
||||||
|
shutdown(descriptor, SHUT_WR);
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
char buffer[4096];
|
||||||
|
|
||||||
|
result = read(descriptor, buffer, sizeof(buffer));
|
||||||
|
if (result <= 0)
|
||||||
|
{
|
||||||
|
if (result < 0)
|
||||||
|
{
|
||||||
|
NSLog(@"%@ read fail on socket shutdown: %@",
|
||||||
|
self, [NSError _last]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
(void)close(descriptor);
|
(void)close(descriptor);
|
||||||
descriptor = -1;
|
descriptor = -1;
|
||||||
acceptOK = NO;
|
acceptOK = NO;
|
||||||
|
@ -1917,17 +2053,11 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
|
||||||
GSFileHandle *h;
|
GSFileHandle *h;
|
||||||
struct sockaddr sin;
|
struct sockaddr sin;
|
||||||
unsigned int size = sizeof(sin);
|
unsigned int size = sizeof(sin);
|
||||||
int status;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Enable tcp-level tracking of whether connection is alive.
|
|
||||||
*/
|
|
||||||
status = 1;
|
|
||||||
setsockopt(desc, SOL_SOCKET, SO_KEEPALIVE, (char *)&status,
|
|
||||||
sizeof(status));
|
|
||||||
|
|
||||||
|
[tune tune: (void*)(intptr_t)desc];
|
||||||
|
|
||||||
h = [[[self class] alloc] initWithFileDescriptor: desc
|
h = [[[self class] alloc] initWithFileDescriptor: desc
|
||||||
closeOnDealloc: YES];
|
closeOnDealloc: YES];
|
||||||
h->isSocket = YES;
|
h->isSocket = YES;
|
||||||
getpeername(desc, &sin, &size);
|
getpeername(desc, &sin, &size);
|
||||||
[h setAddr: &sin];
|
[h setAddr: &sin];
|
||||||
|
@ -1946,7 +2076,8 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
|
||||||
NSMutableData *item;
|
NSMutableData *item;
|
||||||
int length;
|
int length;
|
||||||
int received = 0;
|
int received = 0;
|
||||||
char buf[READ_SIZE];
|
int rmax = [tune recvSize];
|
||||||
|
char buf[rmax];
|
||||||
|
|
||||||
item = [readInfo objectForKey: NSFileHandleNotificationDataItem];
|
item = [readInfo objectForKey: NSFileHandleNotificationDataItem];
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue