ssize_t recvmmsg_assume_fd_is_nonblocking( value v_fd, struct iovec *iovecs, value v_count, value v_srcs, struct mmsghdr *hdrs) { CAMLparam3(v_fd, v_count, v_srcs); CAMLlocal1(v_sockaddrs); size_t total_len = 0; union sock_addr_union addrs[Int_val(v_count)]; int i; for (i = 0; i < Int_val(v_count); i++) { hdrs[i].msg_hdr.msg_name = (Is_block(v_srcs) ? &addrs[i].s_gen : 0); hdrs[i].msg_hdr.msg_namelen = (Is_block(v_srcs) ? sizeof(addrs[i]) : 0); #if DEBUG fprintf(stderr, "i=%d, count=%d, is_some srcs=%d\n", i, Int_val(v_count), Is_block(v_srcs)); #endif total_len += iovecs[i].iov_len; hdrs[i].msg_hdr.msg_iov = &iovecs[i]; hdrs[i].msg_hdr.msg_iovlen = 1; hdrs[i].msg_hdr.msg_control = 0; hdrs[i].msg_hdr.msg_controllen = 0; hdrs[i].msg_hdr.msg_flags = 0; /* We completely ignore msg_flags and ancillary data (msg_control) for now. In the future, users may be interested in this. */ } ssize_t n_read; /* pszilagyi: This is only 64k in unix_utils.h, which we will very quickly overrun with recvmmsg and then maybe Jumbo frames. bnigito has already observed the Pico feed filling over 32 recvmmsg buffers in a single call, in a test scenario. */ if (total_len > THREAD_IO_CUTOFF) { caml_enter_blocking_section(); n_read = recvmmsg(Int_val(v_fd), hdrs, Int_val(v_count), 0, 0); caml_leave_blocking_section(); } else n_read = recvmmsg(Int_val(v_fd), hdrs, Int_val(v_count), 0, 0); if (n_read == -1) { /* bnigito via pszilagyi: This prototype performance tweak saves the allocation of an exception in common cases, at the cost of conflating reception of an empty message with nothing to do. */ if (errno == EWOULDBLOCK || errno == EAGAIN) n_read = -errno; else uerror("recvmmsg_assume_fd_is_nonblocking", Nothing); } else { if (Is_block(v_srcs)) { /* Some */ v_sockaddrs = Field(v_srcs, 0); for (i = 0; (unsigned)i < n_read && (unsigned)i < Wosize_val(v_sockaddrs); i++) Store_field(v_sockaddrs, i, alloc_sockaddr(&addrs[i], hdrs[i].msg_hdr.msg_namelen, -1)); } } CAMLreturnT(ssize_t, n_read); }
bool Bridge_ReceiveDDPData(void) { // LogExcess(VB_E131BRIDGE, "Bridge_ReceiveData()\n"); int msgcnt = recvmmsg(ddpSock, msgs, MAX_MSG, 0, nullptr); bool sync = false; while (msgcnt > 0) { for (int x = 0; x < msgcnt; x++) { sync |= Bridge_StoreDDPData((char*)buffers[x]); } msgcnt = recvmmsg(ddpSock, msgs, MAX_MSG, 0, nullptr); } return sync; }
void on_response(evutil_socket_t fd, short what, void *arg) { struct client_state *state = arg; struct timespec recv_time, result; if (what&EV_READ) { int retval = recvmmsg(state->sock, state->msgs, state->vlen, MSG_WAITFORONE, NULL); if (retval < 0) { perror("recvmmsg()"); exit(EXIT_FAILURE); } state->mps += retval; int i; for (i = 0; i < retval; i++) { state->bufs[i][state->msgs[i].msg_len] = 0; if (state->verbose) { printf("Received %d messages\n", retval); printf("%d %s %d\n", i+1, state->bufs[i], state->msgs[i].msg_len); } } gettime(&recv_time); int negative = timediff(&result, &recv_time, &state->send_time); if (negative) { fprintf(stderr, "Latency is negative\n"); } else { double latency = (result.tv_sec + ((double)result.tv_nsec) / 1e9); fprintf(state->fp, "%.9f\n", latency); } // clean receiving buffer send_message(state, retval); gettime(&state->send_time); } if (what&EV_TIMEOUT) { send_message(state, state->vlen); } }
int rcv_packet(int sock_raw, char *buffers, struct hdr_histogram *hist) { struct mmsghdr msgs[NUM_BUFFERS]; struct iovec entries[NUM_BUFFERS]; struct { struct cmsghdr cm; char control[512]; } control[NUM_BUFFERS]; struct timespec timeout; int valid_pkts = 0; int npkts = 0; memset(&timeout, 0, sizeof(timeout)); memset(msgs, 0, sizeof(msgs)); for (int i = 0; i < NUM_BUFFERS; ++i) { entries[i].iov_base = &buffers[i * BUFFER_SIZE]; entries[i].iov_len = BUFFER_SIZE; msgs[i].msg_hdr.msg_iov = &entries[i]; msgs[i].msg_hdr.msg_iovlen = 1; msgs[i].msg_hdr.msg_control = &control[i]; msgs[i].msg_hdr.msg_controllen = sizeof(control[i]); } npkts = recvmmsg(sock_raw, msgs, NUM_BUFFERS, MSG_WAITFORONE, &timeout); if (npkts < 0) { perror("recvmmsg()"); return 0; } for (int i = 0; i < npkts; ++i) { if (process_msg(&msgs[i].msg_hdr, &buffers[i * BUFFER_SIZE], hist)) valid_pkts += 1; } return valid_pkts; }
int udp_multirecv_read( udp_multirecv_t *um, int fd, int packets, struct iovec **iovec ) { static char use_emul = 0; int n, i; if (um == NULL || iovec == NULL) { errno = EINVAL; return -1; } if (packets > um->um_packets) packets = um->um_packets; if (!use_emul) { n = recvmmsg(fd, (struct mmsghdr *)um->um_msg, packets, MSG_DONTWAIT, NULL); } else { n = -1; errno = ENOSYS; } if (n < 0 && errno == ENOSYS) { use_emul = 1; n = recvmmsg_i(fd, (struct mmsghdr *)um->um_msg, packets, MSG_DONTWAIT); } if (n > 0) { for (i = 0; i < n; i++) um->um_riovec[i].iov_len = ((struct mmsghdr *)um->um_msg)[i].msg_len; *iovec = um->um_riovec; } return n; }
int main() { struct sigaction sa = {0}; sa.sa_handler = &timer_handler; sigaction(SIGALRM, &sa, NULL); struct itimerval timer = {0}; timer.it_value.tv_sec = 1; timer.it_interval.tv_sec = 1; setitimer(ITIMER_REAL, &timer, NULL); struct sockaddr_storage listen_addr; net_gethostbyname(&listen_addr, "::", 1234); int fd = net_bind_udp(&listen_addr); struct mmsghdr messages[MAX_MSG] = {0}; char buffers[MAX_MSG][MTU_SIZE]; struct iovec iovecs[MAX_MSG] = {0}; /* Setup recvmmsg data structures. */ int i; for (i = 0; i < MAX_MSG; i++) { char *buf = &buffers[i][0]; struct iovec *iovec = &iovecs[i]; struct mmsghdr *msg = &messages[i]; msg->msg_hdr.msg_iov = iovec; msg->msg_hdr.msg_iovlen = 1; iovec->iov_base = &buf[0]; iovec->iov_len = MTU_SIZE; } while (1) { int r = recvmmsg(fd, messages, MAX_MSG, MSG_WAITFORONE, NULL); if (r == 0) { return 0; } if (r < 0) { if (errno == EINTR) { continue; } PFATAL("recv()"); } else { for (i = 0; i < MAX_MSG; i++) { struct mmsghdr *msg = &messages[i]; bytes += msg->msg_len; msg->msg_len = 0; } packets += r; } } close(fd); return 0; }
static void graphite_run_recvmmsg(struct brubeck_graphite *graphite, int sock) { const unsigned int SIM_PACKETS = graphite->mmsg_count; struct brubeck_server *server = graphite->sampler.server; struct brubeck_graphite_msg msg; struct brubeck_metric *metric; unsigned int i; struct iovec iovecs[SIM_PACKETS]; struct mmsghdr msgs[SIM_PACKETS]; memset(msgs, 0x0, sizeof(msgs)); for (i = 0; i < SIM_PACKETS; ++i) { iovecs[i].iov_base = xmalloc(MAX_PACKET_SIZE); iovecs[i].iov_len = MAX_PACKET_SIZE - 1; msgs[i].msg_hdr.msg_iov = &iovecs[i]; msgs[i].msg_hdr.msg_iovlen = 1; } log_splunk("sampler=graphite event=worker_online syscall=recvmmsg socket=%d", sock); for (;;) { int res = recvmmsg(sock, msgs, SIM_PACKETS, 0, NULL); if (res < 0) { if (errno == EAGAIN || errno == EINTR) continue; log_splunk_errno("sampler=graphite event=failed_read"); brubeck_server_mark_dropped(server); continue; } /* store stats */ brubeck_atomic_add(&server->stats.metrics, SIM_PACKETS); brubeck_atomic_add(&graphite->sampler.inflow, SIM_PACKETS); for (i = 0; i < SIM_PACKETS; ++i) { char *buf = msgs[i].msg_hdr.msg_iov->iov_base; int len = msgs[i].msg_len; if (brubeck_graphite_msg_parse(&msg, buf, len) < 0) { log_splunk("sampler=graphite event=bad_key key='%.*s'", len, buf); brubeck_server_mark_dropped(server); continue; } metric = brubeck_metric_find(server, msg.key, msg.key_len, BRUBECK_MT_GAUGE); if (metric != NULL) brubeck_metric_record(metric, msg.value); } } }
static int data_deliver_fn ( int fd, int revents, void *data) { struct totemknet_instance *instance = (struct totemknet_instance *)data; struct mmsghdr msg_recv[MAX_BUFFERS]; struct iovec iov_recv[MAX_BUFFERS]; struct sockaddr_storage system_from; int msgs_received; int i; for (i=0; i<MAX_BUFFERS; i++) { iov_recv[i].iov_base = instance->iov_buffer[i]; iov_recv[i].iov_len = FRAME_SIZE_MAX; msg_recv[i].msg_hdr.msg_name = &system_from; msg_recv[i].msg_hdr.msg_namelen = sizeof (struct sockaddr_storage); msg_recv[i].msg_hdr.msg_iov = &iov_recv[i]; msg_recv[i].msg_hdr.msg_iovlen = 1; #ifdef HAVE_MSGHDR_CONTROL msg_recv[i].msg_hdr.msg_control = 0; #endif #ifdef HAVE_MSGHDR_CONTROLLEN msg_recv[i].msg_hdr.msg_controllen = 0; #endif #ifdef HAVE_MSGHDR_FLAGS msg_recv[i].msg_hdr.msg_flags = 0; #endif #ifdef HAVE_MSGHDR_ACCRIGHTS msg_recv[i].msg_hdr.msg_accrights = NULL; #endif #ifdef HAVE_MSGHDR_ACCRIGHTSLEN msg_recv[i].msg_hdr.msg_accrightslen = 0; #endif } msgs_received = recvmmsg (fd, msg_recv, MAX_BUFFERS, MSG_NOSIGNAL | MSG_DONTWAIT, NULL); if (msgs_received == -1) { return (0); } for (i=0; i<msgs_received; i++) { instance->stats_recv += msg_recv[i].msg_len; /* * Handle incoming message */ instance->totemknet_deliver_fn ( instance->context, instance->iov_buffer[i], msg_recv[i].msg_len); } return (0); }
extern int totemknet_recv_mcast_empty ( void *knet_context) { struct totemknet_instance *instance = (struct totemknet_instance *)knet_context; unsigned int res; struct sockaddr_storage system_from; struct mmsghdr msg_recv[MAX_BUFFERS]; struct iovec iov_recv[MAX_BUFFERS]; struct pollfd ufd; int nfds; int msg_processed = 0; int i; for (i=0; i<MAX_BUFFERS; i++) { iov_recv[i].iov_base = instance->iov_buffer[i]; iov_recv[i].iov_len = FRAME_SIZE_MAX; msg_recv[i].msg_hdr.msg_name = &system_from; msg_recv[i].msg_hdr.msg_namelen = sizeof (struct sockaddr_storage); msg_recv[i].msg_hdr.msg_iov = &iov_recv[i]; msg_recv[i].msg_hdr.msg_iovlen = 1; #ifdef HAVE_MSGHDR_CONTROL msg_recv[i].msg_hdr.msg_control = 0; #endif #ifdef HAVE_MSGHDR_CONTROLLEN msg_recv[i].msg_hdr.msg_controllen = 0; #endif #ifdef HAVE_MSGHDR_FLAGS msg_recv[i].msg_hdr.msg_flags = 0; #endif #ifdef HAVE_MSGHDR_ACCRIGHTS msg_recv[i].msg_hdr.msg_accrights = NULL; #endif #ifdef HAVE_MSGHDR_ACCRIGHTSLEN msg_recv[i].msg_hdr.msg_accrightslen = 0; #endif } do { ufd.fd = instance->knet_fd; ufd.events = POLLIN; nfds = poll (&ufd, 1, 0); if (nfds == 1 && ufd.revents & POLLIN) { res = recvmmsg (instance->knet_fd, msg_recv, MAX_BUFFERS, MSG_NOSIGNAL | MSG_DONTWAIT, NULL); if (res != -1) { msg_processed = 1; } else { msg_processed = -1; } } } while (nfds == 1); return (msg_processed); }
static void statsd_run_recvmmsg(struct brubeck_statsd *statsd, int sock) { const unsigned int SIM_PACKETS = statsd->mmsg_count; struct brubeck_server *server = statsd->sampler.server; struct brubeck_statsd_msg msg; struct brubeck_metric *metric; unsigned int i; struct iovec iovecs[SIM_PACKETS]; struct mmsghdr msgs[SIM_PACKETS]; memset(msgs, 0x0, sizeof(msgs)); for (i = 0; i < SIM_PACKETS; ++i) { iovecs[i].iov_base = xmalloc(MAX_PACKET_SIZE); iovecs[i].iov_len = MAX_PACKET_SIZE; msgs[i].msg_hdr.msg_iov = &iovecs[i]; msgs[i].msg_hdr.msg_iovlen = 1; } log_splunk("sampler=statsd event=worker_online syscall=recvmmsg socket=%d", sock); for (;;) { int res = recvmmsg(sock, msgs, SIM_PACKETS, 0, NULL); if (res == EAGAIN || res == EINTR || res == 0) continue; /* store stats */ brubeck_atomic_add(&server->stats.metrics, SIM_PACKETS); brubeck_atomic_add(&statsd->sampler.inflow, SIM_PACKETS); if (res < 0) { brubeck_server_mark_dropped(server); continue; } for (i = 0; i < SIM_PACKETS; ++i) { char *buf = msgs[i].msg_hdr.msg_iov->iov_base; int len = msgs[i].msg_len; if (brubeck_statsd_msg_parse(&msg, buf, len) < 0) { brubeck_server_mark_dropped(server); log_splunk("sampler=statsd event=packet_drop"); continue; } metric = brubeck_metric_find(server, msg.key, msg.key_len, msg.type); if (metric != NULL) brubeck_metric_record(metric, msg.value); } } }
int udp_multirecv_read( udp_multirecv_t *um, int fd, int packets, struct iovec **iovec ) { int n, i; if (packets > um->um_packets) packets = um->um_packets; n = recvmmsg(fd, (struct mmsghdr *)um->um_msg, packets, MSG_DONTWAIT, NULL); if (n > 0) { for (i = 0; i < n; i++) um->um_riovec[i].iov_len = ((struct mmsghdr *)um->um_msg)[i].msg_len; *iovec = um->um_riovec; } return n; }
static int do_cmsg_generic(int child, int use_recvmmsg) { int fd = do_open(child); /* launder it through SCM_RIGHTS */ char ch = 0; struct mmsghdr msgvec; struct msghdr* msg = &msgvec.msg_hdr; struct iovec iov; uint8_t cbuf[CMSG_SPACE(sizeof(fd))]; struct cmsghdr* cmsg; int sockfds[2]; test_assert(0 == socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfds)); iov.iov_base = "x"; iov.iov_len = 1; memset(msg, 0, sizeof(*msg)); msg->msg_iov = &iov; msg->msg_iovlen = 1; msg->msg_control = cbuf; msg->msg_controllen = sizeof(cbuf); cmsg = CMSG_FIRSTHDR(msg); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd)); test_assert(1 == sendmsg(sockfds[1], msg, 0)); iov.iov_base = &ch; if (use_recvmmsg) { test_assert(1 == recvmmsg(sockfds[0], &msgvec, 1, 0, NULL)); test_assert(1 == msgvec.msg_len); } else { test_assert(1 == recvmsg(sockfds[0], msg, 0)); } test_assert('x' == ch); cmsg = CMSG_FIRSTHDR(msg); test_assert(SOL_SOCKET == cmsg->cmsg_level && SCM_RIGHTS == cmsg->cmsg_type); memcpy(&fd, CMSG_DATA(cmsg), sizeof(fd)); close(sockfds[0]); close(sockfds[1]); return fd; }
static void statsd_run_recvmmsg(struct brubeck_statsd *statsd, int sock) { const unsigned int SIM_PACKETS = statsd->mmsg_count; struct brubeck_server *server = statsd->sampler.server; unsigned int i; struct iovec iovecs[SIM_PACKETS]; struct mmsghdr msgs[SIM_PACKETS]; memset(msgs, 0x0, sizeof(msgs)); for (i = 0; i < SIM_PACKETS; ++i) { iovecs[i].iov_base = xmalloc(MAX_PACKET_SIZE); iovecs[i].iov_len = MAX_PACKET_SIZE - 1; msgs[i].msg_hdr.msg_iov = &iovecs[i]; msgs[i].msg_hdr.msg_iovlen = 1; } log_splunk("sampler=statsd event=worker_online syscall=recvmmsg socket=%d", sock); for (;;) { int res = recvmmsg(sock, msgs, SIM_PACKETS, 0, NULL); if (res < 0) { if (errno == EAGAIN || errno == EINTR) continue; log_splunk_errno("sampler=statsd event=failed_read"); brubeck_stats_inc(server, errors); continue; } /* store stats */ brubeck_atomic_add(&statsd->sampler.inflow, SIM_PACKETS); for (i = 0; i < SIM_PACKETS; ++i) { char *buf = msgs[i].msg_hdr.msg_iov->iov_base; char *end = buf + msgs[i].msg_len; brubeck_statsd_packet_parse(server, buf, end); } } }
CAMLprim value iobuf_recvmmsg_assume_fd_is_nonblocking_stub (value v_fd, value v_iobufs, value v_recvmmsg_ctx) { CAMLparam3(v_fd, v_iobufs, v_recvmmsg_ctx); CAMLlocal1(v_iobuf); value v_lo_min; unsigned i; int n_read; struct mmsghdr * hdrs; struct iovec * iovecs; hdrs = Recvmmsg_ctx_ptr(v_recvmmsg_ctx)->hdrs; iovecs = Recvmmsg_ctx_ptr(v_recvmmsg_ctx)->iovecs; n_read = recvmmsg(Int_val(v_fd), hdrs, Wosize_val(v_iobufs), 0, 0); for (i = 0; (int) i < n_read; i++) { v_iobuf = Field(v_iobufs, i); v_lo_min = Field(v_iobuf, iobuf_lo_min); /* Here we fail if the user has called set_bounds_and_buffer, replacing the underlying * bigstring after we've cached the pointer. */ if (get_bstr(Field(v_iobuf, iobuf_buf), v_lo_min) != hdrs[i].msg_hdr.msg_iov->iov_base) { n_read = -1; errno = EINVAL; } else { /* Knowing the structure of an Iobuf record (which we already * are dependent on), we can use Field(v_iobuf, iobuf_lo) as an * lvalue and skip the caml_modify done by Store_field. */ Field(v_iobuf, iobuf_lo) = v_lo_min; Field(v_iobuf, iobuf_hi) = Val_long(Long_val(v_lo_min) + hdrs[i].msg_len); } } if (n_read == -1) n_read = -errno; CAMLreturn(Val_int(n_read)); }
static void* reader_thread(void* dontcare) { char token = '!'; int sock = sockfds[1]; struct timeval ts; char c = '\0'; int i; gettimeofday(&ts, NULL); atomic_puts("r: acquiring mutex ..."); pthread_mutex_lock(&lock); atomic_puts("r: ... releasing mutex"); pthread_mutex_unlock(&lock); for (i = 0; i < 2; ++i) { atomic_puts("r: reading socket ..."); gettimeofday(&ts, NULL); test_assert(1 == read(sock, &c, sizeof(c))); atomic_printf("r: ... read '%c'\n", c); test_assert(c == token); ++token; } /* TODO: readv() support */ atomic_puts("r: recv'ing socket ..."); gettimeofday(&ts, NULL); test_assert(1 == recv(sock, &c, sizeof(c), 0)); atomic_printf("r: ... recv'd '%c'\n", c); test_assert(c == token); ++token; atomic_puts("r: recvfrom'ing socket ..."); test_assert(1 == recvfrom(sock, &c, sizeof(c), 0, NULL, NULL)); atomic_printf("r: ... recvfrom'd '%c'\n", c); test_assert(c == token); ++token; { struct sockaddr_un addr; socklen_t addrlen = sizeof(addr); atomic_puts("r: recvfrom(&sock)'ing socket ..."); test_assert(1 == recvfrom(sock, &c, sizeof(c), 0, &addr, &addrlen)); atomic_printf("r: ... recvfrom'd '%c' from sock len:%d\n", c, addrlen); test_assert(c == token); /* socketpair() AF_LOCAL sockets don't identify * themselves. */ test_assert(addrlen == 0); ++token; } { struct mmsghdr mmsg = {{ 0 }}; struct iovec data = { 0 }; int magic = ~msg_magic; int err, ret; data.iov_base = &magic; data.iov_len = sizeof(magic); mmsg.msg_hdr.msg_iov = &data; mmsg.msg_hdr.msg_iovlen = 1; atomic_puts("r: recvmsg with DONTWAIT ..."); ret = recvmsg(sock, &mmsg.msg_hdr, MSG_DONTWAIT); err = errno; atomic_printf("r: ... returned %d (%s/%d)\n", ret, strerror(err), err); test_assert(-1 == ret && EWOULDBLOCK == err); atomic_puts("r: recmsg'ing socket ..."); test_assert(0 < recvmsg(sock, &mmsg.msg_hdr, 0)); atomic_printf("r: ... recvmsg'd 0x%x\n", magic); test_assert(msg_magic == magic); magic = ~msg_magic; atomic_puts("r: recmmsg'ing socket ..."); pthread_barrier_wait(&cheater_barrier); breakpoint(); test_assert(1 == recvmmsg(sock, &mmsg, 1, 0, NULL)); atomic_printf("r: ... recvmmsg'd 0x%x (%u bytes)\n", magic, mmsg.msg_len); test_assert(msg_magic == magic); } { struct msghdr msg = { 0 }; struct iovec iovs[2]; char c1 = '\0', c2 = '\0'; iovs[0].iov_base = &c1; iovs[0].iov_len = sizeof(c1); iovs[1].iov_base = &c2; iovs[1].iov_len = sizeof(c2); msg.msg_iov = iovs; msg.msg_iovlen = sizeof(iovs) / sizeof(iovs[0]); atomic_puts("r: recmsg'ing socket with two iovs ..."); test_assert(2 == recvmsg(sock, &msg, 0)); atomic_printf("r: ... recvmsg'd '%c' and '%c'\n", c1, c2); test_assert(c1 == token); token++; test_assert(c2 == token); token++; } { struct pollfd pfd; atomic_puts("r: polling socket ..."); pfd.fd = sock; pfd.events = POLLIN; gettimeofday(&ts, NULL); poll(&pfd, 1, -1); atomic_puts("r: ... done, doing nonblocking read ..."); test_assert(1 == read(sock, &c, sizeof(c))); atomic_printf("r: ... read '%c'\n", c); test_assert(c == token); ++token; } { struct pollfd pfd; atomic_puts("r: polling socket ..."); pfd.fd = sock; pfd.events = POLLIN; gettimeofday(&ts, NULL); ppoll(&pfd, 1, NULL, NULL); atomic_puts("r: ... done, doing nonblocking read ..."); test_assert(1 == read(sock, &c, sizeof(c))); atomic_printf("r: ... read '%c'\n", c); test_assert(c == token); ++token; } { fd_set fds; const struct timeval infinity = { 1 << 30, 0 }; struct timeval tv = infinity; int ret; atomic_puts("r: select()ing socket ..."); FD_ZERO(&fds); FD_SET(sock, &fds); ret = select(sock + 1, &fds, NULL, NULL, &tv); atomic_printf("r: ... returned %d; tv { %ld, %ld }\n", ret, tv.tv_sec, tv.tv_usec); test_assert(1 == ret); test_assert(FD_ISSET(sock, &fds)); test_assert(0 < tv.tv_sec && tv.tv_sec < infinity.tv_sec); atomic_puts("r: ... done, doing nonblocking read ..."); test_assert(1 == read(sock, &c, sizeof(c))); atomic_printf("r: ... read '%c'\n", c); test_assert(c == token); ++token; } { int epfd; struct epoll_event ev; atomic_puts("r: epolling socket ..."); test_assert(0 <= (epfd = epoll_create(1/*num events*/))); ev.events = EPOLLIN; ev.data.fd = sock; gettimeofday(&ts, NULL); test_assert(0 == epoll_ctl(epfd, EPOLL_CTL_ADD, ev.data.fd, &ev)); test_assert(1 == epoll_wait(epfd, &ev, 1, -1)); atomic_puts("r: ... done, doing nonblocking read ..."); test_assert(sock == ev.data.fd); test_assert(1 == read(sock, &c, sizeof(c))); atomic_printf("r: ... read '%c'\n", c); test_assert(c == token); ++token; close(epfd); } { char* buf = (char*)malloc(num_sockbuf_bytes); ssize_t nwritten = 0; struct iovec iov; ++token; memset(buf, token, num_sockbuf_bytes); atomic_printf("r: writing outbuf of size %d ...\n", num_sockbuf_bytes); while (nwritten < num_sockbuf_bytes) { ssize_t this_write = write(sock, buf, num_sockbuf_bytes - nwritten); atomic_printf("r: wrote %d bytes this time\n", this_write); nwritten += this_write; } ++token; memset(buf, token, num_sockbuf_bytes); iov.iov_base = buf; iov.iov_len = num_sockbuf_bytes; atomic_printf("r: writev()ing outbuf of size %d ...\n", num_sockbuf_bytes); while (iov.iov_len > 0) { ssize_t this_write = writev(sock, &iov, 1); atomic_printf("r: wrote %d bytes this time\n", this_write); iov.iov_len -= this_write; } free(buf); } atomic_puts("r: reading socket with masked signals ..."); { sigset_t old_mask, mask; sigfillset(&mask); test_assert(0 == pthread_sigmask(SIG_BLOCK, &mask, &old_mask)); test_assert(1 == read(sock, &c, sizeof(c))); test_assert(0 == pthread_sigmask(SIG_SETMASK, &old_mask, NULL)); } ++token; atomic_printf("r: ... read '%c'\n", c); test_assert(c == token); /* Make the main thread wait on our join() */ atomic_puts("r: sleeping ..."); usleep(500000); return NULL; }
int J1939SocketRead (int Socket, struct J1939FrameBag *Bags, unsigned int BagsCount, int TimeoutMs) { struct mmsghdr msgs[BagsCount]; struct iovec iovs[BagsCount]; struct sockaddr_can addr[BagsCount]; char ctrlmsgs[BagsCount][ CMSG_SPACE(sizeof(struct timeval)) + CMSG_SPACE(sizeof(__u8)) /* dest addr */ + CMSG_SPACE(sizeof(__u64)) /* dest name */ + CMSG_SPACE(sizeof(__u8)) /* priority */ ]; unsigned int i; for (i = 0; i < BagsCount; i++) { memset(&msgs[i], 0, sizeof(msgs[0])); memset(&iovs[i], 0, sizeof(iovs[0])); memset(&addr[i], 0, sizeof(addr[0])); msgs[i].msg_hdr.msg_name = &addr[i]; msgs[i].msg_hdr.msg_namelen = sizeof(struct sockaddr_can); iovs[i].iov_base = (void *) &(Bags[i].Frame.data); iovs[i].iov_len = sizeof(Bags[i].Frame.data); msgs[i].msg_hdr.msg_iov = &iovs[i]; msgs[i].msg_hdr.msg_iovlen = 1; msgs[i].msg_hdr.msg_control = &ctrlmsgs[i]; msgs[i].msg_hdr.msg_controllen = sizeof(ctrlmsgs[0]); msgs[i].msg_hdr.msg_flags = 0; } struct timeval tNow, tEnd; for ( initTimers(&tNow, &tEnd, TimeoutMs); timercmp(&tNow, &tEnd, <=); gettimeofday (&tNow, NULL) ) { int rcount; rcount = recvmmsg(Socket, msgs, BagsCount, MSG_DONTWAIT, NULL); if (rcount >= 0) { int i; for (i = 0; i < rcount; i ++) { struct timeval tv; struct cmsghdr *cmsg; for (cmsg = CMSG_FIRSTHDR(&msgs[i].msg_hdr); cmsg; cmsg = CMSG_NXTHDR(&msgs[i].msg_hdr,cmsg)) { switch (cmsg->cmsg_level) { case SOL_SOCKET: if (cmsg->cmsg_type == SO_TIMESTAMP) { tv = *(struct timeval *)CMSG_DATA(cmsg); Bags[i].TimeStamp.seconds = tv.tv_sec; Bags[i].TimeStamp.microseconds = tv.tv_usec; } else if (cmsg->cmsg_type == SO_RXQ_OVFL) Bags[i].DroppedMessagesCount = *(__u32 *)CMSG_DATA(cmsg); break; case SOL_CAN_J1939: break; } } Bags[i].Frame.pgn = addr[i].can_addr.j1939.pgn; Bags[i].Frame.length = msgs[i].msg_len; if (msgs[i].msg_hdr.msg_flags & MSG_CONFIRM) Bags[i].Flags |= (1 << 0); } return rcount; } else { int errsv = errno; if (errsv == EAGAIN) { usleep (100); continue; } else return errsv; } } return 0; }
int aeron_udp_channel_transport_recvmmsg( aeron_udp_channel_transport_t *transport, struct mmsghdr *msgvec, size_t vlen, aeron_udp_transport_recv_func_t recv_func, void *clientd) { #if defined(HAVE_RECVMMSG) struct timespec tv = {.tv_nsec = 0, .tv_sec = 0}; int result = recvmmsg(transport->fd, msgvec, vlen, 0, &tv); if (result < 0) { int err = errno; if (EINTR == err || EAGAIN == err) { return 0; } aeron_set_err(err, "recvmmsg: %s", strerror(err)); return -1; } else if (0 == result) { return 0; } else { for (size_t i = 0, length = result; i < length; i++) { recv_func( clientd, transport->dispatch_clientd, msgvec[i].msg_hdr.msg_iov[0].iov_base, msgvec[i].msg_len, msgvec[i].msg_hdr.msg_name); } return result; } #else int work_count = 0; for (size_t i = 0, length = vlen; i < length; i++) { ssize_t result = recvmsg(transport->fd, &msgvec[i].msg_hdr, 0); if (result < 0) { int err = errno; if (EINTR == err || EAGAIN == err) { break; } aeron_set_err(err, "recvmsg: %s", strerror(err)); return -1; } if (0 == result) { break; } msgvec[i].msg_len = (unsigned int)result; recv_func( clientd, transport->dispatch_clientd, msgvec[i].msg_hdr.msg_iov[0].iov_base, msgvec[i].msg_len, msgvec[i].msg_hdr.msg_name); work_count++; } return work_count; #endif } int aeron_udp_channel_transport_sendmmsg( aeron_udp_channel_transport_t *transport, struct mmsghdr *msgvec, size_t vlen) { #if defined(HAVE_RECVMMSG) int sendmmsg_result = sendmmsg(transport->fd, msgvec, vlen, 0); if (sendmmsg_result < 0) { aeron_set_err(errno, "sendmmsg: %s", strerror(errno)); return -1; } return sendmmsg_result; #else int result = 0; for (size_t i = 0, length = vlen; i < length; i++) { ssize_t sendmsg_result = sendmsg(transport->fd, &msgvec[i].msg_hdr, 0); if (sendmsg_result < 0) { aeron_set_err(errno, "sendmsg: %s", strerror(errno)); return -1; } msgvec[i].msg_len = (unsigned int)sendmsg_result; if (0 == sendmsg_result) { break; } result++; } return result; #endif }
static void ind_ovs_handle_port_upcalls(struct ind_ovs_upcall_thread *thread, struct ind_ovs_port *port) { int fd = nl_socket_get_fd(port->notify_socket); int count = 0; /* total messages processed */ while (count < 128) { /* Fast recv into our preallocated messages */ int n = recvmmsg(fd, thread->msgvec, NUM_UPCALL_BUFFERS, 0, NULL); if (n < 0) { if (errno == EAGAIN) { break; } else { continue; } } thread->tx_queue_len = 0; ind_ovs_fwd_read_lock(); int i; for (i = 0; i < n; i++) { struct nl_msg *msg = thread->msgs[i]; struct nlmsghdr *nlh = nlmsg_hdr(msg); /* * HACK to workaround OVS not using nlmsg_end(). * This size is padded to 4 byte alignment which * nlmsg_len shouldn't be. This hasn't confused * the parser yet. Worse is that in the case of * multipart messages the buffer returned by * read contains multiple messages. Luckily the * only buggy messages are from the packet family, * which doesn't use any multipart messages. */ /* Don't mess with messages that aren't broken. */ int len = thread->msgvec[i].msg_len; if (nlh->nlmsg_len + nlmsg_padlen(nlh->nlmsg_len) != len) { //LOG_TRACE("fixup size: nlh->nlmsg_len=%d pad=%d len=%d", nlh->nlmsg_len, nlmsg_padlen(nlh->nlmsg_len), len); nlh->nlmsg_len = len; } ind_ovs_handle_one_upcall(thread, port, msg); } ind_ovs_fwd_read_unlock(); struct msghdr msghdr = { 0 }; msghdr.msg_iov = thread->tx_queue; msghdr.msg_iovlen = thread->tx_queue_len; (void) sendmsg(fd, &msghdr, 0); count += n; if (n != NUM_UPCALL_BUFFERS) { break; } } /* See ind_ovs_upcall_quiesce */ /* TODO remove locking from the fast path */ pthread_mutex_lock(&port->quiesce_lock); if (port->quiescing) { port->quiescing = false; pthread_cond_signal(&port->quiesce_cvar); pthread_mutex_unlock(&port->quiesce_lock); return; } pthread_mutex_unlock(&port->quiesce_lock); ind_ovs_upcall_rearm(port); }
CAMLprim value bigstring_recvmmsg_assume_fd_is_nonblocking_stub( value v_fd, value v_iovecs, value v_count, value v_srcs, value v_lens) { CAMLparam5(v_fd, v_iovecs, v_count, v_srcs, v_lens); CAMLlocal5(v_iovec, v_buf, v_pos, v_len, v_sockaddrs); size_t total_len = 0; struct mmsghdr hdrs[Long_val(v_count)]; union sock_addr_union addrs[Long_val(v_count)]; struct iovec iovecs[Long_val(v_count)]; unsigned i; ssize_t n_read; int save_source_addresses; int fd; unsigned int count; save_source_addresses = Is_block(v_srcs); fd = Int_val(v_fd); count = (unsigned int) Long_val(v_count); if (count != Long_val(v_count)) { caml_invalid_argument("bigstring_recvmmsg_assume_fd_is_nonblocking_stub: " "v_count exceeds unsigned int"); } if (!Is_block(v_lens)) { caml_invalid_argument("bigstring_recvmmsg_assume_fd_is_nonblocking_stub: " "v_lens is not an array"); } if (Wosize_val(v_lens) < count) { caml_invalid_argument("bigstring_recvmmsg_assume_fd_is_nonblocking_stub: " "length v_lens < count"); } for (i = 0; i < count; i++) { hdrs[i].msg_hdr.msg_name = (save_source_addresses ? &addrs[i].s_gen : 0); hdrs[i].msg_hdr.msg_namelen = sizeof(addrs[i]); v_iovec = Field(v_iovecs, i); v_buf = Field(v_iovec, 0); v_pos = Field(v_iovec, 1); v_len = Field(v_iovec, 2); iovecs[i].iov_base = get_bstr(v_buf, v_pos); iovecs[i].iov_len = Long_val(v_len); total_len += iovecs[i].iov_len; hdrs[i].msg_hdr.msg_iov = &iovecs[i]; hdrs[i].msg_hdr.msg_iovlen = 1; hdrs[i].msg_hdr.msg_control = 0; hdrs[i].msg_hdr.msg_flags = 0; } if (total_len > THREAD_IO_CUTOFF) { caml_enter_blocking_section(); n_read = recvmmsg(fd, hdrs, count, 0, 0); caml_leave_blocking_section(); } else { n_read = recvmmsg(fd, hdrs, count, 0, 0); } if (n_read > count) { caml_failwith("bigstring_recvmmsg_assume_fd_is_nonblocking_stub: " "recvmmsg unexpectedly returned n_read > count"); } if (n_read == -1) { uerror("recvmmsg_assume_fd_is_nonblocking", Nothing); } else { if (save_source_addresses) { v_sockaddrs = Field(v_srcs, 0); if (!Is_block(v_sockaddrs)) { caml_invalid_argument("bigstring_recvmmsg_assume_fd_is_nonblocking_stub: " "v_sockaddrs is not an array"); } if (Wosize_val(v_sockaddrs) < count) { caml_invalid_argument("bigstring_recvmmsg_assume_fd_is_nonblocking_stub: " "length v_sockaddrs < count"); } for (i = 0; i < n_read; i++) { value addr = alloc_sockaddr(&addrs[i], hdrs[i].msg_hdr.msg_namelen, -1); Store_field(v_sockaddrs, i, addr); } } for (i = 0; i < n_read; i++) { Field(v_lens, i) = Val_long(hdrs[i].msg_len); } } CAMLreturn(Val_long(n_read)); }
static void* reader_thread(void* dontcare) { char token = '!'; int sock = sockfds[1]; struct timeval ts; char c = '\0'; int i; gettimeofday(&ts, NULL); atomic_puts("r: acquiring mutex ..."); pthread_mutex_lock(&lock); atomic_puts("r: ... releasing mutex"); pthread_mutex_unlock(&lock); for (i = 0; i < 2; ++i) { atomic_puts("r: reading socket ..."); gettimeofday(&ts, NULL); test_assert(1 == read(sock, &c, sizeof(c))); atomic_printf("r: ... read '%c'\n", c); test_assert(c == token); ++token; } /* TODO: readv() support */ atomic_puts("r: recv'ing socket ..."); gettimeofday(&ts, NULL); test_assert(1 == recv(sock, &c, sizeof(c), 0)); atomic_printf("r: ... recv'd '%c'\n", c); test_assert(c == token); ++token; atomic_puts("r: recvfrom'ing socket ..."); test_assert(1 == recvfrom(sock, &c, sizeof(c), 0, NULL, NULL)); atomic_printf("r: ... recvfrom'd '%c'\n", c); test_assert(c == token); ++token; { struct sockaddr_un addr; socklen_t addrlen = sizeof(addr); atomic_puts("r: recvfrom(&sock)'ing socket ..."); test_assert(1 == recvfrom(sock, &c, sizeof(c), 0, &addr, &addrlen)); atomic_printf("r: ... recvfrom'd '%c' from sock len:%d\n", c, addrlen); test_assert(c == token); /* socketpair() AF_LOCAL sockets don't identify * themselves. */ test_assert(addrlen == 0); ++token; } { struct mmsghdr mmsg = { { 0 } }; struct iovec data = { 0 }; int magic = ~msg_magic; int err, ret; data.iov_base = &magic; data.iov_len = sizeof(magic); mmsg.msg_hdr.msg_iov = &data; mmsg.msg_hdr.msg_iovlen = 1; struct cmsghdr* cmptr = (struct cmsghdr*)malloc(CTRLMSG_LEN); mmsg.msg_hdr.msg_control = cmptr; mmsg.msg_hdr.msg_controllen = CTRLMSG_LEN; atomic_puts("r: recvmsg with DONTWAIT ..."); ret = recvmsg(sock, &mmsg.msg_hdr, MSG_DONTWAIT); err = errno; atomic_printf("r: ... returned %d (%s/%d)\n", ret, strerror(err), err); test_assert(-1 == ret); test_assert(EWOULDBLOCK == err); test_assert(mmsg.msg_hdr.msg_iov == &data); atomic_puts("r: recmsg'ing socket ..."); test_assert(0 < recvmsg(sock, &mmsg.msg_hdr, 0)); atomic_printf("r: ... recvmsg'd 0x%x\n", magic); test_assert(msg_magic == magic); test_assert(mmsg.msg_hdr.msg_iov == &data); int fd = *(int*)CMSG_DATA(cmptr); struct stat fs_new, fs_old; fstat(fd, &fs_new); fstat(STDERR_FILENO, &fs_old); // check if control msg was send successfully test_assert( fs_old.st_dev == fs_new.st_dev && fs_old.st_ino == fs_new.st_ino && fs_old.st_uid == fs_new.st_uid && fs_old.st_gid == fs_new.st_gid && fs_old.st_rdev == fs_new.st_rdev && fs_old.st_size == fs_new.st_size); magic = ~msg_magic; atomic_puts("r: recmmsg'ing socket ..."); breakpoint(); test_assert(1 == recvmmsg(sock, &mmsg, 1, 0, NULL)); atomic_printf("r: ... recvmmsg'd 0x%x (%u bytes)\n", magic, mmsg.msg_len); test_assert(msg_magic == magic); test_assert(mmsg.msg_hdr.msg_iov == &data); magic = ~msg_magic; #if defined(SYS_socketcall) struct recvmmsg_arg arg = { 0 }; arg.sockfd = sock; arg.msgvec = &mmsg; arg.vlen = 1; test_assert(1 == syscall(SYS_socketcall, SYS_RECVMMSG, (void*)&arg)); #elif defined(SYS_recvmmsg) test_assert(1 == syscall(SYS_recvmmsg, sock, &mmsg, 1, 0, NULL)); #else #error unable to call recvmmsg #endif atomic_printf("r: ... recvmmsg'd(by socketcall) 0x%x (%u bytes)\n", magic, mmsg.msg_len); test_assert(msg_magic == magic); free(cmptr); } { struct msghdr msg = { 0 }; struct iovec iovs[2]; char c1 = '\0', c2 = '\0'; iovs[0].iov_base = &c1; iovs[0].iov_len = sizeof(c1); iovs[1].iov_base = &c2; iovs[1].iov_len = sizeof(c2); msg.msg_iov = iovs; msg.msg_iovlen = sizeof(iovs) / sizeof(iovs[0]); atomic_puts("r: recmsg'ing socket with two iovs ..."); test_assert(2 == recvmsg(sock, &msg, 0)); atomic_printf("r: ... recvmsg'd '%c' and '%c'\n", c1, c2); test_assert(c1 == token); token++; test_assert(c2 == token); token++; } { struct pollfd pfd; atomic_puts("r: polling socket ..."); pfd.fd = sock; pfd.events = POLLIN; gettimeofday(&ts, NULL); poll(&pfd, 1, -1); atomic_puts("r: ... done, doing nonblocking read ..."); test_assert(1 == read(sock, &c, sizeof(c))); atomic_printf("r: ... read '%c'\n", c); test_assert(c == token); ++token; } { struct pollfd pfd; atomic_puts("r: polling socket ..."); pfd.fd = sock; pfd.events = POLLIN; gettimeofday(&ts, NULL); ppoll(&pfd, 1, NULL, NULL); atomic_puts("r: ... done, doing nonblocking read ..."); test_assert(1 == read(sock, &c, sizeof(c))); atomic_printf("r: ... read '%c'\n", c); test_assert(c == token); ++token; } { fd_set fds; const struct timeval infinity = { 1 << 30, 0 }; struct timeval tv = infinity; int ret; atomic_puts("r: select()ing socket ..."); FD_ZERO(&fds); FD_SET(sock, &fds); #if defined(__i386__) struct select_arg arg = { 0 }; arg.n_fds = sock + 1; arg.read = &fds; arg.write = NULL; arg.except = NULL; arg.timeout = &tv; ret = syscall(SYS_select, &arg); #else ret = syscall(SYS_select, sock + 1, &fds, NULL, NULL, &tv); #endif atomic_printf("r: ... returned %d; tv { %ld, %ld }\n", ret, tv.tv_sec, tv.tv_usec); test_assert(1 == ret); test_assert(FD_ISSET(sock, &fds)); test_assert(0 < tv.tv_sec && tv.tv_sec < infinity.tv_sec); atomic_puts("r: ... done, doing nonblocking read ..."); test_assert(1 == read(sock, &c, sizeof(c))); atomic_printf("r: ... read '%c'\n", c); test_assert(c == token); ++token; } { fd_set fds; const struct timeval infinity = { 1 << 30, 0 }; struct timeval tv = infinity; int ret; atomic_puts("r: select()ing socket ..."); FD_ZERO(&fds); FD_SET(sock, &fds); ret = select(sock + 1, &fds, NULL, NULL, &tv); atomic_printf("r: ... returned %d; tv { %ld, %ld }\n", ret, tv.tv_sec, tv.tv_usec); test_assert(1 == ret); test_assert(FD_ISSET(sock, &fds)); test_assert(0 < tv.tv_sec && tv.tv_sec < infinity.tv_sec); atomic_puts("r: ... done, doing nonblocking read ..."); test_assert(1 == read(sock, &c, sizeof(c))); atomic_printf("r: ... read '%c'\n", c); test_assert(c == token); ++token; } { int epfd; struct epoll_event ev; atomic_puts("r: epolling socket ..."); test_assert(0 <= (epfd = epoll_create(1 /*num events*/))); ev.events = EPOLLIN; ev.data.fd = sock; gettimeofday(&ts, NULL); test_assert(0 == epoll_ctl(epfd, EPOLL_CTL_ADD, ev.data.fd, &ev)); test_assert(1 == epoll_wait(epfd, &ev, 1, -1)); atomic_puts("r: ... done, doing nonblocking read ..."); test_assert(sock == ev.data.fd); test_assert(1 == epoll_wait(epfd, &ev, 1, -1)); test_assert(1 == read(sock, &c, sizeof(c))); atomic_printf("r: ... read '%c'\n", c); test_assert(c == token); ++token; close(epfd); } { char* buf = (char*)malloc(num_sockbuf_bytes); ssize_t nwritten = 0; struct iovec iov; ++token; memset(buf, token, num_sockbuf_bytes); atomic_printf("r: writing outbuf of size %zd ...\n", num_sockbuf_bytes); while (nwritten < num_sockbuf_bytes) { ssize_t this_write = write(sock, buf, num_sockbuf_bytes - nwritten); atomic_printf("r: wrote %zd bytes this time\n", this_write); nwritten += this_write; } ++token; memset(buf, token, num_sockbuf_bytes); iov.iov_base = buf; iov.iov_len = num_sockbuf_bytes; atomic_printf("r: writev()ing outbuf of size %zd ...\n", num_sockbuf_bytes); while (iov.iov_len > 0) { ssize_t this_write = writev(sock, &iov, 1); atomic_printf("r: wrote %zd bytes this time\n", this_write); iov.iov_len -= this_write; } free(buf); } atomic_puts("r: reading socket with masked signals ..."); { sigset_t old_mask, mask; sigfillset(&mask); test_assert(0 == pthread_sigmask(SIG_BLOCK, &mask, &old_mask)); test_assert(1 == read(sock, &c, sizeof(c))); test_assert(0 == pthread_sigmask(SIG_SETMASK, &old_mask, NULL)); } ++token; atomic_printf("r: ... read '%c'\n", c); test_assert(c == token); /* Make the main thread wait on our join() */ atomic_puts("r: sleeping ..."); usleep(500000); return NULL; }
int CNIOLinux_recvmmsg(int sockfd, CNIOLinux_mmsghdr *msgvec, unsigned int vlen, int flags, struct timespec *timeout) { // This is technically undefined behaviour, but it's basically fine because these types are the same size, and we // don't think the compiler is inclined to blow anything up here. return recvmmsg(sockfd, (struct mmsghdr *)msgvec, vlen, flags, timeout); }
int main() { int s, fd_null; struct sockaddr_in sin1, sin2, sin4, from; pid_t pid = 0; char buf[2][1024]; fd_set rdfds; struct timeval timeout; socklen_t fromlen; struct mmsghdr msgs[2]; struct iovec iov[2]; struct sockaddr_un sun1; char tmpsunpath[1024]; struct timespec tim = {0, 20000}; /* initialize sockaddr's */ sin1.sin_family = AF_INET; sin1.sin_port = htons((getpid() % 32768) + 11000); sin1.sin_addr.s_addr = INADDR_ANY; (void)strcpy(tmpsunpath, "udsockXXXXXX"); s = mkstemp(tmpsunpath); close(s); unlink(tmpsunpath); sun1.sun_family = AF_UNIX; strcpy(sun1.sun_path, tmpsunpath); pid = start_server(&sin1, &sun1); sin2.sin_family = AF_INET; /* this port must be unused! */ sin2.sin_port = htons((getpid() % 32768) + 10000); sin2.sin_addr.s_addr = INADDR_ANY; sin4.sin_family = 47; /* bogus address family */ sin4.sin_port = 0; sin4.sin_addr.s_addr = htonl(0x0AFFFEFD); fromlen = sizeof(from); memset(msgs, 0, sizeof(msgs)); iov[0].iov_base = buf[0]; iov[0].iov_len = sizeof(buf[0]); msgs[0].msg_hdr.msg_iov = &iov[0]; msgs[0].msg_hdr.msg_iovlen = 1; iov[1].iov_base = buf[1]; iov[1].iov_len = sizeof(buf[1]); msgs[1].msg_hdr.msg_iov = &iov[1]; msgs[1].msg_hdr.msg_iovlen = 1; fd_null = open("/dev/null", O_WRONLY); //staptest// [[[[open (!!!!openat (AT_FDCWD, ]]]]"/dev/null", O_WRONLY) = NNNN recvmmsg(-1, msgs, 2, 0, NULL); //staptest// recvmmsg (-1, XXXX, 2, 0x0, NULL) = -NNNN (EBADF) recvmmsg(fd_null, msgs, 2, MSG_DONTWAIT, NULL); //staptest// recvmmsg (NNNN, XXXX, 2, MSG_DONTWAIT, NULL) = -NNNN (ENOTSOCK) s = socket(PF_INET, SOCK_STREAM, 0); //staptest// socket (PF_INET, SOCK_STREAM, IPPROTO_IP) = NNNN connect(s, (struct sockaddr *)&sin1, sizeof(sin1)); //staptest// connect (NNNN, {AF_INET, 0.0.0.0, NNNN}, 16) = 0 /* Wait for something to be readable */ FD_ZERO(&rdfds); FD_SET(s, &rdfds); timeout.tv_sec = 2; timeout.tv_usec = 0; select(s + 1, &rdfds, 0, 0, &timeout); //staptest// [[[[select (NNNN, XXXX, 0x[0]+, 0x[0]+, [2\.[0]+]!!!!pselect6 (NNNN, XXXX, 0x[0]+, 0x[0]+, [2\.[0]+], 0x0]]]]) = 1 recvmmsg(s, (struct mmsghdr *)-1, 2, 0, NULL); #ifdef __s390__ //staptest// recvmmsg (NNNN, 0x[7]?[f]+, 2, 0x0, NULL) = -NNNN (EFAULT) #else //staptest// recvmmsg (NNNN, 0x[f]+, 2, 0x0, NULL) = -NNNN (EFAULT) #endif close(s); //staptest// close (NNNN) = 0 s = socket(PF_INET, SOCK_STREAM, 0); //staptest// socket (PF_INET, SOCK_STREAM, IPPROTO_IP) = NNNN connect(s, (struct sockaddr *)&sin1, sizeof(sin1)); //staptest// connect (NNNN, {AF_INET, 0.0.0.0, NNNN}, 16) = 0 /* Wait for something to be readable */ FD_ZERO(&rdfds); FD_SET(s, &rdfds); timeout.tv_sec = 2; timeout.tv_usec = 0; select(s + 1, &rdfds, 0, 0, &timeout); //staptest// [[[[select (NNNN, XXXX, 0x[0]+, 0x[0]+, [2\.[0]+]!!!!pselect6 (NNNN, XXXX, 0x[0]+, 0x[0]+, [2\.[0]+], 0x0]]]]) = 1 // Note that the exact failure return value can differ here, so // we'll just ignore it. Also note that on a 32-bit kernel (i686 // for instance), MAXSTRINGLEN is only 256. Passing a -1 as the // flags value can produce a string that will cause argstr to get // too big. So, we'll make the end of the argument optional. recvmmsg(s, msgs, 2, -1, NULL); //staptest// recvmmsg (NNNN, XXXX, 2, MSG_[^ ]+[[[[|XXXX, NULL]]]]?) = -NNNN close(s); //staptest// close (NNNN) = 0 s = socket(PF_UNIX, SOCK_STREAM, 0); //staptest// socket (PF_LOCAL, SOCK_STREAM, 0) = NNNN connect(s, (struct sockaddr *)&sun1, sizeof(sun1)); //staptest// connect (NNNN, {AF_UNIX, "[^"]+"}, 110) = 0 // We don't want to wait for -1 vectors, since we'd be waiting for // a long time... recvmmsg(s, msgs, -1, MSG_DONTWAIT, NULL); //staptest// recvmmsg (NNNN, XXXX, 4294967295, MSG_DONTWAIT, NULL) = -NNNN (EAGAIN) recvmmsg(s, msgs, 2, MSG_DONTWAIT, (struct timespec *)-1); #ifdef __s390__ //staptest// recvmmsg (NNNN, XXXX, 2, MSG_DONTWAIT, 0x[7]?[f]+) = -NNNN (EFAULT) #else //staptest// recvmmsg (NNNN, XXXX, 2, MSG_DONTWAIT, 0x[f]+) = -NNNN (EFAULT) #endif close(s); //staptest// close (NNNN) = 0 s = socket(PF_UNIX, SOCK_STREAM, 0); //staptest// socket (PF_LOCAL, SOCK_STREAM, 0) = NNNN connect(s, (struct sockaddr *)&sun1, sizeof(sun1)); //staptest// connect (NNNN, {AF_UNIX, "[^"]+"}, 110) = 0 write(s, "R", 1); //staptest// write (NNNN, "R", 1) = 1 /* Wait for something to be readable */ FD_ZERO(&rdfds); FD_SET(s, &rdfds); timeout.tv_sec = 2; timeout.tv_usec = 0; select(s + 1, &rdfds, 0, 0, &timeout); //staptest// [[[[select (NNNN, XXXX, 0x[0]+, 0x[0]+, [2\.[0]+]!!!!pselect6 (NNNN, XXXX, 0x[0]+, 0x[0]+, [2\.[0]+], 0x0]]]]) = 1 recvmmsg(s, msgs, 2, MSG_DONTWAIT, NULL); //staptest// recvmmsg (NNNN, XXXX, 2, MSG_DONTWAIT, NULL) = NNNN close(s); //staptest// close (NNNN) = 0 s = socket(PF_UNIX, SOCK_STREAM, 0); //staptest// socket (PF_LOCAL, SOCK_STREAM, 0) = NNNN connect(s, (struct sockaddr *)&sun1, sizeof(sun1)); //staptest// connect (NNNN, {AF_UNIX, "[^"]+"}, 110) = 0 write(s, "R", 1); //staptest// write (NNNN, "R", 1) = 1 /* Wait for something to be readable */ FD_ZERO(&rdfds); FD_SET(s, &rdfds); timeout.tv_sec = 2; timeout.tv_usec = 0; select(s + 1, &rdfds, 0, 0, &timeout); //staptest// [[[[select (NNNN, XXXX, 0x[0]+, 0x[0]+, [2\.[0]+]!!!!pselect6 (NNNN, XXXX, 0x[0]+, 0x[0]+, [2\.[0]+], 0x0]]]]) = 1 recvmmsg(s, msgs, 2, MSG_DONTWAIT, &tim); //staptest// recvmmsg (NNNN, XXXX, 2, MSG_DONTWAIT, \[0.000020000\]) = NNNN close(s); //staptest// close (NNNN) = 0 close(fd_null); //staptest// close (NNNN) = 0 if (pid > 0) (void)kill(pid, SIGKILL); /* kill server */ //staptest// kill (NNNN, SIGKILL) = 0 (void)unlink(tmpsunpath); return 0; }
static void statsd_run_recvmmsg(struct brubeck_statsd *statsd, int sock) { const unsigned int SIM_PACKETS = statsd->mmsg_count; struct brubeck_server *server = statsd->sampler.server; struct brubeck_statsd_msg msg; struct brubeck_metric *metric; unsigned int i; struct iovec iovecs[SIM_PACKETS]; struct mmsghdr msgs[SIM_PACKETS]; memset(msgs, 0x0, sizeof(msgs)); for (i = 0; i < SIM_PACKETS; ++i) { iovecs[i].iov_base = xmalloc(MAX_PACKET_SIZE); iovecs[i].iov_len = MAX_PACKET_SIZE - 1; msgs[i].msg_hdr.msg_iov = &iovecs[i]; msgs[i].msg_hdr.msg_iovlen = 1; } log_splunk("sampler=statsd event=worker_online syscall=recvmmsg socket=%d", sock); for (;;) { int res = recvmmsg(sock, msgs, SIM_PACKETS, 0, NULL); if (res < 0) { if (errno == EAGAIN || errno == EINTR) continue; log_splunk_errno("sampler=statsd event=failed_read"); brubeck_server_mark_dropped(server); continue; } /* store stats */ brubeck_atomic_add(&server->stats.metrics, SIM_PACKETS); brubeck_atomic_add(&statsd->sampler.inflow, SIM_PACKETS); for (i = 0; i < SIM_PACKETS; ++i) { char *buf = msgs[i].msg_hdr.msg_iov->iov_base; int len = msgs[i].msg_len; char *cur; int curLen; int processed = 0; do { cur = memchr(buf,'\n', len); if(cur == NULL){ cur = buf; curLen = len - processed; } else{ curLen = cur - buf; cur = buf; } //log_splunk("msg to be processed ='%.*s'", curLen, cur); if (brubeck_statsd_msg_parse(&msg, cur, curLen) < 0) { if (msg.key_len > 0) buf[msg.key_len] = ':'; log_splunk("sampler=statsd event=bad_key key='%.*s'", curLen, cur); brubeck_server_mark_dropped(server); continue; } //log_splunk("key: %s, value: %s",msg.key, msg.value); metric = brubeck_metric_find(server, msg.key, msg.key_len, msg.type); if (metric != NULL) brubeck_metric_record(metric, msg.value); processed += curLen +1; buf += curLen +1; }while(processed < len); } } }