Files
m241Neelima/components/ip_net2-6.9/ipcom/src/ipcom_cmd_ttcp.c
T
2026-07-30 11:19:44 +05:30

1394 lines
43 KiB
C

/*
******************************************************************************
* SOURCE FILE
*
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipcom_cmd_ttcp.c,v $ $Revision: 1.106.10.4 $
* $Source: /home/interpeak/CVSRoot/ipcom/src/ipcom_cmd_ttcp.c,v $
* $Author: hxie $ $Date: 2013-05-28 06:20:09 $
* $State: Exp $ $Locker: $
*
* INTERPEAK_COPYRIGHT_STRING
* Design and implementation by Firstname Lastname <email@interpeak.se>
******************************************************************************
*/
/*
****************************************************************************
* 1 DESCRIPTION.
*
* Test TCP connection. Makes a connection on default port 5001
* and transfers fabricated buffers or data copied from stdin.
*
* Machines using System V with BSD sockets should define SYSV.
*
* HISTORY OF DEVELOPMENT.
*
* Modified for operation under 4.2BSD, 18 Dec 84
* T.C. Slattery, USNA
* Minor improvements, Mike Muuss and Terry Slattery, 16-Oct-85.
* Modified in 1989 at Silicon Graphics, Inc.
* catch SIGPIPE to be able to print stats when receiver has died
* for tcp, don't look for sentinel during reads to allow small transfers
* increased default buffer size to 8K, nbuf to 2K to transfer 16MB
* moved default port to 5001, beyond IPPORT_USERRESERVED
* make sinkmode default because it is more popular,
* -s now means don't sink/source
* count number of read/write system calls to see effects of
* blocking from full socket buffers
* for tcp, -D option turns off buffered writes (sets TCP_NODELAY sockopt)
* buffer alignment options, -A and -O
* print stats in a format that's a bit easier to use with grep & awk
* for SYSV, mimic BSD routines to use most of the existing timing code
* Modified by Steve Miller of the University of Maryland, College Park
* -b sets the socket buffer size (SO_SNDBUF/SO_RCVBUF)
* Modified Sept. 1989 at Silicon Graphics, Inc.
* restored -s sense at request of tcs@brl
* Modified Oct. 1991 at Silicon Graphics, Inc.
* use getopt(3) for option processing, add -f and -T options.
* SGI IRIX 3.3 and 4.0 releases don't need #define SYSV.
* Rewritten (being careful not to affect test loop performance) to use Interpeak
* IPCOM APIs. Added IPv6 support. October 2001, Lennart Bång.
*
* Distribution Status -
* Public Domain. Distribution Unlimited.
*/
/*
****************************************************************************
* 2 CONFIGURATION
****************************************************************************
*/
#include "ipcom_config.h"
#define DEFAULT_PORT 5001
#ifdef IPCOM_SOCK
#define DEFAULT_UDP_RCVBUF 10000
#define DEFAULT_UDP_SNDBUF 10000
#define DEFAULT_TCP_RCVBUF 16384
#define DEFAULT_TCP_SNDBUF 32767
#else
#define DEFAULT_UDP_RCVBUF 16384
#define DEFAULT_UDP_SNDBUF 32767
#define DEFAULT_TCP_RCVBUF 16384
#define DEFAULT_TCP_SNDBUF 32767
#endif
/* Includes ipcom_fwrite and ipcom_fread:
#define IPCOM_TTCP_USE_STDIOMODE
*/
/* Do not set if want exact ttcp comparison numbers. */
#define IPCOM_TTCP_REENTRANT
/*
****************************************************************************
* 3 INCLUDE FILES.
****************************************************************************
*/
#if defined(IP_PORT_INTEGRITY)
#include "ipcom_ipcom2bsd.h"
#endif
#define IPCOM_USE_CLIB_PROTO
#include "ipcom_clib.h"
#include "ipcom_cstyle.h"
#include "ipcom_getopt.h"
#include "ipcom_os.h"
#include "ipcom_sock.h"
#include "ipcom_sock2.h"
#include "ipcom_time.h"
#include "ipcom_type.h"
#include "ipcom_err.h"
#ifdef IP_PORT_INTEGRITY
#include "ipcom_ipcom2bsd.h"
#endif
#if defined(IP_PORT_VXWORKS) && IP_PORT_VXWORKS >= 65
/*#define IPCOM_CMD_SOCKTEST_USE_BSD_API*/
#endif
#if defined(IPCOM_CMD_SOCKTEST_USE_BSD_API)
#include "ipcom_ipcom2bsd.h"
#endif
#ifdef IPSCTP
#include "ipsctp_sock.h"
#endif
/*
****************************************************************************
* 4 DEFINES
****************************************************************************
*/
#define UDPMINLEN 1
#define ERR -1
#ifdef IPCOM_TTCP_REENTRANT
#define NWRITE(fd,buf,len,ctx) Nwrite(fd,buf,len,&addrhim,ctx)
#define ZERONWRITE(fd,len,ctx) ZeroNwrite(fd,len,&addrhim,ctx)
#else
#define NWRITE(fd,buf,len,ctx) Nwrite(fd,buf,len,ctx)
#define ZERONWRITE(fd,len,ctx) ZeroNwrite(fd,len,ctx)
#endif
/*
****************************************************************************
* 5 TYPES
****************************************************************************
*/
/*
****************************************************************************
* 6 LOCAL PROTOTYPES
****************************************************************************
*/
struct Ipcom_cmd_ttcp_data;
/* Local functions. */
int ipcom_cmd_ttcp(int argc, char **argv);
static void mes(int trans, char *s);
static void pattern(char *cp, int cnt);
static int Nread(int fd, void *ibuf, int count, struct Ipcom_cmd_ttcp_data *context);
#ifdef IPCOM_CMD_TTCP_USE_ZEROCOPY_API
static int ZeroNread(int fd, struct Ipcom_cmd_ttcp_data *context);
#endif
#ifdef IPCOM_TTCP_REENTRANT
static int Nwrite(int fd, void *obuf, int count, union Ip_sockaddr_union *addrhimp, struct Ipcom_cmd_ttcp_data *context);
#ifdef IPCOM_CMD_TTCP_USE_ZEROCOPY_API
static int ZeroNwrite(int fd, int count, union Ip_sockaddr_union *addrhimp, struct Ipcom_cmd_ttcp_data *context);
#endif
#else
static int Nwrite(int fd, void *obuf, int count, struct Ipcom_cmd_ttcp_data *context);
#ifdef IPCOM_CMD_TTCP_USE_ZEROCOPY_API
static int ZeroNwrite(int fd, int count, struct Ipcom_cmd_ttcp_data *context);
#endif
#endif
#ifdef IPCOM_USE_TCP
static int mread(int fd, char *bufp, unsigned n, struct Ipcom_cmd_ttcp_data *context);
#endif
IP_PUBLIC int ipcom_getsockaddrbyaddrname(int domain, Ip_bool no_dns, IP_CONST char *addr_or_name, struct Ip_sockaddr *sa);
/*
****************************************************************************
* 7 DATA
****************************************************************************
*/
/*
*===========================================================================
* USAGE
*===========================================================================
*/
/*
*===========================================================================
* STATIC DATA
*===========================================================================
*/
struct Ipcom_cmd_ttcp_data
{
int udp; /* 0 = tcp, !0 = udp */
int b_flag; /* use mread() */
int touchdata; /* access data after reading */
int err_no;
Ip_u32 numCalls; /* # of I/O system calls */
int family;
Ip_socklen_t addrsize;
#ifndef IPCOM_TTCP_REENTRANT
union Ip_sockaddr_union addrhim;
#endif
};
/*
****************************************************************************
* 8 LOCAL FUNCTIONS
****************************************************************************
*/
/*
****************************************************************************
* 9 PUBLIC FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ttcperror
*===========================================================================
*/
#define ttcperror(ctx,expr) do { \
(ctx)->err_no = ipcom_errno; \
ipcom_fprintf(ip_stderr, "ttcp error: %s (line %d, errno %d)."IP_LF, expr, __LINE__, (ctx)->err_no); \
goto errorout; \
} while((0))
/*
*===========================================================================
* terror
*===========================================================================
*/
#define terror(ctx, expr) softbreak(ctx, expr, __LINE__)
static void
softbreak(struct Ipcom_cmd_ttcp_data *context, char *expr, unsigned int line)
{
char buf[256];
context->err_no = ipcom_errno;
ipcom_sprintf(buf, "TERROR: %s [line %d] [errno %d]", expr, line, context->err_no);
ipcom_perror(buf);
}
/*
*===========================================================================
* get_millisec
*===========================================================================
*/
static Ip_u32
get_millisec(void)
{
#ifdef IPCOM_USE_TIME
struct Ip_tms tms;
return (Ip_u32)ipcom_times(&tms);
#else
return 0;
#endif
}
/*
*===========================================================================
* ipcom_cmd_ttcp
*===========================================================================
*/
int
ipcom_cmd_ttcp(int argc, char **argv)
{
/* Uninitialized variables. */
union Ip_sockaddr_union addrme;
char *host = IP_NULL; /* ptr to name of host */
int c;
Ip_u32 msec0, msec1, msecd, bpermsec, kbpersec;
Ip_fd sockfd = -1;
char *buf; /* ptr to dynamic buffer */
char *orgbuf = 0; /* the buffer to free. */
struct Ipcom_cmd_ttcp_data context;
/* misc initialized variables. */
#ifdef IPCOM_USE_TCP
union Ip_sockaddr_union frominet;
Ip_socklen_t fromlen;
int one = 1; /* for 4.3 BSD style setsockopt() */
Ip_fd oldfd = IP_INVALID_SOCKET; /* fd of network socket */
#endif
Ip_u32 nbytes = 0; /* bytes on net */
int trans = 1; /* 0=receive, !0=transmit mode. Default transmit! */
/* Configuration variables. */
#if defined(IP_SO_X_VR)
int vr = 0;
#endif
int buflen = 8 * 1024; /* length of buffer */
int nbuf = 2 * 1024; /* number of buffers to send in sinkmode */
int bufoffset = 0; /* align buffer to this */
int bufalign = 16; /* modulo this */
int options = 0; /* socket options */
unsigned short port = DEFAULT_PORT; /* TCP port number */
unsigned short meport = 0; /* local port, default 0. */
int sinkmode = 1; /* 0=normal I/O, !0=sink/source mode */
int verbose = 0; /* 0=print basic info, 1=print cpu rate, proc resource usage. */
int sockbufsize = -1; /* Default socket buffer size to use. */
#ifdef IP_TCP_NODELAY
int nodelay = 0; /* set TCP_NODELAY socket option. */
#endif
int enable = 1;
#ifdef TCP_OSERFC2385
char *md5opt = IP_NULL;
#endif
#ifdef IP_SO_REUSEPORT
int reuse_port = 0;
#endif
#ifdef IPCOM_TTCP_REENTRANT
union Ip_sockaddr_union addrhim;
#endif
int sock_error;
int mev = 0; /* Use event logging */
int nend = 5; /* Number of UDP end packets */
#ifdef IPCOM_CMD_TTCP_USE_ZEROCOPY_API
int zerocopy = 0;
#endif
int cpu = -1;
#ifdef IPSCTP
Ip_bool sctp_type_conflict = IP_FALSE;
#endif
int udplite_cscov = 0;
/* Initialize some static data, default configuration. */
#ifdef IPCOM_USE_TCP
int proto = IP_IPPROTO_TCP;
int sock_type = IP_SOCK_STREAM;
const char *proto_as_str = "TCP";
context.udp = 0; /* Default is TCP. */
#else
int proto = IP_IPPROTO_UDP;
int sock_type = IP_SOCK_DGRAM;
const char *proto_as_str = "UDP";
context.udp = 1; /* Only UDP. */
#endif
context.b_flag = 0;
context.touchdata = 0;
context.numCalls = 0;
context.err_no = 0;
#ifdef IPCOM_USE_INET
context.family = IP_AF_INET; /* default IPv4 */
#else
context.family = IP_AF_INET6; /* default IPv6 */
#endif
context.addrsize = sizeof(struct Ip_sockaddr_in);
(void)ipcom_proc_self(); /* when called from vxworks shell, this prevents a crash */
(void)options;
/* Init some more. */
ipcom_memset(&addrhim, 0, sizeof (addrhim));
IPCOM_SA_LEN_SET(&addrhim.sa, sizeof(struct Ip_sockaddr_in));
addrhim.sa.sa_family = IP_AF_INET;
ipcom_memset(&addrme, 0, sizeof(addrme));
IPCOM_SA_LEN_SET(&addrme.sa, sizeof(struct Ip_sockaddr_in));
addrme.sa.sa_family = IP_AF_INET;
#ifdef IP_PORT_INTEGRITY
ipcom_init_libsocket();
#endif
if (argc < 2)
goto usage;
ipcom_getopt_clear();
while ((c = ipcom_getopt(argc, argv, "M:xdrstUuvBDTb:f:l:n:p:A:O:V:RP:me:a:cSLC:")) != -1)
{
switch (c)
{
#ifdef TCP_OSERFC2385
case 'M': /* MD5 signature option */
md5opt = ip_optarg;
break;
#endif
#ifdef IPCOM_USE_INET6
case 'x':
context.family = IP_AF_INET6;
break;
#endif
case 'm':
mev = 1;
break;
case 'e':
nend = ipcom_atoi(ip_optarg);
break;
case 'B':
context.b_flag = 1;
break;
case 't':
trans = 1;
break;
case 'r':
trans = 0;
break;
#ifdef IP_SO_DEBUG
case 'd':
options |= IP_SO_DEBUG;
break;
#endif
case 'D':
#ifdef IP_TCP_NODELAY
nodelay = 1;
#else
ipcom_fprintf(ip_stderr, "ttcp: -D option ignored: IP_TCP_NODELAY socket option not supported"IP_LF);
#endif
break;
case 'n':
nbuf = ipcom_atoi(ip_optarg);
break;
case 'l':
buflen = ipcom_atoi(ip_optarg);
break;
case 's':
#ifdef IPCOM_TTCP_USE_STDIOMODE
sinkmode = !sinkmode;
#endif
break;
case 'p':
port = (unsigned short)ipcom_atoi(ip_optarg);
break;
case 'P':
meport = (unsigned short)ipcom_atoi(ip_optarg);
break;
#ifdef IPCOM_CMD_TTCP_USE_ZEROCOPY_API
case 'U':
zerocopy = 1;
/* fall through */
#endif
case 'u':
proto = IP_IPPROTO_UDP;
sock_type = IP_SOCK_DGRAM;
proto_as_str = "UDP";
context.udp = 1;
break;
case 'L':
proto = IP_IPPROTO_UDPLITE;
sock_type = IP_SOCK_DGRAM;
proto_as_str = "UDP-Lite";
context.udp = 1;
break;
case 'C':
udplite_cscov = ipcom_atoi(ip_optarg);
break;
case 'v':
verbose = 1;
break;
case 'A':
bufalign = ipcom_atoi(ip_optarg);
break;
case 'O':
bufoffset = ipcom_atoi(ip_optarg);
break;
case 'b':
#if defined(IP_SO_SNDBUF) || defined(IP_SO_RCVBUF)
sockbufsize = ipcom_atoi(ip_optarg);
#else
ipcom_fprintf(ip_stderr, "ttcp: -b option ignored: IP_SO_SNDBUF/IP_SO_RCVBUF socket options not supported"IP_LF);
#endif
break;
#ifdef IP_SO_REUSEPORT
case 'R':
reuse_port = 1;
break;
#endif
case 'T':
context.touchdata = 1;
break;
#if defined(IP_SO_X_VR)
case 'V':
vr = ipcom_atoi(ip_optarg);
break;
#endif
case 'a':
cpu = ipcom_atoi(ip_optarg);
break;
#ifdef IPSCTP
case 'c':
proto = IP_IPPROTO_SCTP;
sock_type = IP_SOCK_STREAM;
proto_as_str = "SCTP";
if (IP_TRUE == sctp_type_conflict)
{
ipcom_fprintf(ip_stderr, "ttcp: c/S conflict in command."IP_LF);
goto errorout;
}
sctp_type_conflict = IP_TRUE;
break;
case 'S':
proto = IP_IPPROTO_SCTP;
sock_type = IP_SOCK_SEQPACKET;
proto_as_str = "SCTP";
if (IP_TRUE == sctp_type_conflict)
{
ipcom_fprintf(ip_stderr, "ttcp: c/S conflict in command."IP_LF);
goto errorout;
}
sctp_type_conflict = IP_TRUE;
break;
#endif
default:
goto usage;
}
}
#ifndef IP_PORT_LAS
if (cpu >= 0)
{
Ip_cpu_set_t cpuset;
if (cpu < 0 || cpu >= IP_CPU_SETSIZE)
{
ipcom_fprintf(ip_stderr, "ttcp: CPU must be between #0 and #%d"IP_LF, IP_CPU_SETSIZE-1);
return -1;
}
IP_CPU_ZERO(&cpuset);
IP_CPU_SET(cpu, &cpuset);
if (ipcom_proc_cpu_affinity_set(0, &cpuset) != IPCOM_SUCCESS)
{
ipcom_fprintf(ip_stderr, "ttcp: Failed to set affinity to CPU #%d"IP_LF, cpu);
return -1;
}
}
#endif /* IP_PORT_LAS */
if(trans)
{
host = argv[ip_optind];
if (host == 0)
goto usage;
sock_error = ipcom_getsockaddrbyaddrname(context.family, IP_FALSE, host, (struct Ip_sockaddr *)&addrhim);
if(sock_error != 0)
{
ipcom_fprintf(ip_stderr, "ttcp error: ipcom_getsockaddrbyaddrname failed, errno = %d."IP_LF, sock_error);
ttcperror(&context, "unknown host");
}
#ifdef IPCOM_USE_INET
addrme.sin.sin_port = ip_htons(meport);
addrhim.sin.sin_port = ip_htons(port); /* same port offset for IPv4 and IPv6 */
#else
addrme.sin6.sin6_port = ip_htons(meport);
addrhim.sin6.sin6_port = ip_htons(port);
#endif
}
else
{
/* rcvr */
#ifdef IPCOM_USE_INET
addrme.sin.sin_port = ip_htons(port);
#else
addrme.sin6.sin6_port = ip_htons(port);
#endif
}
#ifdef IPCOM_USE_INET6
if(context.family == IP_AF_INET6)
{
context.addrsize = sizeof(struct Ip_sockaddr_in6);
IPCOM_SA_LEN_SET(&addrme.sin6, sizeof(struct Ip_sockaddr_in6));
addrme.sin6.sin6_family = IP_AF_INET6;
IPCOM_SA_LEN_SET(&addrhim.sin6, sizeof(struct Ip_sockaddr_in6));
addrhim.sin6.sin6_family = IP_AF_INET6;
}
#endif
/* Send more than the sentinel size - UDPMINLEN. */
if(context.udp && buflen <= UDPMINLEN)
buflen = UDPMINLEN + 1;
/* Align buffer. */
if ((buf = (char *) ipcom_malloc((Ip_size_t)(buflen + bufalign))) == (char *) IP_NULL)
ttcperror(&context, "malloc");
else
orgbuf = buf;
if (bufalign != 0)
buf += (bufalign - (int)((Ip_ptrdiff_t) buf % (Ip_ptrdiff_t)bufalign) + bufoffset) % bufalign;
/* Get a socket. */
if ((sockfd = ipcom_socket(context.family, sock_type, proto)) == ERR)
ttcperror(&context,"socket");
if (trans)
{
if(sockbufsize < 0)
{
if(context.udp)
sockbufsize = DEFAULT_UDP_SNDBUF;
else
sockbufsize = DEFAULT_TCP_SNDBUF;
}
ipcom_fprintf(ip_stdout, "ttcp-t: fd=%d, buflen=%d, nbuf=%d, align=%d/%d, port=%d",
sockfd, buflen, nbuf, bufalign, bufoffset, (int)port);
if (sockbufsize)
ipcom_fprintf(ip_stdout, ", sockbufsize=%d", sockbufsize);
ipcom_fprintf(ip_stdout, " %s -> %s"IP_LF, proto_as_str, host);
}
else
{
if(sockbufsize < 0)
{
if(context.udp)
sockbufsize = DEFAULT_UDP_RCVBUF;
else
sockbufsize = DEFAULT_TCP_RCVBUF;
}
ipcom_fprintf(ip_stdout, "ttcp-r: fd=%d, buflen=%d, nbuf=%d, align=%d/%d, port=%d",
sockfd, buflen, nbuf, bufalign, bufoffset, (int)port);
if (sockbufsize)
ipcom_fprintf(ip_stdout, ", sockbufsize=%d", sockbufsize);
ipcom_fprintf(ip_stdout, " %s"IP_LF, proto_as_str);
}
/* Code to open socket is moved to before the printf to get 'sockfd' right. */
mes(trans, "socket");
/* Set REUSE addr */
if(ipcom_setsockopt(sockfd, IP_SOL_SOCKET, IP_SO_REUSEADDR, (char *)&enable, sizeof (int)) == ERR)
ttcperror(&context, "setsockopt(IP_SO_REUSEADDR)");
else
mes(trans, "setsockopt(IP_SO_REUSEADDR)");
#ifdef IP_SO_REUSEPORT
/* Set REUSE port */
if(reuse_port)
{
if(ipcom_setsockopt(sockfd, IP_SOL_SOCKET, IP_SO_REUSEPORT, (char *)&reuse_port, sizeof (int)) == ERR)
ttcperror(&context, "setsockopt(IP_SO_REUSEPORT)");
else
mes(trans, "setsockopt(IP_SO_REUSEPORT)");
}
#endif
#ifdef IPCOM_USE_TCP
#ifdef TCP_OSERFC2385
if (!udp && md5opt)
{
if (ipcom_setsockopt(sockfd, IPPROTO_TCP, TCP_OSERFC2385,
md5opt, strlen(md5opt)) == ERR)
{
ttcperror(&context, "setsockopt(IP_SO_REUSEADDR)");
}
else
{
mes(trans, "setsockopt(IP_SO_REUSEADDR)");
}
}
#endif
#endif
/* Set routing table index in socket. */
#if defined(IP_SO_X_VR)
if(vr != 0)
{
if (ipcom_setsockopt(sockfd, IP_SOL_SOCKET, IP_SO_X_VR, (char *)&vr, 4) == ERR)
ttcperror(&context, "setsockopt: vr");
else
mes(trans, "setsockopt(vr)");
}
#endif
if (proto == IP_IPPROTO_UDPLITE)
{
if (ipcom_setsockopt(sockfd,
IP_IPPROTO_UDPLITE,
IP_UDPLITE_SEND_CSCOV,
&udplite_cscov,
sizeof(udplite_cscov)) < 0)
ttcperror(&context, "setsockopt(UDPLITE_SEND_CSCOV)");
else
mes(trans, "setsockopt(UDPLITE_SEND_CSCOV)");
}
/* Bind the socket. */
if(ipcom_bind(sockfd, (struct Ip_sockaddr *)&addrme, context.addrsize) == ERR)
ttcperror(&context, "bind");
else
#ifdef IPCOM_USE_INET6
ipcom_fprintf(ip_stderr, "ttcp%s: bind %s %d"IP_LF, trans ? "-t" : "-r",
context.family == IP_AF_INET ? "IPv4" : "IPv6",
(int)ip_ntohs(addrme.sin6.sin6_port));
#else
{
char tmpbuf[32];
ipcom_sprintf(tmpbuf, "bind %d", ip_ntohs(addrme.sin.sin_port));
mes(trans, tmpbuf);
}
#endif
/* Adjust socker buffer size. */
#if defined(IP_SO_SNDBUF) || defined(IP_SO_RCVBUF)
if(sockbufsize)
{
if (trans)
{
if (ipcom_setsockopt(sockfd, IP_SOL_SOCKET, IP_SO_SNDBUF, (char *)&sockbufsize, sizeof sockbufsize) == ERR)
ttcperror(&context,"setsockopt: sndbuf");
else
mes(trans, "setsockopt(sndbuf)");
}
else
{
if (ipcom_setsockopt(sockfd, IP_SOL_SOCKET, IP_SO_RCVBUF, (char *)&sockbufsize, sizeof sockbufsize) == ERR)
ttcperror(&context,"setsockopt: rcvbuf");
else
mes(trans, "setsockopt(rcvbuf)");
}
}
#endif
/* If TCP we need to connect else accept to remote side. */
#ifdef IPCOM_USE_TCP
if (context.udp)
{
mes(trans, "opened");
}
else
{
/* We are the client if transmitting */
if(trans)
{
if(options)
{
if(ipcom_setsockopt(sockfd, IP_SOL_SOCKET, options, (char *)&one, sizeof (one)) == ERR)
ttcperror(&context,"setsockopt");
}
#ifdef IP_TCP_NODELAY
if(nodelay)
{
if(ipcom_setsockopt(sockfd, IP_IPPROTO_TCP, IP_TCP_NODELAY, (char *)&one, sizeof (one)) == ERR)
ttcperror(&context,"setsockopt: nodelay");
mes(trans, "nodelay");
}
#endif
if(ipcom_connect(sockfd, (struct Ip_sockaddr *)&addrhim, context.addrsize) == ERR)
ttcperror(&context,"connect");
else
mes(trans, "connect");
}
/* Otherwise, we are the TCP server and should listen for the connections. */
else
{
if(ipcom_listen(sockfd, 0) == ERR)
ttcperror(&context,"listen");
else
mes(trans, "listen");
if(options)
{
if(ipcom_setsockopt(sockfd, IP_SOL_SOCKET, options, (char *)&one, sizeof (one)) == ERR)
ttcperror(&context,"setsockopt");
}
fromlen = context.addrsize;
oldfd = sockfd;
#ifdef IPSCTP
if ((IP_SOCK_SEQPACKET == sock_type)
&& (IP_IPPROTO_SCTP == proto))
{
#define TTCP_SCTP_RCV_BUF_LEN 128
struct Ipsctp_event_subscribe events;
union Ip_sockaddr_union local_addr;
struct Ipsctp_sndrcvinfo sinfo;
Ip_u32 len = 0;
char pbuf[TTCP_SCTP_RCV_BUF_LEN];
int flags = 0;
int ret = 0;
/* set data I/O event flag */
ipcom_memset(&events, 0, sizeof(events));
events.Ipsctp_data_io_event = 1;
ret = ipcom_setsockopt(sockfd,
IP_IPPROTO_SCTP,
IPSCTP_EVENTS,
(void *)&events,
sizeof(events));
if (ERR == ret)
ttcperror(&context, "setsockopt events");
/* get the association identifier */
ipcom_memset(pbuf, 0, TTCP_SCTP_RCV_BUF_LEN);
len = sizeof(local_addr);
/* Wait for connections */
ret = (int)ipsctp_recvmsg(sockfd,
pbuf,
TTCP_SCTP_RCV_BUF_LEN,
&local_addr.sa,
&len,
&sinfo,
&flags);
sockfd = ipsctp_peeloff(sockfd, sinfo.sinfo_assoc_id);
if (IP_SOCKERR == sockfd)
ttcperror(&context,"peeloff");
}
else
#endif
{
if((sockfd = ipcom_accept(sockfd, (struct Ip_sockaddr *)&frominet, &fromlen)) == ERR)
ttcperror(&context,"accept");
}
{
union Ip_sockaddr_union peer;
Ip_socklen_t peerlen = context.addrsize;
/* Close the mother socket. */
if(ipcom_socketclose(oldfd) == ERR)
ttcperror(&context,"close of oldfd.");
oldfd = IP_INVALID_SOCKET;
#if defined(IP_SO_RCVBUF)
/* Had to add this code in addition to the above because some stacks don't inherit
* the receive buffer size from the server socket. /Lennart Bang Enea Ose Systems 980116.
*/
if(sockbufsize)
{
if(ipcom_setsockopt(sockfd, IP_SOL_SOCKET, IP_SO_RCVBUF, (char *)&sockbufsize, sizeof sockbufsize) == ERR)
ttcperror(&context,"setsockopt: rcvbuf");
else
mes(trans, "setsockopt(rcvbuf)");
}
#endif
if(ipcom_getpeername(sockfd, (struct Ip_sockaddr *) &peer, &peerlen) == ERR)
ttcperror(&context, "getpeername");
#ifdef IPCOM_USE_INET
if(context.family == IP_AF_INET)
{
char addr[16];
ipcom_fprintf(ip_stderr, "ttcp-r: accept from %s"IP_LF,
ipcom_inet_ntop(IP_AF_INET, &peer.sin.sin_addr, addr, sizeof(addr)));
}
#endif
#ifdef IPCOM_USE_INET6
if(context.family == IP_AF_INET6)
{
char addr[40];
ipcom_fprintf(ip_stderr, "ttcp-r: accept from %s"IP_LF,
ipcom_inet_ntop(IP_AF_INET6, &peer.sin6.sin6_addr, addr, sizeof(addr)));
}
#endif
}
}
}
#endif
/* Begin the TTCP performance test. */
msec0 = get_millisec();
if (mev)
{
#if defined (IP_PORT_INTEGRITY)
#include "ipcom_integrity.h"
extern void EventLogOn(void);
#if IP_VER < 500
extern void EventLogMask(unsigned int newmask);
EventLogMask(~0);
#endif
EventLogOn();
#endif
}
if(sinkmode)
{
register int cnt;
/* Transmit side. */
if(trans)
{
pattern(buf, buflen);
if(context.udp)
{
(void) NWRITE(sockfd, buf, UDPMINLEN, &context); /* rcvr start */
ipcom_millisleep(500); /* arp time */
/* Renew the start time to not include the 500 msec sleep */
msec0 = get_millisec();
}
#ifdef IPCOM_CMD_TTCP_USE_ZEROCOPY_API
if (zerocopy)
{
while (nbuf-- && ZERONWRITE(sockfd, buflen, &context) == buflen)
nbytes += (Ip_u32)buflen;
}
else
#endif
{
while (nbuf-- && NWRITE(sockfd, buf, buflen, &context) == buflen)
nbytes += (Ip_u32)buflen;
}
if(context.udp)
(void) NWRITE(sockfd, buf, UDPMINLEN, &context); /* rcvr end */
}
/* Receive side. */
else
{
if(context.udp)
{
int going = 0;
#ifdef IPCOM_CMD_TTCP_USE_ZEROCOPY_API
if (zerocopy)
{
while ((cnt = ZeroNread(sockfd, &context)) > 0)
{
if(cnt <= UDPMINLEN)
{
if(going)
break; /* "EOF" */
going = 1;
msec0 = get_millisec();
}
else
{
nbytes += cnt;
}
}
}
else
#endif
{
while ((cnt = Nread(sockfd, buf, buflen, &context)) > 0)
{
if(cnt <= UDPMINLEN)
{
if(going)
break; /* "EOF" */
going = 1;
msec0 = get_millisec();
}
else
{
nbytes += (Ip_u32)cnt;
}
}
}
}
#ifdef IPCOM_USE_TCP
else
{
while ((cnt = Nread(sockfd, buf, buflen, &context)) > 0)
{
nbytes += (Ip_u32)cnt;
}
}
#endif
}
}
#ifdef IPCOM_TTCP_USE_STDIOMODE
/* non sinkmode. */
else
{
register int cnt;
if(trans)
{
/* Read from standard input and send to other side. */
while ((cnt = ipcom_fread(buf, buflen, 1, ip_stdin)) > 0 &&
NWRITE(sockfd, buf, cnt) == cnt)
nbytes += cnt;
}
else
{
/* Read from network and print on stdout. */
while ((cnt = Nread(sockfd, buf, buflen, &context)) > 0)
{
ipcom_fwrite(buf, cnt, 1, ip_stdout);
nbytes += cnt;
}
}
}
#endif
if (mev)
{
#if defined (IP_PORT_INTEGRITY)
extern void EventLogOff(void);
EventLogOff();
#elif defined (IP_PORT_RTCORE)
extern void ip_trace(char *what, char *file, int line, int id, void *data);
extern void ip_tracedump(void);
ip_trace("[ASSERT]", __FILE__, __LINE__, ipcom_getpid(), IP_NULL);
ip_tracedump();
#endif
}
/* Read the final time and calculate some statistics. */
msec1 = get_millisec();
msecd = msec1 - msec0;
if (msecd == 0)
msecd = 1;
bpermsec = nbytes / msecd; /* Bytes per millisecond. */
kbpersec = nbytes / 128;
kbpersec = kbpersec * 125 / msecd; /* kilobyte per sec. */
/* End of test assemble statistice. */
if(context.err_no)
{
ipcom_fprintf(ip_stdout, "ttcp%s: socket errno: %d."IP_LF, trans ? "-t" : "-r", context.err_no);
}
if(context.udp && trans)
{
int j;
for (j = 0; j < nend; j++)
{
ipcom_millisleep(100); /* Let the reading side catch up. */
(void) NWRITE(sockfd, buf, UDPMINLEN, &context); /* rcvr end */
}
}
/* Print the statistics. */
ipcom_fprintf(ip_stdout, "ttcp%s: %u bytes in %u milliseconds = %u KB/sec, %u B/msec +++"IP_LF,
trans ? "-t" : "-r", nbytes, msecd, kbpersec, bpermsec);
ipcom_fprintf(ip_stdout, "ttcp%s: %u I/O calls, msec/call = %u, calls/sec = %u"IP_LF,
trans ? "-t" : "-r",
context.numCalls,
msecd / context.numCalls,
1000 * context.numCalls / msecd);
if (verbose)
ipcom_fprintf(ip_stdout, "ttcp%s: buffer address %p"IP_LF, trans ? "-t" : "-r", buf);
/* Test succeeded, goto errorout to cleanup. */
goto errorout;
/* Usage. */
usage:
ipcom_fprintf(ip_stderr,
"Usage: ttcp -t [-options] host [ < in ]"IP_LF
"ttcp -r [-options > out]"IP_LF
"Common options:"IP_LF
"-x use IPv6 instead of IPv4"IP_LF
"-l ## length of bufs read from or written to network (default 8192)"IP_LF
#ifdef IPCOM_CMD_TTCP_USE_ZEROCOPY_API
"-U use UDP and interpeak zero copy API instead of TCP"IP_LF
#endif
"-u use UDP (default is TCP)"IP_LF
"-L use UDP-Lite (RFC3828)"IP_LF
#ifdef IPSCTP
"-c use SCTP STREAM type(default is TCP)"IP_LF
"-S use SCTP SEQPACKET type(default is TCP)"IP_LF
#endif
"-p ## port number to send to or listen at (default DEFAULT_PORT)"IP_LF);
ipcom_fprintf(ip_stderr,
"-s -t: source a pattern to network"IP_LF
"-r sink (discard) all data from network"IP_LF
"-e ## number of packets to end UDP transmission"IP_LF
"-m use event logging (not supported on all platforms)"IP_LF
"-A align the start of buffers to this modulus (default 16384)"IP_LF
"-O start buffers at this offset from the modulus (default 0)"IP_LF
"-v verbose: print more statistics"IP_LF
"-d set SO_DEBUG socket option (if supported)"IP_LF);
ipcom_fprintf(ip_stderr,
"-b ## set socket buffer size (if supported)"IP_LF
"Options specific to -t:"IP_LF
"-n## number of source bufs written to network (default 2048)"IP_LF
"-D don't buffer TCP writes (sets TCP_NODELAY socket option)"IP_LF
"Options specific to -r:"IP_LF
"-B for -s, only output full blocks as specified by -l (for TAR)"IP_LF
"-T \"touch\": access each byte as it's read"IP_LF
#if defined(IP_SO_X_VR)
"-V virtual router index (if supported)"IP_LF);
#endif
/* fall through to cleanup...*/
/* Free buffer and close socket if any error. */
errorout:
#ifndef IP_PORT_LAS
if (cpu >= 0)
ipcom_proc_cpu_affinity_clr(0);
#endif /* IP_PORT_LAS */
if(orgbuf)
ipcom_free(orgbuf);
if (oldfd != IP_INVALID_SOCKET && oldfd != sockfd)
{
if(ipcom_socketclose(oldfd) == ERR)
ipcom_fprintf(ip_stderr, "ttcp error: close of oldfd. (line %d, errno %d)."IP_LF, __LINE__, ipcom_errno);
}
if(sockfd != -1)
{
if(ipcom_socketclose(sockfd) == ERR)
ipcom_fprintf(ip_stderr, "ttcp error: close of sockfd. (line %d, errno %d)."IP_LF, __LINE__, ipcom_errno);
}
#ifdef IP_PORT_INTEGRITY
ipcom_shutdown_libsocket();
#endif
return 0;
}
/*
*===========================================================================
* mes
*===========================================================================
*/
static void
mes(int trans, char *s)
{
ipcom_fprintf(ip_stdout, "ttcp%s: %s"IP_LF, trans ? "-t" : "-r", s);
}
/*
*===========================================================================
* pattern
*===========================================================================
*/
static void
pattern(char *cp, int cnt)
{
register char c;
c = 0;
while (cnt-- > 0)
{
while (!ipcom_isprint((c & 0x7F)))
c++;
*cp++ = (char)(c++ & 0x7F);
}
}
/*
*===========================================================================
* Nread
*===========================================================================
*/
static int
Nread(int fd, void *ibuf, int count, struct Ipcom_cmd_ttcp_data *context)
{
union Ip_sockaddr_union from;
Ip_socklen_t len = context->addrsize;
register int cnt;
if(context->udp)
{
if ((cnt = (int)ipcom_recvfrom(fd, ibuf, (Ip_size_t)count, 0, (struct Ip_sockaddr *)&from, &len)) < 0)
context->err_no = ipcom_errno;
context->numCalls++;
}
else
#ifdef IPCOM_USE_TCP
{
if(context->b_flag)
cnt = mread(fd, ibuf, (unsigned)count, context); /* fill buf */
else
{
if ((cnt = (int)ipcom_socketread(fd, ibuf, (Ip_size_t)count)) < 0)
context->err_no = ipcom_errno;
context->numCalls++;
}
if(context->touchdata && cnt > 0)
{
register int c = cnt;
volatile int sum = 0;
register char *b = ibuf;
while (c--)
sum += *b++;
(void)sum; /* lint */
}
}
#else
{
(void)b_flag;
(void)touchdata;
cnt = 0;
}
#endif /* IPCOM_USE_TCP */
return (cnt);
}
/*
*===========================================================================
* Nwrite
*===========================================================================
*/
#ifdef IPCOM_TTCP_REENTRANT
static int
Nwrite(int fd, void *obuf, int count, union Ip_sockaddr_union *addrhimp, struct Ipcom_cmd_ttcp_data *context)
#else
static int
Nwrite(int fd, void *obuf, int count, struct Ipcom_cmd_ttcp_data *context)
#endif
{
register int cnt;
ipcom_errno = 0;
if(context->udp)
{
again:
#ifdef IPCOM_TTCP_REENTRANT
cnt = (int)ipcom_sendto(fd, obuf, (Ip_size_t)count, 0, (struct Ip_sockaddr *)addrhimp, context->addrsize);
#else
cnt = (int)ipcom_sendto(fd, obuf, (Ip_size_t)count, 0, (struct Ip_sockaddr *)&addrhim, context->addrsize);
#endif
context->numCalls++;
if(cnt == ERR)
{
terror(context, "Nwrite");
/* The vxWorks native stack returns ENOBUFS. Could be because the driver
* schedules netTask to free buffers once they are sent. Forcing a context
* switch and retrying seems to help */
if(ipcom_errno == IP_ERRNO_ENOBUFS)
{
(void)ipcom_proc_yield();
goto again;
}
return -1;
}
}
else
#ifdef IPCOM_USE_TCP
{
if ((cnt = (int)ipcom_socketwrite(fd, obuf, (Ip_size_t)count)) < 0)
context->err_no = ipcom_errno;
context->numCalls++;
}
#else
cnt = 0;
#endif /* IPCOM_USE_TCP */
return (cnt);
}
/*
*===========================================================================
* mread
*===========================================================================
* This function performs the function of a read(II) but will
* call read(II) multiple times in order to get the requested
* number of characters. This can be necessary because
* network connections don't deliver data with the same
* grouping as it is written with. Written by Robert S. Miles, BRL.
*/
#ifdef IPCOM_USE_TCP
static int
mread(int fd, char *bufp, unsigned n, struct Ipcom_cmd_ttcp_data *context)
{
register unsigned count = 0;
register int nread;
do
{
nread = (int)ipcom_socketread(fd, bufp, n - count);
context->numCalls++;
if(nread == ERR)
{
terror(context, "ttcp_mread");
return (-1);
}
if(nread == 0)
return ((int) count);
count += (unsigned) nread;
bufp += nread;
}
while (count < n);
return ((int) count);
}
#endif
#ifdef IPCOM_CMD_TTCP_USE_ZEROCOPY_API
/*
*===========================================================================
* ZeroNread
*===========================================================================
*/
static int
ZeroNread(int fd, struct Ipcom_cmd_ttcp_data *context)
{
/* Only sink mode */
union Ip_sockaddr_union from;
Ip_socklen_t len = context->addrsize;
register int cnt;
void *buf;
int start;
Ipcom_pkt_freefunc freefunc;
void *cookie;
cnt = ipcom_pkt_recvfrom(fd, &buf, &start, &freefunc, &cookie, 0, &from.sa, &len);
if (cnt < 0)
context->err_no = ipcom_errno;
context->numCalls++;
freefunc(buf, cookie);
return (cnt);
}
/*
*===========================================================================
* ZeroNwriteFreeFunc
*===========================================================================
*/
static void ZeroNwriteFreeFunc(void *aligned_buf, void *buf)
{
(void)aligned_buf;
ipcom_pkt_buffer_free(buf);
}
/*
*===========================================================================
* Nwrite
*===========================================================================
*/
#ifdef IPCOM_TTCP_REENTRANT
static int
ZeroNwrite(int fd, int count, union Ip_sockaddr_union *addrhimp, struct Ipcom_cmd_ttcp_data *context)
#else
static int
ZeroNwrite(int fd, int count, struct Ipcom_cmd_ttcp_data *context)
#endif
{
register int cnt;
int start;
void *buf;
void *aligned_buf;
start = ipcom_pkt_hdrspace(fd);
buf = ipcom_pkt_buffer_malloc(start + count + 15);
aligned_buf = (void *) (((unsigned long) buf + 15u) & ~0xf);
#ifdef IPCOM_TTCP_REENTRANT
cnt = ipcom_pkt_sendto(fd, aligned_buf, start, count, ZeroNwriteFreeFunc, buf, 0, (struct Ip_sockaddr *)addrhimp, context->addrsize);
#else
cnt = ipcom_pkt_sendto(fd, aligned_buf, start, count, ZeroNwriteFreeFunc, buf, 0, (struct Ip_sockaddr *)&addrhim, context->addrsize);
#endif
context->numCalls++;
if (cnt == ERR)
{
terror(context, "Nwrite");
return -1;
}
return (cnt);
}
#endif /* IPCOM_CMD_TTCP_USE_ZEROCOPY_API */
#if defined(IPCOM_CMD_SOCKTEST_USE_BSD_API)
#include "ipcom_ipcom2bsd_finish.h"
#endif
/*
*===========================================================================
* END OF FILE
*===========================================================================
*/