/* ****************************************************************************** * INTERPEAK SOURCE FILE * * Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipcom_cmd_smptest.c,v $ $Revision: 1.15 $ * $Source: /home/interpeak/CVSRoot/ipcom/src/ipcom_cmd_smptest.c,v $ * $Author: gulgi $ * $State: Exp $ $Locker: $ * * INTERPEAK_COPYRIGHT_STRING * Design and implementation by Adam Skoglund ****************************************************************************** */ /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** * SMP stresstest. */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ #include "ipcom_config.h" #ifdef IPCOM_USE_SMPTEST_CMD /* **************************************************************************** * 3 INCLUDE FILES **************************************************************************** */ #define IPCOM_USE_CLIB_PROTO #include "ipcom_cstyle.h" #include "ipcom_type.h" #include "ipcom_getopt.h" #include "ipcom_clib.h" #include "ipcom_sock.h" #include "ipcom_sock2.h" #include "ipcom_os.h" #include "ipcom_shell.h" #include "ipcom_atomic.h" /* **************************************************************************** * 4 DEFINES **************************************************************************** */ #define MAX_TASKS 40 #define SECONDS_CLIENT 5 #define SECONDS_SERVER 45 /* **************************************************************************** * 5 TYPES **************************************************************************** */ typedef struct Ipcom_cmd_smptest_struct { Ip_bool server; Ip_bool ip4; Ip_bool tcp; Ip_u32 num_bytes; Ip_u32 num_sock; Ip_u32 port; struct Ip_addrinfo *res; } Ipcom_cmd_smptest_t; /* **************************************************************************** * 6 EXTERN PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 7 LOCAL PROTOTYPES **************************************************************************** */ IP_PUBLIC int ipcom_cmd_smptest(int argc, char **argv); IP_STATIC IPCOM_PROCESS( ipcom_cmd_smptest_server_spawn ); IP_STATIC IPCOM_PROCESS( ipcom_cmd_smptest_client_spawn ); /* **************************************************************************** * 8 DATA **************************************************************************** */ static Ipcom_sem sem_wait_client; static Ipcom_sem sem_wait_server; static Ipcom_atomic_t num_wait_client; static Ipcom_atomic_t num_wait_server; static Ipcom_atomic_t listen_wait; static int return_client = 0; static int return_server = 0; static Ipcom_cmd_smptest_t smp_opt_client; static Ipcom_cmd_smptest_t smp_opt_server; static volatile Ip_u32 spawn_number_client = 0; static volatile Ip_u32 spawn_number_server = 0; static Ip_bool verbose = 0; static Ip_fd server_out = 0; /* **************************************************************************** * 9 STATIC FUNCTIONS **************************************************************************** */ /* *=========================================================================== * ipcom_cmd_smptest_print_usage *=========================================================================== * Description: Print usage information for the SMP test shell command. * Parameters: none. * Returns: nothing. */ IP_STATIC void ipcom_cmd_smptest_print_usage(void) { ipcom_printf( "SMP stress test"IP_LF "usage: "IP_LF " smptest [options] [address]"IP_LF " -c client mode (default is server mode)"IP_LF " -6 use IPv6 (default is IPv4)"IP_LF " -u use UDP (default is TCP)"IP_LF " -l number of bytes to write/read in each call (default 1024)"IP_LF " -p socket port (default 8484)"IP_LF " -s number of sockets to use, must be same on both ends (default 1)"IP_LF " -v verbose"IP_LF " -h this help"IP_LF IP_LF ); } /* *=========================================================================== * ipcom_cmd_smptest_server *=========================================================================== * Description: This is the server part of the smptest command * Parameters: The address we should listen to, and info about how many sockets * we should use. * Returns: 0 on success. -1 on failure. */ IP_STATIC int ipcom_cmd_smptest_server() { Ipcom_proc_attr attr; unsigned int i; Ipcom_proc *proc; int retval; spawn_number_server = 0; if ( 0 != ipcom_sem_create( &sem_wait_server, 0 ) ) { ipcom_printf("ipcom_sem_create failed: %s"IP_LF, ipcom_strerror(ipcom_errno)); return -1; } ipcom_atomic_set( &num_wait_server, smp_opt_server.num_sock ); ipcom_atomic_set( &listen_wait, smp_opt_server.num_sock ); ipcom_proc_attr_init(&attr); attr.priority = IPCOM_PRIORITY_DEFAULT; /* Hacky hacky way to write from a task.. copied from ipcom_mshell.c */ proc = ipcom_proc_self(); ip_assert( proc != 0 ); server_out = proc->shell_fd; for ( i = 0;i < smp_opt_server.num_sock;++i ) { retval = ipcom_proc_acreate("ipcom_cmd_smptest_server_spawn", (Ipcom_proc_func)ipcom_cmd_smptest_server_spawn, &attr, 0 ); if (retval != 0) { ipcom_printf( "Error spawning smptest server"IP_LF ); return retval; } } ipcom_sem_wait( sem_wait_server ); ipcom_sem_delete( &sem_wait_server ); return 0; } /* *=========================================================================== * ipcom_cmd_smptest_server_spawn *=========================================================================== * Description: This is the server spawn part of the smptest command * Parameters: None * Returns: Nothing. */ IP_STATIC IPCOM_PROCESS( ipcom_cmd_smptest_server_spawn ) { union { struct Ip_sockaddr sa; #ifdef IPCOM_USE_INET6 struct Ip_sockaddr_in6 sin6; #endif struct Ip_sockaddr_storage ss; struct Ip_sockaddr_in sin; } addr; Ip_fd listen_socket; Ip_fd connect_sock = 0; int opt_val = 1; int portadd = spawn_number_server++; int bytes = 0; int sec = SECONDS_CLIENT + SECONDS_SERVER; unsigned char *buf = 0; int num_recives = 0; unsigned long num_bytes = 0; struct Ip_sockaddr from; struct Ip_linger linger; Ip_socklen_t from_length = 0; int retry_count = 0; ipcom_proc_init(); ipcom_memset( &addr.ss, 0, sizeof( addr.ss ) ); ipcom_memcpy( &addr.sa, smp_opt_server.res->ai_addr, smp_opt_server.res->ai_addrlen ); linger.l_onoff = 1; linger.l_linger = 2; listen_socket = ipcom_socket( smp_opt_server.res->ai_family, smp_opt_server.res->ai_socktype, smp_opt_server.res->ai_protocol ); if (listen_socket == IP_SOCKERR) { ipcom_printf("Failed to create socket: %s"IP_LF, ipcom_strerror(ipcom_errno)); return_server = 1; ipcom_sem_post( sem_wait_server ); return; } if ( 0 != ipcom_setsockopt(listen_socket, IP_SOL_SOCKET, IP_SO_REUSEPORT, &opt_val, sizeof (opt_val)) ) { ipcom_printf("ipcom_setsockopt failed: %s"IP_LF, ipcom_strerror(ipcom_errno)); return_server = 1; ipcom_sem_post( sem_wait_server ); return; } addr.sin.sin_port = ip_htons( smp_opt_server.port + portadd ); /* port is in the same place for IPv4 and IPv6 */ if ( 0 != ipcom_bind( listen_socket, &addr.sa, sizeof( addr.ss ) ) ) { ipcom_printf("Failed to bind: %s"IP_LF, ipcom_strerror(ipcom_errno)); return_server = 1; ipcom_sem_post( sem_wait_server ); return; } buf = ipcom_malloc( smp_opt_server.num_bytes ); if ( smp_opt_server.tcp ) { if ( -1 == ipcom_listen( listen_socket, 0 ) ) { ipcom_printf("Listen failed: %s"IP_LF, ipcom_strerror(ipcom_errno)); return_server = 1; ipcom_sem_post( sem_wait_server ); return; } if ( verbose ) ipcom_printf("Thread %d listens to %s:%d"IP_LF, portadd, smp_opt_server.res->ai_canonname, ip_ntohs( addr.sin.sin_port ) ); } if ( 0 == ipcom_atomic_sub_and_return( &listen_wait, 1 ) ) { /* Send to the test-server or write to stdout? */ if ( server_out >= 0 ) { char ready[] = "Ready."; ipcom_socketwrite(server_out, ready, 8 ); } else ipcom_printf("Ready."IP_LF ); } if ( 0 != ipcom_socketioctl( listen_socket, IP_X_SIOCSINTR, &sec ) ) { ipcom_printf("ipcom_socketioctl failed: %s"IP_LF, ipcom_strerror(ipcom_errno)); return_server = 1; ipcom_sem_post( sem_wait_server ); return; } if ( smp_opt_server.tcp ) { retry: connect_sock = ipcom_accept( listen_socket, IP_NULL, 0 ); if ( -1 == connect_sock ) { if ( ipcom_errno == IP_ERRNO_EINTR ) { if ( verbose ) { if ( ++retry_count < 5 ) { ipcom_printf("Accept failed for thread %d: %s.. Retrying."IP_LF, portadd, ipcom_strerror(ipcom_errno)); goto retry; } } } ipcom_printf("Accept failed for thread %d: %s"IP_LF, portadd, ipcom_strerror(ipcom_errno)); return_server = 1; ipcom_socketclose( listen_socket ); ipcom_sem_post( sem_wait_server ); return; } if ( 0 != ipcom_socketioctl( connect_sock, IP_X_SIOCSINTR, &sec ) ) { ipcom_printf("ipcom_socketioctl failed: %s"IP_LF, ipcom_strerror(ipcom_errno)); return_server = 1; ipcom_sem_post( sem_wait_server ); return; } if ( 0 != ipcom_setsockopt( connect_sock, IP_SOL_SOCKET, IP_SO_LINGER, &linger, sizeof (linger)) ) { ipcom_printf("ipcom_setsockopt failed: %s"IP_LF, ipcom_strerror(ipcom_errno)); return_server = 1; ipcom_sem_post( sem_wait_server ); return; } } while ( 1 ) { num_recives++; if ( smp_opt_server.tcp ) bytes = ipcom_recv( connect_sock, buf, smp_opt_server.num_bytes, 0); else { bytes = ipcom_recvfrom( listen_socket, buf, smp_opt_server.num_bytes, 0, &from, &from_length ); if ( num_recives == 1 && 0 == smp_opt_server.tcp ) { sec = SECONDS_CLIENT+2+portadd; if ( 0 != ipcom_socketioctl( listen_socket, IP_X_SIOCSINTR, &sec ) ) { ipcom_printf("ipcom_socketioctl failed: %s"IP_LF, ipcom_strerror(ipcom_errno)); return_server = 1; ipcom_sem_post( sem_wait_server ); return; } } } if ( bytes > 0 ) num_bytes += bytes; if (bytes == 0) { if ( verbose ) { ipcom_printf("Thread %d done."IP_LF, portadd ); ipcom_printf(" Recives: %d"IP_LF, num_recives ); ipcom_printf(" MB/s: %f"IP_LF, ((float)(num_bytes)/(1024.0f*1024.0f) )/5.0f ); } break; } else if (bytes < 0) { if ( ipcom_errno == IP_ERRNO_EINTR ) { if ( smp_opt_server.tcp ) { return_server = 1; ipcom_printf("Error! Out of time!"IP_LF ); break; } else { if ( verbose ) { ipcom_printf("Thread %d done."IP_LF, portadd ); ipcom_printf(" Recives: %d"IP_LF, num_recives ); ipcom_printf(" MB/s: %f"IP_LF, ((float)(num_bytes)/(1024.0f*1024.0f) )/5.0f ); } break; } } else if ( bytes == IP_SOCKERR ) /* Connection reset by peer */ { } return_server = 1; ipcom_printf("recv failed: %s"IP_LF, ipcom_strerror(ipcom_errno)); return; } } if ( verbose ) { if ( spawn_number_server != smp_opt_server.num_sock ) { ipcom_printf("Error. Only %d server-sockets seemed to work."IP_LF, spawn_number_server ); } } if ( smp_opt_server.tcp ) ipcom_shutdown( connect_sock, IP_SHUT_RDWR ); ipcom_free( buf ); ipcom_socketclose( listen_socket ); if ( 0 == ipcom_atomic_sub_and_return( &num_wait_server, 1 ) ) ipcom_sem_post( sem_wait_server ); if ( smp_opt_server.tcp ) ipcom_socketclose( connect_sock ); ipcom_proc_exit(); } /* *=========================================================================== * ipcom_cmd_smptest_client *=========================================================================== * Description: This is the client part of the smptest command * Parameters: The address we should connect to, and info about how many sockets * we should use. * Returns: 0 on success. -1 on failure. */ IP_STATIC int ipcom_cmd_smptest_client() { Ipcom_proc_attr attr; unsigned int i; int retval; spawn_number_client = 0; if ( 0 != ipcom_sem_create( &sem_wait_client, 0 ) ) { ipcom_printf("ipcom_sem_create failed: %s"IP_LF, ipcom_strerror(ipcom_errno)); return -1; } ipcom_atomic_set( &num_wait_client, smp_opt_client.num_sock ); ipcom_proc_attr_init(&attr); attr.priority = IPCOM_PRIORITY_DEFAULT; for ( i = 0;i < smp_opt_client.num_sock;++i ) { retval = ipcom_proc_acreate("ipcom_cmd_smptest_client_spawn", (Ipcom_proc_func)ipcom_cmd_smptest_client_spawn, &attr, 0 ); if (retval != 0) { ipcom_printf( "Error spawning smptest client"IP_LF ); return retval; } } ipcom_sem_wait( sem_wait_client ); /* wait for tasks to complete */ ipcom_sem_delete( &sem_wait_client ); return 0; } /* *=========================================================================== * ipcom_cmd_smptest_client_spawn *=========================================================================== * Description: This is the server spawn part of the smptest command * Parameters: None * Returns: Nothing. */ IP_STATIC IPCOM_PROCESS( ipcom_cmd_smptest_client_spawn ) { union { struct Ip_sockaddr sa; #ifdef IPCOM_USE_INET6 struct Ip_sockaddr_in6 sin6; #endif struct Ip_sockaddr_storage ss; struct Ip_sockaddr_in sin; } addr; Ip_fd socket; unsigned char *buf = 0; int portadd = spawn_number_client++; int opt_val = 1; int sec = SECONDS_CLIENT; int send = 0; int num_sends = 0; unsigned long num_bytes = 0; ipcom_proc_init(); ipcom_memset( &addr.ss, 0, sizeof( addr.ss ) ); ipcom_memcpy( &addr.sa, smp_opt_client.res->ai_addr, smp_opt_client.res->ai_addrlen ); socket = ipcom_socket( smp_opt_client.res->ai_family, smp_opt_client.res->ai_socktype, smp_opt_client.res->ai_protocol ); if (socket == IP_SOCKERR) { ipcom_printf("Failed to create socket for thread %d: %s"IP_LF, portadd, ipcom_strerror(ipcom_errno)); return_client = 1; ipcom_sem_post( sem_wait_client ); return; } if ( 0 != ipcom_setsockopt(socket, IP_SOL_SOCKET, IP_SO_REUSEPORT, &opt_val, sizeof (opt_val)) ) { ipcom_printf("ipcom_setsockopt failed: %s"IP_LF, ipcom_strerror(ipcom_errno)); return_client = 1; ipcom_sem_post( sem_wait_client ); return; } if ( 0 != ipcom_socketioctl( socket, IP_X_SIOCSINTR, &sec ) ) { ipcom_printf("ipcom_socketioctl failed: %s"IP_LF, ipcom_strerror(ipcom_errno)); return_client = 1; ipcom_sem_post( sem_wait_client ); return; } addr.sin.sin_port = ip_htons( smp_opt_client.port + portadd ); /* port is in the same place for IPv4 and IPv6 */ if ( smp_opt_client.tcp ) { if ( 0 != ipcom_connect( socket, &addr.sa, smp_opt_client.res->ai_addrlen ) ) { ipcom_printf("Thread %d failed to connect: %s"IP_LF, portadd, ipcom_strerror(ipcom_errno)); return_client = 1; ipcom_sem_post( sem_wait_client ); return; } if ( verbose ) ipcom_printf("Thread %d connected to port %d"IP_LF, portadd, smp_opt_client.port + portadd ); } buf = ipcom_malloc( smp_opt_client.num_bytes ); while ( 1 ) { if ( smp_opt_client.tcp ) send = ipcom_send( socket, buf, smp_opt_client.num_bytes, 0); else send = ipcom_sendto( socket, buf, smp_opt_client.num_bytes, 0, &addr.sa, smp_opt_client.res->ai_addrlen ); if ( send > 0 ) num_bytes += send; num_sends++; if ( send == 0 ) { ipcom_printf( "Error: Disconnected"IP_LF ); return_client = 1; break; } else if ( send < 0 ) { if ( ipcom_errno == IP_ERRNO_EINTR ) { if ( verbose ) { ipcom_printf("Thread %d done."IP_LF, portadd ); ipcom_printf(" Sends: %d"IP_LF, num_sends ); ipcom_printf(" MB/s: %f"IP_LF, ((float)(num_bytes)/(1024.0f*1024.0f) )/5.0f ); } break; } return_client = 1; ipcom_printf("Error on thread %d: %s"IP_LF, portadd, ipcom_strerror(ipcom_errno)); break; } } if ( verbose ) { if ( spawn_number_client != smp_opt_client.num_sock ) { ipcom_printf("Error. Only %d client-sockets seemed to work."IP_LF, spawn_number_client ); } } ipcom_socketclose( socket ); ipcom_free( buf ); if ( 0 == ipcom_atomic_sub_and_return( &num_wait_client, 1 ) ) ipcom_sem_post( sem_wait_client ); ipcom_proc_exit(); } /* **************************************************************************** * 10 GLOBAL FUNCTIONS **************************************************************************** */ /* **************************************************************************** * 11 PUBLIC FUNCTIONS **************************************************************************** */ IP_PUBLIC int ipcom_cmd_smptest(int argc, char **argv) { Ipcom_getopt opt; int c; struct Ip_addrinfo hints; struct Ip_addrinfo *res; char *hostname = "0.0.0.0"; char *servname = "8484"; int socktype = IP_SOCK_STREAM; int domain = IP_AF_INET; Ipcom_cmd_smptest_t smp_opt; return_client = 0; return_server = 0; verbose = 0; ipcom_memset(&smp_opt, 0, sizeof(smp_opt)); smp_opt.server = 1; smp_opt.ip4 = 1; smp_opt.tcp = 1; smp_opt.num_bytes = 1024; smp_opt.num_sock = 1; smp_opt.port = 8484; ipcom_getopt_clear_r(&opt); while ((c = ipcom_getopt_r(argc, argv, "l:p:s:c6uhv", &opt)) != -1) { switch(c) { case 'c': smp_opt.server = 0; if ( verbose ) ipcom_printf( "client"IP_LF ); break; case '6': smp_opt.ip4 = 0; domain = IP_AF_INET6; hostname = "::"; if ( verbose ) ipcom_printf( "IPv6"IP_LF ); break; case 'u': smp_opt.tcp = 0; socktype = IP_SOCK_DGRAM; if ( verbose ) ipcom_printf( "UDP"IP_LF ); break; case 'l': smp_opt.num_bytes = ipcom_atoi(opt.optarg); if ( verbose ) ipcom_printf( "num bytes: %d"IP_LF, smp_opt.num_bytes ); break; case 'p': servname = opt.optarg; smp_opt.port = ipcom_atoi(opt.optarg); if ( verbose ) ipcom_printf( "port: %s"IP_LF, servname ); break; case 's': smp_opt.num_sock = ipcom_atoi(opt.optarg); if ( smp_opt.num_sock > MAX_TASKS ) smp_opt.num_sock = MAX_TASKS; if ( verbose ) ipcom_printf( "sockets: %d"IP_LF, smp_opt.num_sock ); break; case 'v': verbose = 1; break; case 'h': ipcom_cmd_smptest_print_usage(); return -1; default: ipcom_printf("smptest: unknown option %c"IP_LF, (char)c); ipcom_cmd_smptest_print_usage(); return -1; } } if (opt.optind < argc) hostname = argv[opt.optind]; else { if ( 0 == smp_opt.server ) { if ( smp_opt.ip4 ) hostname = "127.0.0.1"; else hostname = "::1"; } } if ( verbose ) ipcom_printf( "%s : %s"IP_LF, hostname, servname ); ipcom_memset(&hints, 0, sizeof(hints)); hints.ai_socktype = socktype; hints.ai_flags = IP_AI_CANONNAME; hints.ai_family = domain; if (ipcom_getaddrinfo(hostname, servname, &hints, &res) != 0) { ipcom_printf("sockperf: getaddrinfo() failed"IP_LF); goto cleanup; } smp_opt.res = res; if ( smp_opt.server ) smp_opt_server = smp_opt; else smp_opt_client = smp_opt; if ( smp_opt.server == 1 ) { if ( 0 != ipcom_cmd_smptest_server() || 0 != return_server ) { ipcom_printf( "Failure."IP_LF ); goto cleanup; } } else { if ( 0 != ipcom_cmd_smptest_client() || 0 != return_client ) { ipcom_printf( "Failure"IP_LF ); goto cleanup; } } ipcom_printf( "Success." ); /* Success */ cleanup: ipcom_freeaddrinfo( res ); return 0; } #else int ipcom_cmd_smptest_empty_file; #endif /* #ifdef IPCOM_USE_SMPTEST_CMD */ /* **************************************************************************** * END OF FILE **************************************************************************** */