Name server updates.

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@3144 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
richard 1998-10-29 12:50:23 +00:00
parent 18db5ed559
commit eacd1dbd46
6 changed files with 1126 additions and 234 deletions

View file

@ -1,3 +1,14 @@
Thu Oct 29 13:30:00 1998 Richard Frith-Macdonald <richard@brainstorm.co.uk>
* src/UnixFileHandle.m: Improved handling of error conditions on
background connection operations. Disable SIGPIPE to avoid abort
when we attempt to write to a socket that's closed by the other end.
* src/TCPPort.m: Modified to use NSPortNameServer, also changed to
disable SIGPIPE on initialisation only, not on every write.
* src/include/NSPortNameServer.h: new class.
* src/NSPortNameServer.m: new class.
* src/GNUmakefile: Added NSPortNameServer.
Wed Oct 28 14:30:00 1998 Richard Frith-Macdonald <richard@brainstorm.co.uk>
* Tools/gdomap.c: Added command-line options to lookup, register, and

View file

@ -0,0 +1,47 @@
/* Interface of NSPortNameServer class for Distributed Objects
Copyright (C) 1998 Free Software Foundation, Inc.
Written by: Richard Frith-Macdonald <richard@brainstorm.co.uk>
Created: October 1998
This file is part of the GNUstep Base Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __NSPortNameServer_h_GNUSTEP_BASE_INCLUDE
#define __NSPortNameServer_h_GNUSTEP_BASE_INCLUDE
#include <Foundation/NSObject.h>
@class NSPort, NSString, NSMutableData, NSFileHandle;
@interface NSPortNameServer : NSObject
{
NSFileHandle *handle; /* File handle to talk to gdomap. */
NSMutableData *data; /* Where to accumulated incoming data. */
unsigned expecting; /* Length of data we want. */
}
+ (id) defaultPortNameServer;
- (NSPort*) portForName: (NSString*)name;
- (NSPort*) portForName: (NSString*)name
onHost: (NSString*)host;
- (BOOL) registerPort: (NSPort*)port
forName: (NSString*)name;
- (void) removePortForName: (NSString*)name;
@end
#endif

View file

@ -340,6 +340,7 @@ NSPipe.m \
NSPort.m \
NSPortCoder.m \
NSPortMessage.m \
NSPortNameServer.m \
NSProcessInfo.m \
NSProtocolChecker.m \
NSProxy.m \
@ -433,6 +434,7 @@ Foundation/NSPathUtilities.h \
Foundation/NSPort.h \
Foundation/NSPortCoder.h \
Foundation/NSPortMessage.h \
Foundation/NSPortNameServer.h \
Foundation/NSProcessInfo.h \
Foundation/NSProtocolChecker.h \
Foundation/NSProxy.h \

765
Source/NSPortNameServer.m Normal file
View file

@ -0,0 +1,765 @@
/* Implementation of NSPortNameServer class for Distributed Objects
Copyright (C) 1998 Free Software Foundation, Inc.
Written by: Richard Frith-Macdonald <richard@brainstorm.co.uk>
Created: October 1998
This file is part of the GNUstep Base Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <config.h>
#include <Foundation/NSString.h>
#include <Foundation/NSByteOrder.h>
#include <Foundation/NSException.h>
#include <Foundation/NSAutoreleasePool.h>
#include <Foundation/NSLock.h>
#include <Foundation/NSFileHandle.h>
#include <Foundation/NSRunLoop.h>
#include <Foundation/NSNotificationQueue.h>
#include <Foundation/NSPort.h>
#include <Foundation/NSPortNameServer.h>
#include <gnustep/base/TcpPort.h>
/*
* Protocol definition stuff for talking to gdomap process.
*/
#include "../Tools/gdomap.h"
/*
* Macros to build text to start name server and to give an error
* message about it - they include installation path information.
*/
#define stringify_it(X) #X
#define make_gdomap_cmd(X) stringify_it(X) "/Tools/"GNUSTEP_TARGET_DIR"/gdomap &"
#define make_gdomap_err(X) "check that " stringify_it(X) "/Tools/"GNUSTEP_TARGET_DIR"/gdomap is running and owned by root."
/*
* Private methods for internal use only.
*/
@interface NSPortNameServer (Private)
- (void) _close;
- (void) _didConnect: (NSNotification*)notification;
- (void) _didRead: (NSNotification*)notification;
- (void) _didWrite: (NSNotification*)notification;
- (void) _open: (NSString*)host;
- (void) _retry;
@end
@implementation NSPortNameServer
static NSTimeInterval writeTimeout = 5.0;
static NSTimeInterval readTimeout = 15.0;
static NSTimeInterval connectTimeout = 20.0;
static NSString *serverPort = @"gdomap";
static NSString *mode = @"NSPortServerLookupMode";
static NSArray *modes = nil;
static NSRecursiveLock *serverLock = nil;
static NSPortNameServer *defaultServer = nil;
+ (id) allocWithZone: (NSZone*)aZone
{
[NSException raise: NSGenericException
format: @"attempt to create extra port name server"];
return nil;
}
+ (void) initialize
{
if (self == [NSPortNameServer class])
{
serverLock = [NSRecursiveLock new];
[serverLock lock];
if (modes == nil)
{
modes = [[NSArray alloc] initWithObjects: &mode count: 1];
}
[serverLock unlock];
}
}
+ (id) defaultPortNameServer
{
if (defaultServer == nil)
{
NSPortNameServer *s;
[serverLock lock];
if (defaultServer)
{
[serverLock unlock];
return defaultServer;
}
s = (NSPortNameServer*)NSAllocateObject(self, 0, NSDefaultMallocZone());
s->data = [NSMutableData new];
defaultServer = s;
[serverLock unlock];
}
return defaultServer;
}
- (void) dealloc
{
[NSException raise: NSGenericException
format: @"attempt to deallocate default port name server"];
}
- (NSPort*) portForName: (NSString*)name
{
return [self portForName: name onHost: nil];
}
- (NSPort*) portForName: (NSString*)name
onHost: (NSString*)host
{
gdo_req msg; /* Message structure. */
NSMutableData *dat; /* Hold message here. */
unsigned len;
NSRunLoop *loop = [NSRunLoop currentRunLoop];
struct in_addr singleServer;
struct in_addr *svrs = &singleServer;
unsigned numSvrs;
unsigned count;
unsigned portNum = 0;
if (name == nil)
{
[NSException raise: NSInvalidArgumentException
format: @"attempt to register port with nil name"];
}
len = [name cStringLength];
if (len == 0)
{
[NSException raise: NSInvalidArgumentException
format: @"attempt to register port with no name"];
}
if (len > GDO_NAME_MAX_LEN)
{
[NSException raise: NSInvalidArgumentException
format: @"name of port is too long (max %d) bytes",
GDO_NAME_MAX_LEN];
}
if (host != nil && [host isEqual: @"*"])
{
NSMutableData *tmp;
unsigned bufsiz;
unsigned length;
msg.rtype = GDO_SERVERS; /* Get a list of name servers. */
msg.ptype = GDO_TCP_GDO; /* Port is TCP port for GNU DO */
msg.nsize = 0;
msg.port = 0;
dat = [NSMutableData dataWithBytes: (void*)&msg length: sizeof(msg)];
[serverLock lock];
NS_DURING
{
[self _open: nil];
expecting = sizeof(msg);
[handle writeInBackgroundAndNotify: dat
forModes: modes];
[loop runMode: mode
beforeDate: [NSDate dateWithTimeIntervalSinceNow: writeTimeout]];
if (expecting)
{
[self _close];
[NSException raise: NSPortTimeoutException
format: @"timed out writing to gdomap"];
}
expecting = sizeof(unsigned);
[data setLength: 0];
[handle readInBackgroundAndNotifyForModes: modes];
[loop runMode: mode
beforeDate: [NSDate dateWithTimeIntervalSinceNow: readTimeout]];
if (expecting)
{
[self _close];
[NSException raise: NSPortTimeoutException
format: @"timed out reading from gdomap"];
}
numSvrs = NSSwapBigIntToHost(*(unsigned*)[data bytes]);
if (numSvrs == 0)
{
[self _close];
[NSException raise: NSInternalInconsistencyException
format: @"failed to get list of name servers on net"];
}
/*
* Calculate size of buffer for server internet addresses and
* allocate a buffer to store them in.
*/
bufsiz = numSvrs * sizeof(struct in_addr);
tmp = [NSMutableData dataWithLength: bufsiz];
svrs = (struct in_addr*)[tmp mutableBytes];
/*
* Read the addresses from the name server if necessary
* and copy them to our newly allocated buffer.
* We may already have some/all of the data, in which case
* we don't need to do a read.
*/
length = [data length] - sizeof(unsigned);
if (length > 0)
{
void *bytes = [data mutableBytes];
memcpy(bytes, bytes+sizeof(unsigned), length);
[data setLength: length];
}
else
{
[data setLength: 0];
}
if (length < bufsiz)
{
expecting = bufsiz;
[handle readInBackgroundAndNotifyForModes: modes];
[loop runMode: mode
beforeDate: [NSDate dateWithTimeIntervalSinceNow:
readTimeout]];
if (expecting)
{
[self _close];
[NSException raise: NSPortTimeoutException
format: @"timed out reading from gdomap"];
}
}
[data getBytes: (void*)svrs length: bufsiz];
[self _close];
}
NS_HANDLER
{
/*
* If we had a problem - unlock before continueing.
*/
[serverLock unlock];
[localException raise];
}
NS_ENDHANDLER
[serverLock unlock];
}
else
{
/*
* Query a single nameserver - on the local host.
*/
numSvrs = 1;
#ifndef HAVE_INET_ATON
svrs->s_addr = inet_addr("127.0.0.1");
#else
inet_aton("127.0.0.1", &svrs->s_addr);
#endif
}
[serverLock lock];
NS_DURING
{
for (count = 0; count < numSvrs; count++)
{
NSString *addr;
msg.rtype = GDO_LOOKUP; /* Find the named port. */
msg.ptype = GDO_TCP_GDO; /* Port is TCP port for GNU DO */
msg.port = 0;
msg.nsize = len;
[name getCString: msg.name];
dat = [NSMutableData dataWithBytes: (void*)&msg length: sizeof(msg)];
addr = [NSString stringWithCString: (char*)inet_ntoa(svrs[count])];
[self _open: addr];
expecting = sizeof(msg);
[handle writeInBackgroundAndNotify: dat
forModes: modes];
[loop runMode: mode
beforeDate: [NSDate dateWithTimeIntervalSinceNow: writeTimeout]];
if (expecting)
{
[self _close];
}
else
{
expecting = sizeof(unsigned);
[data setLength: 0];
[handle readInBackgroundAndNotifyForModes: modes];
[loop runMode: mode
beforeDate: [NSDate dateWithTimeIntervalSinceNow:
readTimeout]];
[self _close];
if (expecting == 0)
{
portNum = NSSwapBigIntToHost(*(unsigned*)[data bytes]);
if (portNum != 0)
{
break;
}
}
}
}
}
NS_HANDLER
{
/*
* If we had a problem - unlock before continueing.
*/
[serverLock unlock];
[localException raise];
}
NS_ENDHANDLER
[serverLock unlock];
if (portNum)
{
struct sockaddr_in sin;
NSPort *p;
unsigned short n;
memset(&sin, '\0', sizeof(sin));
sin.sin_family = AF_INET;
/*
* The returned port is an unsigned int - so we have to
* convert to a short in network byte order (big endian).
*/
n = (unsigned short)portNum;
sin.sin_port = NSSwapHostShortToBig(n);
/*
* The host addresses are given to us in network byte order
* so we just copy the address into place.
*/
sin.sin_addr.s_addr = svrs[count].s_addr;
p = [TcpOutPort newForSendingToSockaddr: &sin
withAcceptedSocket: 0
pollingInPort: nil];
return [p autorelease];
}
else
{
return nil;
}
}
- (BOOL) registerPort: (NSPort*)port
forName: (NSString*)name
{
gdo_req msg; /* Message structure. */
NSMutableData *dat; /* Hold message here. */
unsigned len;
NSRunLoop *loop = [NSRunLoop currentRunLoop];
if (name == nil)
{
[NSException raise: NSInvalidArgumentException
format: @"attempt to register port with nil name"];
}
if (port == nil)
{
[NSException raise: NSInvalidArgumentException
format: @"attempt to register nil port"];
}
len = [name cStringLength];
if (len == 0)
{
[NSException raise: NSInvalidArgumentException
format: @"attempt to register port with no name"];
}
if (len > GDO_NAME_MAX_LEN)
{
[NSException raise: NSInvalidArgumentException
format: @"name of port is too long (max %d) bytes",
GDO_NAME_MAX_LEN];
}
msg.rtype = GDO_REGISTER; /* Register a port. */
msg.ptype = GDO_TCP_GDO; /* Port is TCP port for GNU DO */
msg.nsize = len;
[name getCString: msg.name];
msg.port = NSSwapHostIntToBig((unsigned)[(TcpInPort*)port portNumber]);
dat = [NSMutableData dataWithBytes: (void*)&msg length: sizeof(msg)];
/*
* Lock out other threads while doing I/O to gdomap
*/
[serverLock lock];
NS_DURING
{
[self _open: nil];
/*
* Queue a write request in our own run mode then run until the
* timeout period or until the write completes.
*/
expecting = sizeof(msg);
[handle writeInBackgroundAndNotify: dat
forModes: modes];
[loop runMode: mode
beforeDate: [NSDate dateWithTimeIntervalSinceNow: writeTimeout]];
if (expecting)
{
[self _close];
[NSException raise: NSPortTimeoutException
format: @"timed out writing to gdomap"];
}
/*
* Queue a read request in our own run mode then run until the
* timoeut period or until the read completes.
*/
expecting = sizeof(unsigned);
[data setLength: 0];
[handle readInBackgroundAndNotifyForModes: modes];
[loop runMode: mode
beforeDate: [NSDate dateWithTimeIntervalSinceNow: readTimeout]];
if (expecting)
{
[self _close];
[NSException raise: NSPortTimeoutException
format: @"timed out reading from gdomap"];
}
/*
* Finished with server - so close connection.
*/
[self _close];
if ([data length] != sizeof(unsigned))
{
[NSException raise: NSInternalInconsistencyException
format: @"too much data read from gdomap"];
}
else
{
unsigned result = NSSwapBigIntToHost(*(unsigned*)[data bytes]);
if (result == 0)
{
NSLog(@"NSPortNameServer unable to register '%@'\n", name);
}
}
}
NS_HANDLER
{
/*
* If we had a problem - unlock before continueing.
*/
[serverLock unlock];
[localException raise];
}
NS_ENDHANDLER
[serverLock unlock];
}
- (void) removePortForName: (NSString*)name
{
gdo_req msg; /* Message structure. */
NSMutableData *dat; /* Hold message here. */
unsigned len;
NSRunLoop *loop = [NSRunLoop currentRunLoop];
if (name == nil)
{
[NSException raise: NSInvalidArgumentException
format: @"attempt to remove port with nil name"];
}
len = [name cStringLength];
if (len == 0)
{
[NSException raise: NSInvalidArgumentException
format: @"attempt to remove port with no name"];
}
if (len > GDO_NAME_MAX_LEN)
{
[NSException raise: NSInvalidArgumentException
format: @"name of port is too long (max %d) bytes",
GDO_NAME_MAX_LEN];
}
msg.rtype = GDO_UNREG; /* Unregister a port. */
msg.ptype = GDO_TCP_GDO; /* Port is TCP port for GNU DO */
msg.nsize = len;
[name getCString: msg.name];
msg.port = 0;
dat = [NSMutableData dataWithBytes: (void*)&msg length: sizeof(msg)];
/*
* Lock out other threads while doing I/O to gdomap
*/
[serverLock lock];
NS_DURING
{
[self _open: nil];
/*
* Queue a write request in our own run mode then run until the
* timeout period or until the write completes.
*/
expecting = sizeof(msg);
[handle writeInBackgroundAndNotify: dat
forModes: modes];
[loop runMode: mode
beforeDate: [NSDate dateWithTimeIntervalSinceNow: writeTimeout]];
if (expecting)
{
[self _close];
[NSException raise: NSPortTimeoutException
format: @"timed out writing to gdomap"];
}
/*
* Queue a read request in our own run mode then run until the
* timeout period or until the read completes.
*/
expecting = sizeof(unsigned);
[data setLength: 0];
[handle readInBackgroundAndNotifyForModes: modes];
[loop runMode: mode
beforeDate: [NSDate dateWithTimeIntervalSinceNow: readTimeout]];
if (expecting)
{
[self _close];
[NSException raise: NSPortTimeoutException
format: @"timed out reading from gdomap"];
}
/*
* Finished with server - so close connection.
*/
[self _close];
if ([data length] != sizeof(unsigned))
{
[NSException raise: NSInternalInconsistencyException
format: @"too much data read from gdomap"];
}
else
{
unsigned result = NSSwapBigIntToHost(*(unsigned*)[data bytes]);
if (result == 0)
{
NSLog(@"NSPortNameServer unable to unregister '%@'\n", name);
}
}
}
NS_HANDLER
{
/*
* If we had a problem - unlock before continueing.
*/
[serverLock unlock];
[localException raise];
}
NS_ENDHANDLER
[serverLock unlock];
}
@end
@implementation NSPortNameServer (Private)
- (void) _close
{
if (handle)
{
[NSNotificationCenter removeObserver: self
name: GSFileHandleConnectCompletionNotification
object: handle];
[NSNotificationCenter removeObserver: self
name: NSFileHandleReadCompletionNotification
object: handle];
[NSNotificationCenter removeObserver: self
name: GSFileHandleWriteCompletionNotification
object: handle];
[handle closeFile];
[handle release];
handle = nil;
}
}
- (void) _didConnect: (NSNotification*)notification
{
NSDictionary *userInfo = [notification userInfo];
NSString *e;
e = [userInfo objectForKey:GSFileHandleNotificationError];
if (e)
{
NSLog(@"NSPortNameServer failed connect to gdomap - %@", e);
}
else
{
/*
* There should now be nothing for the runloop to do so
* control should return to the method that started the connection.
* Set 'expecting' to zero to show that the connection worked and
* stop watching for connection completion.
*/
expecting = 0;
[NSNotificationCenter removeObserver: self
name: GSFileHandleConnectCompletionNotification
object: handle];
}
}
- (void) _didRead: (NSNotification*)notification
{
NSDictionary *userInfo = [notification userInfo];
NSData *d;
d = [userInfo objectForKey:NSFileHandleNotificationDataItem];
if (d == nil || [d length] == 0)
{
[self _close];
[NSException raise: NSGenericException
format: @"NSPortNameServer lost connection to gdomap"];
}
else
{
[data appendData: d];
if ([data length] < expecting)
{
/*
* Not enough data read yet - go read some more.
*/
[handle readInBackgroundAndNotifyForModes: modes];
}
else
{
/*
* There should now be nothing for the runloop to do so
* control should return to the method that started the read.
* Set 'expecting' to zero to show that the data was read.
*/
expecting = 0;
}
}
}
- (void) _didWrite: (NSNotification*)notification
{
NSDictionary *userInfo = [notification userInfo];
NSString *e;
e = [userInfo objectForKey:GSFileHandleNotificationError];
if (e)
{
[self _close];
[NSException raise: NSGenericException
format: @"NSPortNameServer failed write to gdomap - %@", e];
}
else
{
/*
* There should now be nothing for the runloop to do so
* control should return to the method that started the write.
* Set 'expecting' to zero to show that the data was written.
*/
expecting = 0;
}
}
- (void) _open: (NSString*)host
{
NSRunLoop *loop;
NSString *hostname = host;
if (handle)
{
return; /* Connection already open. */
}
if (hostname == nil)
{
hostname = @"localhost";
}
expecting = 1;
handle = [NSFileHandle fileHandleAsClientInBackgroundAtAddress: host
service: serverPort
protocol: @"tcp"
forModes: modes];
if (handle == nil)
{
[NSException raise: NSGenericException
format: @"failed to create file handle to gdomap on %@",
hostname];
}
[handle retain];
[NSNotificationCenter addObserver: self
selector: @selector(_didConnect:)
name: GSFileHandleConnectCompletionNotification
object: handle];
[NSNotificationCenter addObserver: self
selector: @selector(_didRead:)
name: NSFileHandleReadCompletionNotification
object: handle];
[NSNotificationCenter addObserver: self
selector: @selector(_didWrite:)
name: GSFileHandleWriteCompletionNotification
object: handle];
loop = [NSRunLoop currentRunLoop];
[loop runMode: mode
beforeDate: [NSDate dateWithTimeIntervalSinceNow: connectTimeout]];
if (expecting)
{
static BOOL retrying = NO;
[self _close];
if (retrying == NO)
{
retrying = YES;
NS_DURING
{
[self _retry];
}
NS_HANDLER
{
retrying = NO;
[localException raise];
}
NS_ENDHANDLER
retrying = NO;
}
else
{
NSLog(@"NSPortNameServer failed to connect to gdomap - %s",
make_gdomap_err(GNUSTEP_INSTALL_PREFIX));
}
}
}
- (void) _retry
{
NSLog(@"NSPortNameServer attempting to start gdomap on local host");
system(make_gdomap_cmd(GNUSTEP_INSTALL_PREFIX));
sleep(5);
NSLog(@"NSPortNameServer retrying connection attempt to gdomap");
[self _open: nil];
}
@end

View file

@ -43,6 +43,7 @@
#include <gnustep/base/Invocation.h>
#include <Foundation/NSData.h>
#include <Foundation/NSDate.h>
#include <Foundation/NSPortNameServer.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
@ -68,6 +69,7 @@
#define NBLK_OPT FNDELAY
#endif
#define NSPORTNAMESERVER 1
#define GDOMAP 1 /* 1 = Use name server. */
#define stringify_it(X) #X
#define make_gdomap_cmd(X) stringify_it(X) "/Tools/"GNUSTEP_TARGET_DIR"/gdomap &"
@ -317,15 +319,7 @@ tryWrite(int desc, int tim, unsigned char* dat, int len)
return(-1); /* Error in select. */
}
else if (len > 0) {
void (*ifun)();
/*
* Should be able to write this short a message immediately, but
* if the connection is lost we will get a signal we must trap.
*/
ifun = signal(SIGPIPE, (void(*)(int))SIG_IGN);
rval = write(desc, &dat[pos], len - pos);
signal(SIGPIPE, ifun);
if (rval <= 0) {
if (errno != EWOULDBLOCK) {
@ -745,10 +739,17 @@ static NSMapTable* port_number_2_port;
+ (void) initialize
{
if (self == [TcpInPort class])
{
port_number_2_port =
NSCreateMapTable (NSIntMapKeyCallBacks,
NSNonOwnedPointerMapValueCallBacks, 0);
init_port_socket_2_port ();
/*
* If SIGPIPE is not ignored, we will abort on any attempt to
* write to a pipe/socket that has been closed by the other end!
*/
signal(SIGPIPE, SIG_IGN);
}
}
/* This is the designated initializer.
@ -919,12 +920,17 @@ static NSMapTable* port_number_2_port;
struct sockaddr_in sin;
if (p) {
#if NSPORTNAMESERVER
[[NSPortNameServer defaultPortNameServer] registerPort: p
forName: name];
#else
int port = [p portNumber];
if (nameServer([name cString], 0, GDO_REGISTER, &sin, port, 1) == 0) {
[p release];
return nil;
}
#endif
}
return p;
#else
@ -1390,6 +1396,11 @@ static NSMapTable *out_port_bag = NULL;
init_port_socket_2_port ();
out_port_bag = NSCreateMapTable (NSNonOwnedPointerMapKeyCallBacks,
NSNonOwnedPointerMapValueCallBacks, 0);
/*
* If SIGPIPE is not ignored, we will abort on any attempt to
* write to a pipe/socket that has been closed by the other end!
*/
signal(SIGPIPE, SIG_IGN);
}
}
@ -1647,6 +1658,13 @@ static NSMapTable *out_port_bag = NULL;
onHost: (NSString*)hostname
{
#ifdef GDOMAP
#if NSPORTNAMESERVER
id c;
c = [[NSPortNameServer defaultPortNameServer] portForName: name
onHost: hostname];
return [c retain];
#else
struct sockaddr_in sin[100];
int found;
int i;
@ -1661,6 +1679,7 @@ static NSMapTable *out_port_bag = NULL;
pollingInPort: nil];
}
return c;
#endif
#else
return [self newForSendingToPortNumber:
name_2_port_number ([name cString]) onHost: hostname];;

View file

@ -43,6 +43,7 @@
#include <sys/param.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <signal.h>
#endif /* WIN32 */
#include <sys/file.h>
@ -146,7 +147,19 @@ getAddr(NSString* name, NSString* svc, NSString* pcl, struct sockaddr_in *sin)
}
}
+ allocWithZone:(NSZone*)z
+ (void) initialize
{
if (self == [UnixFileHandle class])
{
/*
* If SIGPIPE is not ignored, we will abort on any attempt to
* write to a pipe/socket that has been closed by the other end!
*/
signal(SIGPIPE, SIG_IGN);
}
}
+ (id) allocWithZone: (NSZone*)z
{
return NSAllocateObject ([self class], 0, z);
}
@ -1139,23 +1152,27 @@ getAddr(NSString* name, NSString* svc, NSString* pcl, struct sockaddr_in *sin)
if (isNonBlocking == NO)
[self setNonBlocking: YES];
if (type == ET_RDESC) {
if (type == ET_RDESC)
{
operation = [readInfo objectForKey: NotificationKey];
if (operation == NSFileHandleConnectionAcceptedNotification) {
if (operation == NSFileHandleConnectionAcceptedNotification)
{
struct sockaddr_in buf;
int desc;
int blen = sizeof(buf);
NSFileHandle* hdl;
desc = accept(descriptor, (struct sockaddr*)&buf, &blen);
if (desc < 0) {
if (desc < 0)
{
NSString *s;
s = [NSString stringWithFormat: @"Accept attempt failed - %s",
strerror(errno)];
[readInfo setObject: s forKey: GSFileHandleNotificationError];
}
else { // Accept attempt completed.
else
{ // Accept attempt completed.
UnixFileHandle *h;
struct sockaddr_in sin;
int size = sizeof(sin);
@ -1163,15 +1180,18 @@ getAddr(NSString* name, NSString* svc, NSString* pcl, struct sockaddr_in *sin)
h = [[UnixFileHandle alloc] initWithFileDescriptor: desc];
getpeername(desc, (struct sockaddr*)&sin, &size);
[h setAddr: &sin];
[readInfo setObject: h forKey: NSFileHandleNotificationFileHandleItem];
[readInfo setObject: h
forKey: NSFileHandleNotificationFileHandleItem];
[h release];
}
[self postReadNotification];
}
else if (operation == NSFileHandleDataAvailableNotification) {
else if (operation == NSFileHandleDataAvailableNotification)
{
[self postReadNotification];
}
else {
else
{
NSMutableData *item;
int length;
int received = 0;
@ -1181,11 +1201,14 @@ getAddr(NSString* name, NSString* svc, NSString* pcl, struct sockaddr_in *sin)
length = [item length];
received = read(descriptor, buf, sizeof(buf));
if (received == 0) { // Read up to end of file.
if (received == 0)
{ // Read up to end of file.
[self postReadNotification];
}
else if (received < 0) {
if (errno != EAGAIN) {
else if (received < 0)
{
if (errno != EAGAIN)
{
NSString *s;
s = [NSString stringWithFormat: @"Read attempt failed - %s",
@ -1194,21 +1217,25 @@ getAddr(NSString* name, NSString* svc, NSString* pcl, struct sockaddr_in *sin)
[self postReadNotification];
}
}
else {
else
{
[item appendBytes: buf length: received];
if (operation == NSFileHandleReadCompletionNotification) {
if (operation == NSFileHandleReadCompletionNotification)
{
// Read a single chunk of data
[self postReadNotification];
}
}
}
}
else if (type == ET_WDESC) {
else if (type == ET_WDESC)
{
NSMutableDictionary *info;
info = [writeInfo objectAtIndex: 0];
operation = [info objectForKey: NotificationKey];
if (operation == GSFileHandleWriteCompletionNotification) {
if (operation == GSFileHandleWriteCompletionNotification)
{
NSData *item;
int length;
const void *ptr;
@ -1216,32 +1243,53 @@ getAddr(NSString* name, NSString* svc, NSString* pcl, struct sockaddr_in *sin)
item = [info objectForKey: NSFileHandleNotificationDataItem];
length = [item length];
ptr = [item bytes];
if (writePos < length) {
if (writePos < length)
{
int written;
written = write(descriptor, (char*)ptr+writePos, length-writePos);
if (written <= 0) {
if (errno != EAGAIN) {
if (written <= 0)
{
if (errno != EAGAIN)
{
NSString *s;
s = [NSString stringWithFormat:@"Write attempt failed - %s",
strerror(errno)];
s = [NSString stringWithFormat:
@"Write attempt failed - %s", strerror(errno)];
[info setObject: s forKey: GSFileHandleNotificationError];
[self postWriteNotification];
}
}
else {
else
{
writePos += written;
}
}
if (writePos >= length) { // Write operation completed.
if (writePos >= length)
{ // Write operation completed.
[self postWriteNotification];
}
}
else { // Connection attempt completed.
connectOK = NO;
else
{ // Connection attempt completed.
int result;
int len = sizeof(result);
if (getsockopt(descriptor, SOL_SOCKET, SO_ERROR,
(char*)&result, &len) == 0 && result != 0)
{
NSString *s;
s = [NSString stringWithFormat: @"Connect attempt failed - %s",
strerror(result)];
[info setObject: s forKey: GSFileHandleNotificationError];
}
else
{
readOK = YES;
writeOK = YES;
}
connectOK = NO;
[self postWriteNotification];
}
}