| /** @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 <climits> |
| #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<LLQ *>(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<LLQ *>(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<LLQ *>(l))) { |
| return nullptr; |
| } |
| |
| return dequeue(static_cast<LLQ *>(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<LLQ *>(l)); |
| } |
| |
| tsapi int |
| TSListLen(TSList l) |
| { |
| ink_assert(l); |
| if (!l) { |
| return -1; |
| } |
| |
| return queue_len(static_cast<LLQ *>(l)); |
| } |
| |
| tsapi bool |
| TSListIsValid(TSList l) |
| { |
| int i, len; |
| |
| if (!l) { |
| return false; |
| } |
| |
| len = queue_len(static_cast<LLQ *>(l)); |
| for (i = 0; i < len; i++) { |
| void *ele = dequeue(static_cast<LLQ *>(l)); |
| if (!ele) { |
| return false; |
| } |
| enqueue(static_cast<LLQ *>(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<LLQ *>(strl))) { |
| char *str = static_cast<char *>(dequeue(static_cast<LLQ *>(strl))); |
| ats_free(str); |
| } |
| |
| delete_queue(static_cast<LLQ *>(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<LLQ *>(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<LLQ *>(strl))) { |
| return nullptr; |
| } |
| |
| return static_cast<char *>(dequeue(static_cast<LLQ *>(strl))); |
| } |
| |
| tsapi bool |
| TSStringListIsEmpty(TSStringList strl) |
| { |
| ink_assert(strl); |
| if (!strl) { |
| return true; |
| } |
| |
| return queue_is_empty(static_cast<LLQ *>(strl)); |
| } |
| |
| tsapi int |
| TSStringListLen(TSStringList strl) |
| { |
| ink_assert(strl); |
| if (!strl) { |
| return -1; |
| } |
| |
| return queue_len(static_cast<LLQ *>(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<LLQ *>(strl)); |
| for (i = 0; i < len; i++) { |
| char *str = static_cast<char *>(dequeue(static_cast<LLQ *>(strl))); |
| if (!str) { |
| return false; |
| } |
| enqueue(static_cast<LLQ *>(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<LLQ *>(intl))) { |
| int *iPtr = static_cast<int *>(dequeue(static_cast<LLQ *>(intl))); |
| ats_free(iPtr); |
| } |
| |
| delete_queue(static_cast<LLQ *>(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<LLQ *>(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<LLQ *>(intl))) { |
| return nullptr; |
| } |
| |
| return static_cast<int *>(dequeue(static_cast<LLQ *>(intl))); |
| } |
| |
| tsapi bool |
| TSIntListIsEmpty(TSIntList intl) |
| { |
| ink_assert(intl); |
| if (!intl) { |
| return true; |
| } |
| |
| return queue_is_empty(static_cast<LLQ *>(intl)); |
| } |
| |
| tsapi int |
| TSIntListLen(TSIntList intl) |
| { |
| ink_assert(intl); |
| if (!intl) { |
| return -1; |
| } |
| |
| return queue_len(static_cast<LLQ *>(intl)); |
| } |
| |
| tsapi bool |
| TSIntListIsValid(TSIntList intl, int min, int max) |
| { |
| if (!intl) { |
| return false; |
| } |
| |
| for (unsigned long i = 0; i < queue_len(static_cast<LLQ *>(intl)); i++) { |
| int *item = static_cast<int *>(dequeue(static_cast<LLQ *>(intl))); |
| if (*item < min) { |
| return false; |
| } |
| if (*item > max) { |
| return false; |
| } |
| enqueue(static_cast<LLQ *>(intl), item); |
| } |
| return true; |
| } |
| |
| /*--- allocate/deallocate operations --------------------------------------*/ |
| tsapi TSMgmtEvent * |
| TSEventCreate(void) |
| { |
| TSMgmtEvent *event = static_cast<TSMgmtEvent *>(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<TSRecordEle *>(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<LLQ *>(rec_names)); |
| for (i = 0; i < num_recs; i++) { |
| char *rec_name = static_cast<char *>(dequeue(static_cast<LLQ *>(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<LLQ *>(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<TSRecordEle *>(dequeue(static_cast<LLQ *>(rec_vals))); |
| if (ele) { |
| TSRecordEleDestroy(ele); |
| } |
| } |
| return ret; |
| } |
| enqueue(static_cast<LLQ *>(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<LLQ *>(rec_list)); |
| |
| for (i = 0; i < num_recs; i++) { |
| TSRecordEle *ele = static_cast<TSRecordEle *>(dequeue(static_cast<LLQ *>(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<LLQ *>(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: <none> |
| * 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<TSCacheClearT>(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: <none> |
| * 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<uint64_t>(timeout))) != TS_ERR_OKAY) { |
| goto END; |
| } |
| |
| memset(buffer, 0, bufsize); /* empty the buffer */ |
| if ((status = readHTTPResponse(hFD, buffer, bufsize, static_cast<uint64_t>(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<uint64_t>(timeout))) != TS_ERR_OKAY) { |
| goto END; |
| } |
| |
| memset(response, 0, URL_BUFSIZE); |
| if ((err = readHTTPResponse(fd, response, URL_BUFSIZE, static_cast<uint64_t>(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<uint64_t>(timeout))) != TS_ERR_OKAY) { |
| goto END; |
| } |
| |
| memset(response, 0, URL_BUFSIZE); |
| if ((err = readHTTPResponse(fd, response, URL_BUFSIZE, static_cast<uint64_t>(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<uint64_t>(timeout))) != TS_ERR_OKAY) { |
| goto END; |
| } |
| |
| memset(response, 0, URL_BUFSIZE); |
| if ((err = readHTTPResponse(fd, response, URL_BUFSIZE, static_cast<uint64_t>(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<uint64_t>(timeout))) != TS_ERR_OKAY) { |
| goto END; |
| } |
| |
| memset(response, 0, URL_BUFSIZE); |
| if ((err = readHTTPResponse(fd, response, URL_BUFSIZE, static_cast<uint64_t>(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<uint64_t>(timeout))) != TS_ERR_OKAY) { |
| goto END; |
| } |
| |
| memset(response, 0, URL_BUFSIZE); |
| if ((err = readHTTPResponse(fd, response, URL_BUFSIZE, static_cast<uint64_t>(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<LLQ *>(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<TSConfigRecordDescription *>(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); |
| } |