/** @file A brief file description @section license License Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ /***************************************************************************** * Filename: InkMgmtAPI.cc * Purpose: This file implements all traffic server management functions. * Created: 9/11/00 * Created by: Lan Tran * * ***************************************************************************/ #include "tscore/ink_platform.h" #include "tscore/ink_code.h" #include "tscore/ink_memory.h" #include "tscore/ParseRules.h" #include #include "tscore/I_Layout.h" #include "mgmtapi.h" #include "CoreAPI.h" #include "CoreAPIShared.h" #include "tscore/TextBuffer.h" /*************************************************************************** * API Memory Management ***************************************************************************/ void * _TSmalloc(unsigned int size, const char * /* path ATS_UNUSED */) { return ats_malloc(size); } void * _TSrealloc(void *ptr, unsigned int size, const char * /* path ATS_UNUSED */) { return ats_realloc(ptr, size); } char * _TSstrdup(const char *str, int length, const char * /* path ATS_UNUSED */) { return ats_strndup(str, length); } void _TSfree(void *ptr) { ats_free(ptr); } /*************************************************************************** * API Helper Functions for Data Carrier Structures ***************************************************************************/ /*--- TSList operations -------------------------------------------------*/ tsapi TSList TSListCreate(void) { return (void *)create_queue(); } /* NOTE: The List must be EMPTY */ tsapi void TSListDestroy(TSList l) { if (!l) { return; } delete_queue(static_cast(l)); return; } tsapi TSMgmtError TSListEnqueue(TSList l, void *data) { int ret; ink_assert(l && data); if (!l || !data) { return TS_ERR_PARAMS; } ret = enqueue(static_cast(l), data); /* returns TRUE=1 or FALSE=0 */ if (ret == 0) { return TS_ERR_FAIL; } else { return TS_ERR_OKAY; } } tsapi void * TSListDequeue(TSList l) { ink_assert(l); if (!l || queue_is_empty(static_cast(l))) { return nullptr; } return dequeue(static_cast(l)); } tsapi bool TSListIsEmpty(TSList l) { ink_assert(l); if (!l) { return true; // list doesn't exist, so it's empty } return queue_is_empty(static_cast(l)); } tsapi int TSListLen(TSList l) { ink_assert(l); if (!l) { return -1; } return queue_len(static_cast(l)); } tsapi bool TSListIsValid(TSList l) { int i, len; if (!l) { return false; } len = queue_len(static_cast(l)); for (i = 0; i < len; i++) { void *ele = dequeue(static_cast(l)); if (!ele) { return false; } enqueue(static_cast(l), ele); } return true; } /*--- TSStringList operations --------------------------------------*/ tsapi TSStringList TSStringListCreate() { return (void *)create_queue(); /* this queue will be a list of char* */ } /* usually, must be an empty list before destroying*/ tsapi void TSStringListDestroy(TSStringList strl) { if (!strl) { return; } /* dequeue each element and free it */ while (!queue_is_empty(static_cast(strl))) { char *str = static_cast(dequeue(static_cast(strl))); ats_free(str); } delete_queue(static_cast(strl)); } tsapi TSMgmtError TSStringListEnqueue(TSStringList strl, char *str) { int ret; ink_assert(strl && str); if (!strl || !str) { return TS_ERR_PARAMS; } ret = enqueue(static_cast(strl), str); /* returns TRUE=1 or FALSE=0 */ if (ret == 0) { return TS_ERR_FAIL; } else { return TS_ERR_OKAY; } } tsapi char * TSStringListDequeue(TSStringList strl) { ink_assert(strl); if (!strl || queue_is_empty(static_cast(strl))) { return nullptr; } return static_cast(dequeue(static_cast(strl))); } tsapi bool TSStringListIsEmpty(TSStringList strl) { ink_assert(strl); if (!strl) { return true; } return queue_is_empty(static_cast(strl)); } tsapi int TSStringListLen(TSStringList strl) { ink_assert(strl); if (!strl) { return -1; } return queue_len(static_cast(strl)); } // returns false if any element is NULL string tsapi bool TSStringListIsValid(TSStringList strl) { int i, len; if (!strl) { return false; } len = queue_len(static_cast(strl)); for (i = 0; i < len; i++) { char *str = static_cast(dequeue(static_cast(strl))); if (!str) { return false; } enqueue(static_cast(strl), str); } return true; } /*--- TSIntList operations --------------------------------------*/ tsapi TSIntList TSIntListCreate() { return (void *)create_queue(); /* this queue will be a list of int* */ } /* usually, must be an empty list before destroying*/ tsapi void TSIntListDestroy(TSIntList intl) { if (!intl) { return; } /* dequeue each element and free it */ while (!queue_is_empty(static_cast(intl))) { int *iPtr = static_cast(dequeue(static_cast(intl))); ats_free(iPtr); } delete_queue(static_cast(intl)); return; } tsapi TSMgmtError TSIntListEnqueue(TSIntList intl, int *elem) { int ret; ink_assert(intl && elem); if (!intl || !elem) { return TS_ERR_PARAMS; } ret = enqueue(static_cast(intl), elem); /* returns TRUE=1 or FALSE=0 */ if (ret == 0) { return TS_ERR_FAIL; } else { return TS_ERR_OKAY; } } tsapi int * TSIntListDequeue(TSIntList intl) { ink_assert(intl); if (!intl || queue_is_empty(static_cast(intl))) { return nullptr; } return static_cast(dequeue(static_cast(intl))); } tsapi bool TSIntListIsEmpty(TSIntList intl) { ink_assert(intl); if (!intl) { return true; } return queue_is_empty(static_cast(intl)); } tsapi int TSIntListLen(TSIntList intl) { ink_assert(intl); if (!intl) { return -1; } return queue_len(static_cast(intl)); } tsapi bool TSIntListIsValid(TSIntList intl, int min, int max) { if (!intl) { return false; } for (unsigned long i = 0; i < queue_len(static_cast(intl)); i++) { int *item = static_cast(dequeue(static_cast(intl))); if (*item < min) { return false; } if (*item > max) { return false; } enqueue(static_cast(intl), item); } return true; } /*--- allocate/deallocate operations --------------------------------------*/ tsapi TSMgmtEvent * TSEventCreate(void) { TSMgmtEvent *event = static_cast(ats_malloc(sizeof(TSMgmtEvent))); event->id = -1; event->name = nullptr; event->description = nullptr; event->priority = TS_EVENT_PRIORITY_UNDEFINED; return event; } tsapi void TSEventDestroy(TSMgmtEvent *event) { if (event) { ats_free(event->name); ats_free(event->description); ats_free(event); } return; } tsapi TSRecordEle * TSRecordEleCreate(void) { TSRecordEle *ele = static_cast(ats_malloc(sizeof(TSRecordEle))); ele->rec_name = nullptr; ele->rec_type = TS_REC_UNDEFINED; return ele; } tsapi void TSRecordEleDestroy(TSRecordEle *ele) { if (ele) { ats_free(ele->rec_name); if (ele->rec_type == TS_REC_STRING && ele->valueT.string_val) { ats_free(ele->valueT.string_val); } ats_free(ele); } return; } /*************************************************************************** * API Core ***************************************************************************/ /*--- host status operations ----------------------------------------------- */ tsapi TSMgmtError TSHostStatusSetUp(const char *host_name, int down_time, const char *reason) { return HostStatusSetUp(host_name, down_time, reason); } tsapi TSMgmtError TSHostStatusSetDown(const char *host_name, int down_time, const char *reason) { return HostStatusSetDown(host_name, down_time, reason); } /*--- statistics operations ----------------------------------------------- */ tsapi TSMgmtError TSStatsReset(const char *name) { return StatsReset(name); } /*--- variable operations ------------------------------------------------- */ /* Call the CfgFileIO variable operations */ tsapi TSMgmtError TSRecordGet(const char *rec_name, TSRecordEle *rec_val) { return MgmtRecordGet(rec_name, rec_val); } TSMgmtError TSRecordGetInt(const char *rec_name, TSInt *int_val) { TSMgmtError ret = TS_ERR_OKAY; TSRecordEle *ele = TSRecordEleCreate(); ret = MgmtRecordGet(rec_name, ele); if (ret != TS_ERR_OKAY) { goto END; } *int_val = ele->valueT.int_val; END: TSRecordEleDestroy(ele); return ret; } TSMgmtError TSRecordGetCounter(const char *rec_name, TSCounter *counter_val) { TSMgmtError ret; TSRecordEle *ele = TSRecordEleCreate(); ret = MgmtRecordGet(rec_name, ele); if (ret != TS_ERR_OKAY) { goto END; } *counter_val = ele->valueT.counter_val; END: TSRecordEleDestroy(ele); return ret; } TSMgmtError TSRecordGetFloat(const char *rec_name, TSFloat *float_val) { TSMgmtError ret; TSRecordEle *ele = TSRecordEleCreate(); ret = MgmtRecordGet(rec_name, ele); if (ret != TS_ERR_OKAY) { goto END; } *float_val = ele->valueT.float_val; END: TSRecordEleDestroy(ele); return ret; } TSMgmtError TSRecordGetString(const char *rec_name, TSString *string_val) { TSMgmtError ret; TSRecordEle *ele = TSRecordEleCreate(); ret = MgmtRecordGet(rec_name, ele); if (ret != TS_ERR_OKAY) { goto END; } *string_val = ats_strdup(ele->valueT.string_val); END: TSRecordEleDestroy(ele); return ret; } /*------------------------------------------------------------------------- * TSRecordGetMlt *------------------------------------------------------------------------- * Purpose: Retrieves list of record values specified in the rec_names list * Input: rec_names - list of record names to retrieve * rec_vals - queue of TSRecordEle* that corresponds to rec_names * Output: If at any point, while retrieving one of the records there's a * a failure then the entire process is aborted, all the allocated * TSRecordEle's are deallocated and TS_ERR_FAIL is returned. * Note: rec_names is not freed; if function is successful, the rec_names * list is unchanged! * * IS THIS FUNCTION AN ATOMIC TRANSACTION? Technically, all the variables * requested should refer to the same config file. But a lock is only * put on each variable it is looked up. Need to be able to lock * a file while retrieving all the requested records! */ tsapi TSMgmtError TSRecordGetMlt(TSStringList rec_names, TSList rec_vals) { int num_recs, i, j; TSMgmtError ret; if (!rec_names || !rec_vals) { return TS_ERR_PARAMS; } num_recs = queue_len(static_cast(rec_names)); for (i = 0; i < num_recs; i++) { char *rec_name = static_cast(dequeue(static_cast(rec_names))); // remove name from list if (!rec_name) { return TS_ERR_PARAMS; // NULL is invalid record name } TSRecordEle *ele = TSRecordEleCreate(); ret = MgmtRecordGet(rec_name, ele); enqueue(static_cast(rec_names), rec_name); // return name to list if (ret != TS_ERR_OKAY) { // RecordGet failed // need to free all the ele's allocated by MgmtRecordGet so far TSRecordEleDestroy(ele); for (j = 0; j < i; j++) { ele = static_cast(dequeue(static_cast(rec_vals))); if (ele) { TSRecordEleDestroy(ele); } } return ret; } enqueue(static_cast(rec_vals), ele); // all is good; add ele to end of list } return TS_ERR_OKAY; } tsapi TSMgmtError TSRecordGetMatchMlt(const char *regex, TSList rec_vals) { if (!regex || !rec_vals) { return TS_ERR_PARAMS; } return MgmtRecordGetMatching(regex, rec_vals); } tsapi TSMgmtError TSRecordSet(const char *rec_name, const char *val, TSActionNeedT *action_need) { return MgmtRecordSet(rec_name, val, action_need); } tsapi TSMgmtError TSRecordSetInt(const char *rec_name, TSInt int_val, TSActionNeedT *action_need) { return MgmtRecordSetInt(rec_name, int_val, action_need); } tsapi TSMgmtError TSRecordSetCounter(const char *rec_name, TSCounter counter_val, TSActionNeedT *action_need) { return MgmtRecordSetCounter(rec_name, counter_val, action_need); } tsapi TSMgmtError TSRecordSetFloat(const char *rec_name, TSFloat float_val, TSActionNeedT *action_need) { return MgmtRecordSetFloat(rec_name, float_val, action_need); } tsapi TSMgmtError TSRecordSetString(const char *rec_name, const char *str_val, TSActionNeedT *action_need) { return MgmtRecordSetString(rec_name, str_val, action_need); } /*------------------------------------------------------------------------- * TSRecordSetMlt *------------------------------------------------------------------------- * Basically iterates through each RecordEle in rec_list and calls the * appropriate "MgmtRecordSetxx" function for that record * Input: rec_list - queue of TSRecordEle*; each TSRecordEle* must have * a valid record name (remains unchanged on return) * Output: if there is an error during the setting of one of the variables then * will continue to try to set the other variables. Error response will * indicate though that not all set operations were successful. * TS_ERR_OKAY is returned if all the records are set successfully * Note: Determining the action needed is more complex b/c need to keep * track of which record change is the most drastic out of the group of * records; action_need will be set to the most severe action needed of * all the "Set" calls */ tsapi TSMgmtError TSRecordSetMlt(TSList rec_list, TSActionNeedT *action_need) { int num_recs, ret, i; TSMgmtError status = TS_ERR_OKAY; TSActionNeedT top_action_req = TS_ACTION_UNDEFINED; if (!rec_list || !action_need) { return TS_ERR_PARAMS; } num_recs = queue_len(static_cast(rec_list)); for (i = 0; i < num_recs; i++) { TSRecordEle *ele = static_cast(dequeue(static_cast(rec_list))); if (ele) { switch (ele->rec_type) { case TS_REC_INT: ret = MgmtRecordSetInt(ele->rec_name, ele->valueT.int_val, action_need); break; case TS_REC_COUNTER: ret = MgmtRecordSetCounter(ele->rec_name, ele->valueT.counter_val, action_need); break; case TS_REC_FLOAT: ret = MgmtRecordSetFloat(ele->rec_name, ele->valueT.float_val, action_need); break; case TS_REC_STRING: ret = MgmtRecordSetString(ele->rec_name, ele->valueT.string_val, action_need); break; default: ret = TS_ERR_FAIL; break; }; /* end of switch (ele->rec_type) */ if (ret != TS_ERR_OKAY) { status = TS_ERR_FAIL; } // keep track of most severe action; reset if needed // the TSActionNeedT should be listed such that most severe actions have // a lower number (so most severe action == 0) if (*action_need < top_action_req) { // a more severe action top_action_req = *action_need; } } enqueue(static_cast(rec_list), ele); } // set the action_need to be the most sever action needed of all the "set" calls *action_need = top_action_req; return status; } /*--- api initialization and shutdown -------------------------------------*/ tsapi TSMgmtError TSInit(const char *socket_path, TSInitOptionT options) { return Init(socket_path, options); } tsapi TSMgmtError TSTerminate() { return Terminate(); } /*--- plugin initialization -----------------------------------------------*/ inkexp extern void TSPluginInit(int /* argc ATS_UNUSED */, const char * /* argv ATS_UNUSED */[]) { } /*--- network operations --------------------------------------------------*/ tsapi TSMgmtError TSConnect(TSIpAddr /* ip_addr ATS_UNUSED */, int /* port ATS_UNUSED */) { return TS_ERR_OKAY; } tsapi TSMgmtError TSDisconnectCbRegister(TSDisconnectFunc * /* func ATS_UNUSED */, void * /* data ATS_UNUSED */) { return TS_ERR_OKAY; } tsapi TSMgmtError TSDisconnectRetrySet(int /* retries ATS_UNUSED */, int /* retry_sleep_msec ATS_UNUSED */) { return TS_ERR_OKAY; } tsapi TSMgmtError TSDisconnect() { return TS_ERR_OKAY; } /*--- control operations --------------------------------------------------*/ /* NOTE: these operations are wrappers that make direct calls to the CoreAPI */ /* TSProxyStateGet: get the proxy state (on/off) * Input: * Output: proxy state (on/off) */ tsapi TSProxyStateT TSProxyStateGet() { return ProxyStateGet(); } /* TSProxyStateSet: set the proxy state (on/off) * Input: proxy_state - set to on/off * clear - start TS with cache clearing option, * when stopping TS should always be TS_CACHE_CLEAR_NONE * Output: TSMgmtError */ tsapi TSMgmtError TSProxyStateSet(TSProxyStateT proxy_state, unsigned clear) { unsigned mask = TS_CACHE_CLEAR_NONE | TS_CACHE_CLEAR_CACHE | TS_CACHE_CLEAR_HOSTDB; if (clear & ~mask) { return TS_ERR_PARAMS; } return ProxyStateSet(proxy_state, static_cast(clear)); } tsapi TSMgmtError TSProxyBacktraceGet(unsigned options, TSString *trace) { if (options != 0) { return TS_ERR_PARAMS; } if (trace == nullptr) { return TS_ERR_PARAMS; } return ServerBacktrace(options, trace); } /* TSReconfigure: tell traffic_server to re-read its configuration files * Input: * Output: TSMgmtError */ tsapi TSMgmtError TSReconfigure() { return Reconfigure(); } /* TSRestart: restarts Traffic Server * Input: options - bitmask of TSRestartOptionT * Output: TSMgmtError */ tsapi TSMgmtError TSRestart(unsigned options) { return Restart(options); } /* TSActionDo: based on TSActionNeedT, will take appropriate action * Input: action - action that needs to be taken * Output: TSMgmtError */ tsapi TSMgmtError TSActionDo(TSActionNeedT action) { TSMgmtError ret; switch (action) { case TS_ACTION_RESTART: ret = Restart(true); // cluster wide by default? break; case TS_ACTION_RECONFIGURE: ret = Reconfigure(); break; case TS_ACTION_DYNAMIC: /* do nothing - change takes effect immediately */ return TS_ERR_OKAY; case TS_ACTION_SHUTDOWN: default: return TS_ERR_FAIL; } return ret; } /* TSBouncer: restarts the traffic_server process(es) * Input: options - bitmask of TSRestartOptionT * Output: TSMgmtError */ tsapi TSMgmtError TSBounce(unsigned options) { return Bounce(options); } tsapi TSMgmtError TSStop(unsigned options) { return Stop(options); } tsapi TSMgmtError TSDrain(unsigned options) { return Drain(options); } tsapi TSMgmtError TSStorageDeviceCmdOffline(const char *dev) { return StorageDeviceCmdOffline(dev); } tsapi TSMgmtError TSLifecycleMessage(const char *tag, void const *data, size_t data_size) { return LifecycleMessage(tag, data, data_size); } /* NOTE: user must deallocate the memory for the string returned */ char * TSGetErrorMessage(TSMgmtError err_id) { char msg[1024]; // need to define a MAX_ERR_MSG_SIZE??? char *err_msg = nullptr; switch (err_id) { case TS_ERR_OKAY: snprintf(msg, sizeof(msg), "[%d] Everything's looking good.", err_id); break; case TS_ERR_READ_FILE: /* Error occur in reading file */ snprintf(msg, sizeof(msg), "[%d] Unable to find/open file for reading.", err_id); break; case TS_ERR_WRITE_FILE: /* Error occur in writing file */ snprintf(msg, sizeof(msg), "[%d] Unable to find/open file for writing.", err_id); break; case TS_ERR_PARSE_CONFIG_RULE: /* Error in parsing configuration file */ snprintf(msg, sizeof(msg), "[%d] Error parsing configuration file.", err_id); break; case TS_ERR_INVALID_CONFIG_RULE: /* Invalid Configuration Rule */ snprintf(msg, sizeof(msg), "[%d] Invalid configuration rule reached.", err_id); break; case TS_ERR_NET_ESTABLISH: snprintf(msg, sizeof(msg), "[%d] Error establishing socket connection.", err_id); break; case TS_ERR_NET_READ: /* Error reading from socket */ snprintf(msg, sizeof(msg), "[%d] Error reading from socket.", err_id); break; case TS_ERR_NET_WRITE: /* Error writing to socket */ snprintf(msg, sizeof(msg), "[%d] Error writing to socket.", err_id); break; case TS_ERR_NET_EOF: /* Hit socket EOF */ snprintf(msg, sizeof(msg), "[%d] Reached socket EOF.", err_id); break; case TS_ERR_NET_TIMEOUT: /* Timed out waiting for socket read */ snprintf(msg, sizeof(msg), "[%d] Timed out waiting for socket read.", err_id); break; case TS_ERR_SYS_CALL: /* Error in sys/utility call, eg.malloc */ snprintf(msg, sizeof(msg), "[%d] Error in basic system/utility call.", err_id); break; case TS_ERR_PARAMS: /* Invalid parameters for a fn */ snprintf(msg, sizeof(msg), "[%d] Invalid parameters passed into function call.", err_id); break; case TS_ERR_FAIL: snprintf(msg, sizeof(msg), "[%d] Generic Fail message (ie. CoreAPI call).", err_id); break; case TS_ERR_NOT_SUPPORTED: snprintf(msg, sizeof(msg), "[%d] Operation not supported on this platform.", err_id); break; case TS_ERR_PERMISSION_DENIED: snprintf(msg, sizeof(msg), "[%d] Operation not permitted.", err_id); break; default: snprintf(msg, sizeof(msg), "[%d] Invalid error type.", err_id); break; } err_msg = ats_strdup(msg); return err_msg; } /* ReadFromUrl: reads a remotely located config file into a buffer * Input: url - remote location of the file * header - a buffer is allocated on the header char* pointer * headerSize - the size of the header buffer is returned * body - a buffer is allocated on the body char* pointer * bodySize - the size of the body buffer is returned * Output: TSMgmtError - TS_ERR_OKAY if succeed, TS_ERR_FAIL otherwise * Obsolete: tsapi TSMgmtError TSReadFromUrl (char *url, char **text, int *size); * NOTE: The URL can be expressed in the following forms: * - http://www.example.com:80/products/network/index.html * - http://www.example.com/products/network/index.html * - http://www.example.com/products/network/ * - http://www.example.com/ * - http://www.example.com * - www.example.com * NOTE: header and headerSize can be NULL */ tsapi TSMgmtError TSReadFromUrl(char *url, char **header, int *headerSize, char **body, int *bodySize) { // return ReadFromUrl(url, header, headerSize, body, bodySize); return TSReadFromUrlEx(url, header, headerSize, body, bodySize, URL_TIMEOUT); } tsapi TSMgmtError TSReadFromUrlEx(const char *url, char **header, int *headerSize, char **body, int *bodySize, int timeout) { int hFD = -1; char *httpHost = nullptr; char *httpPath = nullptr; int httpPort = HTTP_PORT; int bufsize = URL_BUFSIZE; char buffer[URL_BUFSIZE]; char request[BUFSIZE]; char *hdr_temp; char *bdy_temp; TSMgmtError status = TS_ERR_OKAY; // Sanity check if (!url) { return TS_ERR_FAIL; } if (timeout < 0) { timeout = URL_TIMEOUT; } // Chop the protocol part, if it exists const char *doubleSlash = strstr(url, "//"); if (doubleSlash) { url = doubleSlash + 2; // advance two positions to get rid of leading '//' } // the path starts after the first occurrence of '/' const char *tempPath = strstr(url, "/"); char *host_and_port; if (tempPath) { host_and_port = ats_strndup(url, strlen(url) - strlen(tempPath)); tempPath += 1; // advance one position to get rid of leading '/' httpPath = ats_strdup(tempPath); } else { host_and_port = ats_strdup(url); httpPath = ats_strdup(""); } // the port proceed by a ":", if it exists char *colon = strstr(host_and_port, ":"); if (colon) { httpHost = ats_strndup(host_and_port, strlen(host_and_port) - strlen(colon)); colon += 1; // advance one position to get rid of leading ':' httpPort = ink_atoi(colon); if (httpPort <= 0) { httpPort = HTTP_PORT; } } else { httpHost = ats_strdup(host_and_port); } ats_free(host_and_port); hFD = connectDirect(httpHost, httpPort, timeout); if (hFD == -1) { status = TS_ERR_NET_ESTABLISH; goto END; } /* sending the HTTP request via the established socket */ snprintf(request, BUFSIZE, "http://%s:%d/%s", httpHost, httpPort, httpPath); if ((status = sendHTTPRequest(hFD, request, static_cast(timeout))) != TS_ERR_OKAY) { goto END; } memset(buffer, 0, bufsize); /* empty the buffer */ if ((status = readHTTPResponse(hFD, buffer, bufsize, static_cast(timeout))) != TS_ERR_OKAY) { goto END; } if ((status = parseHTTPResponse(buffer, &hdr_temp, headerSize, &bdy_temp, bodySize)) != TS_ERR_OKAY) { goto END; } if (header && headerSize) { *header = ats_strndup(hdr_temp, *headerSize); } *body = ats_strndup(bdy_temp, *bodySize); END: ats_free(httpHost); ats_free(httpPath); return status; } /*--- cache inspector operations -------------------------------------------*/ tsapi TSMgmtError TSLookupFromCacheUrl(TSString url, TSString *info) { TSMgmtError err = TS_ERR_OKAY; int fd; char request[BUFSIZE]; char response[URL_BUFSIZE]; char *header; char *body; int hdr_size; int bdy_size; int timeout = URL_TIMEOUT; TSInt ts_port = 8080; if ((err = TSRecordGetInt("proxy.config.http.server_port", &ts_port)) != TS_ERR_OKAY) { goto END; } if ((fd = connectDirect("localhost", ts_port, timeout)) < 0) { err = TS_ERR_FAIL; goto END; } snprintf(request, BUFSIZE, "http://{cache}/lookup_url?url=%s", url); if ((err = sendHTTPRequest(fd, request, static_cast(timeout))) != TS_ERR_OKAY) { goto END; } memset(response, 0, URL_BUFSIZE); if ((err = readHTTPResponse(fd, response, URL_BUFSIZE, static_cast(timeout))) != TS_ERR_OKAY) { goto END; } if ((err = parseHTTPResponse(response, &header, &hdr_size, &body, &bdy_size)) != TS_ERR_OKAY) { goto END; } *info = ats_strndup(body, bdy_size); END: return err; } tsapi TSMgmtError TSLookupFromCacheUrlRegex(TSString url_regex, TSString *list) { TSMgmtError err = TS_ERR_OKAY; int fd = -1; char request[BUFSIZE]; char response[URL_BUFSIZE]; char *header; char *body; int hdr_size; int bdy_size; int timeout = -1; TSInt ts_port = 8080; if ((err = TSRecordGetInt("proxy.config.http.server_port", &ts_port)) != TS_ERR_OKAY) { goto END; } if ((fd = connectDirect("localhost", ts_port, timeout)) < 0) { err = TS_ERR_FAIL; goto END; } snprintf(request, BUFSIZE, "http://{cache}/lookup_regex?url=%s", url_regex); if ((err = sendHTTPRequest(fd, request, static_cast(timeout))) != TS_ERR_OKAY) { goto END; } memset(response, 0, URL_BUFSIZE); if ((err = readHTTPResponse(fd, response, URL_BUFSIZE, static_cast(timeout))) != TS_ERR_OKAY) { goto END; } if ((err = parseHTTPResponse(response, &header, &hdr_size, &body, &bdy_size)) != TS_ERR_OKAY) { goto END; } *list = ats_strndup(body, bdy_size); END: return err; } tsapi TSMgmtError TSDeleteFromCacheUrl(TSString url, TSString *info) { TSMgmtError err = TS_ERR_OKAY; int fd = -1; char request[BUFSIZE]; char response[URL_BUFSIZE]; char *header; char *body; int hdr_size; int bdy_size; int timeout = URL_TIMEOUT; TSInt ts_port = 8080; if ((err = TSRecordGetInt("proxy.config.http.server_port", &ts_port)) != TS_ERR_OKAY) { goto END; } if ((fd = connectDirect("localhost", ts_port, timeout)) < 0) { err = TS_ERR_FAIL; goto END; } snprintf(request, BUFSIZE, "http://{cache}/delete_url?url=%s", url); if ((err = sendHTTPRequest(fd, request, static_cast(timeout))) != TS_ERR_OKAY) { goto END; } memset(response, 0, URL_BUFSIZE); if ((err = readHTTPResponse(fd, response, URL_BUFSIZE, static_cast(timeout))) != TS_ERR_OKAY) { goto END; } if ((err = parseHTTPResponse(response, &header, &hdr_size, &body, &bdy_size)) != TS_ERR_OKAY) { goto END; } *info = ats_strndup(body, bdy_size); END: return err; } tsapi TSMgmtError TSDeleteFromCacheUrlRegex(TSString url_regex, TSString *list) { TSMgmtError err = TS_ERR_OKAY; int fd = -1; char request[BUFSIZE]; char response[URL_BUFSIZE]; char *header; char *body; int hdr_size; int bdy_size; int timeout = -1; TSInt ts_port = 8080; if ((err = TSRecordGetInt("proxy.config.http.server_port", &ts_port)) != TS_ERR_OKAY) { goto END; } if ((fd = connectDirect("localhost", ts_port, timeout)) < 0) { err = TS_ERR_FAIL; goto END; } snprintf(request, BUFSIZE, "http://{cache}/delete_regex?url=%s", url_regex); if ((err = sendHTTPRequest(fd, request, static_cast(timeout))) != TS_ERR_OKAY) { goto END; } memset(response, 0, URL_BUFSIZE); if ((err = readHTTPResponse(fd, response, URL_BUFSIZE, static_cast(timeout))) != TS_ERR_OKAY) { goto END; } if ((err = parseHTTPResponse(response, &header, &hdr_size, &body, &bdy_size)) != TS_ERR_OKAY) { goto END; } *list = ats_strndup(body, bdy_size); END: return err; } tsapi TSMgmtError TSInvalidateFromCacheUrlRegex(TSString url_regex, TSString *list) { TSMgmtError err = TS_ERR_OKAY; int fd = -1; char request[BUFSIZE]; char response[URL_BUFSIZE]; char *header; char *body; int hdr_size; int bdy_size; int timeout = -1; TSInt ts_port = 8080; if ((err = TSRecordGetInt("proxy.config.http.server_port", &ts_port)) != TS_ERR_OKAY) { goto END; } if ((fd = connectDirect("localhost", ts_port, timeout)) < 0) { err = TS_ERR_FAIL; goto END; } snprintf(request, BUFSIZE, "http://{cache}/invalidate_regex?url=%s", url_regex); if ((err = sendHTTPRequest(fd, request, static_cast(timeout))) != TS_ERR_OKAY) { goto END; } memset(response, 0, URL_BUFSIZE); if ((err = readHTTPResponse(fd, response, URL_BUFSIZE, static_cast(timeout))) != TS_ERR_OKAY) { goto END; } if ((err = parseHTTPResponse(response, &header, &hdr_size, &body, &bdy_size)) != TS_ERR_OKAY) { goto END; } *list = ats_strndup(body, bdy_size); END: return err; } /*--- events --------------------------------------------------------------*/ tsapi TSMgmtError TSEventSignal(char *event_name, ...) { va_list ap; TSMgmtError ret; va_start(ap, event_name); // initialize the argument pointer ap ret = EventSignal(event_name, ap); va_end(ap); return ret; } tsapi TSMgmtError TSEventResolve(const char *event_name) { return EventResolve(event_name); } tsapi TSMgmtError TSActiveEventGetMlt(TSList active_events) { return ActiveEventGetMlt(static_cast(active_events)); } tsapi TSMgmtError TSEventIsActive(char *event_name, bool *is_current) { return EventIsActive(event_name, is_current); } tsapi TSMgmtError TSEventSignalCbRegister(char *event_name, TSEventSignalFunc func, void *data) { return EventSignalCbRegister(event_name, func, data); } tsapi TSMgmtError TSEventSignalCbUnregister(char *event_name, TSEventSignalFunc func) { return EventSignalCbUnregister(event_name, func); } TSConfigRecordDescription * TSConfigRecordDescriptionCreate(void) { TSConfigRecordDescription *val = static_cast(ats_malloc(sizeof(TSConfigRecordDescription))); ink_zero(*val); val->rec_type = TS_REC_UNDEFINED; return val; } void TSConfigRecordDescriptionDestroy(TSConfigRecordDescription *val) { TSConfigRecordDescriptionFree(val); ats_free(val); } void TSConfigRecordDescriptionFree(TSConfigRecordDescription *val) { if (val) { ats_free(val->rec_name); ats_free(val->rec_checkexpr); if (val->rec_type == TS_REC_STRING) { ats_free(val->rec_value.string_val); } ink_zero(*val); val->rec_type = TS_REC_UNDEFINED; } } TSMgmtError TSConfigRecordDescribe(const char *rec_name, unsigned flags, TSConfigRecordDescription *val) { if (!rec_name || !val) { return TS_ERR_PARAMS; } TSConfigRecordDescriptionFree(val); return MgmtConfigRecordDescribe(rec_name, flags, val); } TSMgmtError TSConfigRecordDescribeMatchMlt(const char *rec_regex, unsigned flags, TSList rec_vals) { if (!rec_regex || !rec_vals) { return TS_ERR_PARAMS; } return MgmtConfigRecordDescribeMatching(rec_regex, flags, rec_vals); }