Commit fe86dd4e authored by Robert Ricci's avatar Robert Ricci

Add two new features to libnetmon. First, it now reports on the

line of the application it's instrumenting, so that we can find the
source of some mysterious lines in the libnetmon.out files. Second,
report when sendmsg gets called, so that we can find out whether we
need to instrument this for any of our applications or not.

I also fixed several minor almost-bugs caught by -pedantic.
parent 3e0890fe
......@@ -13,5 +13,6 @@ if [ "x$LIBNETMON_OUTPUTVERSION" = "x" ]; then
else
export LIBNETMON_OUTPUTVERSION
fi
#export LIBNETMON_NETMOND=1
$*
......@@ -26,6 +26,9 @@ Connected (no value) (RemoteIP and RemotePort MUST be sent before this command)
Send (value is the size of the write or sendto)
SendTo (value is <localPort>:<remoteIP>:<remotePort>:<size>
Closed (no value)
Init (value is command line, enclosed in ' ')
Exit (no value)
SendMsg (no value yet)
On a TCP connection, there should be the following sequence:
......
/*
* EMULAB-COPYRIGHT
* Copyright (c) 2006 University of Utah and the Flux Group.
* Copyright (c) 2006-2007 University of Utah and the Flux Group.
*
* libnetmon, a library for monitoring network traffic sent by a process. See
* README for instructions.
*/
#include "libnetmon.h"
/*
* So that we can find out the name of the process that we're instrumenting
*/
extern int argc;
extern char** argv;
/*
* Die with a standard Emulab-type error message format. In the future, I might
* try to modify this to simply unlink our wrapper functions so that the app
......@@ -28,13 +34,13 @@ static void croak(const char *format, ...) {
*/
void lnm_init() {
static bool intialized = false;
static bool initialized = false;
char *sockpath;
char *ctrl_sockpath;
char *filepath;
char *std_netmond;
if (intialized == false) {
if (initialized == false) {
DEBUG(printf("Initializing\n"));
/*
......@@ -56,7 +62,7 @@ void lnm_init() {
char *outversion_s;
outversion_s = getenv("LIBNETMON_OUTPUTVERSION");
if (outversion_s) {
if (!sscanf(outversion_s,"%i",&output_version) == 1) {
if (!sscanf(outversion_s,"%u",&output_version) == 1) {
croak("Bad output version: %s\n",outversion_s);
}
} else {
......@@ -94,7 +100,7 @@ void lnm_init() {
* 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_io = report_sockopt = report_connect = report_init = false;
report_all = true;
char *reports_s;
reports_s = getenv("LIBNETMON_REPORTS");
......@@ -122,6 +128,7 @@ void lnm_init() {
FIND_REAL_FUN(recvmsg);
FIND_REAL_FUN(accept);
FIND_REAL_FUN(sendto);
FIND_REAL_FUN(sendmsg);
/*
* Connect to netmond if we've been asked to
......@@ -247,7 +254,7 @@ void lnm_init() {
* others now
*/
if (report_all) {
report_io = report_sockopt = report_connect = true;
report_io = report_sockopt = report_connect = report_init = true;
}
/*
......@@ -273,7 +280,51 @@ void lnm_init() {
croak("Unable to register atexit() function\n");
}
intialized = true;
/*
* Get our command line. I really don't like going into the /proc
* filesystem to get it, but it beats mucking around in the stack.
*/
char cmdfile[1024];
char *cmdline;
char cmdbuf[4096];
snprintf(cmdfile,1024,"/proc/%i/cmdline",pid);
DEBUG(printf("Opening %s\n",cmdfile));
int cmdfd = open(cmdfile,O_RDONLY);
/*
* If we couldn't open it, report why in lieu of the command line
*/
if (cmdfd < 0) {
cmdline = strerror(errno);
} else {
/*
* Read as much of the command line as we can, and null terminate
* it
*/
int bytesread = real_read(cmdfd,cmdbuf,sizeof(cmdbuf) - 1);
real_close(cmdfd);
cmdbuf[bytesread] = '\0';
/*
* But wait, there's more! What we got out of /proc is
* null-separated, so we have to change it into a tidy
* space-separated string.
*/
for (int i = 0; i < bytesread - 1; i++) {
if (cmdbuf[i] == '\0') {
cmdbuf[i] = ' ';
}
}
cmdline = cmdbuf;
}
/*
* XXX: Should escape 's, so as not to confuse the monitor
*/
printlog(LOG_INIT,NO_FD,"'%s'",cmdline);
initialized = true;
DEBUG(printf("Done initializing\n"));
} else {
/* DEBUG(printf("Skipping intialization\n")); */
}
......@@ -336,9 +387,9 @@ void lnm_control_wait() {
DEBUG(printf("Waiting for a control message\n"));
selectrv = select(controlfd + 1, &fds, NULL, NULL, &tv);
if (select == 0) {
if (selectrv == 0) {
croak("Timed out waiting for a control message\n");
} else if (select < 0) {
} else if (selectrv < 0) {
croak("Bad return value from select() in lnm_control_wait()\n");
}
......@@ -525,6 +576,7 @@ void stopWatchingAll() {
stopFD(i);
}
}
printlog(LOG_EXIT,NO_FD);
}
void printlog(logmsg_t type, int fd, ...) {
......@@ -534,6 +586,7 @@ void printlog(logmsg_t type, int fd, ...) {
*/
bool print_name = true;
bool print_id = true;
bool id_is_pid = false;
bool print_timestamp = true;
bool print_value = true;
......@@ -627,6 +680,25 @@ void printlog(logmsg_t type, int fd, ...) {
// Allow global turning on/off of this message type
if (!report_connect) { print = false; }
break;
case LOG_INIT:
if (output_version < 3) { print = false; }
if (!report_init) { print = false; }
id_is_pid = true;
break;
case LOG_EXIT:
if (output_version < 3) { print = false; }
if (!report_init) { print = false; }
id_is_pid = true;
print_value = false;
break;
case LOG_SENDMSG:
// In version 3, we don't actually log anything about the contents
// of the call - we just want to make sure it isn't sneaking past
// us. Techinically, it doesn't have to be UDP, but we'll lump it
// in for now
if (output_version < 3) { print = false; }
if (!monitor_udp) { print = false; }
print_value = false;
default:
croak("Invalid type (%) passed to printlog()\n",type);
}
......@@ -647,11 +719,16 @@ void printlog(logmsg_t type, int fd, ...) {
}
/*
* Print out the ID of the socket the action is for
* Print out the ID of the socket the action is for. Some actions are not
* associated with a specific socket, so we use the pid as the identifier
*/
if (print_id) {
fprintID(outstream,fd);
fprintf(outstream," ");
if (id_is_pid) {
fprintf(outstream,"%i ",pid);
} else {
fprintID(outstream,fd);
fprintf(outstream," ");
}
}
/*
......@@ -682,6 +759,12 @@ void printlog(logmsg_t type, int fd, ...) {
*/
void fprintID(FILE *f, int fd) {
if (fd == NO_FD) {
croak("NO_FD passed to fprintID");
} else if (fd < 0) {
croak("Negative pid (%i) passed to fprintID");
}
if (output_version <= 2) {
/*
* Note, we've switched from local_port to FD for the first field - this is
......@@ -857,6 +940,8 @@ static void lnm_parse_reportopt(char *s) {
report_connect = true;
} else if (!strncmp(p,"sockopt",numchars)) {
report_sockopt = true;
} else if (!strncmp(p,"init",numchars)) {
report_init = true;
} else {
croak("Bad report: %s\n",p);
}
......@@ -1062,8 +1147,8 @@ void informConnect(int fd) {
}
int getNewSockbuf(int fd, int which) {
int newsize;
int optsize;
socklen_t newsize;
socklen_t optsize;
optsize = sizeof(newsize);
if (getsockopt(fd,SOL_SOCKET,which,&newsize,&optsize)) {
croak("Unable to get socket buffer size");
......@@ -1160,7 +1245,7 @@ int connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen) {
* Get the local port number so that we can monitor it
*/
struct sockaddr_in localaddr;
int namelen = sizeof(localaddr);
socklen_t namelen = sizeof(localaddr);
if (getsockname(sockfd, (struct sockaddr*)&localaddr,&namelen) != 0) {
croak("Unable to get local socket name: %s\n", strerror(errno));
}
......@@ -1244,7 +1329,6 @@ int close(int d) {
*
* TODO: Need to write wrappers for other functions that can be used to send
* data on a socket:
* sendmsg
* writev
* others?
*/
......@@ -1340,6 +1424,30 @@ ssize_t sendto(int fd, const void *buf, size_t count, int flags,
}
/*
* Wrap the sendmsg() function
*/
ssize_t sendmsg(int s, const struct msghdr *msg, int flags) {
ssize_t rv;
lnm_init();
lnm_control();
/*
* Wait until _after_ the packet is sent to log it, since the call might
* block, and we basically want to report when the kernel acked receipt of
* the packet
*/
rv = real_sendmsg(s,msg,flags);
if ((rv > 0) && monitorFD_p(s)) {
printlog(LOG_SENDMSG,s);
}
return rv;
}
int setsockopt (int s, int level, int optname, const void *optval,
socklen_t optlen) {
int rv;
......
/*
* EMULAB-COPYRIGHT
* Copyright (c) 2006 University of Utah and the Flux Group.
* Copyright (c) 2006-2007 University of Utah and the Flux Group.
*
* Header for libnetmon, a library for monitoring network traffic sent by a
* process. See README for instructions.
......@@ -32,7 +32,7 @@
#include "netmon.h"
/* #define DEBUGGING */
// #define DEBUGGING
#ifdef DEBUGGING
#define DEBUG(x) (x)
......@@ -107,7 +107,10 @@ typedef enum { LOG_NEW = 0,
LOG_CONNECTED,
LOG_SEND,
LOG_SENDTO,
LOG_CLOSED
LOG_CLOSED,
LOG_INIT,
LOG_EXIT,
LOG_SENDMSG
} logmsg_t;
static char *log_type_names[] = {
"New",
......@@ -121,7 +124,10 @@ static char *log_type_names[] = {
"Connected",
"Send",
"SendTo",
"Closed"
"Closed",
"Init",
"Exit",
"SendMsg"
};
/*
......@@ -132,6 +138,12 @@ static char *log_type_names[] = {
*/
static void printlog(logmsg_t,int, ... );
/*
* A constant passed to printlog() to indicate that there is no file descriptor
* associated with this message
*/
static int NO_FD = -42;
/*
* Log that a packet has been sent to the kernel on a given FD with a given
* size. If the final argument is non-NULL, then we are logging a packet from
......@@ -254,6 +266,7 @@ static bool report_all;
static bool report_io;
static bool report_sockopt;
static bool report_connect;
static bool report_init;
/*
* Prototypes for the real library functions - just makes it easier to declare
......@@ -261,7 +274,7 @@ static bool report_connect;
*/
typedef int open_proto_t(const char *, int, ...);
typedef int stat_proto_t(const char *, struct stat *sb);
typedef int socket_proto_t(int,int,int);
typedef int socket_proto_t(int, int,int);
typedef int close_proto_t(int);
typedef int connect_proto_t(int, const struct sockaddr*, socklen_t);
typedef ssize_t write_proto_t(int, const void *, size_t);
......@@ -269,10 +282,11 @@ typedef ssize_t send_proto_t(int, const void *, ssize_t, int);
typedef int setsockopt_proto_t(int, int, int, const void*, socklen_t);
typedef ssize_t read_proto_t(int, void *, size_t);
typedef ssize_t recv_proto_t(int, void *, size_t, int);
typedef ssize_t recvmsg_proto_t(int,struct msghdr *, int);
typedef ssize_t accept_proto_t(int,struct sockaddr *, socklen_t *);
typedef ssize_t recvmsg_proto_t(int, struct msghdr *, int);
typedef ssize_t accept_proto_t(int, struct sockaddr *, socklen_t *);
typedef ssize_t sendto_proto_t(int, const void *, size_t, int,
const struct sockaddr *, socklen_t);
typedef ssize_t sendmsg_proto_t(int, const struct msghdr *, int);
/*
* Locations of the real library functions
......@@ -288,6 +302,7 @@ static recv_proto_t *real_recv;
static recvmsg_proto_t *real_recvmsg;
static accept_proto_t *real_accept;
static sendto_proto_t *real_sendto;
static sendmsg_proto_t *real_sendmsg;
/*
* Note: Functions that we're wrapping are in the .c file
......
......@@ -43,7 +43,7 @@ typedef enum {
*/
typedef struct {
unsigned int type;
unsigned char payload[CONTROL_MESSAGE_PAYLOAD_SIZE];
char payload[CONTROL_MESSAGE_PAYLOAD_SIZE];
} generic_m;
......@@ -78,7 +78,7 @@ typedef struct {
*/
typedef struct {
unsigned int type;
unsigned char reports[CONTROL_MESSAGE_PAYLOAD_SIZE];
char reports[CONTROL_MESSAGE_PAYLOAD_SIZE];
} reports_m;
/*
......
/*
* EMULAB-COPYRIGHT
* Copyright (c) 2006 University of Utah and the Flux Group.
* Copyright (c) 2006-2007 University of Utah and the Flux Group.
*
* netmond, a 'server' for libnetmon - simply repeat what a process being
* monitored with libnetmon tell us on a unix-domian socket
......@@ -173,17 +173,17 @@ int main(int argc, char **argv) {
while ((ch = getopt(argc, argv, "f:l:v:r:u")) != -1) {
switch(ch) {
case 'f':
if (sscanf(optarg,"%i",&forced_socksize) != 1) {
if (sscanf(optarg,"%u",&forced_socksize) != 1) {
usage();
}
break;
case 'l':
if (sscanf(optarg,"%i",&max_socksize) != 1) {
if (sscanf(optarg,"%u",&max_socksize) != 1) {
usage();
}
break;
case 'v':
if (sscanf(optarg,"%i",&output_version) != 1) {
if (sscanf(optarg,"%u",&output_version) != 1) {
usage();
}
break;
......
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