New Protocol Plugins¶
The new protocol APIs enable you to extend Traffic Server to be a web proxy for any protocol. This chapter describes new protocol APIs and the plugins that support new protocols. It also provides a detailed review of code for a sample Protocol plugin that supports a very simple artificial HTTP-like protocol.
About the Sample Protocol¶
The sample protocol enables a client to ask a server for a file. Clients
send requests to a specific Traffic Server port (specified in
plugin.config); each request has the following structure:
server_name file_name
Using the Protocol plugin, Traffic Server can accept these requests, parse them, and act as a proxy cache (i.e., request the file from the origin server on the client’s behalf and store copies of response messages in cache). The Protocol plugin is a state machine that flows through the states illustrated in the Sample Protocol State Diagram. This figure illustrates the steps that Traffic Server and the Protocol plugin go through in order to support the sample protocol.
In more specific terms, Traffic Server and the Protocol plugin must:
- Listen for and accept client connections (on the accept port
specified in
plugin.config) - Read incoming client requests
- Look up the requested content in the Traffic Server cache
- Serve content from cache if the request is a cache hit (this simple example does not do freshness checking)
- Open a connection to the origin server if the request is a cache miss
(on the server port specified in
plugin.config) - Forward the request to the origin server
- Receive the origin server response
- Cache the response and send it on to the client
Sample Protocol State Diagram
Sample Protocol State Diagram
Protocol Plugin Structure¶
To see how the Protocol plugin works, you need to understand some broader concepts. This section assumes you’re familiar with the concepts of continuation, Traffic Server’s asynchronous event model, and basic Traffic Server plugin structure. If you are not familiar with these concepts, then you may want to begin with the Getting Started section.
Continuations in the Protocol Plugin¶
The Protocol plugin creates a static continuation that is an “accept” state machine - that is, a state machine whose job is to accept client connections on the appropriate port. When Traffic Server accepts a net connection from a client on that port, the accept state machine is activated. It then creates a new continuation: a transaction state machine. The accept state machine creates one transaction state machine for each transaction (where a transaction consists of a client request and Traffic Server’s response). Each transaction state machine lives until the transaction completes; then it is destroyed. If the client’s request for content is a cache miss, then a transaction state machine might need to open a connection to the origin server. This is illustrated in the Protocol Plugin Overview diagram below.
Protocol Plugin Overview
Protocol Plugin Overview
The first steps for writing the Protocol plugin are now clear: in
TSPluginInit, you must create a continuation that listens for net
connections on the client port specified in plugin.config (this
continuation is the accept state machine).
Below is a summary of the continuations implemented for the Protocol plugin:
- An accept state machine that listens for client connections, and then creates transaction state machines whenever Traffic Server accepts a new client connection. The accept state machine lives as long as Traffic Server is running.
- Transaction state machines that read client requests, process them, and are then destroyed when the transaction is finished.
Event Flow¶
Implementing the rest of the Protocol plugin requires that you
understand the flow of events during the course of a transaction. Unlike
HTTP transaction plugins, this plugin must read data from network
connections and then read/write data to the Traffic Server cache. This
means that its continuations do not receive HTTP state machine events;
they receive events from Traffic Server’s processor subsystems. For
example: the accept state machine is activated by an
TS_EVENT_NET_ACCEPT event from Traffic Server’s Net Processor; the
handler function for the accept state machine must therefore be able to
handle that event.
The transaction state machines are activated when the client connection receives incoming request data. The Net Processor notifies the transaction state machine of incoming data. The transaction state machine reads the data; when finished, it initiates a cache lookup of the requested file. When the cache lookup completes, the transaction state machine is activated by the Traffic Server Cache Processor.
If the transaction state machine needs to open a connection to the origin server to fetch content (in the case of a cache miss), then the transaction state machine initiates a DNS lookup of the server name. The transaction state machine is activated by a DNS lookup event from the Traffic Server Host Database Processor. If the transaction must connect to the origin server, then the transaction state machine initiates a net connection and waits for an event from the Net Processor.
Protocol Plugin Flow of Events
Protocol Plugin Flow of Events
The flow of events is illustrated in the Protocol Plugin Flow of Events diagram above. The thin straight lines show Net Processor event flow, the thin dashed lines represent Host Database event flow, and the thick dashed lines show Cache event flow.
Notice that this flow of events is independent of the Protocol plugin’s
design (i.e., whether you build accept or transaction state
machines). Any plugin that supports network connections uses the net
vconnection interfaces (TSNetAccept, TSNetConnect) and thus
receives events from the Net Processor. Any plugin that performs cache
lookups or cache writes uses TSCacheRead, TSCacheWrite,
TSVConnRead, and TSVConnWrite and thus receives events from the
Cache Processor and Traffic Server event system. Similarly, any plugin
that does DNS lookups receives events from the Host Database Processor.
One Way to Implement a Transaction State Machine¶
Transaction state machines (TSMs) in the Protocol plugin must do the following:
- Keep track of the state of the transaction
- Handle events received (based on the state of the transaction and the event received)
- Update the state of the transaction as it changes
Below is one way you can implement TSMs. Details about how the Protocol plugin does this are provided in the next section.
- Create a data structure for transactions that contains all of the
state data you need to keep track of. In the Protocol plugin this is
a struct,
Txn_SM. - When you create the TSM’s continuation, initialize data of type
Txn_SM. Initialize the data to the initial state of a transaction (in this case, a net connection has just been accepted). Associate this data to the TSM continuation usingTSContDataSet. - Write state handler functions that handle the expected events for each state.
- Write the handler for the TSM. Its job is to receive events, examine
the current state, and execute the appropriate state handler
function. In the Protocol plugin, the handler is
main_handler.main_handlercalls the state handler functions to handle each state.
The steps below describe the flow of execution illustrated in “How Transaction State Machines are Implemented in the Protocol Plugin”.
- The handler for the TSM, (called
main_handlerin the Protocol plugin) receives events from the TSM. main_handlerexamines the state of the transaction-in particular, it examines the current handler.main_handlercalls thecurrent_handler(which is one of the state handler functions), and then passes the current event tocurrent_handler. In the image below below, the current handler is calledstate2_handler.- The
current_handlerhandles the event and updates the data. In the image below below, the state is changed fromstate2tostate3(and the current handler is changed fromstate2_handlertostate3_handler). The next timemain_handlerreceives an event, it will be processed bystate3_handler. state2_handlerarranges the next callback of the TSM. Typically, it gives Traffic Server additional work to do (such as writing a file to cache) so that it can progress to the next state. The TSM (main_handler) then waits for the next event to arrive from Traffic Server.
How Transaction State Machines are Implemented in the Protocol Plugin
How Transaction State Machines are Implemented in the Protocol Plugin
Processing a Typical Transaction¶
The code is contained in the following files:
Protocol.candProtocol.hAccept.candAccept.hTxnSM.candTxnSM.h
Below is a step-by-step walk-through of the code that processes a typical transaction.
- The
TSPluginInitfunction is in theProtocol.cfile. It checks the validity of theplugin.configentries (there must be two: a client accept port and a server port) and runs an initialization routine,init. - The
initfunction (inProtocol.c) creates the plugin’s log file usingTSTextLogObjectCreate. - The
initfunction creates the accept state machine usingAcceptCreate. The code forAcceptCreateis in theAccept.cfile. - The accept state machine, like the transaction state machine, keeps
track of its state with a data structure. This data structure,
Accept, is defined in theAccept.hfile. State data inAcceptCreateis associated with the new accept state machine viaTSContDataSet. - The
initfunction arranges the callback of the accept state machine when there is a network connection by usingTSNetAccept. - The handler for the accept state machine is
accept_eventin theAccept.cfile. When Traffic Server’s Net Processor sendsTS_EVENT_NET_ACCEPTto the accept state machine,accept_eventcreates a transaction state machine (txn_sm) by callingTxnSMCreate. Notice thataccept_eventcreates a mutex for the transaction state machine, since each transaction state machine has its own mutex. - The
TxnSMCreatefunction is in theTxnSM.cfile. The first thing it does is initialize the transaction’s data, which is of typeTxnSM(as defined inTxnSM.h). Notice that the current handler (q_current_handler) is set tostate_start. TxnSMCreatethen creates a transaction state machine usingTSContCreate. The handler for the transaction state machine ismain_handler, which is in theTxnSM.cfile.- When
accept_eventreceivesTS_EVENT_NET_ACCEPT, it calls the transaction state machine (TSContCall (txn_sm, 0, NULL);). The event passed tomain_handleris0(TS_EVENT_NONE). - The first thing
main_handlerdoes is examine the currenttxn_smstate by callingTSContDataGet. The state isstate_start. main_handlerthen invokes the handler forstate_startby using the function pointerTxnSMHandler(as defined inTxnSM.h).- The
state_starthandler function (in theTxnSM.cfile) is handed an event (at this stage, the event isTS_EVENT_NET_ACCEPT) and a client vconnection.state_startchecks to see if this client vconnection is closed; if it is not, thenstate_startattempts to read data from the client vconnection into anTSIOBuffer(state_startis handling the event it receives). state_startchanges the current handler tostate_interface_with_client(that is, it updates the state of the transaction to the next state).state_startinitiates a read of the client vconnection (arranges for Traffic Server to sendTS_EVENT_VCONN_READ_READYevents to the TSM) by callingTSVConnRead.state_interface_with_clientis activated by the next event from Traffic Server. It checks for errors and examines the read VIO for the read operation initiated byTSVConnRead.- If the read VIO is the
client_read_VIO(which we are expecting at this stage in the transaction), thenstate_interface_with_clientupdates the state tostate_read_request_from_client. state_read_request_from_clienthandles actualTS_EVENT_READ_READYevents and reads the client request.state_read_request_from_clientparses the client request.state_read_request_from_clientupdates the current state to the next state,state_handle_cache_lookup.state_read_request_from_clientarranges for Traffic Server to call back the TSM with the next set of events (initiating the cache lookup) by callingTSCacheRead.- When the
TSCacheReadsends the TSM eitherTS_EVENT_OPEN_READ(a cache hit) orTS_EVENT_OPEN_READ_FAILED(a cache miss),main_handlercallsstate_handle_cache_lookup.