/*<ATGCOPYRIGHT>
 * Copyright (C) 1997 Art Technology Group, Inc.
 * All Rights Reserved.  No use, copying or distribution of this
 * work may be made except in accordance with a valid license
 * agreement from Art Technology Group.  This notice must be
 * included on all copies, modifications and derivatives of this
 * work.
 *
 * Art Technology Group (ATG) MAKES NO REPRESENTATIONS OR WARRANTIES 
 * ABOUT THE SUITABILITY OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, 
 * INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. ATG SHALL NOT BE
 * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, 
 * MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
 *
 * "Dynamo" is a trademark of Art Technology Group, Inc.
 </ATGCOPYRIGHT>*/

/* 
   DRPServerIO.c - routines for sending/receiving DRP objects, etc
 */


#include <stdlib.h>

#ifndef WIN32
/* UNIXen */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/tcp.h>
#else
#define EINTR WSAEINTR
#endif


#include "DRPClient.h"
#include "DRPServerIO.h"


#include <stdio.h>
#include <string.h>

/**
 * do_recv
 * locally-buffered interface to recv().  if requested amount of data
 *   is not already in the "receive" socket io buffer in the context block
 *   (pCB), then the io buffer is filled from socket iSock.
 * (NB: assumed that iSock, flags always the same for given context)
 * return: number of bytes received; 0 == sock closed; SOCKET_ERROR == failure
 */
static size_t
do_recv(drpContextBlock * pCB, socket_t iSock, char *oBuffer,
        size_t iLength, int iFlags)
{
    size_t returnValue = 0;
    sockBuf *recvBuf = &pCB->recvBuf;
    size_t bytesAvail;

    if (recvBuf->used - recvBuf->curPtr < iLength) {
        /* fewer bytes in recvBuf than requested */
        int result;

        if (recvBuf->curPtr > 0) {
            /* move as-yet-unretrieved data in recvBuf to beginning of recvBuf */
            memmove(recvBuf->data, recvBuf->data + recvBuf->curPtr,
                    recvBuf->used - recvBuf->curPtr);
            recvBuf->used -= recvBuf->curPtr;
            recvBuf->curPtr = 0;
        }
        /* fill recvBuf with delicious data */
      tryagain:
        result = recv(iSock, recvBuf->data + recvBuf->used,
                      recvBuf->capacity - recvBuf->used, iFlags);
        if (result < 0) {
            int errorNum = net_error();
            char buf[128];

            if (errorNum == EINTR) {
                if (pCB->debugEnabled) {
                    sprintf(buf,
                            "read failed from socket %d with errno %d retrying...",
                            iSock, errorNum);

                    pCB->logMessage(pCB->shellData, kLog_Info,
                                    kLogMessage_OneString, buf, NULL);
                }
                goto tryagain;
            }

            if (pCB->debugEnabled) {
                sprintf(buf, "read failed from socket %d with errno %d",
                        iSock, errorNum);

                pCB->logMessage(pCB->shellData, kLog_Info,
                                kLogMessage_OneString, buf, NULL);
            }
            returnValue = result;
            goto DO_RECV_EXIT;
        } else {
            if (result == 0 && pCB->debugEnabled) {
                pCB->logMessage(pCB->shellData, kLog_Info,
                                kLogMessage_OneString, "recv returned 0",
                                NULL);
            }
            recvBuf->used += result;
        }
    }
    bytesAvail = recvBuf->used - recvBuf->curPtr;       /* avail in recvBuf */
    returnValue = MIN(bytesAvail, iLength);     /* bytes to copy into return buf */
    memcpy(oBuffer, recvBuf->data + recvBuf->curPtr, returnValue);
    recvBuf->curPtr += returnValue;

  DO_RECV_EXIT:

    return returnValue;
}


/**
 * do_send
 * uses send() to send all data currently in the "send" socket io buffer
 *   in the context block (pCB) via socket iSock.
 * return: number of bytes send; SOCKET_ERROR == failure
 */
static size_t do_send(drpContextBlock * pCB, socket_t iSock, int iFlags)
{
    size_t returnValue = 0;
    sockBuf *sendBuf = &pCB->sendBuf;
    size_t result = 1;
    size_t bytesSentSoFar = 0;

    while ((bytesSentSoFar < sendBuf->used) && (result > 0)) {
        result = send(iSock, sendBuf->data + bytesSentSoFar,
                      sendBuf->used - bytesSentSoFar, iFlags);

        if (result < 0) {
            char buf[128];
            int errorNum = net_error();

            if (errorNum == EINTR)
                continue;

            if (pCB->debugEnabled) {
                sprintf(buf, "write failed to socket %d with errno %d",
                        iSock, errorNum);

                pCB->logMessage(pCB->shellData, kLog_Info,
                                kLogMessage_OneString, buf, NULL);
            }
        }
        bytesSentSoFar += result;
    }
    if (result == SOCKET_ERROR) {
        returnValue = result;
        goto DO_SEND_EXIT;
    } else {
        returnValue += result;
        sendBuf->used = 0;
    }

  DO_SEND_EXIT:

    return returnValue;
}


/**
 * send_queue
 * locally-buffered interface to send().  if there is not enough space
 *   in the "send" socket io buffer for the data, the buffer is flushed
 *   out to socket iSock.  otherwise, data is copied into send buffer
 *   to be sent later.
 * (NB: assumed that iSock, flags always the same for given context)
 * return: number of bytes (queued to be) sent; SOCKET_ERROR == failure
 */
static size_t
send_queue(drpContextBlock * pCB, socket_t iSock, const char *iBuffer,
           size_t iLength, int iFlags)
{
    size_t returnValue = 0;
    sockBuf *sendBuf = &pCB->sendBuf;
    size_t bytesAvail;

    if (sendBuf->capacity - sendBuf->used < iLength) {
        size_t result;

        /* fewer bytes avail in sendBuf than needed to store data */
        result = do_send(pCB, iSock, iFlags);
        if (result == SOCKET_ERROR) {
            returnValue = result;
            goto DO_SEND_EXIT;
        }
    }
    bytesAvail = sendBuf->capacity - sendBuf->used;     /* avail in sendBuf */
    returnValue = MIN(bytesAvail, iLength);     /* bytes to copy into sendBuf */
    memcpy(sendBuf->data + sendBuf->used, iBuffer, returnValue);
    sendBuf->used += returnValue;

  DO_SEND_EXIT:

    return returnValue;
}


/**
 * send_flush
 * forces send of data currently in "send" socket io buffer in the context
 *   block (pCB) via socket iSock.
 * return: 0 == success; SOCKET_ERROR == failure
 */
int send_flush(drpContextBlock * pCB, socket_t iSock, int iFlags)
{
    size_t result;

    result = do_send(pCB, iSock, iFlags);

    return (result == SOCKET_ERROR ? result : 0);
}


/**
 * recvByte
 * Receive a single byte from the DRP server
 * oByte: will be filled in with byte value received
 * return: 0 == success; !0 == failure
 */
int recvByte(drpContextBlock * pCB, socket_t iSock, drpByte * oByte)
{
    int returnValue = 0;
    size_t bytesRead;

    bytesRead = do_recv(pCB, iSock, oByte, sizeof(drpByte), 0);
    if (bytesRead != sizeof(drpByte)) {
        if (pCB->debugEnabled) {
            char buf[128];
#if defined(SOLARIS2) && !defined(_LP64) && !defined(_I32LPx) || defined(WIN32) || defined(LINUX)
            sprintf(buf, "failed to read byte (size=%u) from socket %d",
#else
            sprintf(buf, "failed to read byte (size=%lu) from socket %d",
#endif
                    bytesRead, iSock);
            pCB->logMessage(pCB->shellData, kLog_Info,
                            kLogMessage_OneString, buf, NULL);
        }
        returnValue = -1;
    }

    return returnValue;
}


/**
 * sendByte
 * Send a single byte to the DRP server
 * iByte: byte to send
 * return: 0 == success; !0 == failure
 */
int sendByte(drpContextBlock * pCB, socket_t iSock, const drpByte * iByte)
{
    int returnValue = 0;
    int bytesSent;

    bytesSent = send_queue(pCB, iSock, iByte, sizeof(drpByte), 0);
    if (bytesSent != sizeof(drpByte))
        returnValue = -1;

    return returnValue;
}


/**
 * recvLong
 * Receive a 4-byte integer from the DRP server
 * oLong: will be filled in with the "long" value received
 * return: 0 == success; !0 == failure
 */
int recvLong(drpContextBlock * pCB, socket_t iSock, drpInt * oLong)
{
    int returnValue = 0;
    size_t bytesRead;

    bytesRead = do_recv(pCB, iSock, (char *) oLong, sizeof(drpInt), 0);
    if (bytesRead != sizeof(drpInt)) {
        if (pCB->debugEnabled) {
            char buf[128];
#if defined(SOLARIS2) && !defined(_LP64) && !defined(_I32LPx) || defined(WIN32) || defined(LINUX)
            sprintf(buf, "failed to read long (size=%u) from socket %d",
#else
            sprintf(buf, "failed to read long (size=%lu) from socket %d",
#endif
                    bytesRead, iSock);
            pCB->logMessage(pCB->shellData, kLog_Info,
                            kLogMessage_OneString, buf, NULL);
        }
        returnValue = -1;
    } else
        *oLong = ntohl(*oLong);

    return returnValue;
}


/**
 * sendLong
 * Send a 4-byte integer to the DRP server
 * iLong: the "long" value to send
 * return: 0 == success; !0 == failure
 */
int sendLong(drpContextBlock * pCB, socket_t iSock, const drpInt * iLong)
{
    int returnValue = 0;
    size_t bytesSent;
    drpInt value;

    value = htonl(*iLong);
    bytesSent = send_queue(pCB, iSock, (char *) &value, sizeof(drpInt), 0);
    if (bytesSent != sizeof(drpInt))
        returnValue = -1;

    return returnValue;
}


/**
 * recvBuffer
 * Receive a byte stream from the DRP server
 * oBuffer: buffer object to fill with data received
 * iLength: number of bytes to receive
 * return: 0 == success; !0 == failure
 */
int
recvBuffer(drpContextBlock * pCB, socket_t iSock, growBuffer * oBuffer,
           size_t iLength)
{
    int returnValue = 0;
    size_t bytesRead = 1;

    /* NB: not necessary to grow buffer */

    oBuffer->used = 0;

    while ((oBuffer->used < iLength) && (bytesRead > 0)) {
        bytesRead = do_recv(pCB, iSock, oBuffer->buffer + oBuffer->used,
                            iLength - oBuffer->used, 0);

        if (bytesRead > 0)
            oBuffer->used += bytesRead;
    }

    if (oBuffer->used < iLength) {
        if (pCB->debugEnabled) {
            char buf[128];
            sprintf(buf, "failed to read buffer stream "
#if defined(SOLARIS2) && !defined(_LP64) && !defined(_I32LPx) || defined(WIN32) || defined(LINUX)
                    "(size=%u != %u) read=%u from socket %d",
#else
                    "(size=%lu != %lu) read=%lu from socket %d",
#endif
                    oBuffer->used, iLength, bytesRead, iSock);
            pCB->logMessage(pCB->shellData, kLog_Info,
                            kLogMessage_OneString, buf, NULL);
        }
        returnValue = -1;
    }

    return returnValue;
}


/**
 * sendBuffer
 * Send a byte stream to the DRP server
 * iBuffer: buffer object containing data to send
 *   (iBuffer->used is number of bytes to send)
 * return: 0 == success; !0 == failure
 */
int
sendBuffer(drpContextBlock * pCB, socket_t iSock,
           const growBuffer * iBuffer)
{
    int returnValue = 0;

    returnValue =
        sendByteStream(pCB, iSock, iBuffer->buffer, iBuffer->used);

    return returnValue;
}


/**
 * sendBytes
 * Send a byte stream to the DRP server
 * iBytes: bytes to send
 * iLength: number of bytes to send
 * return: 0 == success; !0 == failure
 */
int
sendByteStream(drpContextBlock * pCB, socket_t iSock, const char *iBytes,
               size_t iLength)
{
    int returnValue = 0;
    size_t bytesSent = 1;
    size_t bytesSentSoFar = 0;

    while ((bytesSentSoFar < iLength) && (bytesSent > 0)) {
        bytesSent = send_queue(pCB, iSock, iBytes + bytesSentSoFar,
                               iLength - bytesSentSoFar, 0);
        bytesSentSoFar += bytesSent;
    }

    if (bytesSentSoFar < iLength)
        returnValue = -1;

    return returnValue;
}


/**
 * recvIdentifier
 * Receive a DRP Identifier object from the DRP server.
 * oIdent: will be filled in with received Identifier data.
 * oBuffer: if received Identifier includes string data, that data will
 *   be placed in oBuffer (and the appropriate Identifier field will be
 *   pointed to oBuffer)
 * return: 0 == success; !0 == failure
 */
int
recvIdentifier(drpContextBlock * pCB, socket_t iSock,
               drpIdentifier * oIdent, growBuffer * oBuffer)
{
    int returnValue = 0;

    /* recv has-index byte */
    returnValue = recvByte(pCB, iSock, &oIdent->hasIndex);
    if (returnValue == 0)
        /* recv ident name (TLiteral) */
        returnValue = recvTLiteral(pCB, iSock, &oIdent->name, oBuffer);
    if (oIdent->hasIndex && (returnValue == 0))
        /* recv ident index (TLiteral) */
        returnValue = recvTLiteral(pCB, iSock, &oIdent->index, oBuffer);
    else
        memset(&oIdent->index, 0, sizeof(drpTLiteral));

    return returnValue;
}


/**
 * recvTLiteral
 * Receive a DRP Typed Literal object from the DRP server.
 * oTLiteral: will be filled in with received TLiteral data.
 * oBuffer: if received TLiteral includes string data, that data will
 *   be placed in oBuffer (and the appropriate TLiteral field will be
 *   pointed to oBuffer); will be grown if necessary
 * return: 0 == success; !0 == failure
 */
int
recvTLiteral(drpContextBlock * pCB, socket_t iSock,
             drpTLiteral * oTLiteral, growBuffer * oBuffer)
{
    int returnValue = 0;

    oTLiteral->numChars = 0;

    /* recv TLiteral type byte */
    returnValue = recvByte(pCB, iSock, &oTLiteral->type);
    if (returnValue == 0) {
        switch (oTLiteral->type) {
        case kNull:
            /* do nothing */
            break;
        case kInteger:
            returnValue = recvLong(pCB, iSock, &oTLiteral->value.integer);
            break;
        case kAscii:
            /* recv ascii data length */
            returnValue =
                recvLong(pCB, iSock, (drpInt *) & oTLiteral->numChars);
            if (returnValue == 0) {
                /* recv ascii data */
                ensureGrowBufferSize_m(oBuffer,
                                       (oBuffer->used +
                                        oTLiteral->numChars));
                returnValue =
                    recvByteStream(pCB, iSock,
                                   oBuffer->buffer + oBuffer->used,
                                   oTLiteral->numChars);
                if (returnValue == 0) {
                    oBuffer->used += oTLiteral->numChars;
                    oTLiteral->value.ascii = oBuffer->buffer;
                } else
                    oTLiteral->numChars = 0;
            } else
                oTLiteral->numChars = 0;
            break;
        case kUnicode:
            /* recv unicode data length */
            returnValue =
                recvLong(pCB, iSock, (drpInt *) & oTLiteral->numChars);
            if (returnValue == 0) {
                /* recv unicode data */
                ensureGrowBufferSize_m(oBuffer,
                                       (oBuffer->used +
                                        oTLiteral->numChars *
                                        sizeof(drpChar)));
                returnValue =
                    recvByteStream(pCB, iSock,
                                   oBuffer->buffer + oBuffer->used,
                                   sizeof(drpChar) * oTLiteral->numChars);
                if (returnValue == 0) {
                    oBuffer->used += oTLiteral->numChars * sizeof(drpChar);
                    /* DO NOT re-order unicode */
                    oTLiteral->value.unicode = (drpChar *) oBuffer->buffer;
                } else
                    oTLiteral->numChars = 0;
            } else
                oTLiteral->numChars = 0;
            break;
        case kDefined:
            returnValue = recvByte(pCB, iSock, &oTLiteral->value.defined);
            break;
        default:
            returnValue = -1;
            break;
        }
    }

    return returnValue;
}


/**
 * recvByteStream
 * Receive a byte stream from the DRP server
 * oBuffer: buffer in which to store received data
 * iLength: number of bytes to receive
 * return: 0 == success; !0 == failure
 */
int
recvByteStream(drpContextBlock * pCB, socket_t iSock, char *oBuffer,
               size_t iLength)
{
    int returnValue = 0;
    size_t bytesRead = 1;
    size_t bytesReadSoFar = 0;

    while ((bytesReadSoFar < iLength) && (bytesRead > 0)) {
        bytesRead = do_recv(pCB, iSock, oBuffer + bytesReadSoFar,
                            iLength - bytesReadSoFar, 0);
        if (bytesRead > 0)
            bytesReadSoFar += bytesRead;
    }

    if (bytesReadSoFar < iLength) {
        if (pCB->debugEnabled) {
            char buf[128];
            sprintf(buf, "failed to read byte stream "
#if defined(SOLARIS2) && !defined(_LP64) && !defined(_I32LPx) || defined(WIN32) || defined(LINUX)
                    "(size=%u != %u) read=%u from socket %d",
#else
                    "(size=%lu != %lu) read=%lu from socket %d",
#endif
                    bytesReadSoFar, iLength, bytesRead, iSock);
            pCB->logMessage(pCB->shellData, kLog_Info,
                            kLogMessage_OneString, buf, NULL);
        }
        returnValue = -1;
    }

    return returnValue;
}


/**
 * sendIdentifier
 * Send a DRP Identifier object to the DRP server.
 * iIdent: the Identifier to send.
 * return: 0 == success; !0 == failure
 */
int
sendIdentifier(drpContextBlock * pCB, socket_t iSock,
               const drpIdentifier * iIdent)
{
    int returnValue = 0;

    /* send has-index byte */
    returnValue = sendByte(pCB, iSock, &iIdent->hasIndex);
    if (returnValue == 0)
        /* send ident name (TLiteral) */
        returnValue = sendTLiteral(pCB, iSock, &iIdent->name);
    if (iIdent->hasIndex && (returnValue == 0))
        /* send ident index (TLiteral) */
        returnValue = sendTLiteral(pCB, iSock, &iIdent->index);

    return returnValue;
}


/**
 * sendTLiteral
 * Send a DRP Typed Literal object to the DRP server.
 */
int
sendTLiteral(drpContextBlock * pCB, socket_t iSock,
             const drpTLiteral * iTLiteral)
{
    int returnValue = 0;

    /* send TLiteral type byte */
    returnValue = sendByte(pCB, iSock, &iTLiteral->type);
    if (returnValue == 0) {
        switch (iTLiteral->type) {
        case kNull:
            /* do nothing */
            break;
        case kInteger:
            returnValue = sendLong(pCB, iSock, &iTLiteral->value.integer);
            break;
        case kDefined:
            returnValue = sendByte(pCB, iSock, &iTLiteral->value.defined);
            break;
        case kAscii:
            /* send ascii data length */
            returnValue =
                sendLong(pCB, iSock, (drpInt *) & iTLiteral->numChars);
            if (returnValue == 0)
                /* send ascii data */
                returnValue =
                    sendByteStream(pCB, iSock, iTLiteral->value.ascii,
                                   iTLiteral->numChars);
            break;
        case kUnicode:
            /* send unicode data length */
            returnValue =
                sendLong(pCB, iSock, (drpInt *) & iTLiteral->numChars);
            if (returnValue == 0) {
                /* send unicode data */
                /* DO NOT reorder unicode */
                returnValue = sendByteStream(pCB, iSock,
                                             (char *) iTLiteral->value.
                                             unicode,
                                             iTLiteral->numChars *
                                             sizeof(drpChar));
            }
            break;
        default:
            returnValue = -1;
            break;
        }
    }

    return returnValue;
}


/**
 * sendAsciiTLiteral
 * Send a DRP Typed Literal object with ASCII string data to the DRP server.
 * iAsciiBuffer: the ASCII string data to send.
 * return: 0 == success; !0 == failure
 */
int
sendAsciiTLiteral(drpContextBlock * pCB, socket_t iSock,
                  const growBuffer * iAsciiBuffer)
{
    int returnValue = 0;
    drpByte _ascii = kAscii;

    /* send ascii typed-literal type byte */
    returnValue = sendByte(pCB, iSock, &_ascii);
    if (returnValue == 0)
        /* send length of ascii data */
        returnValue =
            sendLong(pCB, iSock, (drpInt *) & iAsciiBuffer->used);
    if (returnValue == 0)
        /* send ascii data */
        returnValue = sendByteStream(pCB, iSock, iAsciiBuffer->buffer,
                                     iAsciiBuffer->used);

    return returnValue;
}


/**
 * sendIntTLiteral
 * Send a DRP Typed Literal object with DRP-Integer data to the DRP server.
 * iInt: the 4-byte integer to send.
 * return: 0 == success; !0 == failure.
 */
int sendIntTLiteral(drpContextBlock * pCB, socket_t iSock, drpInt iInt)
{
    int returnValue = 0;
    drpByte _int = kInteger;

    /* send integer typed-literal type byte */
    returnValue = sendByte(pCB, iSock, &_int);
    if (returnValue == 0)
        /* send integer value */
        returnValue = sendLong(pCB, iSock, &iInt);

    return returnValue;
}



/**
 * sendNameIndexedPair
 * Send a Name-Value pair, indexed by (ascii string) iIndex.
 * iDefinedName: defined-string index indicating "name" of pair
 * iIndex: (null-terminated) ascii string indicating "index" of pair
 * iAscii: (null-terminated) ascii string "value" of pair.
 * return: 0 == success; !0 == failure
 */
int
sendNameIndexedPair(drpContextBlock * pCB, socket_t iSock,
                    drpByte iDefinedName, const drpByte * iIndex,
                    const drpByte * iAscii)
{
    int returnValue = 0;
    drpByte _1 = 1;
    drpByte _ascii = kAscii;
    drpByte _defined = kDefined;
    drpInt length = strlen(iIndex);

    /* send Identifier (pair name) */
    /* send byte: identifier has index */
    returnValue = sendByte(pCB, iSock, &_1);

    /* send TLiteral (identifier name): iDefinedName */
    if (returnValue == 0)
        /* TLiteral type: defined string type */
        returnValue = sendByte(pCB, iSock, &_defined);
    if (returnValue == 0)
        /* TLiteral value: defined string ID */
        returnValue = sendByte(pCB, iSock, &iDefinedName);

    /* send TLiteral (identifier index): iIndex */
    if (returnValue == 0)
        /* TLiteral type: ascii string type */
        returnValue = sendByte(pCB, iSock, &_ascii);
    if (returnValue == 0)
        /* ascii string length */
        returnValue = sendLong(pCB, iSock, &length);
    if (returnValue == 0)
        /* ascii string data */
        returnValue = sendByteStream(pCB, iSock, iIndex, length);

    length = strlen(iAscii);

    /* send TLiteral (pair value): iAscii */
    if (returnValue == 0)
        /* TLiteral type: ascii string type */
        returnValue = sendByte(pCB, iSock, &_ascii);
    if (returnValue == 0)
        /* ascii string length */
        returnValue = sendLong(pCB, iSock, &length);
    if (returnValue == 0)
        /* ascii string data */
        returnValue = sendByteStream(pCB, iSock, iAscii, length);

    return returnValue;
}


/**
 * sendIntIndexedPair
 * Send a Name-Value pair, indexed by (integer) iIndex.
 * iDefinedName: defined-string index indicating "name" of pair.
 * iIndex: integer "index" of pair.
 * iAscii: (null-terminated) ascii string "value" of pair.
 * return: 0 == success; !0 == failure
 */
int
sendIntIndexedPair(drpContextBlock * pCB, socket_t iSock,
                   drpByte iDefinedName, int iIndex,
                   const drpByte * iAscii)
{
    int returnValue = 0;
    drpByte _1 = 1;
    drpByte _defined = kDefined;
    drpByte _integer = kInteger;
    drpByte _ascii = kAscii;
    drpInt length = strlen(iAscii);

    /* send Identifier (pair name) */
    /* send byte: identifier has index */
    returnValue = sendByte(pCB, iSock, &_1);

    /* send TLiteral (identifier name): iDefinedName */
    if (returnValue == 0)
        /* TLiteral type: defined string type */
        returnValue = sendByte(pCB, iSock, &_defined);
    if (returnValue == 0)
        /* TLiteral value: defined string ID */
        returnValue = sendByte(pCB, iSock, &iDefinedName);

    /* send TLiteral (identifier index): iIndex */
    if (returnValue == 0)
        /* TLiteral type: integer type */
        returnValue = sendByte(pCB, iSock, &_integer);
    if (returnValue == 0)
        /* TLiteral value: iIndex */
        returnValue = sendLong(pCB, iSock, (drpInt *) & iIndex);

    /* send TLiteral (pair value): iAscii */
    if (returnValue == 0)
        /* TLiteral type: ascii string type */
        returnValue = sendByte(pCB, iSock, &_ascii);
    if (returnValue == 0)
        /* ascii string length */
        returnValue = sendLong(pCB, iSock, &length);
    if (returnValue == 0)
        /* ascii string data */
        returnValue = sendByteStream(pCB, iSock, iAscii, length);

    return returnValue;
}
