/*******************************************************************************
 * Copyright (c) 2005, 2008 Intel Corporation and others.
 * 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: TransportOSCalls_win.c,v 1.11 2008/06/16 20:58:04 jkubasta Exp $
 *
 *******************************************************************************/ 

#ifdef _WIN32     // Windows-specific

#include "tptp/TransportSupport.h"

/**
 *********************************************************
 *
 * @brief
 *    required initialization before using socket library.
 *    This also checks for socket DLL version.
 *
 * @return
 *    0 - Success
 *    nonzero - Error.
 *********************************************************/
int initForSocketCalls() 
{
	WORD     wVersionRequested;
	WSADATA  wsaData;
	int      rc = 0 ;

	wVersionRequested = MAKEWORD(2, 2);

	rc = WSAStartup(wVersionRequested, &wsaData);

	if (rc == 0) 
	{
		if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 2 ) 
		{
			WSACleanup();
			rc = -1 ;
		}
	}

	return ( rc );
}


/**
 *********************************************************
 *
 * @brief
 *    set a given handle for child process inheritance
 *
 * @return
 *    0 - Error
 *    nonzero - Success
 *********************************************************/
int setHandleInherited(HANDLE handle)
{
	return (SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0)) ;
}



/**
 *********************************************************
 *
 * @brief
 *    return indicator whether a given socket is valid or not
 *
 * @return
 *    nonzero - Valid
 *    zero - Invalid
 *********************************************************/
int isSocketValid(SOCKET sock)
{
	return (sock != INVALID_SOCKET) ;
}


/**
 *********************************************************
 *
 * @brief
 *    print out info about a given socket request
 *
 * @return
 *    0 - always
 * IPV4-ONLY
 *********************************************************/
int printSocketRequest(SOCKET sock, struct sockaddr_in *pRequester)
{
    printf("Incoming connection request on socket %d from %d.%d.%d.%d \n",
				sock,
				pRequester->sin_addr.S_un.S_un_b.s_b1,
				pRequester->sin_addr.S_un.S_un_b.s_b2,
				pRequester->sin_addr.S_un.S_un_b.s_b3,
				pRequester->sin_addr.S_un.S_un_b.s_b4);

	return 0 ;
}



/**
 *********************************************************
 *
 * @brief
 *    Read from a given sock and place the incoming data
 *    into the given buffer
 *
 * @return
 *    negative - Error in receiving
 *    zero - Socket has been closed
 *    positive - Successfully read. The number of bytes received.
 *********************************************************/
int  readFromSocket(SOCKET sock,
					char *buffer,
					int bufferLength,
					int *pBytesRead)
{
	int    rc = -1;

	int result = recv(sock, buffer, bufferLength, 0);

	switch(result)
	{
		case 0:              rc =  0 ; break ;
		case SOCKET_ERROR:   rc = -1 ; break ;
		default:
			rc = result ;
			*pBytesRead = result ;
			/* terminate with a NULL byte for printf purpose */
			*(buffer+result) = '\0' ;
	}

	return ( rc ) ;
}


/**
 *********************************************************
 *
 * @brief
 *    close the given socket connection
 *
 * @return
 *    0 - Success
 *    nonzero - Error.
 *********************************************************/
int closeThisSocket(SOCKET sock) 
{
	int rc = 0 ;

	shutdown(sock, SD_BOTH); 
	rc = closesocket(sock);

	return ( rc ) ;
}

/**
 *********************************************************
 *
 * @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
 *********************************************************/
int convertIPAddressStringToArrayIPv4M( char *addrStr, unsigned char* addrArray )
{
	struct in_addr addr;
	
	addr.S_un.S_addr = inet_addr( addrStr );
	if ( addr.S_un.S_addr == INADDR_NONE )
	{
		/* The string wasn't recognized as a valid IP address */
		return -1;
	}
	addrArray[0]=addr.S_un.S_un_b.s_b1;
	addrArray[1]=addr.S_un.S_un_b.s_b2;
	addrArray[2]=addr.S_un.S_un_b.s_b3;
	addrArray[3]=addr.S_un.S_un_b.s_b4;

	return 0;
}

/**
 *********************************************************
 *
 * @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 )
{
	char* tempAddrStr;
	struct in_addr  saddr;
	
	saddr.S_un.S_addr = ntohl( addr );
	tempAddrStr = inet_ntoa( saddr );
	if ( tempAddrStr == NULL )
	{
		/* addr wasn't recognized as a valid IP address */
		return -1;
	}

	/* The size here (16) is three digits for each element, plus three dots, plus a NULL */
	*addrStr = tptp_malloc( 16 );
	if ( *addrStr == NULL )
	{
		return TPTP_SYS_NO_MEM;
	}

	strcpy( *addrStr, tempAddrStr );

	return 0;
}

/** IPV4-ONLY */
void extractAddressFromSockAddr(struct sockaddr_in *connection, unsigned char *address)
{
	address[0]=connection->sin_addr.S_un.S_un_b.s_b1;
	address[1]=connection->sin_addr.S_un.S_un_b.s_b2;
	address[2]=connection->sin_addr.S_un.S_un_b.s_b3;
	address[3]=connection->sin_addr.S_un.S_un_b.s_b4;
}

#endif   // end-of-Windows-specific
