Commit 5f290b2c authored by Robert Ricci's avatar Robert Ricci
Browse files

Add the ability for libnetmon to only output certain reports - this

is so that when we use a monitor that doesn't care about, say, writes,
we can avoid waisting the CPU required to parse them.

The four supported reports are:
    connect - connect() and close() notifications
    sockopt - Information about socket options
    io - read()s and write()s
    all - Duh. The default if none are given

You can specify reports by setting LIBNETMON_REPORTS or using the
new -r option to netmond. If you want more than one report type,
seperate them with commas.

Added a new control message, CM_REPORTS, to pass these back and forth
from netmond to libnetmon.

Added a long overdue LIBNETMON_NETMOND option which just uses the
standard socket paths to talk to netmond - this way, you don't have
to set them by hand when debugging, which is a huge PITA.
parent 164c8dbb
......@@ -48,7 +48,9 @@ void lnm_init() {
static bool intialized = false;
char *sockpath;
char *ctrl_sockpath;
char *filepath;
char *std_netmond;
if (intialized == false) {
DEBUG(printf("Initializing\n"));
......@@ -81,6 +83,18 @@ void lnm_init() {
dlerror()); \
}
/*
* Default to reporting on everything - the individual reporting
* options will get turned on later if report_all is true
*/
report_io = report_sockopt = report_connect = false;
report_all = true;
char *reports_s;
reports_s = getenv("LIBNETMON_REPORTS");
if (reports_s) {
lnm_parse_reportopt(reports_s);
}
/*
* Find the real versions of the library functions we're going to wrap
*/
......@@ -98,7 +112,20 @@ void lnm_init() {
/*
* Connect to netmond if we've been asked to
*/
sockpath = getenv("LIBNETMON_SOCKPATH");
/*
* If this is set at all, use the standard data and control sockets for
* netmond - it's a PITA to set them by hand
*/
std_netmond = getenv("LIBNETMON_NETMOND");
if (std_netmond) {
sockpath = SOCKPATH;
ctrl_sockpath = CONTROLSOCK;
} else {
sockpath = getenv("LIBNETMON_SOCKPATH");
ctrl_sockpath = getenv("LIBNETMON_CONTROL_SOCKPATH");
}
filepath = getenv("LIBNETMON_OUTPUTFILE");
if (sockpath) {
int sockfd;
......@@ -142,11 +169,10 @@ void lnm_init() {
/*
* Connect to the netmond's control socket if we've been asked to
*/
sockpath = getenv("LIBNETMON_CONTROL_SOCKPATH");
if (sockpath) {
if (ctrl_sockpath) {
struct sockaddr_un servaddr;
DEBUG(printf("Opening control socket at path %s\n",sockpath));
DEBUG(printf("Opening control socket at path %s\n",ctrl_sockpath));
controlfd = real_socket(AF_LOCAL, SOCK_STREAM, 0);
if (!controlfd) {
......@@ -154,7 +180,7 @@ void lnm_init() {
}
servaddr.sun_family = AF_LOCAL;
strcpy(servaddr.sun_path,sockpath);
strcpy(servaddr.sun_path,ctrl_sockpath);
if (real_connect(controlfd, (struct sockaddr*) &servaddr,
sizeof(servaddr))) {
......@@ -188,6 +214,14 @@ void lnm_init() {
controlfd = -1;
}
/*
* If we got all the way through that with report_all set, turn on the
* others now
*/
if (report_all) {
report_io = report_sockopt = report_connect = true;
}
/*
* Check to see if we're supposed to force a specific socket buffer
* size
......@@ -340,7 +374,9 @@ void nameFD(int fd, const struct sockaddr *localname,
monitorFDs[fd].local_port = ntohs(localaddr->sin_port);
monitorFDs[fd].connected = true;
informConnect(fd);
if (report_connect) {
informConnect(fd);
}
}
......@@ -434,7 +470,7 @@ void stopFD(int fd) {
/*
* Let the monitor know we're done with it
*/
if (output_version == 2) {
if (output_version >= 2 && report_connect) {
fprintf(outstream,"Closed: ");
fprintID(outstream,fd);
fprintf(outstream,"\n");
......@@ -495,6 +531,7 @@ void fprintTime(FILE *f) {
void process_control_packet(generic_m *m) {
max_socket_m *maxmsg;
out_ver_m *vermsg;
reports_m *reportmsg;
DEBUG(printf("Processing control packet\n"));
......@@ -529,6 +566,23 @@ void process_control_packet(generic_m *m) {
DEBUG(printf("Set output version to %i\n", output_version));
break;
case CM_REPORTS:
/*
* The server told us which things it wants us to report
*/
reportmsg = (reports_m *)m;
/*
* Just for the heck of it, null out the last character to prevent
* any dumb string functions from going off the end
*/
reportmsg->reports[CONTROL_MESSAGE_PAYLOAD_SIZE - 1] = '\0';
DEBUG(printf("Setting reports to %s\n", reportmsg->reports));
lnm_parse_reportopt(reportmsg->reports);
break;
default:
croak1("Got an unexepected control message type: %i\n",
......@@ -559,6 +613,57 @@ void control_query() {
}
/*
* Parse a list of reports, setting the appropriate flags
*/
static void lnm_parse_reportopt(char *s) {
char *p = s;
/*
* Turn 'all' off, since if they ask for specific ones, we only
* give them those - but, we might set it back to true if they
* say 'all'...
*/
report_all = false;
while (p != NULL && *p != '\0') {
/*
* Find out how many chars before the next option or end of
* string, whichever comes first
*/
int numchars;
char* nextcomma = strchr(p,',');
if (nextcomma == NULL) {
numchars = strlen(p);
} else {
numchars = nextcomma - p;
}
/*
* Not-so-fancy parsing
*/
if (!strncmp(p,"all",numchars)) {
report_all = true;
} else if (!strncmp(p,"io",numchars)) {
report_io = true;
} else if (!strncmp(p,"connect",numchars)) {
report_connect = true;
} else if (!strncmp(p,"sockopt",numchars)) {
report_sockopt = true;
} else {
croak1("Bad report: %s\n",p);
}
if (nextcomma) {
p = nextcomma + 1;
} else {
p = NULL;
}
}
}
void allocFDspace() {
fdRecord *allocRV;
unsigned int newFDSize;
......@@ -615,6 +720,9 @@ bool connectedFD_p(int whichFD) {
* Let the user know that a packet has been sent.
*/
void log_packet(int fd, size_t len) {
if (!report_io) {
return;
}
struct timeval time;
/*
* XXX - At some point, we may want to use something more precise than
......@@ -648,7 +756,7 @@ void log_packet(int fd, size_t len) {
* Inform the user that the nodelay flag has been changed
*/
void informNodelay(int fd) {
if (output_version == 2) {
if (output_version >= 2) {
fprintf(outstream,"TCP_NODELAY: ");
fprintID(outstream,fd);
fprintf(outstream," %i\n",monitorFDs[fd].tcp_nodelay);
......@@ -656,7 +764,7 @@ void informNodelay(int fd) {
}
void informMaxseg(int fd) {
if (output_version == 2) {
if (output_version >= 2) {
fprintf(outstream,"TCP_MAXSEG: ");
fprintID(outstream,fd);
fprintf(outstream," %i\n",monitorFDs[fd].tcp_maxseg);
......@@ -665,7 +773,7 @@ void informMaxseg(int fd) {
void informBufsize(int fd, int which) {
int bufsize;
if (output_version == 2) {
if (output_version >= 2) {
/* TODO: Handle bad which parameter */
if (which == SO_SNDBUF) {
bufsize = monitorFDs[fd].sndbuf;
......@@ -682,7 +790,7 @@ void informBufsize(int fd, int which) {
}
void informConnect(int fd) {
if (output_version == 2) {
if (output_version >= 2) {
/*
* Let the monitor know about it
*/
......@@ -695,16 +803,20 @@ void informConnect(int fd) {
/*
* Some things we report on for every connection
*/
informNodelay(fd);
informMaxseg(fd);
informBufsize(fd, SO_RCVBUF);
informBufsize(fd, SO_SNDBUF);
if (report_sockopt) {
informNodelay(fd);
informMaxseg(fd);
informBufsize(fd, SO_RCVBUF);
informBufsize(fd, SO_SNDBUF);
}
fprintf(outstream,"Connected: ");
fprintID(outstream,fd);
fprintf(outstream," ");
fprintTime(outstream);
fprintf(outstream,"\n");
if (report_connect) {
fprintf(outstream,"Connected: ");
fprintID(outstream,fd);
fprintf(outstream," ");
fprintTime(outstream);
fprintf(outstream,"\n");
}
}
}
......@@ -813,9 +925,11 @@ int connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen) {
}
int local_port = ntohs(localaddr.sin_port);
fprintf(outstream,"LocalPort: ");
fprintID(outstream,sockfd);
fprintf(outstream," %i\n",local_port);
if (report_connect) {
fprintf(outstream,"LocalPort: ");
fprintID(outstream,sockfd);
fprintf(outstream," %i\n",local_port);
}
} else {
/*
* Do this in case the connection really did fail
......@@ -850,9 +964,11 @@ int accept(int s, struct sockaddr * addr,
*/
startFD(rv);
nameFD(rv,addr,NULL);
fprintf(outstream,"LocalPort: ");
fprintID(outstream,rv);
fprintf(outstream," %i\n",ntohs(((struct sockaddr_in*)addr)->sin_port));
if (report_connect) {
fprintf(outstream,"LocalPort: ");
fprintID(outstream,rv);
fprintf(outstream," %i\n",ntohs(((struct sockaddr_in*)addr)->sin_port));
}
}
return rv;
......@@ -990,7 +1106,7 @@ int setsockopt (int s, int level, int optname, const void *optval,
* not be exactly what the user asked for
*/
getNewSockbuf(s,optname);
if (connectedFD_p(s)) {
if (connectedFD_p(s) && report_sockopt) {
informBufsize(s,optname);
}
}
......@@ -1002,7 +1118,7 @@ int setsockopt (int s, int level, int optname, const void *optval,
if (optname == TCP_NODELAY) {
monitorFDs[s].tcp_nodelay = *((int *)optval);
if (connectedFD_p(s)) {
if (connectedFD_p(s) && report_sockopt) {
/* If connected, inform user of this call */
informNodelay(s);
}
......@@ -1010,7 +1126,7 @@ int setsockopt (int s, int level, int optname, const void *optval,
if (optname == TCP_MAXSEG) {
monitorFDs[s].tcp_maxseg = *((int *)optval);
if (connectedFD_p(s)) {
if (connectedFD_p(s) && report_sockopt) {
/* If connected, inform user of this call */
informMaxseg(s);
}
......
......@@ -62,6 +62,11 @@ static void lnm_control();
*/
static void lnm_control_wait();
/*
* Parse a list of reports
*/
static void lnm_parse_reportopt(char *s);
/*
* Allocate space for the monitorFDs - increases the allocation by
* FD_ALLOC_SIZE slots.
......@@ -177,6 +182,17 @@ static void control_query();
*/
static unsigned int output_version;
/*
* These describe which things we need to report on. report_all is sort of a
* meta-option - at the end of initialization, if it's set, we turn on the
* rest of the options, but it's not used after that. This is to cut down
* on the number of places we have to remember all of them...
*/
static bool report_all;
static bool report_io;
static bool report_sockopt;
static bool report_connect;
/*
* Prototypes for the real library functions - just makes it easier to declare
* function pointers for them.
......
......@@ -26,6 +26,7 @@ typedef enum {
*/
CM_MAXSOCKSIZE = 0,
CM_OUTPUTVER,
CM_REPORTS,
CM_SOCKSIZE = 64,
CM_QUERY
......@@ -66,6 +67,14 @@ typedef struct {
unsigned int version;
} out_ver_m;
/*
* Report, err, report. Okay, bad name.
*/
typedef struct {
unsigned int type;
unsigned char reports[CONTROL_MESSAGE_PAYLOAD_SIZE];
} reports_m;
/*
* Socket size change report
*/
......
......@@ -6,6 +6,13 @@
* monitored with libnetmon tell us on a unix-domian socket
*/
/*
* Get unitstd.h on Linux to declare getopt()
*/
#ifdef __linux__
#define _GNU_SOURCE
#endif
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
......@@ -16,6 +23,7 @@
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <strings.h>
#include "netmon.h"
......@@ -43,6 +51,11 @@ unsigned int max_socksize = 0;
*/
unsigned int forced_socksize = 0;
/*
* Only enable a specific set of reports
*/
char *reports = NULL;
/*
* Give a client a report on what settings it should use.
*
......@@ -53,6 +66,7 @@ unsigned int write_status(int fd) {
generic_m message;
max_socket_m *sockrep;
out_ver_m *verrep;
reports_m *reprep;
/*
* Report on the maximum socket size
......@@ -91,6 +105,21 @@ unsigned int write_status(int fd) {
return 1;
}
/*
* Report on which reports we want
*/
if (reports != NULL) {
reprep = (reports_m *)&(message);
reprep-> type = CM_REPORTS;
strcpy(reprep->reports,reports);
reprep->reports[strlen(reports)] = '\0';
if (write(fd,&message,CONTROL_MESSAGE_SIZE) != CONTROL_MESSAGE_SIZE) {
/* Client probably disconnected */
return 1;
}
}
return 0;
}
......@@ -99,6 +128,7 @@ void usage() {
fprintf(stderr," -v version Specify output version (default is 2)\n");
fprintf(stderr," -l size Maximum socket buffer size\n");
fprintf(stderr," -f size Force a socket buffer size\n");
fprintf(stderr," -r reports Enable listed reports\n");
exit(-1);
}
......@@ -117,7 +147,7 @@ int main(int argc, char **argv) {
/*
* Process command-line args
*/
while ((ch = getopt(argc, argv, "f:l:v:")) != -1) {
while ((ch = getopt(argc, argv, "f:l:v:r:")) != -1) {
switch(ch) {
case 'f':
if (sscanf(optarg,"%i",&forced_socksize) != 1) {
......@@ -134,6 +164,10 @@ int main(int argc, char **argv) {
usage();
}
break;
case 'r':
reports = (char*)malloc(strlen(optarg) + 1);
strcpy(reports,optarg);
break;
default:
usage();
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment