http://git-wip-us.apache.org/repos/asf/trafficserver/blob/8197736c/mgmt/api/CoreAPIRemote.cc
----------------------------------------------------------------------
diff --git a/mgmt/api/CoreAPIRemote.cc b/mgmt/api/CoreAPIRemote.cc
new file mode 100644
index 0000000..cb2ae5c
--- /dev/null
+++ b/mgmt/api/CoreAPIRemote.cc
@@ -0,0 +1,843 @@
+/** @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: CoreAPIRemote.cc
+ * Purpose: Implementation of CoreAPI.h interface but from remote client
+ *          perspective, so must also add networking calls. Basically, any
+ *          TSMgmtAPI calls which are "special" for remote clients
+ *          need to be implemented here.
+ * Note: For remote implementation of this interface, most functions will:
+ *  1) marshal: create the message to send across network
+ *  2) connect and send request
+ *  3) unmarshal: parse the reply (checking for TSError)
+ *
+ * Created: lant
+ *
+ ***************************************************************************/
+
+#include "ink_config.h"
+#include "ink_defs.h"
+#include <strings.h>
+#include "ink_string.h"
+#include "I_Layout.h"
+#include "ParseRules.h"
+#include "CoreAPI.h"
+#include "CoreAPIShared.h"
+#include "CfgContextUtils.h"
+#include "NetworkUtilsRemote.h"
+#include "NetworkUtilsDefs.h"
+#include "EventRegistration.h"
+#include "EventCallback.h"
+
+// extern variables
+extern CallbackTable *remote_event_callbacks;   // from EventRegistration
+extern int main_socket_fd;      // from NetworkUtils
+extern int event_socket_fd;
+
+// forward declarations
+TSError send_and_parse_basic(OpType op);
+TSError send_and_parse_list(OpType op, LLQ * list);
+TSError send_and_parse_name(OpType op, char *name);
+TSError mgmt_record_set(const char *rec_name, const char *rec_val, 
TSActionNeedT * action_need);
+bool start_binary(const char *abs_bin_path);
+
+// global variables
+// need to store the thread id associated with socket_test_thread
+// in case we want to  explicitly stop/cancel the testing thread
+ink_thread ts_test_thread;
+ink_thread ts_event_thread;
+TSInitOptionT ts_init_options;
+
+/***************************************************************************
+ * Helper Functions
+ ***************************************************************************/
+/*-------------------------------------------------------------------------
+ * send_and_parse_basic (helper function)
+ *-------------------------------------------------------------------------
+ * helper function used by operations which only require sending a simple
+ * operation type and parsing a simple error return value
+ */
+TSError
+send_and_parse_basic(OpType op)
+{
+  TSError err;
+
+  err = send_request(main_socket_fd, op);
+  if (err != TS_ERR_OKAY)
+    return err;                 // networking error
+
+  err = parse_reply(main_socket_fd);
+
+  return err;
+}
+
+/*-------------------------------------------------------------------------
+ * send_and_parse_list (helper function)
+ *-------------------------------------------------------------------------
+ * helper function used by operations which only require sending a simple
+ * operation type and parsing a string delimited list
+ * (delimited with REMOTE_DELIM_STR) and storing the tokens in the list
+ * parameter
+ */
+TSError
+send_and_parse_list(OpType op, LLQ * list)
+{
+  TSError ret;
+  char *list_str;
+  const char *tok;
+  Tokenizer tokens(REMOTE_DELIM_STR);
+  tok_iter_state i_state;
+
+  if (!list)
+    return TS_ERR_PARAMS;
+
+  // create and send request
+  ret = send_request(main_socket_fd, op);
+  if (ret != TS_ERR_OKAY)
+    return ret;
+
+  // parse the reply = delimited list of ids of active event names
+  ret = parse_reply_list(main_socket_fd, &list_str);
+  if (ret != TS_ERR_OKAY)
+    return ret;
+
+  // tokenize the list_str and put into LLQ; use Tokenizer
+  if (!list_str)
+    return TS_ERR_FAIL;
+
+  tokens.Initialize(list_str, COPY_TOKS);
+  tok = tokens.iterFirst(&i_state);
+  while (tok != NULL) {
+    enqueue(list, ats_strdup(tok));        // add token to LLQ
+    tok = tokens.iterNext(&i_state);
+  }
+
+  ats_free(list_str);
+  return TS_ERR_OKAY;
+}
+
+/*-------------------------------------------------------------------------
+ * send_and_parse_name (helper function)
+ *-------------------------------------------------------------------------
+ * helper function used by operations which only require sending a simple
+ * operation type with one string name argument and then parsing a simple
+ * TSError reply
+ * NOTE: name can be a NULL parameter!
+ */
+TSError
+send_and_parse_name(OpType op, char *name)
+{
+  TSError ret;
+
+  // create and send request
+  ret = send_request_name(main_socket_fd, op, name);
+  if (ret != TS_ERR_OKAY)
+    return ret;
+
+  // parse the reply
+  ret = parse_reply(main_socket_fd);
+
+  return ret;
+}
+
+
+/*-------------------------------------------------------------------------
+ * mgmt_record_set (helper function)
+ *-------------------------------------------------------------------------
+ * Helper function for all Set functions:
+ * NOTE: regardless of the type of the record being set,
+ * it is converted to a string. Then on the local side, the
+ * CoreAPI::MgmtRecordSet function will do the appropriate type
+ * converstion from the string to the record's type (eg. MgmtInt, MgmtString..)
+ * Hence, on the local side, don't have to worry about typecasting a
+ * void*. Just read out the string from socket and pass it MgmtRecordSet.
+ */
+TSError
+mgmt_record_set(const char *rec_name, const char *rec_val, TSActionNeedT * 
action_need)
+{
+  TSError err;
+
+  if (!rec_name || !rec_val || !action_need)
+    return TS_ERR_PARAMS;
+
+  // create and send request
+  err = send_request_name_value(main_socket_fd, RECORD_SET, rec_name, rec_val);
+  if (err != TS_ERR_OKAY)
+    return err;
+
+  // parse the reply to get TSError response and TSActionNeedT
+  err = parse_record_set_reply(main_socket_fd, action_need);
+
+  return err;
+}
+
+
+/*-------------------------------------------------------------------------
+ * start_binary
+ *-------------------------------------------------------------------------
+ * helper function which calls the executable specified by abs_bin_path;
+ * used by HardRestart to call the stop/start_traffic_server scripts
+ * Output: returns false if fail, true if successful
+ */
+bool
+start_binary(const char *abs_bin_path)
+{
+  TSDiags(TS_DIAG_NOTE, "[start_binary] abs_bin_path = %s", abs_bin_path);
+  // before doing anything, check for existence of binary and its execute
+  // permissions
+  if (access(abs_bin_path, F_OK) < 0) {
+    // ERROR: can't find binary
+    TSDiags(TS_DIAG_ERROR, "Cannot find executable %s", abs_bin_path);
+    return false;
+  }
+  // binary exists, check permissions
+  else if (access(abs_bin_path, R_OK | X_OK) < 0) {
+    // ERROR: doesn't have proper permissions
+    TSDiags(TS_DIAG_ERROR, "Cannot execute %s", abs_bin_path);
+    return false;
+  }
+
+  if (system(abs_bin_path) == -1) {
+    TSDiags(TS_DIAG_ERROR, "Cannot system(%s)", abs_bin_path);
+    return false;
+  }
+
+  return true;
+}
+
+
+/***************************************************************************
+ * SetUp Operations
+ ***************************************************************************/
+TSError
+Init(const char *socket_path, TSInitOptionT options)
+{
+  TSError err = TS_ERR_OKAY;
+
+  ts_init_options = options;
+
+  if (!socket_path) {
+    Layout::create();
+    socket_path = Layout::get()->runtimedir;
+  }
+
+  // store socket_path
+  set_socket_paths(socket_path);
+
+  // need to ignore SIGPIPE signal; in the case that TM is restarted
+  signal(SIGPIPE, SIG_IGN);
+
+  // EVENT setup - initialize callback queue
+  if (0 == (ts_init_options & TS_MGMT_OPT_NO_EVENTS)) {
+    remote_event_callbacks = create_callback_table("remote_callbacks");
+    if (!remote_event_callbacks)
+      return TS_ERR_SYS_CALL;
+  } else {
+    remote_event_callbacks = NULL;
+  }
+
+  // try to connect to traffic manager
+  // do this last so that everything else on client side is set up even if
+  // connection fails; this might happen if client is set up and running
+  // before TM
+  err = ts_connect();
+  if (err != TS_ERR_OKAY)
+    goto END;
+
+  // if connected, create event thread that listens for events from TM
+  if (0 == (ts_init_options & TS_MGMT_OPT_NO_EVENTS)) {
+    ts_event_thread = ink_thread_create(event_poll_thread_main, 
&event_socket_fd, 0, DEFAULT_STACK_SIZE);
+  } else {
+    ts_event_thread = static_cast<ink_thread>(NULL);
+  }
+
+END:
+
+  // create thread that periodically checks the socket connection
+  // with TM alive - reconnects if not alive
+  if (0 == (ts_init_options & TS_MGMT_OPT_NO_SOCK_TESTS)) {
+    ts_test_thread = ink_thread_create(socket_test_thread, NULL, 0, 
DEFAULT_STACK_SIZE);
+  } else {
+    ts_test_thread = static_cast<ink_thread>(NULL);
+  }
+
+  return err;
+
+}
+
+// does clean up for remote API client; destroy structures and disconnects
+TSError
+Terminate()
+{
+  TSError err;
+
+  if (remote_event_callbacks)
+    delete_callback_table(remote_event_callbacks);
+
+  // be sure to do this before reset socket_fd's
+  err = disconnect();
+  if (err != TS_ERR_OKAY)
+    return err;
+
+  // cancel the listening socket thread
+  // it's important to call this before setting paths to NULL because the
+  // socket_test_thread actually will try to reconnect() and this funntion
+  // will seg fault if the socket paths are NULL while it is connecting;
+  // the thread will be cancelled at a cancellation point in the
+  // socket_test_thread, eg. sleep
+  if (ts_test_thread)
+    ink_thread_cancel(ts_test_thread);
+  if (ts_event_thread)
+    ink_thread_cancel(ts_event_thread);
+
+  // Before clear, we should confirm these
+  // two threads have finished. Or the clear
+  // operation may lead them crash.
+  if (ts_test_thread)
+    ink_thread_join(ts_test_thread);
+  if (ts_event_thread)
+    ink_thread_join(ts_event_thread);
+
+  // Clear operation
+  ts_test_thread = static_cast<ink_thread>(NULL);
+  ts_event_thread = static_cast<ink_thread>(NULL);
+  set_socket_paths(NULL);       // clear the socket_path
+
+  return TS_ERR_OKAY;
+}
+
+// ONLY have very basic diag functionality for remote cliets.
+// When a remote client tries to use diags (wants to output runtime
+// diagnostics, the diagnostics will be outputted to the machine
+// the remote client is logged into (the one TM is running on)
+void
+Diags(TSDiagsT mode, const char *fmt, va_list ap)
+{
+  char diag_msg[MAX_BUF_SIZE];
+
+  // format the diag message now so it can be sent
+  // vsnprintf does not compile on DEC
+  vsnprintf(diag_msg, MAX_BUF_SIZE - 1, fmt, ap);
+  TSError ret = send_diags_msg(main_socket_fd, mode, diag_msg);
+  if (ret != TS_ERR_OKAY) {
+    //fprintf(stderr, "[Diags] error sending diags message\n");
+  }
+}
+
+/***************************************************************************
+ * Control Operations
+ ***************************************************************************/
+TSProxyStateT
+ProxyStateGet()
+{
+  TSError ret;
+  TSProxyStateT state;
+
+  ret = send_request(main_socket_fd, PROXY_STATE_GET);
+  if (ret != TS_ERR_OKAY)      // Networking error
+    return TS_PROXY_UNDEFINED;
+
+  ret = parse_proxy_state_get_reply(main_socket_fd, &state);
+  if (ret != TS_ERR_OKAY)      // Newtorking error
+    return TS_PROXY_UNDEFINED;
+
+  return state;
+}
+
+TSError
+ProxyStateSet(TSProxyStateT state, TSCacheClearT clear)
+{
+  TSError ret;
+
+  ret = send_proxy_state_set_request(main_socket_fd, state, clear);
+  if (ret != TS_ERR_OKAY)
+    return ret;                 // networking error
+
+  ret = parse_reply(main_socket_fd);
+
+  return ret;
+}
+
+TSError
+Reconfigure()
+{
+  return send_and_parse_basic(RECONFIGURE);
+}
+
+/*-------------------------------------------------------------------------
+ * Restart
+ *-------------------------------------------------------------------------
+ * if restart of TM is successful, need to reconnect to TM;
+ * it's possible that the SUCCESS msg is received before the
+ * restarting of TM is totally complete(?) b/c the core Restart call
+ * only signals the event putting it in a msg queue;
+ * so keep trying to reconnect until successful or for MAX_CONN_TRIES
+ */
+TSError
+Restart(bool cluster)
+{
+  TSError ret;
+
+  ret = send_request_bool(main_socket_fd, RESTART, cluster);
+  if (ret != TS_ERR_OKAY)
+    return ret;                 // networking error
+
+  ret = parse_reply(main_socket_fd);
+
+  if (ret == TS_ERR_OKAY) {
+    ret = reconnect_loop(MAX_CONN_TRIES);
+  }
+
+  return ret;
+}
+
+
+/*-------------------------------------------------------------------------
+ * HardRestart
+ *-------------------------------------------------------------------------
+ * Restarts Traffic Cop by using the stop_traffic_server, start_traffic_server 
script
+ */
+TSError
+HardRestart()
+{
+  char start_path[1024];
+  char stop_path[1024];
+
+  if (!Layout::get() || !Layout::get()->bindir)
+    return TS_ERR_FAIL;
+  // determine the path of where start and stop TS scripts stored
+  TSDiags(TS_DIAG_NOTE, "Root Directory: %s", Layout::get()->bindir);
+
+  Layout::relative_to(start_path, sizeof(start_path), Layout::get()->bindir, 
"start_traffic_server");
+  Layout::relative_to(stop_path, sizeof(stop_path), Layout::get()->bindir, 
"stop_traffic_server");
+
+  TSDiags(TS_DIAG_NOTE, "[HardRestart] start_path = %s", start_path);
+  TSDiags(TS_DIAG_NOTE, "[HardRestart] stop_path = %s", stop_path);
+
+  if (!start_binary(stop_path)) // call stop_traffic_server script
+    return TS_ERR_FAIL;
+
+  if (!start_binary(start_path))        // call start_traffic_server script
+    return TS_ERR_FAIL;
+
+  return TS_ERR_OKAY;
+}
+
+/*-------------------------------------------------------------------------
+ * Bounce
+ *-------------------------------------------------------------------------
+ * Restart the traffic_server process(es) only.
+ */
+TSError
+Bounce(bool cluster)
+{
+  TSError ret;
+
+  ret = send_request_bool(main_socket_fd, BOUNCE, cluster);
+  if (ret != TS_ERR_OKAY)
+    return ret;                 // networking error
+
+  return parse_reply(main_socket_fd);
+}
+
+
+/***************************************************************************
+ * Record Operations
+ ***************************************************************************/
+// note that the record value is being sent as chunk of memory, regardless of
+// record type; it's not being converted to a string!!
+TSError
+MgmtRecordGet(const char *rec_name, TSRecordEle * rec_ele)
+{
+  TSError ret;
+  void *val;
+
+  if (!rec_name || !rec_ele)
+    return TS_ERR_PARAMS;
+
+  rec_ele->rec_name = ats_strdup(rec_name);
+
+  // create and send request
+  ret = send_record_get_request(main_socket_fd, rec_ele->rec_name);
+  if (ret != TS_ERR_OKAY)
+    return ret;
+
+  // parse the reply to get record value and type
+  ret = parse_record_get_reply(main_socket_fd, &(rec_ele->rec_type), &val);
+  if (ret != TS_ERR_OKAY)
+    return ret;
+
+  // convert the record value to appropriate type
+  switch (rec_ele->rec_type) {
+  case TS_REC_INT:
+    rec_ele->int_val = *(TSInt *) val;
+    break;
+  case TS_REC_COUNTER:
+    rec_ele->counter_val = *(TSCounter *) val;
+    break;
+  case TS_REC_FLOAT:
+    rec_ele->float_val = *(TSFloat *) val;
+    break;
+  case TS_REC_STRING:
+    rec_ele->string_val = ats_strdup((char *) val);
+    break;
+  default:                     // ERROR - invalid record type
+    return TS_ERR_FAIL;
+  }
+
+  ats_free(val);
+  return TS_ERR_OKAY;
+}
+
+
+TSError
+MgmtRecordSet(const char *rec_name, const char *val, TSActionNeedT * 
action_need)
+{
+  TSError ret;
+
+  if (!rec_name || !val || !action_need)
+    return TS_ERR_PARAMS;
+
+  ret = mgmt_record_set(rec_name, val, action_need);
+  return ret;
+}
+
+// first convert the MgmtInt into a string
+// NOTE: use long long, not just long, MgmtInt = int64_t
+TSError
+MgmtRecordSetInt(const char *rec_name, MgmtInt int_val, TSActionNeedT * 
action_need)
+{
+  char str_val[MAX_RECORD_SIZE];
+  TSError ret;
+
+  if (!rec_name || !action_need)
+    return TS_ERR_PARAMS;
+
+  bzero(str_val, MAX_RECORD_SIZE);
+  snprintf(str_val, sizeof(str_val), "%" PRId64 "", int_val);
+  ret = mgmt_record_set(rec_name, str_val, action_need);
+
+  return ret;
+}
+
+// first convert the MgmtIntCounter into a string
+TSError
+MgmtRecordSetCounter(const char *rec_name, MgmtIntCounter counter_val, 
TSActionNeedT * action_need)
+{
+  char str_val[MAX_RECORD_SIZE];
+  TSError ret;
+
+  if (!rec_name || !action_need)
+    return TS_ERR_PARAMS;
+
+  bzero(str_val, MAX_RECORD_SIZE);
+  snprintf(str_val, sizeof(str_val), "%" PRId64 "", counter_val);
+  ret = mgmt_record_set(rec_name, str_val, action_need);
+
+  return ret;
+}
+
+// first convert the MgmtFloat into string
+TSError
+MgmtRecordSetFloat(const char *rec_name, MgmtFloat float_val, TSActionNeedT * 
action_need)
+{
+  char str_val[MAX_RECORD_SIZE];
+  TSError ret;
+
+  bzero(str_val, MAX_RECORD_SIZE);
+  if (snprintf(str_val, sizeof(str_val), "%f", float_val) < 0)
+    return TS_ERR_SYS_CALL;
+  ret = mgmt_record_set(rec_name, str_val, action_need);
+
+  return ret;
+}
+
+
+TSError
+MgmtRecordSetString(const char *rec_name, const char *string_val, 
TSActionNeedT * action_need)
+{
+  TSError ret;
+
+  if (!rec_name || !action_need)
+    return TS_ERR_PARAMS;
+
+  ret = mgmt_record_set(rec_name, string_val, action_need);
+  return ret;
+}
+
+
+/***************************************************************************
+ * File Operations
+ ***************************************************************************/
+/*-------------------------------------------------------------------------
+ * ReadFile
+ *-------------------------------------------------------------------------
+ * 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
+ * Output:
+ *
+ * Marshals a read file request that can be sent over the unix domain socket.
+ * Connects to the socket and sends request over. Parses the response from
+ * Traffic Manager.
+ */
+TSError
+ReadFile(TSFileNameT file, char **text, int *size, int *version)
+{
+  TSError ret;
+
+  // marshal data into message request to be sent over socket
+  // create connection and send request
+  ret = send_file_read_request(main_socket_fd, file);
+  if (ret != TS_ERR_OKAY)
+    return ret;
+
+  // read response from socket and unmarshal the response
+  ret = parse_file_read_reply(main_socket_fd, version, size, text);
+
+  return ret;
+}
+
+/*-------------------------------------------------------------------------
+ * 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
+ *
+ * Marshals a write file request that can be sent over the unix domain socket.
+ * Connects to the socket and sends request over. Parses the response from
+ * Traffic Manager.
+ */
+TSError
+WriteFile(TSFileNameT file, char *text, int size, int version)
+{
+  TSError ret;
+
+  ret = send_file_write_request(main_socket_fd, file, version, size, text);
+  if (ret != TS_ERR_OKAY)
+    return ret;
+
+  ret = parse_reply(main_socket_fd);
+
+  return ret;
+}
+
+
+/***************************************************************************
+ * Events
+ ***************************************************************************/
+/*-------------------------------------------------------------------------
+ * EventSignal
+ *-------------------------------------------------------------------------
+ * LAN - need to implement
+ */
+TSError
+EventSignal(char */* event_name ATS_UNUSED */, va_list /* ap ATS_UNUSED */)
+{
+  return TS_ERR_FAIL;
+}
+
+/*-------------------------------------------------------------------------
+ * EventResolve
+ *-------------------------------------------------------------------------
+ * purpose: Resolves the event of the specified name
+ * note:    when sending the message request, actually sends the event name,
+ *          not the event id
+ */
+TSError
+EventResolve(char *event_name)
+{
+  if (!event_name)
+    return TS_ERR_PARAMS;
+
+  return (send_and_parse_name(EVENT_RESOLVE, event_name));
+}
+
+/*-------------------------------------------------------------------------
+ * ActiveEventGetMlt
+ *-------------------------------------------------------------------------
+ * purpose: Retrieves a list of active(unresolved) events
+ * note:    list of event names returned in network msg which must be tokenized
+ */
+TSError
+ActiveEventGetMlt(LLQ * active_events)
+{
+  if (!active_events)
+    return TS_ERR_PARAMS;
+
+  return (send_and_parse_list(EVENT_GET_MLT, active_events));
+}
+
+/*-------------------------------------------------------------------------
+ * EventIsActive
+ *-------------------------------------------------------------------------
+ * determines if the event_name is active; sets result in is_current
+ */
+TSError
+EventIsActive(char *event_name, bool * is_current)
+{
+  TSError ret;
+
+  if (!event_name || !is_current)
+    return TS_ERR_PARAMS;
+
+  // create and send request
+  ret = send_request_name(main_socket_fd, EVENT_ACTIVE, event_name);
+  if (ret != TS_ERR_OKAY)
+    return ret;
+
+  // parse the reply
+  ret = parse_event_active_reply(main_socket_fd, is_current);
+  if (ret != TS_ERR_OKAY)
+    return ret;
+
+  return ret;
+}
+
+/*-------------------------------------------------------------------------
+ * EventSignalCbRegister
+ *-------------------------------------------------------------------------
+ * Adds the callback function in appropriate places in the remote side
+ * callback table.
+ * If this is the first callback to be registered for a certain event type,
+ * then sends a callback registration notification to TM so that TM will know
+ * which events have remote callbacks registered on it.
+ */
+TSError
+EventSignalCbRegister(char *event_name, TSEventSignalFunc func, void *data)
+{
+  bool first_time = 0;
+  TSError err;
+
+  if (func == NULL)
+    return TS_ERR_PARAMS;
+  if (!remote_event_callbacks)
+    return TS_ERR_FAIL;
+
+  err = cb_table_register(remote_event_callbacks, event_name, func, data, 
&first_time);
+  if (err != TS_ERR_OKAY)
+    return err;
+
+  // if we need to notify traffic manager of the event then send msg
+  if (first_time) {
+    err = send_request_name(event_socket_fd, EVENT_REG_CALLBACK, event_name);
+    if (err != TS_ERR_OKAY)
+      return err;
+  }
+
+  return TS_ERR_OKAY;
+}
+
+/*-------------------------------------------------------------------------
+ * EventSignalCbUnregister
+ *-------------------------------------------------------------------------
+ * Removes the callback function from the remote side callback table.
+ * After removing the callback function, needs to check which events now
+ * no longer have any callbacks registered at all; sends an unregister callback
+ * notification to TM so that TM knows that that event doesn't have any
+ * remote callbacks registered for it
+ * Input: event_name - the event to unregister the callback from; if NULL,
+ *                     unregisters the specified func from all events
+ *        func       - the callback function to unregister; if NULL, then
+ *                     unregisters all callback functions for the event_name
+ *                     specified
+ */
+TSError
+EventSignalCbUnregister(char *event_name, TSEventSignalFunc func)
+{
+  TSError err;
+
+  if (!remote_event_callbacks)
+    return TS_ERR_FAIL;
+
+  // remove the callback function from the table
+  err = cb_table_unregister(remote_event_callbacks, event_name, func);
+  if (err != TS_ERR_OKAY)
+    return err;
+
+  // check if we need to notify traffic manager of the event (notify TM
+  // only if the event has no callbacks)
+  err = send_unregister_all_callbacks(event_socket_fd, remote_event_callbacks);
+  if (err != TS_ERR_OKAY)
+    return err;
+
+  return TS_ERR_OKAY;
+}
+
+/***************************************************************************
+ * Snapshots
+ ***************************************************************************/
+TSError
+SnapshotTake(char *snapshot_name)
+{
+  if (!snapshot_name)
+    return TS_ERR_PARAMS;
+
+  return send_and_parse_name(SNAPSHOT_TAKE, snapshot_name);
+}
+
+TSError
+SnapshotRestore(char *snapshot_name)
+{
+  if (!snapshot_name)
+    return TS_ERR_PARAMS;
+
+  return send_and_parse_name(SNAPSHOT_RESTORE, snapshot_name);
+}
+
+TSError
+SnapshotRemove(char *snapshot_name)
+{
+  if (!snapshot_name)
+    return TS_ERR_PARAMS;
+
+  return send_and_parse_name(SNAPSHOT_REMOVE, snapshot_name);
+}
+
+TSError
+SnapshotGetMlt(LLQ * snapshots)
+{
+  return send_and_parse_list(SNAPSHOT_GET_MLT, snapshots);
+}
+
+TSError
+StatsReset(bool cluster, const char* name)
+{
+  TSError ret;
+
+  if (cluster) {
+    ret = send_request_name(main_socket_fd, STATS_RESET_CLUSTER, name);
+  } else {
+    ret = send_request_name(main_socket_fd, STATS_RESET_NODE, name);
+  }
+  if (ret != TS_ERR_OKAY)
+    return ret;                 // networking error
+
+  return parse_reply(main_socket_fd);
+}

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/8197736c/mgmt/api/EventRegistration.cc
----------------------------------------------------------------------
diff --git a/mgmt/api/EventRegistration.cc b/mgmt/api/EventRegistration.cc
new file mode 100644
index 0000000..2a3d7fb
--- /dev/null
+++ b/mgmt/api/EventRegistration.cc
@@ -0,0 +1,166 @@
+/** @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: EventRegistration.cc
+ * Purpose: This file contains functions and structures used in event
+ *          notification and callbacks for remote clients; also has the
+ *          thread that services event notification.
+ * Created: 2/15/01
+ *
+ *
+ ***************************************************************************/
+
+#include "libts.h"
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <string.h>
+
+#include "ink_thread.h"
+
+#include "MgmtSocket.h"
+
+#include "mgmtapi.h"
+#include "EventRegistration.h"
+#include "CoreAPIShared.h"
+#include "NetworkUtilsDefs.h"
+#include "NetworkUtilsRemote.h"
+#include "EventCallback.h"
+
+CallbackTable *remote_event_callbacks;
+
+/**********************************************************************
+ * event_poll_thread_main
+ *
+ * purpose: thread listens on the client's event socket connection;
+ *          only reads from the event_socket connection and
+ *          processes EVENT_NOTIFY messages; each time client
+ *          makes new event-socket connection to TM, must launch
+ *          a new event_poll_thread_main thread
+ * input:   arg - contains the socket_fd to listen on
+ * output:  NULL - if error
+ * notes:   each time the client's socket connection to TM is reset
+ *          a new thread will be launched as old one dies; there are
+ *          only two places where a new thread is created:
+ *          1) when client first connects (TSInit call)
+ *          2) client reconnects() due to a TM restart
+ * Uses blocking socket; so blocks until receives an event notification.
+ * Shouldn't need to use select since only waiting for a notification
+ * message from event_callback_main thread!
+ **********************************************************************/
+void *
+event_poll_thread_main(void *arg)
+{
+  TSError err;
+  int sock_fd;
+  TSEvent *event_notice = NULL;
+
+  sock_fd = *((int *) arg);     // should be same as event_socket_fd
+
+  // the sock_fd is going to be the one we listen for events on
+  while (1) {
+    // possible sock_fd is invalid if TM restarts and client reconnects
+    if (sock_fd < 0) {
+      break;
+    }
+
+    // read the entire message, so create TSEvent for the callback
+    event_notice = TSEventCreate();
+    err = parse_event_notification(sock_fd, event_notice);
+    if (err == TS_ERR_NET_READ || err == TS_ERR_NET_EOF) {
+      break;
+    } else if (err != TS_ERR_OKAY) {
+      TSEventDestroy(event_notice);
+      continue;                 // skip the message
+    }
+    // got event notice; spawn new thread to handle the event's callback 
functions
+    ink_thread_create(event_callback_thread, (void *) event_notice, 0, 
DEFAULT_STACK_SIZE);
+  }
+
+  if (event_notice)
+    TSEventDestroy(event_notice);
+  ink_thread_exit(NULL);
+  return NULL;
+}
+
+/**********************************************************************
+ * event_callback_thread
+ *
+ * purpose: Given an event, determines and calls the registered cb functions
+ *          in the CallbackTable for remote events
+ * input: arg - should be an TSEvent with the event info sent from TM msg
+ * output: returns when done calling all the callbacks
+ * notes: None
+ **********************************************************************/
+void *
+event_callback_thread(void *arg)
+{
+  TSEvent *event_notice;
+  EventCallbackT *event_cb;
+  int index;
+
+  event_notice = (TSEvent *) arg;
+  index = (int) event_notice->id;
+  LLQ *func_q;                  // list of callback functions need to call
+
+  func_q = create_queue();
+  if (!func_q) {
+    if (event_notice)
+      TSEventDestroy(event_notice);
+    return NULL;
+  }
+
+  // obtain lock
+  ink_mutex_acquire(&remote_event_callbacks->event_callback_lock);
+
+  TSEventSignalFunc cb;
+
+  // check if we have functions to call
+  if (remote_event_callbacks->event_callback_l[index] && 
(!queue_is_empty(remote_event_callbacks->event_callback_l[index]))) {
+    int queue_depth = 
queue_len(remote_event_callbacks->event_callback_l[index]);
+
+    for (int i = 0; i < queue_depth; i++) {
+      event_cb = (EventCallbackT *) 
dequeue(remote_event_callbacks->event_callback_l[index]);
+      cb = event_cb->func;
+      enqueue(remote_event_callbacks->event_callback_l[index], event_cb);
+      enqueue(func_q, (void *) cb);     // add callback function only to list
+    }
+  }
+  // release lock
+  ink_mutex_release(&remote_event_callbacks->event_callback_lock);
+
+  // execute the callback function
+  while (!queue_is_empty(func_q)) {
+    cb = (TSEventSignalFunc) dequeue(func_q);
+    (*cb) (event_notice->name, event_notice->description, 
event_notice->priority, NULL);
+  }
+
+  // clean up event notice
+  TSEventDestroy(event_notice);
+  delete_queue(func_q);
+
+  // all done!
+  ink_thread_exit(NULL);
+  return NULL;
+}

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/8197736c/mgmt/api/EventRegistration.h
----------------------------------------------------------------------
diff --git a/mgmt/api/EventRegistration.h b/mgmt/api/EventRegistration.h
new file mode 100644
index 0000000..fe4bb89
--- /dev/null
+++ b/mgmt/api/EventRegistration.h
@@ -0,0 +1,49 @@
+/** @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: EventRegistration.h
+ * Purpose: This file contains sturctures intended for event notification
+ * Created: 8/8/00
+ * Created by: Stephanie Song
+ *
+ ***************************************************************************/
+
+#ifndef _EVENT_REGISTRATION_H
+#define _EVENT_REGISTRATION_H
+
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+void *event_callback_thread(void *arg);
+void *event_poll_thread_main(void *arg);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* _EVENT_REGISTRATION_H */

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/8197736c/mgmt/api/Makefile.am
----------------------------------------------------------------------
diff --git a/mgmt/api/Makefile.am b/mgmt/api/Makefile.am
index b3b3c8b..a68a77a 100644
--- a/mgmt/api/Makefile.am
+++ b/mgmt/api/Makefile.am
@@ -17,7 +17,7 @@
 #  See the License for the specific language governing permissions and
 #  limitations under the License.
 
-SUBDIRS = remote include
+SUBDIRS = include
 
 AM_CPPFLAGS = \
   $(iocore_include_dirs) \
@@ -37,25 +37,54 @@ noinst_LIBRARIES = libmgmtapilocal.a
 libmgmtapilocal_a_SOURCES = \
   include/mgmtapi.h \
   CfgContextDefs.h \
+  CoreAPI.cc \
+  CoreAPI.h \
+  EventControlMain.cc \
+  EventControlMain.h \
+  NetworkUtilsDefs.h \
+  NetworkUtilsLocal.cc \
+  NetworkUtilsLocal.h \
+  TSControlMain.cc \
+  TSControlMain.h
+
+lib_LTLIBRARIES = libtsmgmt.la libtsmgmtshare.la
+libtsmgmtshare_la_SOURCES = \
   CfgContextImpl.cc \
   CfgContextImpl.h \
   CfgContextManager.cc \
   CfgContextManager.h \
   CfgContextUtils.cc \
   CfgContextUtils.h \
-  CoreAPI.cc \
-  CoreAPI.h \
   CoreAPIShared.cc \
   CoreAPIShared.h \
   EventCallback.cc \
   EventCallback.h \
-  EventControlMain.cc \
-  EventControlMain.h \
   GenericParser.cc \
   GenericParser.h \
-  INKMgmtAPI.cc \
-  NetworkUtilsDefs.h \
-  NetworkUtilsLocal.cc \
-  NetworkUtilsLocal.h \
-  TSControlMain.cc \
-  TSControlMain.h
+  INKMgmtAPI.cc
+
+if BUILD_TESTS
+  noinst_PROGRAMS = traffic_api_cli_remote
+endif
+
+
+libtsmgmt_la_LDFLAGS = -version-info @TS_LIBTOOL_VERSION@
+libtsmgmt_la_LIBADD = @LIBOBJS@ \
+  $(top_builddir)/lib/ts/libtsutil.la \
+  libtsmgmtshare.la
+
+libtsmgmt_la_SOURCES = \
+  CoreAPIRemote.cc \
+  EventRegistration.cc \
+  EventRegistration.h \
+  NetworkUtilsRemote.cc \
+  NetworkUtilsRemote.h
+
+if BUILD_TESTS
+  traffic_api_cli_remote_SOURCES = APITestCliRemote.cc
+endif
+
+traffic_api_cli_remote_LDADD = \
+  libtsmgmt.la \
+  $(top_builddir)/lib/ts/libtsutil.la \
+  @LIBTCL@ @LIBSSL@

Reply via email to