| /** @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. |
| */ |
| |
| /***************************************************************************** |
| * CoreAPI.cc |
| * |
| * Implementation of many of INKMgmtAPI functions, but from local side. |
| * |
| * |
| ***************************************************************************/ |
| |
| #include "ink_platform.h" |
| #include "Main.h" |
| #include "LocalManager.h" |
| #include "FileManager.h" |
| #include "Rollback.h" |
| #include "RecordsConfig.h" |
| #include "WebMgmtUtils.h" |
| #include "Diags.h" |
| #include "ink_hash_table.h" |
| #include "ExpandingArray.h" |
| //#include "I_AccCrypto.h" |
| |
| #include "CoreAPI.h" |
| #include "CoreAPIShared.h" |
| #include "CfgContextUtils.h" |
| #include "EventCallback.h" |
| #if defined(OEM) |
| #include "INKMgmtAPI.h" |
| #include "CfgContextManager.h" |
| #endif |
| |
| extern int diags_init; // from Main.cc |
| |
| // global variable |
| CallbackTable *local_event_callbacks; |
| |
| /*------------------------------------------------------------------------- |
| * determine_action_need (forward declaration) |
| *------------------------------------------------------------------------- |
| * uses the update type that's stored with the record rec_name to determine |
| * which type of INKActionNeedT to return. |
| */ |
| INKActionNeedT determine_action_need(char *rec_name); |
| |
| /*------------------------------------------------------------------------- |
| * Init |
| *------------------------------------------------------------------------- |
| * performs any necesary initializations for the local API client, |
| * eg. set up global structures; called by the INKMgmtAPI::INKInit() |
| */ |
| INKError |
| Init(char *socket_path) |
| { |
| // socket_path should be null; only applies to remote clients |
| local_event_callbacks = create_callback_table("local_callbacks"); |
| if (!local_event_callbacks) |
| return INK_ERR_SYS_CALL; |
| |
| return INK_ERR_OKAY; |
| } |
| |
| /*------------------------------------------------------------------------- |
| * Terminate |
| *------------------------------------------------------------------------- |
| * performs any necesary cleanup of global structures, etc, |
| * for the local API client, |
| */ |
| INKError |
| Terminate() |
| { |
| delete_callback_table(local_event_callbacks); |
| |
| return INK_ERR_OKAY; |
| } |
| |
| |
| /*------------------------------------------------------------------------- |
| * Diags |
| *------------------------------------------------------------------------- |
| * Uses the Traffic Manager diags object to display the diags output. |
| */ |
| void |
| Diags(INKDiagsT mode, const char *fmt, va_list ap) |
| { |
| // Mapping INKDiagsT to Diags.h:DiagsLevel |
| // Simple casting would work, but not inflexible |
| DiagsLevel level = DL_Undefined; |
| switch (mode) { |
| case INK_DIAG_DIAG: |
| level = DL_Diag; |
| break; |
| case INK_DIAG_DEBUG: |
| level = DL_Debug; |
| break; |
| case INK_DIAG_STATUS: |
| level = DL_Status; |
| break; |
| case INK_DIAG_NOTE: |
| level = DL_Note; |
| break; |
| case INK_DIAG_WARNING: |
| level = DL_Warning; |
| break; |
| case INK_DIAG_ERROR: |
| level = DL_Error; |
| break; |
| case INK_DIAG_FATAL: |
| level = DL_Fatal; |
| break; |
| case INK_DIAG_ALERT: |
| level = DL_Alert; |
| break; |
| case INK_DIAG_EMERGENCY: |
| level = DL_Emergency; |
| break; |
| default: |
| level = DL_Diag; |
| } |
| |
| if (diags_init) { // check that diags is initialized |
| diags->print_va("INKMgmtAPI", level, NULL, NULL, fmt, ap); |
| va_end(ap); |
| } |
| } |
| |
| |
| /*************************************************************************** |
| * Control Operations |
| ***************************************************************************/ |
| /*------------------------------------------------------------------------- |
| * ProxyStateGet |
| *------------------------------------------------------------------------- |
| * return INK_PROXY_OFF if Traffic Server is off. |
| * return INK_PROXY_ON if Traffic Server is on. |
| */ |
| INKProxyStateT |
| ProxyStateGet() |
| { |
| if (!lmgmt->processRunning()) |
| return INK_PROXY_OFF; |
| else |
| return INK_PROXY_ON; |
| } |
| |
| /*------------------------------------------------------------------------- |
| * ProxyStateSet |
| *------------------------------------------------------------------------- |
| * If state == INK_PROXY_ON, will turn on TS (unless it's already running). |
| * If steat == INK_PROXY_OFF, will turn off TS (unless it's already off). |
| * tsArgs - (optional) a string with space delimited options that user |
| * wants to start traffic Server with |
| */ |
| INKError |
| ProxyStateSet(INKProxyStateT state, INKCacheClearT clear) |
| { |
| int i = 0; |
| char tsArgs[MAX_BUF_SIZE]; |
| char *proxy_options; |
| bool found; |
| |
| memset(tsArgs, 0, MAX_BUF_SIZE); |
| |
| switch (state) { |
| case INK_PROXY_OFF: |
| if (!ProxyShutdown()) // from WebMgmtUtils |
| goto Lerror; // unsuccessful shutdown |
| break; |
| case INK_PROXY_ON: |
| if (lmgmt->processRunning()) // already on |
| break; |
| |
| // taken from mgmt2/Main.cc when check the -tsArgs option |
| // Update cmd line overrides/environmental overrides/etc |
| switch (clear) { |
| case INK_CACHE_CLEAR_ON: // traffic_server -K |
| snprintf(tsArgs, sizeof(tsArgs), "-K -M"); |
| break; |
| case INK_CACHE_CLEAR_HOSTDB: // traffic_server -k |
| snprintf(tsArgs, sizeof(tsArgs), "-k -M"); |
| break; |
| case INK_CACHE_CLEAR_OFF: |
| // use default tsargs in records.config |
| int rec_err = RecGetRecordString_Xmalloc("proxy.config.proxy_binary_opts", &proxy_options); |
| found = (rec_err == REC_ERR_OKAY); |
| if (!found) |
| goto Lerror; |
| |
| ink_snprintf(tsArgs, MAX_BUF_SIZE, "%s", proxy_options); |
| xfree(proxy_options); |
| break; |
| } |
| |
| if (strlen(tsArgs) > 0) { /* Passed command line args for proxy */ |
| if (lmgmt->proxy_options) { |
| xfree(lmgmt->proxy_options); |
| } |
| lmgmt->proxy_options = xstrdup(tsArgs); |
| mgmt_log("[ProxyStateSet] Traffic Server Args: '%s'\n", lmgmt->proxy_options); |
| } |
| |
| lmgmt->run_proxy = true; |
| lmgmt->listenForProxy(); |
| do { |
| mgmt_sleep_sec(1); |
| } while (i++ < 20 && (lmgmt->proxy_running == 0)); |
| if (!lmgmt->processRunning()) |
| goto Lerror; |
| break; |
| default: |
| goto Lerror; |
| } |
| |
| return INK_ERR_OKAY; |
| |
| Lerror: |
| return INK_ERR_FAIL; /* failed to set proxy state */ |
| } |
| |
| /*------------------------------------------------------------------------- |
| * Reconfigure |
| *------------------------------------------------------------------------- |
| * Rereads configuration files |
| */ |
| INKError |
| Reconfigure() |
| { |
| configFiles->rereadConfig(); // TM rereads |
| lmgmt->signalEvent(MGMT_EVENT_PLUGIN_CONFIG_UPDATE, "*"); // TS rereads |
| |
| return INK_ERR_OKAY; |
| } |
| |
| /*------------------------------------------------------------------------- |
| * Restart |
| *------------------------------------------------------------------------- |
| * Restarts Traffic Manager. Traffic Cop must be running in order to |
| * restart Traffic Manager!! |
| */ |
| INKError |
| Restart(bool cluster) |
| { |
| if (cluster) { // Enqueue an event to restart the proxies across the cluster |
| // this will kill TM completely;traffic_cop will restart TM/TS |
| lmgmt->ccom->sendClusterMessage(CLUSTER_MSG_SHUTDOWN_MANAGER); |
| } else { // just bounce local proxy |
| lmgmt->mgmtShutdown(0); |
| } |
| |
| return INK_ERR_OKAY; |
| } |
| |
| /*------------------------------------------------------------------------- |
| * HardRestart |
| *------------------------------------------------------------------------- |
| * Cannot be executed locally since it requires a restart of Traffic Cop. |
| * So just return INK_ERR_FAIL. Should only be called by remote API clients. |
| */ |
| INKError |
| HardRestart() |
| { |
| return INK_ERR_FAIL; |
| } |
| |
| |
| /************************************************************************** |
| * RECORD OPERATIONS |
| *************************************************************************/ |
| /*------------------------------------------------------------------------- |
| * MgmtRecordGet |
| *------------------------------------------------------------------------- |
| * rec_ele has allocated memory already but with all empty fields. |
| * The record info associated with rec_name will be returned in rec_ele. |
| */ |
| INKError |
| MgmtRecordGet(char *rec_name, INKRecordEle * rec_ele) |
| { |
| RecDataT rec_type; |
| char rec_val[MAX_BUF_SIZE]; |
| char *str_val; |
| MgmtIntCounter counter_val; |
| MgmtInt int_val; |
| MgmtLLong llong_val; |
| |
| Debug("RecOp", "[MgmtRecordGet] Start\n"); |
| |
| // initialize the record name |
| rec_ele->rec_name = xstrdup(rec_name); |
| memset(rec_val, 0, MAX_BUF_SIZE); |
| |
| // get variable type; returns INVALID if invalid rec_name |
| rec_type = varType(rec_name); |
| switch (rec_type) { |
| case RECD_COUNTER: |
| rec_ele->rec_type = INK_REC_COUNTER; |
| if (!varCounterFromName(rec_name, &(counter_val))) |
| return INK_ERR_FAIL; |
| rec_ele->counter_val = (INKCounter) counter_val; |
| |
| Debug("RecOp", "[MgmtRecordGet] Get Counter Var %s = %d\n", rec_ele->rec_name, rec_ele->counter_val); |
| break; |
| |
| case RECD_INT: |
| rec_ele->rec_type = INK_REC_INT; |
| if (!varIntFromName(rec_name, &(int_val))) |
| return INK_ERR_FAIL; |
| rec_ele->int_val = (INKInt) int_val; |
| |
| Debug("RecOp", "[MgmtRecordGet] Get Int Var %s = %d\n", rec_ele->rec_name, rec_ele->int_val); |
| break; |
| |
| case RECD_LLONG: |
| rec_ele->rec_type = INK_REC_LLONG; |
| if (!varLLongFromName(rec_name, &(llong_val))) |
| return INK_ERR_FAIL; |
| rec_ele->llong_val = (INKLLong) llong_val; |
| |
| Debug("RecOp", "[MgmtRecordGet] Get LLong Var %s = %lld\n", rec_ele->rec_name, rec_ele->llong_val); |
| break; |
| |
| case RECD_FLOAT: |
| rec_ele->rec_type = INK_REC_FLOAT; |
| if (!varFloatFromName(rec_name, &(rec_ele->float_val))) |
| return INK_ERR_FAIL; |
| |
| Debug("RecOp", "[MgmtRecordGet] Get Float Var %s = %f\n", rec_ele->rec_name, rec_ele->float_val); |
| break; |
| |
| case RECD_STRING: |
| if (!varStrFromName(rec_name, rec_val, MAX_BUF_SIZE)) |
| return INK_ERR_FAIL; |
| |
| |
| if (rec_val[0] != '\0') { // non-NULL string value |
| // allocate memory & duplicate string value |
| str_val = xstrdup(rec_val); |
| } else { |
| str_val = xstrdup("NULL"); |
| } |
| |
| rec_ele->rec_type = INK_REC_STRING; |
| rec_ele->string_val = str_val; |
| Debug("RecOp", "[MgmtRecordGet] Get String Var %s = %s\n", rec_ele->rec_name, rec_ele->string_val); |
| break; |
| |
| default: // UNKOWN TYPE |
| Debug("RecOp", "[MgmtRecordGet] Get Failed : %d is Unknown Var type %s\n", rec_type, rec_name); |
| return INK_ERR_FAIL; |
| } |
| |
| return INK_ERR_OKAY; |
| } |
| |
| |
| /*------------------------------------------------------------------------- |
| * determine_action_need (HELPER FN) |
| *------------------------------------------------------------------------- |
| * reads the RecordsConfig info to determine which type of action is needed |
| * when the record rec_name is changed; if the rec_name is invalid, |
| * then returns INK_ACTION_UNDEFINED |
| */ |
| INKActionNeedT |
| determine_action_need(char *rec_name) |
| { |
| int r; // index in RecordsConfig[] |
| RecordUpdateType update_t; |
| |
| // INKqa09916 |
| // the hashtable lookup will return 0 if there is no binding for the |
| // rec_name in the hashtable |
| if (!RecordsConfigIndex->mgmt_hash_table_lookup((char *) rec_name, (void **) &r)) |
| return INK_ACTION_UNDEFINED; // failed to find the rec_name in the records table |
| |
| update_t = RecordsConfig[r].update; |
| |
| switch (update_t) { |
| case RU_NULL: // default:don't know behaviour |
| return INK_ACTION_UNDEFINED; |
| |
| case RU_REREAD: // update dynamically by rereading config files |
| return INK_ACTION_RECONFIGURE; |
| |
| case RU_RESTART_TS: // requires TS restart |
| return INK_ACTION_RESTART; |
| |
| case RU_RESTART_TM: // requirs TM/TS restart |
| return INK_ACTION_RESTART; |
| |
| case RU_RESTART_TC: // requires TC/TM/TS restart |
| return INK_ACTION_SHUTDOWN; |
| default: // shouldn't get here actually |
| return INK_ACTION_UNDEFINED; |
| } |
| return INK_ACTION_UNDEFINED; // ERROR |
| } |
| |
| |
| /*------------------------------------------------------------------------- |
| * MgmtRecordSet |
| *------------------------------------------------------------------------- |
| * Uses bool WebMgmtUtils::varSetFromStr(const char*, const char* ) |
| * Sets the named local manager variable from the value string |
| * passed in. Does the appropriate type conversion on |
| * value string to get it to the type of the local manager |
| * variable |
| * |
| * returns true if the variable was successfully set |
| * and false otherwise |
| */ |
| INKError |
| MgmtRecordSet(char *rec_name, char *val, INKActionNeedT * action_need) |
| { |
| Debug("RecOp", "[MgmtRecordSet] Start\n"); |
| |
| if (!rec_name || !val || !action_need) |
| return INK_ERR_PARAMS; |
| |
| *action_need = determine_action_need(rec_name); |
| |
| if (recordValidityCheck(rec_name, val)) { |
| if (varSetFromStr(rec_name, val)) |
| return INK_ERR_OKAY; |
| } |
| |
| return INK_ERR_FAIL; |
| } |
| |
| |
| /*------------------------------------------------------------------------- |
| * MgmtRecordSetInt |
| *------------------------------------------------------------------------- |
| * Use the record's name to look up the record value and its type. |
| * Returns INK_ERR_FAIL if the type is not a valid integer. |
| * Converts the integer value to a string and call MgmtRecordSet |
| */ |
| INKError |
| MgmtRecordSetInt(char *rec_name, MgmtInt int_val, INKActionNeedT * action_need) |
| { |
| if (!rec_name || !action_need) |
| return INK_ERR_PARAMS; |
| |
| // convert int value to string for validity check |
| char str_val[MAX_RECORD_SIZE]; |
| |
| memset(str_val, 0, MAX_RECORD_SIZE); |
| snprintf(str_val, sizeof(str_val), "%lld", int_val); |
| |
| return MgmtRecordSet(rec_name, str_val, action_need); |
| |
| /* INKqa10300 |
| *action_need = determine_action_need(rec_name); |
| if (recordValidityCheck(rec_name, str_val)) { |
| if (varSetInt(rec_name, int_val)) |
| return INK_ERR_OKAY; |
| } |
| return INK_ERR_FAIL; |
| */ |
| } |
| |
| |
| /*------------------------------------------------------------------------- |
| * MgmtRecordSetCounter |
| *------------------------------------------------------------------------- |
| * converts the counter_val to a string and uses MgmtRecordSet |
| */ |
| INKError |
| MgmtRecordSetCounter(char *rec_name, MgmtIntCounter counter_val, INKActionNeedT * action_need) |
| { |
| if (!rec_name || !action_need) |
| return INK_ERR_PARAMS; |
| |
| // convert int value to string for validity check |
| char str_val[MAX_RECORD_SIZE]; |
| |
| memset(str_val, 0, MAX_RECORD_SIZE); |
| snprintf(str_val, sizeof(str_val), "%lld", counter_val); |
| |
| return MgmtRecordSet(rec_name, str_val, action_need); |
| |
| /* INKqa10300 |
| *action_need = determine_action_need(rec_name); |
| if (recordValidityCheck(rec_name, str_val)) { |
| if (varSetCounter(rec_name, counter_val)) |
| return INK_ERR_OKAY; |
| } |
| return INK_ERR_FAIL; |
| */ |
| } |
| |
| |
| /*------------------------------------------------------------------------- |
| * MgmtRecordSetFloat |
| *------------------------------------------------------------------------- |
| * converts the float value to string (to do record validity check) |
| * and calls MgmtRecordSet |
| */ |
| INKError |
| MgmtRecordSetFloat(char *rec_name, MgmtFloat float_val, INKActionNeedT * action_need) |
| { |
| if (!rec_name || !action_need) |
| return INK_ERR_PARAMS; |
| |
| // convert float value to string for validity check |
| char str_val[MAX_RECORD_SIZE]; |
| |
| memset(str_val, 0, MAX_RECORD_SIZE); |
| snprintf(str_val, sizeof(str_val), "%f", float_val); |
| |
| return MgmtRecordSet(rec_name, str_val, action_need); |
| |
| /* INKqa10300 |
| *action_need = determine_action_need(rec_name); |
| if (recordValidityCheck(rec_name, str_val)) { |
| if (varSetFloat(rec_name, float_val)) |
| return INK_ERR_OKAY; |
| } |
| return INK_ERR_FAIL; |
| */ |
| } |
| |
| |
| /*------------------------------------------------------------------------- |
| * MgmtRecordSetString |
| *------------------------------------------------------------------------- |
| * The string value is copied so it's okay to free the string later |
| */ |
| INKError |
| MgmtRecordSetString(char *rec_name, INKString string_val, INKActionNeedT * action_need) |
| { |
| return MgmtRecordSet(rec_name, string_val, action_need); |
| } |
| |
| |
| /************************************************************************** |
| * FILE OPERATIONS |
| *************************************************************************/ |
| |
| /*------------------------------------------------------------------------- |
| * ReadFile (MgmtAPILocal::get_lines_from_file) |
| *------------------------------------------------------------------------- |
| * Purpose: returns copy of the most recent version of the file |
| * Input: file - the config file to read |
| * text - a buffer is allocated on the text char* pointer |
| * size - the size of the buffer is returned |
| * ver - the version number of file being read |
| * Note: CALLEE must DEALLOCATE text memory returned |
| */ |
| INKError |
| ReadFile(INKFileNameT file, char **text, int *size, int *version) |
| { |
| char *fname; |
| Rollback *file_rb; |
| int ret, old_file_len; |
| textBuffer *old_file_content; |
| char *old_file_lines; |
| version_t ver; |
| |
| Debug("FileOp", "[get_lines_from_file] START\n"); |
| |
| #if defined(OEM) |
| if (file == INK_FNAME_RMSERVER) { |
| char *fileBuff, *NfileBuff, *ps; |
| Tokenizer lineTok("\n"); |
| tok_iter_state lineTok_state; |
| char *line; |
| long NfileBuffsize; |
| int llength; |
| char *new_line; |
| |
| if ((ReadRmCfgFile(&fileBuff)) != INK_ERR_OKAY) { |
| return INK_ERR_FAIL; |
| } |
| // Debug("config", "Filebuff size :%d\n", strlen(fileBuff)); |
| NfileBuffsize = strlen(fileBuff) * 2; |
| NfileBuff = new char[NfileBuffsize]; |
| memset((void *) NfileBuff, 0, NfileBuffsize); |
| lineTok.Initialize(fileBuff); |
| |
| line = (char *) lineTok.iterFirst(&lineTok_state); |
| ps = NfileBuff; |
| while (line) { |
| if (strstr(line, RM_ADMIN_PORT)) { |
| new_line = RmdeXMLize(line, &llength); |
| sprintf(ps, "%s", new_line); |
| if (!new_line) { |
| xfree(new_line); |
| } |
| ps += llength; |
| } else if (strstr(line, RM_LISTTAG_SCU_ADMIN)) { |
| sprintf(ps, "#%s\n", line); |
| ps += strlen(line) + 2; |
| RmReadCfgList(&lineTok, &lineTok_state, &ps, INK_RM_LISTTAG_SCU_ADMIN); |
| } else if (strstr(line, RM_LISTTAG_CNN_REALM)) { |
| sprintf(ps, "#%s\n", line); |
| ps += strlen(line) + 2; |
| RmReadCfgList(&lineTok, &lineTok_state, &ps, INK_RM_LISTTAG_CNN_REALM); |
| } else if (strstr(line, RM_LISTTAG_ADMIN_FILE)) { |
| sprintf(ps, "#%s\n", line); |
| ps += strlen(line) + 2; |
| RmReadCfgList(&lineTok, &lineTok_state, &ps, INK_RM_LISTTAG_ADMIN_FILE); |
| } else if (strstr(line, RM_LISTTAG_AUTH)) { |
| sprintf(ps, "#%s\n", line); |
| ps += strlen(line) + 2; |
| RmReadCfgList(&lineTok, &lineTok_state, &ps, INK_RM_LISTTAG_AUTH); |
| } else if (strstr(line, RM_LISTTAG_PROXY)) { |
| sprintf(ps, "#%s\n", line); |
| ps += strlen(line) + 2; |
| RmReadCfgList(&lineTok, &lineTok_state, &ps, INK_RM_LISTTAG_PROXY); |
| } else if (strstr(line, RM_LISTTAG_PNA_RDT)) { |
| sprintf(ps, "#%s\n", line); |
| ps += strlen(line) + 2; |
| RmReadCfgList(&lineTok, &lineTok_state, &ps, INK_RM_LISTTAG_PNA_RDT); |
| } else { |
| sprintf(ps, "#%s\n", line); |
| ps += strlen(line) + 2; |
| } |
| line = (char *) lineTok.iterNext(&lineTok_state); |
| } |
| delete[]fileBuff; |
| *text = NfileBuff; |
| *size = NfileBuffsize; |
| *version = 1; |
| return INK_ERR_OKAY; |
| } |
| #endif |
| |
| fname = filename_to_string(file); |
| if (!fname) |
| return INK_ERR_READ_FILE; |
| |
| ret = configFiles->getRollbackObj(fname, &file_rb); |
| if (ret != TRUE) { |
| Debug("FileOp", "[get_lines_from_file] Can't get Rollback for file: %s\n", fname); |
| xfree(fname); |
| return INK_ERR_READ_FILE; |
| } |
| xfree(fname); |
| ver = file_rb->getCurrentVersion(); |
| file_rb->getVersion(ver, &old_file_content); |
| *version = ver; |
| |
| // don't need to allocate memory b/c "getVersion" allocates memory |
| #ifdef _WIN32 // BZ48741 |
| convertHtmlToUnix(old_file_content->bufPtr()); |
| #endif |
| old_file_lines = old_file_content->bufPtr(); |
| old_file_len = strlen(old_file_lines); |
| |
| *text = xstrdup(old_file_lines); //make copy before deleting textBuffer |
| *size = old_file_len; |
| |
| delete old_file_content; // delete textBuffer |
| |
| return INK_ERR_OKAY; |
| } |
| |
| /*------------------------------------------------------------------------- |
| * WriteFile |
| *------------------------------------------------------------------------- |
| * Purpose: replaces the current file with the file passed in; |
| * does forceUpdate for Rollback and FileManager so correct file |
| * versioning is maintained |
| * Input: file - the config file to write |
| * text - text buffer to write |
| * size - the size of the buffer to write |
| * version - the current version level; new file will have the |
| * version number above this one |
| */ |
| INKError |
| WriteFile(INKFileNameT file, char *text, int size, int version) |
| { |
| char *fname; |
| Rollback *file_rb; |
| textBuffer *file_content; |
| int ret; |
| version_t ver; |
| |
| #if defined(OEM) |
| if (file == INK_FNAME_RMSERVER) { |
| char *NfileBuff, *ps; |
| Tokenizer lineTok("\n"); |
| tok_iter_state lineTok_state; |
| char *line, *new_line; |
| int llength; |
| long NfileBuffsize; |
| |
| lineTok.Initialize(text); |
| line = (char *) lineTok.iterFirst(&lineTok_state); |
| NfileBuffsize = strlen(text) * 2; |
| NfileBuff = new char[NfileBuffsize]; |
| memset((void *) NfileBuff, 0, NfileBuffsize); |
| ps = NfileBuff; |
| while (line) { |
| if (*line == '#') { |
| sprintf(ps, "%s\n", line + 1); /* need this \n, since the old \n is used by tokenizer */ |
| ps += strlen(line); |
| } else { |
| new_line = RmXMLize(line, &llength); |
| sprintf(ps, "%s", new_line); |
| if (!new_line) { |
| xfree(new_line); |
| } |
| ps += llength; |
| } |
| line = (char *) lineTok.iterNext(&lineTok_state); |
| } |
| if (WriteRmCfgFile(NfileBuff) != INK_ERR_OKAY) { |
| delete[]NfileBuff; |
| return INK_ERR_WRITE_FILE; |
| } |
| delete[]NfileBuff; |
| return INK_ERR_OKAY; |
| } |
| #endif |
| |
| fname = filename_to_string(file); |
| if (!fname) |
| return INK_ERR_WRITE_FILE; |
| |
| // get rollback object for config file |
| mgmt_log(stderr, "[CfgFileIO::WriteFile] %s\n", fname); |
| if (!(configFiles->getRollbackObj(fname, &file_rb))) { |
| mgmt_log(stderr, "[CfgFileIO::WriteFile] ERROR getting rollback object\n"); |
| //goto generate_error_msg; |
| } |
| xfree(fname); |
| |
| // if version < 0 then, just use next version in sequence; |
| // otherwise check if trying to commit an old version |
| if (version >= 0) { |
| // check that the current version is equal to or less than the version |
| // that wants to be written |
| ver = file_rb->getCurrentVersion(); |
| if (ver != version) // trying to commit an old version |
| return INK_ERR_WRITE_FILE; |
| } |
| // use rollback object to update file with new content |
| file_content = new textBuffer(size + 1); |
| ret = file_content->copyFrom(text, size); |
| if (ret < 0) { |
| delete file_content; |
| return INK_ERR_WRITE_FILE; |
| } |
| |
| if ((file_rb->forceUpdate(file_content, -1)) != OK_ROLLBACK) { |
| delete file_content; |
| return INK_ERR_WRITE_FILE; |
| } |
| |
| delete file_content; |
| return INK_ERR_OKAY; |
| } |
| |
| /************************************************************************** |
| * EVENTS |
| *************************************************************************/ |
| /*------------------------------------------------------------------------- |
| * EventSignal |
| *------------------------------------------------------------------------- |
| * LAN: THIS FUNCTION IS HACKED AND INCOMPLETE!!!!! |
| * with the current alarm processor system, the argument list is NOT |
| * used; a set description is associated with each alarm already; |
| * be careful because this alarm description is used to keep track |
| * of alarms in the current alarm processor |
| */ |
| INKError |
| EventSignal(char *event_name, va_list ap) |
| { |
| //char *text; |
| //int id; |
| |
| //id = get_event_id(event_name); |
| //text = get_event_text(event_name); |
| //lmgmt->alarm_keeper->signalAlarm(id, text, NULL); |
| |
| return INK_ERR_OKAY; |
| } |
| |
| /*------------------------------------------------------------------------- |
| * EventResolve |
| *------------------------------------------------------------------------- |
| * Resolves the event of the given event_name. If the event is already |
| * unresolved, just return INK_ERR_OKAY. |
| |
| */ |
| INKError |
| EventResolve(char *event_name) |
| { |
| alarm_t a; |
| |
| if (!event_name) |
| return INK_ERR_PARAMS; |
| |
| a = get_event_id(event_name); |
| lmgmt->alarm_keeper->resolveAlarm(a); |
| |
| return INK_ERR_OKAY; |
| } |
| |
| /*------------------------------------------------------------------------- |
| * ActiveEventGetMlt |
| *------------------------------------------------------------------------- |
| * returns failure, and an incomplete active_alarms list if any of |
| * functions fail for a single event |
| * note: returns list of local alarms at that instant of fn call (snapshot) |
| */ |
| INKError |
| ActiveEventGetMlt(LLQ * active_events) |
| { |
| InkHashTable *event_ht; |
| InkHashTableEntry *entry; |
| InkHashTableIteratorState iterator_state; |
| int event_id; |
| char *event_name; |
| |
| if (!active_events) |
| return INK_ERR_PARAMS; |
| |
| // Alarms stores a hashtable of all active alarms where: |
| // key = alarm_t, |
| // value = alarm_description defined in Alarms.cc alarmText[] array |
| event_ht = lmgmt->alarm_keeper->getLocalAlarms(); |
| |
| // iterate through hash-table and insert event_name's into active_events list |
| for (entry = ink_hash_table_iterator_first(event_ht, &iterator_state); |
| entry != NULL; entry = ink_hash_table_iterator_next(event_ht, &iterator_state)) { |
| |
| char *key = (char *) ink_hash_table_entry_key(event_ht, entry); |
| |
| // convert key to int; insert into llQ |
| event_id = ink_atoi(key); |
| event_name = get_event_name(event_id); |
| if (event_name) { |
| if (!enqueue(active_events, event_name)) // returns true if successful |
| return INK_ERR_FAIL; |
| } |
| } |
| |
| return INK_ERR_OKAY; |
| } |
| |
| /*------------------------------------------------------------------------- |
| * EventIsActive |
| *------------------------------------------------------------------------- |
| * Sets *is_current to true if the event named event_name is currently |
| * unresolved; otherwise sets *is_current to false. |
| */ |
| INKError |
| EventIsActive(char *event_name, bool * is_current) |
| { |
| alarm_t a; |
| |
| if (!event_name || !is_current) |
| return INK_ERR_PARAMS; |
| |
| a = get_event_id(event_name); |
| // consider an invalid event_name an error |
| if (a < 0) |
| return INK_ERR_PARAMS; |
| if (lmgmt->alarm_keeper->isCurrentAlarm(a)) |
| *is_current = true; // currently an event |
| else |
| *is_current = false; |
| |
| return INK_ERR_OKAY; |
| } |
| |
| /*------------------------------------------------------------------------- |
| * EventSignalCbRegister |
| *------------------------------------------------------------------------- |
| * This differs from the remote side callback registered. Technically, I think |
| * we need to redesign the alarm processor before we can handle the callback |
| * functionality we want to accomplish. Because currently the alarm processor |
| * only allow registering callbacks for general alarms. |
| * Mimic remote side and have a separate structure (eg. hashtable) of |
| * event callback functions for each type of event. The functions are also |
| * stored in the the hashtable, not in the TM alarm processor model |
| */ |
| INKError |
| EventSignalCbRegister(char *event_name, INKEventSignalFunc func, void *data) |
| { |
| return cb_table_register(local_event_callbacks, event_name, func, data, NULL); |
| |
| } |
| |
| /*------------------------------------------------------------------------- |
| * EventSignalCbUnregister |
| *------------------------------------------------------------------------- |
| * Removes the callback function from the local side CallbackTable |
| */ |
| INKError |
| EventSignalCbUnregister(char *event_name, INKEventSignalFunc func) |
| { |
| return cb_table_unregister(local_event_callbacks, event_name, func); |
| } |
| |
| /*************************************************************************** |
| * Snapshots |
| ***************************************************************************/ |
| INKError |
| SnapshotTake(char *snapshot_name) |
| { |
| char *snapDirFromRecordsConf; |
| bool found; |
| |
| if (!snapshot_name) |
| return INK_ERR_PARAMS; |
| |
| int rec_err = RecGetRecordString_Xmalloc("proxy.config.snapshot_dir", &snapDirFromRecordsConf); |
| found = (rec_err == REC_ERR_OKAY); |
| |
| ink_assert(found); |
| |
| if (snapDirFromRecordsConf[0] != '/') { |
| char *config_dir; |
| int rec_err = RecGetRecordString_Xmalloc("proxy.config.config_dir", &config_dir); |
| found = (rec_err == REC_ERR_OKAY); |
| ink_assert(found); |
| |
| char *snap_dir_cpy = strdup(snapDirFromRecordsConf); |
| int newLen; |
| |
| newLen = strlen(snap_dir_cpy) + strlen(config_dir) + 2; |
| xfree(snapDirFromRecordsConf); |
| snapDirFromRecordsConf = new char[newLen]; |
| ink_assert(snapDirFromRecordsConf != NULL); |
| snprintf(snapDirFromRecordsConf, newLen, "%s%s%s", config_dir, DIR_SEP, snap_dir_cpy); |
| xfree(config_dir); |
| xfree(snap_dir_cpy); |
| } |
| |
| SnapResult result = configFiles->takeSnap(snapshot_name, snapDirFromRecordsConf); |
| xfree(snapDirFromRecordsConf); |
| if (result != SNAP_OK) |
| return INK_ERR_FAIL; |
| else |
| return INK_ERR_OKAY; |
| } |
| |
| INKError |
| SnapshotRestore(char *snapshot_name) |
| { |
| char *snapDirFromRecordsConf; |
| bool found; |
| |
| if (!snapshot_name) |
| return INK_ERR_PARAMS; |
| |
| int rec_err = RecGetRecordString_Xmalloc("proxy.config.snapshot_dir", &snapDirFromRecordsConf); |
| found = (rec_err == REC_ERR_OKAY); |
| ink_assert(found); |
| |
| if (snapDirFromRecordsConf[0] != '/') { |
| char *config_dir; |
| int rec_err = RecGetRecordString_Xmalloc("proxy.config.config_dir", &config_dir); |
| found = (rec_err == REC_ERR_OKAY); |
| ink_assert(found); |
| |
| char *snap_dir_cpy = strdup(snapDirFromRecordsConf); |
| int newLen; |
| |
| newLen = strlen(snap_dir_cpy) + strlen(config_dir) + 2; |
| xfree(snapDirFromRecordsConf); |
| snapDirFromRecordsConf = new char[newLen]; |
| ink_assert(snapDirFromRecordsConf != NULL); |
| snprintf(snapDirFromRecordsConf, newLen, "%s%s%s", config_dir, DIR_SEP, snap_dir_cpy); |
| xfree(config_dir); |
| xfree(snap_dir_cpy); |
| } |
| |
| SnapResult result = configFiles->restoreSnap(snapshot_name, snapDirFromRecordsConf); |
| xfree(snapDirFromRecordsConf); |
| if (result != SNAP_OK) |
| return INK_ERR_FAIL; |
| else |
| return INK_ERR_OKAY; |
| } |
| |
| INKError |
| SnapshotRemove(char *snapshot_name) |
| { |
| char *snapDirFromRecordsConf; |
| bool found; |
| if (!snapshot_name) |
| return INK_ERR_PARAMS; |
| |
| int rec_err = RecGetRecordString_Xmalloc("proxy.config.snapshot_dir", &snapDirFromRecordsConf); |
| found = (rec_err == REC_ERR_OKAY); |
| ink_assert(found); |
| |
| if (snapDirFromRecordsConf[0] != '/') { |
| char *config_dir; |
| rec_err = RecGetRecordString_Xmalloc("proxy.config.config_dir", &config_dir); |
| found = (rec_err == REC_ERR_OKAY); |
| ink_assert(found); |
| |
| char *snap_dir_cpy = strdup(snapDirFromRecordsConf); |
| int newLen; |
| |
| newLen = strlen(snap_dir_cpy) + strlen(config_dir) + 2; |
| xfree(snapDirFromRecordsConf); |
| snapDirFromRecordsConf = new char[newLen]; |
| ink_assert(snapDirFromRecordsConf != NULL); |
| snprintf(snapDirFromRecordsConf, newLen, "%s%s%s", config_dir, DIR_SEP, snap_dir_cpy); |
| xfree(config_dir); |
| xfree(snap_dir_cpy); |
| } |
| |
| SnapResult result = configFiles->removeSnap(snapshot_name, snapDirFromRecordsConf); |
| xfree(snapDirFromRecordsConf); |
| if (result != SNAP_OK) |
| return INK_ERR_FAIL; |
| else |
| return INK_ERR_OKAY; |
| } |
| |
| /* based on FileManager.cc::displaySnapOption() */ |
| INKError |
| SnapshotGetMlt(LLQ * snapshots) |
| { |
| ExpandingArray snap_list(25, true); |
| SnapResult snap_result; |
| int num_snaps; |
| char *snap_name; |
| |
| snap_result = configFiles->WalkSnaps(&snap_list); |
| if (snap_result != SNAP_OK) |
| return INK_ERR_FAIL; |
| |
| num_snaps = snap_list.getNumEntries(); |
| for (int i = 0; i < num_snaps; i++) { |
| snap_name = (char *) (snap_list[i]); |
| if (snap_name) |
| enqueue(snapshots, xstrdup(snap_name)); |
| } |
| |
| return INK_ERR_OKAY; |
| } |
| |
| /*------------------------------------------------------------------------- |
| * StatsReset |
| *------------------------------------------------------------------------- |
| * Iterates through the RecordsConfig table, and for all stats |
| * (type PROCESS, NODE, CLUSTER), sets them back to their default value |
| * If one stat fails to be set correctly, then continues onto next one, |
| * but will return INK_ERR_FAIL. Only returns INK_ERR_OKAY if all |
| * stats are set back to defaults succesfully. |
| */ |
| INKError |
| StatsReset() |
| { |
| bool okay = true; |
| |
| // iterate through all records in RecordsConfig |
| int i = 0; |
| while (RecordsConfig[i].value_type != INVALID) { |
| if (RecordsConfig[i].type == PROCESS || RecordsConfig[i].type == NODE || RecordsConfig[i].type == CLUSTER) { |
| // stats variable, so restore default using table value |
| if (varSetFromStr(RecordsConfig[i].name, RecordsConfig[i].value) == false) |
| okay = false; |
| } |
| i++; |
| } |
| |
| if (okay) |
| return INK_ERR_OKAY; |
| else |
| return INK_ERR_FAIL; |
| } |
| |
| /*------------------------------------------------------------------------- |
| * EncryptToFile |
| *------------------------------------------------------------------------- |
| * Encrypts the password and stores the encrypted password in the |
| * location specified by "filepath" |
| */ |
| INKError |
| EncryptToFile(char *passwd, char *filepath) |
| { |
| //AuthString fileAuthStr(filepath); |
| //AuthString passwdAuthStr(passwd); |
| /*if (!AccCrypto::encryptToFile(fileAuthStr, passwdAuthStr)) { |
| Debug("config", "[EncryptToFile] Failed to encrypt password"); |
| return INK_ERR_FAIL; |
| }*/ |
| |
| return INK_ERR_OKAY; |
| } |
| |
| |
| /* Network conifguration functions */ |
| |
| /*------------------------------------------------------------- |
| * rmserver.cfg |
| *-------------------------------------------------------------*/ |
| #if defined(OEM) |
| |
| INKString |
| GetRmCfgPath() |
| { |
| INKString path; |
| #ifndef _WIN32 |
| |
| char buf[1024]; |
| FILE *ts_file, *rec_file, *pid_file; |
| int i = 0, num_args = 0, found_pid_path = 0; |
| char buffer[1024]; |
| char proxy_restart_cmd[1024]; |
| char ts_base_dir[1024]; |
| char rec_config[1024]; |
| static char *restart_cmd_args[100]; |
| INKString tmp; |
| INKString temp; |
| INKString tmp2; |
| char *env_path; |
| |
| if ((env_path = getenv("TS_ROOT"))) { |
| ink_strncpy(ts_base_dir, env_path, sizeof(ts_base_dir)); |
| } else { |
| if ((ts_file = fopen(DEFAULT_TS_DIRECTORY_FILE, "r")) == NULL) { |
| ink_strncpy(ts_base_dir, "/usr/local",sizeof(ts_base_dir)); |
| } else { |
| fgets(buffer, 1024, ts_file); |
| fclose(ts_file); |
| while (!isspace(buffer[i])) { |
| ts_base_dir[i] = buffer[i]; |
| i++; |
| } |
| ts_base_dir[i] = '\0'; |
| } |
| } |
| |
| sprintf(rec_config, "%s/etc/trafficserver/records.config", ts_base_dir); |
| |
| if ((rec_file = fopen(rec_config, "r")) == NULL) { |
| fprintf(stderr, "Error: unable to open %s.\n", rec_config); |
| return NULL; |
| } |
| |
| while (fgets(buffer, 1024, rec_file) != NULL) { |
| if (strstr(buffer, "proxy.config.rni.proxy_restart_cmd") != NULL) { |
| if ((tmp = strstr(buffer, "STRING ")) != NULL) { |
| tmp += strlen("STRING "); |
| for (i = 0; tmp[i] != '\n' && tmp[i] != '\0'; i++) { |
| proxy_restart_cmd[i] = tmp[i]; |
| } |
| proxy_restart_cmd[i] = '\0'; |
| |
| tmp = proxy_restart_cmd; |
| while ((tmp2 = strtok(tmp, " \t")) != NULL) { |
| restart_cmd_args[num_args++] = strdup(tmp2); |
| tmp = NULL; |
| } |
| restart_cmd_args[num_args] = NULL; |
| } |
| } |
| } |
| fclose(rec_file); |
| |
| path = xstrdup(restart_cmd_args[num_args - 1]); |
| // printf("rmservercfgpath: %s \n",path); |
| if (!path) { |
| fprintf(stderr, "Error[get_rmserver_path]:rmserver.cfg path not found!\n"); |
| /*************************************************************** |
| strcpy(temp,path); |
| strcpy(rmserver_path,path); |
| |
| tmp = temp; |
| if ((tmp1 = strstr(tmp, "/rmserver.cfg")) != NULL) |
| tmp[tmp1-tmp] = '\0'; |
| if(!tmp) { |
| fprintf(stderr,"Error:rmserver.cfg not found in identified path!\n"); |
| return INK_ERR_FAIL; |
| ***************************************************************/ |
| return NULL; |
| } |
| |
| #endif |
| return path; |
| } |
| |
| /* |
| DeXMLize the line and get rid of the quotes |
| */ |
| |
| INKString |
| RmdeXMLize(INKString XMLline, int *lengthp) |
| { |
| INKString linecp; |
| INKString head; |
| INKString tail; |
| INKString quote_1; |
| |
| linecp = xstrdup(XMLline); |
| memset((void *) linecp, 0, strlen(linecp)); |
| head = strstr(XMLline, "<Var"); |
| tail = strstr(XMLline, "\"/>"); |
| quote_1 = strstr(XMLline, "\""); |
| |
| if (head && tail && quote_1) { |
| memcpy(linecp, (void *) (head + 4), (int) quote_1 - (int) head - 4); |
| memcpy(linecp + (int) quote_1 - (int) head - 4, (void *) (quote_1 + 1), (int) tail - (int) quote_1 - 1); |
| linecp = strcat(linecp, "\n"); |
| *lengthp = strlen(linecp); |
| } else { |
| *lengthp = 0; |
| } |
| return linecp; |
| } |
| |
| INKString |
| RmXMLize(INKString line, int *lengthp) |
| { |
| INKString XMLline; |
| |
| XMLline = new char[strlen(line) + 9]; |
| memset(XMLline, 0, strlen(line) + 9); |
| sprintf(XMLline, "%s%s%s\n", "<Var ", line, "/>"); |
| *lengthp = strlen(XMLline); |
| //Debug ("CoreAPI", "XMLline as %s\n", XMLline); |
| return XMLline; |
| } |
| |
| INKError |
| ReadRmCfgFile(char **Buffp) |
| { |
| |
| INKString path; |
| long fsize; |
| FILE *fp; |
| |
| //read the rmserver.cfg file |
| path = GetRmCfgPath(); |
| if (!path) { |
| fprintf(stderr, "Error:rmserver.cfg path not found!\n"); |
| return INK_ERR_FAIL; |
| } |
| if ((fp = fopen(path, "r")) == NULL) { |
| fprintf(stderr, "Error: unable to open %s\n", path); |
| return INK_ERR_READ_FILE; |
| } |
| if (path) { |
| xfree(path); |
| } |
| /* Get the file size to alloc an text buffer */ |
| if (fseek(fp, 0, SEEK_END) < 0) { |
| mgmt_fatal(stderr, "[CoreAPI::ReadFile] Failed seek in conf file: '%s'\n", path); |
| return INK_ERR_FAIL; |
| } else { |
| fsize = ftell(fp); |
| rewind(fp); |
| *Buffp = new char[fsize + 1]; |
| memset(*Buffp, 0, fsize + 1); |
| if (fread(*Buffp, sizeof(char), fsize, fp) == (size_t) fsize) { |
| fclose(fp); |
| return INK_ERR_OKAY; |
| } else { |
| fclose(fp); |
| return INK_ERR_READ_FILE; |
| } |
| } |
| } |
| |
| /* |
| This function process the list in XML file with Certain interested Tags. |
| */ |
| void |
| RmReadCfgList(Tokenizer * Tp, tok_iter_state * Tstate, char **buffp, INKRmServerListT ListType) |
| { |
| |
| char *line, *new_line; |
| bool deXMLed; |
| int llength; |
| |
| line = (char *) Tp->iterNext(Tstate); |
| do { |
| deXMLed = false; |
| switch (ListType) { |
| case INK_RM_LISTTAG_SCU_ADMIN: |
| case INK_RM_LISTTAG_CNN_REALM: |
| case INK_RM_LISTTAG_ADMIN_FILE: |
| case INK_RM_LISTTAG_AUTH: |
| /* process the REALM */ |
| if (strstr(line, RM_REALM)) { |
| new_line = RmdeXMLize(line, &llength); |
| deXMLed = true; |
| } |
| break; |
| case INK_RM_LISTTAG_PROXY: |
| /* prcess the RTSP/PNA/MAXs */ |
| if (strstr(line, RM_PNA_PORT) || |
| strstr(line, RM_MAX_PROXY_CONN) || strstr(line, RM_MAX_GWBW) || strstr(line, RM_MAX_PXBW)) { |
| new_line = RmdeXMLize(line, &llength); |
| deXMLed = true; |
| } |
| break; |
| case INK_RM_LISTTAG_PNA_RDT: |
| /* process the PNARedirector */ |
| if (strstr(line, RM_PNA_RDT_PORT) || strstr(line, RM_PNA_RDT_IP)) { |
| new_line = RmdeXMLize(line, &llength); |
| deXMLed = true; |
| } |
| break; |
| } |
| if (!deXMLed) { |
| sprintf(*buffp, "#%s\n", line); |
| *buffp += (strlen(line) + 2); |
| } else { |
| sprintf(*buffp, "%s", new_line); |
| if (!new_line) { |
| xfree(new_line); |
| } |
| *buffp += llength; |
| } |
| line = (char *) Tp->iterNext(Tstate); |
| } while (!strstr(line, "/List")); |
| |
| sprintf(*buffp, "#%s\n", line); |
| *buffp += (strlen(line) + 2); |
| return; |
| } |
| |
| INKError |
| WriteRmCfgFile(char *text) |
| { |
| |
| INKString path; |
| FILE *fp; |
| INKError rc; |
| |
| //read the rmserver.cfg file |
| path = GetRmCfgPath(); |
| if (!path) { |
| fprintf(stderr, "Error:rmserver.cfg path not found!\n"); |
| return INK_ERR_FAIL; |
| } |
| if ((fp = fopen(path, "w")) == NULL) { |
| fprintf(stderr, "Error: unable to open %s\n", path); |
| return INK_ERR_READ_FILE; |
| } |
| long fsize = strlen(text); |
| if (fwrite((void *) text, sizeof(char), fsize, fp) == (size_t) fsize) { |
| rc = INK_ERR_OKAY; |
| } else { |
| rc = INK_ERR_WRITE_FILE; |
| } |
| fclose(fp); |
| return rc; |
| } |
| |
| #endif |