An addendum to the previous message I have resorted to reading the traffic server code in order to try to discern what it does:

I am examining 


TSVConnWrite(TSVConn connp, TSCont contp, TSIOBufferReader readerp, int64_t nbytes)


  sdk_assert(sdk_sanity_check_iocore_structure(connp) == TS_SUCCESS);

  sdk_assert(sdk_sanity_check_iocore_structure(contp) == TS_SUCCESS);

  sdk_assert(sdk_sanity_check_iocore_structure(readerp) == TS_SUCCESS);

  sdk_assert(nbytes >= 0);


  VConnection *vc = (VConnection *) connp;

  return reinterpret_cast<TSVIO>(vc->do_io_write((INKContInternal *) contp, nbytes, (IOBufferReader *) readerp));


It would appear that the answer to what this method does lies in what happens in the function "vc->do_io_write" yet when I search the trafficserver 3.2.0 codebase for any file that actually contains an implementation of "vc->do_io_write" I find that "do_io_write" is declared in several .h files but not defined in any .c or .cpp files.

Does anyone know where in the code base the implementation of "do_io_write" resides?

From: "Owens, Steve" <>
Reply-To: "" <>
Date: Fri, 25 Jan 2013 10:48:11 -0800
To: "" <>
Subject: Api Questions

I am trying to understand the relationship between the following functions as they are used within a transformation plugin and so far no matter how hard I dig the mystery remains.  I am hoping that people who have a better understanding of ATS than I do would be willing to help clear up any misunderstandings I have.

Here are the functions I find confusing:


(TSIOBufferCopy and or TSIOBufferWrite)

And finally


Each of the above functions takes an int_64 argument at the end to indicate the number of bytes but I don't fully understand the purpose of this parameter with respect to each of the functions.

Suppose I have a transformation which is intended to write a prefix spew the response and then write a suffix to the down stream I would imagine it looks something like this:

void handleTransformOperation(TSCont contp) {

TSIOBuffer buf_test;

int_64 written = 0;

TransormationData* pData = (TransformationData*) TSContDataGet(contp);

TSVIO input_vio = TSTransformOutputVConnGet(contp);

if(data->state == STATE_BEGIN) {

    // Initialize the output_buffer and output_reader

    data->output_buffer = TSIOBufferCreate();

    data->output_reader = TSIOBufferReaderAlloc(data->output_buffer);

   // Write out a prefix

   written += TSIOBufferWrite(data->output_buffer, "{Hello I am a prefix}", strlen(prefix) * sizeof(char));

   data->state == STATE_MIDDLE;

   // Figure out if the upstream wants to stop receiving WRITEREADY and WRITE_COMPLETE events

   buf_test = TSVIOBufferGet(input_vio);

   if (!buf_test) {

       int64_t doneget = TSVIONDoneGet(input_vio);

       TSVIONBytesSet(data->output_vio, /*What goes here doneget or written + doneget or just written?  Bonus question: why? /* ???);

       data->state = STATE_END;

   } else

       data->state = STATE_MIDDLE;


// Notice that the above if falls through to the next state so it is possible that the following code may or may not

// get executed based on the buf_test result above.

if(data->state == STATE_MIDDLE) {

   // Figure out if the upstream wants to stop receiving WRITEREADY and WRITE_COMPLETE events

   buf_test = TSVIOBufferGet(input_vio);

   if (!buf_test) {

       int64_t doneget = TSVIONDoneGet(input_vio);

       TSVIONBytesSet(data->output_vio/*What goes here doneget or written + doneget or just written?  Bonus question: why? /* ???);

       data->state = STATE_END;

   } else {

       // Figure out how much data is left to read from the upstream

       int64_t upstreamBytesRemaining = TSVIONTodoGet(input_vio);

       int64_t upstreamBytesAvail = TSIOBufferReaderAvail(TSVIOReaderGet(input_vio));

       if(upstreamBytesRemaining > 0) {

            int64_t bytesToWrite = upstreamBytesRemaining;

            if(bytesToWrite > upstreamBytesAvail)

                 bytesToWrite = upstreamBytesAvail;


            /* Copy the data from the read buffer to the output buffer. */

    TSIOBufferCopy(TSVIOBufferGet(data->output_vio), TSVIOReaderGet(input_vio), bytesToWrite, 0);

           /* Tell the read buffer that we have read the data and are no

    * longer interested in it.


    TSIOBufferReaderConsume(TSVIOReaderGet(input_vio), bytesToWrite);

           /* Modify the input VIO to reflect how much data we've

    * completed.


           int64_t doneget = TSVIONDoneGet(input_vio);

   TSVIONDoneSet(input_vio, /* This is where things get really muddy what goes here?  doneget or doneget + bytesToWrite or doneget + bytesToWrite + written */ ??);

           /* What is the impact of calling this later in the handler if it has already been called here?


       /* Now we check the input VIO to see if there is data left to

* read.


        upstreamBytesRemaining = TSVIONTodoGet(input_vio);

if (upstreamBytesRemaining > 0) {

    if (upstreamBytesAvail > 0) {

      /* If there is data left to read, then we reenable the output

       * connection by reenabling the output VIO. This will wake up

       * the output connection and allow it to consume data from the

       * output buffer.



       /* Call back the input VIO continuation to let it know that we

        * are ready for more data.





} else {

    /* There is no data left to read so set state to STATE_END and */

    data->state = STATE_END;



   // The above can fall through to this if block

   if(data->state == STATE_END) {

       /* Spew a suffix */

       const char* suffix = "{i am a suffix}";

       int64_t localWritten = TSIOBufferWrite(data->output_buffer, suffix, (strlen(suffix) - 1) * sizeof(char));


       int64_t doneget = TSVIONDoneGet(input_vio);

       TSVIONBytesSet(data->output_vio, /* What goes here? Why? */??);


      /* Call back the input VIO continuation to let it know that we

       * have completed the write operation.


       TSContCall(TSVIOContGet(input_vio), TS_EVENT_VCONN_WRITE_COMPLETE, input_vio);


   /* I am presuming we only want to call this once per invocation of handlerOperation  But I am not sure */

  data->output_vio = TSVConnWrite(output_conn, contp, data->output_reader, /* What to put here hmmm and why? */ ?? );


I really want to understand how these methods relate and what they do.  I would be willing to help update/contribute to the ATS docs but first I would need to understand what they do and so far the examples that are available have not made it clear to me what is going on as yet so any help would be appreciated.