// Copyright 1997-1998 Omni Development, Inc.  All rights reserved.

#import "ONServiceEntry.h"

#import <Foundation/Foundation.h>
#import <OmniBase/OmniBase.h>
#import <OmniBase/system.h>

RCS_ID("$Header: /Network/Developer/Source/CVS/OmniGroup/OmniNetworking/ONServiceEntry.m,v 1.6 1998/01/12 06:53:50 kc Exp $")

@interface ONServiceEntry (Private)
- _initWithServiceEntry:(struct servent *)entry serviceName:(NSString *)aServiceName protocolName:(NSString *)aProtocolName;
@end

@implementation ONServiceEntry

static NSRecursiveLock *serviceLookupLock;
static NSMutableDictionary *serviceCache;

+ (void)initialize;
{
    static BOOL initialized = NO;

    [super initialize];
    if (initialized)
	return;
    initialized = YES;

    serviceLookupLock = [[NSRecursiveLock alloc] init];
    serviceCache = [[NSMutableDictionary alloc] initWithCapacity:16];
}

+ serviceEntryNamed:(NSString *)aServiceName protocolName:(NSString *)aProtocolName;
{
    ONServiceEntry *entry = nil;
    unsigned int serviceNameLength, protocolNameLength;
    struct servent *newServiceEntry;
    NSMutableDictionary *protocolDictionary;

    if (!aServiceName || !aProtocolName)
	return nil;

    [serviceLookupLock lock];

    if (!(protocolDictionary = [serviceCache objectForKey:aServiceName])) {
	protocolDictionary = [[NSMutableDictionary alloc] init];
	[serviceCache setObject:protocolDictionary forKey:aServiceName];
	[protocolDictionary release];
    }
    entry = [protocolDictionary objectForKey:aProtocolName];
    if (!entry) {
        char *cServiceName, *cProtocolName;

        serviceNameLength = [aServiceName length];
        protocolNameLength = [aProtocolName length];
        cServiceName = (char *)alloca(serviceNameLength + 1);
        cProtocolName = (char *)alloca(protocolNameLength + 1);

        [aServiceName getCString:cServiceName maxLength:serviceNameLength];
        [aProtocolName getCString:cProtocolName maxLength:protocolNameLength];

        newServiceEntry = getservbyname(cServiceName, cProtocolName);
        if (newServiceEntry) {
            entry = [[self alloc] _initWithServiceEntry:newServiceEntry serviceName:aServiceName protocolName:aProtocolName];
            [protocolDictionary setObject:entry forKey:aProtocolName];
            [entry release];
        }
    }

    [serviceLookupLock unlock];

    if (!entry)
	[NSException raise:ONServiceNotFoundExceptionName format:@"Service/Protocol '%@/%@' not found", aServiceName, aProtocolName];

    return entry;
}

- (void)dealloc;
{
    [serviceName release];
    [protocolName release];
    NSZoneFree(NULL, serviceEntry);
    [super dealloc];
}

- (NSString *)serviceName;
{
    return serviceName;
}

- (NSString *)protocolName;
{
    return protocolName;
}

- (unsigned short int)portNumber;
{
    return ntohs(serviceEntry->s_port);
}

- (const struct servent *)serviceEntry;
{
    return serviceEntry;
}

@end

@implementation ONServiceEntry (Private)

- _initWithServiceEntry:(struct servent *)entry serviceName:(NSString *)aServiceName protocolName:(NSString *)aProtocolName;
{
    if (![super init])
        return nil;

    serviceEntry = NSZoneMalloc(NULL, sizeof(struct servent));
    *serviceEntry = *entry;
    serviceName = [aServiceName copy];
    protocolName = [aProtocolName copy];

    return self;
}

@end

NSString *ONServiceEntryIPProtocolName = @"ip";
NSString *ONServiceEntryICMPProtocolName = @"icmp";
NSString *ONServiceEntryTCPProtocolName = @"tcp";
NSString *ONServiceEntryUDPProtocolName = @"udp";

DEFINE_NSSTRING(ONServiceNotFoundExceptionName);
