/***************************************************************************
 * 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
 * Network Subroutines
 * $Revision: 1.18 $
 * $Date: 1997/07/11 00:54:07 $
 * $Author: yukio-m $
 *****************************************************************/

#ifdef __linux__
#include <endian.h>
#else
#if !defined(sun) && !defined(mips) && !defined(ultrix) && !defined(__hpux)
#include <machine/endian.h>
#endif
#endif

/*#define _SOCKADDR_LEN*/

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/time.h>
#include <errno.h>
#include "dbs.h"
#include "dbsd.h"

#define ASSOSIATION_DEBUG {\
			       int sp, dp, sa, da;\
			       sa=(int)ntohl(a->source_address);\
			       sp=(int)ntohs(a->source_port);\
			       da=(int)ntohl(a->dest_address);\
			       dp=(int)ntohs(a->dest_port);\
			       fprintf(stderr,"ASSOSIATION:(%3d.%3d.%3d.%3d, %3d.%3d.%3d.%3d)(%5d,%5d)\n",\
				       GET_IP_ADDR(sa,4), GET_IP_ADDR(sa,3), GET_IP_ADDR(sa,2), GET_IP_ADDR(sa,1),\
				       GET_IP_ADDR(da,4), GET_IP_ADDR(da,3), GET_IP_ADDR(da,2), GET_IP_ADDR(da,1),\
				       sp,dp);\
		       }

void getaddr_sub __P((char *hostname, int port, struct sockaddr_in *address));
void socket_opt  __P((int fd, struct dbsd_param *cmd));

/****************************************************************
 * Address resolution Subroutine
 ****************************************************************/
/*
 * Get Address Subroutine
 *
 * {hostname, port} ->  (struct sockaddr_in *)address 
 */
void getaddr_sub(hostname, port, address)
char *hostname;
int port;
struct sockaddr_in *address;
{
    unsigned int tmp;
    struct hostent *hp;
    
#ifndef INADDR_NONE
#define INADDR_NONE (-1)
#endif

    address->sin_family = AF_INET;
    address->sin_port   = htons((short)port);

    if (strcmp(hostname,"") == 0) {
	address->sin_addr.s_addr = htonl(INADDR_ANY);
    } else {
	tmp = inet_addr(hostname);
	if(tmp != (unsigned long) INADDR_NONE){
	    address->sin_addr.s_addr = tmp;
	} else {
	    if ((hp = gethostbyname(hostname)) == NULL) {
		char tmp[512];
		sprintf(tmp, "gethostbyname \"%s\"", hostname); 
		DEBUGMSG2(1, perror("gethostbyname"));
		safe_exit(GETHOSTBYNAME, tmp, strerror(errno));
	    }
	    bcopy((char *)hp->h_addr, (char *)&address->sin_addr, hp->h_length);
	}
    }
}

/*
 * Get Address Subroutine
 *
 * Set (struct sockaddr_in *)address 
 */
void getaddr(a, d_address, b_address)
struct assosiation *a;
struct sockaddr_in *d_address;
struct sockaddr_in *b_address;
{
    bzero((char *)d_address, sizeof(*d_address));
    bzero((char *)b_address, sizeof(*b_address));

    getaddr_sub(a->dsthostname, (int)a->dest_port, d_address);
    getaddr_sub(a->srchostname, (int)a->source_port, b_address);
}

/*
 * Set Address
 *
 * File Descripter -> (struct assosiation *)
 */
void setaddr(fd, a)
int fd;
struct assosiation *a;
{
    struct sockaddr_in dest;
    struct sockaddr_in source;
    int len;

    len = sizeof (dest);
    getpeername(fd, (struct sockaddr *) &dest, &len);

    len = sizeof (source);
    getsockname(fd, (struct sockaddr *) &source, &len);

    a->source_address = source.sin_addr.s_addr;
    a->source_port    = source.sin_port;
    a->dest_address   = dest.sin_addr.s_addr;
    a->dest_port      = dest.sin_port;

    DEBUGMSG2(5, ASSOSIATION_DEBUG);
}


/*****************************************************************
 *  TCP Initialization Server
 *
 *  Return Value:  file descripter
 *****************************************************************/
int tcp_init_server(a, cmd)
struct assosiation *a;
struct dbsd_param *cmd;
{
    getaddr(a, &cmd->d_address, &cmd->b_address);

    if ((cmd->sockfd = socket(cmd->d_address.sin_family, SOCK_STREAM, 0)) <0)
	safe_exit(SOCKET, "TCP SERVER socket", strerror(errno));

    if (bind(cmd->sockfd, (struct sockaddr *)&cmd->b_address, sizeof(cmd->b_address)) < 0)
	safe_exit(BIND, "TCP SERVER bind", strerror(errno));

    socket_opt(cmd->sockfd, cmd);
    
    listen(cmd->sockfd, 1);

    return 0;
}

/*
 *  TCP Initialization Server2
 *  
 *  Connection_mode == BEFORE
 */
int tcp_init_server2(a, cmd)
struct assosiation *a;
struct dbsd_param *cmd;
{
    if (cmd->connection_mode == BEFORE) {
	int d_len = sizeof(cmd->d_address);

	DEBUGMSG2(2, fprintf(stderr, "Wait Connection from (%s).(%d).....",
			      a->dsthostname, (int)ntohs(cmd->d_address.sin_port)));

	if ((cmd->fd = accept(cmd->sockfd, (struct sockaddr *)&cmd->d_address, &d_len)) < 0)
	    safe_exit(ACCEPT, "TCP SERVER accept", strerror(errno));

	DEBUGMSG(2, "Accepted.\n");

	setaddr(cmd->fd, a);

	close(cmd->sockfd);
	return cmd->fd;
    }

    return 0;
}

/*****************************************************************
 *  TCP Initialization Client
 *
 *  Return Value:  file descripter
 *****************************************************************/
int tcp_init_client(a, cmd)
struct assosiation *a;
struct dbsd_param  *cmd;
{
    DEBUGMSG(2, "TCP_INIT_CLIENT: ");

    getaddr(a, &cmd->d_address, &cmd->b_address);

    if ((cmd->fd = socket(cmd->d_address.sin_family, SOCK_STREAM, 0)) <0)
	safe_exit(SOCKET, "TCP CLIENT socket", strerror(errno));

    if (bind(cmd->fd, (struct sockaddr *)&cmd->b_address, sizeof(cmd->b_address)) < 0)
	safe_exit(BIND, "TCP CLIENT bind", strerror(errno));

    socket_opt(cmd->fd, cmd);

    if (cmd->connection_mode == BEFORE) {
	DEBUGMSG2(2, fprintf(stderr, "Connecting to (%s).(%u).....",
			     a->dsthostname, (int)ntohs(cmd->d_address.sin_port)));

	if (connect(cmd->fd, (struct sockaddr *)&cmd->d_address, sizeof(cmd->d_address)) < 0)
	    safe_exit(CONNECT, "TCP CLIENT connect", strerror(errno));

	DEBUGMSG(2, "Connected.\n");
	setaddr(cmd->fd, a);
	return cmd->fd;
    }

    return 0;
}

/*****************************************************************
 * UDP Initialization
 *****************************************************************/
int udp_init(a, cmd)
struct assosiation *a;
struct dbsd_param *cmd;
{
    DEBUGMSG(2, "TCP_INIT_SERVER:\n");

    getaddr(a, &cmd->d_address, &cmd->b_address);

    if ((cmd->fd = socket(cmd->d_address.sin_family, SOCK_DGRAM, 0)) < 0)
	safe_exit(SOCKET, "UDP Socket Open", strerror(errno));

    if (bind(cmd->fd, (struct sockaddr *)&cmd->b_address, sizeof(cmd->b_address)) < 0)
	safe_exit(BIND, "UDP Bind Socket(Server)", strerror(errno));

    socket_opt(cmd->fd, cmd);

    return cmd->fd;
}

/*****************************************************************
 * Set Socket Option
 *****************************************************************/
void socket_opt(fd, cmd)
int fd;
struct dbsd_param *cmd;
{
    int i;

    i = cmd->sock_opt.send_buff;
    if (i > 0) {
	DEBUGMSG2(2, fprintf(stderr, " send_buff = %dbyte\n", i));

	if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char *)&i, sizeof(i)) < 0)
	    safe_exit(SOSNDBUF, "setsockopt", strerror(errno));
    }

    i = cmd->sock_opt.recv_buff;
    if (i > 0) {
	DEBUGMSG2(2, fprintf(stderr, " recv_buff = %dbyte\n", i));

	if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *)&i, sizeof(i)) < 0)
	    safe_exit(SORCVBUF, "setsockopt", strerror(errno));
    }

    i = cmd->sock_opt.so_debug;
    if (i == ON) {
	DEBUGMSG2(2, fprintf(stderr, " so_debug = %s\n", (i==ON)?"ON":"OFF"));

	if (setsockopt(fd, SOL_SOCKET, SO_DEBUG, (char *)&i, sizeof(i)) < 0)
	    safe_exit(SODEBUG, "setsockopt", strerror(errno));
    }

    i = cmd->sock_opt.no_delay;
    if (i == ON) {
	DEBUGMSG2(2, fprintf(stderr, " tcp_nodelay = %s\n", (i==ON)?"ON":"OFF"));

	if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&i, sizeof(i)) < 0)
	    safe_exit(TCPNODELAY, "setsockopt", strerror(errno));
    }

    i = cmd->sock_opt.mss;
    if (i > 0) {
	DEBUGMSG2(2, fprintf(stderr, " mss = %dbyte\n", i));

	if (setsockopt(fd, IPPROTO_TCP, TCP_MAXSEG, (char *)&i, sizeof(i)) < 0)
	    safe_exit(TCPMAXSEG, "setsockopt", strerror(errno));
    }

    if (cmd->assosiation.transport == TCP) {
	int l = sizeof(i);

	if (getsockopt(fd, IPPROTO_TCP, TCP_MAXSEG, (char *)&i, &l) < 0)
	    safe_exit(ABNORMAL, "getsockopt", strerror(errno));

	cmd->sock_opt.mss = i;
	
	l = sizeof(i);
	if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char *)&i, &l) < 0)
	    safe_exit(ABNORMAL, "getsockopt", strerror(errno));

	cmd->sock_opt.send_buff = i;
	
	l = sizeof(i);
	if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *)&i, &l) < 0)
	    safe_exit(ABNORMAL, "getsockopt", strerror(errno));

	cmd->sock_opt.recv_buff = i;

	DEBUGMSG2(2, fprintf(stderr, " MSS=%d SNDBUF=%d RCVBUF=%d\n",
			     cmd->sock_opt.mss, cmd->sock_opt.send_buff, cmd->sock_opt.recv_buff));
    }
}


syntax highlighted by Code2HTML, v. 0.9.1