/***************************************************************************
 * 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 Header File
 * $Revision: 1.25 $
 * $Date: 1997/05/09 05:12:03 $
 * $Author: yukio-m $
 *****************************************************************/

#include <stdio.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <signal.h>
#include <setjmp.h>
#include <errno.h>
#include <string.h>
#include <sys/resource.h>
#include <sys/wait.h>

#include "dbs.h"
#include "dbsd.h"
#include "record.h"

#define INIT_RECORD()  (rdp = rd->d, rd->n=0)
#define INIT_RECORD2() (rdp2 = rd2->d, rd2->n=0)

#define RECORD(NO,SIZE) (gettimeofday(&(rdp->tv), (struct timezone *)&tzp),\
			 rdp->packet_no   = (NO),\
			 rdp->packet_size = (SIZE),\
			 rdp++, rd->n++)

#define RECORD2(NO,SIZE) (gettimeofday(&(rdp2->tv), (struct timezone *)&tzp),\
			  rdp2->packet_no   = (NO),\
			  rdp2->packet_size = (SIZE),\
			  rdp2++, rd2->n++)

#define TIMEVAL_ADD(_TP1, _TP2) _TP1.tv_sec  += _TP2.tv_sec;\
				_TP1.tv_usec += _TP2.tv_usec;\
				if (_TP1.tv_usec>=1000000) {\
				    _TP1.tv_sec+=_TP1.tv_usec/1000000;\
				    _TP1.tv_usec %= 1000000;\
				}

#define GETTIMEOFDAY(_TPP) gettimeofday(&tp, (struct timezone *)&tzp);\
                           tp.tv_sec  = _TPP.tv_sec  - tp.tv_sec;\
                           tp.tv_usec = _TPP.tv_usec - tp.tv_usec;\
                           if (tp.tv_usec < 0) {\
                               tp.tv_usec += 1000000;\
                               tp.tv_sec--;\
                           }

#define USLEEP0(_SLEEP_) \
                select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, (&(_SLEEP_)))

#define USLEEP(_SLEEP_) \
                (((_SLEEP_.tv_sec)>=0 && (_SLEEP_.tv_usec>=0))?(select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, (&(_SLEEP_)))):(1))

#define USLEEP2(_SLEEP_, _SLEEP_FLAG_) \
                ((_SLEEP_FLAG_==1)?(select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, (&(_SLEEP_)))):(1))

#define WAIT_AT(_TPP) GETTIMEOFDAY(_TPP);\
	              USLEEP(tp);

/* before 0.00001s */
#define WAIT_BEFORE(_TPP) gettimeofday(&tp, (struct timezone *) &tzp);\
                          tp.tv_sec  = _TPP.tv_sec  - tp.tv_sec;\
                          tp.tv_usec = _TPP.tv_usec - tp.tv_usec - 1000;\
                          if (tp.tv_usec < 0) {\
                              tp.tv_usec += 1000000;\
	                      tp.tv_sec--;\
		          }\
	                  USLEEP(tp);

#define WAIT_UNTIL(_TPU) GETTIMEOFDAY(_TPU);\
    DEBUGMSG2(3, fprintf(stderr, "A (%12d %12d)\n", tp.tv_sec, tp.tv_usec));\
                         while (tp.tv_sec>=0 && tp.tv_usec>=0) {\
                             USLEEP0(tp);\
                             GETTIMEOFDAY(_TPU);\
    DEBUGMSG2(3, fprintf(stderr, "A (%12d %12d)\n", tp.tv_sec, tp.tv_usec));\
			 }\
    DEBUGMSG2(3, fprintf(stderr, "A (%12d %12d)\n", tp.tv_sec, tp.tv_usec));

#define WAIT_AT2(_TPP, _TPI, _WAIT_FLAG_) if (_WAIT_FLAG_ == 1) {\
					      TIMEVAL_ADD(_TPP, _TPI);\
                                              GETTIMEOFDAY(_TPP);\
	                                      USLEEP(tp);\
					  }

static void udp_receive_timeout __P((int signo));
static void udp_send_timeout    __P((int signo));
static void tcp_receive_timeout __P((int signo));
static void tcp_send_timeout    __P((int signo));

void wait_at             __P((struct timeval *tpp));
void alarm_at            __P((struct timeval *tpp));

static sigjmp_buf env_alrm;

static struct record_d *rdp;
static struct record_d *rdp2;

/************************************************************
 * TCP SEND 
 ************************************************************/
int tcp_send(cmd, data, rd, rd2, rt)
struct dbsd_param * volatile cmd;
char *data;
struct record *rd;
struct record *rd2;
struct tcp_trace * volatile rt;
{
    static struct timeval tp;
    struct timezone volatile tzp;
    struct timeval esleep;
    int i, j, s, offset, rest;
    int total=0; /* Total Size of sended data */
    struct dbsd_traffic *traffic = cmd->traffic;
    int volatile timeout_flg = OFF;
    int volatile connect_flg = OFF;

    /* These are to avoid the optimization with the SPARC CPU's register window. */
    struct dbsd_param * volatile * tmp  = &cmd;
    struct tcp_trace  * volatile * tmp2 = &rt;
    int volatile * tmp3 = & connect_flg;
    int volatile * tmp4 = & timeout_flg;
    struct timezone  volatile * tmp5 = & tzp;

    DEBUGMSG(2, "TCP_SEND: Start.\n");

    if (sigsetjmp(env_alrm, 0) == 0) {

	/*
	 * Initialization
	 */

	if (signal(SIGALRM, tcp_send_timeout) == SIG_ERR)
	    safe_exit(SIGNAL, "TCP_SEND.signal(SIGALRM)", strerror(errno));
    
	INIT_RECORD();
	INIT_RECORD2();
	timeval_cp(&esleep, &cmd->start_time);

	alarm_at(&cmd->end_time);

        /*
         * Connection Establish
         */

	if (cmd->connection_mode == AFTER) {
	    if (cmd->serverflg == SERVER) {
		int d_len = sizeof(cmd->d_address);
		
		if ((cmd->fd = accept(cmd->sockfd, (struct sockaddr *)&cmd->d_address, &d_len)) < 0)
		    safe_exit(ACCEPT, "TCP_SEND.accept", strerror(errno));

		RECORD2(0,0);
		connect_flg = ON;

		setaddr(cmd->fd, &cmd->assosiation);
		close(cmd->sockfd);
		
		if (cmd->tcp_trace == ON) {
		    init_so_debug(rt, &cmd->assosiation, TA_INPUT, cmd->connection_mode);
		    DEBUGMSG(3, "INIT_SO_DEBUG: Normal END\n");
		}
	    } else if (cmd->serverflg == CLIENT) {

		WAIT_BEFORE(cmd->start_time);
		WAIT_AT(cmd->start_time);

/*		WAIT_UNTIL(cmd->start_time);*/

		alarm_at(&cmd->end_time);

		RECORD2(0,0);
		if (connect(cmd->fd, (struct sockaddr *)&cmd->d_address, sizeof(cmd->d_address)) < 0) {
		    DEBUGMSG2(1, perror("connect"));
		    safe_exit(CONNECT, "TCP_SEND.connect", strerror(errno));
		}

		RECORD2(0,0);
		connect_flg = ON;

		setaddr(cmd->fd, &cmd->assosiation);

		if (cmd->tcp_trace == ON) {
		    init_so_debug(rt, &cmd->assosiation, TA_OUTPUT, cmd->connection_mode);
		    DEBUGMSG(3, "INIT_SO_DEBUG: Normal END\n");
		}
	    } else {
		DEBUGMSG(1, "DBSD: tcp_send error\n");
		safe_exit(INTERNALERROR, "TCP_SEND", "");
	    }
	} else {
	    connect_flg = ON;

	    WAIT_BEFORE(cmd->start_time);
	    WAIT_AT(cmd->start_time);

/*	    WAIT_UNTIL(cmd->start_time);*/
	    alarm_at(&cmd->end_time);
	}

        /*
         * Send Main Loop
         */

	if (cmd->traffic_n == 1 && traffic->size == traffic->packet && 
	    traffic->isleep_flag == 0 && traffic->esleep_flag == 0) {
	    if (cmd->tcp_trace != ON) {
		s = traffic[0].size;
		for (j=1; j <= cmd->send_times; j++) {
		    if (send(cmd->fd, data, s, 0) != s)
			goto send_end;
		    RECORD(total, s);
		    total += s;
		}
	    } else {
		s = traffic[0].size;
		for (j=1; j <= cmd->send_times; j++) {
		    if (send(cmd->fd, data, s, 0) != s)
			goto send_end;
		    RECORD(total, s);
		    total += s;
		    record_tcp_trace(rt, &cmd->assosiation, TA_OUTPUT);
		}
	    }
	} else {
	    for (j=1; j <= cmd->send_times; j++) {
		for (i=0, traffic=cmd->traffic; i < cmd->traffic_n; i++, traffic++) {
		    for (offset=0, rest=traffic->size; rest > 0; offset+=traffic->packet, rest-=traffic->packet) {
			s = MIN(traffic->packet, rest);
			if (send(cmd->fd, data + offset, s, 0) != traffic->packet)
			    goto send_end;         /* ? */
			RECORD(total, s);
			total += s;
			if (cmd->tcp_trace == ON)
			    record_tcp_trace(rt, &cmd->assosiation, TA_OUTPUT);
		    }
		    USLEEP2(traffic->isleep, traffic->isleep_flag);
		    WAIT_AT2(esleep, traffic->esleep, traffic->esleep_flag);
		}
	    }
	}
    } else {
	DEBUGMSG(1, "*Time Out!*\n");
	timeout_flg = ON;
    }

  send_end:    

    /*
     * Data Transfer End
     */

    if (connect_flg == OFF) {
	DEBUGMSG(1, "DBSD: connection error\n");
	safe_exit(ABNORMAL, "Connection Error.", "");
    }

    if (cmd->connection_mode == AFTER && timeout_flg == OFF) {
	RECORD2(0,0);
	close(cmd->fd);
	RECORD2(0,0);
    }

    alarm(0);
    wait_at(&cmd->end_time);
    sleep(END_TIME_OFFSET1);

    if (cmd->tcp_trace == ON) {
	if (cmd->connection_mode == BEFORE)
	    record_tcp_trace2(rt, &cmd->assosiation, TA_OUTPUT);
	else
	    record_tcp_trace(rt, &cmd->assosiation, TA_OUTPUT);
    } else if (cmd->tcp_trace == AFTER) {
	if (cmd->serverflg == CLIENT)
	    init_so_debug(rt, &cmd->assosiation, TA_OUTPUT, cmd->connection_mode);
	else
	    init_so_debug(rt, &cmd->assosiation, TA_INPUT, cmd->connection_mode);

	record_tcp_trace(rt, &cmd->assosiation, TA_OUTPUT);
    }

    if (cmd->connection_mode == BEFORE || timeout_flg == ON) {
	if (cmd->serverflg == SERVER)
	    sleep(END_TIME_OFFSET2);
	close(cmd->fd);
    }
    DEBUGMSG(2, "TCP_SEND: Now END.\n");

    return timeout_flg;
}

/************************************************************
 * TCP RECEIVE
 ************************************************************/
int tcp_recv(cmd, data, rd, rd2, rt)
struct dbsd_param * volatile cmd;
char *data;
struct record *rd;
struct record *rd2;
struct tcp_trace * volatile rt;
{
    static struct timeval tp;
    struct timezone tzp;
    struct timeval esleep;
    int i, rest, offset, o, r, rr, total_rest, s;
    int total=0; /* Total Size of sended data */
    struct dbsd_traffic *traffic = cmd->traffic;
    int volatile timeout_flg = OFF;
    int volatile connect_flg = OFF;

    /* These are to avoid the optimization with the SPARC CPU's register window. */
    struct dbsd_param * volatile * tmp  = &cmd;
    struct tcp_trace  * volatile * tmp2 = &rt;
    int volatile * tmp3 = & connect_flg;
    int volatile * tmp4 = & timeout_flg;
    struct timezone  volatile * tmp5 = & tzp;

    DEBUGMSG(2, "TCP_RECV: Start.\n");

    if (sigsetjmp(env_alrm, 0) == 0) {

	/*
	 * Initialization
	 */

	if (signal(SIGALRM, tcp_receive_timeout) == SIG_ERR)
	    safe_exit(SIGNAL, "TCP_RECEIVE.signal(SIGALRM)", strerror(errno));

	total_rest = cmd->total_size;

	INIT_RECORD();
	INIT_RECORD2();
	timeval_cp(&esleep, &cmd->start_time);


	WAIT_BEFORE(cmd->start_time);
	WAIT_AT(cmd->start_time);

/*	WAIT_UNTIL(cmd->start_time);*/

	alarm_at(&cmd->end_time);

        /*
         * Connection Establish
         */

	if (cmd->connection_mode == AFTER) {
	    if (cmd->serverflg == SERVER) {
		int d_len = sizeof(cmd->d_address);

		if ((cmd->fd = accept(cmd->sockfd, (struct sockaddr *)&cmd->d_address, &d_len)) < 0) {
		    DEBUGMSG2(1, perror("accept"));
		    safe_exit(ACCEPT, "TCP_RECEIVE.accept", strerror(errno));
		}
		RECORD2(0,0);
		connect_flg = ON;

		setaddr(cmd->fd, &cmd->assosiation);
		close(cmd->sockfd);

		if (cmd->tcp_trace == ON) {
		    init_so_debug(rt, &cmd->assosiation, TA_INPUT, cmd->connection_mode);
		    DEBUGMSG(3, "INIT_SO_DEBUG: Normal END\n");
		}
	    } else if (cmd->serverflg == CLIENT) {
		RECORD2(0,0);
		if (connect(cmd->fd, (struct sockaddr *)&cmd->d_address, sizeof(cmd->d_address)) < 0) {
		    DEBUGMSG2(1, perror("connect"));
		    safe_exit(CONNECT, "TCP_RECEIVE.connect", strerror(errno));
		}
		RECORD2(0,0);
		connect_flg = ON;

		setaddr(cmd->fd, &cmd->assosiation);
		
		if (cmd->tcp_trace == ON) {
		    init_so_debug(rt, &cmd->assosiation, TA_OUTPUT, cmd->connection_mode);
		    DEBUGMSG(3, "INIT_SO_DEBUG: Normal END\n");
		}
	    } else {
		safe_exit(INTERNALERROR,"TCP_RECEIVE.serverflg", "");
	    }
	} else {
	    connect_flg = ON;
	}

	/*
	 * Receive Main Loop
	 */

	if (cmd->recv_mode == PACKET) {
	    if (cmd->traffic_n == 1 && traffic->size == traffic->packet && 
		traffic->isleep_flag == 0 && traffic->esleep_flag == 0) {
		if (cmd->tcp_trace != ON) {		
		    while (total_rest > 0) {
			o = 0;
			rr = r = traffic[0].packet;
			while (r > 0) {
			    if ((s=recv(cmd->fd, data, r, 0)) < 0)
				safe_exit(RECVERROR, "TCP_RECEIVE.recv", strerror(errno));
			    r -= s;
			    o += s;
			}
			
			RECORD(total, rr);
			total      += rr;
			rest       -= rr;
			total_rest -= rr;
		    }
		} else {
		    while (total_rest > 0) {
			o = 0;
			rr = r = traffic[0].packet;
			while (r > 0) {
			    if ((s=recv(cmd->fd, data, r, 0)) < 0)
				safe_exit(RECVERROR, "TCP_RECEIVE.recv", strerror(errno));

			    r -= s;
			    o += s;
			}
			RECORD(total, rr);
			total      += rr;
			rest       -= rr;
			total_rest -= rr;
			record_tcp_trace(rt, &cmd->assosiation, TA_OUTPUT);
		    }
		}
	    } else {
		while (total_rest > 0) {
		    for (i=0, traffic=cmd->traffic; i < cmd->traffic_n; i++, traffic++) {
			for (offset=0, rest=traffic->size; rest > 0; offset+=traffic->packet, rest-=traffic->packet) {
			    rr = r = MIN(traffic->packet, rest);
			    rr = r = MIN(total_rest, r);
			
			    o = 0;
			    while (r > 0) {
				if ((s=recv(cmd->fd, data + offset + o, r, 0)) < 0)
				    safe_exit(RECVERROR, "TCP_RECEIVE.recv", strerror(errno));

				r -= s;
				o += s;
			    }

			    RECORD(total, rr);
			    total      += rr;
			    rest       -= rr;
			    total_rest -= rr;
			    
			    if (cmd->tcp_trace == ON)
				record_tcp_trace(rt, &cmd->assosiation, TA_OUTPUT);
			    
			    if (total_rest <= 0)
				goto recv_end; /* Exit All Loop */
			}
			USLEEP2(traffic->isleep, traffic->isleep_flag);
			WAIT_AT2(esleep, traffic->esleep, traffic->esleep_flag);
		    }
		}
	    }
	} else {
	    if (traffic->isleep_flag == 0 && traffic->esleep_flag == 0) {
		if (cmd->tcp_trace != ON) {		
		    i=0;
		    total = 0;
		    while (total_rest > 0) {
			if ((s=recv(cmd->fd, data, traffic[0].size, 0)) < 0)
			    safe_exit(RECVERROR, "TCP_RECEIVE.recv", strerror(errno));

			if (i < rd->size) {
			    RECORD(total, s);
			    i++;
			}

			total_rest -= s;
			total += s;
		    }
		} else {
		    i=0;
		    total = 0;
		    while (total_rest > 0) {
			if ((s=recv(cmd->fd, data, traffic[0].size, 0)) < 0)
			    safe_exit(RECVERROR, "TCP_RECEIVE.recv", strerror(errno));

			if (i < rd->size) {
			    RECORD(total, s);
			    i++;
			}

			total_rest -= s;
			total += s;

			record_tcp_trace(rt, &cmd->assosiation, TA_OUTPUT);
		    }
		}
	    } else {
		i=0;
		total = 0;
		while (total_rest > 0) {
		    if ((s=recv(cmd->fd, data, traffic[0].size, 0)) < 0)
			safe_exit(RECVERROR, "TCP_RECEIVE.recv", strerror(errno));

		    if (i < rd->size) {
			RECORD(total, s);
			i++;
		    }
		    
		    total_rest -= s;
		    total += s;
		    
		    if(cmd->tcp_trace == ON)
			record_tcp_trace(rt, &cmd->assosiation, TA_OUTPUT);
		    
		    USLEEP2(traffic->isleep, traffic->isleep_flag);
		    WAIT_AT2(esleep, traffic->esleep, traffic->esleep_flag);
		}
	    }
	}
    }
    else {
        DEBUGMSG(1, "*Time Out!*\n");
	timeout_flg = ON;
    }

  recv_end:

    /*
     * Data Transfer End
     */

    if (connect_flg == OFF)
	safe_exit(ABNORMAL, "Connection Error.", "");

    if (cmd->connection_mode == AFTER && timeout_flg == OFF) {
	RECORD2(0,0);
	close(cmd->fd);
	RECORD2(0,0);
    }

    alarm(0);
    wait_at(&cmd->end_time);
    sleep(END_TIME_OFFSET1);

    if (cmd->tcp_trace == ON) {
	if (cmd->connection_mode == BEFORE)
	    record_tcp_trace2(rt, &cmd->assosiation, TA_OUTPUT);
	else
	    record_tcp_trace(rt, &cmd->assosiation, TA_OUTPUT);
    } else if (cmd->tcp_trace == AFTER) {
	if (cmd->serverflg == CLIENT)
	    init_so_debug(rt, &cmd->assosiation, TA_OUTPUT, cmd->connection_mode);
	else
	    init_so_debug(rt, &cmd->assosiation, TA_INPUT, cmd->connection_mode);

	record_tcp_trace(rt, &cmd->assosiation, TA_OUTPUT);
    }

    if (cmd->connection_mode == BEFORE || timeout_flg == ON) {
	if (cmd->serverflg == SERVER)
	    sleep(END_TIME_OFFSET2);
	close(cmd->fd);
    }
    DEBUGMSG(2, "TCP_RECV: Now END.\n");

    return timeout_flg;
}

/************************************************************
 * UDP SEND
 ************************************************************/
int udp_send(cmd, data, rd)
struct dbsd_param * volatile cmd;
char *data;
struct record *rd;
{
    static struct timeval tp;
    struct timezone tzp;
    struct timeval esleep;
    int s, i, j;
    int total=0;        /* Total Size of sended data */
    int rest, offset;
    struct dbsd_traffic *traffic = cmd->traffic;
    char *d;
    struct sockaddr *dest;
    int length;
    int volatile timeout_flg = OFF;

    /* These are to avoid the optimization with the SPARC CPU's register window. */
    struct dbsd_param * volatile * tmp = &cmd;   /* to allocate cmd to memory */
    int volatile * tmp4 = &timeout_flg;
    
    DEBUGMSG(2, "UDP_SEND: Start.\n");

    if (sigsetjmp(env_alrm, 0) == 0) {

	/*
	 * Initialization
	 */

	if (signal(SIGALRM, udp_send_timeout) == SIG_ERR)
	    safe_exit(SIGNAL, "UDP_SEND.signal(SIGALRM)", strerror(errno));
    
	INIT_RECORD();
	timeval_cp(&esleep, &cmd->start_time);

	dest = (struct sockaddr *)&cmd->d_address;
	length = sizeof(cmd->d_address);

	WAIT_BEFORE(cmd->start_time);
	WAIT_AT(cmd->start_time);

	/* WAIT_UNTIL(cmd->start_time); */

	alarm_at(&cmd->end_time);

	/*
	 * Send Main Loop
	 */

	for (j=1; j<=cmd->send_times; j++) {
	    for (i=0, traffic=cmd->traffic; i < cmd->traffic_n; i++, traffic++) {
		offset = 0;
		rest   = traffic->size;
		while (1) {
		    d = data + offset;
		    *((unsigned int *)d) = htonl(total); /* XXX UDP Packet must larger than sizeof(int), 4byte*/

		    while ((s = sendto(cmd->fd, d, MIN(traffic->packet, rest), 0, dest, length)) < 0)
			/* NULL */;

		    RECORD(total, traffic->packet);

		    total  += traffic->packet;
		    rest   -= traffic->packet;
		    offset += traffic->packet;
		    
		    if(rest <= 3)                     /* XXX */
			break;
		}
		USLEEP2(traffic->isleep, traffic->isleep_flag);
		WAIT_AT2(esleep, traffic->esleep, traffic->esleep_flag);
	    }
	}
    } else {
	timeout_flg = ON;
	DEBUGMSG(1, "*Time Out!*\n");
    }

    /*
     * Data Transfer End.
     */

    alarm(0);
    wait_at(&cmd->end_time);
    sleep(END_TIME_OFFSET1);
    DEBUGMSG(2, "UDP_SEND: Now END.\n");

    return timeout_flg;
}

/************************************************************
 * UDP RECEIVE
 ************************************************************/
int udp_recv(cmd, data, rd)
struct dbsd_param * volatile cmd;
char *data;
struct record *rd;
{
    static struct timeval tp;
    struct timezone tzp;
    struct timeval esleep;
    int i, length, offset, rest, r;
    int total_rest;
    struct dbsd_traffic *traffic = cmd->traffic;
    struct sockaddr *dest;
    int size;
    int volatile ii=0;
    int volatile timeout_flg = OFF;

    /* These are to avoid the optimization with the SPARC CPU's register window. */
    struct dbsd_param * volatile *tmp = &cmd;   /* to allocate cmd to memory */
    int volatile * tmp4 = & timeout_flg;

    DEBUGMSG(2, "UDP_RECV: Start.\n");

    if (sigsetjmp(env_alrm, 0) == 0) {

	/*
	 * Initialization
	 */

	if (signal(SIGALRM, udp_receive_timeout) == SIG_ERR)
	    safe_exit(SIGNAL, "UDP_RECEIVE.signal(SIGALRM)", strerror(errno));

	dest = (struct sockaddr *)&cmd->d_address;
	length=sizeof(cmd->d_address);
	
	total_rest = (unsigned long)cmd->total_size;
	
	INIT_RECORD();
	timeval_cp(&esleep, &cmd->start_time);

	alarm_at(&cmd->end_time);

	/*
	 * Receive Main Loop
	 */

	while (total_rest > 0) {
	    for (i=0; i < cmd->traffic_n; i++) {
		for (offset=0, rest=traffic->size; rest > 0; offset+=traffic->packet, rest-=traffic->packet) {
		    if ((r = (int)recvfrom(cmd->fd, (char *)data + offset, traffic->packet, 0, dest, &length)) < 0)
			safe_exit(RECVFROM, "UDP_RECEIVE.recvfrom", strerror(errno));

		    RECORD(ntohl(*((unsigned int *)((char *)data + offset))), r);
		    ii++;

		    total_rest -= r;
		}
		USLEEP2(traffic->isleep, traffic->isleep_flag);
		WAIT_AT2(esleep, traffic->esleep, traffic->esleep_flag);
	    }
	}
    } else {
/*	timeout_flg = ON;                        XXX */
/*	DEBUGMSG(1, "*Time Out!*\n");            XXX */
    }

    /*
     * Data Transfer End.
     */

    alarm(0);
    wait_at(&cmd->end_time);
    sleep(END_TIME_OFFSET1);
    DEBUGMSG2(1, fprintf(stderr, "RECEIVE PACKET=%d\n", ii));
    DEBUGMSG(2, "UDP_RECV: Now END.\n");

    return timeout_flg;
}

/*****************************************************************
 * Signal Handlers
 *****************************************************************/
static void tcp_send_timeout(signo)
int signo;
{
    siglongjmp(env_alrm, 1);
}

static void tcp_receive_timeout(signo)
int signo;
{
    siglongjmp(env_alrm, 1);
}

static void udp_send_timeout(signo)
int signo;
{
    siglongjmp(env_alrm, 1);
}

static void udp_receive_timeout(signo)
int signo;
{
    siglongjmp(env_alrm, 1);
}

/*****************************************************************
 * Timer Subroutine
 *****************************************************************/

/*
 * wait at the timeval
 */
void wait_at(tpp)
struct timeval *tpp;
{
    static struct timeval tp;
    static struct timezone tzp;
    
    if (debug >= 3) {
	gettimeofday(&tp, &tzp);

	fprintf(stderr, "Current Time (%12d %12d)\n", tp.tv_sec, tp.tv_usec);
	fprintf(stderr, "Sleep To     (%12d %12d)\n", tpp->tv_sec, tpp->tv_usec);    

	tp.tv_sec  = tpp->tv_sec  - tp.tv_sec;
	tp.tv_usec = tpp->tv_usec - tp.tv_usec;
	if (tp.tv_usec < 0) {
	    tp.tv_usec += 1000000;
	    tp.tv_sec--;
	}
	fprintf(stderr, "Sleep Time   (%12d %12d)\n", tp.tv_sec, tp.tv_usec);    
	USLEEP(tp);

	gettimeofday(&tp, &tzp);
	fprintf(stderr, "Waked Up At  (%12d %12d)\n", tp.tv_sec, tp.tv_usec);
    } else {
	gettimeofday(&tp, &tzp);

	tp.tv_sec  = tpp->tv_sec  - tp.tv_sec;
	tp.tv_usec = tpp->tv_usec - tp.tv_usec;

	if (tp.tv_usec < 0) {
	    tp.tv_usec += 1000000;
	    tp.tv_sec--;
	}
	USLEEP(tp);
    }
}

/*
 * alarm set at the timeval
 */
void alarm_at(tpp)
struct timeval *tpp;
{
    static struct timeval tp;
    static struct timezone tzp;

    gettimeofday(&tp, &tzp);
	
    DEBUGMSG2(3, fprintf(stderr, "Current Time (%12d %12d)\n", tp.tv_sec, tp.tv_usec));

    tp.tv_sec  = tpp->tv_sec  - tp.tv_sec;
    tp.tv_usec = tpp->tv_usec - tp.tv_usec;
	
    if (tp.tv_usec < 0) {
	tp.tv_usec += 1000000;
	tp.tv_sec--;
    }
    DEBUGMSG2(3, fprintf(stderr, "Alarm Set    (%12d %12d)\n", tpp->tv_sec, tpp->tv_usec));
	
    if (tp.tv_sec >= 0) {
	alarm(tp.tv_sec + 1);
    }
}


syntax highlighted by Code2HTML, v. 0.9.1