trafficserver-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From z..@apache.org
Subject [4/9] TS-2172: cleanup and move mgmt/api/remote up
Date Thu, 07 Nov 2013 03:40:21 GMT
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/8197736c/mgmt/api/NetworkUtilsRemote.cc
----------------------------------------------------------------------
diff --git a/mgmt/api/NetworkUtilsRemote.cc b/mgmt/api/NetworkUtilsRemote.cc
new file mode 100644
index 0000000..92a2e55
--- /dev/null
+++ b/mgmt/api/NetworkUtilsRemote.cc
@@ -0,0 +1,1772 @@
+/** @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: NetworkUtilsRemote.cc
+ * Purpose: This file contains functions used by remote api client to
+ *          marshal requests to TM and unmarshal replies from TM.
+ *          Also stores the information about the client's current
+ *          socket connection to Traffic Manager
+ * Created: 8/9/00
+ *
+ *
+ ***************************************************************************/
+
+#include "ink_config.h"
+#include "ink_defs.h"
+#include "ink_sock.h"
+#include "ink_string.h"
+#include "I_Layout.h"
+#include "NetworkUtilsRemote.h"
+#include "CoreAPI.h"
+#include "CoreAPIShared.h"
+#include "EventRegistration.h"
+#include "MgmtSocket.h"
+
+extern CallbackTable *remote_event_callbacks;
+
+int main_socket_fd = -1;
+int event_socket_fd = -1;
+
+// need to store for reconnecting scenario
+char *main_socket_path = NULL;  // "<path>/mgmtapisocket"
+char *event_socket_path = NULL; // "<path>/eventapisocket"
+
+// From CoreAPIRemote.cc
+extern ink_thread ts_test_thread;
+extern ink_thread ts_event_thread;
+extern TSInitOptionT ts_init_options;
+
+
+/**********************************************************************
+ * Socket Helper Functions
+ **********************************************************************/
+void
+set_socket_paths(const char *path)
+{
+  // free previously set paths if needed
+  ats_free(main_socket_path);
+  ats_free(event_socket_path);
+
+  // construct paths based on user input
+  // form by replacing "mgmtapisocket" with "eventapisocket"
+  if (path) {
+    main_socket_path = Layout::relative_to(path, "mgmtapisocket");
+    event_socket_path = Layout::relative_to(path, "eventapisocket");
+  } else {
+    main_socket_path = NULL;
+    event_socket_path = NULL;
+  }
+
+  return;
+}
+
+/**********************************************************************
+ * socket_test
+ *
+ * purpose: performs socket write to check status of other end of connection
+ * input: None
+ * output: return   0 if other end of connection closed;
+ *         return < 0 if socket write failed due to some other error
+ *         return > 0 if socket write successful
+ * notes: send the test msg: UNDEFINED_OP 0(=msg_len)
+ **********************************************************************/
+int
+socket_test(int fd)
+{
+  char msg[6];                  /* 6 = SIZE_OP + SIZE_LEN */
+  int16_t op;
+  int32_t msg_len = 0;
+  int ret, amount_read = 0;
+
+  // write the op
+  op = (int16_t) UNDEFINED_OP;
+  memcpy(msg, (void *) &op, SIZE_OP_T);
+
+  // write msg-len = 0
+  memcpy(msg + SIZE_OP_T, &msg_len, SIZE_LEN);
+
+  while (amount_read < 6) {
+    ret = write(fd, msg + amount_read, 6 - amount_read);
+    if (ret < 0) {
+      if (errno == EAGAIN)
+        continue;
+
+      if (errno == EPIPE || errno == ENOTCONN) {        // other socket end is closed
+        return 0;
+      }
+
+      return -1;
+    }
+    amount_read += ret;
+  }
+
+  return 1;                     // write was successful; connection still open
+}
+
+
+/***************************************************************************
+ * connect
+ *
+ * purpose: connects to the port on traffic server that listens to mgmt
+ *          requests & issues out responses and alerts
+ * 1) create and set the client socket_fd; connect to TM
+ * 2) create and set the client's event_socket_fd; connect to TM
+ * output: TS_ERR_OKAY          - if both sockets sucessfully connect to TM
+ *         TS_ERR_NET_ESTABLISH - at least one unsuccessful connection
+ * notes: If connection breaks it is responsibility of client to reconnect
+ *        otherwise traffic server will assume mgmt stopped request and
+ *        goes back to just sitting and listening for connection.
+ ***************************************************************************/
+TSError
+ts_connect()
+{
+  struct sockaddr_un client_sock;
+  struct sockaddr_un client_event_sock;
+
+  int sockaddr_len;
+
+  // make sure a socket path is set up
+  if (!main_socket_path || !event_socket_path)
+    goto ERROR;
+
+  // create a socket
+  main_socket_fd = socket(AF_UNIX, SOCK_STREAM, 0);
+  if (main_socket_fd < 0) {
+    //fprintf(stderr, "[connect] ERROR: can't open socket\n");
+    goto ERROR;                 // ERROR - can't open socket
+  }
+  // setup Unix domain socket
+  memset(&client_sock, 0, sizeof(sockaddr_un));
+  client_sock.sun_family = AF_UNIX;
+  ink_strlcpy(client_sock.sun_path, main_socket_path, sizeof(client_sock.sun_path));
+#if defined(darwin) || defined(freebsd)
+  sockaddr_len = sizeof(sockaddr_un);
+#else
+  sockaddr_len = sizeof(client_sock.sun_family) + strlen(client_sock.sun_path);
+#endif
+  // connect call
+  if (connect(main_socket_fd, (struct sockaddr *) &client_sock, sockaddr_len) < 0) {
+    fprintf(stderr, "[connect] ERROR (main_socket_fd %d): %s\n", main_socket_fd, strerror(int(errno)));
+    close(main_socket_fd);
+    main_socket_fd = -1;
+    goto ERROR;                 //connection is down
+  }
+  // -------- set up the event socket ------------------
+  // create a socket
+  event_socket_fd = socket(AF_UNIX, SOCK_STREAM, 0);
+  if (event_socket_fd < 0) {
+    //fprintf(stderr, "[connect] ERROR: can't open event socket\n");
+    close(main_socket_fd);      // close the other socket too!
+    main_socket_fd = -1;
+    goto ERROR;                 // ERROR - can't open socket
+  }
+  // setup Unix domain socket
+  memset(&client_event_sock, 0, sizeof(sockaddr_un));
+  client_event_sock.sun_family = AF_UNIX;
+  ink_strlcpy(client_event_sock.sun_path, event_socket_path, sizeof(client_sock.sun_path));
+#if defined(darwin) || defined(freebsd)
+  sockaddr_len = sizeof(sockaddr_un);
+#else
+  sockaddr_len = sizeof(client_event_sock.sun_family) + strlen(client_event_sock.sun_path);
+#endif
+  // connect call
+  if (connect(event_socket_fd, (struct sockaddr *) &client_event_sock, sockaddr_len) < 0) {
+    //fprintf(stderr, "[connect] ERROR (event_socket_fd %d): %s\n", event_socket_fd, strerror(int(errno)));
+    close(event_socket_fd);
+    close(main_socket_fd);
+    event_socket_fd = -1;
+    main_socket_fd = -1;
+    goto ERROR;                 //connection is down
+  }
+
+  return TS_ERR_OKAY;
+
+ERROR:
+  return TS_ERR_NET_ESTABLISH;
+}
+
+/***************************************************************************
+ * disconnect
+ *
+ * purpose: disconnect from traffic server; closes sockets and resets their values
+ * input: None
+ * output: TS_ERR_FAIL, TS_ERR_OKAY
+ * notes: doesn't do clean up - all cleanup should be done before here
+ ***************************************************************************/
+TSError
+disconnect()
+{
+  int ret;
+
+  if (main_socket_fd > 0) {
+    ret = close(main_socket_fd);
+    main_socket_fd = -1;
+    if (ret < 0)
+      return TS_ERR_FAIL;
+  }
+
+  if (event_socket_fd > 0) {
+    ret = close(event_socket_fd);
+    event_socket_fd = -1;
+    if (ret < 0)
+      return TS_ERR_FAIL;
+  }
+
+  return TS_ERR_OKAY;
+}
+
+/***************************************************************************
+ * reconnect
+ *
+ * purpose: reconnects to TM (eg. when TM restarts); does all the necesarry
+ *          set up for reconnection
+ * input: None
+ * output: TS_ERR_FAIL, TS_ERR_OKAY
+ * notes: necessarry events for a new client-TM connection:
+ * 1) get new socket_fd using old socket_path by calling connect()
+ * 2) relaunch event_poll_thread_main with new socket_fd
+ * 3) re-notify TM of all the client's registered callbacks by send msg
+ ***************************************************************************/
+TSError
+reconnect()
+{
+  TSError err;
+
+  err = disconnect();
+  if (err != TS_ERR_OKAY)      // problem disconnecting
+    return err;
+
+  // use the socket_path that was called by remote client on first init
+  // use connect instead of TSInit() b/c if TM restarted, client-side tables
+  // would be recreated; just want to reconnect to same socket_path
+  err = ts_connect();
+  if (err != TS_ERR_OKAY)      // problem establishing connection
+    return err;
+
+  // relaunch a new event thread since socket_fd changed
+  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);
+    // reregister the callbacks on the TM side for this new client connection
+    if (remote_event_callbacks) {
+      err = send_register_all_callbacks(event_socket_fd, remote_event_callbacks);
+      if (err != TS_ERR_OKAY)      // problem establishing connection
+        return err;
+    }
+  } else {
+    ts_event_thread = static_cast<ink_thread>(NULL);
+  }
+
+  return TS_ERR_OKAY;
+}
+
+/***************************************************************************
+ * reconnect_loop
+ *
+ * purpose: attempts to reconnect to TM (eg. when TM restarts) for the
+ *          specified number of times
+ * input:  num_attempts - number of reconnection attempts to try before quit
+ * output: TS_ERR_OKAY - if successfully reconnected within num_attempts
+ *         TS_ERR_xx - the reason the reconnection failed
+ * notes:
+ ***************************************************************************/
+TSError
+reconnect_loop(int num_attempts)
+{
+  int numTries = 0;
+  TSError err = TS_ERR_FAIL;
+
+  while (numTries < num_attempts) {
+    numTries++;
+    err = reconnect();
+    if (err == TS_ERR_OKAY) {
+      //fprintf(stderr, "[reconnect_loop] Successful reconnction; Leave loop\n");
+      return TS_ERR_OKAY;      // successful connection
+    }
+    sleep(1);                   // to make it slower
+  }
+
+  //fprintf(stderr, "[reconnect_loop] FAIL TO CONNECT after %d tries\n", num_attempts);
+  return err;                   // unsuccessful connection after num_attempts
+}
+
+/*************************************************************************
+ * connect_and_send
+ *
+ * purpose:
+ * When sending a request, it's possible that the user had restarted
+ * Traffic Manager. This means that the connection between TM and
+ * the remote client has been broken, so the client needs to re-"connect"
+ * to Traffic Manager. So, after "writing" to the socket in each
+ * "send_xx_request" function, need to check if the TM socket has
+ * been closed or not; the "write" function's errno will indicate if
+ * the other end of the socket has been closed or not. If it is closed,
+ * then need to try to re"connect", then resend the message request if
+ * the "connect" was successful.
+ * 1) try connect()
+ * 2) if connect() success, then resend the request.
+ * output: TS_ERR_NET_xx - connection problem or TS_ERR_OKAY
+ * notes:
+ * This function is basically called by the special "socket_write_conn" fn
+ * which will call this fn if it tries to write to the socket and discovers
+ * the local end of the socket is closed
+ * Warning: system also sends a SIGPIPE error when try to write to socket
+ * which is not open; which will by default terminate the process;
+ * client needs to "ignore" the SIGPIPE signal
+ **************************************************************************/
+TSError
+connect_and_send(const char *msg, int msg_len)
+{
+  TSError err;
+  int total_wrote = 0, ret;
+
+  // connects to TM and does all necessary event updates required
+  err = reconnect();
+  if (err != TS_ERR_OKAY)
+    return err;
+
+  // makes sure the descriptor is writable
+  if (socket_write_timeout(main_socket_fd, MAX_TIME_WAIT, 0) <= 0) {
+    return TS_ERR_NET_TIMEOUT;
+  }
+  // connection successfully established; resend msg
+  // socket_fd should be new fd
+  while (total_wrote < msg_len) {
+    ret = write(main_socket_fd, msg + total_wrote, msg_len - total_wrote);
+
+    if (ret == 0) {
+      return TS_ERR_NET_EOF;
+    }
+
+    if (ret < 0) {
+      if (errno == EAGAIN)
+        continue;
+      else if (errno == EPIPE || errno == ENOTCONN) {
+        // clean-up sockets
+        close(main_socket_fd);
+        close(event_socket_fd);
+        main_socket_fd = -1;
+        event_socket_fd = -1;
+
+        return TS_ERR_NET_ESTABLISH;   // can't establish connection
+
+      } else
+        return TS_ERR_NET_WRITE;       // general socket writing error
+
+    }
+
+    total_wrote += ret;
+  }
+
+  return TS_ERR_OKAY;
+}
+
+/**************************************************************************
+ * socket_write_conn
+ *
+ * purpose: guarantees writing of n bytes; if connection error, tries
+ *          reconnecting to TM again (in case TM was restarted)
+ * input:   fd to write to, buffer to write from & number of bytes to write
+ * output:  TS_ERR_xx
+ * note:   EPIPE - this happens if client makes a call after stopping then
+ *         starting TM again.
+ *         ENOTCONN - this happens if the client tries to make a call after
+ *         stopping TM, but before starting it; then restarts TM and makes a
+ *          new call
+ * In the send_xx_request function, use a special socket writing function
+ * which calls connect_and_send() instead of just the basic connect():
+ * 1) if the write returns EPIPE error, then call connect_and_send()
+ * 2) return the value returned from EPIPE
+ *************************************************************************/
+TSError
+socket_write_conn(int fd, const char *msg_buf, int bytes)
+{
+  int ret, byte_wrote = 0;
+
+  // makes sure the descriptor is writable
+  if (socket_write_timeout(fd, MAX_TIME_WAIT, 0) <= 0) {
+    return TS_ERR_NET_TIMEOUT;
+  }
+  // read until we fulfill the number
+  while (byte_wrote < bytes) {
+    ret = write(fd, msg_buf + byte_wrote, bytes - byte_wrote);
+
+    if (ret == 0) {
+      return TS_ERR_NET_EOF;
+    }
+
+    if (ret < 0) {
+      if (errno == EAGAIN)
+        continue;
+
+      else if (errno == EPIPE || errno == ENOTCONN) {   // other socket end is closed
+        // clean-up of sockets is done in reconnect()
+        return connect_and_send(msg_buf, bytes);
+      } else
+        return TS_ERR_NET_WRITE;
+    }
+    // we are all good here
+    byte_wrote += ret;
+  }
+
+  return TS_ERR_OKAY;
+}
+
+/**********************************************************************
+ * socket_test_thread
+ *
+ * purpose: continually polls to check if local end of socket connection
+ *          is still open; this thread is created when the client calls
+ *          Init() to initialize the API; and will not
+ *          die until the client process dies
+ * input: none
+ * output: if other end is closed, it reconnects to TM
+ * notes: uses the current main_socket_fd because the main_socket_fd could be
+ *        in flux; basically it is possible that the client will reconnect
+ *        from some other call, thus making the main_socket_fd actually
+ *        valid when socket_test is called
+ * reason: decided to create this "watcher" thread for the socket
+ *         connection because if TM is restarted or the client process
+ *         is started before the TM process, then the client will not
+ *         be able to receive any event notifications until a "request"
+ *         is issued. In order to prevent losing an event notifications
+ *         that are called in between the time TM is restarted and
+ *         client issues a first request, we just run this thread which
+ *         will try to reconnect to TM if it is not already connected
+ **********************************************************************/
+void *
+socket_test_thread(void *)
+{
+  // loop until client process dies
+  while (1) {
+    if (main_socket_fd == -1 || socket_test(main_socket_fd) <= 0) {
+      // ASSUMES that in between the time the socket_test is made
+      // and this reconnect call is made, the main_socket_fd remains
+      // the same (eg. no one else called reconnect to TM successfully!!
+      // WHAT IF in between this time, the client had issued a request
+      // calling socket_write_conn which then calls reconnect(); then
+      // reconnect will return an "ALREADY CONNECTED" error when it
+      // tries to connect, and on the next loop iteration, the socket_test
+      // will actually pass because main_socket_fd is valid!!
+      if (reconnect() == TS_ERR_OKAY) {
+        //fprintf(stderr, "[socket_test_thread] reconnect succeeds\n");
+      }
+    }
+
+    sleep(5);
+  }
+
+  ink_thread_exit(NULL);
+  return NULL;
+}
+
+/**********************************************************************
+ * MARSHALL REQUESTS
+ **********************************************************************/
+/**********************************************************************
+ * send_request
+ *
+ * purpose: sends file read request to Traffic Manager
+ * input:   fd - file descriptor to use to send to
+ *          op - the type of OpType request sending
+ * output:  TS_ERR_xx
+ * notes:  used by operations which don't need to send any additional
+ *         parameters
+ * format: <OpType> <msg_len=0>
+ **********************************************************************/
+TSError
+send_request(int fd, OpType op)
+{
+  int16_t op_t;
+  int32_t msg_len;
+  char msg_buf[SIZE_OP_T + SIZE_LEN];
+  TSError err;
+
+  // fill in op type
+  op_t = (int16_t) op;
+  memcpy(msg_buf, &op_t, SIZE_OP_T);
+
+  // fill in msg_len == 0
+  msg_len = 0;
+  memcpy(msg_buf + SIZE_OP_T, &msg_len, SIZE_LEN);
+
+  // send message
+  err = socket_write_conn(fd, msg_buf, SIZE_OP_T + SIZE_LEN);
+  return err;
+}
+
+/**********************************************************************
+ * send_request_name (helper fn)
+ *
+ * purpose: sends generic  request with one string argument name
+ * input: fd - file descriptor to use
+ *        op - .
+ * output: TS_ERR_xx
+ * note: format: <OpType> <str_len> <string>
+ **********************************************************************/
+TSError
+send_request_name(int fd, OpType op, const char *name)
+{
+  char *msg_buf;
+  int16_t op_t;
+  int32_t msg_len;
+  int total_len;
+  TSError err;
+
+  if (name == NULL) {           //reg callback for all events when op==EVENT_REG_CALLBACK
+    msg_len = 0;
+  } else {
+    msg_len = (int32_t) strlen(name);
+  }
+
+  total_len = SIZE_OP_T + SIZE_LEN + msg_len;
+  msg_buf = (char *)ats_malloc(sizeof(char) * total_len);
+
+  // fill in op type
+  op_t = (int16_t) op;
+  memcpy(msg_buf, (void *) &op_t, SIZE_OP_T);
+
+  // fill in msg_len
+  memcpy(msg_buf + SIZE_OP_T, (void *) &msg_len, SIZE_LEN);
+
+  // fill in name (if NOT NULL)
+  if (name)
+    memcpy(msg_buf + SIZE_OP_T + SIZE_LEN, name, msg_len);
+
+
+  // send message
+  err = socket_write_conn(fd, msg_buf, total_len);
+  ats_free(msg_buf);
+  return err;
+}
+
+/**********************************************************************
+ * send_request_name_value (helper fn)
+ *
+ * purpose: sends generic request with 2 str arguments; a name-value pair
+ * input: fd - file descriptor to use
+ *        op - Op type
+ * output: TS_ERR_xx
+ * note: format: <OpType> <name-len> <val-len> <name> <val>
+ **********************************************************************/
+TSError
+send_request_name_value(int fd, OpType op, const char *name, const char *value)
+{
+  char *msg_buf;
+  int msg_pos = 0, total_len;
+  int32_t msg_len, name_len, val_size;    // these are written to msg
+  int16_t op_t;
+  TSError err;
+
+  if (!name || !value)
+    return TS_ERR_PARAMS;
+
+  // set the sizes
+  name_len = strlen(name);
+  val_size = strlen(value);
+  msg_len = (SIZE_LEN * 2) + name_len + val_size;
+  total_len = SIZE_OP_T + SIZE_LEN + msg_len;
+  msg_buf = (char *)ats_malloc(sizeof(char) * (total_len));
+
+  // fill in op type
+  op_t = (int16_t) op;
+  memcpy(msg_buf + msg_pos, (void *) &op_t, SIZE_OP_T);
+  msg_pos += SIZE_OP_T;
+
+  // fill in msg length
+  memcpy(msg_buf + msg_pos, (void *) &msg_len, SIZE_LEN);
+  msg_pos += SIZE_LEN;
+
+  // fill in record name length
+  memcpy(msg_buf + msg_pos, (void *) &name_len, SIZE_LEN);
+  msg_pos += SIZE_LEN;
+
+  // fill in record value length
+  memcpy(msg_buf + msg_pos, (void *) &val_size, SIZE_LEN);
+  msg_pos += SIZE_LEN;
+
+  // fill in record name
+  memcpy(msg_buf + msg_pos, name, name_len);
+  msg_pos += name_len;
+
+  // fill in record value
+  memcpy(msg_buf + msg_pos, value, val_size);
+
+  // send message
+  err = socket_write_conn(fd, msg_buf, total_len);
+  ats_free(msg_buf);
+  return err;
+}
+
+/**********************************************************************
+ * send_request_bool (helper)
+ *
+ * purpose: sends a simple op with a boolean flag argument
+ * input: fd      - file descriptor to use
+ *        flag    - boolean flag
+ * output: TS_ERR_xx
+ **********************************************************************/
+TSError
+send_request_bool(int fd, OpType op, bool flag)
+{
+  char msg_buf[SIZE_OP_T + SIZE_LEN + SIZE_BOOL];
+  int16_t flag_t;
+  int32_t msg_len;
+
+  // Fill in the operator
+  memcpy(msg_buf, (void *) &op, SIZE_OP_T);
+
+  // fill in msg_len = SIZE_BOOL
+  msg_len = (int32_t) SIZE_BOOL;
+  memcpy(msg_buf + SIZE_OP_T, (void *)&msg_len, SIZE_LEN);
+
+  // Fill in the argument (the boolean flag)
+  flag_t = flag ? 1 : 0;
+  memcpy(msg_buf + SIZE_OP_T + SIZE_LEN, (void *) &flag_t, SIZE_BOOL);
+
+  // send message
+  return socket_write_conn(fd, msg_buf, SIZE_OP_T + SIZE_LEN + SIZE_BOOL);
+}
+
+/**********************************************************************
+ * send_file_read_request
+ *
+ * purpose: sends file read request to Traffic Manager
+ * input:   fd - file descriptor to use to send to
+ *          file - file to read
+ * output:  TS_ERR_xx
+ * notes:   first must create the message and then send it across network
+ *          msg format = <OpType> <msg_len> <TSFileNameT>
+ **********************************************************************/
+TSError
+send_file_read_request(int fd, TSFileNameT file)
+{
+  char msg_buf[SIZE_OP_T + SIZE_LEN + SIZE_FILE_T];
+  int msg_pos = 0;
+  int32_t msg_len = (int32_t) SIZE_FILE_T;  //marshalled values
+  int16_t op, file_t;
+
+  // fill in op type
+  op = (int16_t) FILE_READ;
+  memcpy(msg_buf + msg_pos, &op, SIZE_OP_T);
+  msg_pos += SIZE_OP_T;
+
+  // fill in msg length
+  memcpy(msg_buf + msg_pos, &msg_len, SIZE_LEN);
+  msg_pos += SIZE_LEN;
+
+  // fill in file type
+  file_t = (int16_t) file;
+  memcpy(msg_buf + msg_pos, &file_t, SIZE_FILE_T);
+
+  // send message
+  return socket_write_conn(fd, msg_buf, SIZE_OP_T + SIZE_LEN + SIZE_FILE_T);
+}
+
+/**********************************************************************
+ * send_file_write_request
+ *
+ * purpose: sends file write request to Traffic Manager
+ * input: fd - file descriptor to use
+ *        file - file to read
+ *        text - new text to write to specified file
+ *        size - length of the text
+ *        ver  - version of the file to be written
+ * output: TS_ERR_xx
+ * notes: format - FILE_WRITE <msg_len> <file_type> <file_ver> <file_size> <text>
+ **********************************************************************/
+TSError
+send_file_write_request(int fd, TSFileNameT file, int ver, int size, char *text)
+{
+  char *msg_buf;
+  int msg_pos = 0, total_len;
+  int32_t msg_len, f_size;        //marshalled values
+  int16_t op, file_t, f_ver;
+  TSError err;
+
+  if (!text)
+    return TS_ERR_PARAMS;
+
+  msg_len = SIZE_FILE_T + SIZE_VER + SIZE_LEN + size;
+  total_len = SIZE_OP_T + SIZE_LEN + msg_len;
+  msg_buf = (char *)ats_malloc(sizeof(char) * total_len);
+
+  // fill in op type
+  op = (int16_t) FILE_WRITE;
+  memcpy(msg_buf + msg_pos, &op, SIZE_OP_T);
+  msg_pos += SIZE_OP_T;
+
+  // fill in msg length
+  memcpy(msg_buf + msg_pos, &msg_len, SIZE_LEN);
+  msg_pos += SIZE_LEN;
+
+  // fill in file type
+  file_t = (int16_t) file;
+  memcpy(msg_buf + msg_pos, &file_t, SIZE_FILE_T);
+  msg_pos += SIZE_FILE_T;
+
+  // fill in file version
+  f_ver = (int16_t) ver;
+  memcpy(msg_buf + msg_pos, &f_ver, SIZE_VER);
+  msg_pos += SIZE_VER;
+
+  // fill in file size
+  f_size = (int32_t) size;        //typecase to be safe
+  memcpy(msg_buf + msg_pos, &f_size, SIZE_LEN);
+  msg_pos += SIZE_LEN;
+
+  // fill in text of file
+  memcpy(msg_buf + msg_pos, text, size);
+
+  // send message
+  err = socket_write_conn(fd, msg_buf, total_len);
+  ats_free(msg_buf);
+  return err;
+}
+
+/**********************************************************************
+ * send_record_get_request
+ *
+ * purpose: sends request to get record value from Traffic Manager
+ * input: fd       - file descriptor to use
+ *        rec_name - name of record to retrieve value for
+ * output: TS_ERR_xx
+ * format: RECORD_GET <msg_len> <rec_name>
+ **********************************************************************/
+TSError
+send_record_get_request(int fd, char *rec_name)
+{
+  char *msg_buf;
+  int msg_pos = 0, total_len;
+  int16_t op;
+  int32_t msg_len;
+  TSError err;
+
+  if (!rec_name)
+    return TS_ERR_PARAMS;
+
+  total_len = SIZE_OP_T + SIZE_LEN + strlen(rec_name);
+  msg_buf = (char *)ats_malloc(sizeof(char) * total_len);
+
+  // fill in op type
+  op = (int16_t) RECORD_GET;
+  memcpy(msg_buf + msg_pos, (void *) &op, SIZE_OP_T);
+  msg_pos += SIZE_OP_T;
+
+  // fill in msg length
+  msg_len = (int32_t) strlen(rec_name);
+  memcpy(msg_buf + msg_pos, (void *) &msg_len, SIZE_LEN);
+  msg_pos += SIZE_LEN;
+
+  // fill in record name
+  memcpy(msg_buf + msg_pos, rec_name, strlen(rec_name));
+
+  // send message
+  err = socket_write_conn(fd, msg_buf, total_len);
+  ats_free(msg_buf);
+  return err;
+}
+
+
+/*------ control functions -------------------------------------------*/
+/**********************************************************************
+ * send_proxy_state_get_request
+ *
+ * purpose: sends request to get the proxy state (on/off)
+ * input: fd       - file descriptor to use
+ * output: TS_ERR_xx
+ * note: format: PROXY_STATE_GET 0(=msg_len)
+ **********************************************************************/
+TSError
+send_proxy_state_get_request(int fd)
+{
+  TSError err;
+
+  err = send_request(fd, PROXY_STATE_GET);
+  return err;
+}
+
+/**********************************************************************
+ * send_proxy_state_set_request
+ *
+ * purpose: sends request to set the proxy state (on/off)
+ * input: fd    - file descriptor to use
+ *        state - TS_PROXY_ON, TS_PROXY_OFF
+ * output: TS_ERR_xx
+ * note: format: PROXY_STATE_SET  <msg_len> <TSProxyStateT> <TSCacheClearT>
+ **********************************************************************/
+TSError
+send_proxy_state_set_request(int fd, TSProxyStateT state, TSCacheClearT clear)
+{
+  char msg_buf[SIZE_OP_T + SIZE_LEN + SIZE_PROXY_T + SIZE_TS_ARG_T];
+  int16_t op, state_t, cache_t;
+  int32_t msg_len;
+
+  // fill in op type
+  op = (int16_t) PROXY_STATE_SET;
+  memcpy(msg_buf, (void *) &op, SIZE_OP_T);
+
+  // fill in msg_len
+  msg_len = (int32_t) (SIZE_PROXY_T + SIZE_TS_ARG_T);
+  memcpy(msg_buf + SIZE_OP_T, (void *) &msg_len, SIZE_LEN);
+
+  // fill in proxy state
+  state_t = (int16_t) state;
+  memcpy(msg_buf + SIZE_OP_T + SIZE_LEN, (void *) &state_t, SIZE_PROXY_T);
+
+  // fill in cache clearing option
+  cache_t = (int16_t) clear;
+  memcpy(msg_buf + SIZE_OP_T + SIZE_LEN + SIZE_PROXY_T, (void *) &cache_t, SIZE_TS_ARG_T);
+
+  // send message
+  return socket_write_conn(fd, msg_buf, SIZE_OP_T + SIZE_LEN + SIZE_PROXY_T + SIZE_TS_ARG_T);
+}
+
+
+/*------ events -------------------------------------------------------*/
+
+/**********************************************************************
+ * send_register_all_callbacks
+ *
+ * purpose: determines all events which have at least one callback registered
+ *          and sends message to notify TM that this client has a callback
+ *          registered for each event
+ * input: None
+ * output: return TS_ERR_OKAY only if ALL events sent okay
+ * notes: could create a function which just sends a list of all the events to
+ * reregister; but actually just reuse the function
+ * send_request_name(EVENT_REG_CALLBACK) and call it for each event
+ * 1) get list of all events with callbacks
+ * 2) for each event, call send_request_name
+ **********************************************************************/
+TSError
+send_register_all_callbacks(int fd, CallbackTable * cb_table)
+{
+  LLQ *events_with_cb;
+  TSError err, send_err = TS_ERR_FAIL;
+  bool no_errors = true;        // set to false if one send is not okay
+
+  events_with_cb = get_events_with_callbacks(cb_table);
+  // need to check that the list has all the events registered
+  if (!events_with_cb) {        // all events have registered callback
+    err = send_request_name(fd, EVENT_REG_CALLBACK, NULL);
+    if (err != TS_ERR_OKAY)
+      return err;
+  } else {
+    char *event_name;
+    int event_id;
+    int num_events = queue_len(events_with_cb);
+    // iterate through the LLQ and send request for each event
+    for (int i = 0; i < num_events; i++) {
+      event_id = *(int *) dequeue(events_with_cb);
+      event_name = (char *) get_event_name(event_id);
+      if (event_name) {
+        err = send_request_name(fd, EVENT_REG_CALLBACK, event_name);
+        ats_free(event_name);      // free memory
+        if (err != TS_ERR_OKAY) {
+          send_err = err;       // save the type of send error
+          no_errors = false;
+        }
+      }
+      // REMEMBER: WON"T GET A REPLY from TM side!
+    }
+  }
+
+  if (events_with_cb)
+    delete_queue(events_with_cb);
+
+  if (no_errors)
+    return TS_ERR_OKAY;
+  else
+    return send_err;
+}
+
+/**********************************************************************
+ * send_unregister_all_callbacks
+ *
+ * purpose: determines all events which have no callback registered
+ *          and sends message to notify TM that this client has no
+ *          callbacks registered for that event
+ * input: None
+ * output: TS_ERR_OKAY only if all send requests are okay
+ * notes: could create a function which just sends a list of all the events to
+ * unregister; but actually just reuse the function
+ * send_request_name(EVENT_UNREG_CALLBACK) and call it for each event
+ **********************************************************************/
+TSError
+send_unregister_all_callbacks(int fd, CallbackTable * cb_table)
+{
+  char *event_name;
+  int event_id;
+  LLQ *events_with_cb;          // list of events with at least one callback
+  int reg_callback[NUM_EVENTS];
+  TSError err, send_err = TS_ERR_FAIL;
+  bool no_errors = true;        // set to false if at least one send fails
+
+  // init array so that all events don't have any callbacks
+  for (int i = 0; i < NUM_EVENTS; i++) {
+    reg_callback[i] = 0;
+  }
+
+  events_with_cb = get_events_with_callbacks(cb_table);
+  if (!events_with_cb) {        // all events have a registered callback
+    return TS_ERR_OKAY;
+  } else {
+    int num_events = queue_len(events_with_cb);
+    // iterate through the LLQ and mark events that have a callback
+    for (int i = 0; i < num_events; i++) {
+      event_id = *(int *) dequeue(events_with_cb);
+      reg_callback[event_id] = 1;       // mark the event as having a callback
+    }
+    delete_queue(events_with_cb);
+  }
+
+  // send message to TM to mark unregister
+  for (int k = 0; k < NUM_EVENTS; k++) {
+    if (reg_callback[k] == 0) { // event has no registered callbacks
+      event_name = get_event_name(k);
+      err = send_request_name(fd, EVENT_UNREG_CALLBACK, event_name);
+      ats_free(event_name);
+      if (err != TS_ERR_OKAY) {
+        send_err = err;         //save the type of the sending error
+        no_errors = false;
+      }
+      // REMEMBER: WON"T GET A REPLY!
+      // only the event_poll_thread_main does any reading of the event_socket;
+      // so DO NOT parse reply b/c a reply won't be sent
+    }
+  }
+
+  if (no_errors)
+    return TS_ERR_OKAY;
+  else
+    return send_err;
+}
+
+/**********************************************************************
+ * send_diags_msg
+ *
+ * purpose: sends the diag msg across along with they diag msg type
+ * input: mode - type of diags msg
+ *        msg  - the diags msg
+ * output: TS_ERR_xx
+ * note: format: <OpType> <msg_len> <TSDiagsT> <diag_msg_len> <diag_msg>
+ **********************************************************************/
+TSError
+send_diags_msg(int fd, TSDiagsT mode, const char *diag_msg)
+{
+  char *msg_buf;
+  int16_t op_t, diag_t;
+  int32_t msg_len, diag_msg_len;
+  int total_len;
+  TSError err;
+
+  if (!diag_msg)
+    return TS_ERR_PARAMS;
+
+  diag_msg_len = (int32_t) strlen(diag_msg);
+  msg_len = SIZE_DIAGS_T + SIZE_LEN + diag_msg_len;
+  total_len = SIZE_OP_T + SIZE_LEN + msg_len;
+  msg_buf = (char *)ats_malloc(sizeof(char) * total_len);
+
+  // fill in op type
+  op_t = (int16_t) DIAGS;
+  memcpy(msg_buf, (void *) &op_t, SIZE_OP_T);
+
+  // fill in entire msg len
+  memcpy(msg_buf + SIZE_OP_T, (void *) &msg_len, SIZE_LEN);
+
+  // fill in TSDiagsT
+  diag_t = (int16_t) mode;
+  memcpy(msg_buf + SIZE_OP_T + SIZE_LEN, (void *) &diag_t, SIZE_DIAGS_T);
+
+  // fill in diags msg_len
+  memcpy(msg_buf + SIZE_OP_T + SIZE_LEN + SIZE_DIAGS_T, (void *) &diag_msg_len, SIZE_LEN);
+
+  // fill in diags msg
+  memcpy(msg_buf + SIZE_OP_T + SIZE_LEN + SIZE_DIAGS_T + SIZE_LEN, diag_msg, diag_msg_len);
+
+  // send message
+  err = socket_write_conn(fd, msg_buf, total_len);
+  ats_free(msg_buf);
+  return err;
+}
+
+
+/**********************************************************************
+ * UNMARSHAL REPLIES
+ **********************************************************************/
+
+/* Error handling implementation:
+ * All the parsing functions which parse the reply returned from local side
+ * also must read the TSERror return value sent from local side; this return
+ * value is the same value that will be returned by the parsing function.
+ * ALL PARSING FUNCTIONS MUST FIRST CHECK that the retval is TS_ERR_OKAY;
+ * if it is not, then DON"T PARSE THE REST OF THE REPLY!!
+ */
+
+/* Reading replies:
+ * The reading is done in while loop in the parse_xx_reply functions;
+ * need to add a timeout so that the function is not left looping and
+ * waiting if a msg isn't sent to the socket from local side (eg. TM died)
+ */
+
+/**********************************************************************
+ * parse_reply
+ *
+ * purpose: parses a reply from traffic manager. return that error
+ * input: fd
+ * output: errors on error or fill up class with response &
+ *         return TS_ERR_xx
+ * notes: only returns an TSError
+ **********************************************************************/
+TSError
+parse_reply(int fd)
+{
+  int ret, amount_read = 0;
+  int16_t ret_val;
+
+  // check to see if anything to read; wait for specified time = 1 sec
+  if (socket_read_timeout(fd, MAX_TIME_WAIT, 0) <= 0) { // time expires before ready to read
+    return TS_ERR_NET_TIMEOUT;
+  }
+  // get the return value (TSError type)
+  while (amount_read < SIZE_ERR_T) {
+    ret = read(fd, (void *) &ret_val, SIZE_ERR_T - amount_read);
+
+    if (ret < 0) {
+      if (errno == EAGAIN)
+        continue;
+      else {
+        return TS_ERR_NET_READ;
+      }
+    }
+
+    if (ret == 0) {
+      return TS_ERR_NET_EOF;
+    }
+    // all is good here :)
+    amount_read += ret;
+  }
+
+  return (TSError) ret_val;
+}
+
+/**********************************************************************
+ * parse_reply_list
+ *
+ * purpose: parses a TM reply to a request to get a list of string tokens
+ * input: fd - socket to read
+ *        list - will contain delimited string list of tokens
+ * output: TS_ERR_xx
+ * notes:
+ * format: <TSError> <string_list_len> <delimited_string_list>
+ **********************************************************************/
+TSError
+parse_reply_list(int fd, char **list)
+{
+  int ret, amount_read = 0;
+  int16_t ret_val;
+  int32_t list_size;
+  TSError err_t;
+
+  if (!list)
+    return TS_ERR_PARAMS;
+
+  // check to see if anything to read; wait for specified time
+  if (socket_read_timeout(fd, MAX_TIME_WAIT, 0) <= 0) {
+    return TS_ERR_NET_TIMEOUT;
+  }
+  // get the return value (TSError type)
+  while (amount_read < SIZE_ERR_T) {
+    ret = read(fd, (void *) &ret_val, SIZE_ERR_T - amount_read);
+
+    if (ret < 0) {
+      if (errno == EAGAIN)
+        continue;
+      else {
+        return TS_ERR_NET_READ;
+      }
+    }
+
+    if (ret == 0) {
+      return TS_ERR_NET_EOF;
+    }
+    // all is good here :)
+    amount_read += ret;
+  }
+  // if !TS_ERR_OKAY, stop reading rest of msg
+  err_t = (TSError) ret_val;
+  if (err_t != TS_ERR_OKAY) {
+    return err_t;
+  }
+  // now get size of string event list
+  amount_read = 0;
+  while (amount_read < SIZE_LEN) {
+    ret = read(fd, (void *) &list_size, SIZE_LEN - amount_read);
+
+    if (ret < 0) {
+      if (errno == EAGAIN)
+        continue;
+      else {
+        return TS_ERR_NET_READ;
+      }
+    }
+
+    if (ret == 0) {
+      return TS_ERR_NET_EOF;
+    }
+    // all is good here :)
+    amount_read += ret;
+  }
+
+  // get the delimited event list string
+  *list = (char *)ats_malloc(sizeof(char) * (list_size + 1));
+  amount_read = 0;
+  while (amount_read < list_size) {
+    ret = read(fd, (void *) *list, list_size - amount_read);
+
+    if (ret < 0) {
+      if (errno == EAGAIN)
+        continue;
+      else {
+        ats_free(*list);
+        return TS_ERR_NET_READ;
+      }
+    }
+
+    if (ret == 0) {
+      ats_free(*list);
+      return TS_ERR_NET_EOF;
+    }
+
+    amount_read += ret;
+  }
+  // add end of string to end of the record value
+  ((char *) (*list))[list_size] = '\0';
+
+  return err_t;
+}
+
+
+/**********************************************************************
+ * parse_file_read_reply
+ *
+ * purpose: parses a file read reply from traffic manager.
+ * input: fd
+ *        ver -
+ *        size - size of text
+ *        text -
+ * output: errors on error or fill up class with response &
+ *         return TS_ERR_xx
+ * notes: reply format = <TSError> <file_version> <file_size> <text>
+ **********************************************************************/
+TSError
+parse_file_read_reply(int fd, int *ver, int *size, char **text)
+{
+  int ret, amount_read = 0;
+  int32_t f_size;
+  int16_t ret_val, f_ver;
+  TSError err_t;
+
+  if (!ver || !size || !text)
+    return TS_ERR_PARAMS;
+
+  // check to see if anything to read; wait for specified time
+  if (socket_read_timeout(fd, MAX_TIME_WAIT, 0) <= 0) { // time expires before ready to read
+    return TS_ERR_NET_TIMEOUT;
+  }
+  // get the error return value
+  while (amount_read < SIZE_ERR_T) {
+    ret = read(fd, (void *) &ret_val, SIZE_ERR_T - amount_read);
+
+    if (ret < 0) {
+      if (errno == EAGAIN)
+        continue;
+      else {
+        return TS_ERR_NET_READ;
+      }
+    }
+
+    if (ret == 0) {
+      return TS_ERR_NET_EOF;
+    }
+
+    amount_read += ret;
+  }
+  // if !TS_ERR_OKAY, stop reading rest of msg
+  err_t = (TSError) ret_val;
+  if (err_t != TS_ERR_OKAY) {
+    return err_t;
+  }
+  // now get file version
+  amount_read = 0;
+  while (amount_read < SIZE_VER) {
+    ret = read(fd, (void *) &f_ver, SIZE_VER - amount_read);
+
+    if (ret < 0) {
+      if (errno == EAGAIN)
+        continue;
+      else {
+        return TS_ERR_NET_READ;
+      }
+    }
+
+    if (ret == 0) {
+      return TS_ERR_NET_EOF;
+    }
+
+    amount_read += ret;
+  }
+  *ver = (int) f_ver;
+
+  // now get file size
+  amount_read = 0;
+  while (amount_read < SIZE_LEN) {
+    ret = read(fd, (void *) &f_size, SIZE_LEN - amount_read);
+
+    if (ret < 0) {
+      if (errno == EAGAIN)
+        continue;
+      else {
+        return TS_ERR_NET_READ;
+      }
+    }
+
+    if (ret == 0) {
+      return TS_ERR_NET_EOF;
+    }
+    // all is good here :)
+    amount_read += ret;
+  }
+  *size = (int) f_size;
+
+  // check size before reading text
+  if ((*size) <= 0) {
+    *text = ats_strndup("", 1);                 // set to empty string
+  } else {
+    // now we got the size, we can read everything into our msg * then parse it
+    *text = (char *)ats_malloc(sizeof(char) * (f_size + 1));
+    amount_read = 0;
+    while (amount_read < f_size) {
+      ret = read(fd, (void *) *text, f_size - amount_read);
+
+      if (ret < 0) {
+        if (errno == EAGAIN)
+          continue;
+        else {
+          ats_free(*text);
+          return TS_ERR_NET_READ;
+        }
+      }
+
+      if (ret == 0) {
+        ats_free(*text);
+        return TS_ERR_NET_EOF;
+      }
+
+      amount_read += ret;
+    }
+    (*text)[f_size] = '\0';     // end the string
+  }
+
+  return err_t;
+}
+
+/**********************************************************************
+ * parse_record_get_reply
+ *
+ * purpose: parses a record_get reply from traffic manager.
+ * input: fd
+ *        retval   -
+ *        rec_type - the type of the record
+ *        rec_value - the value of the record in string format
+ * output: errors on error or fill up class with response &
+ *         return SUCC
+ * notes: reply format = <TSError> <val_size> <rec_type> <record_value>
+ * It's the responsibility of the calling function to conver the rec_value
+ * based on the rec_type!!
+ **********************************************************************/
+TSError
+parse_record_get_reply(int fd, TSRecordT * rec_type, void **rec_val)
+{
+  int ret, amount_read = 0;
+  int16_t ret_val, rec_t;
+  int32_t rec_size;
+  TSError err_t;
+
+  if (!rec_type || !rec_val)
+    return TS_ERR_PARAMS;
+
+  // check to see if anything to read; wait for specified time
+  if (socket_read_timeout(fd, MAX_TIME_WAIT, 0) <= 0) { //time expired before ready to read
+    return TS_ERR_NET_TIMEOUT;
+  }
+  // get the return value (TSError type)
+  while (amount_read < SIZE_ERR_T) {
+    ret = read(fd, (void *) &ret_val, SIZE_ERR_T - amount_read);
+
+    if (ret < 0) {
+      if (errno == EAGAIN)
+        continue;
+      else {
+        return TS_ERR_NET_READ;
+      }
+    }
+
+    if (ret == 0) {
+      return TS_ERR_NET_EOF;
+    }
+    // all is good here :)
+    amount_read += ret;
+  }
+  // if !TS_ERR_OKAY, stop reading rest of msg
+  err_t = (TSError) ret_val;
+  if (err_t != TS_ERR_OKAY) {
+    return err_t;
+  }
+  // now get size of record_value
+  amount_read = 0;
+  while (amount_read < SIZE_LEN) {
+    ret = read(fd, (void *) &rec_size, SIZE_LEN - amount_read);
+
+    if (ret < 0) {
+      if (errno == EAGAIN)
+        continue;
+      else {
+        return TS_ERR_NET_READ;
+      }
+    }
+
+    if (ret == 0) {
+      return TS_ERR_NET_EOF;
+    }
+    // all is good here :)
+    amount_read += ret;
+  }
+
+  // get the record type
+  amount_read = 0;
+  while (amount_read < SIZE_REC_T) {
+    ret = read(fd, (void *) &rec_t, SIZE_REC_T - amount_read);
+
+    if (ret < 0) {
+      if (errno == EAGAIN) {
+        continue;
+      } else {
+        return TS_ERR_NET_READ;
+      }
+    }
+
+    if (ret == 0) {
+      return TS_ERR_NET_EOF;
+    }
+    // all is good here :)
+    amount_read += ret;
+  }
+  *rec_type = (TSRecordT) rec_t;
+
+  // get record value
+  // allocate correct amount of memory for record value
+  if (*rec_type == TS_REC_STRING)
+    *rec_val = ats_malloc(sizeof(char) * (rec_size + 1));
+  else
+    *rec_val = ats_malloc(sizeof(char) * (rec_size));
+
+  amount_read = 0;
+  while (amount_read < rec_size) {
+    ret = read(fd, (void *) *rec_val, rec_size - amount_read);
+
+    if (ret < 0) {
+      if (errno == EAGAIN)
+        continue;
+      else {
+        ats_free(*rec_val);
+        return TS_ERR_NET_READ;
+      }
+    }
+
+    if (ret == 0) {
+      ats_free(*rec_val);
+      return TS_ERR_NET_EOF;
+    }
+
+    amount_read += ret;
+  }
+  // add end of string to end of the record value
+  if (*rec_type == TS_REC_STRING)
+    ((char *) (*rec_val))[rec_size] = '\0';
+
+  return err_t;
+}
+
+/**********************************************************************
+ * parse_record_set_reply
+ *
+ * purpose: parses a record_set reply from traffic manager.
+ * input: fd
+ *        action_need - will contain the type of action needed from the set
+ * output: TS_ERR_xx
+ * notes: reply format = <TSError> <val_size> <rec_type> <record_value>
+ * It's the responsibility of the calling function to conver the rec_value
+ * based on the rec_type!!
+ **********************************************************************/
+TSError
+parse_record_set_reply(int fd, TSActionNeedT * action_need)
+{
+  int ret, amount_read = 0;
+  int16_t ret_val, action_t;
+  TSError err_t;
+
+  if (!action_need)
+    return TS_ERR_PARAMS;
+
+  // check to see if anything to read; wait for specified time
+  if (socket_read_timeout(fd, MAX_TIME_WAIT, 0) <= 0) {
+    return TS_ERR_NET_TIMEOUT;
+  }
+  // get the return value (TSError type)
+  while (amount_read < SIZE_ERR_T) {
+    ret = read(fd, (void *) &ret_val, SIZE_ERR_T - amount_read);
+
+    if (ret < 0) {
+      if (errno == EAGAIN)
+        continue;
+      else {
+        return TS_ERR_NET_READ;
+      }
+    }
+
+    if (ret == 0) {
+      return TS_ERR_NET_EOF;
+    }
+    // all is good here :)
+    amount_read += ret;
+  }
+  // if !TS_ERR_OKAY, stop reading rest of msg
+  err_t = (TSError) ret_val;
+  if (err_t != TS_ERR_OKAY) {
+    return err_t;
+  }
+  // now get the action needed
+  amount_read = 0;
+  while (amount_read < SIZE_ACTION_T) {
+    ret = read(fd, (void *) &action_t, SIZE_ACTION_T - amount_read);
+
+    if (ret < 0) {
+      if (errno == EAGAIN)
+        continue;
+      else {
+        return TS_ERR_NET_READ;
+      }
+    }
+
+    if (ret == 0) {
+      return TS_ERR_NET_EOF;
+    }
+    // all is good here :)
+    amount_read += ret;
+  }
+  *action_need = (TSActionNeedT) action_t;
+
+  return err_t;
+}
+
+
+/**********************************************************************
+ * parse_proxy_state_get_reply
+ *
+ * purpose: parses a TM reply to a PROXY_STATE_GET request
+ * input: fd
+ *        state - will contain the state of the proxy
+ * output: TS_ERR_xx
+ * notes: function is DIFFERENT becuase it has NO TSError at head of msg
+ * format: <TSProxyStateT>
+ **********************************************************************/
+TSError
+parse_proxy_state_get_reply(int fd, TSProxyStateT * state)
+{
+  int ret, amount_read = 0;
+  int16_t state_t;
+
+  if (!state)
+    return TS_ERR_PARAMS;
+
+  // check to see if anything to read; wait for specified time
+  if (socket_read_timeout(fd, MAX_TIME_WAIT, 0) <= 0) { // time expires before ready to read
+    return TS_ERR_NET_TIMEOUT;
+  }
+  // now get proxy state
+  amount_read = 0;
+  while (amount_read < SIZE_PROXY_T) {
+    ret = read(fd, (void *) &state_t, SIZE_PROXY_T - amount_read);
+
+    if (ret < 0) {
+      if (errno == EAGAIN)
+        continue;
+      else {
+        return TS_ERR_NET_READ;
+      }
+    }
+
+    if (ret == 0) {
+      return TS_ERR_NET_EOF;
+    }
+    // all is good here :)
+    amount_read += ret;
+  }
+  *state = (TSProxyStateT) state_t;
+
+  return TS_ERR_OKAY;
+}
+
+/*------------- events ---------------------------------------------*/
+
+/**********************************************************************
+ * parse_event_active_reply
+ *
+ * purpose: parses a TM reply to a request to get status of an event
+ * input: fd - socket to read
+ *        is_active - set to true if event is active; false otherwise
+ * output: TS_ERR_xx
+ * notes:
+ * format: reply format = <TSError> <bool>
+ **********************************************************************/
+TSError
+parse_event_active_reply(int fd, bool * is_active)
+{
+  int ret, amount_read = 0;
+  int16_t ret_val, active;
+  TSError err_t;
+
+  if (!is_active)
+    return TS_ERR_PARAMS;
+
+  // check to see if anything to read; wait for specified time
+  if (socket_read_timeout(fd, MAX_TIME_WAIT, 0) <= 0) {
+    return TS_ERR_NET_TIMEOUT;
+  }
+  // get the return value (TSError type)
+  while (amount_read < SIZE_ERR_T) {
+    ret = read(fd, (void *) &ret_val, SIZE_ERR_T - amount_read);
+
+    if (ret < 0) {
+      if (errno == EAGAIN)
+        continue;
+      else {
+        return TS_ERR_NET_READ;
+      }
+    }
+
+    if (ret == 0) {
+      return TS_ERR_NET_EOF;
+    }
+    // all is good here :)
+    amount_read += ret;
+  }
+  // if !TS_ERR_OKAY, stop reading rest of msg
+  err_t = (TSError) ret_val;
+  if (err_t != TS_ERR_OKAY) {
+    return err_t;
+  }
+  // now get the boolean
+  amount_read = 0;
+  while (amount_read < SIZE_BOOL) {
+    ret = read(fd, (void *) &active, SIZE_BOOL - amount_read);
+
+    if (ret < 0) {
+      if (errno == EAGAIN)
+        continue;
+      else {
+        return TS_ERR_NET_READ;
+      }
+    }
+
+    if (ret == 0) {
+      return TS_ERR_NET_EOF;
+    }
+    // all is good here :)
+    amount_read += ret;
+  }
+  *is_active = (bool) active;
+
+  return err_t;
+}
+
+/**********************************************************************
+ * parse_event_notification
+ *
+ * purpose: parses the event notification message from TM when an event
+ *          is signalled; stores the event info in the TSEvent
+ * input: fd - socket to read
+ *        event - where the event info from msg is stored
+ * output:TS_ERR_OKAY, TS_ERR_NET_READ, TS_ERR_NET_EOF, TS_ERR_PARAMS
+ * notes:
+ * format: <OpType> <event_name_len> <event_name> <desc_len> <desc>
+ **********************************************************************/
+TSError
+parse_event_notification(int fd, TSEvent * event)
+{
+  int amount_read, ret;
+  OpType msg_type;
+  int16_t type_op;
+  int32_t msg_len;
+  char *event_name = NULL, *desc = NULL;
+
+  if (!event)
+    return TS_ERR_PARAMS;
+
+  // read the operation type; should be EVENT_NOTIFY
+  amount_read = 0;
+  while (amount_read < SIZE_OP_T) {
+    ret = read(fd, (void *) &type_op, SIZE_OP_T - amount_read);
+
+    // the thread can receive a bad file descriptor error(EBADF)
+    // if the current socket_fd being used by this thread is invalid;
+    // this occurs when TM restarts and the client has to reconnect and
+    // get a new socket_fd; in this case, this thread will return null
+    // and die; and the client will launch a new event_poll_thread_main
+    // when it reconnects to TM
+
+    // connection broken or error
+    if ((ret < 0) && (errno != EAGAIN)) {
+      //fprintf(stderr, "[event_poll_thread_main] ERROR read event socket %d: %s\n", sock_fd, strerror((int)errno));
+      goto ERROR_READ;
+    }
+
+    if (ret == 0) {
+      goto ERROR_EOF;
+    }
+
+    // if we read some bytes keep on going.
+    amount_read += ret;
+  }
+
+  // got the message type; the msg_type should be EVENT_NOTIFY
+  msg_type = (OpType) type_op;
+  if (msg_type != EVENT_NOTIFY)
+    return TS_ERR_FAIL;
+  //fprintf(stderr, "[event_poll_thread_main] received EVENT_NOTIFY from TM\n");
+
+  // read in event name length
+  amount_read = 0;
+  while (amount_read < SIZE_LEN) {
+    ret = read(fd, (void *) &msg_len, SIZE_LEN - amount_read);
+
+    if (ret < 0) {
+      if (errno == EAGAIN)
+        continue;
+      else {
+        //fprintf(stderr, "[event_poll_thread_main] EXIT: error reading\n");
+        goto ERROR_READ;
+      }
+    }
+
+    if (ret == 0) {
+      goto ERROR_EOF;
+    }
+
+    amount_read += ret;
+  }
+
+  // read the event name
+  event_name = (char *)ats_malloc(sizeof(char) * (msg_len + 1));
+  amount_read = 0;
+  while (amount_read < msg_len) {
+    ret = read(fd, (void *) event_name, msg_len - amount_read);
+
+    if (ret < 0) {
+      if (errno == EAGAIN)
+        continue;
+      else {
+        goto ERROR_READ;
+      }
+    }
+
+    if (ret == 0) {
+      goto ERROR_EOF;
+    }
+
+    amount_read += ret;
+  }
+  event_name[msg_len] = '\0';   // end the string
+
+  // read in event description length
+  amount_read = 0;
+  while (amount_read < SIZE_LEN) {
+    ret = read(fd, (void *) &msg_len, SIZE_LEN - amount_read);
+
+    if (ret < 0) {
+      if (errno == EAGAIN)
+        continue;
+      else {
+        goto ERROR_READ;
+      }
+    }
+
+    if (ret == 0) {
+      goto ERROR_EOF;
+    }
+
+    amount_read += ret;
+  }
+
+  // read the event description
+  desc = (char *)ats_malloc(sizeof(char) * (msg_len + 1));
+  amount_read = 0;
+  while (amount_read < msg_len) {
+    ret = read(fd, (void *) desc, msg_len - amount_read);
+
+    if (ret < 0) {
+      if (errno == EAGAIN)
+        continue;
+      else {
+        goto ERROR_READ;
+      }
+    }
+
+    if (ret == 0) {
+      goto ERROR_EOF;
+    }
+
+    amount_read += ret;
+  }
+  desc[msg_len] = '\0';         // end the string
+
+  // fill in event info
+  event->name = event_name;
+  event->id = (int) get_event_id(event_name);
+  event->description = desc;
+
+  return TS_ERR_OKAY;
+
+ERROR_READ:
+  ats_free(event_name);
+  ats_free(desc);
+  return TS_ERR_NET_READ;
+
+ERROR_EOF:
+  ats_free(event_name);
+  ats_free(desc);
+  return TS_ERR_NET_EOF;
+}

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/8197736c/mgmt/api/NetworkUtilsRemote.h
----------------------------------------------------------------------
diff --git a/mgmt/api/NetworkUtilsRemote.h b/mgmt/api/NetworkUtilsRemote.h
new file mode 100644
index 0000000..c54d62e
--- /dev/null
+++ b/mgmt/api/NetworkUtilsRemote.h
@@ -0,0 +1,109 @@
+/** @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: NetworkUtilsRemote.h
+ * Purpose: This file contains functions used by remote api client to
+ *          marshal requests to TM and unmarshal replies from TM.
+ *          Also contains functions used to store information specific
+ *          to a remote client connection.
+ * Created: 8/9/00
+ * Created by: lant
+ *
+ ***************************************************************************/
+
+#ifndef _NETWORK_UTILS_H_
+#define _NETWORK_UTILS_H_
+
+#include "ink_defs.h"
+#include "ink_mutex.h"
+
+#include "mgmtapi.h"
+#include "NetworkUtilsDefs.h"
+#include "EventCallback.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+const int DEFAULT_STACK_SIZE = 1048576; // 1MB stack
+
+/**********************************************************************
+ * Socket Helper Functions
+ **********************************************************************/
+void set_socket_paths(const char *path);
+int socket_test(int fd);
+
+/* The following functions are specific for a client connection; uses
+ * the client connection information stored in the variables in
+ * NetworkUtilsRemote.cc
+ */
+TSError ts_connect(); /* TODO: update documenation, Renamed due to conflict with connect() in <sys/socket.h> on some platforms*/
+TSError disconnect();
+TSError reconnect();
+TSError reconnect_loop(int num_attempts);
+TSError connect_and_send(const char *msg, int msg_len);
+TSError socket_write_conn(int fd, const char *msg_buf, int bytes);
+void *socket_test_thread(void *arg);
+
+/*****************************************************************************
+ * Marshalling (create requests)
+ *****************************************************************************/
+TSError send_request(int fd, OpType op);
+TSError send_request_name(int fd, OpType op, const char *name);
+TSError send_request_name_value(int fd, OpType op, const char *name, const char *value);
+TSError send_request_bool(int fd, OpType op, bool flag);
+
+TSError send_file_read_request(int fd, TSFileNameT file);
+TSError send_file_write_request(int fd, TSFileNameT file, int ver, int size, char *text);
+TSError send_record_get_request(int fd, char *rec_name);
+
+TSError send_proxy_state_set_request(int fd, TSProxyStateT state, TSCacheClearT clear);
+
+TSError send_register_all_callbacks(int fd, CallbackTable * cb_table);
+TSError send_unregister_all_callbacks(int fd, CallbackTable * cb_table);
+
+TSError send_diags_msg(int fd, TSDiagsT mode, const char *diag_msg);
+
+/*****************************************************************************
+ * Un-marshalling (parse responses)
+ *****************************************************************************/
+TSError parse_reply(int fd);
+TSError parse_reply_list(int fd, char **list);
+
+TSError parse_file_read_reply(int fd, int *version, int *size, char **text);
+
+TSError parse_record_get_reply(int fd, TSRecordT * rec_type, void **rec_val);
+TSError parse_record_set_reply(int fd, TSActionNeedT * action_need);
+
+TSError parse_proxy_state_get_reply(int fd, TSProxyStateT * state);
+
+TSError parse_event_active_reply(int fd, bool * is_active);
+TSError parse_event_notification(int fd, TSEvent * event);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif


Mime
View raw message