/*******************************************************************************
 * Copyright (c) 2005, 2008 Intel Corporation.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Hoang M Nguyen, Intel - Initial API and Implementation
 *
 * $Id: TransportSupportSocket.h,v 1.11 2008/07/25 00:22:43 jcayne Exp $
 *
 *******************************************************************************/



#ifndef TransportSupportSocket_H
#define TransportSupportSocket_H


#include "tptp/TPTPSupportTypes.h"


#ifdef __cplusplus
extern "C" {
#endif



/**
 *********************************************************
 *
 * @brief
 *    convert the given IP address string from "II.JJ.KK.LL"
 *    format to a four byte data array containting
 *    [II][JJ][KK][LL] as unsigned characters
 *
 * @return
 *    0          success
 *    non-zero   failure code
 *
 *********************************************************/
int convertIPAddressStringToArrayIPv4M( char *addrStr, unsigned char* addrArray );

/**
 *********************************************************
 *
 * @brief
 *    convert the given IP address string from "II.JJ.KK.LL"
 *    format to an unsigned long
 *
 * @return
 *    0          success
 *    non-zero   failure code
 *
 *********************************************************/
int convertIPAddressStringToUlongIPv4M( char *addrStr, unsigned long* addr );

/**
 *********************************************************
 *
 * @brief
 *    convert the given IP address unsigned long value
 *    to "II.JJ.KK.LL" format.  The string returned will
 *    have been allocated using tptp_malloc and should
 *    be freed by the caller using tptp_free
 *
 * @return
 *    0          success
 *    non-zero   failure
 *********************************************************/
int convertIPAddressUlongToStringIPv4M( unsigned long addr, char **addrStr );

/**
 *********************************************************
 *
 * @brief
 *    get the IP address associated with the given socket
 *
 * @param sock       The socket whose IP address is returned
 * @param ipAddrStr  Pointer to receive the address of the
 *                   IP addr string.  The caller must free
 *                   the memory allocated for this string
 *                   using tptp_free.
 *
 * @return
 *    0          success
 *    non-zero   failure code
 *
 *********************************************************/
int getSocketIPStringIPv4M( SOCKET sock, char** ipAddrStr );

/**
 *********************************************************
 *
 * @brief
 *    get the IP address associated with the given socket
 *
 * @param sock       The socket whose IP peer address is returned
 * @param ipAddrStr  Pointer to receive the address of the
 *                   IP addr string.  The caller must free
 *                   the memory allocated for this string
 *                   using tptp_free.
 *
 * @return
 *    0          success
 *    non-zero   failure code
 *
 *********************************************************/
int getPeerIPString( SOCKET sock, char** ipAddrStr );

/**
 *********************************************************
 *
 * @brief
 *    get the localhost info
 *
 * @return
 *    host info data structure
 *********************************************************/
struct sockaddr_storage* getHostInfo();

struct hostent * getHostInfoIPv4M();

/**
 *********************************************************
 *
 * @brief
 *    get the host info with the passed in hostname
 *
 * @return
 *    host info data structure
 *********************************************************/
struct hostent * getTargetHostInfoIPv4M(char* hostname);

/**
 *********************************************************
 *
 * @brief
 *    get the localhost socket connection
 *
 * @return
 *    the raw unconnected socket
 *
 *********************************************************/
int getTheSocket(int portNum, SOCKET *outResult, int *outNumSockets);

/**
 *********************************************************
 *
 * @brief
 *    bind and prepare the server socket
 *
 * @return
 *    0 - Success
 *    nonzero - Error.
 *********************************************************/
SOCKET bindAndListen(struct addrinfo *AI);

/**
 *********************************************************
 *
 * @brief
 *    Get server socket ready and accept incoming connection requests
 *
 * @return
 *    the socket for the connection request
 *********************************************************/
SOCKET  acceptSocketConnection(SOCKET serverSock) ;

/**
 *********************************************************
 *
 * @brief
 *    connect to the given system
 *
 * @return
 *    If we were able to connect pSock contans a SOCKET, otherwise, it's INVALID_SOCKET.
 *********************************************************/
int connectToTCPServer(char * hostname, int port, SOCKET *pSock);


/**
 *********************************************************
 *
 * @brief
 *    connect to the given system
 *
 * @return
 *    If we were able to connect pSock contans a SOCKET, otherwise, it's INVALID_SOCKET.
 *********************************************************/
int connectToTCPServerAddr(struct sockaddr_storage * addr, int port, SOCKET *pSock);


int connectToTCPServerIPv4M(unsigned long ipAddr, unsigned short portNum, SOCKET *pSock);

/**
 *********************************************************
 *
 * @brief
 *    common interface to terminate the given connection
 *    (socket).
 *
 * @return
 *    the actual number of bytes sent
 *********************************************************/
int  writeToSocket(SOCKET sock,
				   char *buffer,
				   int byteCount);

int getPeerName(SOCKET sock, unsigned char *pAddr);

int closeSocket(int socket);

/** SOCKET ->  struct sockaddr_storage * for the peer. */
struct sockaddr_storage * getPeerAddrOfSocket(SOCKET ConnSocket);

/** struct sockaddr_storage * => IP address in byte format (e.g. in_addr / in6_addr) + family 
    The bytes are stored in outAddr, and the family is stored in family.*/
void getByteFormatFromSockAddr(struct sockaddr_storage *addr, void ** outAddr, int *family);

void getSockAddrFromByteFormat(void *inAddr, int family, struct sockaddr_storage **outResult);

void setSockaddrStoragePort(struct sockaddr_storage *addr, int port);

typedef struct {
	tptp_list_t serverSocketList;

	tptp_list_t socketsToProcess;
	Lock_t sockProcLock;

} socket_accept_t;

SOCKET acceptSocketConnections(SOCKET * sockets, int numSockets, socket_accept_t * sockAcceptState);
void initSocketAccept(socket_accept_t * sat);

struct sockaddr_storage * cloneSockAddr(struct sockaddr_storage * addr);


int isAddrLocal(struct sockaddr_storage * addr);
int compareAddresses(struct sockaddr_storage * one, struct sockaddr_storage * two);
char * convertAddrToHostname(struct sockaddr_storage *addr);

void getLocalHostAddresses(struct sockaddr_storage *** arrOfAddr, int * numAddr);

void freeAddressList(struct sockaddr_storage ** arrOfAddr, int numAddr);

int convertHostnameToAddrs(char *hostname, struct sockaddr_storage *** outResult, int *outNumResults);

struct sockaddr_storage * getSelfAddrOfSocket(SOCKET ConnSocket);

void printSockAddrStorage(struct sockaddr_storage *inAddr);

SOCKET connectToHostWithHostname(char * hostnameOrIp, int port, struct addrinfo ** sockAddrOut );

int isAddressIPv6RemappedToIPv4(struct sockaddr_storage * addr);

struct sockaddr_storage * convertIPv6RemappedAddresstoIPv4(struct sockaddr_storage * in);


#ifdef __cplusplus
}
#endif


#endif


