/* *=========================================================================== * ipcom_cmd_sockperf_tv_to_msec *=========================================================================== * Description: Returns the number of milliseconds between 2 absolute times. * Parameters: * Returns: */ IP_STATIC Ip_s32 ipcom_cmd_sockperf_tv_to_msec(struct Ip_timeval *start, struct Ip_timeval *stop) { Ip_s32 sec; Ip_s32 usec; usec = stop->tv_usec - start->tv_usec; sec = stop->tv_sec - start->tv_sec; if (usec < 0) { usec += 1000000; sec -= 1; } return IP_MAX(sec * 1000 + usec / 1000, 1); }
/* *=========================================================================== * ipcom_inet6_opt_next *=========================================================================== * Description: * Parameters: * Returns: * */ IP_PUBLIC int ipcom_inet6_opt_next(void *extbuf, Ip_socklen_t extlen, int offset, Ip_u8 *typep, Ip_socklen_t *lenp, void **databufp) { Ip_socklen_t current_offset; Ip_pkt_ip6_opt *opt = IP_NULL; current_offset = IP_MAX((int)sizeof(Ip_pkt_ip6_ext_hdr), offset); while (current_offset < extlen) { /* Skip PAD1 and PADN */ opt = (Ip_pkt_ip6_opt *) ((Ip_u8 *) extbuf + current_offset); if (opt->ip6o_type == IP_IP6OPT_PAD1) { current_offset++; continue; } if (current_offset + sizeof(Ip_pkt_ip6_opt) > extlen || current_offset + opt->ip6o_len > extlen) /* Extends beyond the buffer */ return -1; if (opt->ip6o_type == IP_IP6OPT_PADN) { current_offset += opt->ip6o_len + sizeof(Ip_pkt_ip6_ext_hdr); continue; } break; } if (current_offset >= extlen) /* No more options to return */ return -1; *typep = opt->ip6o_type; *lenp = opt->ip6o_len; *databufp = opt + 1; return (int)(current_offset + opt->ip6o_len + sizeof(Ip_pkt_ip6_ext_hdr)); }
/* *=========================================================================== * ipl2tps *=========================================================================== * Description: * Parameters: * Returns: * */ IP_STATIC IPCOM_PROCESS(ipl2tps) { Ip_fd ipd_fd = IP_INVALID_SOCKET; Ip_bool ipd_init = 0; #ifdef IPPPP_USE_PPPL2TP Ip_fd ipl2tp_ppp_ipc_recv_fd = IP_INVALID_SOCKET; #endif ipcom_proc_init(); #ifdef IPPPP_USE_PPPL2TP if ((ipl2tp_ppp_ipc_recv_fd = ipppp_pppl2tp_pkt_que_open()) == IP_INVALID_SOCKET) { ipcom_printf("Cannot allocate data packet output socket, errno: %d"IP_LF, ipcom_errno); goto leave; } #endif /* Get socket */ if ((udp_fd = ipcom_socket(IP_AF_INET, IP_SOCK_DGRAM, IP_IPPROTO_UDP)) < 0) { ipcom_printf("Cannot allocate socket, errno: %d"IP_LF, ipcom_errno); goto leave; } else { union Ip_sockaddr_union uaddr; /* Bind to L2TP port */ ipcom_memset(&uaddr, 0, sizeof(uaddr)); uaddr.sin.sin_family = IP_AF_INET; uaddr.sin.sin_addr.s_addr = IP_INADDR_ANY; uaddr.sin.sin_port = ip_htons(IPL2TP_PORT_NUMBER); uaddr.sin.sin_len = sizeof(struct Ip_sockaddr_in); if (ipcom_bind(udp_fd, &uaddr.sa, sizeof(struct Ip_sockaddr_in)) < 0) { ipcom_printf("Cannot bind socket, errno: %d"IP_LF, ipcom_errno); ipcom_socketclose(udp_fd); goto leave; } } /* Get socket */ if ((ip_fd = ipcom_socket(IP_AF_INET, IP_SOCK_RAW, IP_IPPROTO_L2TP)) < 0) { ipcom_printf("Cannot allocate socket, errno: %d"IP_LF, ipcom_errno); ipcom_socketclose(udp_fd); goto leave; } /* Init IPD */ if (ipd_init == 0 && ipcom_ipd_init("ipl2tp", IPCOM_SUCCESS, &ipd_fd) != IPCOM_SUCCESS) { ipcom_printf("Cannot initialize ipd: %s"IP_LF, ipcom_strerror(ipcom_errno)); goto leave; } ipd_init = 1; /* Enter read loop (never return) */ for (;;) { Ip_fd_set fds; Ipl2tp_example_fd_entry_t *fd; int fd_max; struct Ip_timeval tv; int ret; IP_FD_ZERO(&fds); IP_FD_SET(udp_fd, &fds); IP_FD_SET(ip_fd, &fds); IP_FD_SET(ipd_fd, &fds); fd_max = IP_MAX(udp_fd, ip_fd); fd_max = IP_MAX(fd_max, ipd_fd); #ifdef IPPPP_USE_PPPL2TP IP_FD_SET(ipl2tp_ppp_ipc_recv_fd, &fds); fd_max = IP_MAX(fd_max, ipl2tp_ppp_ipc_recv_fd); #endif fd = IPCOM_LIST_FIRST(&ipl2tp_example_fds); while (fd != IP_NULL) { Ipl2tp_example_fd_entry_t *nfd = IPCOM_LIST_NEXT(&fd->next); if (fd->data != IP_NULL) { IP_FD_SET(fd->fd, &fds); fd_max = IP_MAX(fd_max, fd->fd); } else { ipcom_list_remove(&fd->next); ipcom_socketclose(fd->fd); ipcom_free(fd); } fd = nfd; } tv.tv_sec = 0; tv.tv_usec = 10000; if ((ret = ipcom_socketselect(fd_max + 1, &fds, IP_NULL, IP_NULL, &tv)) > 0) { union Ip_sockaddr_union uaddr; int length; Ip_u8 *buffer; if (IP_FD_ISSET(ipd_fd, &fds)) { int event; event = ipcom_ipd_input(ipd_fd); if (event == IPCOM_IPD_EVENT_RECONFIGURE) goto leave; } #ifdef IPPPP_USE_PPPL2TP if (IP_FD_ISSET(ipl2tp_ppp_ipc_recv_fd, &fds)) { Ipppp_pppl2tp_pkt_que_entry que_entry; Ipcom_netif *netif; Ipcom_pkt *pkt; char addrstr[IP_INET_ADDRSTRLEN]; /* Read message and feed it to L2TP main input */ if (ipppp_pppl2tp_pkt_que_recv(&que_entry, &uaddr) == IPCOM_SUCCESS) { if ((que_entry.netif == IP_NULL) || (que_entry.pkt == IP_NULL)) { ipcom_printf("ipl2tps: L2TPv2 pkt from %s:%d contains null ptr(s)."IP_LF, ipcom_inet_ntop(IP_AF_INET, &uaddr.sin.sin_addr, addrstr, sizeof(addrstr)), ipcom_ntohs(uaddr.sin.sin_port)); } else { pkt = que_entry.pkt; netif = que_entry.netif; ipppp_pppl2tp_output(netif, pkt); } } else ipcom_printf("ipl2tps: PPP pkt recv failed."IP_LF); } #endif /* IPPPP_USE_PPPL2TP */ if (IP_FD_ISSET(udp_fd, &fds)) { /* Read message and feed it to L2TP main input */ if ((length = ipl2tp_l2tp_read(udp_fd, &buffer, &uaddr)) > 0) { ipl2tp_api_l2tp_input(buffer, buffer + HEADER_SPACE, (Ip_u16)length, &uaddr, IPL2TP_ATTR_TRANSPORT_UDP); /* Free buffer if not in PPP output queue */ if (ipl2tp_buffer_free) { ipl2tp_cache_free(buffer); } } } if (IP_FD_ISSET(ip_fd, &fds)) { /* Read message and feed it to L2TP main input */ if ((length = ipl2tp_l2tp_read(ip_fd, &buffer, &uaddr)) > 0) { /* Remove the IP header before invoking */ ipl2tp_api_l2tp_input(buffer, buffer + HEADER_SPACE + 20, (Ip_u16)(length - 20), &uaddr, IPL2TP_ATTR_TRANSPORT_IP); /* Free buffer if not in PPP output queue */ if (ipl2tp_buffer_free) { ipl2tp_cache_free(buffer); } } } fd = IPCOM_LIST_FIRST(&ipl2tp_example_fds); while (fd != IP_NULL) { Ipl2tp_example_fd_entry_t *nfd = IPCOM_LIST_NEXT(&fd->next); if (fd->data!= IP_NULL && IP_FD_ISSET(fd->fd, &fds)) { /* Read message and feed it to L2TP main input */ if ((length = ipl2tp_l2tp_read(fd->fd, &buffer, &uaddr)) > 0) { if (fd->data != IP_NULL) { (*fd->data) (fd, buffer, buffer + HEADER_SPACE, length); } /* Free buffer if not in PPP output queue */ if (ipl2tp_buffer_free) { ipl2tp_cache_free(buffer); } } } fd = nfd; } } else if (ret < 0) { ipcom_printf("select error"IP_LF); } } leave: /* Have to call ipd init if not done yet */ if (ipd_init == 0 && ipcom_ipd_init("ipl2tp", IPCOM_ERR_FAILED, &ipd_fd) == IPCOM_SUCCESS) { ipd_init = 1; } if (ipd_init != 0) { (void)ipcom_ipd_exit("ipl2tp", ipd_fd); } ipcom_proc_exit(); }
/* *=========================================================================== * ipnet_usr_sock_tcp_pkts_from_iov *=========================================================================== * Description: Copies the user data into MSS sized packets. * Parameters: sock - The socket that will be use to send. * msg - 'msg_iov' contains the buffer(s) to send. * flags - IP_MSG_xxx flags. * offset - Number of bytes into the msg->msg_iov buffers * where the copy into packets should start. * total_buf_len - the sum of the length of all * msg->msg_iov buffers in 'msg'. * ppkt - Will point to the created packet(s) if the * operation is successfil. The (*ppkt)->next * points to the next packet in case of more than * one packet was allocated. * Returns: <0 = error code (-IPNET_ERRNO_xxx) * 0 = this operation released the socket lock, the * sendmsg operation must be restarted * >0 = number of bytes that has been allocated in the * socket send buffer and copied into the * packet(s) pointed to by *ppkt. */ IP_STATIC int ipnet_usr_sock_tcp_pkts_from_iov(Ipnet_socket *sock, IP_CONST struct Ip_msghdr *msg, int flags, int offset, int total_buf_len, Ipcom_pkt **ppkt) { Ipcom_pkt *pkt_head; Ipcom_pkt *pkt_tail; Iptcp_tcb *tcb = sock->tcb; int mss = tcb->mss; Ip_u8 *buf; int buf_len; int i = 0; int len = 0; int bytes_to_copy = total_buf_len - offset; Ip_bool non_blocking; Ip_bool urgent = IP_BIT_ISSET(flags, IP_MSG_OOB); *ppkt = IP_NULL; /* * If offset == total_buf_len, which can in particular happen * if both are zero, then the loop immediately below can * access beyond the end of the iovec array. Avoid this. */ if (offset == total_buf_len) return 0; for (buf_len = 0; buf_len <= 0; offset = - buf_len) { struct Ip_iovec *iov = &msg->msg_iov[i++]; buf = (Ip_u8 *) iov->iov_base + offset; buf_len = (int) iov->iov_len - offset; } if (IP_LIKELY(urgent == IP_FALSE)) { iptcp_partial_lock(tcb->send.partial_lock); if (tcb->send.partial != IP_NULL) { len = ipnet_sock_tcp_append_send_data(tcb->send.partial, &buf, &buf_len, mss); if (len > 0) ipcom_atomic_add(&sock->snd_bytes, len); } iptcp_partial_unlock(tcb->send.partial_lock); if (len == bytes_to_copy) /* All data that should be sent was queued to the end of the partial finished TCP segment */ return len; } /* else: urgent packet must be sent in a separate signal since the flag field must have IP_MSG_OOB set for correct processing. */ non_blocking = IP_BIT_ISSET(sock->flags, IPNET_SOCKET_FLAG_NONBLOCKING) || IP_BIT_ISSET(flags, IP_MSG_DONTWAIT); bytes_to_copy = 0; do { int bytes_to_alloc = IP_MIN(mss, buf_len - bytes_to_copy); if (ipcom_atomic_add_and_return(&sock->snd_bytes, bytes_to_alloc) < sock->send_max_bytes + bytes_to_alloc) { bytes_to_copy += bytes_to_alloc; } else { int lowat; ipcom_atomic_sub(&sock->snd_bytes, bytes_to_alloc); if (bytes_to_copy > 0 || non_blocking) break; lowat = IP_MAX(mss, (int) sock->tcb->send.lowat); lowat = IP_MIN(lowat, sock->send_max_bytes); (void)ipnet_usr_sock_wait_until_writable(sock, lowat, IP_NULL); if (sock->ipcom.so_errno) { ipcom_atomic_sub(&sock->snd_bytes, bytes_to_copy); return len > 0 && sock->ipcom.so_errno != IP_ERRNO_EINTR ? len : -sock->ipcom.so_errno; } } } while (bytes_to_copy < buf_len); pkt_head = IP_NULL; pkt_tail = IP_NULL; while (bytes_to_copy > 0) { Ipcom_pkt *pkt; int seg_len = IP_MIN(bytes_to_copy, mss); pkt = ipcom_pkt_malloc(mss + sock->max_hdrspace, IP_FLAG_FC_STACKCONTEXT | (non_blocking ? 0 : IP_FLAG_FC_BLOCKOK)); if (IP_UNLIKELY(pkt == IP_NULL)) break; pkt->start = (pkt->maxlen - mss) & ~0x3; pkt->end = pkt->start + seg_len; pkt->chk = ipnet_in_checksum_memcpy(&pkt->data[pkt->start], buf, seg_len); /* Add this packet to the list of packets that will be sent to ipnetd */ if (pkt_head == IP_NULL) pkt_head = pkt; else pkt_tail->next = pkt; pkt_tail = pkt; len += seg_len; buf += seg_len; bytes_to_copy -= seg_len; } if (IP_LIKELY(pkt_tail != IP_NULL)) { if (IP_UNLIKELY(urgent)) IPNET_MARK_PKT_AS_URGENT(pkt_tail); iptcp_partial_lock(tcb->send.partial_lock); tcb->send.partial = pkt_tail; iptcp_partial_unlock(tcb->send.partial_lock); } *ppkt = pkt_head; return (len == 0 ? -IP_ERRNO_EWOULDBLOCK : len); }
/* *=========================================================================== * ipcom_waitif_gifaddr *=========================================================================== * Description: Get interface address. * Parameters: fd - socket descriptor * ifindex - Interface index. * domain - The address domain. * Returns: 0 = No address available, 1 = No address available, -1 = error. * */ IP_STATIC int ipcom_waitif_gifaddr(Ip_fd fd, int ifindex, int domain) { int ret = -1; switch (domain) { case IP_AF_INET: { struct Ip_ifreq ifreq; /* Get if name */ ipcom_memset(&ifreq, 0, sizeof(ifreq)); (void)ipcom_if_indextoname(ifindex, ifreq.ifr_name); /* Get main address */ if (ipcom_socketioctl(fd, IP_SIOCGIFADDR, &ifreq) < 0) { if (ipcom_errno != IP_ERRNO_EADDRNOTAVAIL && ipcom_errno != IP_ERRNO_ENXIO) { IPCOM_LOG1(ERR, "ipcom_waitif :: ipcom_socketioctl(SIOCGIFADDR) failed, errno = %d", ipcom_errno); } } else { struct Ip_in_addr network = ((struct Ip_sockaddr_in *)&ifreq.ip_ifr_addr)->sin_addr; if (network.s_addr != IP_INADDR_DEFAULT) { ret = 0; } } break; } #ifdef IPCOM_USE_INET6 case IP_AF_INET6: { int len = IPNET_WAITIF_MAXIF * sizeof(struct Ip_ifreq); char ifname[IP_IFNAMSIZ]; struct Ip_ifconf ifc; char *buf = IP_NULL; char *ptr; /* Get if name */ (void)ipcom_if_indextoname(ifindex, ifname); /* Get if data buffer */ if ((buf = ipcom_malloc(IPNET_WAITIF_MAXIF * sizeof(struct Ip_ifreq))) == IP_NULL) { IPCOM_LOG0(ERR, "ipcom_waitif :: Out of memory"); goto leave; } /* Enter buf in ifconf struct */ ifc.ifc_len = len; ifc.ip_ifc_buf = buf; if (ipcom_socketioctl(fd, IP_SIOCGIFCONF, &ifc) < 0) { IPCOM_LOG1(ERR, "ipcom_socketioctl(SIOCGIFCONF) failed, errno = %d\n", ipcom_errno); goto leave; } /* Loop for all interfaces */ for (ptr = buf; ptr < buf + ifc.ifc_len; ) { struct Ip_ifreq *ifr = (struct Ip_ifreq *)ptr; char *cptr; /* Calculate pointer to next if */ len = IP_MAX(sizeof(struct Ip_sockaddr_in), ifr->ip_ifr_addr.sa_len); ptr += sizeof(ifr->ifr_name) + len; if ((cptr = ipcom_strchr(ifr->ifr_name, ':')) != IP_NULL) { *cptr = '\0'; } /* Only for v6 addresses */ if (ipcom_strcmp(ifr->ifr_name, ifname) == 0 && ifr->ip_ifr_addr.sa_family == IP_AF_INET6) { struct Ip_sockaddr_in6 *in6 = (struct Ip_sockaddr_in6 *)&ifr->ip_ifr_addr; if (!IP_IN6_IS_ADDR_UNSPECIFIED(&in6->sin6_addr)) { ret = 0; break; } } } leave: if (buf != IP_NULL) { ipcom_free(buf); } break; } #endif /* IPCOM_USE_INET6 */ } return ret; }
/* *=========================================================================== * ipcom_shell_run_extcmd *=========================================================================== * Description: Starts a shell command process and delivers the command arguments * and stdio socket to that process. * Parameters: argc, argv - traditional command arguments * stdio_fd - the standard input, output and error sock * ppid - parent pid * cmd_pid - shell command process id * * Returns: 1 : command process started * 0 : not an external command * -1 : error * */ IP_PUBLIC Ip_err ipcom_shell_run_extcmd(int argc, char **argv, Ip_fd *stdio_fd, Ip_pid_t ppid, Ip_u32 seqno, Ip_pid_t *cmd_pid, int *proc_index) { Ipcom_proc_attr attr; Ipcom_ipc ipc; Ipcom_shellcmd_info *sinfo; Ipcom_shell_cmd *cmd = IP_NULL; Ipcom_shell_cmd *tcmd; Ip_err retval; char procname[40]; Ip_u32 stack = IPCOM_PROC_STACK_DEFAULT; Ip_pid_t pid; pid = ipcom_getpid(); ipcom_sprintf(procname, "ipcom_sc_0x%lx_%d", (Ip_u32)pid, *proc_index); /* Find command and max stack size (since we are reusing the process). */ if (argc > 0) { for (tcmd = IPCOM_LIST_FIRST(&ipcom_shell_cmd_head); tcmd; tcmd = IPCOM_LIST_NEXT(&tcmd->cmd_list)) { stack = (Ip_u32)IP_MAX(stack, tcmd->stack_size); if (cmd == IP_NULL && ipcom_strcmp(tcmd->name, argv[0]) == 0) { cmd = tcmd; if (*cmd_pid != 0) break; } } if (cmd == IP_NULL) return 0; /* Start the shell_cmd process. */ if (*cmd_pid == 0) { ipcom_proc_attr_init(&attr); attr.priority = (Ip_u32)cmd->priority; attr.stacksize = stack; attr.flags |= IPCOM_PROC_FLAG_FP; if (ipcom_proc_acreate(procname, (Ipcom_proc_func)ipcom_shell_cmd, &attr, cmd_pid)) { IPCOM_LOG0(ERR, "ipcom_shell_run_extcmd :: ipcom_proc_acreate() failed"); goto fail; } ip_assert(*cmd_pid != 0); } } else { /* argc == 0 is used to kill the shell_cmd process. */ ip_assert(*cmd_pid != 0); } /* Open IPC with ipcom_shell. */ retval = ipcom_ipc_open(&ipc, procname, -1); if (retval != IPCOM_SUCCESS) { IPCOM_LOG2(ERR, "ipcom_shell_run_extcmd :: ipcom_ipc_open(%s) failed, ret = %d", procname, retval); goto fail; } /* Send a message to ipcom_shell. */ sinfo = ipcom_ipc_malloc(sizeof(Ipcom_shellcmd_info)); if (sinfo == IP_NULL) { IPCOM_LOG1(ERR, "ipcom_shell_run_extcmd :: ipcom_ipc_malloc() failed, ret = %d", retval); goto fail; } /* Fill in IPC info. */ sinfo->argc = argc; if (argc > 0) { sinfo->hook = cmd->hook; sinfo->argv = argv; sinfo->fd = *stdio_fd; sinfo->pid = pid; sinfo->ppid = ppid; sinfo->seqno = seqno; #if IPCOM_USE_FILE != IPCOM_FILE_NONE if (ipcom_getcwd(sinfo->cwd, sizeof(sinfo->cwd)) == IP_NULL) ipcom_memset(sinfo->cwd, 0, sizeof(sinfo->cwd)); else sinfo->cwd[sizeof(sinfo->cwd)-1] = '\0'; #endif sinfo->prio = cmd->priority; } /* Send the IPC info. */ retval = ipcom_ipc_send(&ipc, sinfo); if (retval != IPCOM_SUCCESS) { IPCOM_LOG1(ERR, "ipcom_shell_run_extcmd :: ipcom_ipc_send() failed, ret = %d", retval); ipcom_ipc_free(sinfo); goto fail; } (void)ipcom_ipc_close(&ipc); #ifdef IP_PORT_OSE5 if (argc > 0) { /* OSE5 has process specific sockets -> donate child fd */ ip_assert(*cmd_pid != 0); retval = (Ip_err)efs_donate_fd(*stdio_fd, *cmd_pid); if (retval != 0) { IPCOM_LOG1(ERR, "ipcom_shell_run_extcmd :: efs_donate_fd, ret = %d", retval); goto fail; } } #endif /* IP_PORT_OSE5 */ /* Wait for exit message from shell_cmd process. */ retval = ipcom_ipc_receive(IP_NULL, &sinfo, -1); if (retval != IPCOM_SUCCESS) { IPCOM_LOG1(ERR, "ipcom_shell_run_extcmd :: ipcom_ipc_receive(shell_cmd) failed, ret = %d", retval); goto fail; } ip_assert(argc > 0 || *(Ip_u32 *)sinfo == 1); if (*(Ip_u32 *)sinfo == 1) { *cmd_pid = 0; /* shell command called ipcom_exit(). */ (*proc_index)++; } else { #ifdef IP_PORT_OSE5 *stdio_fd = efs_receive_fd(0); if (*stdio_fd == -1) { IP_PANIC(); goto fail; } #endif #if defined(IP_PORT_OSE) || defined(IP_PORT_OSE5) /* Change child socket owner (A must for OSE to work due to poor ipcom_block impl). */ pid = ipcom_getpid(); if (ipcom_socketioctl(*stdio_fd, IP_SIOCSPGRP, &pid) < 0) { IP_PANIC2(); IPCOM_LOG1(WARNING, "ipcom_shell_run_extcmd :: ipcom_socketioctl(IP_SIOCSPGRP) failed, errno = %d", ipcom_errno); } #endif } ipcom_ipc_free(sinfo); return 1; fail: if (ipcom_ipc_isopen(&ipc)) (void)ipcom_ipc_close(&ipc); return -1; }
/* *=========================================================================== * ipcom_cmd_sockperf_run *=========================================================================== * Description: Sends/receives data. * Parameters: * Returns: */ IP_STATIC void ipcom_cmd_sockperf_run(Ipcom_cmd_sockperf_t *cmd) { struct Ip_timeval tmo = { 0, 0 }; struct Ip_timeval *ptmo; struct Ip_timeval start; struct Ip_timeval stop; Ip_u32 i; Ip_u32 c; int num_ready; Ip_fd *s = cmd->sock_array; Ip_u32 total_bytes_to_send = cmd->num_buf * cmd->buf_len; Ip_u32 finished_sockets = 0; Ip_u32 total_bytes_read = 0; Ip_ssize_t bytes; Ip_fd_set read_set; int send_flags = (cmd->transmit && cmd->receive) ? IP_MSG_DONTWAIT : 0; if (cmd->transmit) ipcom_printf("sockperf-t: send buffer is %u"IP_LF, cmd->sendbuf_size); if (cmd->receive) ipcom_printf("sockperf-r: receive buffer is %u"IP_LF, cmd->sendbuf_size); for (i = 0; i < cmd->num_sock; i++) { int on = 1; if (ipcom_setsockopt(s[i], IP_SOL_SOCKET, IP_SO_REUSEADDR, &on, sizeof(on)) < 0) { ipcom_printf("sockperf-c: setsockopt IP_SO_REUSEADDR failed : %s"IP_LF, ipcom_strerror(ipcom_errno)); return; } if (ipcom_setsockopt(s[i], IP_SOL_SOCKET, IP_SO_SNDBUF, &cmd->sendbuf_size, sizeof(cmd->sendbuf_size)) < 0) { ipcom_printf("sockperf-c: setsockopt IP_SO_SNDBUF failed : %s"IP_LF, ipcom_strerror(ipcom_errno)); return; } if (ipcom_setsockopt(s[i], IP_SOL_SOCKET, IP_SO_RCVBUF, &cmd->recvbuf_size, sizeof(cmd->recvbuf_size)) < 0) { ipcom_printf("sockperf-c: setsockopt IP_SO_SNDBUF failed : %s"IP_LF, ipcom_strerror(ipcom_errno)); return; } } if (cmd->receive) { IP_FD_ZERO(&cmd->read_set); cmd->width = s[0]; IP_FD_SET(s[0], &cmd->read_set); for (i = 1; i < cmd->num_sock; i++) if (s[i] != IP_INVALID_SOCKET) { cmd->width = IP_MAX(cmd->width, s[i]); IP_FD_SET(s[i], &cmd->read_set); } } ipcom_microtime(&start); while ((cmd->transmit && total_bytes_to_send) || (cmd->receive && finished_sockets < cmd->num_sock)) { if (cmd->transmit && total_bytes_to_send) { for (i = 0; i < cmd->num_sock; i++) { if (cmd->testpattern) { /* Test patter is "[B|E|D]xxxxxx ", B = first 8 byte in buffer, E = last 8 bytes, D = all other */ for (c = 0; c < cmd->buf_len; c += 8) ipcom_sprintf(cmd->buf + c, "%c%06ld ", c == 0 ? '>' : (c >= cmd->buf_len - 8 ? '<' : '#'), cmd->send_pattern[i]++ % 1000000); } bytes = ipcom_send(s[i], cmd->buf, IP_MIN(cmd->buf_len, total_bytes_to_send), send_flags); if (bytes < 0 && ipcom_errno == IP_ERRNO_EWOULDBLOCK) (void)ipcom_sleep(0); else { if (bytes < 0) { ipcom_printf("sockperf-t: send failed : %s"IP_LF, ipcom_strerror(ipcom_errno)); return; } total_bytes_to_send -= bytes; } } if (cmd->receive && total_bytes_to_send == 0) for (i = 0; i < cmd->num_sock; i++) if (ipcom_shutdown(s[i], IP_SHUT_WR) < 0) { ipcom_printf("sockperf-t: shutdown failed: %s"IP_LF, ipcom_strerror(ipcom_errno)); return; } } if (cmd->receive) { ptmo = IP_NULL; while (finished_sockets < cmd->num_sock) { read_set = cmd->read_set; num_ready = ipcom_socketselect(cmd->width + 1, &read_set, IP_NULL, IP_NULL, ptmo); if (num_ready == 0) break; if (num_ready < 0) { ipcom_printf("sockperf-r: select failed: %s"IP_LF, ipcom_strerror(ipcom_errno)); return; } for (i = 0; i < cmd->num_sock; i++) { if (IP_FD_ISSET(s[i], &read_set)) { bytes = ipcom_recv(s[i], cmd->buf, cmd->buf_len, 0); if (bytes < 0) { ipcom_printf("sockperf-r: recv failed: %s"IP_LF, ipcom_strerror(ipcom_errno)); return; } if (cmd->testpattern) { if (cmd->echo) ipcom_cmd_sockperf_echo_buf(cmd->buf, bytes, cmd->recv_pattern[i]); for (c = 0; c < (Ip_u32)bytes; c += 8) { if (cmd->buf[c] != '#' && cmd->buf[c] != '>' && cmd->buf[c] != '<') { ipcom_printf("\nsockperf-r: test pattern error, expected B, D or E found %c(%d) offset %ld"IP_LF, cmd->buf[c], (int)cmd->buf[c], c); ipcom_cmd_sockperf_echo_buf(cmd->buf, bytes, 0); return; } if (ipcom_atoi(cmd->buf + c + 1) != (int)(cmd->recv_pattern[i]++ % 1000000)) { ipcom_printf("\nsockperf-r: test pattern error, was %d should be %ld offset %ld"IP_LF, ipcom_atoi(cmd->buf + c + 1), (cmd->recv_pattern[i] - 1) % 1000000, c); ipcom_cmd_sockperf_echo_buf(cmd->buf, bytes, 0); return; } } } if (bytes > 0) total_bytes_read += bytes; else { finished_sockets++; IP_FD_CLR(s[i], &cmd->read_set); } } } if (cmd->transmit && total_bytes_to_send) ptmo = &tmo; } } } ipcom_microtime(&stop); if (cmd->transmit) ipcom_printf("sockperf-t: %lu bytes sent in %ld ms (%lu kbyte/s)"IP_LF, cmd->num_buf * cmd->buf_len, ipcom_cmd_sockperf_tv_to_msec(&start, &stop), cmd->num_buf * cmd->buf_len / (Ip_u32)ipcom_cmd_sockperf_tv_to_msec(&start, &stop) * 1000 / 1024); if (cmd->receive) ipcom_printf("sockperf-r: %lu bytes read in %ld ms (%lu kbyte/s)"IP_LF, total_bytes_read, ipcom_cmd_sockperf_tv_to_msec(&start, &stop), total_bytes_read / (Ip_u32)ipcom_cmd_sockperf_tv_to_msec(&start, &stop) * 1000 / 1024); }