/*******************************************************************

Copyright (c) 2004 Open Mobile Alliance, Ltd.  All Rights Reserved.

This software is made available under the usage and distribution terms 
covered by the Common Public License 1.0 and by using this software you
are bound by the terms and conditions of the same.

EXCEPT AS EXPRESSLY SET FORTH IN THE COMMON PUBLIC LICENSE,
THIS PROGRAM IS PROVIDED ON AN "AS IS" BASIS, 
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 
EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, 
ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, 
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
   
Each recipient is solely responsible for determining the 
appropriateness of using and distributing this program and assumes 
all risks associated with its exercise of rights under the Common 
Public License, including but not limited to the risks and 
costs of program errors, compliance with applicable laws, 
damage to or loss of data, programs or equipment, and 
unavailability or interruption of operations.

********************************************************************/
/*************************************************************************/
/* module:          SyncML Communication Services, TCP/IP functions      */
/* file:            src/xpt/all/xpt-tcp.c                                */
/* target system:   all                                                  */
/* target OS:       all                                                  */
/*************************************************************************/



/**
 * Basic TCP/IP services for the SyncML communication services
 *
 */

#define MAX_SOCKET_CONNECTIONS  10
#define HTTP_PORT             "80"


#include "xptitcp.h" // internal OS specific info.

#include "xpttypes.h"
#include "xptport.h"
#include "xpt-tcp.h"
#include <stdio.h>
#include <time.h>

/**
 * FUNCTION: getConfig
 *
 * check error of ssl
 *
 * OUT:             pErr
 *                  error code of ssl. 
 * 
 * RETURN:
 */
static const char *getConfig(const char *name)
{
    if (!name) return 0;
    if (!strcmp(name, "CAFILE"))
    {
        return "cacert.pem";
    }
    else if(!strcmp(name, "CERTFILE"))
    {
        return "client.pem";
    }
    else if(!strcmp(name, "CIPHER_LIST"))
    {
        return "ALL";
    }
    else if(!strcmp(name, "VERIFY_DEPTH"))
    {
        return "10";
    }
    return "";
}

/**
 * FUNCTION: CHK_SSL
 *
 * check error of ssl
 *
 * OUT:             pErr
 *                  error code of ssl. 
 * 
 * RETURN:
 */
static void CHK_SSL(int *pErr, const char*pMsg)
{
    static FILE *sslLog = 0;
    char * errMsgBuf=0;
    if (!pErr) return;
    if (!sslLog)
    {
        sslLog = fopen("ssl.log", "w");
    }
    *pErr = ERR_get_error();
    errMsgBuf = (char *)xppMalloc(
        xppStrlen(pMsg?pMsg:"")+
        xppStrlen(ERR_error_string(*pErr, 0))+
        4+
        1
        );
    if (errMsgBuf)
    {
        xppStrcpy(errMsgBuf, pMsg);
        xppStrcat(errMsgBuf, " : ");
        xppStrcat(errMsgBuf, ERR_error_string(*pErr, 0));
        setError(*pErr, errMsgBuf);
        fprintf(sslLog, errMsgBuf);
        fprintf(sslLog, "\n");
        fflush(sslLog);
        xppFree(errMsgBuf);
    }
}


/**
 * FUNCTION: setup_client_ctx
 *
 * Config ssl environment and setup context. 
 *
 * OUT:             pErr
 *                  error code of ssl
 * 
 * RETURN:          SSL_CTX*
 *                  new context
 */
static SSL_CTX *setup_client_ctx(int *pErr)
{
    SSL_CTX *ctx = 0;
    if (!pErr) return 0;
    *pErr = 0;

    ctx = SSL_CTX_new(SSLv23_method());
    while (ctx)
    {
        if (SSL_CTX_load_verify_locations(ctx, getConfig("CAFILE"), 0) != 1)
        {
            CHK_SSL(pErr, "load CA certificate fail");
            *pErr = 0;
            //break;
        }
        if (getConfig("CAFILE")[0] != '\0' && SSL_CTX_use_certificate_chain_file(ctx, getConfig("CERTFILE")) != 1)
        {
            CHK_SSL(pErr, "load certificate file fail");
            *pErr = 0;
            //break;
        }
        if (getConfig("CERTFILE")[0] != '\0' && SSL_CTX_use_PrivateKey_file(ctx, getConfig("CERTFILE"), SSL_FILETYPE_PEM) != 1)
        {
            CHK_SSL(pErr, "load private key fail");
            *pErr = 0;
            //break;
        }
        if (SSL_CTX_set_default_verify_paths(ctx) != 1)
        {
            CHK_SSL(pErr, "SSL_CTX_set_default_verify_paths");
            break;
        }
        if (getConfig("VERIFY_DEPTH")[0] != '\0')
        {
            SSL_CTX_set_verify_depth(ctx, atoi(getConfig("VERIFY_DEPTH")));
        }
        SSL_CTX_set_options(ctx, SSL_OP_ALL);
        if (getConfig("CIPHER_LIST")[0] != '\0' && SSL_CTX_set_cipher_list(ctx, getConfig("CIPHER_LIST")) != 1)
        {
            CHK_SSL(pErr, "SSL_CTX_set_cipher_list");
        }
        break;
    }
    if (ctx && *pErr)
    {
        SSL_CTX_free(ctx);
        ctx = 0;
    }
    return ctx;
}

/**
 * FUNCTION: post_connection_check
 *
 * Check certificate after connection opened. 
 *
 * IN:              pSSL
 *                  ssl handler
 * 
 * RETURN:          int
 *                  error code of certificate check. 
 */
static int post_connection_check(SSL *pSSL)
{
    int ret = SSL_get_verify_result(pSSL);
    return 0;
}

/****************************************************************/
/* Function: set up a sockaddr_in structure for a server socket */
/* The function returns 1 if the function succeeds.          */
/****************************************************************/

Bool_t getINServerAddr (CString_t pszPortAddress,  // i: port address (i.e. "80")
                           struct sockaddr_in *pSocketAddress) // o: socket structure
   {
   Bool_t rc = 1;
   int iPort = xppAtoi ((const char *) pszPortAddress);
   pSocketAddress->sin_addr.s_addr = INADDR_ANY;
   pSocketAddress->sin_family      = AF_INET;
   pSocketAddress->sin_port        = htons ((unsigned short) iPort);
   pSocketAddress->sin_addr.s_addr = INADDR_ANY;

   return rc;
   }


/****************************************************************/
/* Function: set up a sockaddr_in structure for a server socket */
/****************************************************************/

Bool_t getINSockAddr (StringBuffer_t pszIPAddress,// i: IP address (ie "192.168.5.0:80")
                      struct sockaddr_in *pSocketAddress) // o: socket structure
   {
   Bool_t rc = 1;
   Ptr_t pszPort;
   struct hostent * hent;
   unsigned long *pAddr;
   unsigned short port;

   pSocketAddress->sin_family = AF_INET;
   pszPort = strrchr ((char *) pszIPAddress, ':');
   if (pszPort == NULL)
      {
         port = xppAtoi (HTTP_PORT);
      }
   else
      {
      *pszPort = '\0';
      port = xppAtoi (pszPort+1);
      }
   pSocketAddress->sin_port = htons ( port ) ;

   hent = gethostbyname (pszIPAddress);
   if (hent == NULL) return 0;
   pAddr = (unsigned long *)hent->h_addr_list[0];

   pSocketAddress->sin_addr.s_addr = *pAddr; // inet_addr (pszIPAddress);

   if (pszPort != NULL)
      *pszPort = ':';

   return rc;
   }

Bool_t getINSockFirewallAddr (TcpFirewallInfoPtr_t pFirewallInfo ,// i: IP address (ie "192.168.5.0:80")
                      struct sockaddr_in *pSocketAddress) // o: socket structure
   {
   Bool_t rc = 1;
   struct hostent * hent;
   unsigned long *pAddr;

   pSocketAddress->sin_family = AF_INET;
   pSocketAddress->sin_port = htons((unsigned short) ((pFirewallInfo->serverPort > 0) ? pFirewallInfo->serverPort : xppAtoi (HTTP_PORT)));

   hent = gethostbyname( pFirewallInfo->serverName );
   if (hent == NULL) return 0;
   pAddr = (unsigned long *)hent->h_addr_list[0];

   pSocketAddress->sin_addr.s_addr = *pAddr; // inet_addr (pszIPAddress);

   return rc;
}

/*********************************************************************/
/* Function: determine the IP address of the communication partner   */
/* and write it into the specified string buffer (i.e."192.168.5.3") */
/*********************************************************************/

void getSenderAddress ( struct sockaddr_in *pSocket,  // i: socket structure
                       StringBuffer_t pchSenderAddress)    // o: IP address
   {
   /* int iPort = ntohs (pSocket->sin_port); */
   /* sprintf ((char *) pchSenderAddress, "%s:%d", inet_ntoa (pSocket->sin_addr), iPort); */
   xppStrcpy ((char *) pchSenderAddress, inet_ntoa (pSocket->sin_addr));
   return;
   }

TcpRc_t makeSocksConnection( SocketPtr_t pSocket, struct sockaddr_in *addr) {
    // TODO: ....
    int rc;
    int len;
                                        // Connect to the socks server
                                        //  an anonymous user id.
    char data[20];
    data[0] = 4;                      // Socks version 4
    data[1] = 1;                      // Socks command 1, CONNECT
                                      // Server connect port, high byte
    data[2] = (unsigned char)( (addr->sin_port & 0xff00) >> 8);
                                      // Server connect port, low byte
    data[3] = (unsigned char)( addr->sin_port & 0xff);
                                      // IP address of the external web server
    *((unsigned long *)(data+4)) = addr->sin_addr.s_addr;
    xppStrcpy((char *)&data[8], "anonymous");

                                        // send Socks connect request to Socks server
    rc = tcpSendData( pSocket, (unsigned char *)data, 18 );
    if( rc != TCP_RC_OK ) {
        return rc;
    }
    len = 8;
                                        // read reply from server
    rc = tcpReadData( pSocket, (unsigned char *)data, (BufferSizePtr_t)&len );
    if ( rc == TCP_RC_OK && data[1] != 90 ) {
        rc = TCP_RC_ECONNREFUSED;
    }

    return rc;
}


/*****************************************************************************/
/*                                                                           */
/*        Function: Open a TCP/IP connection (both client and server)        */
/*                                                                           */
/*****************************************************************************/

TcpRc_t tcpOpenConnection (CString_t pszPort,  // i: Port address (i.e."192.168.5.1:80")
                           SocketPtr_t pSocket,     // o: Pointer to generated socket
                           CString_t   pszOpenMode) // i: open Mode.
   {
       return tcpOpenConnectionEx( pszPort, pSocket, pszOpenMode, NULL );
   }

TcpRc_t tcpOpenConnectionEx (CString_t            pszPort,
                             SocketPtr_t          pSocket,
                             CString_t            pszOpenMode,
                             TcpFirewallInfoPtr_t pFirewallInfo ) {

   TcpRc_t rc = TCP_RC_OK;
   int iTcpRc;
   static Bool_t bFirstConnection = 1;
   SOCKET lSocket = -1L;
   struct sockaddr_in socket_address;

   /*********************************************************/
   /* Initialize TCP/IP, if this function is invoked first. */
   /*********************************************************/

   if (bFirstConnection == 1)
      {
      TCPINIT (rc);
      if (rc == TCP_RC_OK)
         bFirstConnection = 0;
      }

   /**************************/
   /* Obtain a TCP/IP socket */
   /**************************/

   *pSocket = (Socket_t) 0L;
   if (rc == TCP_RC_OK)
      {
      lSocket = socket(PF_INET, SOCK_STREAM, 0);
      rc = CHKERROR ((int)lSocket);
      *pSocket = (Socket_t) lSocket;
      }

   /***************************************************************/
   /* Server socket handling: set the socket to the listener mode */
   /***************************************************************/
   if ((pszOpenMode [0] == 's') || (pszOpenMode [0] == 'S'))
      {
      /*****************************************/
      /* Bind the socket to the specified port */
      /*****************************************/
      if (rc == TCP_RC_OK)
         {
         getINServerAddr ((const char *)pszPort, &socket_address);
         iTcpRc = bind (lSocket, (struct sockaddr *)&socket_address, sizeof (socket_address));
         rc = CHKERROR (iTcpRc);
         }

      /***************************************/
      /* Set the socket to the listener mode */
      /***************************************/
      if (rc == TCP_RC_OK)
         {
         iTcpRc = listen (lSocket, MAX_SOCKET_CONNECTIONS);
         rc = CHKERROR (iTcpRc);
         }
      }

   /***********************************************/
   /* Client socket handling: connect to the host */
   /***********************************************/

   else if ((pszOpenMode [0] == 'c') || (pszOpenMode [0] == 'C')) {
       struct sockaddr_in target_socket_address;
       if ( pFirewallInfo && pFirewallInfo->type == TCP_FIREWALL_PROXY ) {
           getINSockFirewallAddr( pFirewallInfo, &socket_address );
           if (!getINSockAddr ((StringBuffer_t) pszPort, &target_socket_address)) {
               rc = TCP_RC_ERROR;
           }
       } else {
           if (!getINSockAddr ((StringBuffer_t) pszPort, &socket_address)) {
               rc = TCP_RC_ERROR;
           }
       }
       if ( rc == TCP_RC_OK ) {
           iTcpRc = connect (lSocket, (struct sockaddr *)&socket_address, sizeof (socket_address));
           rc = CHKERROR (iTcpRc);
           if ( rc == TCP_RC_OK && pFirewallInfo && pFirewallInfo->type == TCP_FIREWALL_SOCKS ) {
               rc = makeSocksConnection( pSocket, &target_socket_address );
           }
       }
   } else
      rc = TCP_RC_ERROR;

   return rc;
}

/*****************************************************************************/
/*                                                                           */
/*        Function: Open a TCP/IP SSL connection (only for client)           */
/*                                                                           */
/*****************************************************************************/
TcpRc_t tcpOpenConnectionSSL (CString_t   pszPort,
                              SocketPtr_t pSocket,
                              SSL_CTX**   ppCtx,
                              SSL**       ppSSL,
                              CString_t   pszOpenMode,
                              TcpFirewallInfoPtr_t pFirewallInfo)
{
   TcpRc_t rc = TCP_RC_OK;
   int iTcpRc;
   static Bool_t bFirstConnection = 1;
   SOCKET lSocket = -1L;
   struct sockaddr_in socket_address;

   /*********************************************************/
   /* Initialize TCP/IP, if this function is invoked first. */
   /*********************************************************/

    if (bFirstConnection == 1)
    {
        TCPINIT (rc);
        if (rc == TCP_RC_OK)
        {
            SSL_library_init();
            SSL_load_error_strings();
            bFirstConnection = 0;
        }
    }

   *ppCtx = setup_client_ctx(&rc);

   /**************************/
   /* Obtain a TCP/IP socket */
   /**************************/

   *pSocket = (Socket_t) 0L;
   if (rc == TCP_RC_OK)
      {
      lSocket = socket(PF_INET, SOCK_STREAM, 0);
      rc = CHKERROR ((int)lSocket);
      *pSocket = (Socket_t) lSocket;
      }

   /***************************************************************/
   /* Server socket handling: set the socket to the listener mode */
   /***************************************************************/
   if ((pszOpenMode [0] == 's') || (pszOpenMode [0] == 'S'))
      {
      /*****************************************/
      /* Bind the socket to the specified port */
      /*****************************************/
      if (rc == TCP_RC_OK)
         {
         getINServerAddr ((const char *)pszPort, &socket_address);
         iTcpRc = bind (lSocket, (struct sockaddr *)&socket_address, sizeof (socket_address));
         rc = CHKERROR (iTcpRc);
         }

      /***************************************/
      /* Set the socket to the listener mode */
      /***************************************/
      if (rc == TCP_RC_OK)
         {
         iTcpRc = listen (lSocket, MAX_SOCKET_CONNECTIONS);
         rc = CHKERROR (iTcpRc);
         }
      }

   /***********************************************/
   /* Client socket handling: connect to the host */
   /***********************************************/

   else if ((pszOpenMode [0] == 'c') || (pszOpenMode [0] == 'C')) {
       struct sockaddr_in target_socket_address;
       if ( pFirewallInfo && pFirewallInfo->type == TCP_FIREWALL_PROXY ) {
           getINSockFirewallAddr( pFirewallInfo, &socket_address );
           if (!getINSockAddr ((StringBuffer_t) pszPort, &target_socket_address)) {
               rc = TCP_RC_ERROR;
           }
       } else {
           if (!getINSockAddr ((StringBuffer_t) pszPort, &socket_address)) {
               rc = TCP_RC_ERROR;
           }
       }
       if ( rc == TCP_RC_OK ) {
           iTcpRc = connect (lSocket, (struct sockaddr *)&socket_address, sizeof (socket_address));
           rc = CHKERROR (iTcpRc);
           if ( rc == TCP_RC_OK && pFirewallInfo && pFirewallInfo->type == TCP_FIREWALL_SOCKS ) {
               rc = makeSocksConnection( pSocket, &target_socket_address );
           }
       }
       if ( rc == TCP_RC_OK ) {
           *ppSSL = SSL_new(*ppCtx);
           if (*ppSSL) {
               if (!SSL_set_fd(*ppSSL, lSocket)) {
                   CHK_SSL (&rc, "SSL_set_fd");
               }
               else {
                   int ret = SSL_connect (*ppSSL);
                   if (ret < 0)
                   {
                       CHK_SSL (&rc, "SSL_connect");
                   }
                   else if (!ret)
                   {
                       rc = TCP_RC_ERROR;
                   }
                   else
                       rc = post_connection_check(*ppSSL);
               }
           }
       }
   } else
      rc = TCP_RC_ERROR;

   return rc;
}



/*****************************************************************************/
/*                                                                           */
/*             Function: Close the TCP/IP connection                         */
/*                                                                           */
/*****************************************************************************/

TcpRc_t tcpCloseConnection (SocketPtr_t pSocket) // i: socket to be closed
   {
   TcpRc_t rc = TCP_RC_OK;
   int iTcpRc;
   SOCKET lSocket = pSocket ? (SOCKET) *pSocket : -1L;

   if (lSocket == -1L)
      return TCP_RC_ERROR;

   /********************/
   /* Close the socket */
   /********************/
   if (rc == TCP_RC_OK)
      {
      iTcpRc = closesocket (lSocket);
      rc = CHKERROR (iTcpRc);
      }

   if (pSocket) *pSocket = -1L; // reset the socket
   return rc;
   }

/*****************************************************************************/
/*                                                                           */
/*             Function: Close the TCP/IP SSL connection                     */
/*                                                                           */
/*****************************************************************************/
TcpRc_t tcpCloseConnectionSSL (SocketPtr_t pSocket,
                               SSL_CTX*    pCtx,
                               SSL*        pSSL)
{
    TcpRc_t rc = TCP_RC_OK;
    int iTcpRc;
    SOCKET lSocket = pSocket ? (SOCKET) *pSocket : -1L;

    if (lSocket == -1L)
        return TCP_RC_ERROR;

    /********************/
    /* Close the socket */
    /********************/
    if (rc == TCP_RC_OK)
    {
        if (pSSL)
            SSL_shutdown(pSSL);
        iTcpRc = closesocket (lSocket);
        rc = CHKERROR (iTcpRc);
    }

    if (pSocket) *pSocket = -1L; // reset the socket
	if (pSSL) SSL_free (pSSL);
	if (pCtx) SSL_CTX_free (pCtx);
    return rc;
}


/*****************************************************************************/
/*                                                                           */
/*    Function: Wait until a client connected to this server socket.         */
/*                                                                           */
/*****************************************************************************/

TcpRc_t tcpWaitforConnections (SocketPtr_t    pSocket,          // i: server socket
                               SocketPtr_t    pNewSocket,       // o: Connection socket
                               StringBuffer_t pchSenderAddress) // o: Client IP address
   {
   TcpRc_t rc = TCP_RC_OK;
   struct sockaddr_in socket_address;
   SOCKET lSocket = pSocket ? (SOCKET) *pSocket : -1L;

   if ((lSocket == -1L) || (lSocket == 0L))
      return TCP_RC_ERROR;

   else
      {
      /**************************************/
      /* Wait for a client to connect to me */
      /**************************************/
      int iSocketAddressLength = sizeof (socket_address);


	 /* SCTSTK - 26/03/2002 */
	 {
		  extern int sctsGetTerminate();
		  struct timeval timeout;
		  fd_set sockset;
		  while (1)
		  {
			timeout.tv_sec=0;
			timeout.tv_usec=500;
			sockset.fd_count=1;
			sockset.fd_array[0]=lSocket;
			if (select(0,&sockset,0,0,&timeout)) break;
			if (sctsGetTerminate()) 
				return TCP_RC_ETIMEDOUT ;
		  }
	 }

	  
	  *pNewSocket = (long) accept (lSocket, (struct sockaddr *)&socket_address, &iSocketAddressLength);
	  rc = CHKERROR (*pNewSocket);
      if (rc == TCP_RC_OK)
         {
         getSenderAddress (&socket_address, pchSenderAddress);
         }
      else
         {
         // avoid follow-up problems and set output variables to a default value
         *pNewSocket = (long) 0;
         pchSenderAddress [0] = '\0';
         }
      }
   return rc;
   }

/*****************************************************************************/
/*                                                                           */
/*    Function: receive a block of data from the communication partner.      */
/*                                                                           */
/*****************************************************************************/

TcpRc_t tcpReadData (SocketPtr_t     pSocket,   // i: Socket
                     DataBuffer_t    pbBuffer,  // i: Data buffer
                     BufferSizePtr_t pcbBufferSize) // io: size of data buffer / # of bytes reveived
   {
   TcpRc_t rc = TCP_RC_OK;
   int iReceived;
   SOCKET lSocket = pSocket ? (SOCKET) *pSocket : -1L;
   /* SCTSTK - 16/04/2002 */
   extern void sctsTransportLogData(char *data,long size,char sent);

   if (lSocket == -1L)
      return TCP_RC_ERROR;

   /************************/
   /* Receive a data block */
   /************************/
   iReceived = recv (lSocket, (char *)pbBuffer, (int) *pcbBufferSize, 0);

   /************************************************/
   /* 0-byte packages indicate that the connection */
   /* was closed by the communication partner      */
   /************************************************/
   
   if (iReceived == 0)
      {
      pbBuffer [0] = '\0';
      *pcbBufferSize = 0L;
      rc = TCP_RC_EOF; // end-of-transmission
      }
   else if (iReceived < 0)
      {
      /*********************/
      /* An error occurred */
      /*********************/
      rc = CHKERROR (iReceived);
      }
   else
      {
      /* SCTSTK - 16/04/2002 */
      sctsTransportLogData((char *)pbBuffer,iReceived,0);
      *pcbBufferSize = (BufferSize_t) iReceived; // return the # of bytes received.
      rc = TCP_RC_OK;
      }

   return rc;
   }

/**************************************************************************************/
/*                                                                                    */
/*    Function: receive a block of data from the communication partner over SSL.      */
/*                                                                                    */
/**************************************************************************************/

TcpRc_t tcpReadDataSSL (SocketPtr_t     pSocket,
                        SSL*            pSSL,
                        DataBuffer_t    pbBuffer,
                        BufferSizePtr_t pcbBufferSize)
{
    TcpRc_t rc = TCP_RC_OK;
    int iReceived;
    SOCKET lSocket = pSocket ? (SOCKET) *pSocket : -1L;
    /* SCTSTK - 16/04/2002 */
    extern void sctsTransportLogData(char *data,long size,char sent);

    if (lSocket == -1L || !pSSL)
        return TCP_RC_ERROR;

    /************************/
    /* Receive a data block */
    /************************/
    iReceived = SSL_read (pSSL, (char *)pbBuffer, (int) *pcbBufferSize);

    /************************************************/
    /* 0-byte packages indicate that the connection */
    /* was closed by the communication partner      */
    /************************************************/

    if (iReceived == 0)
    {
        pbBuffer [0] = '\0';
        *pcbBufferSize = 0L;
        rc = TCP_RC_EOF; // end-of-transmission
    }
    else if (iReceived < 0)
    {
        /*********************/
        /* An error occurred */
        /*********************/
        CHK_SSL (&rc, "SSL_read");
    }
    else
    {
        /* SCTSTK - 16/04/2002 */
        sctsTransportLogData((char *)pbBuffer,iReceived,0);
        *pcbBufferSize = (BufferSize_t) iReceived; // return the # of bytes received.
        rc = TCP_RC_OK;
    }

    return rc;
}


/*****************************************************************************/
/*                                                                           */
/*        Function: Send a block of data to the communication partner.       */
/*                                                                           */
/*****************************************************************************/

TcpRc_t tcpSendData (SocketPtr_t        pSocket,      // i: socket
                     const DataBuffer_t pbBuffer,     // i: data buffer
                     BufferSize_t       cbBufferSize) // i: size of data buffer
   {
   TcpRc_t rc = TCP_RC_OK;
   int iTcpRc;
   SOCKET lSocket = pSocket ? (SOCKET) *pSocket : -1L;
   /* SCTSTK - 16/04/2002 */
   extern void sctsTransportLogData(char *data,long size,char sent);
   
   if (lSocket == -1L)
      return TCP_RC_ERROR; // invalid socket

   iTcpRc = send (lSocket,  (char *)pbBuffer, (int) cbBufferSize, 0);
   /* SCTSTK - 16/04/2002 */
   if (iTcpRc>0) sctsTransportLogData((char *)pbBuffer,iTcpRc,1);
   rc = CHKERROR (iTcpRc);
   if ((iTcpRc > 0) && (iTcpRc != (int) cbBufferSize))
       rc = TCP_RC_ERROR;
   return rc;
   }

/*********************************************************************************/
/*                                                                               */
/*    Function: Send a block of data to the communication partner over SSL.      */
/*                                                                               */
/*********************************************************************************/
TcpRc_t tcpSendDataSSL (SocketPtr_t        pSocket,
                        SSL*               pSSL,
                        const DataBuffer_t pbBuffer,
                        BufferSize_t       cbBufferSize)
{
    TcpRc_t rc = TCP_RC_OK;
    int iTcpRc;
    SOCKET lSocket = pSocket ? (SOCKET) *pSocket : -1L;
    /* SCTSTK - 16/04/2002 */
    extern void sctsTransportLogData(char *data,long size,char sent);

    if (lSocket == -1L || !pSSL)
        return TCP_RC_ERROR; // invalid socket

    iTcpRc = SSL_write (pSSL,  (char *)pbBuffer, (int) cbBufferSize);
    /* SCTSTK - 16/04/2002 */
    if (iTcpRc>0) sctsTransportLogData((char *)pbBuffer,iTcpRc,1);
    if (iTcpRc <= 0) CHK_SSL (&rc, "SSL_write");
    if ((iTcpRc > 0) && (iTcpRc != (int) cbBufferSize))
        rc = TCP_RC_ERROR;
    return rc;
}

Bool_t getSockIP(SocketPtr_t skt,char** pchAddr)
{
	SOCKADDR_IN sockAddr;
	int nLen =  sizeof(SOCKADDR);
	getsockname(*skt,(SOCKADDR*)&sockAddr,&nLen);
	if(nLen < sizeof(SOCKADDR))
		return 0;
	*pchAddr = inet_ntoa(sockAddr.sin_addr);
	return 1;
		

}