mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-23 09:04:13 +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
a1dc63adf7
commit
33c451f902
1 changed files with 189 additions and 58 deletions
|
@ -95,13 +95,156 @@
|
|||
#endif
|
||||
|
||||
// Maximum data in single I/O operation
|
||||
#define NETBUF_SIZE 4096
|
||||
#define NETBUF_SIZE (1024 * 16)
|
||||
#define READ_SIZE NETBUF_SIZE*10
|
||||
|
||||
static GSFileHandle* fh_stdin = nil;
|
||||
static GSFileHandle* fh_stdout = 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.
|
||||
static NSString* NotificationKey = @"NSFileHandleNotificationKey";
|
||||
|
||||
|
@ -112,6 +255,16 @@ static NSString* NotificationKey = @"NSFileHandleNotificationKey";
|
|||
|
||||
@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
|
||||
* system.
|
||||
|
@ -608,8 +761,6 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
|
|||
{
|
||||
static NSString *esocks = nil;
|
||||
static NSString *dsocks = nil;
|
||||
static int rbuf = 0;
|
||||
static int sbuf = 0;
|
||||
static BOOL beenHere = NO;
|
||||
int net;
|
||||
struct sockaddr sin;
|
||||
|
@ -617,7 +768,6 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
|
|||
NSString *lhost = nil;
|
||||
NSString *shost = nil;
|
||||
NSString *sport = nil;
|
||||
int status;
|
||||
|
||||
if (beenHere == NO)
|
||||
{
|
||||
|
@ -638,8 +788,6 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
|
|||
}
|
||||
esocks = [esocks copy];
|
||||
}
|
||||
rbuf = (int)[defs integerForKey: @"GSTcpRcvBuf"];
|
||||
sbuf = (int)[defs integerForKey: @"GSTcpSndBuf"];
|
||||
}
|
||||
|
||||
if (a == nil || [a isEqualToString: @""])
|
||||
|
@ -752,40 +900,8 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
|
|||
DESTROY(self);
|
||||
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)
|
||||
{
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
[tune tune: (void*)(intptr_t)net];
|
||||
|
||||
if (lhost != nil)
|
||||
{
|
||||
|
@ -1254,7 +1370,8 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
|
|||
|
||||
- (NSData*) availableData
|
||||
{
|
||||
char buf[READ_SIZE];
|
||||
int rmax = [tune recvSize];
|
||||
char buf[rmax];
|
||||
NSMutableData* d;
|
||||
int len;
|
||||
|
||||
|
@ -1323,7 +1440,8 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
|
|||
|
||||
- (NSData*) readDataToEndOfFile
|
||||
{
|
||||
char buf[READ_SIZE];
|
||||
int rmax = [tune recvSize];
|
||||
char buf[rmax];
|
||||
NSMutableData* d;
|
||||
int len;
|
||||
|
||||
|
@ -1350,7 +1468,8 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
|
|||
{
|
||||
NSMutableData *d;
|
||||
int got;
|
||||
char buf[READ_SIZE];
|
||||
int rmax = [tune recvSize];
|
||||
char buf[rmax];
|
||||
|
||||
[self checkRead];
|
||||
if (isNonBlocking == YES)
|
||||
|
@ -1358,7 +1477,7 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
|
|||
[self setNonBlocking: NO];
|
||||
}
|
||||
|
||||
d = [NSMutableData dataWithCapacity: len < READ_SIZE ? len : READ_SIZE];
|
||||
d = [NSMutableData dataWithCapacity: len < sizeof(buf) ? len : sizeof(buf)];
|
||||
do
|
||||
{
|
||||
int chunk = len > sizeof(buf) ? sizeof(buf) : len;
|
||||
|
@ -1397,10 +1516,7 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
|
|||
{
|
||||
int toWrite = len - pos;
|
||||
|
||||
if (toWrite > NETBUF_SIZE)
|
||||
{
|
||||
toWrite = NETBUF_SIZE;
|
||||
}
|
||||
toWrite = [tune sendSize: toWrite];
|
||||
rval = [self write: (char*)ptr+pos length: toWrite];
|
||||
if (rval < 0)
|
||||
{
|
||||
|
@ -1590,7 +1706,7 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
|
|||
[self ignoreReadDescriptor];
|
||||
[self ignoreWriteDescriptor];
|
||||
|
||||
[self setNonBlocking: wasNonBlocking];
|
||||
[self setNonBlocking: NO];
|
||||
#if USE_ZLIB
|
||||
if (gzDescriptor != 0)
|
||||
{
|
||||
|
@ -1598,6 +1714,26 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
|
|||
gzDescriptor = 0;
|
||||
}
|
||||
#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);
|
||||
descriptor = -1;
|
||||
acceptOK = NO;
|
||||
|
@ -1917,17 +2053,11 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
|
|||
GSFileHandle *h;
|
||||
struct sockaddr 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
|
||||
closeOnDealloc: YES];
|
||||
closeOnDealloc: YES];
|
||||
h->isSocket = YES;
|
||||
getpeername(desc, &sin, &size);
|
||||
[h setAddr: &sin];
|
||||
|
@ -1946,7 +2076,8 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
|
|||
NSMutableData *item;
|
||||
int length;
|
||||
int received = 0;
|
||||
char buf[READ_SIZE];
|
||||
int rmax = [tune recvSize];
|
||||
char buf[rmax];
|
||||
|
||||
item = [readInfo objectForKey: NSFileHandleNotificationDataItem];
|
||||
/*
|
||||
|
|
Loading…
Reference in a new issue