/* cf_socket_send * Send to a socket */ int cf_socket_send(int sock, void *buf, size_t buflen, int flags) { int i; flags |= MSG_NOSIGNAL; if (0 >= (i = send(sock, buf, buflen, flags))) { cf_debug(CF_SOCKET, "send() failed: %d %s", errno, cf_strerror(errno)); } return(i); }
int cf_ipaddr_get(int socket, char *nic_id, char **node_ip ) { struct sockaddr_in sin; struct ifreq ifr; in_addr_t ip_addr; memset(&ip_addr, 0, sizeof(in_addr_t)); memset(&sin, 0, sizeof(struct sockaddr)); memset(&ifr, 0, sizeof(ifr)); // copy the nic name (eth0, eth1, eth2, etc.) ifr variable structure strncpy(ifr.ifr_name, nic_id, IFNAMSIZ); // get the ifindex for the adapter... if (ioctl(socket, SIOCGIFINDEX, &ifr) < 0) { cf_debug(CF_MISC, "Can't get ifindex for adapter %s - %d %s\n", nic_id, errno, cf_strerror(errno)); return(-1); } // get the IP address memset(&sin, 0, sizeof(struct sockaddr)); memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, nic_id, IFNAMSIZ); ifr.ifr_addr.sa_family = AF_INET; if (ioctl(socket, SIOCGIFADDR, &ifr)< 0) { cf_debug(CF_MISC, "can't get IP address: %d %s", errno, cf_strerror(errno)); return(-1); } memcpy(&sin, &ifr.ifr_addr, sizeof(struct sockaddr)); ip_addr = sin.sin_addr.s_addr; char cpaddr[24]; if (NULL == inet_ntop(AF_INET, &ip_addr, (char *)cpaddr, sizeof(cpaddr))) { cf_warning(CF_MISC, "received suspicious address %s : %s", cpaddr, cf_strerror(errno)); return(-1); } cf_info (CF_MISC, "Node ip: %s", cpaddr); *node_ip = cf_strdup(cpaddr); return(0); }
void cf_process_privsep(uid_t uid, gid_t gid) { if (0 != getuid() || (uid == getuid() && gid == getgid())) { return; } // Drop all auxiliary groups. if (0 > setgroups(0, (const gid_t *)0)) { cf_crash(CF_MISC, "setgroups: %s", cf_strerror(errno)); } // Change privileges. if (0 > setgid(gid)) { cf_crash(CF_MISC, "setgid: %s", cf_strerror(errno)); } if (0 > setuid(uid)) { cf_crash(CF_MISC, "setuid: %s", cf_strerror(errno)); } }
static void validate_directory(const char *path, const char *log_tag) { struct stat buf; if (stat(path, &buf) != 0) { cf_crash_nostack(AS_AS, "%s directory '%s' is not set up properly: %s", log_tag, path, cf_strerror(errno)); } else if (! S_ISDIR(buf.st_mode)) { cf_crash_nostack(AS_AS, "%s directory '%s' is not set up properly: Not a directory", log_tag, path); } }
/* cf_socket_set_nonblocking * Set a socket to nonblocking mode */ int cf_socket_set_nonblocking(int s) { int flags; if (-1 == (flags = fcntl(s, F_GETFL, 0))) flags = 0; if (-1 == fcntl(s, F_SETFL, flags | O_NONBLOCK)) { cf_crash(CF_SOCKET, "fcntl(): %s", cf_strerror(errno)); return(0); } return(1); }
/* cf_socket_set_nonblocking * Set a socket to nonblocking mode */ int cf_socket_set_nonblocking(int s) { int flags = 0; if (-1 == (flags = fcntl(s, F_GETFL, 0))) { cf_warning(CF_SOCKET, "fcntl(): failed to get socket %d flags - %s", s, cf_strerror(errno)); return(-1); } if (-1 == fcntl(s, F_SETFL, flags | O_NONBLOCK)) { cf_warning(CF_SOCKET, "fcntl(): failed to set socket %d O_NONBLOCK flag - %s", s, cf_strerror(errno)); return(-1); } return(0); }
/* cf_socket_send * Send to a socket */ int cf_socket_sendto(int sock, void *buf, size_t buflen, int flags, cf_sockaddr to) { int i; struct sockaddr_in s, *sp = NULL; if (to) { sp = &s; cf_sockaddr_convertfrom(to, sp); } flags |= MSG_NOSIGNAL; if (0 >= (i = sendto(sock, buf, buflen, flags, (struct sockaddr *)sp, sizeof(const struct sockaddr)))) cf_debug(CF_SOCKET, "sendto() failed: %d %s", errno, cf_strerror(errno)); return(i); }
/* cf_socket_recv * Read from a service socket */ int cf_socket_recv(int sock, void *buf, size_t buflen, int flags) { int i; flags |= MSG_NOSIGNAL; if (0 >= (i = recv(sock, buf, buflen, flags))) { if (EAGAIN == errno) return(0); else if (ECONNRESET == errno || 0 == i) cf_detail(CF_SOCKET, "socket disconnected"); else { cf_crash(CF_SOCKET, "recv() failed: %d %s", errno, cf_strerror(errno)); } } return(i); }
int udf_cask_info_remove(char *name, char * params, cf_dyn_buf * out) { char filename[128] = {0}; int filename_len = sizeof(filename); char file_path[1024] = {0}; struct stat buf; cf_debug(AS_INFO, "UDF CASK INFO REMOVE"); // get (required) script filename if ( as_info_parameter_get(params, "filename", filename, &filename_len) ) { cf_info(AS_UDF, "invalid or missing filename"); cf_dyn_buf_append_string(out, "error=invalid_filename"); } // now check if such a file-name exists : if (!g_config.mod_lua.user_path) { return -1; } snprintf(file_path, 1024, "%s/%s", g_config.mod_lua.user_path, filename); cf_debug(AS_INFO, " Lua file removal full-path is : %s \n", file_path); if (stat(file_path, &buf) != 0) { cf_info(AS_UDF, "failed to read file from : %s, error : %s", file_path, cf_strerror(errno)); cf_dyn_buf_append_string(out, "error=file_not_found"); return -1; } as_smd_delete_metadata(udf_smd_module_name, filename); // this is what an error would look like // cf_dyn_buf_append_string(out, "error="); // cf_dyn_buf_append_int(out, resp); cf_dyn_buf_append_string(out, "ok"); cf_info(AS_UDF, "UDF module '%s' (%s) removed", filename, file_path); return 0; }
void thr_demarshal_resume(as_file_handle *fd_h) { fd_h->trans_active = false; // Make the demarshal thread aware of pending connection data (if any). // Writing to an FD's event mask makes the epoll instance re-check for // data, even when edge-triggered. If there is data, the demarshal thread // gets EPOLLIN for this FD. if (epoll_ctl_modify(fd_h, EPOLLIN | EPOLLET | EPOLLRDHUP) < 0) { if (errno == ENOENT) { // Happens, when we reached NextEvent_FD_Cleanup (e.g, because the // client disconnected) while the transaction was still ongoing. return; } cf_crash(AS_DEMARSHAL, "unable to resume socket FD %d on epoll instance FD %d: %d (%s)", fd_h->fd, fd_h->epoll_fd, errno, cf_strerror(errno)); } }
/* cf_socket_recvfrom * Read from a service socket */ int cf_socket_recvfrom(int sock, void *buf, size_t buflen, int flags, cf_sockaddr *from) { int i; struct sockaddr_in f, *fp = NULL; socklen_t fl = sizeof(f); if (from) { fp = &f; f.sin_family = AF_INET; } flags |= MSG_NOSIGNAL; if (0 >= (i = recvfrom(sock, buf, buflen, flags, (struct sockaddr *)fp, &fl))) { cf_debug(CF_SOCKET, "recvfrom() failed: %d %s", errno, cf_strerror(errno)); if (from) memset(from, 0, sizeof(cf_sockaddr)); } else { if (from) cf_sockaddr_convertto(fp, from); } return(i); }
/* cf_socket_init_client * Connect a socket to a remote endpoint * DOES A BLOCKING CONNECT INLINE - timeout */ int cf_socket_init_client(cf_socket_cfg *s, int timeout) { cf_assert(s, CF_SOCKET, CF_CRITICAL, "invalid argument"); if (0 > (s->sock = socket(AF_INET, s->proto, 0))) { cf_warning(CF_SOCKET, "socket: %s", cf_strerror(errno)); return(-1); } fcntl(s->sock, F_SETFD, FD_CLOEXEC); /* close on exec */ fcntl(s->sock, F_SETFL, O_NONBLOCK); /* non-blocking */ // Try tuning the window: must be done before connect // int flag = (1024 * 32); // setsockopt(s->sock, SOL_SOCKET, SO_SNDBUF, &flag, sizeof(flag) ); // setsockopt(s->sock, SOL_SOCKET, SO_RCVBUF, &flag, sizeof(flag) ); memset(&s->saddr,0,sizeof(s->saddr)); s->saddr.sin_family = AF_INET; int rv = inet_pton(AF_INET, s->addr, &s->saddr.sin_addr.s_addr); if (rv < 0) { cf_warning(CF_SOCKET, "inet_pton: %s", cf_strerror(errno)); close(s->sock); return(-1); } else if (rv == 0) { cf_warning(CF_SOCKET, "inet_pton: invalid ip %s", s->addr); close(s->sock); return(-1); } s->saddr.sin_port = htons(s->port); rv = connect(s->sock, (struct sockaddr *)&s->saddr, sizeof(s->saddr)); cf_debug(CF_SOCKET, "connect: rv %d errno %s",rv,cf_strerror(errno)); if (rv < 0) { int epoll_fd = -1; if (errno == EINPROGRESS) { cf_clock start = cf_getms(); if (0 > (epoll_fd = epoll_create(1))) { cf_warning(CF_SOCKET, "epoll_create() failed (errno %d: \"%s\")", errno, cf_strerror(errno)); goto Fail; } struct epoll_event event; memset(&event, 0, sizeof(struct epoll_event)); event.data.fd = s->sock; event.events = EPOLLOUT; if (0 > epoll_ctl(epoll_fd, EPOLL_CTL_ADD, s->sock, &event)) { cf_warning(CF_SOCKET, "epoll_ctl(ADD) of client socket failed (errno %d: \"%s\")", errno, cf_strerror(errno)); goto Fail; } int tries = 0; do { int nevents = 0; int max_events = 1; int wait_ms = 1; struct epoll_event events[max_events]; if (0 > (nevents = epoll_wait(epoll_fd, events, max_events, wait_ms))) { if (errno == EINTR) { cf_debug(CF_SOCKET, "epoll_wait() on client socket encountered EINTR ~~ Retrying!"); goto Retry; } else { cf_warning(CF_SOCKET, "epoll_wait() on client socket failed (errno %d: \"%s\") ~~ Failing!", errno, cf_strerror(errno)); goto Fail; } } else { if (nevents == 0) { cf_debug(CF_SOCKET, "epoll_wait() returned no events ~~ Retrying!"); goto Retry; } if (nevents != 1) { cf_warning(CF_SOCKET, "epoll_wait() returned %d events ~~ only 1 expected, so ignoring others!", nevents); } if (events[0].data.fd == s->sock) { if (events[0].events & EPOLLOUT) { cf_debug(CF_SOCKET, "epoll_wait() on client socket ready for write detected ~~ Succeeding!"); } else { // (Note: ERR and HUP events are automatically waited for as well.) if (events[0].events & (EPOLLERR | EPOLLHUP)) { cf_debug(CF_SOCKET, "epoll_wait() on client socket detected failure event 0x%x ~~ Failing!", events[0].events); } else { cf_warning(CF_SOCKET, "epoll_wait() on client socket detected non-write events 0x%x ~~ Failing!", events[0].events); } goto Fail; } } else { cf_warning(CF_SOCKET, "epoll_wait() on client socket returned event on unknown socket %d ~~ Retrying!", events[0].data.fd); goto Retry; } if (0 > epoll_ctl(epoll_fd, EPOLL_CTL_DEL, s->sock, &event)) { cf_warning(CF_SOCKET, "epoll_ctl(DEL) on client socket failed (errno %d: \"%s\")", errno, cf_strerror(errno)); } close(epoll_fd); goto Success; } Retry: cf_debug(CF_SOCKET, "Connect epoll loop: Retry #%d", tries++); if (start + timeout < cf_getms()) { cf_warning(CF_SOCKET, "Error in delayed connect() to %s:%d: timed out", s->addr, s->port); errno = ETIMEDOUT; goto Fail; } } while (1); } Fail: cf_debug(CF_SOCKET, "connect failed to %s:%d : %s", s->addr, s->port, cf_strerror(errno)); if (epoll_fd > 0) { close(epoll_fd); } close(s->sock); s->sock = -1; return(-1); } else { cf_debug(CF_SOCKET, "client socket connect() to %s:%d in 1 try!", s->addr, s->port); } Success: ; // regarding this: calling here doesn't seem terribly effective. // on the fabric threads, it seems important to set no-delay much later int flag = 1; setsockopt(s->sock, SOL_TCP, TCP_NODELAY, &flag, sizeof(flag)); long farg = fcntl(s->sock, F_GETFL, 0); fcntl(s->sock, F_SETFL, farg & (~O_NONBLOCK)); /* blocking again */ return(0); }
/* cf_socket_init_svc * Initialize a socket for listening * Leaves the socket in a blocking state - if you want nonblocking, set nonblocking */ int cf_socket_init_svc(cf_socket_cfg *s) { struct timespec delay; cf_assert(s, CF_SOCKET, CF_CRITICAL, "invalid argument"); if (!s->addr) { cf_warning(CF_SOCKET, "could not initialize service, check config file"); return(-1); } if (s->port == 0) { cf_warning(CF_SOCKET, "could not initialize service, missing port, check config file"); return(-1); } delay.tv_sec = 5; delay.tv_nsec = 0; /* Create the socket */ if (0 > (s->sock = socket(AF_INET, s->proto, 0))) { cf_warning(CF_SOCKET, "socket: %s", cf_strerror(errno)); return(-1); } s->saddr.sin_family = AF_INET; if (1 != inet_pton(AF_INET, s->addr, &s->saddr.sin_addr.s_addr)) { cf_warning(CF_SOCKET, "inet_pton: %s", cf_strerror(errno)); return(-1); } s->saddr.sin_port = htons(s->port); if (s->reuse_addr) { int v = 1; setsockopt(s->sock, SOL_SOCKET, SO_REUSEADDR, &v, sizeof(v) ); } /* Set close-on-exec */ fcntl(s->sock, F_SETFD, FD_CLOEXEC); // I've tried a little tuning here, doesn't seem terribly important. // int flag = (1024 * 32); // setsockopt(s->sock, SOL_SOCKET, SO_SNDBUF, &flag, sizeof(flag) ); // setsockopt(s->sock, SOL_SOCKET, SO_RCVBUF, &flag, sizeof(flag) ); // No-delay is terribly important, but setting here doesn't seem all that effective. Doesn't // seem to effect the accepted file descriptors derived from the listen fd // int flag = 1; // setsockopt(s->sock, SOL_TCP, TCP_NODELAY, &flag, sizeof(flag) ); /* Bind to the socket; if we can't, nanosleep() and retry */ while (0 > (bind(s->sock, (struct sockaddr *)&s->saddr, sizeof(struct sockaddr)))) { if (EADDRINUSE != errno) { cf_warning(CF_SOCKET, "bind: %s", cf_strerror(errno)); return(-1); } cf_warning(CF_SOCKET, "bind: socket in use, waiting (port:%d)",s->port); nanosleep(&delay, NULL); } /* Listen for connections */ if ((SOCK_STREAM == s->proto) && (0 > listen(s->sock, 512))) { cf_warning(CF_SOCKET, "listen: %s", cf_strerror(errno)); return(-1); } return(0); }
/* * Gets a unique id for this process instance * Uses the mac address right now * And combine with the unique port number, which is why it needs to be passed in * Needs to be a little more subtle: * Should stash the mac address or something, in case you have to replace a card. * * parameters- * Input params: * port - used in setting Node ID * hb_mode - Controls whether hb_addrp is filled out with the IP address. * config_interface_names - Pointer to an array of interface names if specified in the config file, * NULL if absent. * * Output params: * id - Node ID (address and port) * node_ipp - Pointer wherein the IP address is stored * hb_addrp - Pointer to a string wherein the heartbeat address is stored, as specified by hb_mode */ int cf_nodeid_get(unsigned short port, cf_node *id, char **node_ipp, hb_mode_enum hb_mode, char **hb_addrp, const char **config_interface_names) { // The default interface names can be overridden by the interface name passed into config const char **interface_names = default_interface_names; bool default_config = true; int jlimit = 11; if (config_interface_names) { interface_names = config_interface_names; default_config = false; jlimit = 1; } int fdesc = socket(AF_INET, SOCK_STREAM, 0); if (fdesc <= 0) { cf_warning(CF_MISC, "can't open socket: %d %s", errno, cf_strerror(errno)); return(-1); } struct ifreq req; bool done = false; for (int i = 0; interface_names[i]; i++) { for (int j = 0; j < jlimit; j++) { if (default_config) { sprintf(req.ifr_name, interface_names[i], j); } else { sprintf(req.ifr_name, "%s", interface_names[i]); } if (0 == ioctl(fdesc, SIOCGIFHWADDR, &req)) { if (cf_ipaddr_get(fdesc, req.ifr_name, node_ipp) == 0) { done = true; break; } } cf_debug(CF_MISC, "can't get physical address of interface %s: %d %s", req.ifr_name, errno, cf_strerror(errno)); } if (done) { break; } } if (! done) { if (default_config) { struct ifaddrs *interface_addrs = NULL; if (getifaddrs(&interface_addrs) == -1) { cf_warning(CF_MISC, "getifaddrs failed %d %s", errno, cf_strerror(errno)); return -1; } if (! interface_addrs) { cf_warning(CF_MISC, "getifaddrs returned NULL"); return -1; } struct ifaddrs *ifa; for (ifa = interface_addrs; ifa != NULL; ifa = ifa->ifa_next) { if (! ifa->ifa_data) { continue; } if (! is_biosdevname(ifa->ifa_name)) { continue; } if (check_mac_and_get_ipaddr(fdesc, ifa->ifa_name, &req, node_ipp)) { done = true; break; } } for (ifa = interface_addrs; ifa != NULL && (! done); ifa = ifa->ifa_next) { if (! ifa->ifa_data) { continue; } if (check_mac_and_get_ipaddr(fdesc, ifa->ifa_name, &req, node_ipp)) { done = true; break; } } freeifaddrs(interface_addrs); } else { cf_warning(CF_MISC, "can't get physical address of interface name specified in config file, tried %s. fatal: %d %s", interface_names[0], errno, cf_strerror(errno)); close(fdesc); return(-1); } } close(fdesc); if (! done) { cf_warning(CF_MISC, "Tried eth,bond,wlan,em and list of all available interfaces on device. Failed to retrieve physical address with errno %d %s\n", errno, cf_strerror(errno)); return(-1); } /* * Set the hb_addr to be the same as the ip address if the mode is mesh and the hb_addr parameter is empty * Configuration file overrides the automatic node ip detection * - this gives us a work around in case the node ip is somehow detected wrong in production */ if (hb_mode == AS_HB_MODE_MESH) { if (*hb_addrp == NULL) { *hb_addrp = cf_strdup(*node_ipp); } cf_info(CF_MISC, "Heartbeat address for mesh: %s", *hb_addrp); } *id = 0; memcpy(id, req.ifr_hwaddr.sa_data, 6); memcpy(((byte *)id) + 6, &port, 2); cf_debug(CF_MISC, "port %d id %"PRIx64, port, *id); return(0); }
void cf_fault_event_nostack(const cf_fault_context context, const cf_fault_severity severity, const char *fn, const int line, char *msg, ...) { va_list argp; char mbuf[1024]; time_t now; struct tm nowtm; size_t pos; /* Make sure there's always enough space for the \n\0. */ size_t limit = sizeof(mbuf) - 2; /* Set the timestamp */ now = time(NULL); if (g_use_local_time) { localtime_r(&now, &nowtm); pos = strftime(mbuf, limit, "%b %d %Y %T GMT%z: ", &nowtm); } else { gmtime_r(&now, &nowtm); pos = strftime(mbuf, limit, "%b %d %Y %T %Z: ", &nowtm); } /* Set the context/scope/severity tag */ pos += snprintf(mbuf + pos, limit - pos, "%s (%s): ", cf_fault_severity_strings[severity], cf_fault_context_strings[context]); /* * snprintf() and vsnprintf() will not write more than the size specified, * but they return the size that would have been written without truncation. * These checks make sure there's enough space for the final \n\0. */ if (pos > limit) { pos = limit; } /* Set the location */ if (fn) pos += snprintf(mbuf + pos, limit - pos, "(%s:%d) ", fn, line); if (pos > limit) { pos = limit; } /* Append the message */ va_start(argp, msg); pos += vsnprintf(mbuf + pos, limit - pos, msg, argp); va_end(argp); if (pos > limit) { pos = limit; } pos += snprintf(mbuf + pos, 2, "\n"); /* Route the message to the correct destinations */ if (0 == cf_fault_sinks_inuse) { /* If no fault sinks are defined, use stderr for important messages */ if (severity <= NO_SINKS_LIMIT) fprintf(stderr, "%s", mbuf); } else { for (int i = 0; i < cf_fault_sinks_inuse; i++) { if ((severity <= cf_fault_sinks[i].limit[context]) || (CF_CRITICAL == severity)) { if (0 >= write(cf_fault_sinks[i].fd, mbuf, pos)) { // this is OK for a bit in case of a HUP. It's even better to queue the buffers and apply them // after the hup. TODO. fprintf(stderr, "internal failure in fault message write: %s\n", cf_strerror(errno)); } } } } /* Critical errors */ if (CF_CRITICAL == severity) { fflush(NULL); // these signals don't throw stack traces in our system raise(SIGINT); } }
/* cf_fault_event -- TWO: Expand on the LOG ability by being able to * print the contents of a BINARY array if we're passed a valid ptr (not NULL). * We will print the array according to "format". * Parms: * (*) scope: The module family (e.g. AS_RW, AS_UDF...) * (*) severify: The scope severity (e.g. INFO, DEBUG, DETAIL) * (*) file_name: Ptr to the FILE generating the call * (*) line: The function (really, the FILE) line number of the source call * (*) mem_ptr: Ptr to memory location of binary array (or NULL) * (*) len: Length of the binary string * (*) format: The single char showing the format (e.g. 'D', 'B', etc) * (*) msg: The format msg string * (*) ... : The variable set of parameters the correspond to the msg string. * * NOTE: We will eventually merge this function with the original cf_fault_event() **/ void cf_fault_event2(const cf_fault_context context, const cf_fault_severity severity, const char *file_name, const int line, void * mem_ptr, size_t len, cf_display_type dt, char *msg, ...) { va_list argp; char mbuf[MAX_BINARY_BUF_SZ]; time_t now; struct tm nowtm; size_t pos; char binary_buf[MAX_BINARY_BUF_SZ]; // Arbitrarily limit output to a fixed maximum length. if (len > MAX_BINARY_BUF_SZ) { len = MAX_BINARY_BUF_SZ; } char * labelp = NULL; // initialize to quiet build warning /* Make sure there's always enough space for the \n\0. */ size_t limit = sizeof(mbuf) - 2; /* Set the timestamp */ now = time(NULL); if (g_use_local_time) { localtime_r(&now, &nowtm); pos = strftime(mbuf, limit, "%b %d %Y %T GMT%z: ", &nowtm); } else { gmtime_r(&now, &nowtm); pos = strftime(mbuf, limit, "%b %d %Y %T %Z: ", &nowtm); } // If we're given a valid MEMORY POINTER for a binary value, then // compute the string that corresponds to the bytes. if (mem_ptr) { switch (dt) { case CF_DISPLAY_HEX_DIGEST: labelp = "Digest"; generate_packed_hex_string(mem_ptr, len, binary_buf); break; case CF_DISPLAY_HEX_SPACED: labelp = "HexSpaced"; generate_spaced_hex_string(mem_ptr, len, binary_buf); break; case CF_DISPLAY_HEX_PACKED: labelp = "HexPacked"; generate_packed_hex_string(mem_ptr, len, binary_buf); break; case CF_DISPLAY_HEX_COLUMNS: labelp = "HexColumns"; generate_column_hex_string(mem_ptr, len, binary_buf); break; case CF_DISPLAY_BASE64: labelp = "Base64"; generate_base64_string(mem_ptr, len, binary_buf); break; case CF_DISPLAY_BITS_SPACED: labelp = "BitsSpaced"; generate_4spaced_bits_string(mem_ptr, len, binary_buf); break; case CF_DISPLAY_BITS_COLUMNS: labelp = "BitsColumns"; generate_column_bits_string(mem_ptr, len, binary_buf); break; default: labelp = "Unknown Format"; binary_buf[0] = 0; // make sure it's null terminated. break; } // end switch } // if binary data is present /* Set the context/scope/severity tag */ pos += snprintf(mbuf + pos, limit - pos, "%s (%s): ", cf_fault_severity_strings[severity], cf_fault_context_strings[context]); /* * snprintf() and vsnprintf() will not write more than the size specified, * but they return the size that would have been written without truncation. * These checks make sure there's enough space for the final \n\0. */ if (pos > limit) { pos = limit; } /* Set the location: filename and line number */ if (file_name) { pos += snprintf(mbuf + pos, limit - pos, "(%s:%d) ", file_name, line); } // Check for overflow (see above). if (pos > limit) { pos = limit; } /* Append the message */ va_start(argp, msg); pos += vsnprintf(mbuf + pos, limit - pos, msg, argp); va_end(argp); // Check for overflow (see above). if (pos > limit) { pos = limit; } // Append our final BINARY string, if present (some might pass in NULL). if ( mem_ptr ) { pos += snprintf(mbuf + pos, limit - pos, "<%s>:%s", labelp, binary_buf); } // Check for overflow (see above). if (pos > limit) { pos = limit; } pos += snprintf(mbuf + pos, 2, "\n"); /* Route the message to the correct destinations */ if (0 == cf_fault_sinks_inuse) { /* If no fault sinks are defined, use stderr for critical messages */ if (CF_CRITICAL == severity) fprintf(stderr, "%s", mbuf); } else { for (int i = 0; i < cf_fault_sinks_inuse; i++) { if ((severity <= cf_fault_sinks[i].limit[context]) || (CF_CRITICAL == severity)) { if (0 >= write(cf_fault_sinks[i].fd, mbuf, pos)) { // this is OK for a bit in case of a HUP. It's even better to queue the buffers and apply them // after the hup. TODO. fprintf(stderr, "internal failure in fault message write: %s\n", cf_strerror(errno)); } } } } /* Critical errors */ if (CF_CRITICAL == severity) { fflush(NULL); // Our signal handler will log a stack trace. abort(); } }
int udf_cask_info_list(char *name, cf_dyn_buf * out) { DIR * dir = NULL; bool not_empty = false; struct dirent * entry = NULL; int count = 0; uint8_t * content = NULL; size_t content_len = 0; unsigned char content_gen[256] = {0}; unsigned char hash[SHA_DIGEST_LENGTH]; // hex string to be returned to the client unsigned char sha1_hex_buff[CF_SHA_HEX_BUFF_LEN]; cf_debug(AS_INFO, "UDF CASK INFO LIST"); // Currently just return directly for LUA uint8_t udf_type = AS_UDF_TYPE_LUA; dir = opendir(g_config.mod_lua.user_path); if ( dir == 0 ) { cf_warning(AS_UDF, "could not open udf directory %s: %s", g_config.mod_lua.user_path, cf_strerror(errno)); return -1; } while ( (entry = readdir(dir)) && entry->d_name ) { char * name = entry->d_name; size_t len = strlen(name); // if ( len < 4 ) continue; if ( name[0] == '.' ) continue; if ( not_empty ) { cf_dyn_buf_append_char(out, ';'); } else { not_empty = true; } cf_dyn_buf_append_string(out, "filename="); cf_dyn_buf_append_buf(out, (uint8_t *) name, len); cf_dyn_buf_append_string(out, ","); mod_lua_rdlock(&mod_lua); if (file_read(name, &content, &content_len, content_gen) != 0) { cf_info(AS_UDF, "UDF-list : file not readable"); cf_dyn_buf_append_string(out, "error=file_not_readable"); mod_lua_unlock(&mod_lua); return 0; } mod_lua_unlock(&mod_lua); SHA1(content, content_len, hash); // Convert to a hexadecimal string cf_convert_sha1_to_hex(hash, sha1_hex_buff); cf_dyn_buf_append_string(out, "hash="); cf_dyn_buf_append_buf(out, sha1_hex_buff, CF_SHA_HEX_BUFF_LEN); cf_dyn_buf_append_string(out, ",type="); cf_dyn_buf_append_string(out, as_udf_type_name[udf_type]); count ++; } if (not_empty) { cf_dyn_buf_append_string(out, ";"); } closedir(dir); return 0; }
/* cf_fault_event * Respond to a fault */ void cf_fault_event(const cf_fault_context context, const cf_fault_severity severity, const char *file_name, const char * function_name, const int line, char *msg, ...) { /* Prefilter: don't construct messages we won't end up writing */ if (severity > cf_fault_filter[context]) return; va_list argp; char mbuf[1024]; time_t now; struct tm nowtm; size_t pos; /* Make sure there's always enough space for the \n\0. */ size_t limit = sizeof(mbuf) - 2; /* Set the timestamp */ now = time(NULL); if (g_use_local_time) { localtime_r(&now, &nowtm); pos = strftime(mbuf, limit, "%b %d %Y %T GMT%z: ", &nowtm); } else { gmtime_r(&now, &nowtm); pos = strftime(mbuf, limit, "%b %d %Y %T %Z: ", &nowtm); } /* Set the context/scope/severity tag */ pos += snprintf(mbuf + pos, limit - pos, "%s (%s): ", cf_fault_severity_strings[severity], cf_fault_context_strings[context]); /* * snprintf() and vsnprintf() will not write more than the size specified, * but they return the size that would have been written without truncation. * These checks make sure there's enough space for the final \n\0. */ if (pos > limit) { pos = limit; } /* Set the location: FileName, Optional FunctionName, and Line. It is * expected that we'll use FunctionName ONLY for debug() and detail(), * hence we must treat function_name as optional. */ const char * func_name = ( function_name == NULL ) ? "" : function_name; if (file_name) { pos += snprintf(mbuf + pos, limit - pos, "(%s:%s:%d) ", file_name, func_name, line); } if (pos > limit) { pos = limit; } /* Append the message */ va_start(argp, msg); pos += vsnprintf(mbuf + pos, limit - pos, msg, argp); va_end(argp); if (pos > limit) { pos = limit; } pos += snprintf(mbuf + pos, 2, "\n"); /* Route the message to the correct destinations */ if (0 == cf_fault_sinks_inuse) { /* If no fault sinks are defined, use stderr for important messages */ if (severity <= NO_SINKS_LIMIT) fprintf(stderr, "%s", mbuf); } else { for (int i = 0; i < cf_fault_sinks_inuse; i++) { if ((severity <= cf_fault_sinks[i].limit[context]) || (CF_CRITICAL == severity)) { if (0 >= write(cf_fault_sinks[i].fd, mbuf, pos)) { // this is OK for a bit in case of a HUP. It's even better to queue the buffers and apply them // after the hup. TODO. fprintf(stderr, "internal failure in fault message write: %s\n", cf_strerror(errno)); } } } } /* Critical errors */ if (CF_CRITICAL == severity) { fflush(NULL); // Our signal handler will log a stack trace. abort(); } } // end cf_fault_event()
// Set of threads which talk to client over the connection for doing the needful // processing. Note that once fd is assigned to a thread all the work on that fd // is done by that thread. Fair fd usage is expected of the client. First thread // is special - also does accept [listens for new connections]. It is the only // thread which does it. void * thr_demarshal(void *arg) { cf_socket_cfg *s, *ls; // Create my epoll fd, register in the global list. struct epoll_event ev; int nevents, i, n, epoll_fd; cf_clock last_fd_print = 0; #if defined(USE_SYSTEMTAP) uint64_t nodeid = g_config.self_node; #endif // Early stage aborts; these will cause faults in process scope. cf_assert(arg, AS_DEMARSHAL, CF_CRITICAL, "invalid argument"); s = &g_config.socket; ls = &g_config.localhost_socket; #ifdef USE_JEM int orig_arena; if (0 > (orig_arena = jem_get_arena())) { cf_crash(AS_DEMARSHAL, "Failed to get original arena for thr_demarshal()!"); } else { cf_info(AS_DEMARSHAL, "Saved original JEMalloc arena #%d for thr_demarshal()", orig_arena); } #endif // Figure out my thread index. pthread_t self = pthread_self(); int thr_id; for (thr_id = 0; thr_id < MAX_DEMARSHAL_THREADS; thr_id++) { if (0 != pthread_equal(g_demarshal_args->dm_th[thr_id], self)) break; } if (thr_id == MAX_DEMARSHAL_THREADS) { cf_debug(AS_FABRIC, "Demarshal thread could not figure own ID, bogus, exit, fu!"); return(0); } // First thread accepts new connection at interface socket. if (thr_id == 0) { demarshal_file_handle_init(); epoll_fd = epoll_create(EPOLL_SZ); if (epoll_fd == -1) cf_crash(AS_DEMARSHAL, "epoll_create(): %s", cf_strerror(errno)); memset(&ev, 0, sizeof (ev)); ev.events = EPOLLIN | EPOLLERR | EPOLLHUP; ev.data.fd = s->sock; if (0 > epoll_ctl(epoll_fd, EPOLL_CTL_ADD, s->sock, &ev)) cf_crash(AS_DEMARSHAL, "epoll_ctl(): %s", cf_strerror(errno)); cf_info(AS_DEMARSHAL, "Service started: socket %s:%d", s->addr, s->port); if (ls->sock) { ev.events = EPOLLIN | EPOLLERR | EPOLLHUP; ev.data.fd = ls->sock; if (0 > epoll_ctl(epoll_fd, EPOLL_CTL_ADD, ls->sock, &ev)) cf_crash(AS_DEMARSHAL, "epoll_ctl(): %s", cf_strerror(errno)); cf_info(AS_DEMARSHAL, "Service also listening on localhost socket %s:%d", ls->addr, ls->port); } } else { epoll_fd = epoll_create(EPOLL_SZ); if (epoll_fd == -1) cf_crash(AS_DEMARSHAL, "epoll_create(): %s", cf_strerror(errno)); } g_demarshal_args->epoll_fd[thr_id] = epoll_fd; cf_detail(AS_DEMARSHAL, "demarshal thread started: id %d", thr_id); int id_cntr = 0; // Demarshal transactions from the socket. for ( ; ; ) { struct epoll_event events[EPOLL_SZ]; cf_detail(AS_DEMARSHAL, "calling epoll"); nevents = epoll_wait(epoll_fd, events, EPOLL_SZ, -1); if (0 > nevents) { cf_debug(AS_DEMARSHAL, "epoll_wait() returned %d ; errno = %d (%s)", nevents, errno, cf_strerror(errno)); } cf_detail(AS_DEMARSHAL, "epoll event received: nevents %d", nevents); uint64_t now_ns = cf_getns(); uint64_t now_ms = now_ns / 1000000; // Iterate over all events. for (i = 0; i < nevents; i++) { if ((s->sock == events[i].data.fd) || (ls->sock == events[i].data.fd)) { // Accept new connections on the service socket. int csocket = -1; struct sockaddr_in caddr; socklen_t clen = sizeof(caddr); char cpaddr[64]; if (-1 == (csocket = accept(events[i].data.fd, (struct sockaddr *)&caddr, &clen))) { // This means we're out of file descriptors - could be a SYN // flood attack or misbehaving client. Eventually we'd like // to make the reaper fairer, but for now we'll just have to // ignore the accept error and move on. if ((errno == EMFILE) || (errno == ENFILE)) { if (last_fd_print != (cf_getms() / 1000L)) { cf_info(AS_DEMARSHAL, " warning: hit OS file descript limit (EMFILE on accept), consider raising limit"); last_fd_print = cf_getms() / 1000L; } continue; } cf_crash(AS_DEMARSHAL, "accept: %s (errno %d)", cf_strerror(errno), errno); } // Get the client IP address in string form. if (caddr.sin_family == AF_INET) { if (NULL == inet_ntop(AF_INET, &caddr.sin_addr.s_addr, (char *)cpaddr, sizeof(cpaddr))) { cf_crash(AS_DEMARSHAL, "inet_ntop(): %s (errno %d)", cf_strerror(errno), errno); } } else if (caddr.sin_family == AF_INET6) { struct sockaddr_in6* addr_in6 = (struct sockaddr_in6*)&caddr; if (NULL == inet_ntop(AF_INET6, &addr_in6->sin6_addr, (char *)cpaddr, sizeof(cpaddr))) { cf_crash(AS_DEMARSHAL, "inet_ntop(): %s (errno %d)", cf_strerror(errno), errno); } } else { cf_crash(AS_DEMARSHAL, "unknown address family %u", caddr.sin_family); } cf_detail(AS_DEMARSHAL, "new connection: %s (fd %d)", cpaddr, csocket); // Validate the limit of protocol connections we allow. uint32_t conns_open = g_config.proto_connections_opened - g_config.proto_connections_closed; if (conns_open > g_config.n_proto_fd_max) { if ((last_fd_print + 5000L) < cf_getms()) { // no more than 5 secs cf_warning(AS_DEMARSHAL, "dropping incoming client connection: hit limit %d connections", conns_open); last_fd_print = cf_getms(); } shutdown(csocket, SHUT_RDWR); close(csocket); csocket = -1; continue; } // Set the socket to nonblocking. if (-1 == cf_socket_set_nonblocking(csocket)) { cf_info(AS_DEMARSHAL, "unable to set client socket to nonblocking mode"); shutdown(csocket, SHUT_RDWR); close(csocket); csocket = -1; continue; } // Create as_file_handle and queue it up in epoll_fd for further // communication on one of the demarshal threads. as_file_handle *fd_h = cf_rc_alloc(sizeof(as_file_handle)); if (!fd_h) { cf_crash(AS_DEMARSHAL, "malloc"); } sprintf(fd_h->client, "%s:%d", cpaddr, ntohs(caddr.sin_port)); fd_h->fd = csocket; fd_h->last_used = cf_getms(); fd_h->reap_me = false; fd_h->trans_active = false; fd_h->proto = 0; fd_h->proto_unread = 0; fd_h->fh_info = 0; fd_h->security_filter = as_security_filter_create(); // Insert into the global table so the reaper can manage it. Do // this before queueing it up for demarshal threads - once // EPOLL_CTL_ADD is done it's difficult to back out (if insert // into global table fails) because fd state could be anything. cf_rc_reserve(fd_h); pthread_mutex_lock(&g_file_handle_a_LOCK); int j; bool inserted = true; if (0 != cf_queue_pop(g_freeslot, &j, CF_QUEUE_NOWAIT)) { inserted = false; } else { g_file_handle_a[j] = fd_h; } pthread_mutex_unlock(&g_file_handle_a_LOCK); if (!inserted) { cf_info(AS_DEMARSHAL, "unable to add socket to file handle table"); shutdown(csocket, SHUT_RDWR); close(csocket); csocket = -1; cf_rc_free(fd_h); // will free even with ref-count of 2 } else { // Place the client socket in the event queue. memset(&ev, 0, sizeof(ev)); ev.events = EPOLLIN | EPOLLET | EPOLLRDHUP ; ev.data.ptr = fd_h; // Round-robin pick up demarshal thread epoll_fd and add // this new connection to epoll. int id; while (true) { id = (id_cntr++) % g_demarshal_args->num_threads; if (g_demarshal_args->epoll_fd[id] != 0) { break; } } fd_h->epoll_fd = g_demarshal_args->epoll_fd[id]; if (0 > (n = epoll_ctl(fd_h->epoll_fd, EPOLL_CTL_ADD, csocket, &ev))) { cf_info(AS_DEMARSHAL, "unable to add socket to event queue of demarshal thread %d %d", id, g_demarshal_args->num_threads); pthread_mutex_lock(&g_file_handle_a_LOCK); fd_h->reap_me = true; as_release_file_handle(fd_h); fd_h = 0; pthread_mutex_unlock(&g_file_handle_a_LOCK); } else { cf_atomic_int_incr(&g_config.proto_connections_opened); } } } else { bool has_extra_ref = false; as_file_handle *fd_h = events[i].data.ptr; if (fd_h == 0) { cf_info(AS_DEMARSHAL, "event with null handle, continuing"); goto NextEvent; } cf_detail(AS_DEMARSHAL, "epoll connection event: fd %d, events 0x%x", fd_h->fd, events[i].events); // Process data on an existing connection: this might be more // activity on an already existing transaction, so we have some // state to manage. as_proto *proto_p = 0; int fd = fd_h->fd; if (events[i].events & (EPOLLRDHUP | EPOLLERR | EPOLLHUP)) { cf_detail(AS_DEMARSHAL, "proto socket: remote close: fd %d event %x", fd, events[i].events); // no longer in use: out of epoll etc goto NextEvent_FD_Cleanup; } if (fd_h->trans_active) { goto NextEvent; } // If pointer is NULL, then we need to create a transaction and // store it in the buffer. if (fd_h->proto == NULL) { as_proto proto; int sz; /* Get the number of available bytes */ if (-1 == ioctl(fd, FIONREAD, &sz)) { cf_info(AS_DEMARSHAL, "unable to get number of available bytes"); goto NextEvent_FD_Cleanup; } // If we don't have enough data to fill the message buffer, // just wait and we'll come back to this one. However, we'll // let messages with zero size through, since they are // likely errors. We don't cleanup the FD in this case since // we'll get more data on it. if (sz < sizeof(as_proto) && sz != 0) { goto NextEvent; } // Do a preliminary read of the header into a stack- // allocated structure, so that later on we can allocate the // entire message buffer. if (0 >= (n = cf_socket_recv(fd, &proto, sizeof(as_proto), MSG_WAITALL))) { cf_detail(AS_DEMARSHAL, "proto socket: read header fail: error: rv %d sz was %d errno %d", n, sz, errno); goto NextEvent_FD_Cleanup; } if (proto.version != PROTO_VERSION && // For backward compatibility, allow version 0 with // security messages. ! (proto.version == 0 && proto.type == PROTO_TYPE_SECURITY)) { cf_warning(AS_DEMARSHAL, "proto input from %s: unsupported proto version %u", fd_h->client, proto.version); goto NextEvent_FD_Cleanup; } // Swap the necessary elements of the as_proto. as_proto_swap(&proto); if (proto.sz > PROTO_SIZE_MAX) { cf_warning(AS_DEMARSHAL, "proto input from %s: msg greater than %d, likely request from non-Aerospike client, rejecting: sz %"PRIu64, fd_h->client, PROTO_SIZE_MAX, proto.sz); goto NextEvent_FD_Cleanup; } #ifdef USE_JEM // Attempt to peek the namespace and set the JEMalloc arena accordingly. size_t peeked_data_sz = 0; size_t min_field_sz = sizeof(uint32_t) + sizeof(char); size_t min_as_msg_sz = sizeof(as_msg) + min_field_sz; size_t peekbuf_sz = 2048; // (Arbitrary "large enough" size for peeking the fields of "most" AS_MSGs.) uint8_t peekbuf[peekbuf_sz]; if (PROTO_TYPE_AS_MSG == proto.type) { size_t offset = sizeof(as_msg); // Number of bytes to peek from the socket. // size_t peek_sz = peekbuf_sz; // Peak up to the size of the peek buffer. size_t peek_sz = MIN(proto.sz, peekbuf_sz); // Peek only up to the minimum necessary number of bytes. if (!(peeked_data_sz = cf_socket_recv(fd, peekbuf, peek_sz, 0))) { // That's actually legitimate. The as_proto may have gone into one // packet, the as_msg into the next one, which we haven't yet received. // This just "never happened" without async. cf_detail(AS_DEMARSHAL, "could not peek the as_msg header, expected %zu byte(s)", peek_sz); } if (peeked_data_sz > min_as_msg_sz) { // cf_debug(AS_DEMARSHAL, "(Peeked %zu bytes.)", peeked_data_sz); if (peeked_data_sz > proto.sz) { cf_warning(AS_DEMARSHAL, "Received unexpected extra data from client %s socket %d when peeking as_proto!", fd_h->client, fd); log_as_proto_and_peeked_data(&proto, peekbuf, peeked_data_sz); goto NextEvent_FD_Cleanup; } if (((as_msg*)peekbuf)->info1 & AS_MSG_INFO1_BATCH) { jem_set_arena(orig_arena); } else { uint16_t n_fields = ntohs(((as_msg *) peekbuf)->n_fields), field_num = 0; bool found = false; // cf_debug(AS_DEMARSHAL, "Found %d AS_MSG fields", n_fields); while (!found && (field_num < n_fields)) { as_msg_field *field = (as_msg_field *) (&peekbuf[offset]); uint32_t value_sz = ntohl(field->field_sz) - 1; // cf_debug(AS_DEMARSHAL, "Field #%d offset: %lu", field_num, offset); // cf_debug(AS_DEMARSHAL, "\tvalue_sz %u", value_sz); // cf_debug(AS_DEMARSHAL, "\ttype %d", field->type); if (AS_MSG_FIELD_TYPE_NAMESPACE == field->type) { if (value_sz >= AS_ID_NAMESPACE_SZ) { cf_warning(AS_DEMARSHAL, "namespace too long (%u) in as_msg", value_sz); goto NextEvent_FD_Cleanup; } char ns[AS_ID_NAMESPACE_SZ]; found = true; memcpy(ns, field->data, value_sz); ns[value_sz] = '\0'; // cf_debug(AS_DEMARSHAL, "Found ns \"%s\" in field #%d.", ns, field_num); jem_set_arena(as_namespace_get_jem_arena(ns)); } else { // cf_debug(AS_DEMARSHAL, "Message field %d is not namespace (type %d) ~~ Reading next field", field_num, field->type); field_num++; offset += sizeof(as_msg_field) + value_sz; if (offset >= peeked_data_sz) { break; } } } if (!found) { cf_warning(AS_DEMARSHAL, "Can't get namespace from AS_MSG (peeked %zu bytes) ~~ Using default thr_demarshal arena.", peeked_data_sz); jem_set_arena(orig_arena); } } } else { jem_set_arena(orig_arena); } } else { jem_set_arena(orig_arena); } #endif // Allocate the complete message buffer. proto_p = cf_malloc(sizeof(as_proto) + proto.sz); cf_assert(proto_p, AS_DEMARSHAL, CF_CRITICAL, "allocation: %zu %s", (sizeof(as_proto) + proto.sz), cf_strerror(errno)); memcpy(proto_p, &proto, sizeof(as_proto)); #ifdef USE_JEM // Jam in the peeked data. if (peeked_data_sz) { memcpy(proto_p->data, &peekbuf, peeked_data_sz); } fd_h->proto_unread = proto_p->sz - peeked_data_sz; #else fd_h->proto_unread = proto_p->sz; #endif fd_h->proto = (void *) proto_p; } else { proto_p = fd_h->proto; } if (fd_h->proto_unread > 0) { // Read the data. n = cf_socket_recv(fd, proto_p->data + (proto_p->sz - fd_h->proto_unread), fd_h->proto_unread, 0); if (0 >= n) { if (errno == EAGAIN) { continue; } cf_info(AS_DEMARSHAL, "receive socket: fail? n %d errno %d %s closing connection.", n, errno, cf_strerror(errno)); goto NextEvent_FD_Cleanup; } // Decrement bytes-unread counter. cf_detail(AS_DEMARSHAL, "read fd %d (%d %d)", fd, n, fd_h->proto_unread); fd_h->proto_unread -= n; } // Check for a finished read. if (0 == fd_h->proto_unread) { // It's only really live if it's injecting a transaction. fd_h->last_used = now_ms; thr_demarshal_pause(fd_h); // pause reading while the transaction is in progress fd_h->proto = 0; fd_h->proto_unread = 0; // INIT_TR as_transaction tr; as_transaction_init(&tr, NULL, (cl_msg *)proto_p); cf_rc_reserve(fd_h); has_extra_ref = true; tr.proto_fd_h = fd_h; tr.start_time = now_ns; // set transaction start time tr.preprocessed = false; if (! as_proto_is_valid_type(proto_p)) { cf_warning(AS_DEMARSHAL, "unsupported proto message type %u", proto_p->type); // We got a proto message type we don't recognize, so it // may not do any good to send back an as_msg error, but // it's the best we can do. At least we can keep the fd. as_transaction_demarshal_error(&tr, AS_PROTO_RESULT_FAIL_UNKNOWN); cf_atomic_int_incr(&g_config.proto_transactions); goto NextEvent; } if (g_config.microbenchmarks) { histogram_insert_data_point(g_config.demarshal_hist, now_ns); tr.microbenchmark_time = cf_getns(); } // Check if it's compressed. if (tr.msgp->proto.type == PROTO_TYPE_AS_MSG_COMPRESSED) { // Decompress it - allocate buffer to hold decompressed // packet. uint8_t *decompressed_buf = NULL; size_t decompressed_buf_size = 0; int rv = 0; if ((rv = as_packet_decompression((uint8_t *)proto_p, &decompressed_buf, &decompressed_buf_size))) { cf_warning(AS_DEMARSHAL, "as_proto decompression failed! (rv %d)", rv); cf_warning_binary(AS_DEMARSHAL, proto_p, sizeof(as_proto) + proto_p->sz, CF_DISPLAY_HEX_SPACED, "compressed proto_p"); as_transaction_demarshal_error(&tr, AS_PROTO_RESULT_FAIL_UNKNOWN); cf_atomic_int_incr(&g_config.proto_transactions); goto NextEvent; } // Count the packets. cf_atomic_int_add(&g_config.stat_compressed_pkts_received, 1); // Free the compressed packet since we'll be using the // decompressed packet from now on. cf_free(proto_p); proto_p = NULL; // Get original packet. tr.msgp = (cl_msg *)decompressed_buf; as_proto_swap(&(tr.msgp->proto)); if (! as_proto_wrapped_is_valid(&tr.msgp->proto, decompressed_buf_size)) { cf_warning(AS_DEMARSHAL, "decompressed unusable proto: version %u, type %u, sz %lu [%lu]", tr.msgp->proto.version, tr.msgp->proto.type, tr.msgp->proto.sz, decompressed_buf_size); as_transaction_demarshal_error(&tr, AS_PROTO_RESULT_FAIL_UNKNOWN); cf_atomic_int_incr(&g_config.proto_transactions); goto NextEvent; } } // Security protocol transactions. if (tr.msgp->proto.type == PROTO_TYPE_SECURITY) { as_security_transact(&tr); cf_atomic_int_incr(&g_config.proto_transactions); goto NextEvent; } // Info protocol requests. if (tr.msgp->proto.type == PROTO_TYPE_INFO) { if (as_info(&tr)) { cf_warning(AS_DEMARSHAL, "Info request failed to be enqueued ~~ Freeing protocol buffer"); goto NextEvent_FD_Cleanup; } cf_atomic_int_incr(&g_config.proto_transactions); goto NextEvent; } ASD_TRANS_DEMARSHAL(nodeid, (uint64_t) tr.msgp); // Fast path for batch requests. if (tr.msgp->msg.info1 & AS_MSG_INFO1_BATCH) { as_batch_queue_task(&tr); cf_atomic_int_incr(&g_config.proto_transactions); goto NextEvent; } // Either process the transaction directly in this thread, // or queue it for processing by another thread (tsvc/info). if (0 != thr_tsvc_process_or_enqueue(&tr)) { cf_warning(AS_DEMARSHAL, "Failed to queue transaction to the service thread"); goto NextEvent_FD_Cleanup; } else { cf_atomic_int_incr(&g_config.proto_transactions); } } // Jump the proto message free & FD cleanup. If we get here, the // above operations went smoothly. The message free & FD cleanup // job is handled elsewhere as directed by // thr_tsvc_process_or_enqueue(). goto NextEvent; NextEvent_FD_Cleanup: // If we allocated memory for the incoming message, free it. if (proto_p) { cf_free(proto_p); fd_h->proto = 0; } // If fd has extra reference for transaction, release it. if (has_extra_ref) { cf_rc_release(fd_h); } // Remove the fd from the events list. if (epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, 0) < 0) { cf_crash(AS_DEMARSHAL, "unable to remove socket FD %d from epoll instance FD %d: %d (%s)", fd, epoll_fd, errno, cf_strerror(errno)); } pthread_mutex_lock(&g_file_handle_a_LOCK); fd_h->reap_me = true; as_release_file_handle(fd_h); fd_h = 0; pthread_mutex_unlock(&g_file_handle_a_LOCK); NextEvent: ; } // We should never be canceled externally, but just in case... pthread_testcancel(); } } return NULL; }
int cf_nodeid_get( unsigned short port, cf_node *id, char **node_ipp, hb_mode_enum hb_mode, char **hb_addrp, char **config_interface_names) { int fdesc; struct ifreq req; // The default interface names can be overridden by the interface name passed into config char **interface_names = default_interface_names; bool default_config = true; int jlimit = 11; if (config_interface_names) { interface_names = config_interface_names; default_config = false; jlimit = 1; } if (0 >= (fdesc = socket(AF_INET, SOCK_STREAM, 0))) { cf_warning(CF_MISC, "can't open socket: %d %s", errno, cf_strerror(errno)); return(-1); } int i = 0; bool done = false; while ((interface_names[i]) && (!done)) { int j=0; while ((!done) && (j < jlimit)) { if (default_config) sprintf(req.ifr_name, interface_names[i],j); else sprintf(req.ifr_name, interface_names[i]); if (0 == ioctl(fdesc, SIOCGIFHWADDR, &req)) { if (cf_ipaddr_get(fdesc, req.ifr_name, node_ipp) == 0) { done = true; break; } } cf_debug(CF_MISC, "can't get physical address of interface %s: %d %s", req.ifr_name, errno, cf_strerror(errno)); j++; } i++; } if (!done) { if (default_config) { struct ifaddrs* interface_addrs = NULL; if (getifaddrs(&interface_addrs) == -1) { cf_warning(CF_MISC, "getifaddrs failed %d %s", errno, cf_strerror(errno)); return -1; } if (!interface_addrs) { cf_warning(CF_MISC, "getifaddrs returned NULL"); return -1; } struct ifaddrs *ifa; for (ifa = interface_addrs; ifa != NULL && (!done); ifa = ifa->ifa_next) { if (ifa->ifa_data != 0) { struct ifreq req; strcpy(req.ifr_name, ifa->ifa_name); /* Get MAC address */ if (ioctl(fdesc, SIOCGIFHWADDR, &req) == 0) { uint8_t* mac = (uint8_t*)req.ifr_ifru.ifru_hwaddr.sa_data; /* MAC address sanity check */ if ((mac[0] == 0 && mac[1] == 0 && mac[2] == 0 && mac[3] == 0 && mac[4] == 0 && mac[5] == 0) || (mac[0] == 0xff && mac[1] == 0xff && mac[2] == 0xff && mac[3] == 0xff && mac[4] == 0xff && mac[5] == 0xff )) { continue; } /* Get IP address */ if (cf_ipaddr_get(fdesc, req.ifr_name, node_ipp) == 0) { done = true; continue; } } else { /* Continue to the next interface if cannot get MAC address */ continue; } } } } else { cf_warning(CF_MISC, "can't get physical address of interface name specfied in config file, tried %s. fatal: %d %s", interface_names[0], errno, cf_strerror(errno)); close(fdesc); return(-1); } } if (!done) { cf_warning(CF_MISC, "Tried eth,bond,wlan and list of all available interfaces on device.Failed to retrieve physical address with errno %d %s\n", errno, cf_strerror(errno)); close(fdesc); return(-1); } close(fdesc); /* * Set the hb_addr to be the same as the ip address if the mode is mesh and the hb_addr parameter is empty * Configuration file overrides the automatic node ip detection * - this gives us a work around in case the node ip is somehow detected wrong in production */ if (hb_mode == AS_HB_MODE_MESH) { if (*hb_addrp == NULL) *hb_addrp = cf_strdup(*node_ipp); cf_info(CF_MISC, "Heartbeat address for mesh: %s", *hb_addrp); } *id = 0; memcpy(id, req.ifr_hwaddr.sa_data, 6); memcpy(((byte *)id) + 6, &port, 2); cf_debug(CF_MISC, "port %d id %"PRIx64, port, *id); return(0); }