/*
* TCPVIEW
*
* Author: Martin Hunt
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
* Internet: martinh@cac.washington.edu
*
*
* Copyright 1992 by the University of Washington
*
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose and without fee is hereby granted, provided
* that the above copyright notice appears in all copies and that both the
* above copyright notice and this permission notice appear in supporting
* documentation, and that the name of the University of Washington not be
* used in advertising or publicity pertaining to distribution of the software
* without specific, written prior permission. This software is made
* available "as is", and
* THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
* WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN
* NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL,
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT
* (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#ifndef lint
static char rcsid[] =
"@(#) $Header: /usr/staff/martinh/tcpview/RCS/capture.c,v 1.2 1993/04/22 20:14:24 martinh Exp $ (UW)";
#endif
#include <stdio.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <signal.h>
#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
#include <X11/CoreP.h>
#include <Xm/Xm.h>
#include <Xm/Frame.h>
#include <Xm/MessageB.h>
#include <Xm/RowColumn.h>
#include <Xm/Separator.h>
#include <Xm/ToggleB.h>
#include <Xm/BulletinB.h>
#include <Xm/SelectioB.h>
#include <Xm/TextF.h>
#include <Xm/Form.h>
#include "net/bpf.h"
#include "interface.h"
#include "tcpview.h"
#include "motif.h"
#include "filter.h"
#ifdef __STDC__
struct bpf_program *parse(char *, int, int, u_long); /* gencode.c */
void readfile(char *);
char *malloc( int );
static void max_bytes_callback( Widget, caddr_t, caddr_t );
static void time_limit_callback( Widget, caddr_t, caddr_t );
static void num_frame_callback( Widget, caddr_t, caddr_t );
static void device_callback( Widget, caddr_t, caddr_t );
static void prom_callback( Widget, caddr_t, caddr_t );
static void done_callback( Widget, caddr_t, caddr_t );
static void cancel_callback( Widget, caddr_t, caddr_t );
static void dev_cancel( Widget, caddr_t, caddr_t );
#else
struct bpf_program *parse(); /* gencode.c */
void readfile();
char *malloc();
static void max_bytes_callback();
static void time_limit_callback();
static void num_frame_callback();
static void device_callback();
static void prom_callback();
static void done_callback();
static void cancel_callback();
static void dev_cancel();
#endif /* __STDC__ */
static int if_fd;
static char *strbuf;
static Widget Work, bb_widget, mb_widget, tl_widget, nf_widget, dev_widget, pr_widget;
static char *TempName;
static XtIntervalId TimeoutID = 0;
static char StderrName[64];
/* global configuration variables */
int MaxBytes;
char *Device=0;
static long TimeLimit = 0;
static long NumberOfFrames = -1;
static char *promstring[] = { "ON", "OFF" } ;
static u_short mb_semaphore;
static u_short tl_semaphore;
static u_short nf_semaphore;
static u_short dev_semaphore;
char *ltos( num )
long num;
{
static char str[32];
sprintf(str,"%d",num);
return( str );
}
void cap_opt_callback( widget, name, call_data )
Widget widget;
char *name;
caddr_t call_data;
{
Widget ok, main_row, frame, rc, rd;
int n;
Arg args[5];
mb_semaphore = tl_semaphore = nf_semaphore = dev_semaphore = 0;
n=0;
XtSetArg( args[n], XmNautoUnmanage, False ); n++;
XtSetArg( args[n], XmNdialogStyle, XmDIALOG_PRIMARY_APPLICATION_MODAL ); n++;
bb_widget = XmCreateBulletinBoardDialog (widget,"capture_options",args,n);
n = 0;
XtSetArg( args[n], XmNorientation, XmVERTICAL ); n++;
main_row = XmCreateRowColumn( bb_widget,"main",args,n);
XtManageChild( main_row );
n=0;
XtSetArg ( args[n], XmNshadowThickness, 4 ); n++;
frame = XmCreateFrame (main_row,"frame",args,n);
XtManageChild(frame);
n = 0;
XtSetArg( args[n], XmNorientation, XmVERTICAL ); n++;
rc = XmCreateRowColumn( frame,"row",args,n);
XtManageChild( rc );
n=0;
CreateLabelWidget( rc, "interface_opts"," INTERFACE OPTIONS ", args, n );
XmCreateSeparator( rc, "sep", args, n );
n=0;
XtSetArg( args[n], XmNorientation, XmHORIZONTAL ); n++;
rd = XmCreateRowColumn( rc,"data",args,n);
XtManageChild( rd );
CreateLabelWidget( rd, "device", "Device Name ", args, 0 );
if( Device == NULL ) {
Device = lookup_device();
if( Device == NULL )
eprint("Can't find any interfaces");
}
dev_widget = CreateSimpleButton( rd, Device, device_callback, (caddr_t)0 );
n=0;
XtSetArg( args[n], XmNorientation, XmHORIZONTAL ); n++;
rd = XmCreateRowColumn( rc,"rd",args,n);
XtManageChild( rd );
CreateLabelWidget( rd, "prom_mode", "Promiscuous Mode ", args, 0 );
pr_widget = CreateSimpleButton( rd, promstring[pflag], prom_callback, NULL );
n=0;
XtSetArg ( args[n], XmNshadowThickness, 4 ); n++;
frame = XmCreateFrame (main_row,"frame",args,n);
XtManageChild(frame);
n = 0;
XtSetArg( args[n], XmNorientation, XmVERTICAL ); n++;
rc = XmCreateRowColumn( frame,"row2",args,n);
XtManageChild( rc );
n=0;
CreateLabelWidget( rc, "cap_opts"," CAPTURE OPTIONS ", args, n );
XmCreateSeparator( rc, "sep", args, n );
n=0;
XtSetArg( args[n], XmNorientation, XmHORIZONTAL ); n++;
rd = XmCreateRowColumn( rc,"data",args,n);
XtManageChild( rd );
CreateLabelWidget( rd, "frame_num", "Number of Frames ", args, 0 );
if( NumberOfFrames > 0 )
nf_widget = CreateSimpleButton( rd, ltos(NumberOfFrames), num_frame_callback, (caddr_t)0 );
else
nf_widget = CreateSimpleButton( rd, "infinite", num_frame_callback, (caddr_t)0 );
n=0;
XtSetArg( args[n], XmNorientation, XmHORIZONTAL ); n++;
rd = XmCreateRowColumn( rc,"data",args,n);
XtManageChild( rd );
CreateLabelWidget( rd, "time", "Time Limit ", args, n );
if( TimeLimit > 0 )
tl_widget = CreateSimpleButton( rd, ltos(TimeLimit), time_limit_callback, (caddr_t)0 );
else
tl_widget = CreateSimpleButton( rd, "infinite", time_limit_callback, (caddr_t)0 );
CreateLabelWidget( rd, "time_sec", " seconds", args, 0 );
n=0;
XtSetArg( args[n], XmNorientation, XmHORIZONTAL ); n++;
rd = XmCreateRowColumn( rc,"data",args,n);
XtManageChild( rd );
CreateLabelWidget( rd, "bytes", "Max Bytes Per Frame ", args, 0 );
mb_widget = CreateSimpleButton( rd, ltos(MaxBytes), max_bytes_callback, (caddr_t)0 );
/* create 'OK' pushbutton */
n = 0;
ok = CreatePushButton( main_row, "done", " DONE ", args, n, done_callback);
/* Set OK button as default */
BulletinDefaultButton( bb_widget, ok );
XtManageChild( bb_widget );
} /* cap_opt_callback */
void get_long( parent, def, name, title, callback, semaphore )
Widget parent;
long def;
char *name, *title;
void (*callback)();
u_short *semaphore;
{
Widget w;
Arg args[2];
int n;
XmString ms, ms2;
ms = XmStringCreateSimple(title);
ms2 = XmStringCreateSimple( ltos(def) );
n = 0;
XtSetArg (args[n], XmNselectionLabelString, ms); n++;
if( def > 0 ) {
XtSetArg (args[n], XmNtextString, ms2); n++;
}
w = XmCreatePromptDialog( bb_widget, name ,args,n);
XtAddCallback( w, XmNokCallback, (*callback), (caddr_t)0);
XtAddCallback( w, XmNcancelCallback, cancel_callback, semaphore);
XtAddCallback( w, XmNunmapCallback, cancel_callback, semaphore);
XtManageChild( w );
XmStringFree( ms );
XmStringFree( ms2 );
}
static void mb_result( widget, data, foo )
Widget widget;
char *data;
XmSelectionBoxCallbackStruct *foo;
{
char *string;
XmStringGetLtoR( foo->value, XmSTRING_DEFAULT_CHARSET, &string);
/* make sure MaxBytes is not too small or too large */
MaxBytes = max(DEFAULT_SNAPLEN, atoi(string));
MaxBytes = min(MaxBytes, MAX_SNAPLEN);
SetLabel( mb_widget, ltos(MaxBytes) );
mb_semaphore = 0;
}
static void tl_result( widget, data, foo )
Widget widget;
char *data;
XmSelectionBoxCallbackStruct *foo;
{
char *string;
XmStringGetLtoR( foo->value, XmSTRING_DEFAULT_CHARSET, &string);
TimeLimit = atoi(string);
if( TimeLimit <= 0 )
SetLabel( tl_widget, "infinite" );
else
SetLabel( tl_widget, ltos(TimeLimit) );
tl_semaphore = 0;
}
static void nf_result( widget, data, foo )
Widget widget;
char *data;
XmSelectionBoxCallbackStruct *foo;
{
char *string;
XmStringGetLtoR( foo->value, XmSTRING_DEFAULT_CHARSET, &string);
NumberOfFrames = atoi(string);
if( NumberOfFrames <= 0 ) {
NumberOfFrames = -1;
SetLabel( nf_widget, "infinite" );
} else
SetLabel( nf_widget, ltos(NumberOfFrames) );
nf_semaphore = 0;
}
static void dev_result( widget, data, foo )
Widget widget;
char *data;
XmSelectionBoxCallbackStruct *foo;
{
char *string;
static char buf[16];
XmStringGetLtoR( foo->value, XmSTRING_DEFAULT_CHARSET, &string);
strcpy(buf, string);
Device = buf;
SetLabel( dev_widget, Device );
dev_semaphore = 0;
}
static void max_bytes_callback( widget, data, foo )
Widget widget;
caddr_t data;
caddr_t foo;
{
if( mb_semaphore )
return;
mb_semaphore = 1;
get_long( widget, MaxBytes,
"max_bytes",
"Maximum Number of Bytes to Capture Per Frame",
mb_result, &mb_semaphore );
}
static void time_limit_callback( widget, data, foo )
Widget widget;
caddr_t data;
caddr_t foo;
{
if( tl_semaphore )
return;
tl_semaphore = 1;
get_long( widget, TimeLimit,
"time_limit",
"Time Limit for Capture in Seconds",
tl_result, &tl_semaphore );
}
static void num_frame_callback( widget, data, foo )
Widget widget;
caddr_t data;
caddr_t foo;
{
if( nf_semaphore )
return;
nf_semaphore = 1;
get_long( widget, NumberOfFrames,
"number_frames",
"Number of Frames to Capture",
nf_result, &nf_semaphore );
}
static void prom_callback( widget, data, foo )
Widget widget;
caddr_t data;
caddr_t foo;
{
if( pflag )
pflag = 0;
else
pflag = 1;
SetLabel( pr_widget, promstring[pflag]);
}
static void done_callback( widget, data, foo )
Widget widget;
caddr_t data;
caddr_t foo;
{
XtUnmanageChild( bb_widget );
}
static void cancel_callback( widget, data, foo )
Widget widget;
caddr_t data;
caddr_t foo;
{
*data = 0;
XtUnmanageChild(widget);
}
static void dev_cancel( widget, data, foo )
Widget widget;
caddr_t data;
caddr_t foo;
{
dev_semaphore = 0;
XtUnmanageChild(widget);
}
static void device_callback( parent, data, foo )
Widget parent;
caddr_t data;
caddr_t foo;
{
Widget w;
Arg args[2];
int n;
XmString ms, ms2;
if( dev_semaphore )
return;
dev_semaphore = 1;
ms = XmStringCreateSimple("Network Device Name");
if( Device )
ms2 = XmStringCreateSimple( Device );
else
ms2 = XmStringCreateSimple("");
n = 0;
XtSetArg (args[n], XmNselectionLabelString, ms); n++;
XtSetArg (args[n], XmNtextString, ms2); n++;
w = XmCreatePromptDialog( parent, "dev" ,args,n);
XtAddCallback( w, XmNokCallback, dev_result, (caddr_t)0);
XtAddCallback( w, XmNcancelCallback, dev_cancel, (caddr_t)0);
XtManageChild( w );
XmStringFree( ms );
XmStringFree( ms2 );
}
static void end_capture()
{
if( if_fd >= 0)
wrapup(if_fd);
*StrPtr = 0;
sf_write_end();
exit(0);
}
u_short DoneWithCapture;
static void child_end()
{
int status;
FILE *fp;
int num;
char buf[512];
if( Work) XtUnrealizeWidget( Work );
DoneWithCapture = 1;
signal( SIGCHLD, SIG_IGN);
(void)wait(&status);
/* fprintf(stderr,"child exited with status %d\n",WEXITSTATUS(status)); */
fp = fopen(StderrName,"r");
if( fp ) {
num = fread( buf, 1, sizeof(buf), fp );
if( num ) {
buf[num]='\0';
eprint( buf );
}
unlink( StderrName );
fclose( fp );
}
if( WEXITSTATUS(status) == 0 )
readfile( TempName );
unlink( TempName );
}
/* semaphore */
static u_short Stopped=0;
static void stop_capture_callback( widget, data, call_data )
Widget widget;
caddr_t data;
caddr_t call_data;
{
Stopped = 1;
if( kill( (pid_t)data, SIGINT ) < 0 )
xperror("kill");
if( TimeoutID ) {
XtRemoveTimeOut( TimeoutID );
TimeoutID = 0;
}
Stopped = 0;
}
static void timer_expired( data, id )
caddr_t data;
XtIntervalId *id;
{
if( Stopped )
return;
TimeoutID = 0;
(void)kill( (pid_t)data, SIGINT );
}
void capture_callback( widget, name, call_data )
Widget widget;
char *name;
caddr_t call_data;
{
u_long netmask, localnet;
struct bpf_program *bpf;
pid_t pid;
extern long thiszone;
extern int snaplen, Linktype, Precision;
DoneWithCapture = 0;
Work = NULL;
{
struct timeval now;
struct timezone tz;
if (gettimeofday(&now, &tz) < 0) {
xperror("tcpdump: gettimeofday");
exit(1);
}
thiszone = tz.tz_minuteswest * -60;
if (localtime((time_t *)&now.tv_sec)->tm_isdst)
thiszone += 3600;
}
Precision = clock_sigfigs();
/* this should come from the capture options */
/* default and max should be based on DLC */
snaplen = MaxBytes;
/* pick a temporary name for stderr */
strcpy(StderrName,tmpnam(NULL));
/* pick a temporary name to save frames to */
TempName = tmpnam(NULL);
update_fstr(&Filter);
(void)signal( SIGCHLD, child_end );
if( (pid = fork()) < 0 ) {
eprint("Problem forking capture process");
return;
}
if( pid == 0 ) {
/* send stderr to a temp file */
(void)freopen(StderrName,"w",stderr);
if( Device == NULL ) {
Device = lookup_device();
if( Device == NULL ) {
eprint("Can't find device");
exit(1);
}
}
if_fd = initdevice( Device, pflag, &Linktype );
lookup_net( Device, &localnet, &netmask );
bpf = parse( Fstr, 1, Linktype, netmask );
/* set up printf buffer */
StrPtr = strbuf = malloc(512);
sf_write_init( TempName, Linktype, thiszone, snaplen, Precision );
(void)signal( SIGTERM, end_capture );
(void)signal( SIGINT, end_capture );
(void)signal( SIGHUP, end_capture );
readloop( NumberOfFrames, if_fd, bpf, sf_write );
end_capture();
} else { /* parent */
XmString ms, ms_stop;
Arg args[2];
int n;
if( TimeLimit > 0 )
TimeoutID = XtAddTimeOut( TimeLimit*1000, timer_expired, (caddr_t)pid );
/* now create a dialog with "Stop" button */
ms = XmStringCreateSimple( "Capturing");
ms_stop = XmStringCreateSimple( "STOP" );
n = 0;
XtSetArg( args[n], XmNmessageString, ms ); n++;
XtSetArg( args[n], XmNokLabelString, ms_stop ); n++;
Work = XmCreateWorkingDialog( widget,"STOP",args,n );
RemoveDialButton( Work, XmDIALOG_HELP_BUTTON );
RemoveDialButton( Work, XmDIALOG_CANCEL_BUTTON );
XtAddCallback( Work, XmNokCallback,stop_capture_callback, (caddr_t)pid );
if( !DoneWithCapture )
XtManageChild( Work );
XmStringFree( ms );
XmStringFree( ms_stop );
}
} /* capture_callback */
syntax highlighted by Code2HTML, v. 0.9.1