/***************************************************************************
 * DBS: Distributed Benchmark System
 * Copyright (c) 1995, 1996, 1997 Yukio Murayama
 * Copyright (c) 1995, 1996, 1997 Nara Institute of Science and Technology
 * All rights reserved.
 *
 * Permission to use, copy, modify and distribute this software and its
 * documentation is hereby granted, provided only with the following
 * conditions are satisfied:
 *
 * 1. Both the copyright notice and this permission notice appear in
 *    all copies of the software, derivative works or modified versions,
 *    and any portions thereof, and that both notices appear in
 *    supporting documentation.
 * 2. All advertising materials mentioning features or use of this
 *    software must display the following acknowledgement:
 *      This product includes software developed by Nara Institute of 
 *      Science and Technology and its contributors.
 * 3. Neither the name of Nara Institute of Science and Technology nor 
 *    the names of its contributors may be used to endorse or promote 
 *    products derived from this software without specific prior written
 *    permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND NARA 
 * INSTITUTE OF SCIENCE AND TECHNOLOGY DISCLAIMS ANY LIABILITY OF 
 * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF 
 * THIS SOFTWARE. ALSO, THERE IS NO WARRANTY IMPLIED OR OTHERWISE, 
 * NOR IS SUPPORT PROVIDED.
 *
 * Feedback of the results generated from any improvements or
 * extensions made to this software would be much appreciated.
 * Any such feedback should be sent to:
 *
 *  Yukio Murayama
 *  E-mail:  <yukio-m@is.aist-nara.ac.jp>
 *  URL:     <http://shika.aist-nara.ac.jp/member/yukio-m/index.html>
 *  Address: Graduate School of Information Science, 
 *           Nara Institute of Science and Technology,
 *           Takayama 8916-5, Ikoma, Nara, Japan
 *
 * Nara Institute of Science and Technology has the rights to 
 * redistribute these changes.
 ***************************************************************************/
/*****************************************************************
 * Distributed Benchmark System
 * DBS Client
 * $Revision: 1.25 $
 * $Date: 1997/07/11 00:54:00 $
 * $Author: yukio-m $
 *****************************************************************/

#define DBSC

#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <setjmp.h>
#include <sys/time.h>
#include <time.h>
#include <signal.h>
#include <sys/param.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <errno.h>

#if (!defined(BSD) || (BSD < 199306))
#include <malloc.h>
#endif

#include "dbs.h"
#include "dbsc.h"
#include "dbs_net.h"

#define FREE(A) if ((A) != (NULL)) free(A)

int  receive_status    __P((int fd, char *msg));
void get_origin_time  __P((struct timeval *origin_time));
int  recv_result      __P((struct scan_cmd *cmd));
int  recv_tcp_trace   __P((int fd, struct tcp_trace_net *rt));
void write_tcp_trace  __P((char *name, struct tcp_trace_net *td));
void write_result     __P((char *name, struct record_net *rd1, struct record_net *rd2));
int  recv_sub         __P((int fd, struct record_net *rd));

int  is_send_recv     __P((struct scan_cmd *cmd, int serverflg));
struct send_recv *set_send_recv __P((struct scan_cmd *cmd, int serverflg));

void send_cmd         __P((int fd, struct scan_cmd *cmd, int sendflg));
void send_command     __P((struct scan_cmd *cmd, int port, int sendflg));
void tcp_terminate    __P((int fd));

void send_origin_time __P((int fd, struct timeval origin_time));
int  tcp_init_client  __P((char *remotehost, int port));
void init_scan_cmd    __P((struct scan_cmd *scan_cmd));
void error            __P((struct scan_cmd *scan, int sr, int e, char *msg));
int  send_request     __P((int fd, int i));

void safe_exit        __P((void));
void safe_exit1       __P((int signo));
void safe_exit2       __P((int signo));
void tcp_init_client_timeout __P((int signo));
void help             __P((char *prog));

struct scan_cmd *scan_cmd = (struct scan_cmd *)NULL;

static jmp_buf env_alrm;

/*****************************************************************
 * MAIN
 *****************************************************************/
void main(argc, argv)
int argc;
char *argv[];
{
    struct servent *sp;
    struct timeval origin_time;
    struct scan_cmd *cmd;
    FILE *fp;
    int port;
    int ch, i, e, n;
    int   end_time;
    char *fname=NULL;
    char msg[CHAR_ARRAY];
    char buf[256];
    extern char *optarg;
    extern int optind, opterr;
    extern struct scan_cmd *scan_cmd;

    if ((sp = getservbyname("dbs", "tcp")) != NULL) {
	port = (int)ntohs((u_short)sp->s_port);
    } else {
	port = DEFAULT_PORT;
    }

    if (argc <=1) {
	help(argv[0]);
	exit(1);
    }

    while ((ch = getopt(argc, argv, "dp:v")) != EOF) {
	switch(ch) {
	  case 'p':    /* -p: Port Number */
	    port = atoi(optarg);
	    break;
	  case 'd':    /* -d: DEBUG MODE */
	    debug++;
	    break;
	  case 'v':    /* -v: show version */
	  default:
	    help(argv[0]);
	    exit(1);
	}
    }

    DEBUGMSG2(1, fprintf(stderr,"debug level = %d\n", debug));

    if ((fname = argv[optind]) == 0) {
	help(argv[0]);
	exit(1);
    }

    DEBUGMSG2(2, fprintf(stderr, "sizeof(struct scan_cmd) = %dbyte\n", (int)sizeof(struct scan_cmd)));

    /*
     *  Scan Command file.
     */
    DEBUGMSG(0, "Command File: ");

    if ((fp=fopen(fname, "r")) ==  NULL) {
	char tmp[256];
	sprintf(tmp, "fopen '%s'",fname);
	perror(tmp);
	exit(1);
    }
    n = scan(&scan_cmd, fp);
    fclose(fp);

    if (n <= 0) {
	fprintf(stderr, "\nError: Command File is Empty.\n");
	exit(1);
    }
    DEBUGMSG(0, "OK\n");
    init_scan_cmd(scan_cmd);

    signal(SIGINT,  safe_exit1);
    signal(SIGPIPE, safe_exit2);
    signal(SIGALRM, tcp_init_client_timeout);

    /*
     * Send Command to Server 
     */
    DEBUGMSG(1, "Sending Command to SERVER\n");
    send_command(cmd, port, SERVER);

    sleep((int)RECV_DELAY_OFFSET);

    /*
     * Send Command to Client 
     */
    DEBUGMSG(1, "Sending Command to CLIENT\n");
    send_command(cmd, port, CLIENT);

    DEBUGMSG(1, "SEND COMMAND: Normal END.\n");

    /****** Send Start Time or Exit. *****/
    get_origin_time(&origin_time);
	
    for (cmd = scan_cmd; cmd; cmd = cmd->next) {
	send_origin_time(cmd->sender.fd,   origin_time);
	cmd->sender.status = S_GO;
	
	send_origin_time(cmd->receiver.fd, origin_time);
	cmd->receiver.status = S_GO;
    }

    DEBUGMSG(1, "SEND START TIME: Normal END.\n");

    end_time = 0;
    for (cmd = scan_cmd; cmd; cmd = cmd->next) {
	if (end_time < cmd->end_time.tv_sec)
	    end_time = cmd->end_time.tv_sec;
    }

    i = (int)(end_time + START_TIME_OFFSET + END_TIME_OFFSET1 + END_TIME_OFFSET2);

    DEBUGMSG2(0, fprintf(stderr, "Test Start. Test time=%ds\n", i));
    sleep(i);
    DEBUGMSG(0, "Test End.\n");

    /***** Receive Status (Result). *****/
    DEBUGMSG(1, "Wait for results from dbsd .....\n");
    for (cmd = scan_cmd; cmd; cmd = cmd->next) {
	int timeout_flg = OFF;

	if (send_request(cmd->sender.fd, NORMAL) == -1) {
	    error(cmd, SEND, ABNORMAL, msg);
	    cmd->sender.status = S_ERROR;
	    safe_exit();
	}
	if ((e = receive_status(cmd->sender.fd, msg)) != NORMAL) {
	    error(cmd, SEND, e, msg);
	    cmd->sender.status = S_ERROR;
	    safe_exit();
	}
	if (strcmp(msg,"*Time Out*") == 0) {
	    timeout_flg = ON;
	}

	if (send_request(cmd->receiver.fd, NORMAL) == -1) {
	    error(cmd, RECEIVE, ABNORMAL, msg);
	    cmd->receiver.status = S_ERROR;
	    safe_exit();
	}
	if ((e = receive_status(cmd->receiver.fd, msg)) != NORMAL) {
	    error(cmd, RECEIVE, e, msg);
	    cmd->receiver.status = S_ERROR;
	    safe_exit();
	}
	if (strcmp(msg,"*Time Out*") == 0) {
	    timeout_flg = ON;
	}

	if (timeout_flg == ON) {
	    fprintf(stderr, "*Time Out*:(%s,%s,%d,%d,%s)\n",
		    cmd->sender.hostname,
		    cmd->receiver.hostname,
		    cmd->sender.port,
		    cmd->receiver.port,
		    (cmd->transport==TCP)?"TCP":"UDP");

	    fprintf(stderr, "'end_time=%.0f' is small.\n", timeval2double(&(cmd->end_time)));
	}
    }

    DEBUGMSG(1, "RECEIVE STATUS: Normal END.\n");    
	
    /***** Receive Results and Write into File. *****/
    for (cmd = scan_cmd; cmd; cmd = cmd->next) {
	DEBUGMSG2(0, 
		 fprintf(stderr, "Results:(%s,%s,%d,%d,%s)",
			 cmd->sender.hostname,
			 cmd->receiver.hostname,
			 cmd->sender.port,
			 cmd->receiver.port,
			 (cmd->transport==TCP)?"TCP":"UDP")
		 );

	if (send_request(cmd->sender.fd, NORMAL) == -1) {
	    error(cmd, SEND, ABNORMAL, msg);
	    cmd->sender.status = S_ERROR;
	    safe_exit();
	} else {
	    cmd->sender.status = S_NORMAL;
	}

	if (send_request(cmd->receiver.fd, NORMAL) == -1) {
	    error(cmd, RECEIVE, ABNORMAL, msg);
	    cmd->receiver.status = S_ERROR;
	    safe_exit();
	} else {
	    cmd->receiver.status = S_NORMAL;
	}


	if (recv_result(cmd) != NORMAL) {
	    fprintf(stderr, "Receiving Error\n");
	    cmd->receiver.status = S_ERROR;
	    safe_exit();
	}

	close(cmd->sender.fd);
	cmd->sender.status = S_CLOSE;

	close(cmd->receiver.fd);
	cmd->receiver.status = S_CLOSE;

	DEBUGMSG(0, ":Received\n");    
    }
    DEBUGMSG(1, "RECEIVE RESULT: Normal END\n");
    DEBUGMSG(0, "DBSC: Normal END.\n");    

    exit(0);
}

/*****************************************************************
 * Send Module
 *****************************************************************/
/*
 * Send origin time
 */
void send_origin_time(fd, origin_time)
int fd;
struct timeval origin_time;
{
    struct timeval net_tv;

    net_tv.tv_sec  = htonl(origin_time.tv_sec);
    net_tv.tv_usec = htonl(origin_time.tv_usec);
    send(fd, (void *)&net_tv, sizeof(struct timeval), 0);
}

/*
 * Send Request
 */
int send_request(fd, i)
int fd;
int i;
{
    int net;

    net = htonl(i);

    if (send(fd, (void *)&net, sizeof(net), 0) != sizeof(i))
	return -1;
    else
	return 1;
}

/*
 * set send or recv
 */
struct send_recv *set_send_recv(cmd, serverflg)
struct scan_cmd *cmd;
int serverflg;
{
    if (serverflg == SERVER ) {
	if (cmd->serverflg == SEND)
	    return &(cmd->sender);
	else
	    return &(cmd->receiver);
    } else {
	if (cmd->serverflg == SEND)
	    return &(cmd->receiver);
	else
	    return &(cmd->sender);
    }
}

/*
 * Which is send or recv?
 */
int is_send_recv(cmd, serverflg)
struct scan_cmd *cmd;
int serverflg;
{
    if (serverflg == SERVER) {
	if (cmd->serverflg == SEND)
	    return SEND;
	else
	    return RECEIVE;
    } else {
	if(cmd->serverflg == SEND)
	    return RECEIVE;
	else
	    return SEND;
    }
}

/*
 * DBSC -> DBSD    send_cmd()
 *
 * DBSD -> DBSC
 *
 * Send_Command
 *
 * send_cmd
 * recv status
 * check time synchronization
 */
void send_command(cmd, port, serverflg)
struct scan_cmd *cmd;
int port;
int serverflg;
{
    struct send_recv *sr;
    struct timeval current_time;
    struct timezone tzp;
    char msg[CHAR_ARRAY];
    double d_time, t1, t2;
    extern struct scan_cmd *scan_cmd;
    int e;
    SIGNAL_INIT;

    gettimeofday(&current_time, &tzp);
    t1 = timeval2double(&current_time);

    /* Send Command to Server */
    DEBUGMSG(2, "SEND_COMMAND\n");    
    for (cmd = scan_cmd; cmd; cmd = cmd->next) {
	sr = set_send_recv(cmd, serverflg);

	BEGIN_CRITICAL_REGION;
	sr->fd = tcp_init_client(sr->hostname_cmd, port);
	sr->status = S_CONNECT;
	END_CRITICAL_REGION;

	send_cmd(sr->fd, cmd, is_send_recv(cmd, serverflg));
    }

    /* Receive Status from Server */
    DEBUGMSG(2, "RECEIVE_STATUS\n");    
    for (cmd = scan_cmd; cmd; cmd = cmd->next) {
	sr = set_send_recv(cmd, serverflg);

	if ((e = receive_status(sr->fd, msg)) != NORMAL) {
	    error(cmd, is_send_recv(cmd, serverflg), e, msg);
	    safe_exit();
	}
	gettimeofday(&current_time, &tzp);
	t2 = timeval2double(&current_time);

	d_time  = atof(msg);

	DEBUGMSG2(2, fprintf(stderr, "DBSD TIME=(%f) DBSC TIME=(%f, %f)\n", d_time, t1, t2));
	DEBUGMSG2(1, fprintf(stderr, "TIME DIFF=(%f <= TIME <= %f)\n", t1 - d_time, t2 - d_time));

	if (t1 - MAX_TIME_SYNC > d_time || t2 + MAX_TIME_SYNC < d_time) {
	    error(cmd, is_send_recv(cmd, serverflg), TIMESYNC, "No time sync\nYou should check NTP\n");
	    safe_exit();
	}

	if (t1 - WARN_TIME_SYNC > d_time || t2 + WARN_TIME_SYNC < d_time) {
	    DEBUGMSG2(0, 
		      fprintf(stderr, "WARNING: Host '%s' may be out of time synchronization. You should check NTP.\n", 
			      sr->hostname)
		      );
	}

	if (serverflg == CLIENT) {
	    DEBUGMSG2(0, 
		      fprintf(stderr, "Setup:(%s.%d, %s.%d, %s):End\n",
			      cmd->sender.hostname,
			      cmd->sender.port,
			      cmd->receiver.hostname,
			      cmd->receiver.port,
			      (cmd->transport==TCP)?"TCP":"UDP")
		      );
	}
    }
}

/*
 * Send_cmd
 * Translate Network Byte Order and Transmission Command
 */
void send_cmd(fd, cmd, sendflg)
int fd;
struct scan_cmd *cmd;
int sendflg;
{
    struct net_cmd net_cmd;
    struct net_traffic net_traffic;
    struct send_recv *p1, *p2;
    struct scan_traffic *traffic;
    int i;

    if (sendflg == SEND) {
	p1 = &(cmd->sender);
	p2 = &(cmd->receiver);
    } else if (sendflg == RECEIVE) {
	p1 = &(cmd->receiver);
	p2 = &(cmd->sender);
    } else {
	fprintf(stderr, "Internal Bug!! (send_cmd)\n");
	safe_exit();
    }

    if (cmd->serverflg == sendflg) {
	net_cmd.serverflg      = htonl((u_int)SERVER);
    } else {
	net_cmd.serverflg      = htonl((u_int)CLIENT);
    }

    /*
     * Send Commands
     */
    
    strcpy(net_cmd.dsthostname, p2->hostname);
    strcpy(net_cmd.srchostname, p1->hostname);
    net_cmd.transport          = htonl((u_int)cmd->transport);
    net_cmd.sendflg            = htonl((u_int)sendflg);
    net_cmd.source_port        = htonl((u_int)p1->port);
    net_cmd.dest_port          = htonl((u_int)p2->port);
    net_cmd.send_buff          = htonl((u_int)p1->send_buff);
    net_cmd.recv_buff          = htonl((u_int)p1->recv_buff);
    net_cmd.no_delay           = htonl((u_int)p1->no_delay);
    net_cmd.mss                = htonl((u_int)p1->mss);
    net_cmd.so_debug           = htonl((u_int)p1->so_debug);
    net_cmd.tcp_trace          = htonl((u_int)p1->tcp_trace);
    net_cmd.record_buff        = htonl((u_int)p1->record_buff);
    net_cmd.trace_buff         = htonl((u_int)p1->trace_buff);
    net_cmd.connection_mode    = htonl((u_int)cmd->connection_mode);
    net_cmd.traffic_n          = htonl((u_int)p1->traffic_n);
    net_cmd.mem_align          = htonl((u_int)p1->mem_align);
    net_cmd.align_offset       = htonl((u_int)p1->align_offset);
    net_cmd.align_pad          = htonl((u_int)p1->align_pad);
    net_cmd.send_times         = htonl((u_int)cmd->send_times);
    net_cmd.total_size         = htonl((u_int)cmd->total_size);
    net_cmd.total_message      = htonl((u_int)cmd->total_message);
    net_cmd.start_time.tv_sec  = htonl((u_int)cmd->start_time.tv_sec);
    net_cmd.start_time.tv_usec = htonl((u_int)cmd->start_time.tv_usec);
    net_cmd.end_time.tv_sec    = htonl((u_int)cmd->end_time.tv_sec);
    net_cmd.end_time.tv_usec   = htonl((u_int)cmd->end_time.tv_usec);

    DEBUGMSG2(2, fprintf(stderr, "sizeof(struct net_cmd)=%dbyte\n", (int)sizeof(struct net_cmd)));

    if (debug >= 2) {
	fprintf(stderr, "Command Data --------------------------------------------------\n");
	fprintf(stderr, "Send to %s\n", p1->hostname);
	fprintf(stderr, "Destination    = %-12s %-12s\n", p2->hostname,   net_cmd.dsthostname);
	fprintf(stderr, "Source         = %-12s %-12s\n", p1->hostname,   net_cmd.srchostname);
	fprintf(stderr, "Protocol       = %-12d %-12d\n", cmd->transport, net_cmd.transport);
	fprintf(stderr, "Server flag    = %-12d %-12d\n", ntohl(net_cmd.serverflg), net_cmd.serverflg);
	fprintf(stderr, "Send flag      = %-12d %-12d\n", sendflg,        net_cmd.sendflg);
	fprintf(stderr, "Source Port    = %-12d %-12d\n", p1->port,       net_cmd.source_port);
	fprintf(stderr, "Receive Port   = %-12d %-12d\n", p2->port,       net_cmd.dest_port);
	fprintf(stderr, "Send Times     = %-12d %-12d\n", cmd->send_times,net_cmd.send_times);
	fprintf(stderr, "Send Buffer    = %-12d %-12d\n", p1->send_buff,  net_cmd.send_buff);
	fprintf(stderr, "Receive Buffer = %-12d %-12d\n", p1->recv_buff,  net_cmd.recv_buff);
	fprintf(stderr, "Total Size     = %-12d %-12d\n", cmd->total_size,net_cmd.total_size);
	fprintf(stderr, "Total Message  = %-12d %-12d\n", cmd->total_message,net_cmd.total_message);
	fprintf(stderr, "TCP No Delay   = %-12d %-12d\n", p1->no_delay,   net_cmd.no_delay);
	fprintf(stderr, "MSS            = %-12d %-12d\n", p1->mss,        net_cmd.mss);
	fprintf(stderr, "So Debug       = %-12d %-12d\n", p1->so_debug,   net_cmd.so_debug);
	fprintf(stderr, "TCP Trace      = %-12d %-12d\n", p1->tcp_trace,  net_cmd.tcp_trace);
	fprintf(stderr, "Traffic_N      = %-12d %-12d\n", p1->traffic_n,  net_cmd.traffic_n);
	fprintf(stderr, "Record Buffer  = %-12d %-12d\n", p1->record_buff,net_cmd.record_buff);
	fprintf(stderr, "Trace Buffer   = %-12d %-12d\n", p1->trace_buff, net_cmd.trace_buff);
	fprintf(stderr, "Memory Align   = %-12d %-12d\n", p1->mem_align,  net_cmd.mem_align);
	fprintf(stderr, "Align Offset   = %-12d %-12d\n", p1->align_offset,net_cmd.align_offset);
	fprintf(stderr, "Align Pad      = %-12d %-12d\n", p1->align_pad,  net_cmd.align_pad);
	fprintf(stderr, "Connection Mode= %-12d %-12d\n", cmd->connection_mode, net_cmd.connection_mode);

	fprintf(stderr, "Start Time     = (%-12d, %-12d) (%-12d, %-12d)\n",
		cmd->start_time.tv_sec, cmd->start_time.tv_usec, 
		net_cmd.start_time.tv_sec, net_cmd.start_time.tv_usec);
	fprintf(stderr, "End time       = (%-12d, %-12d) (%-12d, %-12d)\n",
		cmd->end_time.tv_sec, cmd->end_time.tv_usec,
		net_cmd.end_time.tv_sec, net_cmd.end_time.tv_usec);
	fprintf(stderr, "---------------------------------------------------------------\n");
    }

    send(fd, (void *)&net_cmd, sizeof(struct net_cmd), 0);

    /*
     * Send Traffic Patterns
     */
    traffic = p1->traffic;
    for (i=0; i < p1->traffic_n; i++) {
	net_traffic.size    = htonl(traffic->size);
	net_traffic.packet  = htonl(traffic->packet);
	net_traffic.esleep  = htonl((int)(traffic->esleep*(1000.0*1000.0)));
	net_traffic.isleep  = htonl((int)(traffic->isleep*(1000.0*1000.0)));

	if (debug >= 2) {
	    fprintf(stderr, "Traffic Pattern-----------------------------------------\n");
	    fprintf(stderr, "SIZE   = %-12d %-12d\n", traffic->size,    net_traffic.size);
	    fprintf(stderr, "PAKET  = %-12d %-12d\n", traffic->packet,  net_traffic.packet);
	    fprintf(stderr, "ESLEEP = %-12f %-12d\n", traffic->esleep,  net_traffic.esleep);
	    fprintf(stderr, "ISLEEP = %-12f %-12d\n", traffic->isleep,  net_traffic.isleep);
	    fprintf(stderr, "--------------------------------------------------------\n");
	}
	send(fd, (void *)&net_traffic, sizeof(struct net_traffic), 0);
	traffic = traffic->next;
    }
}

/*****************************************************************
 * Receive Module
 *****************************************************************/
/*
 *  Check Status
 */
int receive_status(fd, msg)
int fd;
char *msg;
{
    int net, e, i;

    net = e = i =0;

    /* Error Number */    
    RECV(fd, &net, sizeof(net));
    e = ntohl(net);

    /* Message Length */    
    RECV(fd, &net, sizeof(net));

    i = ntohl(net);
    if (i >= CHAR_ARRAY) {
	fprintf(stderr, "DBSD Version Mismatch or DBSD Internal Error(%d, %d)\n", e, i);

	strcpy(msg, "<null>");
	recv(fd, msg, CHAR_ARRAY-1, 0);
	msg[CHAR_ARRAY-1]= '\0';

	fprintf(stderr, "'%s'\n", msg);
	safe_exit();
    } else if (i > 0) {
	RECV(fd, msg, i); /* Message Strings */    
	msg[i]= '\0';
    } else {
	strcpy(msg, "");
    }
    return e;
}

/*
 *  Receive Result
 */
int recv_result(cmd)
struct scan_cmd *cmd;
{
    struct record_net    rds, rdr;
    struct tcp_trace_net rts, rtr;
    char name[1024];

    /*
     * Receive RD2
     */

    if (cmd->connection_mode == AFTER) {
	recv_sub(cmd->sender.fd,   &rds);
	recv_sub(cmd->receiver.fd, &rdr);
	sprintf(name, "%s%s", (char *)cmd->filename, ".c");
	write_result(name, &rds, &rdr);
    }

    /*
     * Receive RD
     */

    recv_sub(cmd->sender.fd,   &rds);
    recv_sub(cmd->receiver.fd, &rdr);
    sprintf(name, "%s%s", (char *)cmd->filename, ".t");
    write_result(name, &rds, &rdr);

    /*
     * Receive TCP_Trace
     */

    if (cmd->sender.tcp_trace == ON) {
	recv_tcp_trace(cmd->sender.fd, &rts);
	sprintf(name, "%s%s", (char *)cmd->filename, ".td_s");
	write_tcp_trace(name, &rts);
    }

    if (cmd->receiver.tcp_trace == ON) {
	recv_tcp_trace(cmd->receiver.fd, &rtr);
	sprintf(name, "%s%s", (char *)cmd->filename, ".td_r");
	write_tcp_trace(name, &rtr);
    }

    return NORMAL;
}

/*
 *  Receive sub
 */
int recv_sub(fd, rd)
int fd;
struct record_net *rd;
{
    int net_r, r;

    DEBUGMSG(1, "Receive Data:");
    
    RECV(fd, &net_r, sizeof(net_r));
    rd->n = ntohl(net_r);
    r = rd->n * sizeof(struct record_d_net);
    
    DEBUGMSG2(1,fprintf(stderr, "[%3d * %4d] = %6dbyte ", (int)sizeof(struct record_d_net), rd->n, r));

    if (rd->n >= 1) {
	if ((rd->d=(struct record_d_net *)malloc(r)) == NULL) {
	    perror("malloc");
	    return -1;
	}
	RECV(fd, rd->d, r);
    } else {
	rd->d = NULL;
    }
    
    DEBUGMSG(1,	"Received.\n");

    return r;
}

/*
 * Write Result
 */
void write_result(name, rds,  rdr)
char *name;
struct record_net *rds, *rdr;
{
    FILE *fp;
    int i, n;

    if ((fp=fopen(name, "w")) ==  NULL) {
	char tmp[256];
	sprintf(tmp, "fopen '%s'",name);
	perror(tmp);
	return;
    }

    DEBUGMSG2(1, fprintf(stderr, "Writing File (%s)... ", name));

    n = MAX(rds->n, rdr->n);
    DEBUGMSG2(2, fprintf(stderr, "n1=%d, n2=%d, n=%d\n", rds->n, rdr->n, n));

    /*
     * Write Index which is used by dbs_view:Draw Graph Tool
     */
    fprintf(fp, "%10s %10s %13s %10s %10s %13s\n",
	    "send_sequence",
	    "send_size",
	    "send_time",
	    "recv_sequence",
	    "recv_size",
	    "recv_time");

    /*
     * Write Results
     */
    for (i=0; i < n; i++) {
	if (i >= rds->n) {
	    fprintf(fp, "%10s %10s %13s %10d %10d %13.6f\n",
		    "NA",
		    "NA",
		    "NA",
		    (int)ntohl(rdr->d[i].packet_no),
		    (int)ntohl(rdr->d[i].packet_size),
		    (int)ntohl(rdr->d[i].tv_sec) + ntohl(rdr->d[i].tv_usec)/(1000.0*1000.0));
	} else if (i >= rdr->n) {
	    fprintf(fp, "%10d %10d %13.6f %10s %10s %13s\n",
		    (int)ntohl(rds->d[i].packet_no),
		    (int)ntohl(rds->d[i].packet_size),
		    (int)ntohl(rds->d[i].tv_sec) + ntohl(rds->d[i].tv_usec)/(1000.0*1000.0),
		    "NA",
		    "NA",
		    "NA");
	} else {
	    fprintf(fp, "%10d %10d %13.6f %10d %10d %13.6f\n",
		    (int)ntohl(rds->d[i].packet_no),
		    (int)ntohl(rds->d[i].packet_size),
		    (int)ntohl(rds->d[i].tv_sec) + ntohl(rds->d[i].tv_usec)/(1000.0*1000.0),
		    (int)ntohl(rdr->d[i].packet_no),
		    (int)ntohl(rdr->d[i].packet_size),
		    (int)ntohl(rdr->d[i].tv_sec) + ntohl(rdr->d[i].tv_usec)/(1000.0*1000.0));
	}
    }
    fclose(fp);
    DEBUGMSG(1, "END.\n");

    FREE(rds->d);
    FREE(rdr->d);
}

/*****************************************************************
 * tcp_trace process
 *****************************************************************/
int recv_tcp_trace(fd, rt)
int fd;
struct tcp_trace_net *rt;
{
    int tcp_r, r = 0;

    DEBUGMSG(1, "TCP Trace:  ");

    RECV(fd, &tcp_r, sizeof(tcp_r));
    rt->n = ntohl(tcp_r);
    r = sizeof(struct tcp_trace_d_net) * rt->n;

    DEBUGMSG2(1, fprintf(stderr, "[%3d * %4d] = %6dbyte ",
			  (int)sizeof(struct tcp_trace_d_net), rt->n, r));

    if (rt->n >= 1) {
	if ((rt->d=(struct tcp_trace_d_net *)malloc(r)) == NULL) {
	    perror("malloc");
	    return -1;
	}
	RECV(fd, rt->d, r);
    } else {
	rt->d = NULL;
    }

    DEBUGMSG(1, "Received.\n");

    return r;
}

void write_tcp_trace(name, rt)
char *name;
struct tcp_trace_net *rt;
{
    FILE *fp[5];
    char fname[1024];
    int i, th_flags, t_flags, act;
    int seq, ack;

    for (i=0; i<5; i++) {
	sprintf(fname, "%s_%d", name, i);
	if ((fp[i]=fopen(fname, "w")) ==  NULL) {
	    char tmp[256];
	    sprintf(tmp, "fopen '%s'",fname);
	    perror(tmp);
	    return;
	}
    }
    DEBUGMSG2(1, fprintf(stderr, "Writing File (%s0,1,2,3,4)... ", name));
    
    for (i=0; i<5; i++) {
	/*
	 * Write Index which used by dbs_view:Draw Graph Tool
	 */
	fprintf(fp[i],"%7s ",  "td_time");
	fprintf(fp[i],"%3s ",  "act");
	fprintf(fp[i],"%10s ",  "seq");
	fprintf(fp[i],"%10s ",  "ack");
	fprintf(fp[i],"%10s ",  "len");
	fprintf(fp[i],"%10s ", "th_seq");
	fprintf(fp[i],"%10s ", "th_ack");
	fprintf(fp[i],"%8s ",  "th_flags");
	fprintf(fp[i],"%10s ", "t_state");
	fprintf(fp[i],"%10s ", "t_rxtshift");
	fprintf(fp[i],"%10s ", "t_rxtcur");
	fprintf(fp[i],"%10s ", "t_dupacks");
	fprintf(fp[i],"%10s ", "t_maxseg");
/*	fprintf(fp[i],"%10s ", "t_force");*/
	fprintf(fp[i],"%16s ", "t_flags");
	fprintf(fp[i],"%10s ", "snd_una");
	fprintf(fp[i],"%10s ", "snd_nxt");
	fprintf(fp[i],"%10s ", "snd_wl1");
	fprintf(fp[i],"%10s ", "snd_wl2");
	fprintf(fp[i],"%10s ", "iss");
	fprintf(fp[i],"%10s ", "snd_wnd");
	fprintf(fp[i],"%10s ", "rcv_wnd");
	fprintf(fp[i],"%10s ", "rcv_nxt");
	fprintf(fp[i],"%10s ", "irs");
	fprintf(fp[i],"%10s ", "rcv_adv");
	fprintf(fp[i],"%10s ", "snd_max");
	fprintf(fp[i],"%10s ", "snd_cwnd");
	fprintf(fp[i],"%10s ", "snd_ssthresh");
	fprintf(fp[i],"%10s ", "t_idle");
	fprintf(fp[i],"%10s ", "t_rtt");
	fprintf(fp[i],"%10s ", "t_rtseq");
	fprintf(fp[i],"%10s ", "t_srtt");
	fprintf(fp[i],"%10s ", "t_rttvar");
/*	fprintf(fp[i],"%10s ", "t_rttmin");*/
	fprintf(fp[i],"%10s ", "max_sndwnd");
	fprintf(fp[i],"\n");
    }
    
#define TA_INPUT   0
#define TA_OUTPUT  1
#define TA_USER    2
#define TA_RESPOND 3
#define TA_DROP    4

    for (i=0; i < rt->n; i++) {
	th_flags = ntohl(rt->d[i].th_flags);
	t_flags  = ntohl(rt->d[i].t_flags),
	act = ntohl(rt->d[i].td_act);

	if (act >= 5) {
	    /*
	     * Internal Error
	     */
	    fprintf(stderr, "ACT ERRROR td_act=%d\n", act);
	    act=TA_DROP;
	}

	/*
	 * Calculate Sequense Number and Acknowledge Number
	 */
	switch (act) {
	  case TA_INPUT:
	    seq = ntohl(rt->d[i].th_seq) - ntohl(rt->d[i].irs);
	    if ((0x02 & th_flags) != 0)   /* SYN */
		ack = 0;
	    else
		ack = ntohl(rt->d[i].th_ack) - ntohl(rt->d[i].iss);
	    break;
	  case TA_OUTPUT:
	    seq = ntohl(rt->d[i].th_seq) - ntohl(rt->d[i].iss);
	    if ((0x02 & th_flags) != 0 )   /* SYN */
		ack = 0;
	    else
		ack = ntohl(rt->d[i].th_ack) - ntohl(rt->d[i].irs);
	    break;
	  case TA_USER:
	  case TA_RESPOND:
	  case TA_DROP:
	    seq = 0;
	    ack = 0;
	    break;
	  default:
	    if (act >= 5) {
		fprintf(stderr, "ACT ERRROR td_act=%d\n", act);
		act=TA_DROP;
	    }
	    break;
	}
    
#undef TA_INPUT
#undef TA_OUTPUT
#undef TA_USER
#undef TA_RESPOND
#undef TA_DROP

	/*
	 * Write Results
	 */
	fprintf(fp[act], "%7.3f ", (double)((int)ntohl((u_int)rt->d[i].td_time))/1000.0 /*-origin*/ );
	fprintf(fp[act], "%3u ",  act);
	fprintf(fp[act], "%10u ", seq);         /* XXX  calculated by DBSC */
	fprintf(fp[act], "%10u ", ack);         /* XXX  calculated by DBSC */
	fprintf(fp[act], "%10u ", ntohl(rt->d[i].len));
	fprintf(fp[act], "%10u ", ntohl(rt->d[i].th_seq));
	fprintf(fp[act], "%10u ", ntohl(rt->d[i].th_ack));
	fprintf(fp[act], "  %1u%1u%1u%1u%1u%1u ",
 		(int)(0x01 & (th_flags >>5)),   /* URG */
		(int)(0x01 & (th_flags >>4)),   /* ACK */
		(int)(0x01 & (th_flags >>3)),   /* PSH */
		(int)(0x01 & (th_flags >>2)),   /* RST */
		(int)(0x01 & (th_flags >>1)),   /* SYN */
		(int)(0x01 & (th_flags >>0)));  /* FIN */
	fprintf(fp[act], "%10u ", ntohl(rt->d[i].t_state));
	fprintf(fp[act], "%10u ", ntohl(rt->d[i].t_rxtshift));
	fprintf(fp[act], "%10u ", ntohl(rt->d[i].t_rxtcur));
	fprintf(fp[act], "%10u ", ntohl(rt->d[i].t_dupacks));
	fprintf(fp[act], "%10u ", ntohl(rt->d[i].t_maxseg));
/*	fprintf(fp[act], "%10u ", ntohl(rt->d[i].t_force));*/
/*		ntohl(rt->d[i].t_flags)                    */
	fprintf(fp[act], "%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u ", 
		(int)(0x01 & (t_flags >>15)),   /* */
		(int)(0x01 & (t_flags >>14)),   /* */
		(int)(0x01 & (t_flags >>13)),   /* */
		(int)(0x01 & (t_flags >>12)),   /* */
		(int)(0x01 & (t_flags >>11)),   /* */
		(int)(0x01 & (t_flags >>10)),   /* */
		(int)(0x01 & (t_flags >> 9)),   /* TF_SACK_PERMIT */
		(int)(0x01 & (t_flags >> 8)),   /* TF_RCVD_TSTMP  */
		(int)(0x01 & (t_flags >> 7)),   /* TF_REQ_TSTMP   */
		(int)(0x01 & (t_flags >> 6)),   /* TF_RCVD_SCALE  */
		(int)(0x01 & (t_flags >> 5)),   /* TF_REQ_SCALE   */
		(int)(0x01 & (t_flags >> 4)),   /* TF_SENTFIN     */
		(int)(0x01 & (t_flags >> 3)),   /* TF_NOOPT       */
		(int)(0x01 & (t_flags >> 2)),   /* TF_NODELAY     */
		(int)(0x01 & (t_flags >> 1)),   /* TF_DELACK      */
		(int)(0x01 & (t_flags >> 0)));  /* TF_ACKNOW      */
	fprintf(fp[act], "%10u ", ntohl(rt->d[i].snd_una));
	fprintf(fp[act], "%10u ", ntohl(rt->d[i].snd_nxt));
	fprintf(fp[act], "%10u ", ntohl(rt->d[i].snd_wl1));
	fprintf(fp[act], "%10u ", ntohl(rt->d[i].snd_wl2));
	fprintf(fp[act], "%10u ", ntohl(rt->d[i].iss));
	fprintf(fp[act], "%10u ", ntohl(rt->d[i].snd_wnd));
	fprintf(fp[act], "%10u ", ntohl(rt->d[i].rcv_wnd));
	fprintf(fp[act], "%10u ", ntohl(rt->d[i].rcv_nxt));
	fprintf(fp[act], "%10u ", ntohl(rt->d[i].irs));
	fprintf(fp[act], "%10u ", ntohl(rt->d[i].rcv_adv));
	fprintf(fp[act], "%10u ", ntohl(rt->d[i].snd_max));
	fprintf(fp[act], "%10u ", ntohl(rt->d[i].snd_cwnd));
	fprintf(fp[act], "%12u ", ntohl(rt->d[i].snd_ssthresh));
	fprintf(fp[act], "%10u ", ntohl(rt->d[i].t_idle));
	fprintf(fp[act], "%10u ", ntohl(rt->d[i].t_rtt));
	fprintf(fp[act], "%10u ", ntohl(rt->d[i].t_rtseq));
	fprintf(fp[act], "%10u ", ntohl(rt->d[i].t_srtt));
	fprintf(fp[act], "%10u ", ntohl(rt->d[i].t_rttvar));
/*	fprintf(fp[act], "%10u ", ntohl(rt->d[i].t_rttmin));*/
	fprintf(fp[act], "%10u ", ntohl(rt->d[i].max_sndwnd));
	fprintf(fp[act], "\n");
    }
    
    for (i=0; i < 5; i++) {
	fclose(fp[i]);
    }

    FREE(rt->d);

    DEBUGMSG(1, "END.\n");
}

/*****************************************************************
 * Mini Subroutines
 *****************************************************************/
void init_scan_cmd(scan_cmd)
struct scan_cmd *scan_cmd;
{
    struct scan_cmd *cmd;

    for (cmd = scan_cmd; cmd; cmd = cmd->next) {
	cmd->sender.fd = -1;
	cmd->receiver.fd = -1;
    }
}

/*
 *  Deside the time that is used for origin by DBSD.
 */
void get_origin_time(origin_time)
struct timeval *origin_time;
{
    struct timeval current_time;
    struct timezone tzp;
    static struct timeval offset_time = {(int)START_TIME_OFFSET, (int)(START_TIME_OFFSET*1000000)%1000000};

    gettimeofday(&current_time, &tzp);
    timeval_cp(origin_time, &current_time);
    timeval_add(origin_time, &offset_time);

    if (debug >= 2) {
	fprintf(stderr, "Current Time = (%-12d, %-12d)\n", current_time.tv_sec, current_time.tv_usec);
	fprintf(stderr, "Offset       = (%-12d, %-12d)\n", offset_time.tv_sec,  offset_time.tv_usec);
 	fprintf(stderr, "Origin Time  = (%-12d, %-12d)\n", origin_time->tv_sec, origin_time->tv_usec);
    }
}

/*
 * TCP Connection establish for DBSC only.
 * Return value: file discripter of the Connection.
 */
int tcp_init_client(remotehost, port)
char *remotehost;
int port;
{
    struct sockaddr_in serv_addr;
    int fd;
    unsigned int tmp;

    tmp = inet_addr(remotehost);

#ifndef INADDR_NONE
#define INADDR_NONE (-1)
#endif

    if (tmp != (unsigned int) INADDR_NONE) {
	serv_addr.sin_addr.s_addr = tmp;
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_port = htons(port);
    } else {
	struct hostent *hp;
	if ((hp = gethostbyname(remotehost)) == NULL) {
	    char tmp[256];
	    sprintf(tmp, "TCP gethostbyname '%s'",remotehost);
	    perror(tmp);
	    safe_exit();
	}
	bcopy((char *)hp->h_addr, (char *)&serv_addr.sin_addr, hp->h_length);
	serv_addr.sin_family = hp->h_addrtype;
	serv_addr.sin_port = htons(port);
    }

    if ((fd = socket(serv_addr.sin_family, SOCK_STREAM, 0)) < 0) {
	perror("TCP socket");
	safe_exit();
    }

    DEBUGMSG2(1, fprintf(stderr, "Connecting to (%s).(%d).....",remotehost, port));

    alarm(30);
    if (setjmp(env_alrm) == 0) {
	if (connect(fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
	    char tmp[256];
	    sprintf(tmp, "TCP connect (%s).(%d)",remotehost, port);
	    perror(tmp);
	    safe_exit();
	}
    } else {
	    char tmp[256];
	    sprintf(tmp, "TCP connect (%s).(%d)",remotehost, port);
	    perror(tmp);
	    safe_exit();
    }
    alarm(0);
    DEBUGMSG(1, "Connected.\n");

    return fd;
}

void tcp_init_client_timeout(signo)
int signo;
{
    longjmp(env_alrm, 1);
}

/*****************************************************************
 * dbsc error routine
 *****************************************************************/
void error(cmd, sr, e, msg)
struct scan_cmd *cmd;
int sr;
int e;
char *msg;
{
    struct send_recv *p1, *p2;

    if (sr == SEND) {
	p1 = &(cmd->sender);
	p2 = &(cmd->receiver);
    } else if (sr == RECEIVE) {
	p1 = &(cmd->receiver);
	p2 = &(cmd->sender);
    } else {
	fprintf(stderr, "\nSorry! DBSC Internal Bug!!\n");
    }

    fprintf(stderr, "\n");

    fprintf(stderr, "---- Error Messages ---------------------------------------------\n");
    fprintf(stderr, "DBSC Version %d.%d%s", 
	    DBS_MAJOR_VERSION, DBS_MINOR_VERSION, DBS_PATCH_VERSION);
    fprintf(stderr, "Hostname       = %-16s  \n", p1->hostname);

    if (NORMAL <= e && e <= INTERNALERROR)
	fprintf(stderr, "\"%s\"\n", errmsg[e]);
    else
	fprintf(stderr, "error=%d\n", e);

    fprintf(stderr, "%s\n", msg);

    if (e == INTERNALERROR) {
	fprintf(stderr, "*****************************************************************\n");
	fprintf(stderr, "***    Could you send the command file, the error messages    ***\n");
        fprintf(stderr, "***    and the information about your environment             ***\n");
	fprintf(stderr, "***    to yukio-m@is.aist-nara.ac.jp?                         ***\n");
	fprintf(stderr, "*****************************************************************\n");
    }

    fprintf(stderr, "-----------------------------------------------------------------\n");
    fprintf(stderr, "Source         = %-16s  ", p1->hostname);
    fprintf(stderr, "Destination    = %-16s\n", p2->hostname);
    fprintf(stderr, "Source Port    = %-16d  ", p1->port);
    fprintf(stderr, "Dest Port      = %-16d\n", p2->port);
    fprintf(stderr, "Protocol       = %-16s\n", (cmd->transport==TCP)?"TCP":"UDP");

    switch (e) {
      case TCPNODELAY:
	fprintf(stderr, "TCP No Delay   = %-16s\n", (p1->no_delay==ON)?"ON":"OFF");
	break;
      case TCPDEBUG:
      case SODEBUG:
	fprintf(stderr, "TCP Trace      = %-16s", (p1->tcp_trace==ON)?"ON":"OFF");
	fprintf(stderr, "So Debug       = %-16s\n", (p1->so_debug==ON)?"ON":"OFF");
	break;
      case TCPMAXSEG:
	fprintf(stderr, "MSS            = %-16d  ", p1->mss);
	break;
      case SOSNDBUF:
      case SORCVBUF:
	(p1->send_buff > 0)?fprintf(stderr, "Send Buffer    = %-16d  ", p1->send_buff):0;
	(p1->recv_buff > 0)?fprintf(stderr, "Receive Buffer = %-16d\n", p1->recv_buff):0;
	break;
      case MALLOC:
	fprintf(stderr, "Total Size     = %-16d  ", cmd->total_size);
	fprintf(stderr, "Total Message  = %-16d\n", cmd->total_message);
	fprintf(stderr, "Record Buffer  = %-16d  ", p1->record_buff);
	fprintf(stderr, "Trace Buffer   = %-16d\n", p1->trace_buff);
	fprintf(stderr, "Memory Align   = %-16d  ", p1->mem_align);
	fprintf(stderr, "Align Offset   = %-16d\n", p1->align_offset);
	fprintf(stderr, "Align Pad      = %-16d\n", p1->align_pad);
	fprintf(stderr, "Traffic_N      = %-16d\n", p1->traffic_n);
	fprintf(stderr, "Send Times     = %-16d  ", cmd->send_times);
	break;
      case TIME:
      case TIMESYNC:
      case TIMEOUT:
	fprintf(stderr, "Start Time     = %-16f  ", (double)cmd->start_time.tv_sec+(double)cmd->start_time.tv_usec/(1000.0*1000.0));
	fprintf(stderr, "End time       = %-16f\n", (double)cmd->end_time.tv_sec  +(double)cmd->end_time.tv_usec/(1000.0*1000.0));
	break;
      case CONNECT:
      case ACCESSDENY:
	fprintf(stderr, "Server flag    = %-16s  ", (cmd->serverflg==SERVER)?"SERVER":"CLIENT");
	fprintf(stderr, "Connection Mode= %-16s\n", (cmd->connection_mode==AFTER)?"AFTER":"BEFORE");
	break;
    }

    fprintf(stderr, "-----------------------------------------------------------------\n");
}

/*****************************************************************
 * Signal Handlers
 *****************************************************************/
#define CLOSE(FD) if((FD)!=-1 && close(FD)!=-1){shutdown(FD, 1+1);}

void tcp_terminate(fd)
int fd;
{
    if (fd != -1) {
	char dummy[8];

	DEBUGMSG(0, "*");
	send(fd, dummy, 8, MSG_OOB);
	CLOSE(fd);
    } else {
	DEBUGMSG(0, "-");
    }
}

void safe_exit()
{
    extern struct scan_cmd *scan_cmd;
    struct scan_cmd *cmd;
    struct timeval origin_time;
    SIGNAL_INIT;

    DEBUGMSG(0, "DBSC: Stopping process");

    BEGIN_CRITICAL_REGION;

    sleep(1);
    DEBUGMSG(0, ".");
    sleep(1);
    DEBUGMSG(0, ".");

    if (scan_cmd != (struct scan_cmd *)NULL) {
	for (cmd = scan_cmd; cmd; cmd = cmd->next) {
	    tcp_terminate(cmd->sender.fd);
	    tcp_terminate(cmd->receiver.fd);
	}
    }
    DEBUGMSG(0, "\n");
    DEBUGMSG(1, "DBSC is stoped.\n");
    END_CRITICAL_REGION;

    exit(1);
}

#undef TCP_SHUTDOWN

/*
 * Signal Handler for SIGINIT
 */
void safe_exit1(signo)
int signo;
{
    DEBUGMSG(1, "Interrupting");
    DEBUGMSG(0, "\n");
    safe_exit();
}

/*
 * Signal Handler for SIGPIP
 */
void safe_exit2(signo)
int signo;
{
    DEBUGMSG(1, "Pipe is Broken");
    DEBUGMSG(0, "\n");
    safe_exit();
}

/*
 * Help Message
 */
void help(prog)
char *prog;
{
    fprintf(stderr, "DBS Version %d.%d%s  by yukio-m@is.aist-nara.ac.jp\n", DBS_MAJOR_VERSION, DBS_MINOR_VERSION, DBS_PATCH_VERSION);
    fprintf(stderr, "Usage: %s [-p port_number] [-v] [-d] command_file\n", prog);
}


syntax highlighted by Code2HTML, v. 0.9.1