コード例 #1
0
ファイル: socket.c プロジェクト: think-css/aerospike-server
/* 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);
}
コード例 #2
0
ファイル: id.c プロジェクト: Benguang/aerospike-server
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);
}
コード例 #3
0
ファイル: daemon.c プロジェクト: Benguang/aerospike-server
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));
	}
}
コード例 #4
0
ファイル: as.c プロジェクト: aerospike/aerospike-server
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);
	}
}
コード例 #5
0
ファイル: socket.c プロジェクト: Benguang/aerospike-server
/* 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);
}
コード例 #6
0
ファイル: socket.c プロジェクト: think-css/aerospike-server
/* 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);
}
コード例 #7
0
ファイル: socket.c プロジェクト: think-css/aerospike-server
/* 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);
}
コード例 #8
0
ファイル: socket.c プロジェクト: think-css/aerospike-server
/* 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);
}
コード例 #9
0
ファイル: udf_cask.c プロジェクト: CowLeo/aerospike-server
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;
}
コード例 #10
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));
	}
}
コード例 #11
0
ファイル: socket.c プロジェクト: think-css/aerospike-server
/* 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);
}
コード例 #12
0
ファイル: socket.c プロジェクト: think-css/aerospike-server
/* 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);
}
コード例 #13
0
ファイル: socket.c プロジェクト: think-css/aerospike-server
/* 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);
}
コード例 #14
0
ファイル: id.c プロジェクト: CowLeo/aerospike-server
/*
 * 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);
}
コード例 #15
0
ファイル: fault.c プロジェクト: bryongloden/aerospike-server
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);
	}
}
コード例 #16
0
ファイル: fault.c プロジェクト: bryongloden/aerospike-server
/* 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();
	}
}
コード例 #17
0
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;
}
コード例 #18
0
ファイル: fault.c プロジェクト: Steve888888/aerospike-server
/* 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()
コード例 #19
0
// 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;
}
コード例 #20
0
ファイル: id.c プロジェクト: Benguang/aerospike-server
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);
}