/***************************************************************************/
/*                                                                         */
/* Project:     OpenSLP - OpenSource implementation of Service Location    */
/*              Protocol                                                   */
/*                                                                         */
/* File:        slplib_handle.h                                            */
/*                                                                         */
/* Abstract:    Implementation for SLPOpen() and SLPClose() functions      */
/*                                                                         */
/*-------------------------------------------------------------------------*/
/*                                                                         */
/*     Please submit patches to http://www.openslp.org                     */
/*                                                                         */
/*-------------------------------------------------------------------------*/
/*                                                                         */
/* Copyright (C) 2000 Caldera Systems, Inc                                 */
/* All rights reserved.                                                    */
/*                                                                         */
/* Redistribution and use in source and binary forms, with or without      */
/* modification, are permitted provided that the following conditions are  */
/* met:                                                                    */ 
/*                                                                         */
/*      Redistributions of source code must retain the above copyright     */
/*      notice, this list of conditions and the following disclaimer.      */
/*                                                                         */
/*      Redistributions in binary form must reproduce the above copyright  */
/*      notice, this list of conditions and the following disclaimer in    */
/*      the documentation and/or other materials provided with the         */
/*      distribution.                                                      */
/*                                                                         */
/*      Neither the name of Caldera Systems nor the names of its           */
/*      contributors may be used to endorse or promote products derived    */
/*      from this software without specific prior written permission.      */
/*                                                                         */
/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS     */
/* `AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT      */
/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR   */
/* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE CALDERA      */
/* SYSTEMS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */
/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT        */
/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;  LOSS OF USE,  */
/* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON       */
/* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */
/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE   */
/* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.    */
/*                                                                         */
/***************************************************************************/

#include "slp.h"
#include "libslp.h"

/*=========================================================================*/
int G_OpenSLPHandleCount = 0;
/* Global variable that keeps track of the number of handles that are open */
/*=========================================================================*/


/*=========================================================================*/
SLPError SLPAPI SLPOpen(const char *pcLang, SLPBoolean isAsync, SLPHandle *phSLP)
/*                                                                         */
/* Returns a SLPHandle handle in the phSLP parameter for the language      */
/* locale passed in as the pcLang parameter.  The client indicates if      */
/* operations on the handle are to be synchronous or asynchronous          */
/* through the isAsync parameter.  The handle encapsulates the language    */
/* locale for SLP requests issued through the handle, and any other        */
/* resources required by the implementation.  However, SLP properties      */
/* are not encapsulated by the handle; they are global.  The return        */
/* value of the function is an SLPError code indicating the status of      */
/* the operation.  Upon failure, the phSLP parameter is NULL.              */
/*                                                                         */
/* An SLPHandle can only be used for one SLP API operation at a time.      */
/* If the original operation was started asynchronously, any attempt to    */
/* start an additional operation on the handle while the original          */
/* operation is pending results in the return of an SLP_HANDLE_IN_USE      */
/* error from the API function.  The SLPClose() API function terminates    */
/* any outstanding calls on the handle.  If an implementation is unable    */
/* to support a asynchronous( resp.  synchronous) operation, due to        */
/* memory constraints or lack of threading support, the                    */
/* SLP_NOT_IMPLEMENTED flag may be returned when the isAsync flag is       */
/* SLP_TRUE (resp.  SLP_FALSE).                                            */
/*                                                                         */
/* pcLang   A pointer to an array of characters containing the RFC 1766    */
/*          Language Tag RFC 1766 for the natural language locale of       */
/*          requests and registrations issued on the handle. Pass in NULL  */
/*          or the empty string, "" to use the default locale              */
/*                                                                         */
/* isAsync  An SLPBoolean indicating whether the SLPHandle should be opened*/
/*          for asynchronous operation or not.                             */
/*                                                                         */
/* phSLP    A pointer to an SLPHandle, in which the open SLPHandle is      */
/*          returned.  If an error occurs, the value upon return is NULL.  */
/*                                                                         */
/* Returns  SLPError code                                                  */
/*=========================================================================*/
{
    SLPError        result = SLP_OK;
    PSLPHandleInfo  handle = 0;

    /*------------------------------*/
    /* check for invalid parameters */
    /*------------------------------*/
    if(phSLP == 0)
    {
        result =  SLP_PARAMETER_BAD;
        goto FINISHED;
    }

    /* assign out param to zero in just for paranoia */
    *phSLP = 0;


#ifndef ENABLE_ASYNC_API   
    if(isAsync == SLP_TRUE)
    {
        result =  SLP_NOT_IMPLEMENTED;
        goto FINISHED;
    }
/*-------------------------------------------------------*/
/* TODO: remove the #else when we implement async calls  */
/*-------------------------------------------------------*/
#else
    if(isAsync == SLP_TRUE)
    {
        result =  SLP_NOT_IMPLEMENTED;
        goto FINISHED;
    }
#endif 

    /*------------------------------------*/
    /* allocate a SLPHandleInfo structure */
    /*------------------------------------*/
    handle = (PSLPHandleInfo)xmalloc(sizeof(SLPHandleInfo));
    if(handle == 0)
    {
        result =  SLP_PARAMETER_BAD;
        goto FINISHED;
    }
    memset(handle,0,sizeof(SLPHandleInfo));

    /*-------------------------------*/
    /* Set the language tag          */
    /*-------------------------------*/
    if(pcLang && *pcLang)
    {
        handle->langtaglen = strlen(pcLang);
        handle->langtag = (char*)xmalloc(handle->langtaglen + 1);
        if(handle->langtag == 0)
        {
            xfree(handle);
            result =  SLP_PARAMETER_BAD;
            goto FINISHED;
        }
        memcpy(handle->langtag,pcLang,handle->langtaglen + 1); 
    }
    else
    {
        handle->langtaglen = strlen(SLPGetProperty("net.slp.locale"));
        handle->langtag = (char*)xmalloc(handle->langtaglen + 1);
        if(handle->langtag == 0)
        {
            xfree(handle);
            result =  SLP_PARAMETER_BAD;
            goto FINISHED;
        }
        memcpy(handle->langtag,SLPGetProperty("net.slp.locale"),handle->langtaglen + 1);       
    }

    /*---------------------------------------------------------*/
    /* Seed the XID generator if this is the first open handle */
    /*---------------------------------------------------------*/
    if(G_OpenSLPHandleCount == 0)
    {
#ifdef _WIN32
        WSADATA wsaData; 
        WORD    wVersionRequested = MAKEWORD(1,1); 
        if(0 != WSAStartup(wVersionRequested, &wsaData))
        {
            result = SLP_NETWORK_INIT_FAILED;
            goto FINISHED;
        }
#endif

#ifdef DEBUG
        xmalloc_init("/tmp/libslp_xmalloc.log",0);
#endif
        
        SLPXidSeed();
    }

#ifdef ENABLE_SLPv2_SECURITY
    handle->hspi = SLPSpiOpen(LIBSLP_SPIFILE,0);
#endif

    handle->sig = SLP_HANDLE_SIG;
    handle->inUse = SLP_FALSE;
    handle->isAsync = isAsync;
    handle->dasock = -1;
    handle->sasock = -1;
#ifndef UNICAST_NOT_SUPPORTED
    handle->unicastsock = -1;
#endif
		
    G_OpenSLPHandleCount ++;  

    *phSLP = (SLPHandle)handle; 

    FINISHED:                  

    if(result)
    {
        *phSLP = 0;
    }

    return result;
}


/*=========================================================================*/
void SLPAPI SLPClose(SLPHandle hSLP)                                             
/*                                                                         */
/* Frees all resources associated with the handle.  If the handle was      */
/* invalid, the function returns silently.  Any outstanding synchronous    */
/* or asynchronous operations are cancelled so their callback functions    */
/* will not be called any further.                                         */
/*                                                                         */
/* SLPHandle    A SLPHandle handle returned from a call to SLPOpen().      */
/*=========================================================================*/
{
    PSLPHandleInfo   handle;

    /*------------------------------*/
    /* check for invalid parameters */
    /*------------------------------*/
    if(hSLP == 0 || *(unsigned int*)hSLP != SLP_HANDLE_SIG)
    {
        return;
    }

    handle = (PSLPHandleInfo)hSLP;

    if(handle->isAsync)
    {
        /* TODO: stop the usage of this handle (kill threads, etc) */
    }

    if(handle->langtag)
    {
        xfree(handle->langtag);
    }

    if(handle->dasock >=0)
    {
#ifdef _WIN32
        closesocket(handle->dasock);
#else
        close(handle->dasock);
#endif
    }

    if(handle->dascope)
    {
        xfree(handle->dascope);
    }

    if(handle->sasock >=0)
    {
#ifdef _WIN32
        closesocket(handle->sasock);
#else
        close(handle->sasock);
#endif
    }

    if(handle->sascope)
    {
        xfree(handle->sascope);
    }

#ifdef ENABLE_SLPv2_SECURITY
    if(handle->hspi) SLPSpiClose(handle->hspi);
#endif

    handle->sig = 0;  /* If they use the handle again, it won't be valid */

    xfree(hSLP);

    G_OpenSLPHandleCount --;
    

#if DEBUG
    /* Free additional resources if this is the last handle open */
    if(G_OpenSLPHandleCount <= 0)
    {
        G_OpenSLPHandleCount = 0;

        SLPPropertyFreeAll();
        
        KnownDAFreeAll();
        
        xmalloc_deinit();
    }
#endif

}


#ifndef MI_NOT_SUPPORTED
/*=========================================================================*/
SLPError SLPAssociateIFList( SLPHandle hSLP, const char* McastIFList)
/*                                                                         */
/* Associates a list of interfaces McastIFList on which multicast needs to */
/* be done with a particular SLPHandle hSLP. McastIFList is a comma        */
/* separated list of host interface IP addresses.                          */
/*                                                                         */
/* hSLP                 The SLPHandle with which the interface list is to  */
/*                      be associated with.                                */
/*                                                                         */
/* McastIFList          A comma separated list of host interface IP        */
/*                      addresses on which multicast needs to be done.     */
/*                                                                         */
/* Returns  SLPError code                                                  */
/*=========================================================================*/
{

    PSLPHandleInfo      handle;

    /*------------------------------*/
    /* check for invalid parameters */
    /*------------------------------*/
    if(hSLP            == 0 ||
       *(unsigned int*)hSLP != SLP_HANDLE_SIG ||
       McastIFList == 0 ||
       *McastIFList == 0)  /* interface list can't be empty string */
    {
        return SLP_PARAMETER_BAD;
    }

    handle = (PSLPHandleInfo)hSLP;

#ifdef DEBUG
    fprintf(stderr, "SLPAssociateIFList(): McastIFList = %s\n", McastIFList);
#endif

        handle->McastIFList = McastIFList;

    return SLP_OK;
}
#endif /* MI_NOT_SUPPORTED */


#ifndef UNICAST_NOT_SUPPORTED
/*=========================================================================*/
SLPError SLPAssociateIP( SLPHandle hSLP, const char* unicast_ip)
/*                                                                         */
/* Associates an IP address unicast_ip with a particular SLPHandle hSLP.   */
/* unicast_ip is the IP address of the SA/DA from which service is         */
/* requested.                                                              */
/*                                                                         */
/* hSLP                 The SLPHandle with which the unicast_ip address is */
/*                      to be associated with.                             */
/*                                                                         */
/* unicast_ip           IP address of the SA/DA from which service is      */
/*                      requested.                                         */
/*                                                                         */
/* Returns  SLPError code                                                  */
/*=========================================================================*/
{

    PSLPHandleInfo      handle;

    /*------------------------------*/
    /* check for invalid parameters */
    /*------------------------------*/
    if(hSLP            == 0 ||
       *(unsigned int*)hSLP != SLP_HANDLE_SIG ||
       unicast_ip == 0 ||
       *unicast_ip == 0)  /* unicast address not specified */
    {
        return SLP_PARAMETER_BAD;
    }

    handle = (PSLPHandleInfo)hSLP;

#ifdef DEBUG
    fprintf(stderr, "SLPAssociateIP(): unicast_ip = %s\n", unicast_ip);
#endif
    handle->dounicast = 1;
    handle->unicastaddr.sin_family = AF_INET;
    if (inet_aton(unicast_ip, ((struct in_addr *)(&handle->unicastaddr.sin_addr))) == 0 )
    {
        return SLP_PARAMETER_BAD;
    }
    handle->unicastaddr.sin_port = htons(SLP_RESERVED_PORT);

    return SLP_OK;
}
#endif

