//**********************************************************************;
// Copyright (c) 2015, 2016, 2017 Intel Corporation
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. 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.
//
// 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 COPYRIGHT HOLDER 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 <stdio.h>
#include <stdlib.h>   // Needed for _wtoi

#include "sapi/tpm20.h"
#include "tcti/tcti_socket.h"
#include "sysapi_util.h"
#include "common/debug.h"
#include "commonchecks.h"
#include "logging.h"
#include "sockets.h"

#ifdef __cplusplus
extern "C" {
#endif

static TSS2_RC tctiRecvBytes( TSS2_TCTI_CONTEXT *tctiContext, SOCKET sock, unsigned char *data, int len )
{
    TSS2_RC result = 0;
    result = recvBytes( sock, data, len);
    if ( (INT32)result == SOCKET_ERROR) {
        TCTI_LOG( tctiContext, NO_PREFIX, "In recvBytes, recv failed (socket: 0x%x) with error: %d\n", sock, WSAGetLastError() );
        return TSS2_TCTI_RC_IO_ERROR;
    }
#ifdef DEBUG_SOCKETS
    TCTI_LOG( tctiContext, NO_PREFIX, "Receive Bytes from socket #0x%x: \n", sock );
    TCTI_LOG_BUFFER( tctiContext, NO_PREFIX, data, len );
#endif

    return TSS2_RC_SUCCESS;
}

static TSS2_RC tctiSendBytes( TSS2_TCTI_CONTEXT *tctiContext, SOCKET sock, const unsigned char *data, int len )
{
    TSS2_RC ret = TSS2_RC_SUCCESS;

#ifdef DEBUG_SOCKETS
    TCTI_LOG( tctiContext, NO_PREFIX, "Send Bytes to socket #0x%x: \n", sock );
    TCTI_LOG_BUFFER( tctiContext, NO_PREFIX, (UINT8 *)data, len );
#endif

    ret = sendBytes( sock, data, len);
    if (ret != TSS2_RC_SUCCESS)
        TCTI_LOG( tctiContext, NO_PREFIX, "In recvBytes, recv failed (socket: 0x%x) with error: %d\n", sock, WSAGetLastError() );
    return ret;
}

TSS2_RC SendSessionEndSocketTcti(
    TSS2_TCTI_CONTEXT *tctiContext,       /* in */
    UINT8 tpmCmdServer )
{
    UINT32 tpmSendCommand = TPM_SESSION_END;  // Value for "send command" to MS simulator.
    SOCKET sock;
    TSS2_RC rval = TSS2_RC_SUCCESS;

    if( tpmCmdServer )
    {
        sock = TCTI_CONTEXT_INTEL->tpmSock;
    }
    else
    {
        sock = TCTI_CONTEXT_INTEL->otherSock;
    }

    tpmSendCommand = CHANGE_ENDIAN_DWORD(tpmSendCommand);
    rval = tctiSendBytes( tctiContext, sock, (char unsigned *)&tpmSendCommand, 4 );

    return( rval );
}

TSS2_RC SocketSendTpmCommand(
    TSS2_TCTI_CONTEXT *tctiContext,       /* in */
    size_t             command_size,      /* in */
    uint8_t           *command_buffer     /* in */
    )
{
    UINT32 tpmSendCommand = MS_SIM_TPM_SEND_COMMAND;  // Value for "send command" to MS simulator.
    UINT32 cnt = 0;
    UINT8 locality;
    TSS2_RC rval = TSS2_RC_SUCCESS;

#ifdef DEBUG
    UINT32 commandCode;
    printf_type rmPrefix;
#endif

    rval = CommonSendChecks( tctiContext, command_buffer );
    if( rval != TSS2_RC_SUCCESS )
    {
        goto returnFromSocketSendTpmCommand;
    }

#ifdef DEBUG
    if( ( ( TSS2_TCTI_CONTEXT_INTEL *)tctiContext )->status.rmDebugPrefix == 1 )
        rmPrefix = RM_PREFIX;
    else
        rmPrefix = NO_PREFIX;

    if( ((TSS2_TCTI_CONTEXT_INTEL *)tctiContext )->status.debugMsgEnabled == 1 )
    {
        TCTI_LOG( tctiContext, rmPrefix, "" );
		commandCode = CHANGE_ENDIAN_DWORD( ( (TPM20_Header_In *)command_buffer )->commandCode );
#ifdef DEBUG_SOCKETS
        TCTI_LOG( tctiContext, NO_PREFIX, "Command sent on socket #0x%x: %s\n", TCTI_CONTEXT_INTEL->tpmSock, strTpmCommandCode( commandCode ) );
#else
        TCTI_LOG( tctiContext, NO_PREFIX, "Cmd sent: %s\n", strTpmCommandCode( commandCode ) );
#endif
    }
#endif

    // Send TPM_SEND_COMMAND
    tpmSendCommand = CHANGE_ENDIAN_DWORD(tpmSendCommand);
    rval = tctiSendBytes( tctiContext, TCTI_CONTEXT_INTEL->tpmSock, (unsigned char *)&tpmSendCommand, 4 );
    if( rval != TSS2_RC_SUCCESS )
        goto returnFromSocketSendTpmCommand;

    // Send the locality
    locality = (UINT8)( (TSS2_TCTI_CONTEXT_INTEL *)tctiContext)->status.locality;
    rval = tctiSendBytes( tctiContext, TCTI_CONTEXT_INTEL->tpmSock, (unsigned char *)&locality, 1 );
    if( rval != TSS2_RC_SUCCESS )
        goto returnFromSocketSendTpmCommand;

#ifdef DEBUG
    if( ((TSS2_TCTI_CONTEXT_INTEL *)tctiContext )->status.debugMsgEnabled == 1 )
    {
        TCTI_LOG( tctiContext, rmPrefix, "Locality = %d", ( (TSS2_TCTI_CONTEXT_INTEL *)tctiContext)->status.locality );
    }
#endif

    // Send number of bytes.
    cnt = CHANGE_ENDIAN_DWORD(command_size);
    rval = tctiSendBytes( tctiContext, TCTI_CONTEXT_INTEL->tpmSock, (unsigned char *)&cnt, 4 );
    if( rval != TSS2_RC_SUCCESS )
        goto returnFromSocketSendTpmCommand;

    // Send the TPM command buffer
    rval = tctiSendBytes( tctiContext, TCTI_CONTEXT_INTEL->tpmSock, (unsigned char *)command_buffer, command_size );
    if( rval != TSS2_RC_SUCCESS )
        goto returnFromSocketSendTpmCommand;

#ifdef DEBUG
    if( ((TSS2_TCTI_CONTEXT_INTEL *)tctiContext )->status.debugMsgEnabled == 1 )
    {
        DEBUG_PRINT_BUFFER( rmPrefix, command_buffer, command_size );
    }
#endif
    ((TSS2_TCTI_CONTEXT_INTEL *)tctiContext)->status.commandSent = 1;

returnFromSocketSendTpmCommand:

    if( rval == TSS2_RC_SUCCESS )
    {
        ((TSS2_TCTI_CONTEXT_INTEL *)tctiContext)->previousStage = TCTI_STAGE_SEND_COMMAND;
        ((TSS2_TCTI_CONTEXT_INTEL *)tctiContext)->status.tagReceived = 0;
        ((TSS2_TCTI_CONTEXT_INTEL *)tctiContext)->status.responseSizeReceived = 0;
        ((TSS2_TCTI_CONTEXT_INTEL *)tctiContext)->status.protocolResponseSizeReceived = 0;
    }

    return rval;
}

TSS2_RC SocketCancel(
    TSS2_TCTI_CONTEXT *tctiContext
    )
{
    TSS2_RC rval = TSS2_RC_SUCCESS;

    if( tctiContext == 0 )
    {
        rval = TSS2_TCTI_RC_BAD_REFERENCE;
    }
    else if( ((TSS2_TCTI_CONTEXT_INTEL *)tctiContext)->status.commandSent != 1 )
    {
        rval = TSS2_TCTI_RC_BAD_SEQUENCE;
    }
    else
    {
        rval = (TSS2_RC)PlatformCommand( tctiContext, MS_SIM_CANCEL_ON );
#if 0
        if( rval == TSS2_RC_SUCCESS )
        {
            rval = (TSS2_RC)PlatformCommand( tctiContext, MS_SIM_CANCEL_OFF );
            if( ((TSS2_TCTI_CONTEXT_INTEL *)tctiContext )->status.debugMsgLevel == TSS2_TCTI_DEBUG_MSG_ENABLED )
            {
                TCTI_LOG( tctiContext, NO_PREFIX, "%s sent cancel ON command:\n", interfaceName );
            }
        }
#endif
    }

    return rval;
}

TSS2_RC SocketSetLocality(
    TSS2_TCTI_CONTEXT *tctiContext,       /* in */
    uint8_t           locality     /* in */
    )
{
    TSS2_RC rval = TSS2_RC_SUCCESS;

    if( tctiContext == 0 )
    {
        rval = TSS2_TCTI_RC_BAD_REFERENCE;
    }
    else if( ( (TSS2_TCTI_CONTEXT_INTEL *)tctiContext)->status.locality != locality )
    {
        if ( ( (TSS2_TCTI_CONTEXT_INTEL *)tctiContext)->status.commandSent == 1 )
        {
            rval = TSS2_TCTI_RC_BAD_SEQUENCE;
        }
        else
        {
            ((TSS2_TCTI_CONTEXT_INTEL *)tctiContext)->status.locality = locality;
        }
    }

    return rval;
}

TSS2_RC SocketGetPollHandles(
    TSS2_TCTI_CONTEXT     *tctiContext,
    TSS2_TCTI_POLL_HANDLE *handles,
    size_t                *num_handles)
{
    return TSS2_TCTI_RC_NOT_IMPLEMENTED;
}

void SocketFinalize(
    TSS2_TCTI_CONTEXT *tctiContext       /* in */
    )
{
    if( tctiContext != NULL )
    {
        // Send session end messages to servers.
        SendSessionEndSocketTcti( tctiContext, 1 );
        SendSessionEndSocketTcti( tctiContext, 0 );

        CloseSockets( TCTI_CONTEXT_INTEL->otherSock, TCTI_CONTEXT_INTEL->tpmSock );
    }
}

TSS2_RC SocketReceiveTpmResponse(
    TSS2_TCTI_CONTEXT *tctiContext,     /* in */
    size_t          *response_size,     /* out */
    unsigned char   *response_buffer,    /* in */
    int32_t         timeout
    )
{
    UINT32 trash;
    TSS2_RC rval = TSS2_RC_SUCCESS;
    fd_set readFds;
    struct timeval tv, *tvPtr;
    int32_t timeoutMsecs = timeout % 1000;
    int iResult;
    unsigned char responseSizeDelta = 0;
    printf_type rmPrefix;

    rval = CommonReceiveChecks( tctiContext, response_size, response_buffer );
    if( rval != TSS2_RC_SUCCESS )
    {
        goto retSocketReceiveTpmResponse;
    }

    if( ( ( TSS2_TCTI_CONTEXT_INTEL *)tctiContext )->status.rmDebugPrefix == 1 )
        rmPrefix = RM_PREFIX;
    else
        rmPrefix = NO_PREFIX;

    if( timeout == TSS2_TCTI_TIMEOUT_BLOCK )
    {
        tvPtr = 0;
    }
    else
    {
        tv.tv_sec = timeout / 1000;
        tv.tv_usec = timeoutMsecs * 1000;
        tvPtr = &tv;
    }

    FD_ZERO( &readFds );
    FD_SET( TCTI_CONTEXT_INTEL->tpmSock, &readFds );

    iResult = select( TCTI_CONTEXT_INTEL->tpmSock+1, &readFds, 0, 0, tvPtr );
    if( iResult == 0 )
    {
        TCTI_LOG( tctiContext, rmPrefix, "select failed due to timeout, socket #: 0x%x\n", TCTI_CONTEXT_INTEL->tpmSock );
        rval = TSS2_TCTI_RC_TRY_AGAIN;
        goto retSocketReceiveTpmResponse;
    }
    else if( iResult == SOCKET_ERROR )
    {
        TCTI_LOG( tctiContext, rmPrefix, "select failed with socket error: %d\n", WSAGetLastError() );
        rval = TSS2_TCTI_RC_IO_ERROR;
        goto retSocketReceiveTpmResponse;
    }
    else if ( iResult != 1 )
    {
        TCTI_LOG( tctiContext, rmPrefix, "select failed, read the wrong # of bytes: %d\n", iResult );
        rval = TSS2_TCTI_RC_IO_ERROR;
        goto retSocketReceiveTpmResponse;
    }

    if( ((TSS2_TCTI_CONTEXT_INTEL *)tctiContext)->status.protocolResponseSizeReceived != 1 )
    {
        // Receive the size of the response.
        rval = tctiRecvBytes( tctiContext, TCTI_CONTEXT_INTEL->tpmSock, (unsigned char *)& (((TSS2_TCTI_CONTEXT_INTEL *)tctiContext)->responseSize ), 4 );
        if( rval != TSS2_RC_SUCCESS )
            goto retSocketReceiveTpmResponse;

        ((TSS2_TCTI_CONTEXT_INTEL *)tctiContext)->responseSize = CHANGE_ENDIAN_DWORD( ((TSS2_TCTI_CONTEXT_INTEL *)tctiContext)->responseSize );
        ((TSS2_TCTI_CONTEXT_INTEL *)tctiContext)->status.protocolResponseSizeReceived = 1;
    }

    if( response_buffer == NULL )
    {
        // In this case, just return the size
        *response_size = ((TSS2_TCTI_CONTEXT_INTEL *)tctiContext)->responseSize;
        ((TSS2_TCTI_CONTEXT_INTEL *)tctiContext)->status.protocolResponseSizeReceived = 1;
        goto retSocketReceiveTpmResponse;
    }

    if( *response_size < ((TSS2_TCTI_CONTEXT_INTEL *)tctiContext)->responseSize )
    {
        *response_size = ((TSS2_TCTI_CONTEXT_INTEL *)tctiContext)->responseSize;
        rval = TSS2_TCTI_RC_INSUFFICIENT_BUFFER;


        // If possible, receive tag from TPM.
        if( *response_size >= sizeof( TPM_ST ) && ((TSS2_TCTI_CONTEXT_INTEL *)tctiContext)->status.tagReceived == 0 )
        {
            if( TSS2_RC_SUCCESS != tctiRecvBytes( tctiContext, TCTI_CONTEXT_INTEL->tpmSock, (unsigned char *)&( ( (TSS2_TCTI_CONTEXT_INTEL *)tctiContext )->tag ), 2 ) )
            {
                goto retSocketReceiveTpmResponse;
            }
            else
            {
                ((TSS2_TCTI_CONTEXT_INTEL *)tctiContext)->status.tagReceived = 1;
            }
        }

        // If possible, receive response size from TPM
        if( *response_size >= ( sizeof( TPM_ST ) + sizeof( TPM_RC ) ) && ((TSS2_TCTI_CONTEXT_INTEL *)tctiContext)->status.responseSizeReceived == 0 )
        {
            if( TSS2_RC_SUCCESS != tctiRecvBytes( tctiContext, TCTI_CONTEXT_INTEL->tpmSock, (unsigned char *)&( ( (TSS2_TCTI_CONTEXT_INTEL *)tctiContext )->responseSize ), 4 ) )
            {
                goto retSocketReceiveTpmResponse;
            }
            else
            {
                ((TSS2_TCTI_CONTEXT_INTEL *)tctiContext)->responseSize = CHANGE_ENDIAN_DWORD( ((TSS2_TCTI_CONTEXT_INTEL *)tctiContext)->responseSize );
                ((TSS2_TCTI_CONTEXT_INTEL *)tctiContext)->status.responseSizeReceived = 1;
            }
        }
    }
    else
    {
        if( ((TSS2_TCTI_CONTEXT_INTEL *)tctiContext )->status.debugMsgEnabled == 1 &&
                ((TSS2_TCTI_CONTEXT_INTEL *)tctiContext)->responseSize > 0 )
        {
#ifdef DEBUG
            TCTI_LOG( tctiContext, rmPrefix, "Response Received: " );
#endif
#ifdef DEBUG_SOCKETS
            TCTI_LOG( tctiContext, rmPrefix, "from socket #0x%x:\n", TCTI_CONTEXT_INTEL->tpmSock );
#endif
        }

        if( ((TSS2_TCTI_CONTEXT_INTEL *)tctiContext)->status.tagReceived == 1 )
        {
            *(TPM_ST *)response_buffer = ( (TSS2_TCTI_CONTEXT_INTEL *)tctiContext )->tag;
            responseSizeDelta += sizeof( TPM_ST );
            response_buffer += sizeof( TPM_ST );
        }

        if( ((TSS2_TCTI_CONTEXT_INTEL *)tctiContext)->status.responseSizeReceived == 1 )
        {
            *(TPM_RC *)response_buffer = CHANGE_ENDIAN_DWORD( ( (TSS2_TCTI_CONTEXT_INTEL *)tctiContext )->responseSize );
            responseSizeDelta += sizeof( TPM_RC );
            response_buffer += sizeof( TPM_RC );
        }

        // Receive the TPM response.
        rval = tctiRecvBytes( tctiContext, TCTI_CONTEXT_INTEL->tpmSock, (unsigned char *)response_buffer, ((TSS2_TCTI_CONTEXT_INTEL *)tctiContext)->responseSize - responseSizeDelta );
        if( rval != TSS2_RC_SUCCESS )
            goto retSocketReceiveTpmResponse;

#ifdef DEBUG
        if( ((TSS2_TCTI_CONTEXT_INTEL *)tctiContext )->status.debugMsgEnabled == 1 )
        {
            DEBUG_PRINT_BUFFER( rmPrefix, response_buffer, ((TSS2_TCTI_CONTEXT_INTEL *)tctiContext)->responseSize );
        }
#endif

        // Receive the appended four bytes of 0's
        rval = tctiRecvBytes( tctiContext, TCTI_CONTEXT_INTEL->tpmSock, (unsigned char *)&trash, 4 );
        if( rval != TSS2_RC_SUCCESS )
            goto retSocketReceiveTpmResponse;
    }

    if( ((TSS2_TCTI_CONTEXT_INTEL *)tctiContext)->responseSize < *response_size )
    {
        *response_size = ((TSS2_TCTI_CONTEXT_INTEL *)tctiContext)->responseSize;
    }

    ((TSS2_TCTI_CONTEXT_INTEL *)tctiContext)->status.commandSent = 0;

    // Turn cancel off.
    if( rval == TSS2_RC_SUCCESS )
    {
        rval = (TSS2_RC)PlatformCommand( tctiContext, MS_SIM_CANCEL_OFF );
    }
    else
    {
        // Ignore return value so earlier error code is preserved.
        PlatformCommand( tctiContext, MS_SIM_CANCEL_OFF );
    }

    if( ((TSS2_TCTI_CONTEXT_INTEL *)tctiContext )->status.debugMsgEnabled== 1 )
    {
//        TCTI_LOG( tctiContext, NO_PREFIX,  "%s sent cancel OFF command:\n", interfaceName );
    }

retSocketReceiveTpmResponse:
    if( rval == TSS2_RC_SUCCESS &&
		response_buffer != NULL )
    {
        ((TSS2_TCTI_CONTEXT_INTEL *)tctiContext)->previousStage = TCTI_STAGE_RECEIVE_RESPONSE;
    }

    return rval;
}

#ifdef __cplusplus
}
#endif

#define HOSTNAME_LENGTH 200
#define PORT_LENGTH 4

/**
 * This function sends the Microsoft simulator the MS_SIM_POWER_ON and
 * MS_SIM_NV_ON commands using the PlatformCommand mechanism. Without
 * these the simulator will respond with zero sized buffer which causes
 * the TSS to freak out. Sending this command more than once is harmelss
 * so it's advisable to call this function as part of the TCTI context
 * initialization just to be sure.
 *
 * NOTE: The caller will still need to call Tss2_Sys_Startup. If they
 * don't, an error will be returned from each call till they do but
 * the error will at least be meaningful (TPM_RC_INITIALIZE).
 */
static TSS2_RC InitializeMsTpm2Simulator(
    TSS2_TCTI_CONTEXT *tctiContext
    )
{
    TSS2_TCTI_CONTEXT_INTEL *intel_tctiCtx;
    TSS2_RC rval;

    intel_tctiCtx = (TSS2_TCTI_CONTEXT_INTEL*)tctiContext;
    rval = PlatformCommand( tctiContext ,MS_SIM_POWER_ON );
    if( rval != TSS2_RC_SUCCESS ) {
        CloseSockets( intel_tctiCtx->otherSock, intel_tctiCtx->tpmSock );
        return rval;
    }
    rval = PlatformCommand( tctiContext, MS_SIM_NV_ON );
    if( rval != TSS2_RC_SUCCESS )
        CloseSockets( intel_tctiCtx->otherSock, intel_tctiCtx->tpmSock );

    return rval;
}

TSS2_RC InitSocketTcti (
    TSS2_TCTI_CONTEXT *tctiContext, // OUT
    size_t *contextSize,            // IN/OUT
    const TCTI_SOCKET_CONF *conf,              // IN
    const uint8_t serverSockets
    )
{
    TSS2_RC rval = TSS2_RC_SUCCESS;
    SOCKET otherSock;
    SOCKET tpmSock;

    if( tctiContext == NULL && contextSize == NULL )
    {
        return TSS2_TCTI_RC_BAD_VALUE;
    }
    else if( tctiContext == NULL )
    {
        *contextSize = sizeof( TSS2_TCTI_CONTEXT_INTEL );
        return TSS2_RC_SUCCESS;
    }
    else if( conf == NULL )
    {
        return TSS2_TCTI_RC_BAD_VALUE;
    }
    else
    {
        // Init TCTI context.
        TSS2_TCTI_MAGIC( tctiContext ) = TCTI_MAGIC;
        TSS2_TCTI_VERSION( tctiContext ) = TCTI_VERSION;
        TSS2_TCTI_TRANSMIT( tctiContext ) = SocketSendTpmCommand;
        TSS2_TCTI_RECEIVE( tctiContext ) = SocketReceiveTpmResponse;
        TSS2_TCTI_FINALIZE( tctiContext ) = SocketFinalize;
        TSS2_TCTI_CANCEL( tctiContext ) = SocketCancel;
        TSS2_TCTI_GET_POLL_HANDLES( tctiContext ) = SocketGetPollHandles;
        TSS2_TCTI_SET_LOCALITY( tctiContext ) = SocketSetLocality;
        ((TSS2_TCTI_CONTEXT_INTEL *)tctiContext)->status.debugMsgEnabled = 0;
        ((TSS2_TCTI_CONTEXT_INTEL *)tctiContext)->status.locality = 3;
        ((TSS2_TCTI_CONTEXT_INTEL *)tctiContext)->status.commandSent = 0;
        ((TSS2_TCTI_CONTEXT_INTEL *)tctiContext)->status.rmDebugPrefix = 0;
        ((TSS2_TCTI_CONTEXT_INTEL *)tctiContext)->status.tagReceived = 0;
        ((TSS2_TCTI_CONTEXT_INTEL *)tctiContext)->status.responseSizeReceived = 0;
        ((TSS2_TCTI_CONTEXT_INTEL *)tctiContext)->status.protocolResponseSizeReceived = 0;
        ((TSS2_TCTI_CONTEXT_INTEL *)tctiContext)->currentTctiContext = 0;
        ((TSS2_TCTI_CONTEXT_INTEL *)tctiContext)->previousStage = TCTI_STAGE_INITIALIZE;
        TCTI_LOG_CALLBACK( tctiContext ) = conf->logCallback;
        TCTI_LOG_BUFFER_CALLBACK( tctiContext ) = conf->logBufferCallback;
        TCTI_LOG_DATA( tctiContext ) = conf->logData;

        rval = (TSS2_RC) InitSockets( conf->hostname, conf->port, &otherSock, &tpmSock, TCTI_LOG_CALLBACK( tctiContext ), TCTI_LOG_DATA( tctiContext) );
        if( rval == TSS2_RC_SUCCESS )
        {
            ((TSS2_TCTI_CONTEXT_INTEL *)tctiContext)->otherSock = otherSock;
            ((TSS2_TCTI_CONTEXT_INTEL *)tctiContext)->tpmSock = tpmSock;
            rval = InitializeMsTpm2Simulator( tctiContext );
        }
        else
        {
            CloseSockets( otherSock, tpmSock);
        }
    }

    return rval;
}
