static grpc_endpoint_op_status tcp_flush(grpc_tcp *tcp) { struct msghdr msg; struct iovec iov[MAX_WRITE_IOVEC]; int iov_size; ssize_t sent_length; ssize_t sending_length; ssize_t trailing; ssize_t unwind_slice_idx; ssize_t unwind_byte_idx; for (;;) { sending_length = 0; unwind_slice_idx = tcp->outgoing_slice_idx; unwind_byte_idx = tcp->outgoing_byte_idx; for (iov_size = 0; tcp->outgoing_slice_idx != tcp->outgoing_buffer->count && iov_size != MAX_WRITE_IOVEC; iov_size++) { iov[iov_size].iov_base = GPR_SLICE_START_PTR( tcp->outgoing_buffer->slices[tcp->outgoing_slice_idx]) + tcp->outgoing_byte_idx; iov[iov_size].iov_len = GPR_SLICE_LENGTH( tcp->outgoing_buffer->slices[tcp->outgoing_slice_idx]) - tcp->outgoing_byte_idx; sending_length += iov[iov_size].iov_len; tcp->outgoing_slice_idx++; tcp->outgoing_byte_idx = 0; } GPR_ASSERT(iov_size > 0); msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_iov = iov; msg.msg_iovlen = iov_size; msg.msg_control = NULL; msg.msg_controllen = 0; msg.msg_flags = 0; GRPC_TIMER_BEGIN(GRPC_PTAG_SENDMSG, 0); do { /* TODO(klempner): Cork if this is a partial write */ sent_length = sendmsg(tcp->fd, &msg, SENDMSG_FLAGS); } while (sent_length < 0 && errno == EINTR); GRPC_TIMER_END(GRPC_PTAG_SENDMSG, 0); if (sent_length < 0) { if (errno == EAGAIN) { tcp->outgoing_slice_idx = unwind_slice_idx; tcp->outgoing_byte_idx = unwind_byte_idx; return GRPC_ENDPOINT_PENDING; } else { /* TODO(klempner): Log some of these */ return GRPC_ENDPOINT_ERROR; } } GPR_ASSERT(tcp->outgoing_byte_idx == 0); trailing = sending_length - sent_length; while (trailing > 0) { ssize_t slice_length; tcp->outgoing_slice_idx--; slice_length = GPR_SLICE_LENGTH( tcp->outgoing_buffer->slices[tcp->outgoing_slice_idx]); if (slice_length > trailing) { tcp->outgoing_byte_idx = slice_length - trailing; break; } else { trailing -= slice_length; } } if (tcp->outgoing_slice_idx == tcp->outgoing_buffer->count) { return GRPC_ENDPOINT_DONE; } }; }
/* Returns zero on success, less than zero on socket error and greater than * zero on other errors. */ static int conn_read_netlink (void) { #if HAVE_STRUCT_LINUX_INET_DIAG_REQ int fd; struct inet_diag_msg *r; char buf[8192]; /* If this fails, it's likely a permission problem. We'll fall back to * reading this information from files below. */ fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_INET_DIAG); if (fd < 0) { ERROR ("tcpconns plugin: conn_read_netlink: socket(AF_NETLINK, SOCK_RAW, " "NETLINK_INET_DIAG) failed: %s", sstrerror (errno, buf, sizeof (buf))); return (-1); } struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK }; struct nlreq req = { .nlh.nlmsg_len = sizeof(req), .nlh.nlmsg_type = TCPDIAG_GETSOCK, /* NLM_F_ROOT: return the complete table instead of a single entry. * NLM_F_MATCH: return all entries matching criteria (not implemented) * NLM_F_REQUEST: must be set on all request messages */ .nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST, .nlh.nlmsg_pid = 0, /* The sequence_number is used to track our messages. Since netlink is not * reliable, we don't want to end up with a corrupt or incomplete old * message in case the system is/was out of memory. */ .nlh.nlmsg_seq = ++sequence_number, .r.idiag_family = AF_INET, .r.idiag_states = 0xfff, .r.idiag_ext = 0 }; struct iovec iov = { .iov_base = &req, .iov_len = sizeof(req) }; struct msghdr msg = { .msg_name = (void*)&nladdr, .msg_namelen = sizeof(nladdr), .msg_iov = &iov, .msg_iovlen = 1 }; if (sendmsg (fd, &msg, 0) < 0) { ERROR ("tcpconns plugin: conn_read_netlink: sendmsg(2) failed: %s", sstrerror (errno, buf, sizeof (buf))); close (fd); return (-1); } iov.iov_base = buf; iov.iov_len = sizeof(buf); while (1) { int status; struct nlmsghdr *h; memset(&msg, 0, sizeof(msg)); msg.msg_name = (void*)&nladdr; msg.msg_namelen = sizeof(nladdr); msg.msg_iov = &iov; msg.msg_iovlen = 1; status = recvmsg(fd, (void *) &msg, /* flags = */ 0); if (status < 0) { if ((errno == EINTR) || (errno == EAGAIN)) continue; ERROR ("tcpconns plugin: conn_read_netlink: recvmsg(2) failed: %s", sstrerror (errno, buf, sizeof (buf))); close (fd); return (-1); } else if (status == 0) { close (fd); DEBUG ("tcpconns plugin: conn_read_netlink: Unexpected zero-sized " "reply from netlink socket."); return (0); } h = (struct nlmsghdr*)buf; while (NLMSG_OK(h, status)) { if (h->nlmsg_seq != sequence_number) { h = NLMSG_NEXT(h, status); continue; } if (h->nlmsg_type == NLMSG_DONE) { close (fd); return (0); } else if (h->nlmsg_type == NLMSG_ERROR) { struct nlmsgerr *msg_error; msg_error = NLMSG_DATA(h); WARNING ("tcpconns plugin: conn_read_netlink: Received error %i.", msg_error->error); close (fd); return (1); } r = NLMSG_DATA(h); /* This code does not (need to) distinguish between IPv4 and IPv6. */ conn_handle_ports (ntohs(r->id.idiag_sport), ntohs(r->id.idiag_dport), r->idiag_state); h = NLMSG_NEXT(h, status); } /* while (NLMSG_OK) */ } /* while (1) */ /* Not reached because the while() loop above handles the exit condition. */ return (0); #else return (1); #endif /* HAVE_STRUCT_LINUX_INET_DIAG_REQ */ } /* int conn_read_netlink */ static int conn_handle_line (char *buffer) { char *fields[32]; int fields_len; char *endptr; char *port_local_str; char *port_remote_str; uint16_t port_local; uint16_t port_remote; uint8_t state; int buffer_len = strlen (buffer); while ((buffer_len > 0) && (buffer[buffer_len - 1] < 32)) buffer[--buffer_len] = '\0'; if (buffer_len <= 0) return (-1); fields_len = strsplit (buffer, fields, STATIC_ARRAY_SIZE (fields)); if (fields_len < 12) { DEBUG ("tcpconns plugin: Got %i fields, expected at least 12.", fields_len); return (-1); } port_local_str = strchr (fields[1], ':'); port_remote_str = strchr (fields[2], ':'); if ((port_local_str == NULL) || (port_remote_str == NULL)) return (-1); port_local_str++; port_remote_str++; if ((*port_local_str == '\0') || (*port_remote_str == '\0')) return (-1); endptr = NULL; port_local = (uint16_t) strtol (port_local_str, &endptr, 16); if ((endptr == NULL) || (*endptr != '\0')) return (-1); endptr = NULL; port_remote = (uint16_t) strtol (port_remote_str, &endptr, 16); if ((endptr == NULL) || (*endptr != '\0')) return (-1); endptr = NULL; state = (uint8_t) strtol (fields[3], &endptr, 16); if ((endptr == NULL) || (*endptr != '\0')) return (-1); return (conn_handle_ports (port_local, port_remote, state)); } /* int conn_handle_line */ static int conn_read_file (const char *file) { FILE *fh; char buffer[1024]; fh = fopen (file, "r"); if (fh == NULL) return (-1); while (fgets (buffer, sizeof (buffer), fh) != NULL) { conn_handle_line (buffer); } /* while (fgets) */ fclose (fh); return (0); } /* int conn_read_file */ /* #endif KERNEL_LINUX */ #elif HAVE_SYSCTLBYNAME /* #endif HAVE_SYSCTLBYNAME */ #elif HAVE_LIBKVM_NLIST #endif /* HAVE_LIBKVM_NLIST */ static int conn_config (const char *key, const char *value) { if (strcasecmp (key, "ListeningPorts") == 0) { if (IS_TRUE (value)) port_collect_listening = 1; else port_collect_listening = 0; } else if ((strcasecmp (key, "LocalPort") == 0) || (strcasecmp (key, "RemotePort") == 0)) { port_entry_t *pe; int port = atoi (value); if ((port < 1) || (port > 65535)) { ERROR ("tcpconns plugin: Invalid port: %i", port); return (1); } pe = conn_get_port_entry ((uint16_t) port, 1 /* create */); if (pe == NULL) { ERROR ("tcpconns plugin: conn_get_port_entry failed."); return (1); } if (strcasecmp (key, "LocalPort") == 0) pe->flags |= PORT_COLLECT_LOCAL; else pe->flags |= PORT_COLLECT_REMOTE; } else if (strcasecmp (key, "AllPortsSummary") == 0) { if (IS_TRUE (value)) port_collect_total = 1; else port_collect_total = 0; } else { return (-1); } return (0); } /* int conn_config */ #if KERNEL_LINUX static int conn_init (void) { if (port_collect_total == 0 && port_list_head == NULL) port_collect_listening = 1; return (0); } /* int conn_init */ static int conn_read (void) { int status; conn_reset_port_entry (); if (linux_source == SRC_NETLINK) { status = conn_read_netlink (); } else if (linux_source == SRC_PROC) { int errors_num = 0; if (conn_read_file ("/proc/net/tcp") != 0) errors_num++; if (conn_read_file ("/proc/net/tcp6") != 0) errors_num++; if (errors_num < 2) status = 0; else status = ENOENT; } else /* if (linux_source == SRC_DUNNO) */ { /* Try to use netlink for getting this data, it is _much_ faster on systems * with a large amount of connections. */ status = conn_read_netlink (); if (status == 0) { INFO ("tcpconns plugin: Reading from netlink succeeded. " "Will use the netlink method from now on."); linux_source = SRC_NETLINK; } else { INFO ("tcpconns plugin: Reading from netlink failed. " "Will read from /proc from now on."); linux_source = SRC_PROC; /* return success here to avoid the "plugin failed" message. */ return (0); } } if (status == 0) conn_submit_all (); else return (status); return (0); } /* int conn_read */
int emf_cfg_request_send(emf_cfg_request_t *buffer, int length) { struct sockaddr_nl src_addr, dest_addr; struct nlmsghdr *nlh = NULL; struct msghdr msg; struct iovec iov; int sock_fd, ret; if ((buffer == NULL) || (length > MAX_DATA_SIZE)) { fprintf(stderr, "Invalid parameters %p %d\n", buffer, length); return (FAILURE); } /* Create a netlink socket */ sock_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_EMFC); if (sock_fd < 0) { fprintf(stderr, "Netlink socket create failed\n"); return (FAILURE); } /* Associate a local address with the opened socket */ memset(&src_addr, 0, sizeof(struct sockaddr_nl)); src_addr.nl_family = AF_NETLINK; src_addr.nl_pid = getpid(); src_addr.nl_groups = 0; bind(sock_fd, (struct sockaddr *)&src_addr, sizeof(src_addr)); /* Fill the destination address, pid of 0 indicates kernel */ memset(&dest_addr, 0, sizeof(struct sockaddr_nl)); dest_addr.nl_family = AF_NETLINK; dest_addr.nl_pid = 0; dest_addr.nl_groups = 0; /* Allocate memory for sending configuration request */ nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_DATA_SIZE)); if (nlh == NULL) { fprintf(stderr, "Out of memory allocating cfg buffer\n"); return (FAILURE); } /* Fill the netlink message header. The configuration request * contains netlink header followed by data. */ nlh->nlmsg_len = NLMSG_SPACE(MAX_DATA_SIZE); nlh->nlmsg_pid = getpid(); nlh->nlmsg_flags = 0; /* Fill the data part */ memcpy(NLMSG_DATA(nlh), buffer, length); iov.iov_base = (void *)nlh; iov.iov_len = nlh->nlmsg_len; memset(&msg, 0, sizeof(struct msghdr)); msg.msg_name = (void *)&dest_addr; msg.msg_namelen = sizeof(dest_addr); msg.msg_iov = &iov; msg.msg_iovlen = 1; /* Send request to kernel module */ ret = sendmsg(sock_fd, &msg, 0); if (ret < 0) { perror("sendmsg:"); free(nlh); return (ret); } /* Wait for the response */ memset(nlh, 0, NLMSG_SPACE(MAX_DATA_SIZE)); ret = recvmsg(sock_fd, &msg, 0); if (ret < 0) { perror("recvmsg:"); free(nlh); return (ret); } /* Copy data to user buffer */ memcpy(buffer, NLMSG_DATA(nlh), length); free(nlh); close(sock_fd); return (ret); }
void thread_loop(void *userdata) { struct state *state = userdata; pthread_spin_init(&state->lock, PTHREAD_PROCESS_PRIVATE); pthread_spin_lock(&state->lock); stddev_init(&state->stddev); stddev_init(&state->stddev_packet); pthread_spin_unlock(&state->lock); char send_buf[MTU_SIZE], recv_buf[MTU_SIZE]; struct msghdr *msg = calloc(2, sizeof(struct msghdr)); struct iovec *iovec = calloc(2, sizeof(struct iovec)); int i; for (i = 0; i < 2; i++) { msg[i].msg_iov = &iovec[i]; msg[i].msg_iovlen = 1; iovec[i].iov_len = sizeof(send_buf); iovec[i].iov_len = state->packet_size; } iovec[0].iov_base = send_buf; iovec[1].iov_base = recv_buf; char pktinfo[4096]; msg[1].msg_control = pktinfo; msg[1].msg_controllen = sizeof(pktinfo); uint64_t packet_no = 0; while (1) { int fd = net_connect_udp(state->target_addr, state->src_port, state->busy_poll); struct timeval tv = {1, 0}; // 1 second int r = setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); if (r < 0) { PFATAL("setsockopt(SO_RCVTIMEO)"); } for (;; packet_no++) { memset(send_buf, 0, sizeof(send_buf)); snprintf(send_buf, state->packet_size, "%i-%li-%lu", getpid(), gettid(), packet_no); uint64_t t0 = realtime_now(), t1 = 0, tp = 0; int r = sendmsg(fd, &msg[0], 0); if (r <= 0) { if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ECONNREFUSED) { break; } if (errno == EINTR) { continue; } PFATAL("sendmmsg()"); } msg[1].msg_controllen = sizeof(pktinfo); while (1) { int flags = state->polling ? MSG_DONTWAIT : 0; r = recvmsg(fd, &msg[1], flags); t1 = realtime_now(); if (t1 - t0 >= 1000000000) { /* No msg for 1s */ errno = ECONNREFUSED; break; } if (r <= 0 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)) { continue; } if (r == 0 && state->polling) { continue; } break; } if (r <= 0 && errno == ECONNREFUSED) { sleep(1); break; } if (r <= 0) { PFATAL("recvmmsg()"); } if (memcmp(send_buf, recv_buf, sizeof(recv_buf)) != 0) { fprintf(stderr, "[!] bad message\n"); sleep(1); break; } struct cmsghdr *cmsg; for (cmsg = CMSG_FIRSTHDR(&msg[1]); cmsg; cmsg = CMSG_NXTHDR(&msg[1], cmsg)) { switch (cmsg->cmsg_level) { case SOL_SOCKET: switch (cmsg->cmsg_type) { case SO_TIMESTAMPNS: { struct timespec *ts = (struct timespec *) CMSG_DATA(cmsg); tp = TIMESPEC_NSEC(ts); break; } } break; } } pthread_spin_lock(&state->lock); stddev_add(&state->stddev, t1 - t0); if (tp != 0) { stddev_add(&state->stddev_packet, t1 - tp); } pthread_spin_unlock(&state->lock); } close(fd); } }
ssize_t _ribified_sendmsg(int sockfd, const struct msghdr *msg, int flags) { int res; while ((res = sendmsg(sockfd, msg, flags)) < 0 && yield_if_eagain(sockfd)); return res; }
void test_sendmsg_server(cyg_addrword_t pnetdata) { int s, i, sendmsglen; struct sockaddr_in sa, r_sa; struct hostent *hp; struct msghdr msghdr_msg; struct iovec *piov; int j; int perIov_len; char tmp[TEST_SENDMSG_MSG_LEN]; int threadid; int port = ((TEST_SENDMSG_DATA_T*)pnetdata)->iport; char *pbuf = ((TEST_SENDMSG_DATA_T*)pnetdata)->pbuf; threadid = port; if(inet_aton(TEST_SENDMSG_SERVER_ADDR, &sa.sin_addr, pbuf, RNT_BUFFER_LEN) == 0) { test_printf_error("test_sendmsg_server"); cyg_thread_exit(); } sa.sin_family = AF_INET; sa.sin_port = htons(IPPORT_USERRESERVED + port); if((hp = gethostbyname(TEST_REMOTEFUNC_HOSTNAME, pbuf, RNT_BUFFER_LEN)) == NULL) { test_printf_error("test_sendmsg_server"); cyg_thread_exit(); } memcpy(&(r_sa.sin_addr), hp->h_addr_list0, hp->h_length); r_sa.sin_family = AF_INET; r_sa.sin_port = htons(IPPORT_USERRESERVED + port); if((s = socket(AF_INET, SOCK_STREAM, PF_UNSPEC, pbuf, RNT_BUFFER_LEN)) == -1) { test_printf_error("test_sendmsg_server"); cyg_thread_exit(); } if(set_reuseaddr(s, pbuf, RNT_BUFFER_LEN) == -1) { test_printf_error("test_sendmsg_server"); netclose(s, pbuf, RNT_BUFFER_LEN); cyg_thread_exit(); } if(bind(s, (struct sockaddr*)&r_sa, sizeof(r_sa), pbuf, RNT_BUFFER_LEN) == -1) { test_printf_error("test_sendmsg_server"); netclose(s, pbuf, RNT_BUFFER_LEN); cyg_thread_exit(); } if(connect(s, (struct sockaddr*)&sa, sizeof(sa), pbuf, RNT_BUFFER_LEN) == -1) { test_printf_error("test_sendmsg_server"); cyg_thread_exit(); } for(i = 0; i < TEST_SENDMSG_WRITE_TIMES; i++) { strcpy(tmp, TEST_SENDMSG_MSG); perIov_len = TEST_SENDMSG_MSG_PART_LEN; piov = malloc(TEST_SENDMSG_MSG_PARTS*sizeof(struct iovec)); if(piov == NULL) { test_printf_error("test_sendmsg_server"); goto fail; } memset(piov, 0, TEST_SENDMSG_MSG_PARTS*sizeof(struct iovec)); for(j = 0; j < TEST_SENDMSG_MSG_PARTS; j++) { piov[j].iov_base = malloc(perIov_len); if(piov[j].iov_base == NULL) { test_printf_error("test_sendmsg_server"); for(i = 0; i < j; i++) free(piov[j].iov_base); if(piov != NULL) free(piov); goto fail; } piov[j].iov_len = perIov_len; memcpy(piov[j].iov_base, tmp + j * TEST_SENDMSG_MSG_PART_LEN, TEST_SENDMSG_MSG_PART_LEN); } msghdr_msg.msg_name = NULL; msghdr_msg.msg_namelen = 0; msghdr_msg.msg_iov = piov; msghdr_msg.msg_iovlen = TEST_SENDMSG_MSG_PARTS; msghdr_msg.msg_control = NULL; msghdr_msg.msg_controllen = 0; msghdr_msg.msg_flags = 0; sendmsglen = sendmsg(s, &msghdr_msg, 0, pbuf, RNT_BUFFER_LEN); if(sendmsglen < 0) { test_printf_error("test_sendmsg_server"); for(j = 0; j < TEST_SENDMSG_MSG_PARTS; j++) { if(piov[j].iov_base != NULL) free(piov[j].iov_base); } if(piov != NULL) free(piov); break; } for(j = 0; j < TEST_SENDMSG_MSG_PARTS; j++) { if(piov[j].iov_base != NULL) free(piov[j].iov_base); } if(piov != NULL) free(piov); } test_printf_success("test_sendmsg_server"); fail: netclose(s, pbuf, RNT_BUFFER_LEN); cyg_thread_exit(); }
int dhcp_network_icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) { struct sockaddr_in6 dst = { .sin6_family = AF_INET6, .sin6_addr = IN6ADDR_ALL_ROUTERS_MULTICAST_INIT, }; struct { struct nd_router_solicit rs; struct nd_opt_hdr rs_opt; struct ether_addr rs_opt_mac; } _packed_ rs = { .rs.nd_rs_type = ND_ROUTER_SOLICIT, }; struct iovec iov[1] = { { &rs, }, }; struct msghdr msg = { .msg_name = &dst, .msg_namelen = sizeof(dst), .msg_iov = iov, .msg_iovlen = 1, }; int r; if (ether_addr) { memcpy(&rs.rs_opt_mac, ether_addr, ETH_ALEN); rs.rs_opt.nd_opt_type = ND_OPT_SOURCE_LINKADDR; rs.rs_opt.nd_opt_len = 1; iov[0].iov_len = sizeof(rs); } else iov[0].iov_len = sizeof(rs.rs); r = sendmsg(s, &msg, 0); if (r < 0) return -errno; return 0; } int dhcp6_network_bind_udp_socket(int index, struct in6_addr *local_address) { struct in6_pktinfo pktinfo = { .ipi6_ifindex = index, }; union sockaddr_union src = { .in6.sin6_family = AF_INET6, .in6.sin6_port = htobe16(DHCP6_PORT_CLIENT), .in6.sin6_addr = IN6ADDR_ANY_INIT, }; _cleanup_close_ int s = -1; int r, off = 0, on = 1; if (local_address) memcpy(&src.in6.sin6_addr, local_address, sizeof(src.in6.sin6_addr)); s = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, IPPROTO_UDP); if (s < 0) return -errno; r = setsockopt(s, IPPROTO_IPV6, IPV6_PKTINFO, &pktinfo, sizeof(pktinfo)); if (r < 0) return -errno; r = setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)); if (r < 0) return -errno; r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &off, sizeof(off)); if (r < 0) return -errno; r = bind(s, &src.sa, sizeof(src.in6)); if (r < 0) return -errno; r = s; s = -1; return r; } int dhcp6_network_send_udp_socket(int s, struct in6_addr *server_address, const void *packet, size_t len) { union sockaddr_union dest = { .in6.sin6_family = AF_INET6, .in6.sin6_port = htobe16(DHCP6_PORT_SERVER), }; int r; assert(server_address); memcpy(&dest.in6.sin6_addr, server_address, sizeof(dest.in6.sin6_addr)); r = sendto(s, packet, len, 0, &dest.sa, sizeof(dest.in6)); if (r < 0) return -errno; return 0; }
ssize_t sctp_sendv(int sd, const struct iovec *iov, int iovcnt, struct sockaddr *addrs, int addrcnt, void *info, socklen_t infolen, unsigned int infotype, int flags) { ssize_t ret; int i; socklen_t addr_len; struct msghdr msg; in_port_t port; struct sctp_sendv_spa *spa_info; struct cmsghdr *cmsg; char *cmsgbuf; struct sockaddr *addr; struct sockaddr_in *addr_in; struct sockaddr_in6 *addr_in6; if ((addrcnt < 0) || (iovcnt < 0) || ((addrs == NULL) && (addrcnt > 0)) || ((addrs != NULL) && (addrcnt == 0)) || ((iov == NULL) && (iovcnt > 0)) || ((iov != NULL) && (iovcnt == 0))) { errno = EINVAL; return (-1); } cmsgbuf = malloc(CMSG_SPACE(sizeof(struct sctp_sndinfo)) + CMSG_SPACE(sizeof(struct sctp_prinfo)) + CMSG_SPACE(sizeof(struct sctp_authinfo)) + (size_t)addrcnt * CMSG_SPACE(sizeof(struct in6_addr))); if (cmsgbuf == NULL) { errno = ENOMEM; return (-1); } msg.msg_control = cmsgbuf; msg.msg_controllen = 0; cmsg = (struct cmsghdr *)cmsgbuf; switch (infotype) { case SCTP_SENDV_NOINFO: if ((infolen != 0) || (info != NULL)) { free(cmsgbuf); errno = EINVAL; return (-1); } break; case SCTP_SENDV_SNDINFO: if ((info == NULL) || (infolen < sizeof(struct sctp_sndinfo))) { free(cmsgbuf); errno = EINVAL; return (-1); } cmsg->cmsg_level = IPPROTO_SCTP; cmsg->cmsg_type = SCTP_SNDINFO; cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo)); memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_sndinfo)); msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo)); cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_sndinfo))); break; case SCTP_SENDV_PRINFO: if ((info == NULL) || (infolen < sizeof(struct sctp_prinfo))) { free(cmsgbuf); errno = EINVAL; return (-1); } cmsg->cmsg_level = IPPROTO_SCTP; cmsg->cmsg_type = SCTP_PRINFO; cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo)); memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_prinfo)); msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo)); cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_prinfo))); break; case SCTP_SENDV_AUTHINFO: if ((info == NULL) || (infolen < sizeof(struct sctp_authinfo))) { free(cmsgbuf); errno = EINVAL; return (-1); } cmsg->cmsg_level = IPPROTO_SCTP; cmsg->cmsg_type = SCTP_AUTHINFO; cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_authinfo)); memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_authinfo)); msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_authinfo)); cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_authinfo))); break; case SCTP_SENDV_SPA: if ((info == NULL) || (infolen < sizeof(struct sctp_sendv_spa))) { free(cmsgbuf); errno = EINVAL; return (-1); } spa_info = (struct sctp_sendv_spa *)info; if (spa_info->sendv_flags & SCTP_SEND_SNDINFO_VALID) { cmsg->cmsg_level = IPPROTO_SCTP; cmsg->cmsg_type = SCTP_SNDINFO; cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo)); memcpy(CMSG_DATA(cmsg), &spa_info->sendv_sndinfo, sizeof(struct sctp_sndinfo)); msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo)); cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_sndinfo))); } if (spa_info->sendv_flags & SCTP_SEND_PRINFO_VALID) { cmsg->cmsg_level = IPPROTO_SCTP; cmsg->cmsg_type = SCTP_PRINFO; cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo)); memcpy(CMSG_DATA(cmsg), &spa_info->sendv_prinfo, sizeof(struct sctp_prinfo)); msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo)); cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_prinfo))); } if (spa_info->sendv_flags & SCTP_SEND_AUTHINFO_VALID) { cmsg->cmsg_level = IPPROTO_SCTP; cmsg->cmsg_type = SCTP_AUTHINFO; cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_authinfo)); memcpy(CMSG_DATA(cmsg), &spa_info->sendv_authinfo, sizeof(struct sctp_authinfo)); msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_authinfo)); cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_authinfo))); } break; default: free(cmsgbuf); errno = EINVAL; return (-1); } addr = addrs; msg.msg_name = NULL; msg.msg_namelen = 0; for (i = 0; i < addrcnt; i++) { switch (addr->sa_family) { case AF_INET: addr_len = (socklen_t) sizeof(struct sockaddr_in); addr_in = (struct sockaddr_in *)addr; if (addr_in->sin_len != addr_len) { free(cmsgbuf); errno = EINVAL; return (-1); } if (i == 0) { port = addr_in->sin_port; } else { if (port == addr_in->sin_port) { cmsg->cmsg_level = IPPROTO_SCTP; cmsg->cmsg_type = SCTP_DSTADDRV4; cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr)); memcpy(CMSG_DATA(cmsg), &addr_in->sin_addr, sizeof(struct in_addr)); msg.msg_controllen += CMSG_SPACE(sizeof(struct in_addr)); cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct in_addr))); } else { free(cmsgbuf); errno = EINVAL; return (-1); } } break; case AF_INET6: addr_len = (socklen_t) sizeof(struct sockaddr_in6); addr_in6 = (struct sockaddr_in6 *)addr; if (addr_in6->sin6_len != addr_len) { free(cmsgbuf); errno = EINVAL; return (-1); } if (i == 0) { port = addr_in6->sin6_port; } else { if (port == addr_in6->sin6_port) { cmsg->cmsg_level = IPPROTO_SCTP; cmsg->cmsg_type = SCTP_DSTADDRV6; cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_addr)); memcpy(CMSG_DATA(cmsg), &addr_in6->sin6_addr, sizeof(struct in6_addr)); msg.msg_controllen += CMSG_SPACE(sizeof(struct in6_addr)); cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct in6_addr))); } else { free(cmsgbuf); errno = EINVAL; return (-1); } } break; default: free(cmsgbuf); errno = EINVAL; return (-1); } if (i == 0) { msg.msg_name = addr; msg.msg_namelen = addr_len; } addr = (struct sockaddr *)((caddr_t)addr + addr_len); } if (msg.msg_controllen == 0) { msg.msg_control = NULL; } msg.msg_iov = (struct iovec *)iov; msg.msg_iovlen = iovcnt; msg.msg_flags = 0; ret = sendmsg(sd, &msg, flags); free(cmsgbuf); return (ret); }
ssize_t sctp_sendmsg(int s, const void *data, size_t len, const struct sockaddr *to, socklen_t tolen, uint32_t ppid, uint32_t flags, uint16_t stream_no, uint32_t timetolive, uint32_t context) { #ifdef SYS_sctp_generic_sendmsg struct sctp_sndrcvinfo sinfo; memset(&sinfo, 0, sizeof(struct sctp_sndrcvinfo)); sinfo.sinfo_ppid = ppid; sinfo.sinfo_flags = flags; sinfo.sinfo_stream = stream_no; sinfo.sinfo_timetolive = timetolive; sinfo.sinfo_context = context; sinfo.sinfo_assoc_id = 0; return (syscall(SYS_sctp_generic_sendmsg, s, data, len, to, tolen, &sinfo, 0)); #else ssize_t sz; struct msghdr msg; struct sctp_sndrcvinfo *s_info; struct iovec iov; char controlVector[SCTP_CONTROL_VEC_SIZE_RCV]; struct cmsghdr *cmsg; struct sockaddr *who = NULL; union { struct sockaddr_in in; struct sockaddr_in6 in6; } addr; if ((tolen > 0) && ((to == NULL) || (tolen < sizeof(struct sockaddr)))) { errno = EINVAL; return (-1); } if (to && (tolen > 0)) { if (to->sa_family == AF_INET) { if (tolen != sizeof(struct sockaddr_in)) { errno = EINVAL; return (-1); } if ((to->sa_len > 0) && (to->sa_len != sizeof(struct sockaddr_in))) { errno = EINVAL; return (-1); } memcpy(&addr, to, sizeof(struct sockaddr_in)); addr.in.sin_len = sizeof(struct sockaddr_in); } else if (to->sa_family == AF_INET6) { if (tolen != sizeof(struct sockaddr_in6)) { errno = EINVAL; return (-1); } if ((to->sa_len > 0) && (to->sa_len != sizeof(struct sockaddr_in6))) { errno = EINVAL; return (-1); } memcpy(&addr, to, sizeof(struct sockaddr_in6)); addr.in6.sin6_len = sizeof(struct sockaddr_in6); } else { errno = EAFNOSUPPORT; return (-1); } who = (struct sockaddr *)&addr; } iov.iov_base = (char *)data; iov.iov_len = len; if (who) { msg.msg_name = (caddr_t)who; msg.msg_namelen = who->sa_len; } else { msg.msg_name = (caddr_t)NULL; msg.msg_namelen = 0; } msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = (caddr_t)controlVector; cmsg = (struct cmsghdr *)controlVector; cmsg->cmsg_level = IPPROTO_SCTP; cmsg->cmsg_type = SCTP_SNDRCV; cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); s_info = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); s_info->sinfo_stream = stream_no; s_info->sinfo_ssn = 0; s_info->sinfo_flags = flags; s_info->sinfo_ppid = ppid; s_info->sinfo_context = context; s_info->sinfo_assoc_id = 0; s_info->sinfo_timetolive = timetolive; errno = 0; msg.msg_controllen = cmsg->cmsg_len; sz = sendmsg(s, &msg, 0); return (sz); #endif }
//----------------------------------------------------------------------------- //----------------------------------------------------------------------------- int pdcp_fifo_flush_sdus () { //----------------------------------------------------------------------------- mem_block_t *sdu = list_get_head (&pdcp_sdu_list); int bytes_wrote = 0; int pdcp_nb_sdu_sent = 0; uint8_t cont = 1; int ret; while ((sdu) && (cont)) { #ifdef USER_MODE // asjust the instance id when passing sdu to IP ((pdcp_data_ind_header_t *)(sdu->data))->inst = (((pdcp_data_ind_header_t *)(sdu->data))->inst >= NB_eNB_INST) ? ((pdcp_data_ind_header_t *)(sdu->data))->inst - NB_eNB_INST +oai_emulation.info.nb_enb_local - oai_emulation.info.first_ue_local :// UE ((pdcp_data_ind_header_t *)(sdu->data))->inst - oai_emulation.info.first_ue_local; // ENB #else ((pdcp_data_ind_header_t *)(sdu->data))->inst = 0; #endif #ifdef PDCP_DEBUG msg("[PDCP][INFO] PDCP->IP TTI %d INST %d: Preparing %d Bytes of data from rab %d to Nas_mesh\n", Mac_rlc_xface->frame, ((pdcp_data_ind_header_t *)(sdu->data))->inst, ((pdcp_data_ind_header_t *)(sdu->data))->data_size, ((pdcp_data_ind_header_t *)(sdu->data))->rb_id); #endif //PDCP_DEBUG cont = 0; if (!pdcp_output_sdu_bytes_to_write) { if (!pdcp_output_header_bytes_to_write) { pdcp_output_header_bytes_to_write = sizeof (pdcp_data_ind_header_t); } #ifndef USER_MODE bytes_wrote = rtf_put (PDCP2NAS_FIFO, &(((uint8_t *) sdu->data)[sizeof (pdcp_data_ind_header_t) - pdcp_output_header_bytes_to_write]), pdcp_output_header_bytes_to_write); #else #ifdef NAS_NETLINK #ifdef LINUX memcpy(NLMSG_DATA(nas_nlh), &(((uint8_t *) sdu->data)[sizeof (pdcp_data_ind_header_t) - pdcp_output_header_bytes_to_write]), pdcp_output_header_bytes_to_write); nas_nlh->nlmsg_len = pdcp_output_header_bytes_to_write; #endif //LINUX #endif //NAS_NETLINK bytes_wrote = pdcp_output_header_bytes_to_write; #endif //USER_MODE #ifdef PDCP_DEBUG msg("[PDCP][INFO] TTI %d Sent %d Bytes of header to Nas_mesh\n", Mac_rlc_xface->frame, bytes_wrote); #endif //PDCP_DEBUG if (bytes_wrote > 0) { pdcp_output_header_bytes_to_write = pdcp_output_header_bytes_to_write - bytes_wrote; if (!pdcp_output_header_bytes_to_write) { // continue with sdu pdcp_output_sdu_bytes_to_write = ((pdcp_data_ind_header_t *) sdu->data)->data_size; #ifndef USER_MODE bytes_wrote = rtf_put (PDCP2NAS_FIFO, &(sdu->data[sizeof (pdcp_data_ind_header_t)]), pdcp_output_sdu_bytes_to_write); #else #ifdef NAS_NETLINK #ifdef LINUX memcpy(NLMSG_DATA(nas_nlh)+sizeof(pdcp_data_ind_header_t), &(sdu->data[sizeof (pdcp_data_ind_header_t)]), pdcp_output_sdu_bytes_to_write); nas_nlh->nlmsg_len += pdcp_output_sdu_bytes_to_write; ret = sendmsg(nas_sock_fd,&nas_msg,0); if (ret<0) { msg("[PDCP_FIFOS] sendmsg returns %d\n",ret); perror("error code:"); mac_xface->macphy_exit(""); break; } #endif // LINUX #endif //NAS_NETLINK bytes_wrote= pdcp_output_sdu_bytes_to_write; #endif // USER_MODE #ifdef PDCP_DEBUG msg("[PDCP][INFO] PDCP->IP TTI %d INST %d: Sent %d Bytes of data from rab %d to Nas_mesh\n", Mac_rlc_xface->frame, ((pdcp_data_ind_header_t *)(sdu->data))->inst, bytes_wrote, ((pdcp_data_ind_header_t *)(sdu->data))->rb_id); #endif //PDCP_DEBUG if (bytes_wrote > 0) { pdcp_output_sdu_bytes_to_write -= bytes_wrote; if (!pdcp_output_sdu_bytes_to_write) { // OK finish with this SDU // msg("rb sent a sdu qos_sap %d\n",sapiP); list_remove_head (&pdcp_sdu_list); free_mem_block (sdu); cont = 1; pdcp_nb_sdu_sent += 1; sdu = list_get_head (&pdcp_sdu_list); } } else { msg ("[PDCP] RADIO->IP SEND SDU CONGESTION!\n"); } } else { msg ("[PDCP] RADIO->IP SEND SDU CONGESTION!\n"); } } } else { // continue writing sdu #ifndef USER_MODE bytes_wrote = rtf_put (PDCP2NAS_FIFO, (uint8_t *) (&(sdu->data[sizeof (pdcp_data_ind_header_t) + ((pdcp_data_ind_header_t *) sdu->data)->data_size - pdcp_output_sdu_bytes_to_write])), pdcp_output_sdu_bytes_to_write); #else // USER_MODE bytes_wrote = pdcp_output_sdu_bytes_to_write; #endif // USER_MODE if (bytes_wrote > 0) { pdcp_output_sdu_bytes_to_write -= bytes_wrote; if (!pdcp_output_sdu_bytes_to_write) { // OK finish with this SDU //PRINT_RB_SEND_OUTPUT_SDU ("[PDCP] RADIO->IP SEND SDU\n"); list_remove_head (&pdcp_sdu_list); free_mem_block (sdu); cont = 1; pdcp_nb_sdu_sent += 1; sdu = list_get_head (&pdcp_sdu_list); // msg("rb sent a sdu from rab\n"); } } } } #ifndef USER_MODE if ((pdcp_nb_sdu_sent)) { if ((pdcp_2_nas_irq > 0)) { #ifdef PDCP_DEBUG msg("[PDCP][INFO] TTI %d : Trigger NAS RX interrupt\n", Mac_rlc_xface->frame); #endif //PDCP_DEBUG rt_pend_linux_srq (pdcp_2_nas_irq); } else { msg ("[PDCP] TTI %d: ERROR IF IP STACK WANTED : NOTIF PACKET(S) pdcp_2_nas_irq not initialized : %d\n", Mac_rlc_xface->frame, pdcp_2_nas_irq); } } #endif //USER_MODE return pdcp_nb_sdu_sent; }
ssize_t send_to_from(int fd, void *buf, size_t len, int flags, const struct sockaddr *to, const struct sockaddr *from, socklen_t tolen) { #ifndef IP_PKTINFO return sendto(fd, buf, len, flags, to, tolen); #else struct iovec iov[1]; struct msghdr msg; char cbuf[sizeof(struct in_pktinfo) #if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO) | sizeof(struct in6_pktinfo) /* (a|b) is poor man's max(a,b) */ #endif ]; struct cmsghdr* cmsgptr; if (from->sa_family != AF_INET #if ENABLE_FEATURE_IPV6 && from->sa_family != AF_INET6 #endif ) { /* ANY local address */ return sendto(fd, buf, len, flags, to, tolen); } /* man recvmsg and man cmsg is needed to make sense of code below */ iov[0].iov_base = buf; iov[0].iov_len = len; memset(cbuf, 0, sizeof(cbuf)); memset(&msg, 0, sizeof(msg)); msg.msg_name = (void *)(struct sockaddr *)to; /* or compiler will annoy us */ msg.msg_namelen = tolen; msg.msg_iov = iov; msg.msg_iovlen = 1; msg.msg_control = cbuf; msg.msg_controllen = sizeof(cbuf); msg.msg_flags = flags; cmsgptr = CMSG_FIRSTHDR(&msg); if (to->sa_family == AF_INET && from->sa_family == AF_INET) { struct in_pktinfo *pktptr; cmsgptr->cmsg_level = IPPROTO_IP; cmsgptr->cmsg_type = IP_PKTINFO; cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)); pktptr = (struct in_pktinfo *)(CMSG_DATA(cmsgptr)); /* pktptr->ipi_ifindex = 0; -- already done by memset(cbuf...) */ pktptr->ipi_spec_dst = ((struct sockaddr_in*)from)->sin_addr; } #if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO) else if (to->sa_family == AF_INET6 && from->sa_family == AF_INET6) { struct in6_pktinfo *pktptr; cmsgptr->cmsg_level = IPPROTO_IPV6; cmsgptr->cmsg_type = IPV6_PKTINFO; cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); pktptr = (struct in6_pktinfo *)(CMSG_DATA(cmsgptr)); /* pktptr->ipi6_ifindex = 0; -- already done by memset(cbuf...) */ pktptr->ipi6_addr = ((struct sockaddr_in6*)from)->sin6_addr; } #endif return sendmsg(fd, &msg, flags); #endif }
/* Returns zero on success, less than zero on socket error and greater than * zero on other errors. */ static int conn_read_netlink (void) { int fd; struct sockaddr_nl nladdr; struct nlreq req; struct msghdr msg; struct iovec iov; struct inet_diag_msg *r; char buf[8192]; /* If this fails, it's likely a permission problem. We'll fall back to * reading this information from files below. */ fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_INET_DIAG); if (fd < 0) { ERROR ("tcpconns plugin: conn_read_netlink: socket(AF_NETLINK, SOCK_RAW, " "NETLINK_INET_DIAG) failed: %s", sstrerror (errno, buf, sizeof (buf))); return (-1); } memset(&nladdr, 0, sizeof(nladdr)); nladdr.nl_family = AF_NETLINK; memset(&req, 0, sizeof(req)); req.nlh.nlmsg_len = sizeof(req); req.nlh.nlmsg_type = TCPDIAG_GETSOCK; /* NLM_F_ROOT: return the complete table instead of a single entry. * NLM_F_MATCH: return all entries matching criteria (not implemented) * NLM_F_REQUEST: must be set on all request messages */ req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST; req.nlh.nlmsg_pid = 0; /* The sequence_number is used to track our messages. Since netlink is not * reliable, we don't want to end up with a corrupt or incomplete old * message in case the system is/was out of memory. */ req.nlh.nlmsg_seq = ++sequence_number; req.r.idiag_family = AF_INET; req.r.idiag_states = 0xfff; req.r.idiag_ext = 0; memset(&iov, 0, sizeof(iov)); iov.iov_base = &req; iov.iov_len = sizeof(req); memset(&msg, 0, sizeof(msg)); msg.msg_name = (void*)&nladdr; msg.msg_namelen = sizeof(nladdr); msg.msg_iov = &iov; msg.msg_iovlen = 1; if (sendmsg (fd, &msg, 0) < 0) { ERROR ("tcpconns plugin: conn_read_netlink: sendmsg(2) failed: %s", sstrerror (errno, buf, sizeof (buf))); close (fd); return (-1); } iov.iov_base = buf; iov.iov_len = sizeof(buf); while (1) { int status; struct nlmsghdr *h; memset(&msg, 0, sizeof(msg)); msg.msg_name = (void*)&nladdr; msg.msg_namelen = sizeof(nladdr); msg.msg_iov = &iov; msg.msg_iovlen = 1; status = recvmsg(fd, (void *) &msg, /* flags = */ 0); if (status < 0) { if ((errno == EINTR) || (errno == EAGAIN)) continue; ERROR ("tcpconns plugin: conn_read_netlink: recvmsg(2) failed: %s", sstrerror (errno, buf, sizeof (buf))); close (fd); return (-1); } else if (status == 0) { close (fd); DEBUG ("tcpconns plugin: conn_read_netlink: Unexpected zero-sized " "reply from netlink socket."); return (0); } h = (struct nlmsghdr*)buf; while (NLMSG_OK(h, status)) { if (h->nlmsg_seq != sequence_number) { h = NLMSG_NEXT(h, status); continue; } if (h->nlmsg_type == NLMSG_DONE) { close (fd); return (0); } else if (h->nlmsg_type == NLMSG_ERROR) { struct nlmsgerr *msg_error; msg_error = NLMSG_DATA(h); WARNING ("tcpconns plugin: conn_read_netlink: Received error %i.", msg_error->error); close (fd); return (1); } r = NLMSG_DATA(h); /* This code does not (need to) distinguish between IPv4 and IPv6. */ conn_handle_ports (ntohs(r->id.idiag_sport), ntohs(r->id.idiag_dport), r->idiag_state); h = NLMSG_NEXT(h, status); } /* while (NLMSG_OK) */ } /* while (1) */ /* Not reached because the while() loop above handles the exit condition. */ return (0); } /* int conn_read_netlink */
extern int netlink_rcv(struct nl_handler *handler, struct nlmsg *answer) { int ret; struct sockaddr_nl nladdr; struct iovec iov = { .iov_base = answer->nlmsghdr, .iov_len = answer->nlmsghdr->nlmsg_len, }; struct msghdr msg = { .msg_name = &nladdr, .msg_namelen = sizeof(nladdr), .msg_iov = &iov, .msg_iovlen = 1, }; memset(&nladdr, 0, sizeof(nladdr)); nladdr.nl_family = AF_NETLINK; nladdr.nl_pid = 0; nladdr.nl_groups = 0; again: ret = recvmsg(handler->fd, &msg, 0); if (ret < 0) { if (errno == EINTR) goto again; return -errno; } if (!ret) return 0; if (msg.msg_flags & MSG_TRUNC && ret == answer->nlmsghdr->nlmsg_len) return -EMSGSIZE; return ret; } extern int netlink_send(struct nl_handler *handler, struct nlmsg *nlmsg) { struct sockaddr_nl nladdr; struct iovec iov = { .iov_base = nlmsg->nlmsghdr, .iov_len = nlmsg->nlmsghdr->nlmsg_len, }; struct msghdr msg = { .msg_name = &nladdr, .msg_namelen = sizeof(nladdr), .msg_iov = &iov, .msg_iovlen = 1, }; int ret; memset(&nladdr, 0, sizeof(nladdr)); nladdr.nl_family = AF_NETLINK; nladdr.nl_pid = 0; nladdr.nl_groups = 0; ret = sendmsg(handler->fd, &msg, 0); if (ret < 0) return -errno; return ret; } #ifndef NLMSG_ERROR #define NLMSG_ERROR 0x2 #endif extern int netlink_transaction(struct nl_handler *handler, struct nlmsg *request, struct nlmsg *answer) { int ret; ret = netlink_send(handler, request); if (ret < 0) return ret; ret = netlink_rcv(handler, answer); if (ret < 0) return ret; if (answer->nlmsghdr->nlmsg_type == NLMSG_ERROR) { struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(answer->nlmsghdr); return err->error; } return 0; } extern int netlink_open(struct nl_handler *handler, int protocol) { socklen_t socklen; int sndbuf = 32768; int rcvbuf = 32768; memset(handler, 0, sizeof(*handler)); handler->fd = socket(AF_NETLINK, SOCK_RAW, protocol); if (handler->fd < 0) return -errno; if (setsockopt(handler->fd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf)) < 0) return -errno; if (setsockopt(handler->fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf,sizeof(rcvbuf)) < 0) return -errno; memset(&handler->local, 0, sizeof(handler->local)); handler->local.nl_family = AF_NETLINK; handler->local.nl_groups = 0; if (bind(handler->fd, (struct sockaddr*)&handler->local, sizeof(handler->local)) < 0) return -errno; socklen = sizeof(handler->local); if (getsockname(handler->fd, (struct sockaddr*)&handler->local, &socklen) < 0) return -errno; if (socklen != sizeof(handler->local)) return -EINVAL; if (handler->local.nl_family != AF_NETLINK) return -EINVAL; handler->seq = time(NULL); return 0; } extern int netlink_close(struct nl_handler *handler) { close(handler->fd); handler->fd = -1; return 0; }
bool SharedPortClient::PassSocket(Sock *sock_to_pass,char const *shared_port_id,char const *requested_by) { #ifndef HAVE_SHARED_PORT dprintf(D_ALWAYS,"SharedPortClient::PassSocket() not supported on this platform\n"); return false; #elif WIN32 if( !SharedPortIdIsValid(shared_port_id) ) { dprintf(D_ALWAYS, "ERROR: SharedPortClient: refusing to connect to shared port" "%s, because specified id is illegal! (%s)\n", requested_by, shared_port_id ); return false; } MyString pipe_name; MyString socket_dir; SharedPortEndpoint::paramDaemonSocketDir(pipe_name); pipe_name.sprintf_cat("%c%s",DIR_DELIM_CHAR,shared_port_id); MyString requested_by_buf; if( !requested_by ) { requested_by_buf.sprintf( " as requested by %s", sock_to_pass->peer_description()); requested_by = requested_by_buf.Value(); } HANDLE child_pipe; while(true) { child_pipe = CreateFile( pipe_name.Value(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); if(child_pipe != INVALID_HANDLE_VALUE) break; if(GetLastError() == ERROR_PIPE_BUSY) { if (!WaitNamedPipe(pipe_name.Value(), 20000)) { dprintf(D_ALWAYS, "ERROR: SharedPortClient: Wait for named pipe for sending socket timed out: %d\n", GetLastError()); return false; } } else { dprintf(D_ALWAYS, "ERROR: SharedPortClient: Failed to open named pipe for sending socket: %d\n", GetLastError()); return false; } } DWORD child_pid; DWORD read_bytes = 0; BOOL read_result = ReadFile(child_pipe, &child_pid, sizeof(DWORD), &read_bytes, NULL); if(!read_result) { DWORD last_error = GetLastError(); dprintf(D_ALWAYS, "ERROR: SharedPortClient: Failed to read PID from pipe: %d.\n", last_error); CloseHandle(child_pipe); return false; } else { dprintf(D_FULLDEBUG, "SharedPortClient: Read PID: %d\n", child_pid); } #if 1 // tj:2012 kill the else block later #pragma pack(push, 4) struct { int id; // condor commmand id WSAPROTOCOL_INFO wsa; // payload. } protocol_command; #pragma pack(pop) ZeroMemory(&protocol_command, sizeof(protocol_command)); int dup_result = WSADuplicateSocket(sock_to_pass->get_file_desc(), child_pid, &protocol_command.wsa); if(dup_result == SOCKET_ERROR) { dprintf(D_ALWAYS, "ERROR: SharedPortClient: Failed to duplicate socket.\n"); CloseHandle(child_pipe); return false; } protocol_command.id = SHARED_PORT_PASS_SOCK; BOOL write_result = WriteFile(child_pipe, &protocol_command, sizeof(protocol_command), &read_bytes, 0); #else WSAPROTOCOL_INFO protocol_info; int dup_result = WSADuplicateSocket(sock_to_pass->get_file_desc(), child_pid, &protocol_info); if(dup_result == SOCKET_ERROR) { dprintf(D_ALWAYS, "ERROR: SharedPortClient: Failed to duplicate socket.\n"); CloseHandle(child_pipe); return false; } int bufferSize = (sizeof(int) + sizeof(protocol_info)); char *buffer = new char[bufferSize]; ASSERT( buffer ); int cmd = SHARED_PORT_PASS_SOCK; memcpy_s(buffer, sizeof(int), &cmd, sizeof(int)); memcpy_s(buffer+sizeof(int), sizeof(protocol_info), &protocol_info, sizeof(protocol_info)); BOOL write_result = WriteFile(child_pipe, buffer, bufferSize, &read_bytes, 0); delete [] buffer; #endif if(!write_result) { dprintf(D_ALWAYS, "ERROR: SharedPortClient: Failed to send WSAPROTOCOL_INFO struct: %d\n", GetLastError()); CloseHandle(child_pipe); return false; } dprintf(D_FULLDEBUG, "SharedPortClient: Wrote %d bytes to named pipe.\n", read_bytes); FlushFileBuffers(child_pipe); CloseHandle(child_pipe); return true; #elif HAVE_SCM_RIGHTS_PASSFD if( !SharedPortIdIsValid(shared_port_id) ) { dprintf(D_ALWAYS, "ERROR: SharedPortClient: refusing to connect to shared port" "%s, because specified id is illegal! (%s)\n", requested_by, shared_port_id ); return false; } MyString sock_name; MyString socket_dir; SharedPortEndpoint::paramDaemonSocketDir(sock_name); sock_name.sprintf_cat("%c%s",DIR_DELIM_CHAR,shared_port_id); MyString requested_by_buf; if( !requested_by ) { requested_by_buf.sprintf( " as requested by %s", sock_to_pass->peer_description()); requested_by = requested_by_buf.Value(); } struct sockaddr_un named_sock_addr; memset(&named_sock_addr, 0, sizeof(named_sock_addr)); named_sock_addr.sun_family = AF_UNIX; strncpy(named_sock_addr.sun_path,sock_name.Value(),sizeof(named_sock_addr.sun_path)-1); if( strcmp(named_sock_addr.sun_path,sock_name.Value()) ) { dprintf(D_ALWAYS,"ERROR: SharedPortClient: full socket name%s is too long: %s\n", requested_by, sock_name.Value()); return false; } int named_sock_fd = socket(AF_UNIX,SOCK_STREAM,0); if( named_sock_fd == -1 ) { dprintf(D_ALWAYS,"ERROR: SharedPortClient: failed to created named socket%s to connect to %s: %s\n", requested_by, shared_port_id, strerror(errno)); return false; } ReliSock named_sock; named_sock.assign(named_sock_fd); named_sock.set_deadline( sock_to_pass->get_deadline() ); priv_state orig_priv = set_root_priv(); int connect_rc = connect(named_sock_fd,(struct sockaddr *)&named_sock_addr, SUN_LEN(&named_sock_addr)); set_priv( orig_priv ); if( connect_rc != 0 ) { dprintf(D_ALWAYS,"SharedPortClient: failed to connect to %s%s: %s\n", sock_name.Value(), requested_by, strerror(errno)); return false; } // Make certain SO_LINGER is Off. This will result in the default // of closesocket returning immediately and the system attempts to // send any unsent data. struct linger linger = {0,0}; setsockopt(named_sock_fd, SOL_SOCKET, SO_LINGER, (char*)&linger, sizeof(linger)); // Now prepare to pass the file descriptor // to the target process via named_sock. // First tell the target daemon that we are about to send the fd. named_sock.encode(); if( !named_sock.put((int)SHARED_PORT_PASS_SOCK) || !named_sock.end_of_message() ) { dprintf(D_ALWAYS,"SharedPortClient: failed to send SHARED_PORT_PASS_FD to %s%s: %s\n", sock_name.Value(), requested_by, strerror(errno)); return false; } // Now send the fd. // The documented way to initialize msghdr is to first set msg_controllen // to the size of the cmsghdr buffer and then after initializing // cmsghdr(s) to set it to the sum of CMSG_LEN() across all cmsghdrs. struct msghdr msg; char *buf = (char *) malloc(CMSG_SPACE(sizeof(int))); msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_control = buf; msg.msg_controllen = CMSG_SPACE(sizeof(int)); msg.msg_flags = 0; // I have found that on MacOS X 10.5, we must send at least 1 byte, // or we get "Message too long" when trying to send 0-byte message. struct iovec iov[1]; int junk = 0; iov[0].iov_base = &junk; iov[0].iov_len = 1; msg.msg_iov = iov; msg.msg_iovlen = 1; struct cmsghdr *cmsg = CMSG_FIRSTHDR((&msg)); void *cmsg_data = CMSG_DATA(cmsg); ASSERT( cmsg && cmsg_data ); cmsg->cmsg_len = CMSG_LEN(sizeof(int)); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; int fd_to_pass = sock_to_pass->get_file_desc(); memcpy(cmsg_data,&fd_to_pass,sizeof(int)); msg.msg_controllen = cmsg->cmsg_len; if( sendmsg(named_sock.get_file_desc(),&msg,0) != 1 ) { dprintf(D_ALWAYS,"SharedPortClient: failed to pass socket to %s%s: %s\n", sock_name.Value(), requested_by, strerror(errno)); free(buf); return false; } // The following final ACK appears to be necessary on Mac OS X // 10.5.8 (not sure of others). It does not appear to be // necessary on any version of linux that I have tried. The // observed problem that this solves is random failures where // the endpoint sees the passed socket close right away. It // would be nice not to have an ACK, because then the whole // PassSocket() protocol would be non-blocking. Since the // protocol is blocking with this ACK, it means we could // temporarily deadlock if the endpoint we are passing the // socket to is blocking on us on some other channel. If // this becomes a problem, we can at least make the ACK only // happen on platforms that need it. This protocol is always // just local to the machine, so need to worry about keeping // it compatible between different platforms. named_sock.decode(); int status = 0; if( !named_sock.get(status) || !named_sock.end_of_message() ) { dprintf(D_ALWAYS,"SharedPortClient: failed to receive result for SHARED_PORT_PASS_FD to %s%s: %s\n", sock_name.Value(), requested_by, strerror(errno)); free(buf); return false; } if( status != 0 ) { dprintf(D_ALWAYS,"SharedPortClient: received failure response for SHARED_PORT_PASS_FD to %s%s\n", sock_name.Value(), requested_by); free(buf); return false; } dprintf(D_FULLDEBUG,"SharedPortClient: passed socket to %s%s\n", sock_name.Value(), requested_by); free(buf); return true; #else #error HAVE_SHARED_PORT is defined, but no method for passing fds is enabled. #endif }
int main(int argc, char **argv) { struct sockaddr_un sun; char buf[1024]; int s, sunlen, ret, buflen; struct msghdr msg = { 0 }; struct iovec iov; struct cmsghdr *cmsg; int myfd = 0; char cmsgbuf[CMSG_SPACE(sizeof myfd)]; int *fdptr; if (argc != 3) { fprintf(stderr, "usage: %s testfile address\n", argv[0]); exit(-1); } myfd = open(argv[1], O_RDWR); if (myfd < 0) { perror(argv[1]); exit(-1); } s = socket(AF_UNIX, SOCK_STREAM, 0); if (s < 0) { perror("socket"); exit(-1); } sun.sun_family = AF_UNIX; strcpy(sun.sun_path, argv[2]); sunlen = strlen(sun.sun_path) + 1 + sizeof(short); ret = connect(s, (struct sockaddr *)&sun, sunlen); if (ret < 0) { perror("connect"); exit(-1); } printf("client: Connected to server via %s\n", sun.sun_path); strcpy(buf, "hello world"); buflen = strlen(buf)+1; iov.iov_base = buf; iov.iov_len = buflen; msg.msg_name = 0; msg.msg_namelen = 0; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = cmsgbuf; msg.msg_controllen = sizeof cmsgbuf; cmsg = CMSG_FIRSTHDR(&msg); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; cmsg->cmsg_len = CMSG_LEN(sizeof(int)); fdptr = (int *)CMSG_DATA(cmsg); memcpy(fdptr, &myfd, sizeof(int)); msg.msg_controllen = cmsg->cmsg_len; ret = sendmsg(s, &msg, 0); if (ret < 0) { perror("sendmsg"); exit(-1); } printf("client: Sent descriptor, waiting for reply\n"); buf[0] = 0; ret = recv(s, buf, sizeof(buf), 0); if (ret < 0) { perror("recv"); exit(-1); } printf("client: Received reply, code=%d\n", buf[0]); if (buf[0]) printf("client: ...This implies the descriptor was not received\n"); else printf("client: ...This implies the descriptor was received\n"); exit(buf[0]); }
void rauth(Job *job) { sendmsg(job, "dns: authentication not required"); }
int DL_send( channel chan, int32 address, int16 port, sys_scatter *scat ) { #ifndef ARCH_SCATTER_NONE struct msghdr msg; #else /* ARCH_SCATTER_NONE */ char pseudo_scat[MAX_PACKET_SIZE]; #endif /* ARCH_SCATTER_NONE */ struct sockaddr_in soc_addr; struct timeval select_delay = { 0, 10000 }; int ret; int total_len; int i; int num_try; char *send_errormsg = NULL; /* fool compiler */ /* Check that the scatter passed is small enough to be a valid system scatter */ assert(scat->num_elements <= ARCH_SCATTER_SIZE); memset(&soc_addr, 0, sizeof(soc_addr)); soc_addr.sin_family = AF_INET; soc_addr.sin_addr.s_addr= htonl(address); soc_addr.sin_port = htons(port); #ifdef HAVE_SIN_LEN_IN_STRUCT_SOCKADDR_IN soc_addr.sin_len = sizeof(soc_addr); #endif #ifdef ARCH_PC_HOME soc_addr.sin_addr.s_addr= htonl(-1073741814); #endif /* ARCH_PC_HOME */ #ifndef ARCH_SCATTER_NONE memset(&msg, 0, sizeof(msg)); msg.msg_name = (caddr_t) &soc_addr; msg.msg_namelen = sizeof(soc_addr); msg.msg_iov = (struct iovec *)scat->elements; msg.msg_iovlen = scat->num_elements; #endif /* ARCH_SCATTER_NONE */ #ifdef ARCH_SCATTER_CONTROL msg.msg_controllen = 0; #endif /* ARCH_SCATTER_CONTROL */ #ifdef ARCH_SCATTER_ACCRIGHTS msg.msg_accrightslen = 0; #endif /* ARCH_SCATTER_ACCRIGHTS */ for( i=0, total_len=0; i < scat->num_elements; i++) { #ifdef ARCH_SCATTER_NONE memcpy( &pseudo_scat[total_len], scat->elements[i].buf, scat->elements[i].len ); #endif /* ARCH_SCATTER_NONE */ total_len+=scat->elements[i].len; } #if 0 #ifndef ARCH_SCATTER_NONE if( msg.msg_iovlen > 16) { Alarm(EXIT, "Too Big iovec of size %d\n", msg.msg_iovlen); } #endif #endif for( ret=-10, num_try=0; ret < 0 && num_try < 10; num_try++ ) { #ifndef ARCH_SCATTER_NONE ret = sendmsg(chan, &msg, 0); #else /* ARCH_SCATTER_NONE */ ret = sendto(chan, pseudo_scat, total_len, 0, (struct sockaddr *)&soc_addr, sizeof(soc_addr) ); #endif /* ARCH_SCATTER_NONE */ if(ret < 0) { /* delay for a short while */ send_errormsg = sock_strerror(sock_errno); Alarm( DATA_LINK, "DL_send: delaying after failure in send to " IPF ", ret is %d\n", IP(address), ret); select( 0, 0, 0, 0, &select_delay ); select_delay.tv_sec = 0; select_delay.tv_usec = 10000; } } if (ret < 0) { for( i=0; i < scat->num_elements; i++) Alarm( DATA_LINK, "DL_send: element[%d]: %d bytes\n", i,scat->elements[i].len); Alarm( DATA_LINK, "DL_send: error: %s\n sending %d bytes on channel %d to address " IPF "\n", send_errormsg, total_len,chan,IP(address) ); }else if(ret < total_len){ Alarm( DATA_LINK, "DL_send: partial sending %d out of %d\n", ret,total_len); } Alarm( DATA_LINK, "DL_send: sent a message of %d bytes to (" IPF ":%d) on channel %d\n", ret,IP(address),port,chan); return(ret); }
/* * don't flush till all the slaves are done */ void rflush(Job *job) { flushjob(job->request.oldtag); sendmsg(job, 0); }
int main(int argc, char *argv[]) { int data, sfd, opt, fd; ssize_t ns; Boolean useDatagramSocket; struct msghdr msgh; struct iovec iov; /* Allocate a char array of suitable size to hold the ancillary data. However, since this buffer is in reality a 'struct cmsghdr', use a union to ensure that it is aligned as required for that structure. Alternatively, we could allocate the buffer using malloc(), which returns a buffer that satisfies the strictest alignment requirements of any type. */ union { char buf[CMSG_SPACE(sizeof(int))]; /* Space large enough to hold an 'int' */ struct cmsghdr align; } controlMsg; struct cmsghdr *cmsgp; /* Pointer used to iterate through headers in ancillary data */ /* Parse command-line options */ useDatagramSocket = FALSE; while ((opt = getopt(argc, argv, "d")) != -1) { switch (opt) { case 'd': useDatagramSocket = TRUE; break; default: usageErr("%s [-d] file\n" " -d use datagram socket\n", argv[0]); } } if (argc != optind + 1) usageErr("%s [-d] file\n", argv[0]); /* Open the file named on the command line */ fd = open(argv[optind], O_RDONLY); if (fd == -1) errExit("open"); /* The 'msg_name' field can be used to specify the address of the destination socket when sending a datagram. However, we do not need to use this field because we use connect() below, which sets a default outgoing address for datagrams. */ msgh.msg_name = NULL; msgh.msg_namelen = 0; /* On Linux, we must transmit at least 1 byte of real data in order to send ancillary data */ msgh.msg_iov = &iov; msgh.msg_iovlen = 1; iov.iov_base = &data; iov.iov_len = sizeof(int); data = 12345; fprintf(stderr, "Sending data = %d\n", data); /* Set 'msgh' fields to describe the ancillary data buffer */ msgh.msg_control = controlMsg.buf; msgh.msg_controllen = sizeof(controlMsg.buf); /* The control message buffer must be zero-initialized in order for the CMSG_NXTHDR() macro to work correctly. Although we don't need to use CMSG_NXTHDR() in this example (because there is only one block of ancillary data), we show this step to demonstrate best practice */ memset(controlMsg.buf, 0, sizeof(controlMsg.buf)); /* Set message header to describe the ancillary data that we want to send */ cmsgp = CMSG_FIRSTHDR(&msgh); cmsgp->cmsg_len = CMSG_LEN(sizeof(int)); cmsgp->cmsg_level = SOL_SOCKET; cmsgp->cmsg_type = SCM_RIGHTS; *((int *) CMSG_DATA(cmsgp)) = fd; /* Connect to the peer socket */ sfd = unixConnect(SOCK_PATH, useDatagramSocket ? SOCK_DGRAM : SOCK_STREAM); if (sfd == -1) errExit("unixConnect"); fprintf(stderr, "Sending FD %d\n", fd); /* Send real plus ancillary data */ ns = sendmsg(sfd, &msgh, 0); if (ns == -1) errExit("sendmsg"); fprintf(stderr, "sendmsg() returned %ld\n", (long) ns); exit(EXIT_SUCCESS); }
void rcreate(Job *job, Mfile *mf) { USED(mf); sendmsg(job, "creation permission denied"); }
static void connect_try_next(struct dropbear_progress_connection *c) { struct addrinfo *r; int res = 0; int fastopen = 0; #ifdef DROPBEAR_CLIENT_TCP_FAST_OPEN struct msghdr message; #endif for (r = c->res_iter; r; r = r->ai_next) { dropbear_assert(c->sock == -1); c->sock = socket(c->res_iter->ai_family, c->res_iter->ai_socktype, c->res_iter->ai_protocol); if (c->sock < 0) { continue; } ses.maxfd = MAX(ses.maxfd, c->sock); set_sock_nodelay(c->sock); setnonblocking(c->sock); #ifdef DROPBEAR_CLIENT_TCP_FAST_OPEN fastopen = (c->writequeue != NULL); if (fastopen) { memset(&message, 0x0, sizeof(message)); message.msg_name = r->ai_addr; message.msg_namelen = r->ai_addrlen; /* 6 is arbitrary, enough to hold initial packets */ unsigned int iovlen = 6; /* Linux msg_iovlen is a size_t */ struct iovec iov[6]; packet_queue_to_iovec(c->writequeue, iov, &iovlen); message.msg_iov = iov; message.msg_iovlen = iovlen; res = sendmsg(c->sock, &message, MSG_FASTOPEN); /* Returns EINPROGRESS if FASTOPEN wasn't available */ if (res < 0) { if (errno != EINPROGRESS) { m_free(c->errstring); c->errstring = m_strdup(strerror(errno)); /* Not entirely sure which kind of errors are normal - 2.6.32 seems to return EPIPE for any (nonblocking?) sendmsg(). just fall back */ TRACE(("sendmsg tcp_fastopen failed, falling back. %s", strerror(errno))); /* No kernel MSG_FASTOPEN support. Fall back below */ fastopen = 0; /* Set to NULL to avoid trying again */ c->writequeue = NULL; } } else { packet_queue_consume(c->writequeue, res); } } #endif /* Normal connect(), used as fallback for TCP fastopen too */ if (!fastopen) { res = connect(c->sock, r->ai_addr, r->ai_addrlen); } if (res < 0 && errno != EINPROGRESS) { /* failure */ m_free(c->errstring); c->errstring = m_strdup(strerror(errno)); close(c->sock); c->sock = -1; continue; } else { /* new connection was successful, wait for it to complete */ break; } } if (r) { c->res_iter = r->ai_next; } else { c->res_iter = NULL; } }
void rwrite(Job *job, Mfile *mf, Request *req) { int rooted, wantsav, send; ulong cnt; char *err, *p, *atype; char errbuf[ERRMAX]; err = nil; cnt = job->request.count; send = 1; if(mf->qid.type & QTDIR) err = "can't write directory"; else if (job->request.offset != 0) err = "writing at non-zero offset"; else if(cnt >= Maxrequest) err = "request too long"; else send = 0; if (send) goto send; job->request.data[cnt] = 0; if(cnt > 0 && job->request.data[cnt-1] == '\n') job->request.data[cnt-1] = 0; /* * special commands */ // dnslog("rwrite got: %s", job->request.data); send = 1; if(strcmp(job->request.data, "age")==0){ dnslog("dump, age & dump forced"); dndump("/lib/ndb/dnsdump1"); dnforceage(); dndump("/lib/ndb/dnsdump2"); } else if(strcmp(job->request.data, "debug")==0) debug ^= 1; else if(strcmp(job->request.data, "dump")==0) dndump("/lib/ndb/dnsdump"); else if(strcmp(job->request.data, "poolcheck")==0) poolcheck(mainmem); else if(strcmp(job->request.data, "refresh")==0) needrefresh = 1; else if(strcmp(job->request.data, "restart")==0) stop = 1; else if(strcmp(job->request.data, "stats")==0) dnstats("/lib/ndb/dnsstats"); else if(strncmp(job->request.data, "target ", 7)==0){ target = atol(job->request.data + 7); dnslog("target set to %ld", target); } else send = 0; if (send) goto send; /* * kill previous reply */ mf->nrr = 0; mf->rr[0] = 0; /* * break up request (into a name and a type) */ atype = strchr(job->request.data, ' '); if(atype == 0){ snprint(errbuf, sizeof errbuf, "illegal request %s", job->request.data); err = errbuf; goto send; } else *atype++ = 0; /* * tracing request */ if(strcmp(atype, "trace") == 0){ if(trace) free(trace); if(*job->request.data) trace = estrdup(job->request.data); else trace = 0; goto send; } /* normal request: domain [type] */ stats.qrecvd9p++; mf->type = rrtype(atype); if(mf->type < 0){ snprint(errbuf, sizeof errbuf, "unknown type %s", atype); err = errbuf; goto send; } p = atype - 2; if(p >= job->request.data && *p == '.'){ rooted = 1; *p = 0; } else rooted = 0; p = job->request.data; if(*p == '!'){ wantsav = 1; p++; } else wantsav = 0; err = lookupqueryold(job, mf, req, errbuf, p, wantsav, rooted); send: dncheck(0, 1); job->reply.count = cnt; sendmsg(job, err); }
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]; #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 /* * 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 iov and msgh structures. */ memset(&msgh, 0, sizeof(struct msghdr)); 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); }
void rclunk(Job *job, Mfile *mf) { freefid(mf); sendmsg(job, 0); }
void test_msg_dgram(const struct socket_test_info *info) { int rc; int src; int dst; struct sockaddr_storage addr; struct iovec iov[3]; struct msghdr msg1; struct msghdr msg2; char buf1[BUFSIZE]; char buf2[BUFSIZE]; char buf3[BUFSIZE]; debug("entering test_msg_dgram"); info->callback_cleanup(); src = socket(info->domain, SOCK_DGRAM, 0); if (src == -1) { test_fail("socket"); } dst = socket(info->domain, SOCK_DGRAM, 0); if (dst == -1) { test_fail("socket"); } rc = bind(src, info->serveraddr2, info->serveraddr2len); if (rc == -1) { test_fail("bind"); } assert(info->clientaddrlen <= sizeof(addr)); memcpy(&addr, info->clientaddr, info->clientaddrlen); rc = bind(dst, info->serveraddr, info->serveraddrlen); if (rc == -1) { test_fail("bind"); } memset(&buf1, '\0', BUFSIZE); memset(&buf2, '\0', BUFSIZE); memset(&buf3, '\0', BUFSIZE); strncpy(buf1, "Minix ", BUFSIZE-1); strncpy(buf2, "is ", BUFSIZE-1); strncpy(buf3, "great!", BUFSIZE-1); iov[0].iov_base = buf1; iov[0].iov_len = 6; iov[1].iov_base = buf2; iov[1].iov_len = 3; iov[2].iov_base = buf3; iov[2].iov_len = 32; memset(&msg1, '\0', sizeof(struct msghdr)); msg1.msg_name = &addr; msg1.msg_namelen = info->clientaddrlen; msg1.msg_iov = iov; msg1.msg_iovlen = 3; msg1.msg_control = NULL; msg1.msg_controllen = 0; msg1.msg_flags = 0; rc = sendmsg(src, &msg1, 0); if (rc == -1) { test_fail("sendmsg"); } memset(&buf1, '\0', BUFSIZE); memset(&buf2, '\0', BUFSIZE); iov[0].iov_base = buf1; iov[0].iov_len = 9; iov[1].iov_base = buf2; iov[1].iov_len = 32; memset(&addr, '\0', sizeof(addr)); memset(&msg2, '\0', sizeof(struct msghdr)); msg2.msg_name = &addr; msg2.msg_namelen = sizeof(addr); msg2.msg_iov = iov; msg2.msg_iovlen = 2; msg2.msg_control = NULL; msg2.msg_controllen = 0; msg2.msg_flags = 0; rc = recvmsg(dst, &msg2, 0); if (rc == -1) { test_fail("recvmsg"); } if (strncmp(buf1, "Minix is ", 9) || strncmp(buf2, "great!", 6)) { test_fail("recvmsg"); } info->callback_check_sockaddr((struct sockaddr *) &addr, msg2.msg_namelen, "recvmsg", 2); rc = close(dst); if (rc == -1) { test_fail("close"); } rc = close(src); if (rc == -1) { test_fail("close"); } info->callback_cleanup(); debug("leaving test_msg_dgram"); }
void rremove(Job *job, Mfile *mf) { USED(mf); sendmsg(job, "remove permission denied"); }
ngx_int_t ngx_write_channel(ngx_socket_t s, ngx_channel_t *ch, size_t size, ngx_log_t *log) { ssize_t n; ngx_err_t err; struct iovec iov[1]; struct msghdr msg; #if (NGX_HAVE_MSGHDR_MSG_CONTROL) union { struct cmsghdr cm; char space[CMSG_SPACE(sizeof(int))]; } cmsg; if (ch->fd == -1) { msg.msg_control = NULL; msg.msg_controllen = 0; } else { msg.msg_control = (caddr_t) &cmsg; msg.msg_controllen = sizeof(cmsg); cmsg.cm.cmsg_len = CMSG_LEN(sizeof(int)); cmsg.cm.cmsg_level = SOL_SOCKET; cmsg.cm.cmsg_type = SCM_RIGHTS; /* * We have to use ngx_memcpy() instead of simple * *(int *) CMSG_DATA(&cmsg.cm) = ch->fd; * because some gcc 4.4 with -O2/3/s optimization issues the warning: * dereferencing type-punned pointer will break strict-aliasing rules * * Fortunately, gcc with -O1 compiles this ngx_memcpy() * in the same simple assignment as in the code above */ ngx_memcpy(CMSG_DATA(&cmsg.cm), &ch->fd, sizeof(int)); } msg.msg_flags = 0; #else if (ch->fd == -1) { msg.msg_accrights = NULL; msg.msg_accrightslen = 0; } else { msg.msg_accrights = (caddr_t) &ch->fd; msg.msg_accrightslen = sizeof(int); } #endif iov[0].iov_base = (char *) ch; iov[0].iov_len = size; msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_iov = iov; msg.msg_iovlen = 1; n = sendmsg(s, &msg, 0); if (n == -1) { err = ngx_errno; if (err == NGX_EAGAIN) { return NGX_AGAIN; } ngx_log_error(NGX_LOG_ALERT, log, err, "sendmsg() failed"); return NGX_ERROR; } return NGX_OK; }
void rwstat(Job *job, Mfile *mf) { USED(mf); sendmsg(job, "wstat permission denied"); }
int main (int argc, char *argv[]) { int i, sd, hoplimit = 255; uint16_t seq = 0; // IPv6 address struct sockaddr_in6 src = { AF_INET6, 0, 0, 0, 0 }; struct sockaddr_in6 dst = { AF_INET6, 0, 0, 0, 0 }; char hostname[INET6_ADDRSTRLEN]; char addr6[INET6_ADDRSTRLEN]; // ICMPv6 na header struct nd_neighbor_advert na; // ICMPv6 na header option uint8_t option[8]; // Ancillary data struct msghdr msghdr; struct cmsghdr *cmsghdr; struct iovec iov[2]; char cmsghdr_buf[CMSG_SPACE (sizeof (hoplimit))]; // Interface struct ifreq ifr; // interface address struct ifaddrs * ifaddrs = NULL; struct ifaddrs * ifaddr = NULL; // Usage. if (argc < 3) { printf ("Usage: %s <interface> <adddress>\n", argv[0]); exit (EXIT_SUCCESS); } // Create a socket to look up interface. if ((sd = socket (AF_INET6, SOCK_RAW, IPPROTO_IPV6)) < 0) { perror ("socket() "); exit (EXIT_FAILURE); } // Use getifaddrs() to find interface address, ioctl() with SIOCGIFADDR is not work for IPv6. // Get interface address list. getifaddrs (&ifaddrs); // Get all interface and ip address. for (ifaddr = ifaddrs; ifaddr != NULL; ifaddr = ifaddr->ifa_next) { // IPv6 if (ifaddr->ifa_addr->sa_family == AF_INET6) { struct sockaddr_in6 *addr = (struct sockaddr_in6 *)ifaddr->ifa_addr; inet_ntop(AF_INET6, &addr->sin6_addr, addr6, INET6_ADDRSTRLEN); if (strcmp (argv[1], ifaddr->ifa_name) == 0) { src.sin6_addr = addr->sin6_addr; printf("The interface %s address is %s\n", ifaddr->ifa_name, addr6); } } } // Free the list. if (ifaddrs != NULL) freeifaddrs(ifaddrs); // Use ioctl() to find hardware address. memset (&ifr, 0, sizeof(struct ifreq)); snprintf (ifr.ifr_name, sizeof(ifr.ifr_name), "%s", argv[1]); if (ioctl (sd, SIOCGIFHWADDR, &ifr) < 0) { perror ("ioctl() failed to find hardware address "); return (EXIT_FAILURE); } // Set the ICMPv6 ns header option. option[0] = 1; // Option Type - "source link layer address" (Section 4.6 of RFC 4861) option[1] = 8 / 8; // Option Length - units of 8 octets (RFC 4861) for (i=0; i<6; i++) { option[i+2] = (uint8_t) ifr.ifr_hwaddr.sa_data[i]; } printf ("Hardware address is %02X:%02X:%02X:%02X:%02X:%02X\n", option[2], option[3], option[4], option[5], option[6], option[7]); // Use ioctl() to find interface index. memset (&ifr, 0, sizeof(struct ifreq)); snprintf (ifr.ifr_name, sizeof(ifr.ifr_name), "%s", argv[1]); if (ioctl (sd, SIOCGIFINDEX, &ifr) < 0) { perror ("ioctl() failed to find interface "); return (EXIT_FAILURE); } printf ("Index for interface %s is %i\n", argv[1], ifr.ifr_ifindex); // Close sd. close (sd); // Create a ICMPv6 raw socket. // The kernel will fill the IPv6 header automatically. if ((sd = socket (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) { perror ("socket() "); exit (EXIT_FAILURE); } // Convert the hostname to network bytes. if (inet_pton (AF_INET6, argv[2], &(dst.sin6_addr)) < 0) { perror ("inet_pton() "); exit (EXIT_FAILURE); } // Bind the interface using setsockopt() if (setsockopt (sd, SOL_SOCKET, SO_BINDTODEVICE, (void*)&ifr, sizeof(struct ifreq)) < 0) { perror ("setsockopt() failed to bind interface "); return (EXIT_FAILURE); } // Send ICMPv6 neighbor advertisement. // 1. Construct ICMPv6 header and payload. memset (&na, 0, sizeof(na)); // Set header type. na.nd_na_hdr.icmp6_type = ND_NEIGHBOR_ADVERT; // 136 (RFC 4861) // Code is 0 for ns. na.nd_na_hdr.icmp6_code = 0; // When you create a ICMPv6 raw socket, the kernel will calculate and // insert the ICMPv6 checksum automatically. na.nd_na_hdr.icmp6_cksum = htons (0); // Set R/S/O flags as: R(router)=0, S(Solicited)=1, O(override)=1. na.nd_na_flags_reserved = htonl ((1 << 30) + (1 << 29)); na.nd_na_target = src.sin6_addr; // Target address (as type in6_addr) // 2. Assign msghdr's field "msg_name" to destination address. memset (&msghdr, 0, sizeof (msghdr)); msghdr.msg_name = &dst; msghdr.msg_namelen = sizeof (dst); // 3. Assign the packet to the io vector. iov[0].iov_base = &na; iov[0].iov_len = sizeof (struct nd_neighbor_advert); iov[1].iov_base = &option; iov[1].iov_len = sizeof (option); msghdr.msg_iov = iov; msghdr.msg_iovlen = 2; // 4. Set the TTL in cmsghdr. memset (&cmsghdr_buf, 0, sizeof (cmsghdr_buf)); msghdr.msg_control = cmsghdr_buf; msghdr.msg_controllen = sizeof (cmsghdr_buf); // Set the time-to-live value 255. cmsghdr = CMSG_FIRSTHDR (&msghdr); cmsghdr->cmsg_level = IPPROTO_IPV6; cmsghdr->cmsg_type = IPV6_HOPLIMIT; cmsghdr->cmsg_len = CMSG_LEN (sizeof (hoplimit)); *(int *)CMSG_DATA (cmsghdr) = hoplimit; // 5. Send the message. if (sendmsg (sd, &msghdr, 0) <= 0) { perror ("sendmsg() "); exit (EXIT_FAILURE); } // Close sd. close (sd); // Use "tcpdump -nnvvvXS -i eth1 -s0 icmp6" to check neighbor advertisement progress. }
/* * Simulate a blocking sendmsg on the non-blocking socket. * It's non blocking because it was set that way for recvmsg. */ int rxi_Sendmsg(osi_socket socket, struct msghdr *msg_p, int flags) { fd_set *sfds = (fd_set *) 0; while (sendmsg(socket, msg_p, flags) == -1) { int err; if (rx_stats_active) rx_atomic_inc(&rx_stats.sendSelects); if (!sfds) { if (!(sfds = IOMGR_AllocFDSet())) { (osi_Msg "rx failed to alloc fd_set: "); perror("rx_sendmsg"); return -1; } FD_SET(socket, sfds); } #if defined(HAVE_LINUX_ERRQUEUE_H) && defined(ADAPT_PMTU) while((rxi_HandleSocketError(socket)) > 0) ; #endif #ifdef AFS_NT40_ENV if (WSAGetLastError()) #elif defined(AFS_LINUX22_ENV) /* linux unfortunately returns ECONNREFUSED if the target port * is no longer in use */ /* and EAGAIN if a UDP checksum is incorrect */ if (errno != EWOULDBLOCK && errno != ENOBUFS && errno != ECONNREFUSED && errno != EAGAIN) #else if (errno != EWOULDBLOCK && errno != ENOBUFS) #endif { (osi_Msg "rx failed to send packet: "); perror("rx_sendmsg"); #ifndef AFS_NT40_ENV if (errno > 0) return -errno; #else if (WSAGetLastError() > 0) return -WSAGetLastError(); #endif return -1; } while ((err = select( #ifdef AFS_NT40_ENV 0, #else socket + 1, #endif 0, sfds, 0, 0)) != 1) { if (err >= 0 || errno != EINTR) osi_Panic("rxi_sendmsg: select error %d.%d", err, errno); FD_ZERO(sfds); FD_SET(socket, sfds); } } if (sfds) IOMGR_FreeFDSet(sfds); return 0; }