| /** @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: TSControlMain.cc |
| * Purpose: The main section for traffic server that handles all the requests |
| * from the user. |
| * Created: 01/08/01 |
| * Created by: Stephanie Song |
| * |
| ***************************************************************************/ |
| |
| #include "libts.h" |
| #include "LocalManager.h" |
| #include "Main.h" |
| #include "MgmtUtils.h" |
| #include "MgmtSocket.h" |
| #include "TSControlMain.h" |
| #include "CoreAPI.h" |
| #include "CoreAPIShared.h" |
| #include "NetworkUtilsLocal.h" |
| #include "NetworkUtilsDefs.h" |
| |
| #define TIMEOUT_SECS 1; // the num secs for select timeout |
| |
| extern int diags_init; // from Main.cc |
| |
| InkHashTable *accepted_con; // a list of all accepted client connections |
| |
| /********************************************************************* |
| * create_client |
| * |
| * purpose: creates a new ClientT and return pointer to it |
| * input: None |
| * output: ClientT |
| * note: created for each accepted client connection |
| *********************************************************************/ |
| ClientT * |
| create_client() |
| { |
| ClientT *ele = (ClientT *)ats_malloc(sizeof(ClientT)); |
| |
| ele->adr = (struct sockaddr *)ats_malloc(sizeof(struct sockaddr)); |
| return ele; |
| } |
| |
| /********************************************************************* |
| * delete_client |
| * |
| * purpose: frees dynamic memory allocated for a ClientT |
| * input: client - the ClientT to free |
| * output: |
| *********************************************************************/ |
| void |
| delete_client(ClientT * client) |
| { |
| if (client) { |
| ats_free(client->adr); |
| ats_free(client); |
| } |
| return; |
| } |
| |
| /********************************************************************* |
| * remove_client |
| * |
| * purpose: removes the ClientT from the specified hashtable; includes |
| * removing the binding and freeing the ClientT |
| * input: client - the ClientT to remove |
| * output: |
| *********************************************************************/ |
| void |
| remove_client(ClientT * client, InkHashTable * table) |
| { |
| // close client socket |
| close_socket(client->sock_info.fd); // close client socket |
| |
| // remove client binding from hash table |
| ink_hash_table_delete(table, (char *) &client->sock_info.fd); |
| |
| // free ClientT |
| delete_client(client); |
| |
| return; |
| } |
| |
| /********************************************************************* |
| * ts_ctrl_main |
| * |
| * This function is run as a thread in WebIntrMain.cc that listens on a |
| * specified socket. It loops until Traffic Manager dies. |
| * In the loop, it just listens on a socket, ready to accept any connections, |
| * until receives a request from the remote API client. Parse the request |
| * to determine which CoreAPI call to make. |
| *********************************************************************/ |
| void * |
| ts_ctrl_main(void *arg) |
| { |
| int ret; |
| OpType op_t; // operation type for a request; NetworkUtilsDefs.h |
| int *socket_fd; |
| int con_socket_fd; // main socket for listening to new connections |
| char *req = NULL; // the request msg sent over from client (not include header) |
| |
| socket_fd = (int *) arg; |
| con_socket_fd = *socket_fd; |
| |
| // initialize queue for accepted con |
| accepted_con = ink_hash_table_create(InkHashTableKeyType_Word); |
| if (!accepted_con) { |
| return NULL; |
| } |
| // now we can start listening, accepting connections and servicing requests |
| int new_con_fd; // new socket fd when accept connection |
| |
| fd_set selectFDs; // for select call |
| InkHashTableEntry *con_entry; // used to obtain client connection info |
| ClientT *client_entry; // an entry of fd to alarms mapping |
| InkHashTableIteratorState con_state; // used to iterate through hash table |
| int fds_ready; // stores return value for select |
| struct timeval timeout; |
| int addr_len = (sizeof(struct sockaddr)); |
| |
| // loops until TM dies; waits for and processes requests from clients |
| while (1) { |
| // LINUX: to prevent hard-spin of CPU, reset timeout on each loop |
| timeout.tv_sec = TIMEOUT_SECS; |
| timeout.tv_usec = 0; |
| |
| FD_ZERO(&selectFDs); |
| |
| if (con_socket_fd >= 0) { |
| FD_SET(con_socket_fd, &selectFDs); |
| //Debug("ts_main", "[ts_ctrl_main] add fd %d to select set\n", con_socket_fd); |
| } |
| // see if there are more fd to set |
| con_entry = ink_hash_table_iterator_first(accepted_con, &con_state); |
| |
| // iterate through all entries in hash table |
| while (con_entry) { |
| client_entry = (ClientT *) ink_hash_table_entry_value(accepted_con, con_entry); |
| if (client_entry->sock_info.fd >= 0) { // add fd to select set |
| FD_SET(client_entry->sock_info.fd, &selectFDs); |
| Debug("ts_main", "[ts_ctrl_main] add fd %d to select set\n", client_entry->sock_info.fd); |
| } |
| con_entry = ink_hash_table_iterator_next(accepted_con, &con_state); |
| } |
| |
| // select call - timeout is set so we can check events at regular intervals |
| fds_ready = mgmt_select(FD_SETSIZE, &selectFDs, (fd_set *) NULL, (fd_set *) NULL, &timeout); |
| |
| // check if have any connections or requests |
| if (fds_ready > 0) { |
| // first check for connections! |
| if (con_socket_fd >= 0 && FD_ISSET(con_socket_fd, &selectFDs)) { |
| fds_ready--; |
| |
| // create a new instance to store client connection info |
| ClientT *new_client_con = create_client(); |
| if (!new_client_con) { |
| // return TS_ERR_SYS_CALL; WHAT TO DO? just keep going |
| Debug("ts_main", "[ts_ctrl_main] can't allocate new ClientT\n"); |
| } else { // accept connection |
| new_con_fd = mgmt_accept(con_socket_fd, new_client_con->adr, &addr_len); |
| new_client_con->sock_info.fd = new_con_fd; |
| new_client_con->sock_info.SSLcon = NULL; |
| ink_hash_table_insert(accepted_con, (char *) &new_client_con->sock_info.fd, new_client_con); |
| Debug("ts_main", "[ts_ctrl_main] Add new client connection \n"); |
| } |
| } // end if(new_con_fd >= 0 && FD_ISSET(new_con_fd, &selectFDs)) |
| |
| // some other file descriptor; for each one, service request |
| if (fds_ready > 0) { // RECEIVED A REQUEST from remote API client |
| // see if there are more fd to set - iterate through all entries in hash table |
| con_entry = ink_hash_table_iterator_first(accepted_con, &con_state); |
| while (con_entry) { |
| Debug("ts_main", "[ts_ctrl_main] We have a remote client request!\n"); |
| client_entry = (ClientT *) ink_hash_table_entry_value(accepted_con, con_entry); |
| // got information; check |
| if (client_entry->sock_info.fd && FD_ISSET(client_entry->sock_info.fd, &selectFDs)) { |
| // SERVICE REQUEST - read the op and message into a buffer |
| // clear the fields first |
| op_t = UNDEFINED_OP; |
| ret = preprocess_msg(client_entry->sock_info, (OpType *) & op_t, &req); |
| if (ret == TS_ERR_NET_READ || ret == TS_ERR_NET_EOF) { |
| // occurs when remote API client terminates connection |
| Debug("ts_main", "[ts_ctrl_main] ERROR: preprocess_msg - remove client %d \n", client_entry->sock_info.fd); |
| remove_client(client_entry, accepted_con); |
| // get next client connection (if any) |
| con_entry = ink_hash_table_iterator_next(accepted_con, &con_state); |
| continue; |
| } |
| |
| // determine which handler function to call based on operation |
| switch (op_t) { |
| case RECORD_GET: |
| ret = handle_record_get(client_entry->sock_info, req); |
| break; |
| |
| case RECORD_MATCH_GET: |
| ret = handle_record_match(client_entry->sock_info, req); |
| break; |
| |
| case RECORD_SET: |
| ret = handle_record_set(client_entry->sock_info, req); |
| break; |
| |
| case FILE_READ: |
| ret = handle_file_read(client_entry->sock_info, req); |
| break; |
| |
| case FILE_WRITE: |
| ret = handle_file_write(client_entry->sock_info, req); |
| break; |
| |
| case PROXY_STATE_GET: |
| ret = handle_proxy_state_get(client_entry->sock_info); |
| break; |
| |
| case PROXY_STATE_SET: |
| ret = handle_proxy_state_set(client_entry->sock_info, req); |
| break; |
| |
| case RECONFIGURE: |
| ret = handle_reconfigure(client_entry->sock_info); |
| break; |
| |
| case RESTART: |
| ret = handle_restart(client_entry->sock_info, req, false); |
| break; |
| |
| case BOUNCE: |
| ret = handle_restart(client_entry->sock_info, req, true); |
| break; |
| |
| case STORAGE_DEVICE_CMD_OFFLINE: |
| ret = handle_storage_device_cmd_offline(client_entry->sock_info, req); |
| break; |
| |
| case EVENT_RESOLVE: |
| ret = handle_event_resolve(client_entry->sock_info, req); |
| break; |
| |
| case EVENT_GET_MLT: |
| ret = handle_event_get_mlt(client_entry->sock_info); |
| break; |
| |
| case EVENT_ACTIVE: |
| ret = handle_event_active(client_entry->sock_info, req); |
| break; |
| |
| case SNAPSHOT_TAKE: |
| case SNAPSHOT_RESTORE: |
| case SNAPSHOT_REMOVE: |
| ret = handle_snapshot(client_entry->sock_info, req, op_t); |
| break; |
| |
| case SNAPSHOT_GET_MLT: |
| ret = handle_snapshot_get_mlt(client_entry->sock_info); |
| break; |
| |
| case DIAGS: |
| ret = handle_diags(client_entry->sock_info, req); |
| break; |
| |
| case STATS_RESET_CLUSTER: |
| case STATS_RESET_NODE: |
| ret = handle_stats_reset(client_entry->sock_info, req, op_t); |
| break; |
| |
| case UNDEFINED_OP: |
| default: |
| break; |
| |
| } // end switch (op_t) |
| |
| ats_free(req); |
| |
| if (ret == TS_ERR_NET_WRITE || ret == TS_ERR_NET_EOF) { |
| Debug("ts_main", "[ts_ctrl_main] ERROR: sending response for message op %d\n", (int)op_t); |
| remove_client(client_entry, accepted_con); |
| con_entry = ink_hash_table_iterator_next(accepted_con, &con_state); |
| continue; |
| } |
| |
| } // end if(client_entry->sock_info.fd && FD_ISSET(client_entry->sock_info.fd, &selectFDs)) |
| |
| con_entry = ink_hash_table_iterator_next(accepted_con, &con_state); |
| } // end while (con_entry) |
| } // end if (fds_ready > 0) |
| |
| } // end if (fds_ready > 0) |
| |
| } // end while (1) |
| |
| // if we get here something's wrong, just clean up |
| Debug("ts_main", "[ts_ctrl_main] CLOSING AND SHUTTING DOWN OPERATIONS\n"); |
| close_socket(con_socket_fd); |
| |
| // iterate through hash table; close client socket connections and remove entry |
| con_entry = ink_hash_table_iterator_first(accepted_con, &con_state); |
| while (con_entry) { |
| client_entry = (ClientT *) ink_hash_table_entry_value(accepted_con, con_entry); |
| if (client_entry->sock_info.fd >= 0) { |
| close_socket(client_entry->sock_info.fd); // close socket |
| } |
| ink_hash_table_delete(accepted_con, (char *) &client_entry->sock_info.fd); // remove binding |
| delete_client(client_entry); // free ClientT |
| con_entry = ink_hash_table_iterator_next(accepted_con, &con_state); |
| } |
| // all entries should be removed and freed already |
| ink_hash_table_destroy(accepted_con); |
| |
| ink_thread_exit(NULL); |
| return NULL; |
| } |
| |
| /*------------------------------------------------------------------------- |
| HANDLER FUNCTIONS |
| --------------------------------------------------------------------------*/ |
| /* NOTE: all the handle_xx functions basically, take the request, parse it, |
| * and send a reply back to the remote client. So even if error occurs, |
| * each handle functions MUST SEND A REPLY BACK!! If an error occurs during |
| * parsing the request, or while doing the API call, then must send reply back |
| * with only the error return value in the msg!!! It's important that if |
| * an error does occur, the "send_reply" function is used; otherwise the socket |
| * will get written with too much extraneous stuff; the remote side will |
| * only read the TSError type since that's all it expects to be in the message |
| * (for an TSError != TS_ERR_OKAY). |
| */ |
| |
| /************************************************************************** |
| * handle_record_get |
| * |
| * purpose: handles requests to retrieve values of certain variables |
| * in TM. (see local/TSCtrlFunc.cc) |
| * input: socket information |
| * req - the msg sent (should = record name to get) |
| * output: SUCC or ERR |
| * note: |
| *************************************************************************/ |
| TSError |
| handle_record_get(struct SocketInfo sock_info, char *req) |
| { |
| TSError ret; |
| TSRecordEle *ele; |
| |
| // parse msg - don't really need since the request itself is the record name |
| if (!req) { |
| ret = send_reply(sock_info, TS_ERR_FAIL); |
| return ret; |
| } |
| // call CoreAPI call on Traffic Manager side |
| ele = TSRecordEleCreate(); |
| ret = MgmtRecordGet(req, ele); |
| if (ret != TS_ERR_OKAY) { |
| ret = send_reply(sock_info, ret); |
| TSRecordEleDestroy(ele); |
| return ret; |
| } |
| // create and send reply back to client |
| switch (ele->rec_type) { |
| case TS_REC_INT: |
| ret = send_record_get_reply(sock_info, ret, &(ele->int_val), sizeof(TSInt), ele->rec_type, ele->rec_name); |
| break; |
| case TS_REC_COUNTER: |
| ret = send_record_get_reply(sock_info, ret, &(ele->counter_val), sizeof(TSCounter), ele->rec_type, ele->rec_name); |
| break; |
| case TS_REC_FLOAT: |
| ret = send_record_get_reply(sock_info, ret, &(ele->float_val), sizeof(TSFloat), ele->rec_type, ele->rec_name); |
| break; |
| case TS_REC_STRING: |
| ret = send_record_get_reply(sock_info, ret, ele->string_val, strlen(ele->string_val), ele->rec_type, ele->rec_name); |
| break; |
| default: // invalid record type |
| ret = send_reply(sock_info, TS_ERR_FAIL); |
| TSRecordEleDestroy(ele); |
| return ret; |
| } |
| |
| if (ret != TS_ERR_OKAY) { // error sending reply |
| ret = send_reply(sock_info, ret); |
| } |
| |
| TSRecordEleDestroy(ele); // free any memory allocated by CoreAPI call |
| |
| return ret; |
| } |
| |
| struct record_match_state { |
| TSError err; |
| SocketInfo sock; |
| DFA regex; |
| }; |
| |
| static void |
| send_record_match(RecT /* rec_type */, void *edata, int /* registered */, const char *name, int data_type, RecData *rec_val) |
| { |
| record_match_state *match = (record_match_state *)edata ; |
| |
| if (match->err != TS_ERR_OKAY) { |
| return; |
| } |
| |
| if (match->regex.match(name) >= 0) { |
| switch (data_type) { |
| case RECD_INT: |
| match->err = send_record_get_reply(match->sock, TS_ERR_OKAY, &(rec_val->rec_int), sizeof(TSInt), TS_REC_INT, name); |
| break; |
| case RECD_COUNTER: |
| match->err = send_record_get_reply(match->sock, TS_ERR_OKAY, &(rec_val->rec_counter), sizeof(TSCounter), TS_REC_COUNTER, name); |
| break; |
| case RECD_STRING: |
| // For NULL string parameters, end the literal "NULL" to match the behavior of MgmtRecordGet(). |
| if (rec_val->rec_string) { |
| match->err = send_record_get_reply(match->sock, TS_ERR_OKAY, rec_val->rec_string, strlen(rec_val->rec_string), TS_REC_STRING, name); |
| } else { |
| match->err = send_record_get_reply(match->sock, TS_ERR_OKAY, (void *)"NULL", strlen("NULL"), TS_REC_STRING, name); |
| } |
| break; |
| case RECD_FLOAT: |
| match->err = send_record_get_reply(match->sock, TS_ERR_OKAY, &(rec_val->rec_float), sizeof(TSFloat), TS_REC_FLOAT, name); |
| break; |
| default: |
| break; // skip it |
| } |
| } |
| } |
| |
| TSError |
| handle_record_match(struct SocketInfo sock_info, char *req) |
| { |
| TSError ret; |
| record_match_state match; |
| |
| // parse msg - don't really need since the request itself is the regex itself |
| if (!req) { |
| ret = send_reply(sock_info, TS_ERR_FAIL); |
| return ret; |
| } |
| |
| if (match.regex.compile(req, RE_CASE_INSENSITIVE) != 0) { |
| ret = send_reply(sock_info, TS_ERR_FAIL); |
| return ret; |
| } |
| |
| match.err = TS_ERR_OKAY; |
| match.sock = sock_info; |
| |
| RecDumpRecords(RECT_NULL, send_record_match, &match); |
| |
| // If successful, send a list terminator. |
| if (match.err == TS_ERR_OKAY) { |
| return send_record_get_reply(sock_info, TS_ERR_OKAY, NULL, 0, TS_REC_UNDEFINED, NULL); |
| } |
| |
| return match.err; |
| } |
| |
| /************************************************************************** |
| * handle_record_set |
| * |
| * purpose: handles a set request sent by the client |
| * input: sock_info |
| * output: SUCC or ERR |
| * note: request format = <record name>DELIMITER<record_value> |
| *************************************************************************/ |
| TSError |
| handle_record_set(struct SocketInfo sock_info, char *req) |
| { |
| char *name, *val; |
| TSError ret; |
| TSActionNeedT action = TS_ACTION_UNDEFINED; |
| |
| if (!req) { |
| ret = send_reply(sock_info, TS_ERR_PARAMS); |
| return ret; |
| } |
| // parse request msg |
| ret = parse_request_name_value(req, &name, &val); |
| if (ret != TS_ERR_OKAY) { |
| ret = send_reply(sock_info, ret); |
| ats_free(name); |
| return ret; |
| } |
| // call CoreAPI call on Traffic Manager side |
| ret = MgmtRecordSet(name, val, &action); |
| ats_free(name); |
| ats_free(val); |
| |
| if (ret != TS_ERR_OKAY) { |
| ret = send_reply(sock_info, ret); |
| return ret; |
| } |
| // create and send reply back to client |
| ret = send_record_set_reply(sock_info, ret, action); |
| |
| return ret; |
| } |
| |
| /************************************************************************** |
| * handle_file_read |
| * |
| * purpose: handles request to read a file |
| * input: struct SocketInfo sock_info - the socket to use to talk to client |
| * output: SUCC or ERR |
| * note: None |
| *************************************************************************/ |
| TSError |
| handle_file_read(struct SocketInfo sock_info, char *req) |
| { |
| TSError ret; |
| int size, version; |
| TSFileNameT file; |
| char *text; |
| |
| if (!req) { |
| ret = send_reply(sock_info, TS_ERR_PARAMS); |
| return ret; |
| } |
| // first parse the message to retrieve needed data |
| ret = parse_file_read_request(req, &file); |
| if (ret != TS_ERR_OKAY) { |
| ret = send_reply(sock_info, ret); |
| return ret; |
| } |
| // make CoreAPI call on Traffic Manager side |
| ret = ReadFile(file, &text, &size, &version); |
| if (ret != TS_ERR_OKAY) { |
| ret = send_reply(sock_info, ret); |
| return ret; |
| } |
| // marshal the file info message that can be returned to client |
| ret = send_file_read_reply(sock_info, ret, version, size, text); |
| if (ret != TS_ERR_OKAY) { |
| ret = send_reply(sock_info, ret); |
| } |
| ats_free(text); // free memory allocated by ReadFile |
| |
| return ret; |
| } |
| |
| /************************************************************************** |
| * handle_file_write |
| * |
| * purpose: handles request to write a file |
| * input: struct SocketInfo sock_info - the socket to use to talk to client |
| * output: SUCC or ERR |
| * note: None |
| *************************************************************************/ |
| TSError |
| handle_file_write(struct SocketInfo sock_info, char *req) |
| { |
| TSError ret; |
| int size, version; |
| TSFileNameT file; |
| char *text; |
| |
| if (!req) { |
| ret = send_reply(sock_info, TS_ERR_PARAMS); |
| return ret; |
| } |
| // first parse the message |
| ret = parse_file_write_request(req, &file, &version, &size, &text); |
| if (ret != TS_ERR_OKAY) { |
| ret = send_reply(sock_info, ret); |
| return ret; |
| } |
| // make CoreAPI call on Traffic Manager side |
| ret = WriteFile(file, text, size, version); |
| ret = send_reply(sock_info, ret); |
| ats_free(text); // free memory allocated by parsing fn. |
| |
| return ret; |
| } |
| |
| |
| /************************************************************************** |
| * handle_proxy_state_get |
| * |
| * purpose: handles request to get the state of the proxy (TS) |
| * input: struct SocketInfo sock_info - the socket to use to talk to client |
| * output: TS_ERR_xx |
| * note: None |
| *************************************************************************/ |
| TSError |
| handle_proxy_state_get(struct SocketInfo sock_info) |
| { |
| TSProxyStateT state; |
| TSError ret; |
| |
| // make coreAPI call on local side |
| state = ProxyStateGet(); |
| |
| // send reply back |
| ret = send_proxy_state_get_reply(sock_info, state); |
| |
| return ret; //shouldn't get here |
| } |
| |
| /************************************************************************** |
| * handle_proxy_state_set |
| * |
| * purpose: handles the request to set the state of the proxy (TS) |
| * input: struct SocketInfo sock_info - the socket to use to talk to client |
| * req - indicates which state to set it to (on/off?) and specifies |
| * what to set the ts options too (optional) |
| * output: TS_ERR_xx |
| * note: None |
| *************************************************************************/ |
| TSError |
| handle_proxy_state_set(struct SocketInfo sock_info, char *req) |
| { |
| TSProxyStateT state; |
| TSCacheClearT clear; |
| TSError ret; |
| |
| if (!req) { |
| ret = TS_ERR_FAIL; |
| goto END; |
| } |
| // the req should specify the state and any cache clearing options |
| ret = parse_proxy_state_request(req, &state, &clear); |
| if (ret != TS_ERR_OKAY) { |
| goto END; |
| } |
| |
| ret = ProxyStateSet(state, clear); |
| |
| END: |
| ret = send_reply(sock_info, ret); |
| return ret; |
| } |
| |
| /************************************************************************** |
| * handle_reconfigure |
| * |
| * purpose: handles request to reread the config files |
| * input: struct SocketInfo sock_info - the socket to use to talk to client |
| * output: TS_ERR_xx |
| * note: None |
| *************************************************************************/ |
| TSError |
| handle_reconfigure(struct SocketInfo sock_info) |
| { |
| TSError ret; |
| |
| // make local side coreAPI call |
| ret = Reconfigure(); |
| |
| ret = send_reply(sock_info, ret); |
| return ret; |
| } |
| |
| /************************************************************************** |
| * handle_restart |
| * |
| * purpose: handles request to restart TM and TS |
| * input: struct SocketInfo sock_info - the socket to use to talk to client |
| * req - indicates if restart should be cluster wide or not |
| * bounce - indicate if the restart is a traffic_server bounce only |
| * output: TS_ERR_xx |
| * note: None |
| *************************************************************************/ |
| TSError |
| handle_restart(struct SocketInfo sock_info, char *req, bool bounce) |
| { |
| int16_t cluster; |
| TSError ret; |
| |
| if (!req) { |
| ret = send_reply(sock_info, TS_ERR_PARAMS); |
| return ret; // shouldn't get here |
| } |
| // the req should be a boolean value - typecase it |
| memcpy(&cluster, req, SIZE_BOOL); |
| |
| // cluster == 0 means no cluster |
| if (bounce) |
| ret = Bounce(0 != cluster); |
| else |
| ret = Restart(0 != cluster); |
| |
| ret = send_reply(sock_info, ret); |
| return ret; |
| } |
| |
| /************************************************************************** |
| * handle_storage_device_cmd_offline |
| * |
| * purpose: handle storage offline command. |
| * input: struct SocketInfo sock_info - the socket to use to talk to client |
| * output: TS_ERR_xx |
| * note: None |
| *************************************************************************/ |
| TSError |
| handle_storage_device_cmd_offline(struct SocketInfo sock_info, char *req) |
| { |
| TSError ret = TS_ERR_OKAY; |
| |
| if (!req) { |
| ret = send_reply(sock_info, TS_ERR_PARAMS); |
| return ret; // shouldn't get here |
| } |
| // forward to server |
| lmgmt->signalEvent(MGMT_EVENT_STORAGE_DEVICE_CMD_OFFLINE, req); |
| ret = send_reply(sock_info, ret); |
| return ret; |
| } |
| |
| /************************************************************************** |
| * handle_event_resolve |
| * |
| * purpose: handles request to resolve an event |
| * input: struct SocketInfo sock_info - the socket to use to talk to client |
| * output: TS_ERR_xx |
| * note: the req should be the event name |
| *************************************************************************/ |
| TSError |
| handle_event_resolve(struct SocketInfo sock_info, char *req) |
| { |
| TSError ret; |
| |
| // parse msg - don't really need since the request itself is the record name |
| if (!req) { |
| ret = send_reply(sock_info, TS_ERR_PARAMS); |
| return ret; // shouldn't get here |
| } |
| // call CoreAPI call on Traffic Manager side; req == event_name |
| ret = EventResolve(req); |
| ret = send_reply(sock_info, ret); |
| |
| return ret; |
| } |
| |
| /************************************************************************** |
| * handle_event_get_mlt |
| * |
| * purpose: handles request to get list of active events |
| * input: struct SocketInfo sock_info - the socket to use to talk to client |
| * output: TS_ERR_xx |
| * note: the req should be the event name |
| *************************************************************************/ |
| TSError |
| handle_event_get_mlt(struct SocketInfo sock_info) |
| { |
| TSError ret; |
| LLQ *event_list; |
| char buf[MAX_BUF_SIZE]; |
| char *event_name; |
| int buf_pos = 0; |
| |
| event_list = create_queue(); |
| |
| // call CoreAPI call on Traffic Manager side; req == event_name |
| ret = ActiveEventGetMlt(event_list); |
| if (ret != TS_ERR_OKAY) { |
| ret = send_reply(sock_info, ret); |
| delete_queue(event_list); |
| return ret; |
| } |
| // iterate through list and put into a delimited string list |
| memset(buf, 0, MAX_BUF_SIZE); |
| while (!queue_is_empty(event_list)) { |
| event_name = (char *) dequeue(event_list); |
| if (event_name) { |
| snprintf(buf + buf_pos, (MAX_BUF_SIZE - buf_pos), "%s%c", event_name, REMOTE_DELIM); |
| buf_pos += (strlen(event_name) + 1); |
| ats_free(event_name); //free the llq entry |
| } |
| } |
| buf[buf_pos] = '\0'; //end the string |
| |
| ret = send_reply_list(sock_info, ret, buf); |
| |
| delete_queue(event_list); |
| return ret; |
| } |
| |
| /************************************************************************** |
| * handle_event_active |
| * |
| * purpose: handles request to resolve an event |
| * input: struct SocketInfo sock_info - the socket to use to talk to client |
| * output: TS_ERR_xx |
| * note: the req should be the event name |
| *************************************************************************/ |
| TSError |
| handle_event_active(struct SocketInfo sock_info, char *req) |
| { |
| TSError ret; |
| bool active; |
| |
| // parse msg - don't really need since the request itself is the record name |
| if (!req) { |
| ret = send_reply(sock_info, TS_ERR_PARAMS); |
| return ret; // shouldn't get here |
| } |
| // call CoreAPI call on Traffic Manager side; req == event_name |
| ret = EventIsActive(req, &active); |
| if (ret != TS_ERR_OKAY) { |
| ret = send_reply(sock_info, ret); |
| return ret; //shouldn't get here |
| } |
| |
| ret = send_event_active_reply(sock_info, ret, active); |
| |
| return ret; |
| } |
| |
| |
| /************************************************************************** |
| * handle_snapshot |
| * |
| * purpose: handles request to take/remove/restore a snapshot |
| * input: struct SocketInfo sock_info - the socket to use to talk to client |
| * req - the snapshot name |
| * op - SNAPSHOT_TAKE, SNAPSHOT_REMOVE, or SNAPSHOT_RESTORE |
| * output: TS_ERR_xx |
| *************************************************************************/ |
| TSError |
| handle_snapshot(struct SocketInfo sock_info, char *req, OpType op) |
| { |
| TSError ret; |
| |
| if (!req) { |
| ret = send_reply(sock_info, TS_ERR_PARAMS); |
| return ret; |
| } |
| // call CoreAPI call on Traffic Manager side; req == snap_name |
| switch (op) { |
| case SNAPSHOT_TAKE: |
| ret = SnapshotTake(req); |
| break; |
| case SNAPSHOT_RESTORE: |
| ret = SnapshotRestore(req); |
| break; |
| case SNAPSHOT_REMOVE: |
| ret = SnapshotRemove(req); |
| break; |
| default: |
| ret = TS_ERR_FAIL; |
| break; |
| } |
| |
| ret = send_reply(sock_info, ret); |
| return ret; |
| } |
| |
| /************************************************************************** |
| * handle_snapshot_get_mlt |
| * |
| * purpose: handles request to get list of snapshots |
| * input: struct SocketInfo sock_info - the socket to use to talk to client |
| * output: TS_ERR_xx |
| * note: the req should be the event name |
| *************************************************************************/ |
| TSError |
| handle_snapshot_get_mlt(struct SocketInfo sock_info) |
| { |
| TSError ret; |
| LLQ *snap_list; |
| char buf[MAX_BUF_SIZE]; |
| char *snap_name; |
| int buf_pos = 0; |
| |
| snap_list = create_queue(); |
| |
| // call CoreAPI call on Traffic Manager side; req == event_name |
| ret = SnapshotGetMlt(snap_list); |
| if (ret != TS_ERR_OKAY) { |
| ret = send_reply(sock_info, ret); |
| delete_queue(snap_list); |
| return ret; |
| } |
| // iterate through list and put into a delimited string list |
| memset(buf, 0, MAX_BUF_SIZE); |
| while (!queue_is_empty(snap_list)) { |
| snap_name = (char *) dequeue(snap_list); |
| if (snap_name) { |
| snprintf(buf + buf_pos, (MAX_BUF_SIZE - buf_pos), "%s%c", snap_name, REMOTE_DELIM); |
| buf_pos += (strlen(snap_name) + 1); |
| ats_free(snap_name); //free the llq entry |
| } |
| } |
| buf[buf_pos] = '\0'; //end the string |
| |
| ret = send_reply_list(sock_info, ret, buf); |
| |
| delete_queue(snap_list); |
| return ret; |
| } |
| |
| |
| /************************************************************************** |
| * handle_diags |
| * |
| * purpose: handles diags request |
| * input: struct SocketInfo sock_info - the socket to use to talk to client |
| * req - the diag message (already formatted with arguments) |
| * output: TS_ERR_xx |
| *************************************************************************/ |
| TSError |
| handle_diags(struct SocketInfo /* sock_info ATS_UNUSED */, char *req) |
| { |
| TSError ret; |
| TSDiagsT mode; |
| char *diag_msg = NULL; |
| DiagsLevel level; |
| |
| if (!req) |
| goto Lerror; |
| |
| ret = parse_diags_request(req, &mode, &diag_msg); |
| if (ret != TS_ERR_OKAY) |
| goto Lerror; |
| |
| |
| switch (mode) { |
| case TS_DIAG_DIAG: |
| level = DL_Diag; |
| break; |
| case TS_DIAG_DEBUG: |
| level = DL_Debug; |
| break; |
| case TS_DIAG_STATUS: |
| level = DL_Status; |
| break; |
| case TS_DIAG_NOTE: |
| level = DL_Note; |
| break; |
| case TS_DIAG_WARNING: |
| level = DL_Warning; |
| break; |
| case TS_DIAG_ERROR: |
| level = DL_Error; |
| break; |
| case TS_DIAG_FATAL: |
| level = DL_Fatal; |
| break; |
| case TS_DIAG_ALERT: |
| level = DL_Alert; |
| break; |
| case TS_DIAG_EMERGENCY: |
| level = DL_Emergency; |
| break; |
| default: |
| level = DL_Diag; //default value should be Diag not UNDEFINED |
| } |
| |
| if (diags_init) { |
| diags->print("TSMgmtAPI", DTA(level), "%s", diag_msg); |
| ats_free(diag_msg); |
| return TS_ERR_OKAY; |
| } |
| |
| Lerror: |
| ats_free(diag_msg); |
| return TS_ERR_FAIL; |
| } |
| |
| /************************************************************************** |
| * handle_stats_reset |
| * |
| * purpose: handles request to reset statistics to default values |
| * input: struct SocketInfo sock_info - the socket to use to talk to client |
| * req - should be NULL |
| * op - reset type (cluster or node) |
| * output: TS_ERR_xx |
| *************************************************************************/ |
| TSError |
| handle_stats_reset(struct SocketInfo sock_info, char *req, OpType op) |
| { |
| TSError ret; |
| |
| ret = StatsReset(op == STATS_RESET_CLUSTER, req); |
| ret = send_reply(sock_info, ret); |
| |
| return ret; |
| } |