static int process_response(int wait_for_done, unsigned seq) { assert(fd >= 0); do { size_t bytes; ssize_t r; char replybuf[8*1024]; char cred_msg[CMSG_SPACE(sizeof(struct ucred))]; struct msghdr msghdr; struct cmsghdr *cmsghdr; struct ucred *ucred; struct iovec iov; struct nlmsghdr *p = (struct nlmsghdr *) replybuf; memset(&iov, 0, sizeof(iov)); iov.iov_base = replybuf; iov.iov_len = sizeof(replybuf); memset(&msghdr, 0, sizeof(msghdr)); msghdr.msg_name = (void*) NULL; msghdr.msg_namelen = 0; msghdr.msg_iov = &iov; msghdr.msg_iovlen = 1; msghdr.msg_control = cred_msg; msghdr.msg_controllen = sizeof(cred_msg); msghdr.msg_flags = 0; if ((r = recvmsg(fd, &msghdr, 0)) < 0) { daemon_log(LOG_ERR, "recvmsg() failed: %s", strerror(errno)); return -1; } if (!(cmsghdr = CMSG_FIRSTHDR(&msghdr)) || cmsghdr->cmsg_type != SCM_CREDENTIALS) { daemon_log(LOG_WARNING, "No sender credentials received, ignoring data."); return -1; } ucred = (struct ucred*) CMSG_DATA(cmsghdr); if (ucred->uid != 0) return -1; bytes = (size_t) r; for (; bytes > 0; p = NLMSG_NEXT(p, bytes)) { if (!NLMSG_OK(p, bytes) || bytes < sizeof(struct nlmsghdr) || bytes < p->nlmsg_len) { daemon_log(LOG_ERR, "Netlink packet too small."); return -1; } if (p->nlmsg_type == NLMSG_DONE && wait_for_done && p->nlmsg_seq == seq && (pid_t) p->nlmsg_pid == getpid()) return 0; if (p->nlmsg_type == NLMSG_ERROR) { struct nlmsgerr *e = (struct nlmsgerr *) NLMSG_DATA (p); if (e->error) { daemon_log(LOG_ERR, "Netlink error: %s", strerror(-e->error)); return -1; } } if (process_nlmsg(p) < 0) return -1; } } while (wait_for_done); return 0; }
static void routing_packet_read(int fd) { struct in_addr src, dst; int i, len, ttl = -1; /*AODV_msg *aodv_msg;*/ struct dev_info *dev; struct msghdr msgh; struct cmsghdr *cmsg; struct iovec iov; char ctrlbuf[CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(struct in_pktinfo))]; struct sockaddr_in src_addr; iov.iov_base = recv_buf; iov.iov_len = RECV_BUF_SIZE; msgh.msg_name = &src_addr; msgh.msg_namelen = sizeof(src_addr); msgh.msg_iov = &iov; msgh.msg_iovlen = 1; msgh.msg_control = ctrlbuf; msgh.msg_controllen = sizeof(ctrlbuf); len = recvmsg(fd, &msgh, 0); if (len < 0) { fprintf(stderr, "receive ERROR len=%d!", len); return; } src.s_addr = src_addr.sin_addr.s_addr; /* Get the ttl and destination address from the control message */ for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL; cmsg = CMSG_NXTHDR_FIX(&msgh, cmsg)) { if (cmsg->cmsg_level == SOL_IP) { switch (cmsg->cmsg_type) { case IP_TTL: ttl = *(CMSG_DATA(cmsg)); break; case IP_PKTINFO: dst.s_addr = ((struct in_pktinfo *) CMSG_DATA(cmsg))->ipi_addr.s_addr; } } } if (ttl < 0) { fprintf(stderr, "No TTL, packet ignored!"); return; } /* Ignore messages generated locally */ for (i = 0; i < MAX_NR_INTERFACES; i++) if (this_host.devs[i].enabled && memcmp(&src, &this_host.devs[i].ipaddr, sizeof(struct in_addr)) == 0) return; /*aodv_msg = (AODV_msg *) recv_buf;*/ /*dev = devfromsock(fd);*/ callback_set.prot_callback(recv_buf, RECV_BUF_SIZE); #if 0 if (!dev) { DEBUG(LOG_ERR, 0, "Could not get device info!\n"); return; } #endif }
/* * Class: sun_nio_ch_sctp_SctpChannelImpl * Method: receive0 * Signature: (ILsun/nio/ch/sctp/ResultContainer;J*Z)I */ JNIEXPORT jint JNICALL Java_sun_nio_ch_sctp_SctpChannelImpl_receive0 (JNIEnv *env, jclass klass, jint fd, jobject resultContainerObj, jlong address, jint length, jboolean peek) { SOCKADDR sa; int sa_len = sizeof(sa); ssize_t rv = 0; jlong *addr = jlong_to_ptr(address); struct iovec iov[1]; struct msghdr msg[1]; char cbuf[CMSG_SPACE(sizeof (struct sctp_sndrcvinfo))]; int flags = peek == JNI_TRUE ? MSG_PEEK : 0; /* Set up the msghdr structure for receiving */ memset(msg, 0, sizeof (*msg)); msg->msg_name = &sa; msg->msg_namelen = sa_len; iov->iov_base = addr; iov->iov_len = length; msg->msg_iov = iov; msg->msg_iovlen = 1; msg->msg_control = cbuf; msg->msg_controllen = sizeof(cbuf); msg->msg_flags = 0; do { if ((rv = recvmsg(fd, msg, flags)) < 0) { if (errno == EWOULDBLOCK) { return IOS_UNAVAILABLE; } else if (errno == EINTR) { return IOS_INTERRUPTED; #ifdef __linux__ } else if (errno == ENOTCONN) { /* ENOTCONN when EOF reached */ rv = 0; /* there will be no control data */ msg->msg_controllen = 0; #endif /* __linux__ */ } else { handleSocketError(env, errno); return 0; } } if (msg->msg_flags & MSG_NOTIFICATION) { char *bufp = (char*)addr; union sctp_notification *snp; if (!(msg->msg_flags & MSG_EOR) && length < NOTIFICATION_BUFFER_SIZE) { char buf[NOTIFICATION_BUFFER_SIZE]; int rvSAVE = rv; memcpy(buf, addr, rv); iov->iov_base = buf + rv; iov->iov_len = NOTIFICATION_BUFFER_SIZE - rv; if ((rv = recvmsg(fd, msg, flags)) < 0) { handleSocketError(env, errno); return 0; } bufp = buf; rv += rvSAVE; } snp = (union sctp_notification *) bufp; if (handleNotification(env, fd, resultContainerObj, snp, rv, (msg->msg_flags & MSG_EOR), (struct sockaddr*)&sa ) == JNI_TRUE) { /* We have received a notification that is of interest to to the Java API. The appropriate notification will be set in the result container. */ return 0; } // set iov back to addr, and reset msg_controllen iov->iov_base = addr; iov->iov_len = length; msg->msg_control = cbuf; msg->msg_controllen = sizeof(cbuf); } } while (msg->msg_flags & MSG_NOTIFICATION); handleMessage(env, resultContainerObj, msg, rv, (msg->msg_flags & MSG_EOR), (struct sockaddr*)&sa); return rv; }
int main(int argc, char *argv[]) { int sk1, sk2; sockaddr_storage_t loop1; sockaddr_storage_t loop2; struct iovec iov; struct msghdr inmessage; struct msghdr outmessage; char incmsg[CMSG_SPACE(sizeof(sctp_cmsg_data_t))]; char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))]; struct cmsghdr *cmsg; struct sctp_sndrcvinfo *sinfo; struct iovec out_iov; int error; int pf_class; uint32_t ppid; uint32_t stream; sctp_assoc_t associd1; struct sctp_assoc_change *sac; struct sctp_event_subscribe subscribe; char *big_buffer; int offset; struct sctp_send_failed *ssf; socklen_t len; /* Really becomes 2xlen when set. */ int orig_len; struct sctp_status gstatus; /* Rather than fflush() throughout the code, set stdout to * be unbuffered. */ setvbuf(stdout, NULL, _IONBF, 0); /* Set some basic values which depend on the address family. */ #if TEST_V6 pf_class = PF_INET6; loop1.v6.sin6_family = AF_INET6; loop1.v6.sin6_addr = in6addr_loopback; loop1.v6.sin6_port = htons(SCTP_TESTPORT_1); loop2.v6.sin6_family = AF_INET6; loop2.v6.sin6_addr = in6addr_loopback; loop2.v6.sin6_port = htons(SCTP_TESTPORT_2); #else pf_class = PF_INET; loop1.v4.sin_family = AF_INET; loop1.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK; loop1.v4.sin_port = htons(SCTP_TESTPORT_1); loop2.v4.sin_family = AF_INET; loop2.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK; loop2.v4.sin_port = htons(SCTP_TESTPORT_2); #endif /* TEST_V6 */ /* Create the two endpoints which will talk to each other. */ sk1 = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP); sk2 = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP); len = sizeof(int); error = getsockopt(sk2, SOL_SOCKET, SO_RCVBUF, &orig_len, &len); if (error) tst_brkm(TBROK, tst_exit, "can't get rcvbuf size: %s", strerror(errno)); /* Set the MAXSEG to something smallish. */ { int val = SMALL_MAXSEG; test_setsockopt(sk1, SCTP_MAXSEG, &val, sizeof(val)); } memset(&subscribe, 0, sizeof(subscribe)); subscribe.sctp_data_io_event = 1; subscribe.sctp_association_event = 1; subscribe.sctp_send_failure_event = 1; test_setsockopt(sk1, SCTP_EVENTS, &subscribe, sizeof(subscribe)); test_setsockopt(sk2, SCTP_EVENTS, &subscribe, sizeof(subscribe)); /* Bind these sockets to the test ports. */ test_bind(sk1, &loop1.sa, sizeof(loop1)); test_bind(sk2, &loop2.sa, sizeof(loop2)); /* * This code sets the associations RWND very small so we can * fill it. It does this by manipulating the rcvbuf as follows: * 1) Reduce the rcvbuf size on the socket * 2) create an association so that we advertize rcvbuf/2 as * our initial rwnd * 3) raise the rcvbuf value so that we don't drop data wile * receiving later data */ len = SMALL_RCVBUF; error = setsockopt(sk2, SOL_SOCKET, SO_RCVBUF, &len, sizeof(len)); if (error) tst_brkm(TBROK, tst_exit, "setsockopt(SO_RCVBUF): %s", strerror(errno)); /* Mark sk2 as being able to accept new associations. */ test_listen(sk2, 1); /* Send the first message. This will create the association. */ outmessage.msg_name = &loop2; outmessage.msg_namelen = sizeof(loop2); outmessage.msg_iov = &out_iov; outmessage.msg_iovlen = 1; outmessage.msg_control = outcmsg; outmessage.msg_controllen = sizeof(outcmsg); outmessage.msg_flags = 0; cmsg = CMSG_FIRSTHDR(&outmessage); cmsg->cmsg_level = IPPROTO_SCTP; cmsg->cmsg_type = SCTP_SNDRCV; cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); outmessage.msg_controllen = cmsg->cmsg_len; sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo)); ppid = rand(); /* Choose an arbitrary value. */ stream = 1; sinfo->sinfo_ppid = ppid; sinfo->sinfo_stream = stream; outmessage.msg_iov->iov_base = message; outmessage.msg_iov->iov_len = strlen(message) + 1; test_sendmsg(sk1, &outmessage, 0, strlen(message)+1); /* Initialize inmessage for all receives. */ big_buffer = test_malloc(REALLY_BIG); memset(&inmessage, 0, sizeof(inmessage)); iov.iov_base = big_buffer; iov.iov_len = REALLY_BIG; inmessage.msg_iov = &iov; inmessage.msg_iovlen = 1; inmessage.msg_control = incmsg; /* Get the communication up message on sk2. */ inmessage.msg_controllen = sizeof(incmsg); error = test_recvmsg(sk2, &inmessage, MSG_WAITALL); test_check_msg_notification(&inmessage, error, sizeof(struct sctp_assoc_change), SCTP_ASSOC_CHANGE, SCTP_COMM_UP); #if 0 sac = (struct sctp_assoc_change *)iov.iov_base; associd2 = sac->sac_assoc_id; #endif /* Get the communication up message on sk1. */ inmessage.msg_controllen = sizeof(incmsg); error = test_recvmsg(sk1, &inmessage, MSG_WAITALL); test_check_msg_notification(&inmessage, error, sizeof(struct sctp_assoc_change), SCTP_ASSOC_CHANGE, SCTP_COMM_UP); sac = (struct sctp_assoc_change *)iov.iov_base; associd1 = sac->sac_assoc_id; /* restore the rcvbuffer size for the receiving socket */ error = setsockopt(sk2, SOL_SOCKET, SO_RCVBUF, &orig_len, sizeof(orig_len)); if (error) tst_brkm(TBROK, tst_exit, "setsockopt(SO_RCVBUF): %s", strerror(errno)); /* Get the first data message which was sent. */ inmessage.msg_controllen = sizeof(incmsg); error = test_recvmsg(sk2, &inmessage, MSG_WAITALL); test_check_msg_data(&inmessage, error, strlen(message) + 1, MSG_EOR, stream, ppid); /* Figure out how big to make our fillmsg */ len = sizeof(struct sctp_status); memset(&gstatus,0,sizeof(struct sctp_status)); gstatus.sstat_assoc_id = associd1; error = getsockopt(sk1, IPPROTO_SCTP, SCTP_STATUS, &gstatus, &len); if (error) tst_brkm(TBROK, tst_exit, "can't get rwnd size: %s", strerror(errno)); tst_resm(TINFO, "Creating fillmsg of size %d", gstatus.sstat_rwnd+RWND_SLOP); fillmsg = malloc(gstatus.sstat_rwnd+RWND_SLOP); /* Send a fillmsg */ outmessage.msg_controllen = sizeof(outcmsg); outmessage.msg_flags = 0; cmsg = CMSG_FIRSTHDR(&outmessage); cmsg->cmsg_level = IPPROTO_SCTP; cmsg->cmsg_type = SCTP_SNDRCV; cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); outmessage.msg_controllen = cmsg->cmsg_len; sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo)); ppid++; stream++; sinfo->sinfo_ppid = ppid; sinfo->sinfo_stream = stream; memset(fillmsg, 'X', gstatus.sstat_rwnd+RWND_SLOP); fillmsg[gstatus.sstat_rwnd+RWND_SLOP-1] = '\0'; outmessage.msg_iov->iov_base = fillmsg; outmessage.msg_iov->iov_len = gstatus.sstat_rwnd+RWND_SLOP; outmessage.msg_name = NULL; outmessage.msg_namelen = 0; sinfo->sinfo_assoc_id = associd1; sinfo->sinfo_timetolive = 0; test_sendmsg(sk1, &outmessage, MSG_NOSIGNAL, gstatus.sstat_rwnd+RWND_SLOP); /* Now send the message with timeout. */ sinfo->sinfo_ppid = ppid; sinfo->sinfo_stream = stream; outmessage.msg_iov->iov_base = ttlmsg; outmessage.msg_iov->iov_len = strlen(ttlmsg) + 1; outmessage.msg_name = NULL; outmessage.msg_namelen = 0; sinfo->sinfo_assoc_id = associd1; sinfo->sinfo_timetolive = 2000; test_sendmsg(sk1, &outmessage, MSG_NOSIGNAL, strlen(ttlmsg) + 1); tst_resm(TPASS, "Send a message with timeout"); /* Next send a message with no timeout. */ sinfo->sinfo_ppid = ppid; sinfo->sinfo_stream = stream; outmessage.msg_iov->iov_base = nottlmsg; outmessage.msg_iov->iov_len = strlen(nottlmsg) + 1; outmessage.msg_name = NULL; outmessage.msg_namelen = 0; sinfo->sinfo_assoc_id = associd1; sinfo->sinfo_timetolive = 0; test_sendmsg(sk1, &outmessage, MSG_NOSIGNAL, strlen(nottlmsg)+1); tst_resm(TPASS, "Send a message with no timeout"); /* And finally a fragmented message that will time out. */ sinfo->sinfo_ppid = ppid; sinfo->sinfo_stream = stream; memset(ttlfrag, '0', sizeof(ttlfrag)); ttlfrag[sizeof(ttlfrag)-1] = '\0'; outmessage.msg_iov->iov_base = ttlfrag; outmessage.msg_iov->iov_len = sizeof(ttlfrag); outmessage.msg_name = NULL; outmessage.msg_namelen = 0; sinfo->sinfo_assoc_id = associd1; sinfo->sinfo_timetolive = 2000; test_sendmsg(sk1, &outmessage, MSG_NOSIGNAL, sizeof(ttlfrag)); tst_resm(TPASS, "Send a fragmented message with timeout"); /* Sleep waiting for the message to time out. */ tst_resm(TINFO, " ** SLEEPING for 3 seconds **"); sleep(3); /* Read the fillmsg snuck in between the ttl'd messages. */ do { inmessage.msg_controllen = sizeof(incmsg); error = test_recvmsg(sk2, &inmessage, MSG_WAITALL); } while (!(inmessage.msg_flags & MSG_EOR)); /* Now get the message that did NOT time out. */ inmessage.msg_controllen = sizeof(incmsg); error = test_recvmsg(sk2, &inmessage, MSG_WAITALL); test_check_msg_data(&inmessage, error, strlen(nottlmsg) + 1, MSG_EOR, stream, ppid); if (0 != strncmp(iov.iov_base, nottlmsg, strlen(nottlmsg)+1)) tst_brkm(TBROK, tst_exit, "Received Wrong Message !!!"); tst_resm(TPASS, "Receive message with no timeout"); /* Get the SEND_FAILED notification for the message that DID * time out. */ inmessage.msg_controllen = sizeof(incmsg); error = test_recvmsg(sk1, &inmessage, MSG_WAITALL); test_check_msg_notification(&inmessage, error, sizeof(struct sctp_send_failed) + strlen(ttlmsg) + 1, SCTP_SEND_FAILED, 0); ssf = (struct sctp_send_failed *)iov.iov_base; if (0 != strncmp(ttlmsg, (char *)ssf->ssf_data, strlen(ttlmsg) + 1)) tst_brkm(TBROK, tst_exit, "SEND_FAILED data mismatch"); tst_resm(TPASS, "Receive SEND_FAILED for message with timeout"); /* Get the SEND_FAILED notification for the fragmented message that * DID time out. */ offset = 0; do { inmessage.msg_controllen = sizeof(incmsg); error = test_recvmsg(sk1, &inmessage, MSG_WAITALL); test_check_msg_notification(&inmessage, error, sizeof(struct sctp_send_failed) + SMALL_MAXSEG, SCTP_SEND_FAILED, 0); ssf = (struct sctp_send_failed *)iov.iov_base; if (0 != strncmp(&ttlfrag[offset], (char *)ssf->ssf_data, SMALL_MAXSEG)) tst_brkm(TBROK, tst_exit, "SEND_FAILED data mismatch"); offset += SMALL_MAXSEG; } while (!(ssf->ssf_info.sinfo_flags & 0x01)); /* LAST_FRAG */ tst_resm(TPASS, "Receive SEND_FAILED for fragmented message with " "timeout"); /* Shut down the link. */ close(sk1); /* Get the shutdown complete notification. */ inmessage.msg_controllen = sizeof(incmsg); error = test_recvmsg(sk2, &inmessage, MSG_WAITALL); test_check_msg_notification(&inmessage, error, sizeof(struct sctp_assoc_change), SCTP_ASSOC_CHANGE, SCTP_SHUTDOWN_COMP); close(sk2); /* Indicate successful completion. */ return 0; }
static int read_cmsgspecs(struct thread *td, int ncmsghdrs, struct cmsgspec **cmsgspecs, payload_size_t *payload_size) { struct cmsgspec *spec, *specs; payload_size_t actual_payload_size, level_len, nfds_len, type_len; size_t datasize, size; int error, i, level, nfds, type; size = sizeof(specs[0]) * ncmsghdrs; specs = (struct cmsgspec *)fmaster_malloc(td, size); if (specs == NULL) return (ENOMEM); actual_payload_size = 0; for (i = 0; i < ncmsghdrs; i++) { spec = &specs[i]; error = fmaster_read_int(td, &level, &level_len); if (error != 0) return (error); actual_payload_size += level_len; error = fmaster_read_int(td, &type, &type_len); if (error != 0) return (error); actual_payload_size += type_len; spec->cmsgspec_level = level; spec->cmsgspec_type = type; switch (level) { case SOL_SOCKET: switch (type) { case SCM_CREDS: datasize = sizeof(struct cmsgcred); break; case SCM_RIGHTS: error = fmaster_read_int(td, &nfds, &nfds_len); if (error != 0) return (error); actual_payload_size += nfds_len; spec->cmsgspec_nfds = nfds; datasize = sizeof(int) * nfds; break; default: datasize = 0; break; } break; default: datasize = 0; break; } spec->cmsgspec_len = CMSG_LEN(datasize); spec->cmsgspec_space = CMSG_SPACE(datasize); } *cmsgspecs = specs; *payload_size = actual_payload_size; return (0); }
void ngx_event_recvmsg(ngx_event_t *ev) { ssize_t n; ngx_log_t *log; ngx_err_t err; ngx_event_t *rev, *wev; struct iovec iov[1]; struct msghdr msg; ngx_listening_t *ls; ngx_event_conf_t *ecf; ngx_connection_t *c, *lc; u_char sa[NGX_SOCKADDRLEN]; static u_char buffer[65535]; #if (NGX_HAVE_MSGHDR_MSG_CONTROL) #if (NGX_HAVE_IP_RECVDSTADDR) u_char msg_control[CMSG_SPACE(sizeof(struct in_addr))]; #elif (NGX_HAVE_IP_PKTINFO) u_char msg_control[CMSG_SPACE(sizeof(struct in_pktinfo))]; #endif #if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO) u_char msg_control6[CMSG_SPACE(sizeof(struct in6_pktinfo))]; #endif #endif if (ev->timedout) { if (ngx_enable_accept_events((ngx_cycle_t *) ngx_cycle) != NGX_OK) { return; } ev->timedout = 0; } ecf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_event_core_module); if (!(ngx_event_flags & NGX_USE_KQUEUE_EVENT)) { ev->available = ecf->multi_accept; } lc = ev->data; ls = lc->listening; ev->ready = 0; ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, "recvmsg on %V, ready: %d", &ls->addr_text, ev->available); do { ngx_memzero(&msg, sizeof(struct msghdr)); iov[0].iov_base = (void *) buffer; iov[0].iov_len = sizeof(buffer); msg.msg_name = &sa; msg.msg_namelen = sizeof(sa); msg.msg_iov = iov; msg.msg_iovlen = 1; #if (NGX_HAVE_MSGHDR_MSG_CONTROL) if (ls->wildcard) { #if (NGX_HAVE_IP_RECVDSTADDR || NGX_HAVE_IP_PKTINFO) if (ls->sockaddr->sa_family == AF_INET) { msg.msg_control = &msg_control; msg.msg_controllen = sizeof(msg_control); } #endif #if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO) if (ls->sockaddr->sa_family == AF_INET6) { msg.msg_control = &msg_control6; msg.msg_controllen = sizeof(msg_control6); } #endif } #endif n = recvmsg(lc->fd, &msg, 0); if (n == -1) { err = ngx_socket_errno; if (err == NGX_EAGAIN) { ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, err, "recvmsg() not ready"); return; } ngx_log_error(NGX_LOG_ALERT, ev->log, err, "recvmsg() failed"); return; } #if (NGX_STAT_STUB) (void) ngx_atomic_fetch_add(ngx_stat_accepted, 1); #endif #if (NGX_HAVE_MSGHDR_MSG_CONTROL) if (msg.msg_flags & (MSG_TRUNC|MSG_CTRUNC)) { ngx_log_error(NGX_LOG_ALERT, ev->log, 0, "recvmsg() truncated data"); continue; } #endif ngx_accept_disabled = ngx_cycle->connection_n / 8 - ngx_cycle->free_connection_n; c = ngx_get_connection(lc->fd, ev->log); if (c == NULL) { return; } c->shared = 1; c->type = SOCK_DGRAM; c->socklen = msg.msg_namelen; #if (NGX_STAT_STUB) (void) ngx_atomic_fetch_add(ngx_stat_active, 1); #endif c->pool = ngx_create_pool(ls->pool_size, ev->log); if (c->pool == NULL) { ngx_close_accepted_connection(c); return; } c->sockaddr = ngx_palloc(c->pool, c->socklen); if (c->sockaddr == NULL) { ngx_close_accepted_connection(c); return; } ngx_memcpy(c->sockaddr, msg.msg_name, c->socklen); log = ngx_palloc(c->pool, sizeof(ngx_log_t)); if (log == NULL) { ngx_close_accepted_connection(c); return; } *log = ls->log; c->send = ngx_udp_send; c->log = log; c->pool->log = log; c->listening = ls; c->local_sockaddr = ls->sockaddr; c->local_socklen = ls->socklen; #if (NGX_HAVE_MSGHDR_MSG_CONTROL) if (ls->wildcard) { struct cmsghdr *cmsg; struct sockaddr *sockaddr; sockaddr = ngx_palloc(c->pool, c->local_socklen); if (sockaddr == NULL) { ngx_close_accepted_connection(c); return; } ngx_memcpy(sockaddr, c->local_sockaddr, c->local_socklen); c->local_sockaddr = sockaddr; for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) { #if (NGX_HAVE_IP_RECVDSTADDR) if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_RECVDSTADDR && sockaddr->sa_family == AF_INET) { struct in_addr *addr; struct sockaddr_in *sin; addr = (struct in_addr *) CMSG_DATA(cmsg); sin = (struct sockaddr_in *) sockaddr; sin->sin_addr = *addr; break; } #elif (NGX_HAVE_IP_PKTINFO) if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO && sockaddr->sa_family == AF_INET) { struct in_pktinfo *pkt; struct sockaddr_in *sin; pkt = (struct in_pktinfo *) CMSG_DATA(cmsg); sin = (struct sockaddr_in *) sockaddr; sin->sin_addr = pkt->ipi_addr; break; } #endif #if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO) if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO && sockaddr->sa_family == AF_INET6) { struct in6_pktinfo *pkt6; struct sockaddr_in6 *sin6; pkt6 = (struct in6_pktinfo *) CMSG_DATA(cmsg); sin6 = (struct sockaddr_in6 *) sockaddr; sin6->sin6_addr = pkt6->ipi6_addr; break; } #endif } } #endif c->buffer = ngx_create_temp_buf(c->pool, n); if (c->buffer == NULL) { ngx_close_accepted_connection(c); return; } c->buffer->last = ngx_cpymem(c->buffer->last, buffer, n); rev = c->read; wev = c->write; wev->ready = 1; rev->log = log; wev->log = log; /* * TODO: MT: - ngx_atomic_fetch_add() * or protection by critical section or light mutex * * TODO: MP: - allocated in a shared memory * - ngx_atomic_fetch_add() * or protection by critical section or light mutex */ c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1); #if (NGX_STAT_STUB) (void) ngx_atomic_fetch_add(ngx_stat_handled, 1); #endif if (ls->addr_ntop) { c->addr_text.data = ngx_pnalloc(c->pool, ls->addr_text_max_len); if (c->addr_text.data == NULL) { ngx_close_accepted_connection(c); return; } c->addr_text.len = ngx_sock_ntop(c->sockaddr, c->socklen, c->addr_text.data, ls->addr_text_max_len, 0); if (c->addr_text.len == 0) { ngx_close_accepted_connection(c); return; } } #if (NGX_DEBUG) { ngx_str_t addr; u_char text[NGX_SOCKADDR_STRLEN]; ngx_debug_accepted_connection(ecf, c); if (log->log_level & NGX_LOG_DEBUG_EVENT) { addr.data = text; addr.len = ngx_sock_ntop(c->sockaddr, c->socklen, text, NGX_SOCKADDR_STRLEN, 1); ngx_log_debug4(NGX_LOG_DEBUG_EVENT, log, 0, "*%uA recvmsg: %V fd:%d n:%z", c->number, &addr, c->fd, n); } } #endif log->data = NULL; log->handler = NULL; ls->handler(c); if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { ev->available -= n; } } while (ev->available); }
Object* IO::recv_fd(STATE) { #ifdef _WIN32 return Primitives::failure(); #else struct msghdr msg; struct iovec vec[1]; char buf[1]; struct cmsghdr *cmsg; char cmsg_buf[cmsg_space]; msg.msg_name = NULL; msg.msg_namelen = 0; /* Linux and Solaris doesn't work if msg_iov is NULL. */ buf[0] = '\0'; vec[0].iov_base = buf; vec[0].iov_len = 1; msg.msg_iov = vec; msg.msg_iovlen = 1; msg.msg_control = (caddr_t)cmsg_buf; msg.msg_controllen = sizeof(cmsg_buf); msg.msg_flags = 0; cmsg = CMSG_FIRSTHDR(&msg); memset(cmsg_buf, 0, sizeof(cmsg_buf)); cmsg->cmsg_len = CMSG_LEN(sizeof(int)); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; // Workaround for GCC's broken strict-aliasing checks. int* fd_data = (int *)CMSG_DATA(cmsg); *fd_data = -1; int read_fd = descriptor(state); int code = -1; retry: state->vm()->interrupt_with_signal(); state->vm()->thread()->sleep(state, cTrue); { UnmanagedPhase unmanaged(state); code = recvmsg(read_fd, &msg, 0); } state->vm()->thread()->sleep(state, cFalse); state->vm()->clear_waiter(); if(code == -1) { if(errno == EAGAIN || errno == EINTR) { if(state->vm()->thread_interrupted_p(state)) return NULL; ensure_open(state); goto retry; } return Primitives::failure(); } if(msg.msg_controllen != CMSG_SPACE(sizeof(int)) || cmsg->cmsg_len != CMSG_LEN(sizeof(int)) || cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) { return Primitives::failure(); } // Workaround for GCC's broken strict-aliasing checks. fd_data = (int *)CMSG_DATA(cmsg); return Fixnum::from(*fd_data); #endif }
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; }
static PyObject *sendmsg_sendmsg(PyObject *self, PyObject *args, PyObject *keywds) { int fd; int flags = 0; Py_ssize_t sendmsg_result, iovec_length; struct msghdr message_header; struct iovec iov[1]; PyObject *ancillary = NULL; PyObject *iterator = NULL; PyObject *item = NULL; PyObject *result_object = NULL; static char *kwlist[] = {"fd", "data", "flags", "ancillary", NULL}; if (!PyArg_ParseTupleAndKeywords( args, keywds, "it#|iO:sendmsg", kwlist, &fd, &iov[0].iov_base, &iovec_length, &flags, &ancillary)) { return NULL; } iov[0].iov_len = iovec_length; message_header.msg_name = NULL; message_header.msg_namelen = 0; message_header.msg_iov = iov; message_header.msg_iovlen = 1; message_header.msg_control = NULL; message_header.msg_controllen = 0; message_header.msg_flags = 0; if (ancillary) { if (!PyList_Check(ancillary)) { PyErr_Format(PyExc_TypeError, "send1msg argument 3 expected list, got %s", ancillary->ob_type->tp_name); goto finished; } iterator = PyObject_GetIter(ancillary); if (iterator == NULL) { goto finished; } size_t all_data_len = 0; /* First we need to know how big the buffer needs to be in order to have enough space for all of the messages. */ while ( (item = PyIter_Next(iterator)) ) { int type, level; Py_ssize_t data_len; size_t prev_all_data_len; char *data; if (!PyTuple_Check(item)) { PyErr_Format(PyExc_TypeError, "send1msg argument 3 expected list of tuple, " "got list containing %s", item->ob_type->tp_name); goto finished; } if (!PyArg_ParseTuple( item, "iit#:sendmsg ancillary data (level, type, data)", &level, &type, &data, &data_len)) { goto finished; } prev_all_data_len = all_data_len; all_data_len += CMSG_SPACE(data_len); Py_DECREF(item); item = NULL; if (all_data_len < prev_all_data_len) { PyErr_Format(PyExc_OverflowError, "Too much msg_control to fit in a size_t: %zu", prev_all_data_len); goto finished; } } Py_DECREF(iterator); iterator = NULL; /* Allocate the buffer for all of the ancillary elements, if we have * any. */ if (all_data_len) { if (all_data_len > SOCKLEN_MAX) { PyErr_Format(PyExc_OverflowError, "Too much msg_control to fit in a socklen_t: %zu", all_data_len); goto finished; } message_header.msg_control = PyMem_Malloc(all_data_len); if (!message_header.msg_control) { PyErr_NoMemory(); goto finished; } /* From Python 3.5.2 socketmodule.c:3891: Need to zero out the buffer as a workaround for glibc's CMSG_NXTHDR() implementation. After getting the pointer to the next header, it checks its (uninitialized) cmsg_len member to see if the "message" fits in the buffer, and returns NULL if it doesn't. Zero-filling the buffer ensures that this doesn't happen. */ memset(message_header.msg_control, 0, all_data_len); } else { message_header.msg_control = NULL; } message_header.msg_controllen = (socklen_t) all_data_len; iterator = PyObject_GetIter(ancillary); /* again */ if (!iterator) { goto finished; } /* Unpack the tuples into the control message. */ struct cmsghdr *control_message = CMSG_FIRSTHDR(&message_header); while ( (item = PyIter_Next(iterator)) && control_message!=NULL ) { int type, level; Py_ssize_t data_len; size_t data_size; unsigned char *data, *cmsg_data; /* We explicitly allocated enough space for all ancillary data above; if there isn't enough room, all bets are off. */ assert(control_message); if (!PyArg_ParseTuple(item, "iit#:sendmsg ancillary data (level, type, data)", &level, &type, &data, &data_len)) { goto finished; } control_message->cmsg_level = level; control_message->cmsg_type = type; data_size = CMSG_LEN(data_len); if (data_size > SOCKLEN_MAX) { PyErr_Format(PyExc_OverflowError, "CMSG_LEN(%zd) > SOCKLEN_MAX", data_len); goto finished; } control_message->cmsg_len = (socklen_t) data_size; cmsg_data = CMSG_DATA(control_message); memcpy(cmsg_data, data, data_len); Py_DECREF(item); item = NULL; control_message = CMSG_NXTHDR(&message_header, control_message); } Py_DECREF(iterator); iterator = NULL; if (PyErr_Occurred()) { goto finished; } } sendmsg_result = sendmsg(fd, &message_header, flags); if (sendmsg_result < 0) { PyErr_SetFromErrno(sendmsg_socket_error); goto finished; } result_object = Py_BuildValue("n", sendmsg_result); finished: if (item) { Py_DECREF(item); item = NULL; } if (iterator) { Py_DECREF(iterator); iterator = NULL; } if (message_header.msg_control) { PyMem_Free(message_header.msg_control); message_header.msg_control = NULL; } return result_object; }
static int dgram_sctp_write(BIO *b, const char *in, int inl) { int ret; bio_dgram_sctp_data *data = (bio_dgram_sctp_data *)b->ptr; struct bio_dgram_sctp_sndinfo *sinfo = &(data->sndinfo); struct bio_dgram_sctp_prinfo *pinfo = &(data->prinfo); struct bio_dgram_sctp_sndinfo handshake_sinfo; struct iovec iov[1]; struct msghdr msg; struct cmsghdr *cmsg; #if defined(SCTP_SNDINFO) && defined(SCTP_PRINFO) char cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndinfo)) + CMSG_SPACE(sizeof(struct sctp_prinfo))]; struct sctp_sndinfo *sndinfo; struct sctp_prinfo *prinfo; #else char cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))]; struct sctp_sndrcvinfo *sndrcvinfo; #endif clear_socket_error(); /* If we're send anything else than application data, * disable all user parameters and flags. */ if (in[0] != 23) { memset(&handshake_sinfo, 0x00, sizeof(struct bio_dgram_sctp_sndinfo)); #ifdef SCTP_SACK_IMMEDIATELY handshake_sinfo.snd_flags = SCTP_SACK_IMMEDIATELY; #endif sinfo = &handshake_sinfo; } /* If we have to send a shutdown alert message and the * socket is not dry yet, we have to save it and send it * as soon as the socket gets dry. */ if (data->save_shutdown && !BIO_dgram_sctp_wait_for_dry(b)) { data->saved_message.bio = b; data->saved_message.length = inl; data->saved_message.data = OPENSSL_malloc(inl); memcpy(data->saved_message.data, in, inl); return inl; } iov[0].iov_base = (char *)in; iov[0].iov_len = inl; msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_iov = iov; msg.msg_iovlen = 1; msg.msg_control = (caddr_t)cmsgbuf; msg.msg_controllen = 0; msg.msg_flags = 0; #if defined(SCTP_SNDINFO) && defined(SCTP_PRINFO) cmsg = (struct cmsghdr *)cmsgbuf; cmsg->cmsg_level = IPPROTO_SCTP; cmsg->cmsg_type = SCTP_SNDINFO; cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo)); sndinfo = (struct sctp_sndinfo *)CMSG_DATA(cmsg); memset(sndinfo, 0, sizeof(struct sctp_sndinfo)); sndinfo->snd_sid = sinfo->snd_sid; sndinfo->snd_flags = sinfo->snd_flags; sndinfo->snd_ppid = sinfo->snd_ppid; sndinfo->snd_context = sinfo->snd_context; msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo)); cmsg = (struct cmsghdr *)&cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndinfo))]; cmsg->cmsg_level = IPPROTO_SCTP; cmsg->cmsg_type = SCTP_PRINFO; cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo)); prinfo = (struct sctp_prinfo *)CMSG_DATA(cmsg); memset(prinfo, 0, sizeof(struct sctp_prinfo)); prinfo->pr_policy = pinfo->pr_policy; prinfo->pr_value = pinfo->pr_value; msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo)); #else cmsg = (struct cmsghdr *)cmsgbuf; cmsg->cmsg_level = IPPROTO_SCTP; cmsg->cmsg_type = SCTP_SNDRCV; cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); sndrcvinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); memset(sndrcvinfo, 0, sizeof(struct sctp_sndrcvinfo)); sndrcvinfo->sinfo_stream = sinfo->snd_sid; sndrcvinfo->sinfo_flags = sinfo->snd_flags; #ifdef __FreeBSD__ sndrcvinfo->sinfo_flags |= pinfo->pr_policy; #endif sndrcvinfo->sinfo_ppid = sinfo->snd_ppid; sndrcvinfo->sinfo_context = sinfo->snd_context; sndrcvinfo->sinfo_timetolive = pinfo->pr_value; msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndrcvinfo)); #endif ret = sendmsg(b->num, &msg, 0); BIO_clear_retry_flags(b); if (ret <= 0) { if (BIO_dgram_should_retry(ret)) { BIO_set_retry_write(b); data->_errno = get_last_socket_error(); } } return(ret); }
static void aodv_socket_read(int fd) { u_int32_t src, dst; int i, len, ttl = 0; AODV_msg *aodv_msg; #ifdef USE_IW_SPY char ifname[IFNAMSIZ]; #endif /* USE_IW_SPY */ #ifdef RAW_SOCKET int iph_len; struct iphdr *iph; struct udphdr *udph; len = recvfrom(fd, recv_buf, RECV_BUF_SIZE, 0, NULL, NULL); if (len < 0 || len < IPHDR_SIZE) { log(LOG_WARNING, 0, __FUNCTION__, "receive ERROR!"); return; } /* Parse the IP header */ iph = (struct iphdr *) recv_buf; src = ntohl(iph->saddr); dst = ntohl(iph->daddr); ttl = iph->ttl; iph_len = iph->ihl << 2; udph = (struct udphdr *) (recv_buf + iph_len); if (ntohs(udph->dest) != AODV_PORT && ntohs(udph->source) != AODV_PORT) return; /* Ignore messages generated locally */ for (i = 0; i < MAX_NR_INTERFACES; i++) if (this_host.devs[i].enabled && memcmp(&src, &this_host.devs[i].ipaddr, sizeof(u_int32_t)) == 0) return; aodv_msg = (AODV_msg *) (recv_buf + iph_len + sizeof(struct udphdr)); len = ntohs(udph->len) - sizeof(struct udphdr); #else struct sockaddr_in src_addr; struct msghdr msg; union { struct cmsghdr cm; char control[CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(struct in_pktinfo))]; } control_union; struct cmsghdr *cmsg; struct in_pktinfo pktinfo; int sockaddr_len = sizeof(struct sockaddr_in); msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_iov = NULL; msg.msg_iovlen = 0; msg.msg_control = control_union.control; msg.msg_controllen = sizeof(control_union.control); /* Get the information control message first */ if ((len = recvmsg(fd, &msg, MSG_PEEK)) < 0) { log(LOG_WARNING, 0, __FUNCTION__, "recvmsg ERROR!"); return; } /* Read the data payload (i.e. AODV msg) */ len = recvfrom(fd, recv_buf, RECV_BUF_SIZE, 0, (struct sockaddr *) &src_addr, &sockaddr_len); if (len < 0) { log(LOG_WARNING, 0, __FUNCTION__, "receive ERROR!"); return; } aodv_msg = (AODV_msg *) (recv_buf); src = ntohl(src_addr.sin_addr.s_addr); /* Ignore messages generated locally */ for (i = 0; i < MAX_NR_INTERFACES; i++) if (this_host.devs[i].enabled && memcmp(&src, &this_host.devs[i].ipaddr, sizeof(u_int32_t)) == 0) return; /* Get the TTL and pktinfo struct (destination address) from the control messages... For some reason the correct use of the CMSG(3) macros using CMSG_NXTHDR does not work across different Red Hat versions (6.2 vs 7.2), but this code seem to work: */ cmsg = CMSG_FIRSTHDR(&msg); for (i = 0; i < 2; i++) { if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_TTL) { memcpy(&ttl, CMSG_DATA(cmsg), sizeof(int)); cmsg = (void *) cmsg + CMSG_SPACE(sizeof(int)); } else if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_PKTINFO) { memcpy(&pktinfo, CMSG_DATA(cmsg), sizeof(struct in_pktinfo)); cmsg = (void *) cmsg + CMSG_SPACE(sizeof(struct in_pktinfo)); } } dst = ntohl(pktinfo.ipi_addr.s_addr); #endif /* RAW_SOCKET */ #ifdef USE_IW_SPY if (spy_addrs && link_qual_get_from_ip(src, if_indextoname(pktinfo.ipi_ifindex, ifname)) < hello_qual_threshold) return; #endif /* USE_IW_SPY */ aodv_socket_process_packet(aodv_msg, len, src, dst, ttl, pktinfo.ipi_ifindex); }
void pass_fd(int sfd, int fd_to_send) { struct msghdr msg; /*allocate memory to 'msg_control' field in msghdr struct */ char buf[CMSG_SPACE(sizeof(int))]; /*the memory to be allocated should include data + header.. this is calculated by the above macro...(it merely adds some no. of bytes and returs that number..*/ struct cmsghdr *cmsg; struct iovec ve; /*must send/receive atleast one byte... main purpose is to have some error checking.. but this is completely irrelevant in the current context..*/ char *st ="I"; /*jst let us allocate 1 byte for formality and leave it that way...*/ ve.iov_base = st; ve.iov_len =1; /*attach this memory to our main msghdr struct...*/ msg.msg_iov = &ve; msg.msg_iovlen = 1; /*these are optional fields .. leave these fields with zeros.. to prevent unnecessary SIGSEGVs..*/ msg.msg_name = NULL; msg.msg_namelen = 0; /*here starts the main part..*/ /*attach the 'buf' to msg_control.. and fill in the size field correspondingly.. */ msg.msg_control = buf; msg.msg_controllen = sizeof(buf); /*actually msg_control field must point to a struct of type 'cmsghdr' we just allocated the memory, yet we need to set all the corresponding fields.. It is done as follows: */ cmsg = CMSG_FIRSTHDR(&msg); /* this macro returns the address in the buffer.. from where the first header starts.. */ /*set all the fields appropriately..*/ cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; cmsg->cmsg_len = CMSG_LEN(sizeof(fd_to_send)); /*in the above field we need to store the size of header + data(in this case 4 bytes(int) for our fd.. this is returned by the 'CMSG_LEN' macro..*/ *(int*)CMSG_DATA(cmsg) = fd_to_send; /*after the above three fields we keep the actual data.. the macro 'CMSG_DATA' returns pointer to this location and we set it to the file descriptor to be sent.. */ msg.msg_controllen = cmsg->cmsg_len; /*now that we have filled the 'cmsg' struct we store the size of this struct..*/ /*this one isn't required when you pass a single fd.. but useful when u pass multiple fds.*/ msg.msg_flags = 0; /*leave the flags field zeroed..*/ if(sendmsg( sfd, &msg, 0)==-1){ perror("snd:\n"); exit(1); } /*send this over the UNIX deomain socoket..*/ printf("sent fd:%d\n", fd_to_send); close(fd_to_send); /*close the fd which was sent..*/ }
/** * Send netlink message. * @arg sk Netlink socket. * @arg msg Netlink message to be sent. * @arg iov iovec to be sent. * @arg iovlen number of struct iovec to be sent. * @see nl_sendmsg() * @return Number of characters sent on success or a negative error code. */ int nl_send_iovec(struct nl_sock *sk, struct nl_msg *msg, struct iovec *iov, unsigned iovlen) { struct sockaddr_nl *dst; struct ucred *creds; struct msghdr hdr = { .msg_name = (void *) &sk->s_peer, .msg_namelen = sizeof(struct sockaddr_nl), .msg_iov = iov, .msg_iovlen = iovlen, }; /* Overwrite destination if specified in the message itself, defaults * to the peer address of the socket. */ dst = nlmsg_get_dst(msg); if (dst->nl_family == AF_NETLINK) hdr.msg_name = dst; /* Add credentials if present. */ creds = nlmsg_get_creds(msg); if (creds != NULL) { char buf[CMSG_SPACE(sizeof(struct ucred))]; struct cmsghdr *cmsg; hdr.msg_control = buf; hdr.msg_controllen = sizeof(buf); cmsg = CMSG_FIRSTHDR(&hdr); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_CREDENTIALS; cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred)); memcpy(CMSG_DATA(cmsg), creds, sizeof(struct ucred)); } return nl_sendmsg(sk, msg, &hdr); } /** * Send netlink message. * @arg sk Netlink socket. * @arg msg Netlink message to be sent. * @see nl_sendmsg() * @return Number of characters sent on success or a negative error code. */ int nl_send(struct nl_sock *sk, struct nl_msg *msg) { struct iovec iov = { .iov_base = (void *) nlmsg_hdr(msg), .iov_len = nlmsg_hdr(msg)->nlmsg_len, }; return nl_send_iovec(sk, msg, &iov, 1); } void nl_auto_complete(struct nl_sock *sk, struct nl_msg *msg) { struct nlmsghdr *nlh; nlh = nlmsg_hdr(msg); if (nlh->nlmsg_pid == 0) nlh->nlmsg_pid = sk->s_local.nl_pid; if (nlh->nlmsg_seq == 0) nlh->nlmsg_seq = sk->s_seq_next++; if (msg->nm_protocol == -1) msg->nm_protocol = sk->s_proto; nlh->nlmsg_flags |= NLM_F_REQUEST; if (!(sk->s_flags & NL_NO_AUTO_ACK)) nlh->nlmsg_flags |= NLM_F_ACK; } /** * Send netlink message and check & extend header values as needed. * @arg sk Netlink socket. * @arg msg Netlink message to be sent. * * Checks the netlink message \c nlh for completness and extends it * as required before sending it out. Checked fields include pid, * sequence nr, and flags. * * @see nl_send() * @return Number of characters sent or a negative error code. */ int nl_send_auto_complete(struct nl_sock *sk, struct nl_msg *msg) { struct nl_cb *cb = sk->s_cb; nl_auto_complete(sk, msg); if (cb->cb_send_ow) return cb->cb_send_ow(sk, msg); else return nl_send(sk, msg); } /** * Send simple netlink message using nl_send_auto_complete() * @arg sk Netlink socket. * @arg type Netlink message type. * @arg flags Netlink message flags. * @arg buf Data buffer. * @arg size Size of data buffer. * * Builds a netlink message with the specified type and flags and * appends the specified data as payload to the message. * * @see nl_send_auto_complete() * @return Number of characters sent on success or a negative error code. */ int nl_send_simple(struct nl_sock *sk, int type, int flags, void *buf, size_t size) { int err; struct nl_msg *msg; msg = nlmsg_alloc_simple(type, flags); if (!msg) return -NLE_NOMEM; if (buf && size) { err = nlmsg_append(msg, buf, size, NLMSG_ALIGNTO); if (err < 0) goto errout; } err = nl_send_auto_complete(sk, msg); errout: nlmsg_free(msg); return err; } /** @} */ /** * @name Receive * @{ */ /** * Receive data from netlink socket * @arg sk Netlink socket. * @arg nla Destination pointer for peer's netlink address. * @arg buf Destination pointer for message content. * @arg creds Destination pointer for credentials. * * Receives a netlink message, allocates a buffer in \c *buf and * stores the message content. The peer's netlink address is stored * in \c *nla. The caller is responsible for freeing the buffer allocated * in \c *buf if a positive value is returned. Interruped system calls * are handled by repeating the read. The input buffer size is determined * by peeking before the actual read is done. * * A non-blocking sockets causes the function to return immediately with * a return value of 0 if no data is available. * * @return Number of octets read, 0 on EOF or a negative error code. */ int nl_recv(struct nl_sock *sk, struct sockaddr_nl *nla, unsigned char **buf, struct ucred **creds) { int n; int flags = 0; static int page_size = 0; struct iovec iov; struct msghdr msg = { .msg_name = (void *) nla, .msg_namelen = sizeof(struct sockaddr_nl), .msg_iov = &iov, .msg_iovlen = 1, .msg_control = NULL, .msg_controllen = 0, .msg_flags = 0, }; struct cmsghdr *cmsg; if (sk->s_flags & NL_MSG_PEEK) flags |= MSG_PEEK; if (page_size == 0) page_size = getpagesize(); iov.iov_len = page_size; iov.iov_base = *buf = malloc(iov.iov_len); if (sk->s_flags & NL_SOCK_PASSCRED) { msg.msg_controllen = CMSG_SPACE(sizeof(struct ucred)); msg.msg_control = calloc(1, msg.msg_controllen); } retry: n = recvmsg(sk->s_fd, &msg, flags); if (!n) goto abort; else if (n < 0) { if (errno == EINTR) { NL_DBG(3, "recvmsg() returned EINTR, retrying\n"); goto retry; } else if (errno == EAGAIN) { NL_DBG(3, "recvmsg() returned EAGAIN, aborting\n"); goto abort; } else { free(msg.msg_control); free(*buf); return -nl_syserr2nlerr(errno); } } if (iov.iov_len < n || msg.msg_flags & MSG_TRUNC) { /* Provided buffer is not long enough, enlarge it * and try again. */ iov.iov_len *= 2; iov.iov_base = *buf = realloc(*buf, iov.iov_len); goto retry; } else if (msg.msg_flags & MSG_CTRUNC) { msg.msg_controllen *= 2; msg.msg_control = realloc(msg.msg_control, msg.msg_controllen); goto retry; } else if (flags != 0) { /* Buffer is big enough, do the actual reading */ flags = 0; goto retry; } if (msg.msg_namelen != sizeof(struct sockaddr_nl)) { free(msg.msg_control); free(*buf); return -NLE_NOADDR; } for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_CREDENTIALS) { *creds = calloc(1, sizeof(struct ucred)); memcpy(*creds, CMSG_DATA(cmsg), sizeof(struct ucred)); break; } } free(msg.msg_control); return n; abort: free(msg.msg_control); free(*buf); return 0; } #define NL_CB_CALL(cb, type, msg) \ do { \ err = nl_cb_call(cb, type, msg); \ switch (err) { \ case NL_OK: \ err = 0; \ break; \ case NL_SKIP: \ goto skip; \ case NL_STOP: \ goto stop; \ default: \ goto out; \ } \ } while (0) static int recvmsgs(struct nl_sock *sk, struct nl_cb *cb) { int n, err = 0, multipart = 0; unsigned char *buf = NULL; struct nlmsghdr *hdr; struct sockaddr_nl nla = {0}; struct nl_msg *msg = NULL; struct ucred *creds = NULL; continue_reading: NL_DBG(3, "Attempting to read from %p\n", sk); if (cb->cb_recv_ow) n = cb->cb_recv_ow(sk, &nla, &buf, &creds); else n = nl_recv(sk, &nla, &buf, &creds); if (n <= 0) return n; NL_DBG(3, "recvmsgs(%p): Read %d bytes\n", sk, n); hdr = (struct nlmsghdr *) buf; while (nlmsg_ok(hdr, n)) { NL_DBG(3, "recgmsgs(%p): Processing valid message...\n", sk); nlmsg_free(msg); msg = nlmsg_convert(hdr); if (!msg) { err = -NLE_NOMEM; goto out; } nlmsg_set_proto(msg, sk->s_proto); nlmsg_set_src(msg, &nla); if (creds) nlmsg_set_creds(msg, creds); /* Raw callback is the first, it gives the most control * to the user and he can do his very own parsing. */ if (cb->cb_set[NL_CB_MSG_IN]) NL_CB_CALL(cb, NL_CB_MSG_IN, msg); /* Sequence number checking. The check may be done by * the user, otherwise a very simple check is applied * enforcing strict ordering */ if (cb->cb_set[NL_CB_SEQ_CHECK]) NL_CB_CALL(cb, NL_CB_SEQ_CHECK, msg); else if (hdr->nlmsg_seq != sk->s_seq_expect) { if (cb->cb_set[NL_CB_INVALID]) NL_CB_CALL(cb, NL_CB_INVALID, msg); else { err = -NLE_SEQ_MISMATCH; goto out; } } if (hdr->nlmsg_type == NLMSG_DONE || hdr->nlmsg_type == NLMSG_ERROR || hdr->nlmsg_type == NLMSG_NOOP || hdr->nlmsg_type == NLMSG_OVERRUN) { /* We can't check for !NLM_F_MULTI since some netlink * users in the kernel are broken. */ sk->s_seq_expect++; NL_DBG(3, "recvmsgs(%p): Increased expected " \ "sequence number to %d\n", sk, sk->s_seq_expect); } if (hdr->nlmsg_flags & NLM_F_MULTI) multipart = 1; /* Other side wishes to see an ack for this message */ if (hdr->nlmsg_flags & NLM_F_ACK) { if (cb->cb_set[NL_CB_SEND_ACK]) NL_CB_CALL(cb, NL_CB_SEND_ACK, msg); else { /* FIXME: implement */ } } /* messages terminates a multpart message, this is * usually the end of a message and therefore we slip * out of the loop by default. the user may overrule * this action by skipping this packet. */ if (hdr->nlmsg_type == NLMSG_DONE) { multipart = 0; if (cb->cb_set[NL_CB_FINISH]) NL_CB_CALL(cb, NL_CB_FINISH, msg); } /* Message to be ignored, the default action is to * skip this message if no callback is specified. The * user may overrule this action by returning * NL_PROCEED. */ else if (hdr->nlmsg_type == NLMSG_NOOP) { if (cb->cb_set[NL_CB_SKIPPED]) NL_CB_CALL(cb, NL_CB_SKIPPED, msg); else goto skip; } /* Data got lost, report back to user. The default action is to * quit parsing. The user may overrule this action by retuning * NL_SKIP or NL_PROCEED (dangerous) */ else if (hdr->nlmsg_type == NLMSG_OVERRUN) { if (cb->cb_set[NL_CB_OVERRUN]) NL_CB_CALL(cb, NL_CB_OVERRUN, msg); else { err = -NLE_MSG_OVERFLOW; goto out; } } /* Message carries a nlmsgerr */ else if (hdr->nlmsg_type == NLMSG_ERROR) { struct nlmsgerr *e = nlmsg_data(hdr); if (hdr->nlmsg_len < nlmsg_msg_size(sizeof(*e))) { /* Truncated error message, the default action * is to stop parsing. The user may overrule * this action by returning NL_SKIP or * NL_PROCEED (dangerous) */ if (cb->cb_set[NL_CB_INVALID]) NL_CB_CALL(cb, NL_CB_INVALID, msg); else { err = -NLE_MSG_TRUNC; goto out; } } else if (e->error) { /* Error message reported back from kernel. */ if (cb->cb_err) { err = cb->cb_err(&nla, e, cb->cb_err_arg); if (err < 0) goto out; else if (err == NL_SKIP) goto skip; else if (err == NL_STOP) { err = -nl_syserr2nlerr(e->error); goto out; } } else { err = -nl_syserr2nlerr(e->error); goto out; } } else if (cb->cb_set[NL_CB_ACK]) NL_CB_CALL(cb, NL_CB_ACK, msg); } else { /* Valid message (not checking for MULTIPART bit to * get along with broken kernels. NL_SKIP has no * effect on this. */ if (cb->cb_set[NL_CB_VALID]) NL_CB_CALL(cb, NL_CB_VALID, msg); } skip: err = 0; hdr = nlmsg_next(hdr, &n); } nlmsg_free(msg); free(buf); free(creds); buf = NULL; msg = NULL; creds = NULL; if (multipart) { /* Multipart message not yet complete, continue reading */ goto continue_reading; } stop: err = 0; out: nlmsg_free(msg); free(buf); free(creds); return err; }
bool Connection::sendOutgoingMessage(std::unique_ptr<MessageEncoder> encoder) { COMPILE_ASSERT(sizeof(MessageInfo) + attachmentMaxAmount * sizeof(size_t) <= messageMaxSize, AttachmentsFitToMessageInline); Vector<Attachment> attachments = encoder->releaseAttachments(); AttachmentResourceGuard<Vector<Attachment>, Vector<Attachment>::iterator> attachementDisposer(attachments); if (attachments.size() > (attachmentMaxAmount - 1)) { ASSERT_NOT_REACHED(); return false; } MessageInfo messageInfo(encoder->bufferSize(), attachments.size()); size_t messageSizeWithBodyInline = sizeof(messageInfo) + (attachments.size() * sizeof(AttachmentInfo)) + encoder->bufferSize(); if (messageSizeWithBodyInline > messageMaxSize && encoder->bufferSize()) { RefPtr<WebKit::SharedMemory> oolMessageBody = WebKit::SharedMemory::create(encoder->bufferSize()); if (!oolMessageBody) return false; WebKit::SharedMemory::Handle handle; if (!oolMessageBody->createHandle(handle, WebKit::SharedMemory::ReadOnly)) return false; messageInfo.setMessageBodyIsOutOfLine(); memcpy(oolMessageBody->data(), encoder->buffer(), encoder->bufferSize()); attachments.append(handle.releaseToAttachment()); } struct msghdr message; memset(&message, 0, sizeof(message)); struct iovec iov[3]; memset(&iov, 0, sizeof(iov)); message.msg_iov = iov; int iovLength = 1; iov[0].iov_base = reinterpret_cast<void*>(&messageInfo); iov[0].iov_len = sizeof(messageInfo); auto attachmentInfo = std::make_unique<AttachmentInfo[]>(attachments.size()); size_t attachmentFDBufferLength = 0; if (!attachments.isEmpty()) { for (size_t i = 0; i < attachments.size(); ++i) { if (attachments[i].fileDescriptor() != -1) attachmentFDBufferLength++; } } auto attachmentFDBuffer = std::make_unique<char[]>(CMSG_SPACE(sizeof(int) * attachmentFDBufferLength)); if (!attachments.isEmpty()) { int* fdPtr = 0; if (attachmentFDBufferLength) { message.msg_control = attachmentFDBuffer.get(); message.msg_controllen = CMSG_SPACE(sizeof(int) * attachmentFDBufferLength); memset(message.msg_control, 0, message.msg_controllen); struct cmsghdr* cmsg = CMSG_FIRSTHDR(&message); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; cmsg->cmsg_len = CMSG_LEN(sizeof(int) * attachmentFDBufferLength); fdPtr = reinterpret_cast<int*>(CMSG_DATA(cmsg)); } int fdIndex = 0; for (size_t i = 0; i < attachments.size(); ++i) { attachmentInfo[i].setType(attachments[i].type()); switch (attachments[i].type()) { case Attachment::MappedMemoryType: attachmentInfo[i].setSize(attachments[i].size()); // Fall trhough, set file descriptor or null. case Attachment::SocketType: if (attachments[i].fileDescriptor() != -1) { ASSERT(fdPtr); fdPtr[fdIndex++] = attachments[i].fileDescriptor(); } else attachmentInfo[i].setNull(); break; case Attachment::Uninitialized: default: break; } } iov[iovLength].iov_base = attachmentInfo.get(); iov[iovLength].iov_len = sizeof(AttachmentInfo) * attachments.size(); ++iovLength; } if (!messageInfo.isMessageBodyIsOutOfLine() && encoder->bufferSize()) { iov[iovLength].iov_base = reinterpret_cast<void*>(encoder->buffer()); iov[iovLength].iov_len = encoder->bufferSize(); ++iovLength; } message.msg_iovlen = iovLength; int bytesSent = 0; while ((bytesSent = sendmsg(m_socketDescriptor, &message, 0)) == -1) { if (errno != EINTR) return false; } return true; }
/** * Install the seccomp-bpf that generates trace traps for all syscalls * other than those made through _untraced_syscall_entry_point(). */ static void install_syscall_filter(void) { void* untraced_syscall_start = get_untraced_syscall_entry_point(); struct sock_filter filter[] = { /* Allow all system calls from our protected_call * callsite */ ALLOW_SYSCALLS_FROM_CALLSITE((uintptr_t)untraced_syscall_start), /* All the rest are handled in rr */ TRACE_PROCESS, }; struct sock_fprog prog = { .len = (unsigned short)(sizeof(filter)/sizeof(filter[0])), .filter = filter, }; debug("Initializing syscall buffer: protected_call_start = %p", untraced_syscall_start); if (traced_prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { fatal("prctl(NO_NEW_PRIVS) failed, SECCOMP_FILTER is not available: your kernel is too old. Use `record -n` to disable the filter."); } /* Note: the filter is installed only for record. This call * will be emulated in the replay */ if (traced_prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, (uintptr_t)&prog, 0, 0)) { fatal("prctl(SECCOMP) failed, SECCOMP_FILTER is not available: your kernel is too old. Use `record -n` to disable the filter."); } /* anything that happens from this point on gets filtered! */ } /** * Return a counter that generates a signal targeted at this task * every time the task is descheduled |nr_descheds| times. */ static int open_desched_event_counter(size_t nr_descheds, pid_t tid) { struct perf_event_attr attr; int fd; struct f_owner_ex own; memset(&attr, 0, sizeof(attr)); attr.size = sizeof(attr); attr.type = PERF_TYPE_SOFTWARE; attr.config = PERF_COUNT_SW_CONTEXT_SWITCHES; attr.disabled = 1; attr.sample_period = nr_descheds; fd = traced_perf_event_open(&attr, 0/*self*/, -1/*any cpu*/, -1, 0); if (0 > fd) { fatal("Failed to perf_event_open(cs, period=%u)", nr_descheds); } if (traced_fcntl(fd, F_SETFL, O_ASYNC)) { fatal("Failed to fcntl(O_ASYNC) the desched counter"); } own.type = F_OWNER_TID; own.pid = tid; if (traced_fcntl(fd, F_SETOWN_EX, &own)) { fatal("Failed to fcntl(SETOWN_EX) the desched counter to this"); } if (traced_fcntl(fd, F_SETSIG, SYSCALLBUF_DESCHED_SIGNAL)) { fatal("Failed to fcntl(SETSIG, %d) the desched counter", SYSCALLBUF_DESCHED_SIGNAL); } return fd; } static void set_up_buffer(void) { struct sockaddr_un addr; struct msghdr msg; struct iovec data; int msgbuf; struct cmsghdr* cmsg; int* msg_fdptr; int* cmsg_fdptr; char cmsgbuf[CMSG_SPACE(sizeof(*cmsg_fdptr))]; struct socketcall_args args_vec; struct rrcall_init_buffers_params args; pid_t tid = traced_gettid(); assert(!buffer); /* NB: we want this setup emulated during replay. */ if (buffer_enabled) { desched_counter_fd = open_desched_event_counter(1, tid); } /* Prepare arguments for rrcall. We do this in the tracee * just to avoid some hairy IPC to set up the arguments * remotely from the tracer; this isn't strictly * necessary. */ prepare_syscallbuf_socket_addr(&addr, tid); memset(&msg, 0, sizeof(msg)); msg_fdptr = &msgbuf; data.iov_base = msg_fdptr; data.iov_len = sizeof(msgbuf); msg.msg_iov = &data; msg.msg_iovlen = 1; msg.msg_control = cmsgbuf; msg.msg_controllen = sizeof(cmsgbuf); cmsg = CMSG_FIRSTHDR(&msg); cmsg->cmsg_len = CMSG_LEN(sizeof(*cmsg_fdptr)); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; cmsg_fdptr = (int*)CMSG_DATA(cmsg); /* Set the "fd parameter" in the message buffer, which we send * to let the other side know the local fd number we shared to * it. */ *msg_fdptr = desched_counter_fd; /* Set the "fd parameter" in the cmsg buffer, which is the one * the kernel parses, dups, then sets to the fd number * allocated in the other process. */ *cmsg_fdptr = desched_counter_fd; args.syscallbuf_enabled = buffer_enabled; args.traced_syscall_ip = get_traced_syscall_entry_point(); args.untraced_syscall_ip = get_untraced_syscall_entry_point(); args.sockaddr = &addr; args.msg = &msg; args.fdptr = cmsg_fdptr; args.args_vec = &args_vec; /* Trap to rr: let the magic begin! We've prepared the buffer * so that it's immediately ready to be sendmsg()'d to rr to * share the desched counter to it (under rr's control). rr * can further use the buffer to share more fd's to us. * * If the desched signal is currently blocked, then the tracer * will clear our TCB guard and we won't be able to buffer * syscalls. But the tracee will set the guard when (or if) * the signal is unblocked. */ rrcall_init_buffers(&args); /* rr initializes the buffer header. */ buffer = args.syscallbuf_ptr; } /** * Initialize thread-local buffering state, if enabled. */ static void init_thread(void) { assert(process_inited); assert(!thread_inited); if (!buffer_enabled) { thread_inited = 1; return; } set_up_buffer(); thread_inited = 1; }
static PyObject *sendmsg_recvmsg(PyObject *self, PyObject *args, PyObject *keywds) { int fd = -1; int flags = 0; int maxsize = 8192; int cmsg_size = 4096; size_t cmsg_space; size_t cmsg_overhead; Py_ssize_t recvmsg_result; struct msghdr message_header; struct cmsghdr *control_message; struct iovec iov[1]; char *cmsgbuf; PyObject *ancillary; PyObject *final_result = NULL; static char *kwlist[] = {"fd", "flags", "maxsize", "cmsg_size", NULL}; if (!PyArg_ParseTupleAndKeywords(args, keywds, "i|iii:recvmsg", kwlist, &fd, &flags, &maxsize, &cmsg_size)) { return NULL; } cmsg_space = CMSG_SPACE(cmsg_size); /* overflow check */ if (cmsg_space > SOCKLEN_MAX) { PyErr_Format(PyExc_OverflowError, "CMSG_SPACE(cmsg_size) greater than SOCKLEN_MAX: %d", cmsg_size); return NULL; } message_header.msg_name = NULL; message_header.msg_namelen = 0; iov[0].iov_len = maxsize; iov[0].iov_base = PyMem_Malloc(maxsize); if (!iov[0].iov_base) { PyErr_NoMemory(); return NULL; } message_header.msg_iov = iov; message_header.msg_iovlen = 1; cmsgbuf = PyMem_Malloc(cmsg_space); if (!cmsgbuf) { PyMem_Free(iov[0].iov_base); PyErr_NoMemory(); return NULL; } memset(cmsgbuf, 0, cmsg_space); message_header.msg_control = cmsgbuf; /* see above for overflow check */ message_header.msg_controllen = (socklen_t) cmsg_space; recvmsg_result = recvmsg(fd, &message_header, flags); if (recvmsg_result < 0) { PyErr_SetFromErrno(sendmsg_socket_error); goto finished; } ancillary = PyList_New(0); if (!ancillary) { goto finished; } for (control_message = CMSG_FIRSTHDR(&message_header); control_message; control_message = CMSG_NXTHDR(&message_header, control_message)) { PyObject *entry; /* Some platforms apparently always fill out the ancillary data structure with a single bogus value if none is provided; ignore it, if that is the case. */ if ((!(control_message->cmsg_level)) && (!(control_message->cmsg_type))) { continue; } /* * Figure out how much of the cmsg size is cmsg structure overhead - in * other words, how much is not part of the application data. This lets * us compute the right application data size below. There should * really be a CMSG_ macro for this. */ cmsg_overhead = (char*)CMSG_DATA(control_message) - (char*)control_message; entry = Py_BuildValue( "(iis#)", control_message->cmsg_level, control_message->cmsg_type, CMSG_DATA(control_message), (Py_ssize_t) (control_message->cmsg_len - cmsg_overhead)); if (!entry) { Py_DECREF(ancillary); goto finished; } if (PyList_Append(ancillary, entry) < 0) { Py_DECREF(ancillary); Py_DECREF(entry); goto finished; } else { Py_DECREF(entry); } } final_result = Py_BuildValue( "s#iO", iov[0].iov_base, recvmsg_result, message_header.msg_flags, ancillary); Py_DECREF(ancillary); finished: PyMem_Free(iov[0].iov_base); PyMem_Free(cmsgbuf); return final_result; }
struct command *read_command( int cmd_fd ) { struct command *cmd = malloc(sizeof(struct command)); if (! cmd) { fprintf(stderr, "Unable to allocate memory for command!\n"); return NULL; } int fd[1] = {-1}; char buffer[CMSG_SPACE(sizeof fd)]; struct iovec v = { .iov_base = cmd, .iov_len = sizeof(*cmd) }; struct msghdr msg = { .msg_iov = &v, .msg_iovlen = 1, .msg_control = buffer, .msg_controllen = sizeof(buffer) }; int done = recvmsg( cmd_fd, &msg, 0 ); if (done == -1) { fprintf(stderr, "Error reading command."); free(cmd); return NULL; } struct cmsghdr *cmessage = CMSG_FIRSTHDR(&msg); if (cmessage) { memcpy(fd, CMSG_DATA(cmessage), sizeof fd); /* place FD back in the command message */ cmd->fd = (int) fd[0]; } return cmd; } int send_command( int cmd_fd, enum command_type type, char *param, int passfd, int exclusive, char *tag ) { if (type == CMD_ADD && passfd == 1) { type = CMD_PASSFD; } struct command cmd = { .fd = -1, .exclusive = exclusive, .type = type, .param = {0}, .tag = {0} }; if (param != NULL) { strncpy(cmd.param, param, TH_COMMAND_PARAM_LENGTH); cmd.param[TH_COMMAND_PARAM_LENGTH-1] = '\0'; } if (tag != NULL) { strncpy(cmd.tag, tag, TH_DEVICE_TAG_LENGTH); cmd.tag[TH_DEVICE_TAG_LENGTH-1] = '\0'; } struct iovec v = { .iov_base = &cmd, .iov_len = sizeof(cmd) }; struct msghdr m = { .msg_iov = &v, .msg_iovlen = 1 }; /* add FD */ int dev_fd[1] = { -1 }; char buffer[CMSG_SPACE(sizeof(dev_fd))]; if (passfd) { int fd = open( param, O_RDONLY ); if (fd < 0) { perror("open"); return 1; } dev_fd[0] = fd ; m.msg_control = buffer; m.msg_controllen = sizeof(buffer); struct cmsghdr *cmessage = CMSG_FIRSTHDR(&m); cmessage->cmsg_level = SOL_SOCKET; cmessage->cmsg_type = SCM_RIGHTS; cmessage->cmsg_len = CMSG_LEN(sizeof(dev_fd)); m.msg_controllen = cmessage->cmsg_len; memcpy(CMSG_DATA(cmessage), dev_fd, sizeof dev_fd); } int done = sendmsg( cmd_fd, &m, 0 ); return (done == -1); }
int sendfromto(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t fromlen, struct sockaddr *to, socklen_t tolen) { struct msghdr msgh; struct cmsghdr *cmsg; struct iovec iov; char cbuf[256]; #ifdef __FreeBSD__ /* * FreeBSD is extra pedantic about the use of IP_SENDSRCADDR, * and sendmsg will fail with EINVAL if IP_SENDSRCADDR is used * with a socket which is bound to something other than * INADDR_ANY */ struct sockaddr bound; socklen_t bound_len = sizeof(bound); if (getsockname(s, &bound, &bound_len) < 0) { return -1; } switch (bound.sa_family) { case AF_INET: if (((struct sockaddr_in *) &bound)->sin_addr.s_addr != INADDR_ANY) { from = NULL; } break; case AF_INET6: if (!IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *) &bound)->sin6_addr)) { from = NULL; } break; } #else # if !defined(IP_PKTINFO) && !defined(IP_SENDSRCADDR) && !defined(IPV6_PKTINFO) /* * If the sendmsg() flags aren't defined, fall back to * using sendto(). */ from = NULL; # endif #endif /* * Catch the case where the caller passes invalid arguments. */ if (!from || (fromlen == 0) || (from->sa_family == AF_UNSPEC)) { return sendto(s, buf, len, flags, to, tolen); } /* Set up control buffer iov and msgh structures. */ memset(&cbuf, 0, sizeof(cbuf)); memset(&msgh, 0, sizeof(msgh)); memset(&iov, 0, sizeof(iov)); iov.iov_base = buf; iov.iov_len = len; msgh.msg_iov = &iov; msgh.msg_iovlen = 1; msgh.msg_name = to; msgh.msg_namelen = tolen; if (from->sa_family == AF_INET) { #if !defined(IP_PKTINFO) && !defined(IP_SENDSRCADDR) return sendto(s, buf, len, flags, to, tolen); #else struct sockaddr_in *s4 = (struct sockaddr_in *) from; # ifdef IP_PKTINFO struct in_pktinfo *pkt; msgh.msg_control = cbuf; msgh.msg_controllen = CMSG_SPACE(sizeof(*pkt)); cmsg = CMSG_FIRSTHDR(&msgh); cmsg->cmsg_level = SOL_IP; cmsg->cmsg_type = IP_PKTINFO; cmsg->cmsg_len = CMSG_LEN(sizeof(*pkt)); pkt = (struct in_pktinfo *) CMSG_DATA(cmsg); memset(pkt, 0, sizeof(*pkt)); pkt->ipi_spec_dst = s4->sin_addr; # endif # ifdef IP_SENDSRCADDR struct in_addr *in; msgh.msg_control = cbuf; msgh.msg_controllen = CMSG_SPACE(sizeof(*in)); cmsg = CMSG_FIRSTHDR(&msgh); cmsg->cmsg_level = IPPROTO_IP; cmsg->cmsg_type = IP_SENDSRCADDR; cmsg->cmsg_len = CMSG_LEN(sizeof(*in)); in = (struct in_addr *) CMSG_DATA(cmsg); *in = s4->sin_addr; # endif #endif /* IP_PKTINFO or IP_SENDSRCADDR */ } #ifdef AF_INET6 else if (from->sa_family == AF_INET6) { # if !defined(IPV6_PKTINFO) return sendto(s, buf, len, flags, to, tolen); # else struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) from; struct in6_pktinfo *pkt; msgh.msg_control = cbuf; msgh.msg_controllen = CMSG_SPACE(sizeof(*pkt)); cmsg = CMSG_FIRSTHDR(&msgh); cmsg->cmsg_level = IPPROTO_IPV6; cmsg->cmsg_type = IPV6_PKTINFO; cmsg->cmsg_len = CMSG_LEN(sizeof(*pkt)); pkt = (struct in6_pktinfo *) CMSG_DATA(cmsg); memset(pkt, 0, sizeof(*pkt)); pkt->ipi6_addr = s6->sin6_addr; # endif /* IPV6_PKTINFO */ } #endif /* * Unknown address family. */ else { errno = EINVAL; return -1; } return sendmsg(s, &msgh, flags); }
/* * Receive a file descriptor from a Unix socket. * Contributed by @mkasick * * Returns the file descriptor on success, or -1 if a file * descriptor was not actually included in the message * * On error the function terminates by calling exit(-1) */ static int recv_fd(int sockfd) { // Need to receive data from the message, otherwise don't care about it. char iovbuf; struct iovec iov = { .iov_base = &iovbuf, .iov_len = 1, }; char cmsgbuf[CMSG_SPACE(sizeof(int))]; struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1, .msg_control = cmsgbuf, .msg_controllen = sizeof(cmsgbuf), }; if (recvmsg(sockfd, &msg, MSG_WAITALL) != 1) { goto error; } // Was a control message actually sent? switch (msg.msg_controllen) { case 0: // No, so the file descriptor was closed and won't be used. return -1; case sizeof(cmsgbuf): // Yes, grab the file descriptor from it. break; default: goto error; } struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); if (cmsg == NULL || cmsg->cmsg_len != CMSG_LEN(sizeof(int)) || cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) { error: LOGE("unable to read fd"); exit(-1); } return *(int *)CMSG_DATA(cmsg); } /* * Send a file descriptor through a Unix socket. * Contributed by @mkasick * * On error the function terminates by calling exit(-1) * * fd may be -1, in which case the dummy data is sent, * but no control message with the FD is sent. */ static void send_fd(int sockfd, int fd) { // Need to send some data in the message, this will do. struct iovec iov = { .iov_base = "", .iov_len = 1, }; struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1, }; char cmsgbuf[CMSG_SPACE(sizeof(int))]; if (fd != -1) { // Is the file descriptor actually open? if (fcntl(fd, F_GETFD) == -1) { if (errno != EBADF) { goto error; } // It's closed, don't send a control message or sendmsg will EBADF. } else { // It's open, send the file descriptor in a control message. msg.msg_control = cmsgbuf; msg.msg_controllen = sizeof(cmsgbuf); struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); cmsg->cmsg_len = CMSG_LEN(sizeof(int)); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; *(int *)CMSG_DATA(cmsg) = fd; } } if (sendmsg(sockfd, &msg, 0) != 1) { error: PLOGE("unable to send fd"); exit(-1); } } static int read_int(int fd) { int val; int len = read(fd, &val, sizeof(int)); if (len != sizeof(int)) { LOGE("unable to read int: %d", len); exit(-1); } return val; } static void write_int(int fd, int val) { int written = write(fd, &val, sizeof(int)); if (written != sizeof(int)) { PLOGE("unable to write int"); exit(-1); } } static char* read_string(int fd) { int len = read_int(fd); if (len > PATH_MAX || len < 0) { LOGE("invalid string length %d", len); exit(-1); } char* val = malloc(sizeof(char) * (len + 1)); if (val == NULL) { LOGE("unable to malloc string"); exit(-1); } val[len] = '\0'; int amount = read(fd, val, len); if (amount != len) { LOGE("unable to read string"); exit(-1); } return val; } static void write_string(int fd, char* val) { int len = strlen(val); write_int(fd, len); int written = write(fd, val, len); if (written != len) { PLOGE("unable to write string"); exit(-1); } }
ssize_t imsg_read(struct imsgbuf *ibuf) { struct msghdr msg; struct cmsghdr *cmsg; union { struct cmsghdr hdr; char buf[CMSG_SPACE(sizeof(int) * 1)]; } cmsgbuf; struct iovec iov; ssize_t n = -1; int fd; struct imsg_fd *ifd; memset(&msg, 0, sizeof(msg)); memset(&cmsgbuf, 0, sizeof(cmsgbuf)); iov.iov_base = ibuf->r.buf + ibuf->r.wpos; iov.iov_len = sizeof(ibuf->r.buf) - ibuf->r.wpos; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = &cmsgbuf.buf; msg.msg_controllen = CMSG_SPACE(sizeof(int) * 16); if ((ifd = calloc(1, sizeof(struct imsg_fd))) == NULL) return (-1); again: if (getdtablecount() + imsg_fd_overhead + (int)((CMSG_SPACE(sizeof(int))-CMSG_SPACE(0))/sizeof(int)) >= getdtablesize()) { errno = EAGAIN; free(ifd); return (-1); } if ((n = recvmsg(ibuf->fd, &msg, 0)) == -1) { if (errno == EINTR) goto again; goto fail; } ibuf->r.wpos += n; for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) { if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { int i; int j; /* * We only accept one file descriptor. Due to C * padding rules, our control buffer might contain * more than one fd, and we must close them. */ j = ((char *)cmsg + cmsg->cmsg_len - (char *)CMSG_DATA(cmsg)) / sizeof(int); for (i = 0; i < j; i++) { fd = ((int *)CMSG_DATA(cmsg))[i]; if (ifd != NULL) { ifd->fd = fd; TAILQ_INSERT_TAIL(&ibuf->fds, ifd, entry); ifd = NULL; } else close(fd); } } /* we do not handle other ctl data level */ } fail: free(ifd); return (n); }
namespace rubinius { void IO::bootstrap(STATE) { GO(io).set(state->memory()->new_class<Class, IO>(state, G(object), "IO")); G(io)->set_object_type(state, IOType); } IO* IO::create(STATE, int fd) { IO* io = state->memory()->new_object<IO>(state, G(io)); return io; } native_int IO::open_with_cloexec(STATE, const char* path, int mode, int permissions) { if(Class* fd_class = try_as<Class>(G(io)->get_const(state, "FileDescriptor"))) { Tuple* args = Tuple::from(state, 3, String::create(state, path), Fixnum::from(mode), Fixnum::from(permissions)); if(Fixnum* fd = try_as<Fixnum>(fd_class->send(state, state->symbol("open_with_cloexec"), Array::from_tuple(state, args)))) { return fd->to_native(); } else { Exception::raise_runtime_error(state, "unable to open IO with cloexec"); } } else { Exception::raise_runtime_error(state, "unable to access IO::FileDescriptor class"); } } native_int IO::descriptor(STATE) { if(Fixnum* fd = try_as<Fixnum>(send(state, state->symbol("descriptor")))) { return fd->to_native(); } Exception::raise_runtime_error(state, "IO descriptor is not a Fixnum"); } void IO::ensure_open(STATE) { // Will raise an exception if the file descriptor is not open send(state, state->symbol("ensure_open")); } Array* ipaddr(STATE, struct sockaddr* addr, socklen_t len) { String* family; char buf[NI_MAXHOST]; char pbuf[NI_MAXSERV]; switch(addr->sa_family) { case AF_UNSPEC: family = String::create(state, "AF_UNSPEC"); break; case AF_INET: family = String::create(state, "AF_INET"); break; #ifdef INET6 case AF_INET6: family = String::create(state, "AF_INET6"); break; #endif #ifdef AF_LOCAL case AF_LOCAL: family = String::create(state, "AF_LOCAL"); break; #elif AF_UNIX case AF_UNIX: family = String::create(state, "AF_UNIX"); break; #endif default: snprintf(pbuf, NI_MAXSERV, "unknown:%d", addr->sa_family); family = String::create(state, pbuf); break; } int e = getnameinfo(addr, len, buf, NI_MAXHOST, pbuf, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV); // TODO this doesn't support doing the DNS bound lookup at all. // Not doing it better than doing it badly, thats why it's // not here. // String* host; if(e) { host = String::create(state, (char*)addr, len); } else { host = String::create(state, buf); } Array* ary = Array::create(state, 4); ary->set(state, 0, family); ary->set(state, 1, Fixnum::from(atoi(pbuf))); ary->set(state, 2, host); ary->set(state, 3, host); return ary; } #ifndef RBX_WINDOWS static const char* unixpath(struct sockaddr_un *sockaddr, socklen_t len) { if(sockaddr->sun_path < (char*)sockaddr + len) { return sockaddr->sun_path; } return ""; } Array* unixaddr(STATE, struct sockaddr_un* addr, socklen_t len) { Array* ary = Array::create(state, 2); ary->set(state, 0, String::create(state, "AF_UNIX")); ary->set(state, 1, String::create(state, unixpath(addr, len))); return ary; } #endif Object* IO::socket_read(STATE, Fixnum* bytes, Fixnum* flags, Fixnum* type) { char buf[1024]; socklen_t alen = sizeof(buf); size_t size = (size_t)bytes->to_native(); String* buffer = String::create_pinned(state, bytes); OnStack<1> variables(state, buffer); ssize_t bytes_read; native_int t = type->to_native(); retry: state->vm()->interrupt_with_signal(); state->vm()->thread()->sleep(state, cTrue); { UnmanagedPhase unmanaged(state); bytes_read = recvfrom(descriptor(state), (char*)buffer->byte_address(), size, flags->to_native(), (struct sockaddr*)buf, &alen); } state->vm()->thread()->sleep(state, cFalse); state->vm()->clear_waiter(); buffer->unpin(); if(bytes_read == -1) { if(errno == EINTR) { if(state->vm()->thread_interrupted_p(state)) return NULL; ensure_open(state); goto retry; } else { Exception::raise_errno_error(state, "read(2) failed"); } return NULL; } buffer->num_bytes(state, Fixnum::from(bytes_read)); if(t == 0) return buffer; // none Array* ary = Array::create(state, 2); ary->set(state, 0, buffer); switch(type->to_native()) { case 1: // ip // Hack from MRI: // OSX doesn't return a 'from' result from recvfrom for connection-oriented sockets if(alen && alen != sizeof(buf)) { ary->set(state, 1, ipaddr(state, (struct sockaddr*)buf, alen)); } else { ary->set(state, 1, cNil); } break; #ifndef RBX_WINDOWS case 2: // unix ary->set(state, 1, unixaddr(state, (struct sockaddr_un*)buf, alen)); break; #endif default: ary->set(state, 1, String::create(state, buf, alen)); } return ary; } // Stole/ported from 1.8.7. The system fnmatch doesn't support // a bunch of things this does (and must). #ifndef CASEFOLD_FILESYSTEM # if defined DOSISH || defined __VMS # define CASEFOLD_FILESYSTEM 1 # else # define CASEFOLD_FILESYSTEM 0 # endif #endif #define FNM_NOESCAPE 0x01 #define FNM_PATHNAME 0x02 #define FNM_DOTMATCH 0x04 #define FNM_CASEFOLD 0x08 #define FNM_EXTGLOB 0x10 #if CASEFOLD_FILESYSTEM #define FNM_SYSCASE FNM_CASEFOLD #else #define FNM_SYSCASE 0 #endif #define FNM_NOMATCH 1 #define FNM_ERROR 2 #define downcase(c) (nocase && ISUPPER(c) ? tolower(c) : (c)) #define compare(c1, c2) (((unsigned char)(c1)) - ((unsigned char)(c2))) #define Next(p) ((p) + 1) #define Inc(p) (++(p)) #define Compare(p1, p2) (compare(downcase(*(p1)), downcase(*(p2)))) namespace { static char *bracket(const char* p, const char* s, int flags) { const int nocase = flags & FNM_CASEFOLD; const int escape = !(flags & FNM_NOESCAPE); int ok = 0, nope = 0; if(*p == '!' || *p == '^') { nope = 1; p++; } while(*p != ']') { const char *t1 = p; if(escape && *t1 == '\\') t1++; if(!*t1) return NULL; p = Next(t1); if(p[0] == '-' && p[1] != ']') { const char *t2 = p + 1; if(escape && *t2 == '\\') t2++; if(!*t2) return NULL; p = Next(t2); if(!ok && Compare(t1, s) <= 0 && Compare(s, t2) <= 0) ok = 1; } else { if(!ok && Compare(t1, s) == 0) ok = 1; } } return ok == nope ? NULL : (char *)p + 1; } /* If FNM_PATHNAME is set, only path element will be matched. (upto '/' or '\0') Otherwise, entire string will be matched. End marker itself won't be compared. And if function succeeds, *pcur reaches end marker. */ #define UNESCAPE(p) (escape && *(p) == '\\' ? (p) + 1 : (p)) #define ISEND(p) (!*(p) || (pathname && *(p) == '/')) #define RETURN(val) return *pcur = p, *scur = s, (val); bool mri_fnmatch_helper(const char** pcur, const char** scur, int flags) { const int period = !(flags & FNM_DOTMATCH); const int pathname = flags & FNM_PATHNAME; const int escape = !(flags & FNM_NOESCAPE); const int nocase = flags & FNM_CASEFOLD; const char *ptmp = 0; const char *stmp = 0; const char *p = *pcur; const char *s = *scur; if(period && *s == '.' && *UNESCAPE(p) != '.') /* leading period */ RETURN(false); while(1) { switch(*p) { case '*': do { p++; } while (*p == '*'); if(ISEND(UNESCAPE(p))) { p = UNESCAPE(p); RETURN(true); } if(ISEND(s)) RETURN(false); ptmp = p; stmp = s; continue; case '?': if(ISEND(s)) RETURN(false); p++; Inc(s); continue; case '[': { const char *t; if(ISEND(s)) RETURN(false); if((t = bracket(p + 1, s, flags)) != 0) { p = t; Inc(s); continue; } goto failed; } } /* ordinary */ p = UNESCAPE(p); if(ISEND(s)) RETURN(ISEND(p) ? true : false); if(ISEND(p)) goto failed; if(Compare(p, s) != 0) goto failed; Inc(p); Inc(s); continue; failed: /* try next '*' position */ if(ptmp && stmp) { p = ptmp; Inc(stmp); /* !ISEND(*stmp) */ s = stmp; continue; } RETURN(false); } } int mri_fnmatch(const char* p, const char* s, int flags) { const int period = !(flags & FNM_DOTMATCH); const int pathname = flags & FNM_PATHNAME; const char *ptmp = 0; const char *stmp = 0; if(pathname) { while(1) { if(p[0] == '*' && p[1] == '*' && p[2] == '/') { do { p += 3; } while (p[0] == '*' && p[1] == '*' && p[2] == '/'); ptmp = p; stmp = s; } if(mri_fnmatch_helper(&p, &s, flags)) { while(*s && *s != '/') Inc(s); if(*p && *s) { p++; s++; continue; } if(!*p && !*s) return true; } /* failed : try next recursion */ if(ptmp && stmp && !(period && *stmp == '.')) { while(*stmp && *stmp != '/') Inc(stmp); if(*stmp) { p = ptmp; stmp++; s = stmp; continue; } } return false; } } else { return mri_fnmatch_helper(&p, &s, flags); } } } Object* IO::fnmatch(STATE, String* pattern, String* path, Fixnum* flags) { return RBOOL(mri_fnmatch(pattern->c_str(state), path->c_str(state), flags->to_native())); } /** Socket methods */ static const int cmsg_space = CMSG_SPACE(sizeof(int)); Object* IO::send_io(STATE, IO* io) { #ifdef _WIN32 return Primitives::failure(); #else int fd; struct msghdr msg; struct iovec vec[1]; char buf[1]; struct cmsghdr *cmsg; char cmsg_buf[cmsg_space]; fd = io->descriptor(state); msg.msg_name = NULL; msg.msg_namelen = 0; /* Linux and Solaris doesn't work if msg_iov is NULL. */ buf[0] = '\0'; vec[0].iov_base = buf; vec[0].iov_len = 1; msg.msg_iov = vec; msg.msg_iovlen = 1; msg.msg_control = (caddr_t)cmsg_buf; msg.msg_controllen = sizeof(cmsg_buf); msg.msg_flags = 0; cmsg = CMSG_FIRSTHDR(&msg); memset(cmsg_buf, 0, sizeof(cmsg_buf)); cmsg->cmsg_len = CMSG_LEN(sizeof(int)); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; // Workaround for GCC's broken strict-aliasing checks. int* fd_data = (int*)CMSG_DATA(cmsg); *fd_data = fd; if(sendmsg(descriptor(state), &msg, 0) == -1) { return Primitives::failure(); } return cNil; #endif } Object* IO::recv_fd(STATE) { #ifdef _WIN32 return Primitives::failure(); #else struct msghdr msg; struct iovec vec[1]; char buf[1]; struct cmsghdr *cmsg; char cmsg_buf[cmsg_space]; msg.msg_name = NULL; msg.msg_namelen = 0; /* Linux and Solaris doesn't work if msg_iov is NULL. */ buf[0] = '\0'; vec[0].iov_base = buf; vec[0].iov_len = 1; msg.msg_iov = vec; msg.msg_iovlen = 1; msg.msg_control = (caddr_t)cmsg_buf; msg.msg_controllen = sizeof(cmsg_buf); msg.msg_flags = 0; cmsg = CMSG_FIRSTHDR(&msg); memset(cmsg_buf, 0, sizeof(cmsg_buf)); cmsg->cmsg_len = CMSG_LEN(sizeof(int)); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; // Workaround for GCC's broken strict-aliasing checks. int* fd_data = (int *)CMSG_DATA(cmsg); *fd_data = -1; int read_fd = descriptor(state); int code = -1; retry: state->vm()->interrupt_with_signal(); state->vm()->thread()->sleep(state, cTrue); { UnmanagedPhase unmanaged(state); code = recvmsg(read_fd, &msg, 0); } state->vm()->thread()->sleep(state, cFalse); state->vm()->clear_waiter(); if(code == -1) { if(errno == EAGAIN || errno == EINTR) { if(state->vm()->thread_interrupted_p(state)) return NULL; ensure_open(state); goto retry; } return Primitives::failure(); } if(msg.msg_controllen != CMSG_SPACE(sizeof(int)) || cmsg->cmsg_len != CMSG_LEN(sizeof(int)) || cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) { return Primitives::failure(); } // Workaround for GCC's broken strict-aliasing checks. fd_data = (int *)CMSG_DATA(cmsg); return Fixnum::from(*fd_data); #endif } void FDSet::bootstrap(STATE) { // Create a constant for FDSet under the IO::Select namespace, i.e. IO::Select::FDSet GO(select).set(state->memory()->new_class<Class>(state, G(io), "Select")); GO(fdset).set(state->memory()->new_class<Class, FDSet>(state, G(select), "FDSet")); } FDSet* FDSet::allocate(STATE, Object* self) { FDSet* fdset = create(state); fdset->klass(state, as<Class>(self)); return fdset; } FDSet* FDSet::create(STATE) { FDSet* fdset = state->memory()->new_object<FDSet>(state, G(fdset)); return fdset; } Object* FDSet::zero(STATE) { FD_ZERO((fd_set*)descriptor_set); return cTrue; } Object* FDSet::set(STATE, Fixnum* descriptor) { native_int fd = descriptor->to_native(); FD_SET((int_fd_t)fd, (fd_set*)descriptor_set); return cTrue; } Object* FDSet::is_set(STATE, Fixnum* descriptor) { native_int fd = descriptor->to_native(); if (FD_ISSET(fd, (fd_set*)descriptor_set)) { return cTrue; } else { return cFalse; } } Object* FDSet::to_set(STATE) { void *ptr = (void*)&descriptor_set; return Pointer::create(state, ptr); } void RIOStream::bootstrap(STATE) { GO(rio_stream).set(state->memory()->new_class<Class, RIOStream>( state, G(rubinius), "RIOStream")); } Object* RIOStream::close(STATE, Object* io, Object* allow_exception) { // If there is a handle for this IO, and it's been promoted into // a lowlevel RIO struct using fdopen, then we MUST use fclose // to close it. if(capi::Handle* hdl = io->handle(state)) { if(hdl->is_rio()) { if(!hdl->rio_close() && CBOOL(allow_exception)) { Exception::raise_errno_error(state, "failed to close RIOStream"); } return cTrue; } } return cFalse; } }
void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm) { struct cmsghdr __user *cm = (__force struct cmsghdr __user*)msg->msg_control; int fdmax = 0; int fdnum = scm->fp->count; struct file **fp = scm->fp->fp; int __user *cmfptr; int err = 0, i; if (MSG_CMSG_COMPAT & msg->msg_flags) { scm_detach_fds_compat(msg, scm); return; } if (msg->msg_controllen > sizeof(struct cmsghdr)) fdmax = ((msg->msg_controllen - sizeof(struct cmsghdr)) / sizeof(int)); if (fdnum < fdmax) fdmax = fdnum; for (i=0, cmfptr=(__force int __user *)CMSG_DATA(cm); i<fdmax; i++, cmfptr++) { struct socket *sock; int new_fd; err = security_file_receive(fp[i]); if (err) break; err = get_unused_fd_flags(MSG_CMSG_CLOEXEC & msg->msg_flags ? O_CLOEXEC : 0); if (err < 0) break; new_fd = err; err = put_user(new_fd, cmfptr); if (err) { put_unused_fd(new_fd); break; } /* Bump the usage count and install the file. */ sock = sock_from_file(fp[i], &err); if (sock) sock_update_netprioidx(sock->sk, current); fd_install(new_fd, get_file(fp[i])); } if (i > 0) { int cmlen = CMSG_LEN(i*sizeof(int)); err = put_user(SOL_SOCKET, &cm->cmsg_level); if (!err) err = put_user(SCM_RIGHTS, &cm->cmsg_type); if (!err) err = put_user(cmlen, &cm->cmsg_len); if (!err) { cmlen = CMSG_SPACE(i*sizeof(int)); msg->msg_control += cmlen; msg->msg_controllen -= cmlen; } } if (i < fdnum || (fdnum && fdmax <= 0)) msg->msg_flags |= MSG_CTRUNC; /* * All of the files that fit in the message have had their * usage counts incremented, so we just free the list. */ __scm_destroy(scm); }
uint8_t negotiate(struct np_map *npm, uint8_t no_maps, const struct in6_addr *saddr, const struct in6_addr *daddr, int iif, int sock_fd) { // uint8_t all_hosts_addr[] = {0xff,0x02,0,0,0,0,0,0,0,0,0,0,0,0,0,1}; struct sockaddr_in6 addr; struct nd_neighbor_advert *na; struct iovec iov; struct cmsghdr *cmsg; char chdr[CMSG_SPACE(sizeof(struct in6_pktinfo))]; struct in6_pktinfo *pkt_info; struct msghdr mhdr; int i,j = 0; float cur_best_prio = -1; // struct np_finalise npf; struct np_fin_nd_opt npf; char *proc_cat_s = malloc(MAX_PROC_STR_SIZE + 1); unsigned char buff[MSG_SIZE]; int len = 0; int err; struct ifreq ifr; uint8_t *ucp; unsigned int slla_len; memset((void *)&addr, 0, sizeof(addr)); addr.sin6_family = AF_INET6; addr.sin6_port = htons(IPPROTO_ICMPV6); memcpy(&addr.sin6_addr, saddr, sizeof(struct in6_addr)); memset(&buff, 0, sizeof(buff)); na = (struct nd_neighbor_advert *) buff; na->nd_na_type = ND_NEIGHBOR_ADVERT; na->nd_na_code = 0; na->nd_na_cksum = 0; na->nd_na_target = *daddr; len = sizeof(struct nd_neighbor_advert); /* * Add the Source LL Address ICMPv6 Option */ ifr.ifr_addr.sa_family = AF_INET6; strncpy(ifr.ifr_name, conf.interface, IF_NAMESIZE-1); ioctl(sock_fd, SIOCGIFHWADDR, &ifr); printf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n", (unsigned char)ifr.ifr_hwaddr.sa_data[0], (unsigned char)ifr.ifr_hwaddr.sa_data[1], (unsigned char)ifr.ifr_hwaddr.sa_data[2], (unsigned char)ifr.ifr_hwaddr.sa_data[3], (unsigned char)ifr.ifr_hwaddr.sa_data[4], (unsigned char)ifr.ifr_hwaddr.sa_data[5]); ucp = (uint8_t *) (buff + len); *ucp++ = ND_OPT_SOURCE_LINKADDR; *ucp++ = 1; /* XXX : HACK : This will only work for MAC */ len += 2 * sizeof(uint8_t); slla_len = 6; /* XXX : HACK : This will only work for MAC */ memcpy(buff + len, &ifr.ifr_hwaddr.sa_data, slla_len); len+= slla_len; /* * Add NP++ Finalisation Option */ npf.type = 63; npf.length = 1; for(i = 0; i < NP_FIN_PAD_SIZE; i++) { npf.pad[i] = 0; } /* * Perform comparison of mapping tables to determine best mapping to use */ for(i = 0; i < no_maps; i++) { for(j = 0; j < no_my_maps; j++) { // Check mapping exists in both lists if(my_npm[j].mapping == npm[i].mapping) { float av_prio = 0; av_prio = (float)(((float)my_npm[j].prio + (float)npm[i].prio) / 2); if(av_prio > cur_best_prio) { cur_best_prio = av_prio; npf.mapping = my_npm[j].mapping; } } } } printf("New Mapping ID == %d\n", npf.mapping); /* * NP++ : Copy the ICMPv6 option type, length and no_maps field into the send buffer */ memcpy(buff + len, &npf, sizeof(npf)); len += (sizeof(npf)); iov.iov_len = len; iov.iov_base = (caddr_t) buff; memset(chdr, 0, sizeof(chdr)); cmsg = (struct cmsghdr *) chdr; cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); cmsg->cmsg_level = IPPROTO_IPV6; cmsg->cmsg_type = IPV6_PKTINFO; pkt_info = (struct in6_pktinfo *)CMSG_DATA(cmsg); pkt_info->ipi6_ifindex = conf.ifindex; memcpy(&pkt_info->ipi6_addr, &conf.lladdr, sizeof(struct in6_addr)); addr.sin6_scope_id = conf.ifindex; memset(&mhdr, 0, sizeof(mhdr)); mhdr.msg_name = (caddr_t)&addr; mhdr.msg_namelen = sizeof(struct sockaddr_in6); mhdr.msg_iov = &iov; mhdr.msg_iovlen = 1; mhdr.msg_control = (void *) cmsg; mhdr.msg_controllen = sizeof(chdr); err = sendmsg(sock_fd, &mhdr, 0); // printf("NA Received Finalising The Mapping %d - Setting the /proc/ entry\n", mapping); #ifdef __linux__ snprintf(proc_cat_s, MAX_PROC_STR_SIZE + 1, "echo %d > /proc/net/np++/ifcurmappings/%s", npf.mapping, conf.interface); system(proc_cat_s); #endif free(proc_cat_s); if (err < 0) { perror("sendmsg() : "); } return 0; }
/* * If sendStdio is non-zero, the current process's stdio file descriptors * will be sent and inherited by the spawned process. */ static int send_request(int fd, int sendStdio, int argc, const char **argv) { #ifndef HAVE_ANDROID_OS // not supported on simulator targets //ALOGE("zygote_* not supported on simulator targets"); return -1; #else /* HAVE_ANDROID_OS */ uint32_t pid; int i; struct iovec ivs[2]; struct msghdr msg; char argc_buffer[12]; const char *newline_string = "\n"; struct cmsghdr *cmsg; char msgbuf[CMSG_SPACE(sizeof(int) * 3)]; int *cmsg_payload; ssize_t ret; memset(&msg, 0, sizeof(msg)); memset(&ivs, 0, sizeof(ivs)); // First line is arg count snprintf(argc_buffer, sizeof(argc_buffer), "%d\n", argc); ivs[0].iov_base = argc_buffer; ivs[0].iov_len = strlen(argc_buffer); msg.msg_iov = ivs; msg.msg_iovlen = 1; if (sendStdio != 0) { // Pass the file descriptors with the first write msg.msg_control = msgbuf; msg.msg_controllen = sizeof msgbuf; cmsg = CMSG_FIRSTHDR(&msg); cmsg->cmsg_len = CMSG_LEN(3 * sizeof(int)); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; cmsg_payload = (int *)CMSG_DATA(cmsg); cmsg_payload[0] = STDIN_FILENO; cmsg_payload[1] = STDOUT_FILENO; cmsg_payload[2] = STDERR_FILENO; } do { ret = sendmsg(fd, &msg, MSG_NOSIGNAL); } while (ret < 0 && errno == EINTR); if (ret < 0) { return -1; } // Only send the fd's once msg.msg_control = NULL; msg.msg_controllen = 0; // replace any newlines with spaces and send the args for (i = 0; i < argc; i++) { char *tofree = NULL; const char *toprint; toprint = argv[i]; if (strchr(toprint, '\n') != NULL) { tofree = strdup(toprint); toprint = tofree; replace_nl(tofree); } ivs[0].iov_base = (char *)toprint; ivs[0].iov_len = strlen(toprint); ivs[1].iov_base = (char *)newline_string; ivs[1].iov_len = 1; msg.msg_iovlen = 2; do { ret = sendmsg(fd, &msg, MSG_NOSIGNAL); } while (ret < 0 && errno == EINTR); if (tofree != NULL) { free(tofree); } if (ret < 0) { return -1; } } // Read the pid, as a 4-byte network-order integer ivs[0].iov_base = &pid; ivs[0].iov_len = sizeof(pid); msg.msg_iovlen = 1; do { do { ret = recvmsg(fd, &msg, MSG_NOSIGNAL | MSG_WAITALL); } while (ret < 0 && errno == EINTR); if (ret < 0) { return -1; } ivs[0].iov_len -= ret; ivs[0].iov_base += ret; } while (ivs[0].iov_len > 0); pid = ntohl(pid); return pid; #endif /* HAVE_ANDROID_OS */ }
static int afalg_start_cipher_sk(afalg_ctx *actx, const unsigned char *in, size_t inl, const unsigned char *iv, unsigned int enc) { struct msghdr msg = { 0 }; struct cmsghdr *cmsg; struct iovec iov; ssize_t sbytes; # ifdef ALG_ZERO_COPY int ret; # endif char cbuf[CMSG_SPACE(ALG_IV_LEN(ALG_AES_IV_LEN)) + CMSG_SPACE(ALG_OP_LEN)]; memset(cbuf, 0, sizeof(cbuf)); msg.msg_control = cbuf; msg.msg_controllen = sizeof(cbuf); /* * cipher direction (i.e. encrypt or decrypt) and iv are sent to the * kernel as part of sendmsg()'s ancillary data */ cmsg = CMSG_FIRSTHDR(&msg); afalg_set_op_sk(cmsg, enc); cmsg = CMSG_NXTHDR(&msg, cmsg); afalg_set_iv_sk(cmsg, iv, ALG_AES_IV_LEN); /* iov that describes input data */ iov.iov_base = (unsigned char *)in; iov.iov_len = inl; msg.msg_flags = MSG_MORE; # ifdef ALG_ZERO_COPY /* * ZERO_COPY mode * Works best when buffer is 4k aligned * OPENS: out of place processing (i.e. out != in) */ /* Input data is not sent as part of call to sendmsg() */ msg.msg_iovlen = 0; msg.msg_iov = NULL; /* Sendmsg() sends iv and cipher direction to the kernel */ sbytes = sendmsg(actx->sfd, &msg, 0); if (sbytes < 0) { ALG_PERR("%s: sendmsg failed for zero copy cipher operation : ", __func__); return 0; } /* * vmsplice and splice are used to pin the user space input buffer for * kernel space processing avoiding copys from user to kernel space */ ret = vmsplice(actx->zc_pipe[1], &iov, 1, SPLICE_F_GIFT); if (ret < 0) { ALG_PERR("%s: vmsplice failed : ", __func__); return 0; } ret = splice(actx->zc_pipe[0], NULL, actx->sfd, NULL, inl, 0); if (ret < 0) { ALG_PERR("%s: splice failed : ", __func__); return 0; } # else msg.msg_iovlen = 1; msg.msg_iov = &iov; /* Sendmsg() sends iv, cipher direction and input data to the kernel */ sbytes = sendmsg(actx->sfd, &msg, 0); if (sbytes < 0) { ALG_PERR("%s: sendmsg failed for cipher operation : ", __func__); return 0; } if (sbytes != (ssize_t) inl) { ALG_WARN("Cipher operation send bytes %zd != inlen %zd\n", sbytes, inl); return 0; } # endif return 1; }
void linux_event_loop<handler>::run() { int ready_cnt; int buf_size; struct epoll_event evlist[MAX_EVENTS]; char buffer[MAX_BUFFER]; struct msghdr msg; struct iovec iov; char ctrl[CMSG_SPACE(sizeof(struct timeval))]; struct cmsghdr *cmsg = (struct cmsghdr *) & ctrl; struct timeval kernel_time; iov.iov_base = buffer; iov.iov_len = MAX_BUFFER; msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = (char *)ctrl; msg.msg_controllen = sizeof(ctrl); struct timeval tcp_time; _is_running = true; while( _is_running ) { ready_cnt = epoll_wait( _fd_epoll, evlist, MAX_EVENTS, -1 ); if( ready_cnt < 0 ) { char m[1000]; perror(m); std::cerr << "Error in epoll_wait " << m << std::endl; continue; } if( ready_cnt == 0 ) continue; for( int i = 0; i < ready_cnt; ++i) { if (evlist[i].events & (EPOLLHUP | EPOLLERR | EPOLLRDHUP)) { std::string what_exactly; if( evlist[i].events & EPOLLHUP ) what_exactly = "EPOLLHUP"; else if ( evlist[i].events & EPOLLERR ) what_exactly = "EPOLLERR"; else if ( evlist[i].events & EPOLLRDHUP ) what_exactly = "EPOLLRDHUP"; std::cerr << "Error " << what_exactly << " on fd =" << evlist[i].data.fd << std::endl; disable(evlist[i].data.fd); remove(evlist[i].data.fd); _handler->on_disconnect(evlist[i].data.fd); continue; } con_type type = _cons[ evlist[i].data.fd ].type; if(type == UDP) { if(evlist[i].events & EPOLLIN) { iov.iov_len = MAX_BUFFER; while( (buf_size = recvmsg(evlist[i].data.fd, &msg, MSG_DONTWAIT)) > 0 ) { if(cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_TIMESTAMP || cmsg->cmsg_len != CMSG_LEN(sizeof(kernel_time))) { std::cerr << "cannot obtain kernel timestamp ignoring UDP packet" << std::endl; } else { _handler->on_udp_packet(evlist[i].data.fd, buffer, buf_size, from_timeval(*(struct timeval *)CMSG_DATA(cmsg))); } iov.iov_len = MAX_BUFFER; } } } else if(type == TCP) { if(evlist[i].events & EPOLLIN) { while( ( buf_size = recv(evlist[i].data.fd, buffer, MAX_BUFFER, MSG_DONTWAIT)) > 0) { gettimeofday((struct timeval *)&tcp_time, NULL); _handler->on_tcp_packet(evlist[i].data.fd, buffer, buf_size, from_timeval(tcp_time)); } } } else if(type == TIMER) { if(evlist[i].events & EPOLLIN) { if ( (buf_size = read(evlist[i].data.fd, buffer, MAX_BUFFER)) > 0) { gettimeofday((struct timeval *)&tcp_time, NULL); _handler->on_timer(evlist[i].data.fd, buffer, buf_size, from_timeval(tcp_time)); } } } } } }
int main(int argc, char *argv[]) { int error; socklen_t len; int sk,lstn_sk,clnt_sk,acpt_sk,pf_class,sk1; struct msghdr outmessage; struct msghdr inmessage; char *message = "hello, world!\n"; struct iovec iov; struct iovec iov_rcv; struct sctp_sndrcvinfo *sinfo; int msg_count; char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))]; struct cmsghdr *cmsg; struct iovec out_iov; char * buffer_snd; char * buffer_rcv; char incmsg[CMSG_SPACE(sizeof(sctp_cmsg_data_t))]; struct sockaddr *laddrs, *paddrs; struct sockaddr_in conn_addr,lstn_addr,acpt_addr; struct sockaddr_in *addr; /* Rather than fflush() throughout the code, set stdout to * be unbuffered. */ setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); pf_class = PF_INET; sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); /*Creating a regular socket*/ clnt_sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); /*Creating a listen socket*/ lstn_sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); conn_addr.sin_family = AF_INET; conn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK; conn_addr.sin_port = htons(SCTP_TESTPORT_1); lstn_addr.sin_family = AF_INET; lstn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK; lstn_addr.sin_port = htons(SCTP_TESTPORT_1); /*Binding the listen socket*/ test_bind(lstn_sk, (struct sockaddr *) &lstn_addr, sizeof(lstn_addr)); /*Listening many sockets as we are calling too many connect here*/ test_listen(lstn_sk, 1); len = sizeof(struct sockaddr_in); test_connect(clnt_sk, (struct sockaddr *) &conn_addr, len); acpt_sk = test_accept(lstn_sk, (struct sockaddr *) &acpt_addr, &len); memset(&inmessage, 0, sizeof(inmessage)); buffer_rcv = malloc(REALLY_BIG); iov_rcv.iov_base = buffer_rcv; iov_rcv.iov_len = REALLY_BIG; inmessage.msg_iov = &iov_rcv; inmessage.msg_iovlen = 1; inmessage.msg_control = incmsg; inmessage.msg_controllen = sizeof(incmsg); msg_count = strlen(message) + 1; memset(&outmessage, 0, sizeof(outmessage)); buffer_snd = malloc(REALLY_BIG); outmessage.msg_name = &lstn_addr; outmessage.msg_namelen = sizeof(lstn_addr); outmessage.msg_iov = &out_iov; outmessage.msg_iovlen = 1; outmessage.msg_control = outcmsg; outmessage.msg_controllen = sizeof(outcmsg); outmessage.msg_flags = 0; cmsg = CMSG_FIRSTHDR(&outmessage); cmsg->cmsg_level = IPPROTO_SCTP; cmsg->cmsg_type = SCTP_SNDRCV; cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); outmessage.msg_controllen = cmsg->cmsg_len; sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo)); iov.iov_base = buffer_snd; iov.iov_len = REALLY_BIG; outmessage.msg_iov->iov_base = message; outmessage.msg_iov->iov_len = msg_count; test_sendmsg(clnt_sk, &outmessage, MSG_NOSIGNAL, msg_count); test_recvmsg(acpt_sk, &inmessage, MSG_NOSIGNAL); /*sctp_getladdrs() TEST1: Bad socket descriptor, EBADF Expected error*/ error = sctp_getladdrs(-1, 0, &laddrs); if (error != -1 || errno != EBADF) tst_brkm(TBROK, NULL, "sctp_getladdrs with a bad socket " "descriptor error:%d, errno:%d", error, errno); tst_resm(TPASS, "sctp_getladdrs() with a bad socket descriptor - " "EBADF"); /*sctp_getladdrs() TEST2: Invalid socket, ENOTSOCK Expected error*/ error = sctp_getladdrs(0, 0, &laddrs); if (error != -1 || errno != ENOTSOCK) tst_brkm(TBROK, NULL, "sctp_getladdrs with invalid socket " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "sctp_getladdrs() with invalid socket - ENOTSOCK"); /*sctp_getladdrs() TEST3: socket of different protocol EOPNOTSUPP Expected error*/ sk1 = socket(pf_class, SOCK_STREAM, IPPROTO_IP); error = sctp_getladdrs(sk1, 0, &laddrs); if (error != -1 || errno != EOPNOTSUPP) tst_brkm(TBROK, NULL, "sctp_getladdrs with socket of " "different protocol error:%d, errno:%d", error, errno); tst_resm(TPASS, "sctp_getladdrs() with socket of different protocol - " "EOPNOTSUPP"); /*sctp_getladdrs() TEST4: Getting the local addresses*/ error = sctp_getladdrs(lstn_sk, 0, &laddrs); if (error < 0) tst_brkm(TBROK, NULL, "sctp_getladdrs with valid socket " "error:%d, errno:%d", error, errno); addr = (struct sockaddr_in *)laddrs; if (addr->sin_port != lstn_addr.sin_port || addr->sin_family != lstn_addr.sin_family || addr->sin_addr.s_addr != lstn_addr.sin_addr.s_addr) tst_brkm(TBROK, NULL, "sctp_getladdrs comparision failed"); tst_resm(TPASS, "sctp_getladdrs() - SUCCESS"); /*sctp_freealddrs() TEST5: freeing the local address*/ if ((sctp_freeladdrs(laddrs)) < 0) tst_brkm(TBROK, NULL, "sctp_freeladdrs " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "sctp_freeladdrs() - SUCCESS"); /*sctp_getpaddrs() TEST6: Bad socket descriptor, EBADF Expected error*/ error = sctp_getpaddrs(-1, 0, &paddrs); if (error != -1 || errno != EBADF) tst_brkm(TBROK, NULL, "sctp_getpaddrs with a bad socket " "descriptor error:%d, errno:%d", error, errno); tst_resm(TPASS, "sctp_getpaddrs() with a bad socket descriptor - " "EBADF"); /*sctp_getpaddrs() TEST7: Invalid socket, ENOTSOCK Expected error*/ error = sctp_getpaddrs(0, 0, &paddrs); if (error != -1 || errno != ENOTSOCK) tst_brkm(TBROK, NULL, "sctp_getpaddrs with invalid socket " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "sctp_getpaddrs() with invalid socket - ENOTSOCK"); /*sctp_getpaddrs() TEST8: socket of different protocol EOPNOTSUPP Expected error*/ error = sctp_getpaddrs(sk1, 0, &laddrs); if (error != -1 || errno != EOPNOTSUPP) tst_brkm(TBROK, NULL, "sctp_getpaddrs with socket of " "different protocol error:%d, errno:%d", error, errno); tst_resm(TPASS, "sctp_getpaddrs() with socket of different protocol - " "EOPNOTSUPP"); /*sctp_getpaddrs() TEST9: Getting the peer addresses*/ error = sctp_getpaddrs(acpt_sk, 0, &paddrs); if (error < 0) tst_brkm(TBROK, NULL, "sctp_getpaddrs with valid socket " "error:%d, errno:%d", error, errno); addr = (struct sockaddr_in *)paddrs; if (addr->sin_port != acpt_addr.sin_port || addr->sin_family != acpt_addr.sin_family || addr->sin_addr.s_addr != acpt_addr.sin_addr.s_addr) tst_brkm(TBROK, NULL, "sctp_getpaddrs comparision failed"); tst_resm(TPASS, "sctp_getpaddrs() - SUCCESS"); /*sctp_freeapddrs() TEST10: freeing the peer address*/ if ((sctp_freepaddrs(paddrs)) < 0) tst_brkm(TBROK, NULL, "sctp_freepaddrs " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "sctp_freepaddrs() - SUCCESS"); close(clnt_sk); tst_exit(); }
static int ndisc_send_unspec(int oif, const struct in6_addr *dest, uint8_t *hdr, int hdrlen, struct iovec *optv, size_t optvlen) { struct { struct ip6_hdr ip; struct icmp6_hdr icmp; uint8_t data[1500]; } frame; struct msghdr msgh; struct cmsghdr *cmsg; struct in6_pktinfo *pinfo; struct sockaddr_in6 dst; char cbuf[CMSG_SPACE(sizeof(*pinfo))]; struct iovec iov; uint8_t *data = (uint8_t *)(&frame.icmp); int type, fd, ret, remlen, datalen = 0, written = 0, v = 1; if (hdr == NULL || hdrlen < 0 || (size_t)hdrlen < sizeof(struct icmp6_hdr) || (size_t)hdrlen > (sizeof(frame) - sizeof(struct ip6_hdr))) return -EINVAL; if ((fd = socket(AF_INET6, SOCK_RAW, IPPROTO_RAW)) < 0) return -1; if (setsockopt(fd, IPPROTO_IPV6, IP_HDRINCL, &v, sizeof(v)) < 0) { dbg("cannot set IP_HDRINCL: %s\n", strerror(errno)); close(fd); return -errno; } memset(&frame, 0, sizeof(frame)); memset(&dst, 0, sizeof(dst)); dst.sin6_addr = *dest; /* Copy ICMPv6 header and update various length values */ memcpy(data, hdr, hdrlen); data += hdrlen; datalen += hdrlen; remlen = sizeof(frame) - sizeof(struct ip6_hdr) - hdrlen; /* Prepare for csum: write trailing options by linearizing iov */ if ((iov_linearize(data, remlen, optv, optvlen, &written) != 0) || (written & 0x1)) /* Ensure length is even for csum() */ return -1; datalen += written; /* Fill in the IPv6 header */ frame.ip.ip6_vfc = 0x60; frame.ip.ip6_plen = htons(datalen); frame.ip.ip6_nxt = IPPROTO_ICMPV6; frame.ip.ip6_hlim = 255; frame.ip.ip6_dst = *dest; /* all other fields are already set to zero */ frame.icmp.icmp6_cksum = in6_cksum(&in6addr_any, dest, &frame.icmp, datalen, IPPROTO_ICMPV6); iov.iov_base = &frame; iov.iov_len = sizeof(frame.ip) + datalen; dst.sin6_family = AF_INET6; msgh.msg_name = &dst; msgh.msg_namelen = sizeof(dst); msgh.msg_iov = &iov; msgh.msg_iovlen = 1; msgh.msg_flags = 0; memset(cbuf, 0, CMSG_SPACE(sizeof(*pinfo))); cmsg = (struct cmsghdr *)cbuf; pinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg); pinfo->ipi6_ifindex = oif; cmsg->cmsg_len = CMSG_LEN(sizeof(*pinfo)); cmsg->cmsg_level = IPPROTO_IPV6; cmsg->cmsg_type = IPV6_PKTINFO; msgh.msg_control = cmsg; msgh.msg_controllen = cmsg->cmsg_len; ret = sendmsg(fd, &msgh, 0); if (ret < 0) dbg("sendmsg: %s\n", strerror(errno)); close(fd); type = hdr[0]; if (type == ND_NEIGHBOR_SOLICIT) { statistics_inc(&mipl_stat, MIPL_STATISTICS_OUT_NS_UNSPEC); } else if (type == ND_ROUTER_SOLICIT) { statistics_inc(&mipl_stat, MIPL_STATISTICS_OUT_RS_UNSPEC); } return ret; }
/* * Class: sun_nio_ch_sctp_SctpChannelImpl * Method: send0 * Signature: (IJILjava/net/InetAddress;IIIZI)I */ JNIEXPORT jint JNICALL Java_sun_nio_ch_sctp_SctpChannelImpl_send0 (JNIEnv *env, jclass klass, jint fd, jlong address, jint length, jobject targetAddress, jint targetPort, jint assocId, jint streamNumber, jboolean unordered, jint ppid) { SOCKADDR sa; int sa_len = sizeof(sa); ssize_t rv = 0; jlong *addr = jlong_to_ptr(address); struct iovec iov[1]; struct msghdr msg[1]; int cbuf_size = CMSG_SPACE(sizeof (struct sctp_sndrcvinfo)); char cbuf[CMSG_SPACE(sizeof (struct sctp_sndrcvinfo))]; struct controlData cdata[1]; /* SctpChannel: * targetAddress may contain the preferred address or NULL to use primary, * assocId will always be -1 * SctpMultiChannell: * Setup new association, targetAddress will contain address, assocId = -1 * Association already existing, assocId != -1, targetAddress = preferred addr */ if (targetAddress != NULL /*&& assocId <= 0*/) { if (NET_InetAddressToSockaddr(env, targetAddress, targetPort, (struct sockaddr *)&sa, &sa_len, JNI_TRUE) != 0) { return IOS_THROWN; } } else { memset(&sa, '\x0', sa_len); sa_len = 0; } /* Set up the msghdr structure for sending */ memset(msg, 0, sizeof (*msg)); memset(cbuf, 0, cbuf_size); msg->msg_name = &sa; msg->msg_namelen = sa_len; iov->iov_base = addr; iov->iov_len = length; msg->msg_iov = iov; msg->msg_iovlen = 1; msg->msg_control = cbuf; msg->msg_controllen = cbuf_size; msg->msg_flags = 0; cdata->streamNumber = streamNumber; cdata->assocId = assocId; cdata->unordered = unordered; cdata->ppid = ppid; setControlData(msg, cdata); if ((rv = sendmsg(fd, msg, 0)) < 0) { if (errno == EWOULDBLOCK) { return IOS_UNAVAILABLE; } else if (errno == EINTR) { return IOS_INTERRUPTED; } else if (errno == EPIPE) { JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket is shutdown for writing"); } else { handleSocketError(env, errno); return 0; } } return rv; }
bool LogListener::onDataAvailable(SocketClient *cli) { static bool name_set; if (!name_set) { prctl(PR_SET_NAME, "logd.writer"); name_set = true; } char buffer[sizeof_log_id_t + sizeof(uint16_t) + sizeof(log_time) + LOGGER_ENTRY_MAX_PAYLOAD]; struct iovec iov = { buffer, sizeof(buffer) }; memset(buffer, 0, sizeof(buffer)); char control[CMSG_SPACE(sizeof(struct ucred))]; struct msghdr hdr = { NULL, 0, &iov, 1, control, sizeof(control), 0, }; int socket = cli->getSocket(); ssize_t n = recvmsg(socket, &hdr, 0); if (n <= (ssize_t)(sizeof(android_log_header_t))) { return false; } struct ucred *cred = NULL; struct cmsghdr *cmsg = CMSG_FIRSTHDR(&hdr); while (cmsg != NULL) { if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_CREDENTIALS) { cred = (struct ucred *)CMSG_DATA(cmsg); break; } cmsg = CMSG_NXTHDR(&hdr, cmsg); } if (cred == NULL) { return false; } if (cred->uid == AID_LOGD) { // ignore log messages we send to ourself. // Such log messages are often generated by libraries we depend on // which use standard Android logging. return false; } android_log_header_t *header = reinterpret_cast<android_log_header_t *>(buffer); if (/* header->id < LOG_ID_MIN || */ header->id >= LOG_ID_MAX) { return false; } char *msg = ((char *)buffer) + sizeof(android_log_header_t); n -= sizeof(android_log_header_t); // NB: hdr.msg_flags & MSG_TRUNC is not tested, silently passing a // truncated message to the logs. if (logbuf->log((log_id_t)header->id, header->realtime, cred->uid, cred->pid, header->tid, msg, ((size_t) n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX) >= 0) { reader->notifyNewLog(); } return true; }