introduction to ats plugins
TRANSCRIPT
Introduction to ATS plugins
About Me● Phil Sorber● ATS Committer● Work for OmniTI
About This Tutorial● Introductory Overview● Example Walkthrough● Assuming you haven't written a plugin for
ATS before but that you have some programming knowledge
● C API (we also have C++11 and Lua)
Brief History● Inktomi 1996● Yahoo! 2002● ASF 2009● ASF TLP 2010● INK -> TS
Architecturethreaded + async state machine model
● Event Processors● State Machines● Continuations
Architecture
What's in a plugin?1. Initialization2. Hook Registration3. Handle Events in continuations (do work)
Initialization#include <ts/ts.h>
voidTSPluginInit (int argc, const char *argv[])
InitializationvoidTSPluginInit (int argc, const char *argv[]){ TSPluginRegistrationInfo info; MyStateInfo state;
info.plugin_name = "foobar"; info.vendor_name = "foobar inc"; info.support_email = "[email protected]";
InitializationvoidTSPluginInit (int argc, const char *argv[]){... if (TSPluginRegister(TS_SDK_VERSION_3_0, &info) != TS_SUCCESS) { TSError("Plugin registration failed.\n"); return; } else { TSDebug(LOG_PREFIX, "Plugin registration succeeded.\n"); }
InitializationvoidTSPluginInit (int argc, const char *argv[]){... state = TSmalloc(sizeof(MyStateInfo)); TSHttpArgIndexReserve("plugin_txn_state", "txn state info for plugin", &state->txn_slot); state->my_mutex = TSMutexCreate(); my_cont = TSContCreate(my_cont_func, NULL); TSContDataSet(my_cont, (void *) state);
Global Hook Reg.voidTSPluginInit (int argc, const char *argv[]){... TSHttpHookAdd(TS_HTTP_READ_REQUEST_HDR_HOOK, main_cont);}
Global Hook Reg.TSHttpHookAdd: adds a global hook. You can globally add any hook except for TS_HTTP_REQUEST_TRANSFORM_HOOK and TS_HTTP_RESPONSE_TRANSFORM_HOOK.
The following hooks can ONLY be added globally:● TS_HTTP_SELECT_ALT_HOOK● TS_HTTP_SSN_START_HOOK● TS_HTTP_SSN_CLOSE_HOOK
Hook RegistrationTSHttpSsnHookAdd: adds a transaction hook to each transaction within a session.TSHttpTxnHookAdd: adds a callback at a specific point within an HTTP transaction.
Hooks● TS_HTTP_READ_REQUEST_HDR_HOOK● TS_HTTP_OS_DNS_HOOK● TS_HTTP_SEND_REQUEST_HDR_HOOK● TS_HTTP_READ_CACHE_HDR_HOOK● TS_HTTP_READ_RESPONSE_HDR_HOOK● TS_HTTP_SEND_RESPONSE_HDR_HOOK● TS_HTTP_REQUEST_TRANSFORM_HOOK● TS_HTTP_RESPONSE_TRANSFORM_HOOK● TS_HTTP_SELECT_ALT_HOOK● TS_HTTP_TXN_START_HOOK● TS_HTTP_TXN_CLOSE_HOOK● TS_HTTP_SSN_START_HOOK● TS_HTTP_SSN_CLOSE_HOOK● TS_HTTP_CACHE_LOOKUP_COMPLETE_HOOK● TS_HTTP_PRE_REMAP_HOOK● TS_HTTP_POST_REMAP_HOOK
Hooks
Hooks
Hooks
Doing the work
The Continuationstatic int
my_cont_func(TSCont cont, TSEvent event, void *edata){ TSHttpTxn txn = (TSHttpTxn) edata; MyStateInfo state; MyTxnInfo tinfo;
switch (event) {
The Continuationstatic int
my_cont_func(TSCont cont, TSEvent event, void *edata){ ... case TS_EVENT_HTTP_READ_REQUEST_HDR: if (TSHttpIsInternalRequest(txn) != TS_SUCCESS) { tinfo = TSmalloc(sizeof(MyTxnInfo)); time(&tinfo->txn_start); tinfo->req_info = my_get_req_info(txn); state = (MyStateInfo *) TSContDataGet(cont); TSHttpTxnArgSet(txn, state->txn_slot, (void *) tinfo); TSHttpTxnHookAdd(txn, TS_HTTP_CACHE_LOOKUP_COMPLETE_HOOK, cont); } TSHttpTxnReenable(txn, TS_EVENT_HTTP_CONTINUE); break;
The Continuationstatic int
my_cont_func(TSCont cont, TSEvent event, void *edata){ ... case TS_EVENT_HTTP_CACHE_LOOKUP_COMPLETE: state = (MyStateInfo *) TSContDataGet(cont); tinfo = (MyStateInfo *) TSHttpTxnArgGet(txn, state->txn_slot); if (TSHttpTxnCacheLookupStatusGet(txn, &status) == TS_SUCCESS) { if (status == TS_CACHE_LOOKUP_HIT_STALE) {
ContinuationsTSCont TSContCreate(TSEventFunc funcp, TSMutex mutexp);
void TSContDestroy(TSCont contp);
void TSContDataSet(TSCont contp, void* data);
void* TSContDataGet(TSCont contp);
TSAction TSContSchedule(TSCont contp, TSHRTime timeout, TSThreadPool tp);
TSAction TSContScheduleEvery(TSCont contp, TSHRTime every, TSThreadPool tp);
TSAction TSHttpSchedule(TSCont contp, TSHttpTxn txnp, TSHRTime timeout);
int TSContCall(TSCont contp, TSEvent event, void* edata);
TSMutex TSContMutexGet(TSCont contp);
TransactionsA Request and the associated
response
void TSHttpTxnHookAdd(TSHttpTxn txnp, TSHttpHookID id, TSCont contp);
void TSHttpTxnReenable(TSHttpTxn txnp, TSEvent event);
TransactionsGets the client request header for a specified HTTP
transaction:TSReturnCode TSHttpTxnClientReqGet(TSHttpTxn txnp, TSMBuffer*
bufp, TSMLoc* offset);
Gets the client response header for a specified HTTP transaction:
TSReturnCode TSHttpTxnClientRespGet(TSHttpTxn txnp, TSMBuffer* bufp, TSMLoc* offset);
Gets the server request header from a specified HTTP transaction:
TSReturnCode TSHttpTxnServerReqGet(TSHttpTxn txnp, TSMBuffer* bufp, TSMLoc* offset);
TransactionsGets the server response header from a specified HTTP
transaction:TSReturnCode TSHttpTxnServerRespGet(TSHttpTxn txnp,
TSMBuffer* bufp, TSMLoc* offset);
Gets the cached request header for a specified HTTP transaction:
TSReturnCode TSHttpTxnCachedReqGet(TSHttpTxn txnp, TSMBuffer* bufp, TSMLoc* offset);
Gets the cached response header for a specified HTTP transaction:
TSReturnCode TSHttpTxnCachedRespGet(TSHttpTxn txnp, TSMBuffer* bufp, TSMLoc* offset);
Transaction DataTSReturnCode TSHttpArgIndexReserve(const char* name, const char* description, int* arg_idx);
TSReturnCode TSHttpArgIndexNameLookup(const char* name, int* arg_idx, const char** description);
TSReturnCode TSHttpArgIndexLookup(int arg_idx, const char** name, const char** description);
void TSHttpTxnArgSet(TSHttpTxn txnp, int arg_idx, void* arg);
void* TSHttpTxnArgGet(TSHttpTxn txnp, int arg_idx);
void TSHttpSsnArgSet(TSHttpSsn ssnp, int arg_idx, void* arg);
void* TSHttpSsnArgGet(TSHttpSsn ssnp, int arg_idx);
Sessionsvoid TSHttpSsnHookAdd(TSHttpSsn ssnp, TSHttpHookID id, TSCont contp);
void TSHttpSsnReenable(TSHttpSsn ssnp, TSEvent event);
int TSHttpSsnTransactionCount(TSHttpSsn ssnp);
TSHttpSsn TSHttpTxnSsnGet(TSHttpTxn txnp);
Remapping#include <ts/remap.h>
int TSRemapInit(TSRemapInterface *api_info, char *errbuf, int errbuf_size);
int TSRemapNewInstance(int argc, char *argv[], void **ih, char *errbuf, int errbuf_size);
TSRemapStatus TSRemapDoRemap(void* ih, TSHttpTxn rh, TSRemapRequestInfo *rri);
void TSRemapDeleteInstance(void* ih);
void TSRemapOSResponse(void* ih, TSHttpTxn rh, int os_response_type);
Remappingremap.config:
map http://www.example.com/search http://srch1.example.com/search @plugin=query_remap.so@pparam=q@pparam=srch1.example.com @pparam=srch2.example.com @pparam=srch3.example.com
map http://www.example.com/profiles http://prof1.example.com/profiles @plugin=query_remap.so@pparam=user_id@pparam=prof1.example.com @pparam=prof2.example.com
Marshal BuffersTSMBuffer is a heap data structure that
stores parsed:● URLs● HTTP Headers● MIME HeadersTo manipulate these you need a handle to the object (TSMLoc)
Marshal BuffersTSMBuffer TSMBufferCreate(void);
TSReturnCode TSMBufferDestroy(TSMBuffer bufp);
TSReturnCode TSHandleMLocRelease(TSMBuffer bufp, TSMLoc parent, TSMLoc mloc);
URLsTSReturnCode TSUrlCreate(TSMBuffer bufp, TSMLoc* locp);
TSParseResult TSUrlParse(TSMBuffer bufp, TSMLoc offset, const char** start, const char* end);
char* TSUrlStringGet(TSMBuffer bufp, TSMLoc offset, int* length);
int TSUrlPortGet(TSMBuffer bufp, TSMLoc offset);
const char* TSUrlHttpQueryGet(TSMBuffer bufp, TSMLoc offset, int* length);
const char* TSUrlHttpFragmentGet(TSMBuffer bufp, TSMLoc offset, int* length);
HTTP HeadersGET http://www.tiggerwigger.com/ HTTP/1.0Proxy-Connection: Keep-AliveUser-Agent: Mozilla/5.0 [en] (X11; I; Linux 2.2.3 i686)Host: www.tiggerwigger.comAccept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*Accept-Encoding: gzipAccept-Language: enAccept-Charset: iso-8859-1, *, utf-8
HTTP/1.0 200 OKDate: Fri, 13 Nov 2009 06:57:43 GMTContent-Location: http://locutus.tiggerwigger.com/index.htmlEtag: "07db14afa76be1:1074"Last-Modified: Thu, 05 Nov 2009 20:01:38 GMTContent-Length: 7931Content-Type: text/htmlServer: Microsoft-IIS/4.0Age: 922Proxy-Connection: close
HTTP HeadersTSMLoc TSHttpHdrCreate(TSMBuffer bufp);
void TSHttpHdrDestroy(TSMBuffer bufp, TSMLoc offset);
TSHttpType TSHttpHdrTypeGet(TSMBuffer bufp, TSMLoc offset);
int TSHttpHdrVersionGet(TSMBuffer bufp, TSMLoc offset);
const char* TSHttpHdrMethodGet(TSMBuffer bufp, TSMLoc offset, int* length);
TSReturnCode TSHttpHdrUrlGet(TSMBuffer bufp, TSMLoc offset, TSMLoc* locp);
TSHttpStatus TSHttpHdrStatusGet(TSMBuffer bufp, TSMLoc offset);
const char* TSHttpHdrReasonGet(TSMBuffer bufp, TSMLoc offset, int* length);
MIME HeadersTSReturnCode TSMimeHdrCreate(TSMBuffer bufp, TSMLoc* locp);
TSReturnCode TSMimeHdrDestroy(TSMBuffer bufp, TSMLoc offset);
TSParseResult TSMimeHdrParse(TSMimeParser parser, TSMBuffer bufp, TSMLoc offset, const char** start, const char* end);
MIME Header FieldsTSReturnCode TSMimeHdrFieldCreate(TSMBuffer bufp, TSMLoc hdr, TSMLoc* locp);
TSReturnCode TSMimeHdrFieldCreateNamed(TSMBuffer bufp, TSMLoc mh_mloc, const char* name, int name_len, TSMLoc* locp);
TSReturnCode TSMimeHdrFieldDestroy(TSMBuffer bufp, TSMLoc hdr, TSMLoc field);
int TSMimeHdrFieldsCount(TSMBuffer bufp, TSMLoc offset);
TSMLoc TSMimeHdrFieldGet(TSMBuffer bufp, TSMLoc hdr, int idx);
TSMLoc TSMimeHdrFieldFind(TSMBuffer bufp, TSMLoc hdr, const char* name, int length);
TSMLoc TSMimeHdrFieldNext(TSMBuffer bufp, TSMLoc hdr, TSMLoc field);
MIME Hdr Fld Valsint TSMimeHdrFieldValuesCount(TSMBuffer bufp, TSMLoc hdr, TSMLoc field);
const char* TSMimeHdrFieldValueStringGet(TSMBuffer bufp, TSMLoc hdr, TSMLoc field, int idx, int* value_len_ptr);
time_t TSMimeHdrFieldValueDateGet(TSMBuffer bufp, TSMLoc hdr, TSMLoc field);
TSReturnCode TSMimeHdrFieldValueDelete(TSMBuffer bufp, TSMLoc hdr, TSMLoc field, int idx);
VConnections● Specialized Continuation● Abstraction for async IO● You read from or write to a VConn
VConnectionsint TSVConnClosedGet(TSVConn connp);
TSVIO TSVConnRead(TSVConn connp, TSCont contp, TSIOBuffer bufp, int64_t nbytes);
TSVIO TSVConnWrite(TSVConn connp, TSCont contp, TSIOBufferReader readerp, int64_t nbytes);
void TSVConnClose(TSVConn connp);
void TSVConnAbort(TSVConn connp, int error);
void TSVConnShutdown(TSVConn connp, int read, int write);
IOBuffers● TSIOBuffer transfers data to/from a
VConn● A TSIOBuffer has TSIOBufferBlock's● A TSIOBufferBlock has TSIOBufferData's● One writer but can be multiple readers● Readers need no knowledge of each
other and coordinate through a TSIOBufferReader
IOBuffersTSIOBuffer TSIOBufferCreate(void);
TSIOBuffer TSIOBufferSizedCreate(TSIOBufferSizeIndex index);
void TSIOBufferWaterMarkSet(TSIOBuffer bufp, int64_t water_mark);
void TSIOBufferDestroy(TSIOBuffer bufp);
int64_t TSIOBufferCopy(TSIOBuffer bufp, TSIOBufferReader readerp, int64_t length, int64_t offset);
int64_t TSIOBufferWrite(TSIOBuffer bufp, const void* buf, int64_t length);
IOBuffer ReadersTSIOBufferReader TSIOBufferReaderAlloc(TSIOBuffer bufp);
void TSIOBufferReaderFree(TSIOBufferReader readerp);
VIOs● State of the IO transaction● Every VConn has an input and output
VIO
VIOsvoid TSVIOReenable(TSVIO viop);
TSIOBuffer TSVIOBufferGet(TSVIO viop);
TSIOBufferReader TSVIOReaderGet(TSVIO viop);
int64_t TSVIONBytesGet(TSVIO viop);
void TSVIONBytesSet(TSVIO viop, int64_t nbytes);
int64_t TSVIONDoneGet(TSVIO viop);
void TSVIONDoneSet(TSVIO viop, int64_t ndone);
int64_t TSVIONTodoGet(TSVIO viop);
TSVConn TSVIOVConnGet(TSVIO viop);
TransformsTSVConn TSTransformCreate(TSEventFunc event_funcp, TSHttpTxn txnp);
TSVConn TSTransformOutputVConnGet(TSVConn connp);
Transformsstatic inttransform_plugin(TSCont contp, TSEvent event, void *edata){ TSHttpTxn txnp = (TSHttpTxn) edata; TSVConn connp;
switch (event) { case TS_EVENT_HTTP_READ_RESPONSE_HDR: connp = TSTransformCreate(bnull_transform, txnp); TSHttpTxnHookAdd(txnp, TS_HTTP_RESPONSE_TRANSFORM_HOOK, connp);
Actionsvoid TSActionCancel(TSAction actionp);
int TSActionDone(TSAction actionp);
Alternate SelectionTSReturnCode TSHttpAltInfoClientReqGet(TSHttpAltInfo infop, TSMBuffer* bufp, TSMLoc* offset);
TSReturnCode TSHttpAltInfoCachedReqGet(TSHttpAltInfo infop, TSMBuffer* bufp, TSMLoc* offset);
TSReturnCode TSHttpAltInfoCachedRespGet(TSHttpAltInfo infop, TSMBuffer* bufp, TSMLoc* offset);
void TSHttpAltInfoQualitySet(TSHttpAltInfo infop, float quality);
Statisticsint TSStatCreate(const char* the_name, TSRecordDataType the_type, TSStatPersistence persist, TSStatSync sync);
void TSStatIntIncrement(int the_stat, TSMgmtInt amount);
void TSStatIntDecrement(int the_stat, TSMgmtInt amount);
TSMgmtInt TSStatIntGet(int the_stat);
void TSStatIntSet(int the_stat, TSMgmtInt value);
Threadstypedef void *(*TSThreadFunc) (void* data);
TSThread TSThreadCreate(TSThreadFunc func, void* data);
TSThread TSThreadInit(void);
void TSThreadDestroy(TSThread thread);
TSThread TSThreadSelf(void);
MutexesTSMutex my_mutex;
my_mutex = TSMutexCreate();
TSMutexLock(my_mutex);
...
TSMutexUnlock(my_mutex);
TSReturnCode rc;
rc = TSMutexLockTry(my_mutex);
Memory Mgmtvoid* TSmalloc(size_t size, const char* path);
void* TSrealloc(void* ptr, size_t size, const char* path);
char* TSstrdup(const char* str, int64_t length, const char* path);
size_t TSstrlcpy(char *dst, const char *str, size_t siz);
size_t TSstrlcat(char *dst, const char *str, size_t siz);
void TSfree(void* ptr);
Loggingvoid TSDebug(const char* tag, const char* format_str, ...);
void TSError(const char* fmt, ...);
TSTextLogObject
TSReturnCode TSTextLogObjectCreate(const char* filename, int mode, TSTextLogObject* new_log_obj);
TSReturnCode TSTextLogObjectWrite(TSTextLogObject the_object, const char* format, ...);
Cache APITSCacheKey TSCacheKeyCreate(void);
TSReturnCode TSCacheKeyDigestSet(TSCacheKey key, const char* input, int length);
TSReturnCode TSCacheKeyDestroy(TSCacheKey key);
TSAction TSCacheRead(TSCont contp, TSCacheKey key);
TSAction TSCacheWrite(TSCont contp, TSCacheKey key);
TSAction TSCacheRemove(TSCont contp, TSCacheKey key);
Compiling
tsxs -I/usr/lib/include -lfoo -c plugin.c -o plugin.so
tsxs -i -o plugin.so
Questions?
Email: [email protected]: @PhilSorberIRC: PSUdaemon in freenode/#traffic-
server
Come find me with your questions!