IP_PUBLIC int ipcom_rand(void) { long rnd = ipcom_random(); if (rnd < 0) rnd = -rnd; return (int)IP_MIN(rnd, IP_RAND_MAX); }
/* *=========================================================================== * ipnet_sock_tcp_append_send_data *=========================================================================== * Description: Append data to the last packet in the send queue up to * a full MSS segment. * Parameters: send_tail - The last element of the send queue. * pbuf - Pointer to the data buffer pointer. The buffer * pointer (*pbuf) will point to the first byte * that has not been copied. * plen - A pointer to the length length of *pbuf, will * contain the number of bytes not copied when this * function returns. * mss - The maximum segment size for this segment. * Returns: Number of bytes appended. * */ IP_STATIC int ipnet_sock_tcp_append_send_data(Ipcom_pkt *send_tail, Ip_u8 **pbuf, int *plen, int mss) { int bytes_appended; int len = *plen; if (mss <= send_tail->end - send_tail->start) /* mss must have been decresed after the send_tail was created */ return 0; bytes_appended = IP_MIN(mss - (send_tail->end - send_tail->start), len); ip_assert(bytes_appended >= 0); if (send_tail->chk != 0 && (send_tail->end & 0x1) == 0) { /* End is even, just add the checksum of the appended data to the current checksum */ send_tail->chk += ipnet_in_checksum_memcpy(&send_tail->data[send_tail->end], *pbuf, bytes_appended); } else { /* The checksum will be wrong unless the last odd byte is included in the new checksum, since odd bytes is handled as if the byte behind it is 0 (which is probably false now when more data is appended) */ ipnet_copy_from_user(&send_tail->data[send_tail->end], *pbuf, bytes_appended); /* Calculate the checksum when sending instead */ send_tail->chk = 0; } send_tail->end += bytes_appended; ip_assert(send_tail->end <= send_tail->maxlen); *pbuf = *pbuf + bytes_appended; *plen -= bytes_appended; return bytes_appended; }
/* *=========================================================================== * 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_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); }
/* *=========================================================================== * ipnet_rtnetlink_sock_send *=========================================================================== * Description: * Parameters: * Returns: * */ IP_GLOBAL int ipnet_rtnetlink_sock_send(Ipnet_socket *sock, Ip_bool non_blocking, struct Ip_nlmsghdr *nlmsg) { struct Ip_rtattr **rta = IP_NULL; int ret = 0; Ipnet_rtnetlink_func_table_t *tbl; int family; /* Need to retrieve the family byte */ if (nlmsg->nlmsg_len < IP_NLMSG_LENGTH(sizeof(struct Ip_rtgenmsg))) return 0; /* These messages are to be ignored */ if (nlmsg->nlmsg_type < IP_RTM_BASE) return 0; /**/ family = ((struct Ip_rtgenmsg*)IP_NLMSG_DATA(nlmsg))->rtgen_family; /* Dump */ if (IP_BIT_ISSET(nlmsg->nlmsg_flags, IP_NLM_F_DUMP) && ((nlmsg->nlmsg_type - IP_RTM_BASE) & 0x3) == 2) { ret = -IP_ERRNO_EAFNOSUPPORT; tbl = ipnet_rtnetlink_family_get_dump(ipnet->rtnetlink_links, family, nlmsg->nlmsg_type); if (tbl == IP_NULL) goto error_out; ret = ipnet_netlink_dump(tbl->nl_dump, family, sock, nlmsg, non_blocking); goto error_out; } tbl = ipnet_rtnetlink_family_get_do(ipnet->rtnetlink_links, family, nlmsg->nlmsg_type); if (tbl == IP_NULL) { ret = -IP_ERRNO_EAFNOSUPPORT; goto error_out; } else { struct Ip_rtattr *attr = IP_NULL; int attrlen = 0; /* Check minimum length. */ if (nlmsg->nlmsg_len < tbl->nl_size_min) { ret = -IP_ERRNO_EINVAL; goto error_out; } /* */ if (nlmsg->nlmsg_len > tbl->nl_size_min) { attrlen = nlmsg->nlmsg_len - IP_NLMSG_ALIGN(tbl->nl_size_min); attr = (struct Ip_rtattr*)((int)nlmsg + IP_NLMSG_ALIGN(tbl->nl_size_min)); } ret = ipnet_rtnetlink_parse(tbl->nl_rta_max, attr, attrlen, &rta); if (ret < 0) goto error_out; } /* DO */ ret = ipnet_rtnetlink_do(tbl->nl_do, family, sock, nlmsg, non_blocking, (void *)rta); error_out: if (rta) ipcom_free(rta); return IP_MIN(ret, 0); }