Windows Sockets Vuser Functions (LRS) > Customizing WinSocket Scripts > Variable Socket Lengths

Variable Socket Lengths

This section describes how to create a script that handles receive socket buffers with variable lengths.

Problem

Several applications work with variable length receive sockets. The application makes two calls to the server: the first call to obtain the buffer length and the second call to retrieve the buffer information. VuGen only makes a single call and handles the entire socket as buffer information, thus ignoring the dynamic behavior of the application.

In the following example, the replay failed because it handled all of the bytes as data:

Call to receive buffer:

lrs_receive("socket0", "buf7", LrsLastArg);

Contents of Receive Buffer:

recv buf7 64

"\x00\x00\x00"

"<"

"0"

"\x06\x02\x01\x04\x02\x01\x00\x16\x01\x00"

"0!"

"\x02\x04\x01\xb5\x18\x9b\x02\x01\x05\x02\x01"

"2"

"\x02\x01\x00\x02\x01\x00\x02\x01\x01\x02\x01\x02\x02\x01\x04\x02\x01\x00\x02\x0\x03"

"0"

"\x0c\x02\x04\x01\x00"

"!"

"\xe8\x02\x04\x80\x00\x10"

"A"

The recording log indicates that two calls were made to the receive buffer by the application. In the first call, four bytes were received. In the second call, 60 bytes were received.

/* recv(): 4 bytes were received from socket 1568 using flags 0 (4 requested) */

(recv_10, 4, 1568)

    "\x00\x00\x00"

    "<"

/* recv(): 60 bytes were received from socket 1568 using flags 0 (60 requested) */

(recv_11, 60, 1568)

"0"

"\x06\x02\x01\x04\x02\x01\x00\x16\x01\x00"

"0!"

"\x02\x04\x01\xb5\x18\x9b\x02\x01\x05\x02\x01"

"2"

"\x02\x01\x00\x02\x01\x00\x02\x01\x01\x02\x01\x02\x02\x01\x04\x02\x01\x00\x02\x01\x03"

"0"

"\x0c\x02\x04\x01\x00"

"!"

"\xe8\x02\x04\x80\x00\x10"

"A"

Solution

Create a wrapper function, custom_lrs_receive that makes two calls to lrs_receive_ex: the first to get the buffer header (length), and the second to receive all the other bytes in the receive buffer based to the retrieved length. Define the new function and specify its prototype. This wrapper function should also contain a parsing routine that makes any required conversions, for example a Hex string to a number. You can also add a debug function that issues an error message when the function fails. After you define the wrapper function, replace the lrs_receive function from your script with the new function.

#define lrs_receive custom_lrs_receive

int custom_lrs_receive(char *sock_desc, char *buf_desc,void *dummy)

{

int rc;

int buf_len = 4;

char szBytesLength[30], *buf = NULL, *pszError, *pszLastChar;

/* Get first 4 bytes */

rc = lrs_receive_ex(sock_desc, buf_desc,

"NumberOfBytesToRecv=4", LrsLastArg);

if (rc != 0)

{

lr_error_message("Receive 4 bytes failed. The error code = %d", rc);

return -1;

}            /* Receive failed */

lrs_get_last_received_buffer(sock_desc, &buf, &buf_len);

if (buf == NULL || buf_len != 4)

{

lr_error_message("Receive %s failed", buf_desc);

if (szTranSaction != NULL)

my_lr_end_transaction(szTranSaction, LR_FAIL);

return -1;

}

/* Compute buffer length */

sprintf (szBytesLength, "NumberOfBytesToRecv=%d",

        fiFromHexBinToInt(buf) - 4);

lr_debug_message(LR_MSG_CLASS_FULL_TRACE, "!!!! Bytes length = %s",

            szBytesLength);

/* Get the buffer according to the length */

rc = lrs_receive_ex(sock_desc, buf_desc,

szBytesLength, LrsLastArg);

if (rc != 0) /* Receive failed */

return -1;

    

return 0;

}

/* Parse the header, convert HEX string to base 10.*/

int fiFromHexBinToInt (char *szBuffer)

{

    int i, j, iIntValue = 0, iExp = 1;

    for( i = 3; i >= 0; i--)

    {

        iExp = 1;

        for (j = 6; j > i*2; j--)

            iExp *= 16;

        iIntValue +=         (szBuffer[i] & 0x0000000f) * iExp

                +

                ((szBuffer[i] & 0x000000f0) >> 4) * iExp * 16;

    }

                        

                        

    return iIntValue;

}

Example

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

* Created by Mercury Interactive Windows Sockets Recorder

*

* Created on: Thu Nov 12 09:37:54

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

#include "lrs.h"

/*

    szBuffer - length = Fix size 4 bytes.

*/

int fiFromHexBinToInt(char *szBuffer)

{

    int i, j, iIntValue = 0, iExp = 1;

    for( i = 3; i >= 0; i--)

    {

        iExp = 1;

        for (j = 6; j > i*2; j--)

            iExp *= 16;

        iIntValue +=         (szBuffer[i] & 0x0000000f) * iExp

                    +

                    ((szBuffer[i] & 0x000000f0) >> 4) * iExp * 16;

    }

                        

                        

    return iIntValue;

}

int custom_lrs_receive(char *sock_desc, char *buf_desc,void *dummy)

{

int rc;

int buf_len = 4;

char szBytesLength[30], *buf = NULL, *pszError, *pszLastChar;

/* Get first 4 bytes */

rc = lrs_receive_ex(sock_desc, buf_desc,

"NumberOfBytesToRecv=4", LrsLastArg);

if (rc != 0)

{

lr_error_message("Receive 4 bytes failed. The error code = %d", rc);

return -1;

}    /* Receive failed */

lrs_get_last_received_buffer(sock_desc, &buf, &buf_len);

if (buf == NULL || buf_len != 4)

{

lr_error_message("receive of %s failed", buf_desc);

return -1;

}

/* Compute buffer length */

sprintf (szBytesLength, "NumberOfBytesToRecv=%d",

        fiFromHexBinToInt(buf) - 4);

lr_debug_message(LR_MSG_CLASS_FULL_TRACE, "!!!! Bytes length = %s",

            szBytesLength);

/* Get the buffer according to the length */

rc = lrs_receive_ex(sock_desc, buf_desc,

szBytesLength, LrsLastArg);

if (rc != 0) /* Receive failed */

return -1;

    

return 0;

}