You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by jp...@apache.org on 2014/04/10 22:36:32 UTC
git commit: TS-2706: replace the tcp_info plugin config file with
options
Repository: trafficserver
Updated Branches:
refs/heads/master d80ab011a -> 136cc1fde
TS-2706: replace the tcp_info plugin config file with options
Managing a configuration file is a lot of pain for a small number
of options. Replace the tcp_info plugin configuration file with
command line options that can be specified in plugin.config. This
also replaces the number is hook mast option with a human-readable
list of hooks where TCP informations whould be logged.
Project: http://git-wip-us.apache.org/repos/asf/trafficserver/repo
Commit: http://git-wip-us.apache.org/repos/asf/trafficserver/commit/136cc1fd
Tree: http://git-wip-us.apache.org/repos/asf/trafficserver/tree/136cc1fd
Diff: http://git-wip-us.apache.org/repos/asf/trafficserver/diff/136cc1fd
Branch: refs/heads/master
Commit: 136cc1fde704c3d06f6cd5181611066b12a26cc3
Parents: d80ab01
Author: James Peach <jp...@apache.org>
Authored: Tue Apr 8 17:09:46 2014 -0700
Committer: James Peach <jp...@apache.org>
Committed: Thu Apr 10 13:34:37 2014 -0700
----------------------------------------------------------------------
CHANGES | 2 +
plugins/experimental/tcp_info/tcp_info.cc | 211 ++++++++++++++++---------
2 files changed, 138 insertions(+), 75 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/136cc1fd/CHANGES
----------------------------------------------------------------------
diff --git a/CHANGES b/CHANGES
index 6076a4f..adc154b 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,8 @@
-*- coding: utf-8 -*-
Changes with Apache Traffic Server 5.0.0
+ *) [TS-2706] Replace the tcp_info plugin config file with options.
+
*) [TS-2699] Add TSClientProtoStackCreate API.
*) [TS-2678] Some sites (e.g. craigslist) fails to load due to
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/136cc1fd/plugins/experimental/tcp_info/tcp_info.cc
----------------------------------------------------------------------
diff --git a/plugins/experimental/tcp_info/tcp_info.cc b/plugins/experimental/tcp_info/tcp_info.cc
index f9b2b0c..c5277a3 100644
--- a/plugins/experimental/tcp_info/tcp_info.cc
+++ b/plugins/experimental/tcp_info/tcp_info.cc
@@ -1,6 +1,6 @@
/** @file
- A brief file description
+ tcp_info: A plugin to log TCP session information.
@section license License
@@ -21,9 +21,6 @@
limitations under the License.
*/
-/* tcp_info.cc: logs the tcp_info data struture to a file
- */
-
#include <stdio.h>
#include <stdlib.h>
#include <ts/ts.h>
@@ -33,78 +30,26 @@
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <getopt.h>
#include <fcntl.h>
#include <limits.h>
#include <string.h>
#include <sys/time.h>
#include <arpa/inet.h>
+#define TCPI_HOOK_SSN_START 0x01u
+#define TCPI_HOOK_TXN_START 0x02u
+#define TCPI_HOOK_SEND_RESPONSE 0x04u
+#define TCPI_HOOK_SSN_CLOSE 0x08u
+
struct Config {
int sample;
const char* log_file;
int log_fd;
int log_level;
- int hook;
};
-static Config config;
-
-static void
-load_config() {
- char config_file[PATH_MAX];
- config.sample = 1000;
- config.log_level = 1;
- config.log_file = NULL;
- config.hook = 1;
-
- // get the install directory
- const char* install_dir = TSInstallDirGet();
-
- // figure out the config file and open it
- snprintf(config_file, sizeof(config_file), "%s/%s/%s", install_dir, "etc", "tcp_info.config");
- FILE *file = fopen(config_file, "r");
- if (file == NULL) {
- snprintf(config_file, sizeof(config_file), "%s/%s/%s", install_dir, "conf", "tcp_info.config");
- file = fopen(config_file, "r");
- }
- TSDebug("tcp_info", "config file name: %s", config_file);
- assert(file != NULL);
-
- // read and parse the lines
- char line[256];
- while (fgets(line, sizeof(line), file) != NULL) {
- char *pos = strchr(line, '=');
- *pos = '\0';
- char *value = pos + 1;
-
- // remove the new line
- pos = strchr(value, '\n');
- if (pos != NULL) {
- *pos = '\0';
- }
-
- if (value != NULL) {
- TSDebug("tcp_info", "config key: %s", line);
- TSDebug("tcp_info", "config value: %s", value);
- if (strcmp(line, "sample") == 0) {
- config.sample = atoi(value);
- } else if (strcmp(line, "log_file") == 0) {
- config.log_file = strdup(value);
- } else if (strcmp(line, "log_level") == 0) {
- config.log_level = atoi(value);
- } else if (strcmp(line, "hook") == 0) {
- config.hook = atoi(value);
- }
- }
- }
- TSDebug("tcp_info", "sample: %d", config.sample);
- TSDebug("tcp_info", "log filename: %s", config.log_file);
- TSDebug("tcp_info", "log_level: %d", config.log_level);
- TSDebug("tcp_info", "hook: %d", config.hook);
-
- config.log_fd = open(config.log_file, O_APPEND | O_CREAT | O_RDWR, 0666);
- assert(config.log_fd > 0);
-}
+static Config config;
static void
log_tcp_info(const char* event_name, const char* client_ip, const char* server_ip, struct tcp_info &info) {
@@ -259,39 +204,155 @@ done:
return 0;
}
+static bool
+parse_unsigned(const char * str, unsigned long& lval)
+{
+ char * end = NULL;
+
+ if (*str == '\0') {
+ return false;
+ }
+
+ lval = strtoul(str, &end, 0 /* base */);
+ if (end == str) {
+ // No valid characters.
+ return false;
+ }
+
+ if (end != '\0') {
+ // Not all charaters consumed.
+ return false;
+ }
+
+ return true;
+}
+
+// Parse a comma-separated list of hook names into a hook bitmask.
+static unsigned
+parse_hook_list(const char * hook_list)
+{
+ unsigned mask = 0;
+ char * tok;
+ char * str;
+ char * last;
+
+ const struct hookmask { const char * name; unsigned mask; } hooks[] = {
+ { "ssn_start", TCPI_HOOK_SSN_START },
+ { "txn_start", TCPI_HOOK_TXN_START },
+ { "send_resp_hdr", TCPI_HOOK_SEND_RESPONSE },
+ { "ssn_close", TCPI_HOOK_SSN_CLOSE },
+ { NULL, 0u }
+ };
+
+ str = TSstrdup(hook_list);
+
+ for (tok = strtok_r(str, ",", &last); tok; tok = strtok_r(NULL, ",", &last)) {
+ bool match = false;
+
+ for (const struct hookmask * m = hooks; m->name != NULL; ++m) {
+ if (strcmp(m->name, tok) == 0) {
+ mask |= m->mask;
+ match = true;
+ break;
+ }
+ }
+
+ if (!match) {
+ TSError("[tcp_info] invalid hook name '%s'", tok);
+ }
+ }
+
+ TSfree(str);
+ return mask;
+}
+
void
-TSPluginInit(int, const char *[]) // int argc, const char *argv[]
+TSPluginInit(int argc, const char * argv[])
{
+ static const char usage[] = "tcp_info.so [--log-file=PATH] [--log-level=LEVEL] [--hooks=LIST] [--sample-rate=COUNT]";
+ static const struct option longopts[] = {
+ { const_cast<char *>("sample-rate"), required_argument, NULL, 'r' },
+ { const_cast<char *>("log-file"), required_argument, NULL, 'f' },
+ { const_cast<char *>("log-level"), required_argument, NULL, 'l' },
+ { const_cast<char *>("hooks"), required_argument, NULL, 'h' },
+ { NULL, 0, NULL, 0 }
+ };
+
TSPluginRegistrationInfo info;
+ unsigned hooks = 0;
info.plugin_name = (char*)"tcp_info";
info.vendor_name = (char*)"Apache Software Foundation";
info.support_email = (char*)"dev@trafficserver.apache.org";
- if (TSPluginRegister(TS_SDK_VERSION_3_0, &info) != TS_SUCCESS)
- TSError("Plugin registration failed. \n");
+ if (TSPluginRegister(TS_SDK_VERSION_3_0, &info) != TS_SUCCESS) {
+ TSError("tcp_info: plugin registration failed");
+ }
+
+ config.sample = 1000;
+ config.log_level = 1;
+ config.log_file = NULL;
- // load the configuration file
- load_config();
+ optind = 0;
+ for (;;) {
+ unsigned long lval;
- // add a hook to the state machine
- // TODO: need another hook before the socket is closed, keeping it in for now because it will be easier to change if or when another hook is added to ATS
- if ((config.hook & 1) != 0) {
+ switch (getopt_long(argc, (char * const *)argv, "r:f:l:h:", longopts, NULL)) {
+ case 'r':
+ if (parse_unsigned(optarg, lval)) {
+ config.sample = atoi(optarg);
+ } else {
+ TSError("[tcp_info] invalid sample rate '%s'", optarg);
+ }
+ break;
+ case 'f':
+ config.log_file = optarg;
+ break;
+ case 'l':
+ if (parse_unsigned(optarg, lval) && (lval == 1 || lval == 2)) {
+ config.log_level = atoi(optarg);
+ } else {
+ TSError("[tcp_info] invalid log level '%s'", optarg);
+ }
+ break;
+ case 'h':
+ hooks = parse_hook_list(optarg);
+ break;
+ case -1:
+ goto init;
+ default:
+ TSError("[tcp_info] usage: %s", usage);
+ }
+ }
+
+init:
+
+ TSDebug("tcp_info", "sample: %d", config.sample);
+ TSDebug("tcp_info", "log filename: %s", config.log_file);
+ TSDebug("tcp_info", "log_level: %d", config.log_level);
+ TSDebug("tcp_info", "hook mask: 0x%x", hooks);
+
+ config.log_fd = open(config.log_file, O_APPEND | O_CREAT | O_RDWR, 0666);
+ assert(config.log_fd > 0);
+
+ if (hooks & TCPI_HOOK_SSN_START) {
TSHttpHookAdd(TS_HTTP_SSN_START_HOOK, TSContCreate(tcp_info_hook, NULL));
TSDebug("tcp_info", "added hook to the start of the TCP connection");
}
- if ((config.hook & 2) != 0) {
+
+ if (hooks & TCPI_HOOK_TXN_START) {
TSHttpHookAdd(TS_HTTP_TXN_START_HOOK, TSContCreate(tcp_info_hook, NULL));
TSDebug("tcp_info", "added hook to the close of the transaction");
}
- if ((config.hook & 4) != 0) {
+
+ if (hooks & TCPI_HOOK_SEND_RESPONSE) {
TSHttpHookAdd(TS_HTTP_SEND_RESPONSE_HDR_HOOK, TSContCreate(tcp_info_hook, NULL));
TSDebug("tcp_info", "added hook to the sending of the headers");
}
- if ((config.hook & 8) != 0) {
+
+ if (hooks & TCPI_HOOK_SSN_CLOSE) {
TSHttpHookAdd(TS_HTTP_SSN_CLOSE_HOOK, TSContCreate(tcp_info_hook, NULL));
TSDebug("tcp_info", "added hook to the close of the TCP connection");
}
- TSDebug("tcp_info", "tcp info module registered");
}