//
// $Id: SocketAddress.m,v 1.17 2005/06/15 11:43:47 johnstrr Exp $
//
// vi: set ft=objc:

/*
 * ObjectiveLib - a library of containers and algorithms for Objective-C
 *
 * Copyright (c) 2004
 * Will Mason
 *
 * Portions:
 *
 * Copyright (c) 1994
 * Hewlett-Packard Company
 *
 * Copyright (c) 1996,1997
 * Silicon Graphics Computer Systems, Inc.
 *
 * Copyright (c) 1997
 * Moscow Center for SPARC Technology
 *
 * Copyright (c) 1999 
 * Boris Fomitchev
 *
 * 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.1 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
 * Lesser 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * You may contact the author at will_mason@users.sourceforge.net.
 */

#import "SocketAddressPackage.h"
#import "RunTime.h"
#import "Macros.h"
#import "ByteOrder.h"
#import "ConfigPrivate.h"
#import <Foundation/NSString.h>
#import <Foundation/NSException.h>
#import <Foundation/NSData.h>
#import <Foundation/NSPathUtilities.h>
#import <sys/types.h>
#import <sys/param.h>
#import <unistd.h>
#import <string.h>
#import <stdlib.h>
#import <errno.h>
#import <limits.h>

#ifndef WIN32
#import <sys/socket.h>
#import <netdb.h>
#import <netinet/in.h>
#if defined(OL_HAVE_UNIX_SOCKETS)
#import <sys/un.h>
#endif
#else
#import <winsock2.h>
#define MAXHOSTNAMELEN 256
#endif

@interface OLInternetAddress (PrivateMethods)

+ (OLInternetAddress*) addressImplWithHost: (const char*)name service: (const char*)service port: (int)port allocator: (OLAllocator*)alloc;
- (id) initImplWithName: (const char*)name socketType: (int)type allocator: (OLAllocator*)alloc;
- (int) addressFamily;

@end

@interface OLInternet4Address (PrivateMethods)

#if defined(OL_HAVE_GETADDRINFO)

- (id) initImplWithAddrinfo: (const struct addrinfo*)info port: (int) port allocator: (OLAllocator*)alloc;

#elif defined(OL_HAVE_GETHOSTBYNAME)

- (id) initImplWithHostent: (const struct hostent*)hent andServent: (const struct servent*)sent allocator: (OLAllocator*)alloc;

#endif

@end

#if defined(OL_HAVE_INET6_SOCKETS)

@interface OLInternet6Address (PrivateMethods)

#if defined(OL_HAVE_GETADDRINFO)

- (id) initImplWithAddrinfo: (const struct addrinfo*)info port: (int)port allocator: (OLAllocator*)alloc;

#elif defined(OL_HAVE_GETHOSTBYNAME)

- (id) initImplWithHostent: (const struct hostent*)hent andServent: (const struct servent*)sent allocator: (OLAllocator*)alloc;

#endif

@end

#endif

@implementation OLSocketAddress

- (id) copyWithAllocator: (OLAllocator*)alloc
{
    return nil;
}

- (id) copyWithZone: (NSZone*)zone
{
    return nil;
}

- (const struct sockaddr*) hostRepresentation
{
    [self doesNotRecognizeSelector: _cmd];
    return NULL;
}

- (unsigned) hostRepresentationLength
{
    [self doesNotRecognizeSelector: _cmd];
    return 0;
}

@end

@implementation OLInternetAddress

+ (id) addressWithCurrentHostAndPort: (uint16_t)port
{
    char nameBuf[MAXHOSTNAMELEN];

    NS_DURING

        if (gethostname(nameBuf, MAXHOSTNAMELEN - 1) != 0)
        {
            [NSException raise: OLSocketException
                format: @"Could not retrieve the current host name"];
        }
        return [OLInternetAddress addressImplWithHost: nameBuf service: NULL
            port: port allocator: [OLAllocator defaultAllocator]];

    NS_HANDLER

        return [OLInternetAddress addressImplWithHost: "127.0.0.1" service: NULL
            port: port allocator: [OLAllocator defaultAllocator]];

    NS_ENDHANDLER
}

+ (OLInternetAddress*) addressWithCurrentHostAndService: (NSString*)service
{
    char nameBuf[MAXHOSTNAMELEN];

    NS_DURING

        if (gethostname(nameBuf, MAXHOSTNAMELEN - 1) != 0)
        {
            [NSException raise: OLSocketException
                format: @"Could not retrieve the current host name"];
        }
        return [OLInternetAddress addressImplWithHost: nameBuf service: [service UTF8String] port: -1 allocator: [OLAllocator defaultAllocator]];

    NS_HANDLER

        return [OLInternetAddress addressImplWithHost: "127.0.0.1" service: [service UTF8String] port: -1 allocator: [OLAllocator defaultAllocator]];

    NS_ENDHANDLER
}

+ (OLInternetAddress*) addressWithHost: (NSString*)name port: (uint16_t)port
{
    return [OLInternetAddress addressImplWithHost: [name UTF8String] service: NULL port: port allocator: [OLAllocator defaultAllocator]];
}

+ (OLInternetAddress*) addressWithHost: (NSString*)name port: (uint16_t)port allocator: (OLAllocator*)alloc
{
    return [OLInternetAddress addressImplWithHost: [name UTF8String] service: NULL port: port allocator: alloc];
}

+ (OLInternetAddress*) addressWithHost: (NSString*)name service: (NSString*)service
{
    return [OLInternetAddress addressImplWithHost: [name UTF8String] service: [service UTF8String] port: -1 allocator: [OLAllocator defaultAllocator]];
}

+ (OLInternetAddress*) addressWithHost: (NSString*)name service: (NSString*)service allocator: (OLAllocator*)alloc
{
    return [OLInternetAddress addressImplWithHost: [name UTF8String] service: [service UTF8String] port: -1 allocator: alloc];
}

- (void) dealloc
{
    [allocator deallocateObject: canonicalName];
    OBJ_RELEASE(allocator);
    [super dealloc];
}

- (NSString*) canonicalName
{
#if defined(OL_HAVE_GETNAMEINFO)
    char nameBuf[NI_MAXHOST];
#elif defined(OL_HAVE_GETHOSTBYADDR)
    struct hostent* hent;
#endif

    if (canonicalName == nil)
    {
#if defined(OL_HAVE_GETNAMEINFO)
        if (getnameinfo([self hostRepresentation], [self hostRepresentationLength],
                nameBuf, NI_MAXHOST, NULL, 0, NI_NAMEREQD) != 0)
        {
            [NSException raise: OLSocketException
                format: @"Could not resolve host name"];
        }
        canonicalName = [[allocator allocateObject: [NSString class]]
            initWithBytes: nameBuf length: strlen(nameBuf) encoding: NSASCIIStringEncoding];
#elif defined(OL_HAVE_GETHOSTBYADDR)
        hent = gethostbyaddr((const char*)[self hostRepresentation],
            [self hostRepresentationLength], [self addressFamily]);
        if (hent == NULL)
        {
            // No open-source definition of hstrerror seems to be available
            //   for Windows; MS version of winsock2.h must use macros.
#ifndef WIN32
            [NSException raise: OLSocketException
                format: @"Could not resolve host name - %s",
                hstrerror(h_errno)];
#else
            [NSException raise: OLSocketException
                format: @"Could not resolve host name"];
#endif
        }
        canonicalName = [[allocator allocateObject: [NSString class]]
            initWithBytes: hent->h_name length: strlen(hent->h_name)
            encoding: NSASCIIStringEncoding];
#endif
    }
    return canonicalName;
}

- (BOOL) isLocalWildcard
{
    return NO;
}

- (uint16_t) port
{
    [self doesNotRecognizeSelector: _cmd];
    return 0;
}

- (int) socketType
{
    return socketType;
}

@end

@implementation OLInternet4Address

- (id) init
{
    return [self initWithPort: 0];
}

- (id) initWithPort: (uint16_t)port
{
    [super initImplWithName: NULL socketType: SOCK_STREAM
        allocator: [OLAllocator defaultAllocator]];
    hostRep = [allocator allocateBytes: sizeof(struct sockaddr_in)];
#if defined(OL_HAVE_SIN_LEN)
    hostRep->sin_len = INET_ADDRSTRLEN;
#endif
    hostRep->sin_family = AF_INET;
    hostRep->sin_port = H16_TO_N(port);
    hostRep->sin_addr.s_addr = INADDR_ANY;
    memset(hostRep->sin_zero, 0, sizeof(hostRep->sin_zero));
    return self;
}

- (void) dealloc
{
    [allocator deallocateBytes: hostRep];
    [super dealloc];
}

- (id) copyWithAllocator: (OLAllocator*)alloc
{
    return [[alloc allocateObject: [OLInternet4Address class]]
        initWithSockaddr: hostRep socketType: socketType allocator: alloc];
}

- (id) copyWithZone: (NSZone*)zone
{
    return [[OLInternet4Address allocWithZone: zone]
        initWithSockaddr: hostRep socketType: socketType allocator: allocator];
}

- (NSString*) description
{
    uint8_t* addr = (uint8_t*)&hostRep->sin_addr.s_addr;
    NSString* desc;
    int addrInts[4];

    if (canonicalName != nil)
    {
        desc = canonicalName;
    }
    else
    {
        addrInts[0] = addr[0];
        addrInts[1] = addr[1];
        addrInts[2] = addr[2];
        addrInts[3] = addr[3];
        if (hostRep->sin_port == 0)
        {
            desc = [[allocator allocateObject: [NSString class]]
                initWithFormat: @"%i.%i.%i.%i",
                addrInts[0], addrInts[1], addrInts[2], addrInts[3]];
        }
        else
        {
            desc = [[allocator allocateObject: [NSString class]]
                initWithFormat: @"%i.%i.%i.%i:%i",
                addrInts[0], addrInts[1], addrInts[2], addrInts[3],
                N16_TO_H(hostRep->sin_port)];
        }
        OBJ_COND_AUTORELEASE(desc);
    }
    return desc;
}

- (const struct sockaddr*) hostRepresentation
{
    return (const struct sockaddr*)hostRep;
}

- (unsigned) hostRepresentationLength
{
    return sizeof(struct sockaddr_in);
}

- (BOOL) isEqual: (id)object
{
    OLInternet4Address* other;

    if ([object isKindOfClass: [OLInternet4Address class]])
    {
        other = (OLInternet4Address*)object;
        return other->hostRep->sin_port == hostRep->sin_port &&
               !memcmp(&other->hostRep->sin_addr, &hostRep->sin_addr, sizeof(struct in_addr));
    }
    return NO;
}

- (BOOL) isLocalWildcard
{
    return hostRep->sin_addr.s_addr == INADDR_ANY;
}

- (uint16_t) port
{
    return N16_TO_H(hostRep->sin_port);
}

@end

#if defined(OL_HAVE_INET6_SOCKETS)

@implementation OLInternet6Address

- (id) init
{
    return [self initWithPort: 0];
}

- (id) initWithPort: (uint16_t)port
{
    [super initImplWithName: NULL socketType: SOCK_STREAM
        allocator: [OLAllocator defaultAllocator]];
    hostRep = [allocator allocateBytes: sizeof(struct sockaddr_in6)];
    memset(hostRep, 0, sizeof(struct sockaddr_in6));
#if defined(OL_HAVE_SIN6_LEN)
    hostRep->sin6_len = INET6_ADDRSTRLEN;
#endif
    hostRep->sin6_family = AF_INET6;
    hostRep->sin6_port = H16_TO_N(port);
    memcpy(&hostRep->sin6_addr, &in6addr_any, sizeof(struct in6_addr));
    return self;
}

- (void) dealloc
{
    [allocator deallocateBytes: hostRep];
    [super dealloc];
}

- (id) copyWithAllocator: (OLAllocator*)alloc
{
    return [[alloc allocateObject: [OLInternet6Address class]]
        initWithSockaddr6: hostRep socketType: socketType allocator: alloc];
}

- (id) copyWithZone: (NSZone*)zone
{
    return [[OLInternet6Address allocWithZone: zone]
        initWithSockaddr6: hostRep socketType: socketType allocator: allocator];
}

- (NSString*) description
{
    uint16_t* addr = (uint16_t*)hostRep->sin6_addr.s6_addr;
    NSString* desc;

    if (canonicalName != nil)
    {
        desc = canonicalName;
    }
    else
    {
        if (hostRep->sin6_port == 0)
        {
            desc = [[allocator allocateObject: [NSString class]]
                initWithFormat: @"%X:%X:%X:%X:%X:%X:%X:%X",
                N16_TO_H(addr[0]), N16_TO_H(addr[1]),
                N16_TO_H(addr[2]), N16_TO_H(addr[3]),
                N16_TO_H(addr[4]), N16_TO_H(addr[5]),
                N16_TO_H(addr[6]), N16_TO_H(addr[7])];
        }
        else
        {
            desc = [[allocator allocateObject: [NSString class]]
                initWithFormat: @"%X:%X:%X:%X:%X:%X:%X:%X.%i",
                N16_TO_H(addr[0]), N16_TO_H(addr[1]),
                N16_TO_H(addr[2]), N16_TO_H(addr[3]),
                N16_TO_H(addr[4]), N16_TO_H(addr[5]),
                N16_TO_H(addr[6]), N16_TO_H(addr[7]),
                N16_TO_H(hostRep->sin6_port)];
        }
        OBJ_COND_AUTORELEASE(desc);
    }
    return desc;
}

- (const struct sockaddr*) hostRepresentation
{
    return (const struct sockaddr*)hostRep;
}

- (unsigned) hostRepresentationLength
{
    return sizeof(struct sockaddr_in6);
}

- (BOOL) isEqual: (id)object
{
    OLInternet6Address* other;

    if ([object isKindOfClass: [OLInternet6Address class]])
    {
        other = (OLInternet6Address*)object;
        return other->hostRep->sin6_port == hostRep->sin6_port &&
               !memcmp(&other->hostRep->sin6_addr, &hostRep->sin6_addr, sizeof(struct in6_addr));
    }
    return NO;
}

- (BOOL) isLocalWildcard
{
    return memcmp(&in6addr_any, &hostRep->sin6_addr, sizeof(struct in6_addr)) == 0;
}

- (uint16_t) port
{
    return N16_TO_H(hostRep->sin6_port);
}

@end

#endif

#if defined(OL_HAVE_UNIX_SOCKETS)

@implementation OLUnixAddress

+ (id) addressWithPath: (NSString*)pth
{
    OL_BEGIN_AUTO_CTOR(OLUnixAddress)
        initWithPath: pth
    OL_END_AUTO_CTOR;
}

- (id) initWithPath: (NSString*)pth
{
    return [self initWithPath: pth allocator: [OLAllocator defaultAllocator]];
}

- (id) initWithPath: (NSString*)pth allocator: (OLAllocator*)alloc
{
    char nameBuf[PATH_MAX + 1];
    char resolved[PATH_MAX + 1];
#if defined(OL_REALPATH_SUCKS)
    NSString* namePart;
    NSString* withoutName;
#endif

    [super init];
    allocator = OBJ_RETAIN(alloc);
    hostRep = [alloc allocateBytes: sizeof(struct sockaddr_un)];
#if defined(OL_REALPATH_SUCKS)
    namePart = [pth lastPathComponent];
    withoutName = [pth stringByDeletingLastPathComponent];
    if ([withoutName length] == 0)
    {
        getcwd(nameBuf, PATH_MAX);
    }
    else
    {
        if (![withoutName getFileSystemRepresentation: nameBuf maxLength: PATH_MAX])
        {
            [NSException raise: NSGenericException
                format: @"Could not convert \"%@\" to a file name", withoutName];
        }
    }
    if (realpath(nameBuf, resolved) == NULL)
    {
        [NSException raise: NSGenericException
            format: @"Could not resolve full path - %s", strerror(errno)];
    }
    withoutName = [[alloc allocateObject: [NSString class]]
        initWithUTF8String: resolved];
    path = OBJ_RETAIN([withoutName stringByAppendingPathComponent: namePart]);
    [alloc deallocateObject: withoutName];
    [path getFileSystemRepresentation: hostRep->sun_path maxLength: sizeof(hostRep->sun_path) - 1];
#else
    if (![pth getFileSystemRepresentation: nameBuf maxLength: PATH_MAX])
    {
        [NSException raise: NSGenericException
            format: @"Could not convert \"%@\" to a file name", pth];
    }
    if (realpath(nameBuf, resolved) == NULL)
    {
        [NSException raise: NSGenericException
            format: @"Could not resolve full path - %s", strerror(errno)];
    }
    path = [[alloc allocateObject: [NSString class]]
        initWithUTF8String: resolved];
    strcpy(hostRep->sun_path, resolved);
#endif
    hostRep->sun_family = AF_UNIX;
    return self;
}

- (void) dealloc
{
    [allocator deallocateObject: path];
    [allocator deallocateBytes: hostRep];
    OBJ_RELEASE(allocator);
    [super dealloc];
}

- (id) copyWithAllocator: (OLAllocator*)alloc
{
    return [[alloc allocateObject: [OLUnixAddress class]]
        initWithPath: path allocator: alloc];
}

- (id) copyWithZone: (NSZone*)zone
{
    return [[OLUnixAddress allocWithZone: zone]
        initWithPath: path allocator: allocator];
}

- (NSString*) description
{
    return path;
}

- (const struct sockaddr*) hostRepresentation
{
    return (const struct sockaddr*)hostRep;
}

- (unsigned) hostRepresentationLength
{
    return OL_SUN_LEN(hostRep);
}

- (BOOL) isEqual: (id)object
{
    return [object isKindOfClass: [OLUnixAddress class]] &&
           [((OLUnixAddress*)object)->path isEqualToString: path];
}

- (NSString*) path
{
    return path;
}

@end

#endif

@implementation OLInternetAddress (PrivateMethods)

+ (OLInternetAddress*) addressImplWithHost: (const char*)name service: (const char*)service port: (int)port allocator: (OLAllocator*)alloc;
{
    OLInternetAddress* found = nil;
#if defined(OL_HAVE_GETADDRINFO)
    struct addrinfo* returned;
    struct addrinfo* cur;
    int rc;

    rc = getaddrinfo(name, service, NULL, &returned);
    if (rc != 0)
    {
        // No open-source implementation of gai_strerror() seems to be
        //   available for Windows, MS version of winsock2.h must use macros?
#ifndef WIN32
        [NSException raise: OLSocketException
            format: @"Error looking up host %s - %s",
            name, gai_strerror(rc)];
#else
        [NSException raise: OLSocketException
            format: @"Error looking up host %s", name];
#endif
    }
    for (cur = returned; cur != NULL; cur = cur->ai_next)
    {
        if (cur->ai_family == PF_INET)
        {
            found = [[alloc allocateObject: [OLInternet4Address class]]
                initImplWithAddrinfo: cur port: port allocator: alloc];
            break;
        }
#if defined(OL_HAVE_INET6_SOCKETS)
        else if (cur->ai_family == PF_INET6)
        {
            found = [[alloc allocateObject: [OLInternet6Address class]]
                initImplWithAddrinfo: cur port: port allocator: alloc];
            break;
        }
#endif
    }
    freeaddrinfo(returned);
#elif defined(OL_HAVE_GETHOSTBYNAME)
    struct hostent* hent;
    struct servent* sent;
    struct servent localSent;

    hent = gethostbyname(name);
    if (hent == NULL)
    {
        // No open-source definition of hstrerror seems to be available
        //   for Windows; MS version of winsock2.h must use macros.
#ifndef WIN32
        [NSException raise: OLSocketException
            format: @"Error looking up host %s - %s",
            name, hstrerror(h_errno)];
#else
        [NSException raise: OLSocketException
            format: @"Error looking up host %s", name];
#endif
    }
    if (service != NULL)
    {
        sent = getservbyname(service, NULL);
        if (sent == NULL)
        {
            [NSException raise: OLSocketException
                format: @"Error looking up service %s",
                service];
        }
    }
    else
    {
        sent = &localSent;
        sent->s_port = H16_TO_N(port);
    }
    if (hent->h_addrtype == AF_INET)
    {
        found = [[alloc allocateObject: [OLInternet4Address class]]
            initImplWithHostent: hent andServent: sent allocator: alloc];
    }
#if defined(OL_HAVE_INET6_SOCKETS)
    else if (hent->h_addrtype == AF_INET6)
    {
        found = [[alloc allocateObject: [OLInternet6Address class]]
            initImplWithHostent: hent andServent: sent allocator: alloc];
    }
#endif
#endif
    if (found == nil)
    {
        [NSException raise: OLSocketException
            format: @"Host %s not found", name];
    }
    return [alloc autorelease: found];
}

- (id) initImplWithName: (const char*)name socketType: (int)type allocator: (OLAllocator*)alloc
{
    [super init];
    allocator = OBJ_RETAIN(alloc);
    canonicalName = (name == NULL) ?
        nil :
        [[alloc allocateObject: [NSString class]]
        initWithBytes: name length: strlen(name) encoding: NSASCIIStringEncoding];
    socketType = type;
    return self;
}

- (int) addressFamily
{
    return 0;
}

@end

@implementation OLInternet4Address (PackageMethods)

- (id) initWithSockaddr: (const struct sockaddr_in*)addr socketType: (int)sockType allocator: (OLAllocator*)alloc
{
    [super initImplWithName: NULL socketType: sockType allocator: alloc];
    hostRep = [alloc allocateBytes: sizeof(struct sockaddr_in)];
    memcpy(hostRep, addr, sizeof(struct sockaddr_in));
    return self;
}

@end

@implementation OLInternet4Address (PrivateMethods)

#if defined(OL_HAVE_GETADDRINFO)

- (id) initImplWithAddrinfo: (const struct addrinfo*)info port: (int) port allocator: (OLAllocator*)alloc
{
    NSAssert(info->ai_addrlen == sizeof(struct sockaddr_in), @"Incorrect size of sockaddr");
    [super initImplWithName: info->ai_canonname socketType: info->ai_socktype allocator: alloc];
    hostRep = [alloc allocateBytes: sizeof(struct sockaddr_in)];
    memcpy(hostRep, info->ai_addr, sizeof(struct sockaddr_in));
    if (port >= 0)
        hostRep->sin_port = H16_TO_N(port);
    return self;
}

#elif defined(OL_HAVE_GETHOSTBYNAME)

- (id) initImplWithHostent: (const struct hostent*)hent andServent: (const struct servent*)sent allocator: (OLAllocator*)alloc
{
    [super initImplWithName: hent->h_name socketType: hent->h_addrtype allocator: alloc];
    hostRep = [alloc allocateBytes: sizeof(struct sockaddr_in)];
#if defined(OL_HAVE_SIN_LEN)
    hostRep->sin_len = INET_ADDRSTRLEN;
#endif
    hostRep->sin_family = hent->h_addrtype;
    memcpy(&hostRep->sin_addr, hent->h_addr_list[0], hent->h_length);
    hostRep->sin_port = sent->s_port;
    memset(hostRep->sin_zero, 0, sizeof(hostRep->sin_zero));
    return self;
}

#endif

- (int) addressFamily
{
    return AF_INET;
}

@end

#if defined(OL_HAVE_INET6_SOCKETS)

@implementation OLInternet6Address (PackageMethods)

- (id) initWithSockaddr6: (const struct sockaddr_in6*)addr socketType: (int)sockType allocator: (OLAllocator*)alloc
{
    [super initImplWithName: NULL socketType: sockType allocator: alloc];
    hostRep = [alloc allocateBytes: sizeof(struct sockaddr_in6)];
    memcpy(hostRep, addr, sizeof(struct sockaddr_in6));
    return self;
}

@end

@implementation OLInternet6Address (PrivateMethods)

#if defined(OL_HAVE_GETADDRINFO)

- (id) initImplWithAddrinfo: (const struct addrinfo*)info port: (int)port allocator: (OLAllocator*)alloc
{
    NSAssert(info->ai_addrlen == sizeof(struct sockaddr_in6), @"Incorrect size of sockaddr");
    [super initImplWithName: info->ai_canonname socketType: info->ai_socktype allocator: alloc];
    hostRep = [alloc allocateBytes: sizeof(struct sockaddr_in6)];
    memcpy(hostRep, info->ai_addr, sizeof(struct sockaddr_in6));
    if (port >= 0)
        hostRep->sin6_port = H16_TO_N(port);
    return self;
}

#elif defined(OL_HAVE_GETHOSTBYNAME)

- (id) initImplWithHostent: (const struct hostent*)hent andServent: (const struct servent*)sent allocator: (OLAllocator*)alloc
{
    [super initImplWithName: hent->h_name socketType: hent->h_addrtype allocator: alloc];
    hostRep = [alloc allocateBytes: sizeof(struct sockaddr_in6)];
    memset(hostRep, 0, sizeof(struct sockaddr_in6));
#if defined(OL_HAVE_SIN6_LEN)
    hostRep->sin6_len = INET6_ADDRSTRLEN;
#endif
    hostRep->sin6_family = hent->h_addrtype;
    memcpy(&hostRep->sin6_addr, hent->h_addr_list[0], hent->h_length);
    hostRep->sin6_port = sent->s_port;
    return self;
}

#endif

- (int) addressFamily
{
    return AF_INET6;
}

@end

#endif

#if defined(OL_HAVE_UNIX_SOCKETS)

@implementation OLUnixAddress (PackageMethods)

- (id) initWithSockaddrUnix: (const struct sockaddr_un*)addr allocator: (OLAllocator*)alloc
{
    [super init];
    allocator = OBJ_RETAIN(alloc);
    hostRep = [alloc allocateBytes: sizeof(struct sockaddr_un)];
    memcpy(hostRep, addr, sizeof(struct sockaddr_un));
    path = OBJ_RETAIN([[alloc allocateObject: [NSString class]]
        initWithUTF8String: hostRep->sun_path]);
    [alloc deallocateObject: path];
    return self;
}

@end

#endif
