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;
}
IP_PUBLIC int
ipcom_socketpair_tcp(int fd[2])
{
	int server;
	union Ip_sockaddr_union  sock;
	Ip_socklen_t socklen;
	Ip_bool connected = IP_FALSE;
    int opt;
    struct Ip_addrinfo   hints;
    struct Ip_addrinfo  *res = IP_NULL;

	fd[0] = fd[1] = server = -1;

    ipcom_memset(&hints, 0, sizeof(hints));
    hints.ai_socktype = IP_SOCK_STREAM;
    if (ipcom_getaddrinfo(IP_NULL, "0", &hints, &res) != 0)
        goto failed;

    /* Server socket */
    server = ipcom_socket(res->ai_family, res->ai_socktype, res->ai_protocol);
	if (server == -1)
        goto failed;
    opt = 1;
	(void)ipcom_setsockopt(server, IP_SOL_SOCKET, IP_SO_REUSEADDR, &opt, sizeof(opt));
    if (ipcom_bind(server, res->ai_addr, res->ai_addrlen) != 0)
        goto failed;
	if (ipcom_listen(server, 1) != 0)
        goto failed;
    socklen = res->ai_addrlen;
	if (ipcom_getsockname(server, &sock.sa, &socklen) != 0)
        goto failed;

    /* Client socket */
    fd[1] = ipcom_socket(res->ai_family, res->ai_socktype, res->ai_protocol);
	if (fd[1] == -1)
        goto failed;
    opt = 1;
	(void)ipcom_setsockopt(fd[1], IP_SOL_SOCKET, IP_SO_REUSEADDR, &opt, sizeof(opt));
    opt = 1;
    (void)ipcom_socketioctl(fd[1], IP_FIONBIO, &opt);

	if (ipcom_connect(fd[1], &sock.sa, socklen) == -1)
    {
		if (ipcom_errno != IP_ERRNO_EINPROGRESS)
            goto failed;
	}
    else
		connected = IP_TRUE;

    /* Spawn socket */
    fd[0] = ipcom_accept(server, IP_NULL, IP_NULL);
	if (fd[0] == -1)
        goto failed;
    opt = 1;
	(void)ipcom_setsockopt(fd[0], IP_SOL_SOCKET, IP_SO_REUSEADDR, &opt, sizeof(opt));
	ipcom_socketclose(server);

    /* Client socket revisited */
	if (connected == IP_FALSE)
    {
        Ip_fd_set  write_set;
        IP_FD_ZERO(&write_set);
        IP_FD_SET(fd[1], &write_set);
        if (ipcom_socketselect(fd[1] + 1, IP_NULL, &write_set, IP_NULL, IP_NULL) != 1)
            goto failed;
	}
    opt = 0;
    (void)ipcom_socketioctl(fd[1], IP_FIONBIO, &opt);

    if (res != IP_NULL)
        ipcom_freeaddrinfo(res);
	return 0;

 failed:
    if (res != IP_NULL)
        ipcom_freeaddrinfo(res);
	if (fd[0] != -1)
        ipcom_socketclose(fd[0]);
	if (fd[1] != -1)
        ipcom_socketclose(fd[1]);
	if (server != -1)
        ipcom_socketclose(server);
	return -1;
}
/*
 *===========================================================================
 *                    ipcom_cmd_sockperf
 *===========================================================================
 * Description:
 * Parameters:
 * Returns:
 *
 */
IP_PUBLIC int
ipcom_cmd_sockperf(int argc, char **argv)
{
    Ipcom_getopt         opt;
    Ipcom_cmd_sockperf_t cmd;
    int                  c;
    struct Ip_addrinfo   hints;
    char                *hostname = "0.0.0.0";
    char                *servname = "7373";
    int                  socktype = IP_SOCK_STREAM;
    int                  domain = IP_AF_INET;

    if (argc < 2)
    {
        ipcom_cmd_sockperf_print_usage();
        return 0;
    }

    ipcom_memset(&cmd, 0, sizeof(cmd));
    cmd.buf_len         = 8192;
    cmd.num_buf         = 2048;
    cmd.num_sock        = 1;
    cmd.linger.l_onoff  = 1;
    cmd.linger.l_linger = 3;
    cmd.sendbuf_size    = 32767;
    cmd.recvbuf_size    = 16384;

    ipcom_getopt_clear_r(&opt);
    while ((c = ipcom_getopt_r(argc, argv, "6aeL:l:n:Pp:R:rs:T:tu", &opt)) != -1)
    {
        switch(c)
        {
        case '6':
            domain = IP_AF_INET6;
            hostname = "::";
            break;
        case 'a':
            cmd.accept = IP_TRUE;
            break;
        case 'e':
            cmd.echo = IP_TRUE;
            break;
        case 'L':
            cmd.linger.l_linger = ipcom_atoi(opt.optarg);
            break;
        case 'l':
            cmd.buf_len = ipcom_atoi(opt.optarg);
            break;
        case 'n':
            cmd.num_buf = ipcom_atoi(opt.optarg);
            break;
        case 'P':
            cmd.testpattern = IP_TRUE;
            break;
        case 'p':
            servname = opt.optarg;
            break;
        case 'R':
            cmd.recvbuf_size = ipcom_atoi(opt.optarg);
            break;
        case 'r':
            cmd.receive = IP_TRUE;
            break;
        case 's':
            cmd.num_sock = ipcom_atoi(opt.optarg);
            break;
        case 'T':
            cmd.sendbuf_size = ipcom_atoi(opt.optarg);
            break;
        case 't':
            cmd.transmit = IP_TRUE;
            break;
        case 'u':
            socktype = IP_SOCK_DGRAM;
            break;
        default:
            ipcom_printf("sockperf: unknown option %c"IP_LF, (char)c);
            return -1;
        }
    }

    if (cmd.testpattern)
    {
        if (cmd.buf_len & 0x7)
        {
            ipcom_printf("sockperf: the buffert (set with -l) must be a multiple of 8 when "
                         "using a test pattern"IP_LF);
            goto cleanup;
        }

        if (cmd.transmit)
        {
            cmd.send_pattern = ipcom_calloc(cmd.num_sock, sizeof(Ip_u32));
            if (cmd.send_pattern == IP_NULL)
            {
                ipcom_printf("sockperf: out of memory when allocating send pattern"IP_LF);
                goto cleanup;
            }
        }
        if (cmd.receive)
        {
            cmd.recv_pattern = ipcom_calloc(cmd.num_sock, sizeof(Ip_u32));
            if (cmd.recv_pattern == IP_NULL)
            {
                ipcom_printf("sockperf: out of memory when allocating receive pattern"IP_LF);
                goto cleanup;
            }
        }
    }

    if (opt.optind < argc)
        hostname = argv[opt.optind];

    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, &cmd.res) != 0)
    {
        ipcom_printf("sockperf: getaddrinfo() failed"IP_LF);
        goto cleanup;
    }

    cmd.buf = ipcom_malloc(cmd.buf_len + 1);
    if (cmd.buf == IP_NULL)
    {
        ipcom_printf("sockperf: Failed to allocate %lu bytes" IP_LF, cmd.buf_len);
        goto cleanup;
    }

    cmd.sock_array = ipcom_malloc(cmd.num_sock * sizeof(int));
    if (cmd.sock_array == IP_NULL)
    {
        ipcom_printf("sockperf: Failed to allocate %lu bytes for sockets" IP_LF,
                     cmd.num_sock * sizeof(int));
        goto cleanup;
    }

    if (cmd.accept)
        ipcom_cmd_sockperf_accept(&cmd);
    else
        ipcom_cmd_sockperf_connect(&cmd);

 cleanup:
    ipcom_free(cmd.send_pattern);
    ipcom_free(cmd.recv_pattern);
    ipcom_free(cmd.sock_array);
    ipcom_free(cmd.buf);
    ipcom_freeaddrinfo(cmd.res);
    return 0;
}
/*
 *===========================================================================
 *                    ipcom_start_shell
 *===========================================================================
 * Description: Starts a shell process and sets up a TCP connection. The
 *              TCP connection is used to convey stdin and stdout data. The
 *              stdio proxy process and the underlaying shell process is
 *              terminated by closing the socket. If the shell terminates
 *              (e.g. if the user gives the command 'exit') the stdio proxy
 *              will close the TCP connection and terminate.
 * Parameters:
 * Returns:
 *
 */
IP_PUBLIC Ip_err
ipcom_start_shell(Ip_fd *stdio_sock, Ip_fd client_fd)
{
    Ip_fd               mother = IP_INVALID_SOCKET;
    Ip_fd               shell_fd = IP_INVALID_SOCKET;
    Ip_socklen_t        addr_len;
    Ipcom_ipc           ipc;
    Ipcom_shell_info   *sinfo;
    char                procname[40];
    Ip_err              retval;
    Ipcom_proc_attr     attr;
    Ip_bool             ipc_opened = IP_FALSE;
    Ip_pid_t            ppid, shell_pid;
    Ip_u16              mother_port;
    static Ip_u32       seqno = 0;
    struct Ip_addrinfo  hints;
    struct Ip_addrinfo *res = IP_NULL;
    union Ip_sockaddr_union sa;

    *stdio_sock = IP_INVALID_SOCKET;

    sinfo = ipcom_ipc_malloc(sizeof(Ipcom_shell_info));
    if (sinfo == IP_NULL)
    {
        IPCOM_LOG0(ERR, "ipcom_start_shell :: ipcom_ipc_malloc() failed");
        goto exit;
    }
    addr_len = sizeof(sinfo->sa_prompt);
    if (ipcom_getsockname(client_fd, (struct Ip_sockaddr *)&sinfo->sa_prompt, &addr_len) == IP_SOCKERR)
    {
        IPCOM_LOG1(ERR, "ipcom_start_shell :: ipcom_getsockname(client_fd) failed, errno = %d", ipcom_errno);
        goto exit;
    }

    /* Get a tcp socket and let the stack pick a port */
    ipcom_memset(&hints, 0, sizeof(hints));
    hints.ai_family   = sinfo->sa_prompt.sa.sa_family;
    hints.ai_socktype = IP_SOCK_STREAM;
    if (ipcom_getaddrinfo(IP_NULL, "0", &hints, &res) != 0)
    {
        IPCOM_LOG1(ERR, "ipcom_start_shell :: ipcom_getsockname(client_fd) failed, errno = %d", ipcom_errno);
        goto exit;
    }

    mother = ipcom_socket(res->ai_family, res->ai_socktype, res->ai_protocol);
    if (mother == IP_INVALID_SOCKET)
    {
        IPCOM_LOG1(ERR, "ipcom_start_shell :: ipcom_socket(IP_AF_INET) failed, errno = %d", ipcom_errno);
        goto exit;
    }

    if (ipcom_bind(mother, res->ai_addr, res->ai_addrlen) == IP_SOCKERR)
    {
        IPCOM_LOG1(ERR, "ipcom_start_shell :: ipcom_bind(IP_AF_INET) failed, errno = %d", ipcom_errno);
        goto exit;
    }

    /* Find out which port was assigned. */
    addr_len = sizeof(sa);
    if (ipcom_getsockname(mother, (struct Ip_sockaddr *)&sa, &addr_len) == IP_SOCKERR)
    {
        IPCOM_LOG1(ERR, "ipcom_start_shell :: ipcom_getsockname(IP_AF_INET) failed, errno = %d", ipcom_errno);
        goto exit;
    }
    mother_port = ip_ntohs(sa.sin.sin_port);

    if (ipcom_listen(mother, 1) == IP_SOCKERR)
    {
        IPCOM_LOG1(ERR, "ipcom_start_shell :: ipcom_listen() failed, errno = %d", ipcom_errno);
        goto exit;
    }

    /* Create and start the shell process. */
    ipcom_proc_attr_init(&attr);
#ifdef IP_PORT_VXWORKS
    attr.stacksize = IPCOM_PROC_STACK_LARGE;
#else
    attr.priority = IPCOM_PRIORITY_DEFAULT;
#endif /* IP_PORT_VXWORKS */
    ppid = ipcom_getpid();
    ipcom_sprintf(procname, "ipcom_shell_%lx_%lx", (Ip_u32)ppid, ++seqno);
    if (ipcom_proc_acreate(procname, (Ipcom_proc_func)ipcom_shell, &attr, &shell_pid))
    {
        IPCOM_LOG0(ERR, "ipcom_start_shell :: ipcom_proc_acreate() failed");
        goto exit;
    }

    /* Open IPC with ipcom_shell. */
    retval = ipcom_ipc_open(&ipc, procname, -1);
    if (retval != IPCOM_SUCCESS)
    {
        IPCOM_LOG2(ERR, "ipcom_start_shell :: ipcom_ipc_open(%s) failed, ret = %d", procname, retval);
        goto exit;
    }
    ipc_opened = IP_TRUE;

    /* Send a message to ipcom_shell. */
    sinfo->port  = mother_port;
    sinfo->ppid  = ppid;
    sinfo->seqno = seqno;
    retval = ipcom_ipc_send(&ipc, sinfo);
    if (retval != IPCOM_SUCCESS)
    {
        IPCOM_LOG1(ERR, "ipcom_start_shell :: ipcom_ipc_send() failed, ret = %d", retval);
        goto exit;
    }

    /* Wait for the shell process to connect */
    shell_fd = ipcom_accept(mother, IP_NULL, IP_NULL);

exit:
    if (mother != IP_INVALID_SOCKET)
        (void)ipcom_socketclose(mother);
    if (res != IP_NULL)
        ipcom_freeaddrinfo(res);
    if (ipc_opened)
        (void)ipcom_ipc_close(&ipc);
    else if (sinfo != IP_NULL)
        ipcom_ipc_free(sinfo);

    if (shell_fd == IP_INVALID_SOCKET)
        return IPCOM_ERR_FAILED;
    else
    {
        int enable = IP_TRUE;

        *stdio_sock = shell_fd;
        /* Disable Nagle (enable no delay) on this socket since it is an
           interactive connection */
        (void)ipcom_setsockopt(shell_fd, IP_IPPROTO_TCP, IP_TCP_NODELAY, &enable, sizeof(enable));
        return IPCOM_SUCCESS;
    }
}