libs-base/Source/Additions/NSFileHandle+GNUstepBase.m
Richard Frith-MacDonald 6aa7aea38c fix OSX specific file to not build elsewhere
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@30223 72102866-910b-0410-8b05-ffd578937521
2010-04-23 15:59:50 +00:00

244 lines
6.1 KiB
Objective-C

/* Implementation of extension methods to base additions
Copyright (C) 2010 Free Software Foundation, Inc.
Written by: Richard Frith-Macdonald <rfm@gnu.org>
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 Lesser 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 Lesser General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02111 USA.
*/
#import "common.h"
#if defined(NeXT_Foundation_LIBRARY)
#import "Foundation/NSByteOrder.h"
#import "Foundation/NSHost.h"
#import "GSNetwork.h"
#import "GSPrivate.h"
#import "GNUstepBase/NSFileHandle+GNUstepBase.h"
/* Not defined on Solaris 2.7 */
#ifndef INADDR_NONE
#define INADDR_NONE -1
#endif
@implementation NSFileHandle(GNUstepBase)
// From GSFileHandle.m
static BOOL
getAddr(NSString* name, NSString* svc, NSString* pcl, struct addrinfo **ai, struct addrinfo *hints)
{
const char *cHostn = NULL;
const char *cPortn = NULL;
int e = 0;
if (!svc)
{
NSLog(@"service is nil.");
return NO;
}
hints->ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
hints->ai_protocol = IPPROTO_IP; // accept any
if (pcl)
{
if ([pcl isEqualToString:@"tcp"])
{
hints->ai_protocol = IPPROTO_TCP;
hints->ai_socktype = SOCK_STREAM;
}
else if ([pcl isEqualToString:@"udp"])
{
hints->ai_protocol = IPPROTO_UDP;
}
}
/*
* If we were given a hostname, we use any address for that host.
* Otherwise we expect the given name to be an address unless it is
* a null (any address).
*/
if (name)
{
NSHost* host = [NSHost hostWithName: name];
if (host != nil)
{
name = [host address];
NSLog(@"host address '%@'", name);
cHostn = [name cStringUsingEncoding:NSASCIIStringEncoding];
}
}
cPortn = [svc cStringUsingEncoding:NSASCIIStringEncoding];
// getaddrinfo() returns zero on success or one of the error codes listed in
// gai_strerror(3) if an error occurs.
NSLog(@"cPortn '%s'", cPortn);
//&ai
e = getaddrinfo (cHostn, cPortn, hints, ai);
if (e != 0)
{
NSLog(@"getaddrinfo: %s", gai_strerror (e));
return NO;
}
return YES;
}
- (id) initAsServerAtAddress: (NSString*)a
service: (NSString*)s
protocol: (NSString*)p
{
#ifndef BROKEN_SO_REUSEADDR
int status = 1;
#endif
int net;
struct addrinfo *ai;
struct addrinfo hints;
memset (&hints, '\0', sizeof (hints));
if (getAddr(a, s, p, &ai, &hints) == NO)
{
DESTROY(self);
NSLog(@"bad address-service-protocol combination");
return nil;
}
if ((net = socket (ai->ai_family, ai->ai_socktype,
ai->ai_protocol)) < 0)
{
NSLog(@"unable to create socket ai_family: %@ socktype:%@ protocol:%d - %@", (ai->ai_family == PF_INET6 ? @"PF_INET6":@"PF_INET"),
(ai->ai_socktype == SOCK_STREAM ? @"SOCK_STREAM":@"whatever"),
ai->ai_protocol,
[NSError _last]);
DESTROY(self);
return nil;
}
#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!
*/
setsockopt(net, SOL_SOCKET, SO_REUSEADDR, (char *)&status, sizeof(status));
#endif
if (bind(net, ai->ai_addr, ai->ai_addrlen) != 0)
{
NSLog(@"unable to bind to port %@", [NSError _last]);
goto cleanup;
}
if (listen(net, 5) < 0)
{
NSLog(@"unable to listen on port - %@", [NSError _last]);
goto cleanup;
}
// struct sockaddr_storeage sstore;
// int slen = sizeof(ss);
// if (getsockname(net,(struct sockaddr *)&sstore, &slen) < 0)
// {
// NSLog(@"unable to get socket name - %@", [NSError _last]);
// goto cleanup;
// }
freeaddrinfo (ai);
self = [self initWithFileDescriptor: net closeOnDealloc: YES];
return self;
cleanup:
(void) close(net);
freeaddrinfo (ai);
DESTROY(self);
return nil;
}
+ (id) fileHandleAsServerAtAddress: (NSString*)address
service: (NSString*)service
protocol: (NSString*)protocol
{
id o = [self allocWithZone: NSDefaultMallocZone()];
return AUTORELEASE([o initAsServerAtAddress: address
service: service
protocol: protocol]);
}
- (NSString*) socketAddress
{
struct sockaddr_storage sstore;
struct sockaddr *sadr;
socklen_t size = sizeof(sstore);
if (getsockname([self fileDescriptor], (struct sockaddr*)&sstore, &size) < 0)
{
NSLog(@"unable to get socket name - %@", [NSError _last]);
return nil;
}
sadr = (struct sockaddr *) &sstore;
switch (sadr->sa_family)
{
case AF_INET6:
{
char straddr[INET6_ADDRSTRLEN];
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&sstore;
inet_ntop(AF_INET6, &(addr6->sin6_addr), straddr,
sizeof(straddr));
return [NSString stringWithCString: straddr
encoding: NSASCIIStringEncoding];
break;
}
case AF_INET:
{
struct sockaddr_in * addr4 = (struct sockaddr_in*) &sstore;
char *address = inet_ntoa(addr4->sin_addr);
return [NSString stringWithCString: address
encoding: NSASCIIStringEncoding];
break;
}
default:
break;
}
return nil;
}
@end
#endif /* defined(NeXT_Foundation_LIBRARY) */