/* Just IPv4 for now... */ int mk_socket_server(char *port, char *listen_addr, int reuse_port, struct mk_server *server) { int ret; int socket_fd = -1; struct addrinfo hints; struct addrinfo *res, *rp; memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; ret = getaddrinfo(listen_addr, port, &hints, &res); if(ret != 0) { mk_err("Can't get addr info: %s", gai_strerror(ret)); return -1; } for (rp = res; rp != NULL; rp = rp->ai_next) { socket_fd = mk_socket_create(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (socket_fd == -1) { mk_warn("Error creating server socket, retrying"); continue; } ret = mk_socket_set_tcp_nodelay(socket_fd); if (ret == -1) { mk_warn("Could not set TCP_NODELAY"); } mk_socket_reset(socket_fd); /* Check if reuse port can be enabled on this socket */ if (reuse_port == MK_TRUE && (server->kernel_features & MK_KERNEL_SO_REUSEPORT)) { ret = mk_socket_set_tcp_reuseport(socket_fd); if (ret == -1) { mk_warn("Could not use SO_REUSEPORT, using fair balancing mode"); server->scheduler_mode = MK_SCHEDULER_FAIR_BALANCING; } } ret = mk_socket_bind(socket_fd, rp->ai_addr, rp->ai_addrlen, MK_SOMAXCONN, server); if(ret == -1) { mk_err("Cannot listen on %s:%s", listen_addr, port); freeaddrinfo(res); return -1; } break; } freeaddrinfo(res); if (rp == NULL) return -1; return socket_fd; }
/* Run current process in background mode (daemon, evil Monkey >:) */ int mk_utils_set_daemon() { pid_t pid; if ((pid = fork()) < 0){ mk_err("Error: Failed creating to switch to daemon mode(fork failed)"); exit(EXIT_FAILURE); } if (pid > 0) /* parent */ exit(EXIT_SUCCESS); /* set files mask */ umask(0); /* Create new session */ setsid(); if (chdir("/") < 0) { /* make sure we can unmount the inherited filesystem */ mk_err("Error: Unable to unmount the inherited filesystem in the daemon process"); exit(EXIT_FAILURE); } /* Our last STDOUT messages */ mk_details(); mk_info("Background mode ON"); fclose(stderr); fclose(stdout); return 0; }
int _mkp_network_io_server(int port, char *listen_addr, int reuse_port) { int socket_fd = -1; int ret; char *port_str = 0; unsigned long len; struct addrinfo hints; struct addrinfo *res, *rp; memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; mk_api->str_build(&port_str, &len, "%d", port); ret = getaddrinfo(listen_addr, port_str, &hints, &res); mk_api->mem_free(port_str); if(ret != 0) { mk_err("Can't get addr info: %s", gai_strerror(ret)); return -1; } for(rp = res; rp != NULL; rp = rp->ai_next) { socket_fd = _mkp_network_io_create_socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if( socket_fd == -1) { mk_warn("Error creating server socket, retrying"); continue; } mk_api->socket_set_tcp_nodelay(socket_fd); mk_api->socket_reset(socket_fd); /* Check if reuse port can be enabled on this socket */ if (reuse_port == MK_TRUE && (mk_api->config->kernel_features & MK_KERNEL_SO_REUSEPORT)) { ret = mk_api->socket_set_tcp_reuseport(socket_fd); if (ret == -1) { mk_warn("Could not use SO_REUSEPORT, using fair balancing mode"); mk_api->config->scheduler_mode = MK_SCHEDULER_FAIR_BALANCING; } } ret = _mkp_network_io_bind(socket_fd, rp->ai_addr, rp->ai_addrlen, MK_SOMAXCONN); if(ret == -1) { mk_err("Cannot listen on %s:%i\n", listen_addr, port); continue; } break; } freeaddrinfo(res); if (rp == NULL) return -1; return socket_fd; }
static struct proxy_server_entry_array *proxy_parse_ServerList(char *server_addr) { char *tmp; int server_num = 0; struct mk_string_line *entry; struct mk_list *line, *head; struct mk_list *server_list = mk_api->str_split_line(server_addr); struct proxy_server_entry_array *proxy_server_array = 0; if (!server_addr) { return 0; } line = mk_api->str_split_line(server_addr); if (!line) { return 0; } mk_list_foreach(head, line) { server_num++; } if (!server_num) { return 0; } proxy_server_array = mk_api->mem_alloc(sizeof(struct proxy_server_entry_array) + sizeof(struct proxy_server_entry) * server_num); if (!proxy_server_array) { return 0; } proxy_server_array->length = server_num; server_num = 0; mk_list_foreach(head, line) { entry = mk_list_entry(head, struct mk_string_line, _head); if (!entry) { mk_err("ProxyReverse: Invalid configuration ServerList"); mk_api->mem_free(proxy_server_array); return 0; } tmp = memchr(entry->val, ':', entry->len); if (!tmp) { mk_err("ProxyReverse: Invalid configuration ServerList"); mk_api->mem_free(proxy_server_array); return 0; } *tmp = '\0'; proxy_server_array->entry[server_num].hostname = mk_api->str_dup(entry->val); proxy_server_array->entry[server_num].port = strtol(tmp + 1, 0, 10); server_num++; }
/* Write Monkey's PID */ int mk_utils_register_pid() { int fd; char pidstr[MK_MAX_PID_LEN]; unsigned long len = 0; char *filepath = NULL; struct flock lock; struct stat sb; struct mk_config_listener *listen; if (config->pid_status == MK_TRUE) return -1; listen = mk_list_entry_first(&config->listeners, struct mk_config_listener, _head); mk_string_build(&filepath, &len, "%s.%s", config->pid_file_path, listen->port); if (!stat(filepath, &sb)) { /* file exists, perhaps previously kepts by SIGKILL */ unlink(filepath); } if ((fd = open(filepath, O_WRONLY | O_CREAT | O_CLOEXEC, 0444)) < 0) { mk_err("Error: I can't log pid of monkey"); exit(EXIT_FAILURE); } /* create a write exclusive lock for the entire file */ lock.l_type = F_WRLCK; lock.l_start = 0; lock.l_whence = SEEK_SET; lock.l_len = 0; if (fcntl(fd, F_SETLK, &lock) < 0) { close(fd); mk_err("Error: I cannot set the lock for the pid of monkey"); exit(EXIT_FAILURE); } sprintf(pidstr, "%i", getpid()); ssize_t write_len = strlen(pidstr); if (write(fd, pidstr, write_len) != write_len) { close(fd); mk_err("Error: I cannot write the lock for the pid of monkey"); exit(EXIT_FAILURE); } mk_mem_free(filepath); config->pid_status = MK_TRUE; return 0; }
/* Write Monkey's PID */ int mk_utils_register_pid(char *path) { int fd; int ret; char pidstr[MK_MAX_PID_LEN]; struct flock lock; struct stat sb; if (stat(path, &sb) == 0) { /* file exists, perhaps previously kepts by SIGKILL */ ret = unlink(path); if (ret == -1) { mk_err("Could not remove old PID-file path"); exit(EXIT_FAILURE); } } #ifdef __rtems__ #define MK_UTILS_OPEN_FLAGS ( O_WRONLY | O_CREAT ) #else #define MK_UTILS_OPEN_FLAGS ( O_WRONLY | O_CREAT | O_CLOEXEC ) #endif if ((fd = open(path, MK_UTILS_OPEN_FLAGS, 0444)) < 0) { mk_err("Error: I can't log pid of monkey"); exit(EXIT_FAILURE); } /* create a write exclusive lock for the entire file */ lock.l_type = F_WRLCK; lock.l_start = 0; lock.l_whence = SEEK_SET; lock.l_len = 0; if (fcntl(fd, F_SETLK, &lock) < 0) { close(fd); mk_err("Error: I cannot set the lock for the pid of monkey"); exit(EXIT_FAILURE); } sprintf(pidstr, "%i", getpid()); ssize_t write_len = strlen(pidstr); if (write(fd, pidstr, write_len) != write_len) { close(fd); mk_err("Error: I cannot write the lock for the pid of monkey"); exit(EXIT_FAILURE); } close(fd); return 0; }
/* Return process to the original user */ int mk_user_undo_uidgid() { if (config->is_seteuid == MK_TRUE) { if (setegid(0) < 0) { mk_err("Can't restore effective GID"); } if (seteuid(0) < 0) { mk_err("Can't restore effective UID"); } } return 0; }
int _mkp_network_io_server(int port, char *listen_addr) { int socket_fd = -1; int ret; char *port_str = 0; unsigned long len; struct addrinfo hints; struct addrinfo *res, *rp; memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; mk_api->str_build(&port_str, &len, "%d", port); ret = getaddrinfo(listen_addr, port_str, &hints, &res); mk_api->mem_free(port_str); if(ret != 0) { mk_err("Can't get addr info: %s", gai_strerror(ret)); return -1; } for(rp = res; rp != NULL; rp = rp->ai_next) { socket_fd = _mkp_network_io_create_socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if( socket_fd == -1) { mk_warn("Error creating server socket, retrying"); continue; } mk_api->socket_set_tcp_nodelay(socket_fd); mk_api->socket_reset(socket_fd); ret = _mkp_network_io_bind(socket_fd, rp->ai_addr, rp->ai_addrlen, MK_SOMAXCONN); if(ret == -1) { mk_err("Port %i cannot be used, retrying\n", port); continue; } break; } freeaddrinfo(res); if (rp == NULL) return -1; return socket_fd; }
/* Write Monkey's PID */ int mk_utils_register_pid(char *path) { int fd; int ret; char pidstr[MK_MAX_PID_LEN]; struct flock lock; struct stat sb; if (stat(path, &sb) == 0) { /* file exists, perhaps previously kepts by SIGKILL */ ret = unlink(path); if (ret == -1) { mk_err("Could not remove old PID-file path: %s", path); exit(EXIT_FAILURE); } } if ((fd = open(path, O_WRONLY | O_CREAT | O_CLOEXEC, 0444)) < 0) { mk_err("I cannot create PID file '%s'", path); exit(EXIT_FAILURE); } /* create a write exclusive lock for the entire file */ lock.l_type = F_WRLCK; lock.l_start = 0; lock.l_whence = SEEK_SET; lock.l_len = 0; if (fcntl(fd, F_SETLK, &lock) < 0) { close(fd); mk_err("I cannot set the lock for the PID file '%s'", path); exit(EXIT_FAILURE); } sprintf(pidstr, "%i", getpid()); ssize_t write_len = strlen(pidstr); if (write(fd, pidstr, write_len) != write_len) { close(fd); mk_err("I cannot write PID number at '%s' file", path); exit(EXIT_FAILURE); } close(fd); return 0; }
/* Write Monkey's PID */ int mk_utils_register_pid() { int fd; char pidstr[MK_MAX_PID_LEN]; struct flock lock; struct stat sb; if (mk_config->pid_status == MK_TRUE) return -1; if (!stat(mk_config->pid_file_path, &sb)) { /* file exists, perhaps previously kepts by SIGKILL */ unlink(mk_config->pid_file_path); } if ((fd = open(mk_config->pid_file_path, O_WRONLY | O_CREAT | O_CLOEXEC, 0444)) < 0) { mk_err("Error: I can't log pid of monkey"); exit(EXIT_FAILURE); } /* create a write exclusive lock for the entire file */ lock.l_type = F_WRLCK; lock.l_start = 0; lock.l_whence = SEEK_SET; lock.l_len = 0; if (fcntl(fd, F_SETLK, &lock) < 0) { close(fd); mk_err("Error: I cannot set the lock for the pid of monkey"); exit(EXIT_FAILURE); } sprintf(pidstr, "%i", getpid()); ssize_t write_len = strlen(pidstr); if (write(fd, pidstr, write_len) != write_len) { close(fd); mk_err("Error: I cannot write the lock for the pid of monkey"); exit(EXIT_FAILURE); } mk_config->pid_status = MK_TRUE; return 0; }
/* We need to know how to solve the problem with AF_INET and AF_INET6 */ int _mkp_network_io_connect(char *host, int port) { int ret; int socket_fd = -1; char *port_str = 0; unsigned long len; struct addrinfo hints; struct addrinfo *res, *rp; memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; mk_api->str_build(&port_str, &len, "%d", port); ret = getaddrinfo(host, port_str, &hints, &res); mk_api->mem_free(port_str); if(ret != 0) { mk_err("Can't get addr info: %s", gai_strerror(ret)); return -1; } for(rp = res; rp != NULL; rp = rp->ai_next) { socket_fd = _mkp_network_io_create_socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if( socket_fd == -1) { mk_warn("Error creating client socket, retrying"); continue; } if (connect(socket_fd, (struct sockaddr *) rp->ai_addr, rp->ai_addrlen) == -1) { close(socket_fd); mk_err("Can't connect to %s, retrying", host); continue; } break; } freeaddrinfo(res); if (rp == NULL) return -1; return socket_fd; }
int mk_socket_connect(char *host, int port, int async) { int ret; int socket_fd = -1; char *port_str = 0; unsigned long len; struct addrinfo hints; struct addrinfo *res, *rp; memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; mk_string_build(&port_str, &len, "%d", port); ret = getaddrinfo(host, port_str, &hints, &res); mk_mem_free(port_str); if(ret != 0) { mk_err("Can't get addr info: %s", gai_strerror(ret)); return -1; } for (rp = res; rp != NULL; rp = rp->ai_next) { socket_fd = mk_socket_create(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (socket_fd == -1) { mk_warn("Error creating client socket, retrying"); continue; } if (async == MK_TRUE) { mk_socket_set_nonblocking(socket_fd); } ret = connect(socket_fd, (struct sockaddr *) rp->ai_addr, rp->ai_addrlen); if (ret == -1) { if (errno == EINPROGRESS) { break; } else { printf("%s", strerror(errno)); perror("connect"); exit(1); close(socket_fd); continue; } } break; } freeaddrinfo(res); if (rp == NULL) return -1; return socket_fd; }
//duda_package_t *duda_package_load(const char *pkgname) duda_package_t *duda_package_load(const char *pkgname, struct duda_api_objects *api) { int ret; char *package = NULL; void *handle = NULL; unsigned long len; struct file_info finfo; duda_package_t *(*init_pkg)() = NULL; duda_package_t *package_info; mk_api->str_build(&package, &len, "%s/%s.dpkg", packages_root, pkgname); ret = mk_api->file_get_info(package, &finfo); if (ret != 0) { mk_err("Duda: Package '%s' not found", pkgname); mk_api->mem_free(package); exit(EXIT_FAILURE); } if (finfo.is_file == MK_FALSE) { mk_warn("Duda: Invalid Package '%s'", pkgname); mk_api->mem_free(package); return NULL; } handle = duda_load_library(package); if (!handle) { mk_warn("Duda: Invalid Package format '%s'", pkgname); mk_api->mem_free(package); return NULL; } init_pkg = duda_load_symbol(handle, "init_duda_package"); if (!init_pkg) { mk_err("Duda: the package '%s' is broken", pkgname); exit(EXIT_FAILURE); } package_info = init_pkg(api); mk_api->mem_free(package); return package_info; }
/* Change process user */ int mk_user_set_uidgid() { struct passwd *usr; /* Launched by root ? */ if (geteuid() == 0 && config->user) { struct rlimit rl; if (getrlimit(RLIMIT_NOFILE, &rl)) { mk_warn("cannot get resource limits"); } /* Check if user exists */ if ((usr = getpwnam(config->user)) == NULL) { mk_err("Invalid user '%s'", config->user); goto out; } if (initgroups(config->user, usr->pw_gid) != 0) { mk_err("Initgroups() failed"); } /* Change process UID and GID */ if (setegid(usr->pw_gid) == -1) { mk_err("I cannot change the GID to %u", usr->pw_gid); } if (seteuid(usr->pw_uid) == -1) { mk_err("I cannot change the UID to %u", usr->pw_uid); } config->is_seteuid = MK_TRUE; } out: /* Variables set for run checks on file permission */ EUID = geteuid(); EGID = getegid(); return 0; }
int mk_socket_set_nonblocking(int sockfd) { MK_TRACE("Socket, set FD %i to non-blocking", sockfd); if (fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFD, 0) | O_NONBLOCK | O_CLOEXEC) == -1) { mk_err("Can't set to non-blocking mode socket %i", sockfd); return -1; } return 0; }
int mk_epoll_create(int max_events) { int efd; efd = epoll_create(max_events); if (efd == -1) { perror("epoll_create"); mk_err("epoll_create() failed"); } return efd; }
/* Just IPv4 for now... */ int mk_socket_server(char *port, char *listen_addr, int reuse_port) { int socket_fd; if (!mk_config->network) { mk_err("No network layer plugin was found. Aborting."); exit(EXIT_FAILURE); } socket_fd = mk_config->network->server(port, listen_addr, reuse_port); if (socket_fd < 0) { exit(EXIT_FAILURE); } return socket_fd; }
/* * Read the main configuration file for dirhtml: dirhtml.conf, * it will alloc the dirhtml_conf struct */ int mk_dirhtml_read_config(char *path) { unsigned long len; char *default_file = NULL; struct mk_rconf *conf; struct mk_rconf_section *section; struct file_info finfo; mk_api->str_build(&default_file, &len, "%sdirhtml.conf", path); conf = mk_api->config_create(default_file); if (!conf) { return -1; } section = mk_api->config_section_get(conf, "DIRLISTING"); if (!section) { mk_err("Could not find DIRLISTING tag in configuration file"); exit(EXIT_FAILURE); } /* alloc dirhtml config struct */ dirhtml_conf = mk_api->mem_alloc(sizeof(struct dirhtml_config)); dirhtml_conf->theme = mk_api->config_section_get_key(section, "Theme", MK_RCONF_STR); dirhtml_conf->theme_path = NULL; mk_api->str_build(&dirhtml_conf->theme_path, &len, "%sthemes/%s/", path, dirhtml_conf->theme); mk_api->mem_free(default_file); if (mk_api->file_get_info(dirhtml_conf->theme_path, &finfo, MK_FILE_READ) != 0) { mk_warn("Dirlisting: cannot load theme from '%s'", dirhtml_conf->theme_path); mk_warn("Dirlisting: unloading plugin"); return -1; } mk_api->config_free(conf); return 0; }
static inline struct mk_sched_conn *mk_server_listen_handler(struct mk_sched_worker *sched, void *data) { int ret; int client_fd = -1; struct mk_sched_conn *conn; struct mk_server_listen *listener = data; client_fd = mk_socket_accept(listener->server_fd); if (mk_unlikely(client_fd == -1)) { MK_TRACE("[server] Accept connection failed: %s", strerror(errno)); goto error; } conn = mk_sched_add_connection(client_fd, listener, sched); if (mk_unlikely(!conn)) { goto error; } ret = mk_event_add(sched->loop, client_fd, MK_EVENT_CONNECTION, MK_EVENT_READ, conn); if (mk_unlikely(ret != 0)) { mk_err("[server] Error registering file descriptor: %s", strerror(errno)); goto error; } sched->accepted_connections++; MK_TRACE("[server] New connection arrived: FD %i", client_fd); return conn; error: if (client_fd != -1) { listener->network->network->close(client_fd); } return NULL; }
void mk_cheetah_loop_server() { int n, ret; int buf_len; unsigned long len; char buf[1024]; char cmd[1024]; int server_fd; int remote_fd; size_t address_length; struct sockaddr_un address; socklen_t socket_size = sizeof(struct sockaddr_in); struct mk_config_listener *listener; /* Create listening socket */ server_fd = socket(PF_UNIX, SOCK_STREAM, 0); if (server_fd < 0) { perror("socket() failed"); exit(EXIT_FAILURE); } listener = mk_list_entry_first(&mk_api->config->listeners, struct mk_config_listener, _head); cheetah_server = NULL; mk_api->str_build(&cheetah_server, &len, "/tmp/cheetah.%s", listener->port); unlink(cheetah_server); address.sun_family = AF_UNIX; sprintf(address.sun_path, "%s", cheetah_server); address_length = sizeof(address.sun_family) + len + 1; if (bind(server_fd, (struct sockaddr *) &address, address_length) != 0) { perror("bind"); mk_err("Cheetah: could not bind address %s", address.sun_path); exit(EXIT_FAILURE); } if (listen(server_fd, 5) != 0) { perror("listen"); exit(EXIT_FAILURE); } while (1) { /* Listen for incoming connections */ remote_fd = accept(server_fd, (struct sockaddr *) &address, &socket_size); cheetah_socket = remote_fd; buf_len = 0; memset(buf, '\0', 1024); /* Send welcome message and prompt */ mk_cheetah_welcome_msg(); CHEETAH_WRITE(MK_CHEETAH_PROMPT, ANSI_BOLD, ANSI_GREEN, ANSI_RESET); while (1) { /* Read incoming data */ n = read(remote_fd, buf+buf_len, 1024 - buf_len); if (n <= 0) { break; } else { buf_len += n; if (buf[buf_len-1] == '\n') { /* Filter command */ strncpy(cmd, buf, buf_len - 1); cmd[buf_len - 1] = '\0'; /* Run command */ ret = mk_cheetah_cmd(cmd); if (ret == -1) { break; } /* Write prompt */ CHEETAH_WRITE(MK_CHEETAH_PROMPT, ANSI_BOLD, ANSI_GREEN, ANSI_RESET); buf_len = 0; memset(buf, '\0', 1024); } } } close(remote_fd); } }
int duda_body_buffer_flush(int sock, struct duda_body_buffer *bb) { int i; int count = 0; unsigned int bytes_sent, bytes_to; int reset_to = -1; struct mk_iov *buf = bb->buf; /* FIXME: Temporal Check */ if (mk_unlikely(buf->iov_idx > IOV_MAX)) { mk_err("Boddy buffer flush: enqueued data is larger than IOV_MAX (%i)\n", IOV_MAX); exit(EXIT_FAILURE); } bytes_sent = mk_api->socket_sendv(sock, buf); PLUGIN_TRACE("body_flush: %i/%i", bytes_sent, buf->total_len); /* * If the call sent less data than total, we must modify the mk_iov struct * to mark the buffers already processed and set them with with length = zero, * so on the next calls to this function Monkey will skip buffers with bytes * length = 0. */ if (bytes_sent < buf->total_len) { /* Go around each buffer entry and check where the offset took place */ for (i = 0; i < buf->iov_idx; i++) { if (count + buf->io[i].iov_len == bytes_sent) { reset_to = i; break; } else if (bytes_sent < (count + buf->io[i].iov_len)) { reset_to = i - 1; bytes_to = (bytes_sent - count); buf->io[i].iov_base += bytes_to; buf->io[i].iov_len = buf->io[i].iov_len - bytes_to; break; } count += buf->io[i].iov_len; } /* Reset entries */ for (i = 0; i <= reset_to; i++) { buf->io[i].iov_len = 0; } buf->total_len -= bytes_sent; #ifdef TRACE PLUGIN_TRACE("new total len: %i (iov_idx=%i)", buf->total_len, buf->iov_idx); int j; for (j = 0; j < buf->iov_idx; j++) { PLUGIN_TRACE("io[%i] = %i", j, buf->io[j].iov_len); } #endif } /* Successfully end ? */ if (bytes_sent == buf->total_len) { buf->total_len = 0; return 0; } return bytes_sent; }
/* Read configuration parameters */ int mk_patas_conf(char *confdir) { int res; int val_port; char *val_host; char *val_uri; unsigned long len; char *conf_path=NULL; struct mk_config_section *section; struct mk_config_entry *entry; struct mk_patas_node *node; /* Init nodes list */ mk_patas_nodes_list = mk_api->mem_alloc(sizeof(struct mk_list)); mk_list_init(mk_patas_nodes_list); /* Read configuration */ mk_api->str_build(&conf_path, &len, "%s/patas.conf", confdir); conf = mk_api->config_create(conf_path); section = mk_api->config_section_get(conf, "NODE"); while (section) { entry = section->entry; val_host = NULL; val_port = -1; val_uri = NULL; /* Get section values */ val_host = mk_api->config_section_getval(section, "IP", MK_CONFIG_VAL_STR); val_port = (int) mk_api->config_section_getval(section, "Port", MK_CONFIG_VAL_NUM); val_uri = mk_api->config_section_getval(section, "Uri", MK_CONFIG_VAL_LIST); if (val_host && val_uri && val_port > 0) { /* validate that node:ip is not pointing this server */ if (mk_patas_validate_node(val_host, val_port) < 0) { break; } /* alloc node */ node = mk_api->mem_alloc(sizeof(struct mk_patas_node)); node->host = val_host; node->port = val_port; /* pre-socket stuff */ node->sockaddr = mk_api->mem_alloc_z(sizeof(struct sockaddr_in)); node->sockaddr->sin_family = AF_INET; res = inet_pton(AF_INET, node->host, (void *) (&(node->sockaddr->sin_addr.s_addr))); if (res < 0) { mk_warn("Can't set remote->sin_addr.s_addr"); mk_api->mem_free(node->sockaddr); return -1; } else if (res == 0) { mk_err("Invalid IP address"); mk_api->mem_free(node->sockaddr); return -1; } node->sockaddr->sin_port = htons(node->port); /* add node to list */ PLUGIN_TRACE("Balance Node: %s:%i", val_host, val_port); mk_list_add(&node->_head, mk_patas_nodes_list); mk_patas_n_nodes++; } section = section->next; } mk_api->mem_free(conf_path); return 0; }
/* * Initialize the global Event structure used by threads to access the * global file descriptor table. */ int mk_event_initalize() { int i; int ret; mk_event_fdt_t *efdt; struct rlimit rlim; /* * Event File Descriptor Table (EFDT) * ---------------------------------- * The main requirement for this implementation is that we need to maintain * a state of each file descriptor registered events, such as READ, WRITE, * SLEEPING, etc. This is required not by Monkey core but is a fundamental * piece to let plugins perform safe operations over file descriptors and * their events. * * The EFDT is created in the main process context and aims to be used by * every Worker thread. Once a connection arrives and it's notified to the * Worker, this last one will register the file descriptor status on the * EFDT. * * The EFDT is a fixed size array that contains entries for each possible * file descriptor number assigned for a TCP connection. In order to make * sure the assigned number can be used as an index of the array, we have * verified that the Linux Kernel always assigns a number in a range as * defined in __alloc_fd() on file file.c: * * start: > 2 * * end : rlim.rlim.cur * * The maximum number assigned is always the process soft limit for * RLIMIT_NOFILE, so basically we are safe trusting on this model. * * Note: as we make sure each file descriptor number is only handled by one * thread, there is no race conditions. */ efdt = mk_mem_malloc_z(sizeof(mk_event_fdt_t)); if (!efdt) { mk_err("Event: could not allocate memory for event FD Table"); return -1; } /* * Despites what config->server_capacity says, we need to prepare to handle * a high number of file descriptors as process limit allows. */ ret = getrlimit(RLIMIT_NOFILE, &rlim); if (ret == -1) { mk_libc_error("getrlimit"); return -1; } efdt->size = rlim.rlim_cur; efdt->states = mk_mem_malloc_z(sizeof(struct mk_event_fd_state) * efdt->size); if (!efdt->states) { mk_err("Event: could not allocate memory for events states on FD Table"); return -1; } /* mark all file descriptors as available */ for (i = 0; i < efdt->size; i++) { efdt->states[i].fd = -1; efdt->states[i].mask = MK_EVENT_EMPTY; } mk_events_fdt = efdt; return 0; }