/* 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; }
int mk_patas_validate_node(const char *host, int port) { int i, j; char local_addr[16], node_addr[16]; struct hostent local, *node; struct in_addr **node_addr_list, **local_addr_list; memcpy(&local, gethostbyname("localhost"), sizeof(struct hostent)); node = gethostbyname(host); if (!node) { mk_warn("Could not determinate hostname"); return -1; } local_addr_list = (struct in_addr **) local.h_addr_list; node_addr_list = (struct in_addr **) node->h_addr_list; for (i=0; local_addr_list[i] != NULL; i++) { inet_ntop(PF_INET, local.h_addr_list[i], local_addr, 16 ); for (j=0; node_addr_list[j] != NULL; j++) { inet_ntop(PF_INET, node->h_addr_list[j], node_addr, 16); if (strcmp(local_addr, node_addr) == 0 && mk_api->config->serverport == port) { mk_warn("Node %s:%i = localhost:%i, skip node\n", host, port, port); return -1; } } } return 0; }
int mk_socket_ip_str(int socket_fd, char **buf, int size, unsigned long *len) { int ret; struct sockaddr_storage addr; socklen_t s_len = sizeof(addr); ret = getpeername(socket_fd, (struct sockaddr *) &addr, &s_len); if (mk_unlikely(ret == -1)) { MK_TRACE("[FD %i] Can't get addr for this socket", socket_fd); return -1; } errno = 0; if(addr.ss_family == AF_INET) { if((inet_ntop(AF_INET, &((struct sockaddr_in *)&addr)->sin_addr, *buf, size)) == NULL) { mk_warn("mk_socket_ip_str: Can't get the IP text form (%i)", errno); return -1; } } else if(addr.ss_family == AF_INET6) { if((inet_ntop(AF_INET6, &((struct sockaddr_in6 *)&addr)->sin6_addr, *buf, size)) == NULL) { mk_warn("mk_socket_ip_str: Can't get the IP text form (%i)", errno); return -1; } } *len = strlen(*buf); 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; }
/* Return the number of clients that can be attended */ unsigned int mk_server_capacity() { int ret; int cur; struct rlimit lim; /* Limit by system */ getrlimit(RLIMIT_NOFILE, &lim); cur = lim.rlim_cur; if (mk_config->fd_limit > cur) { lim.rlim_cur = mk_config->fd_limit; lim.rlim_max = mk_config->fd_limit; ret = setrlimit(RLIMIT_NOFILE, &lim); if (ret == -1) { mk_warn("Could not increase FDLimit to %i.", mk_config->fd_limit); } else { cur = mk_config->fd_limit; } } else if (mk_config->fd_limit > 0) { cur = mk_config->fd_limit; } return cur; }
/* Remove PID file */ int mk_utils_remove_pid(char *path) { if (unlink(path)) { mk_warn("cannot delete pidfile\n"); } return 0; }
int mk_conn_read(int socket) { int ret; struct client_session *cs; struct sched_list_node *sched; MK_TRACE("[FD %i] Connection Handler / read", socket); /* Plugin hook */ ret = mk_plugin_event_read(socket); switch(ret) { case MK_PLUGIN_RET_EVENT_OWNED: return MK_PLUGIN_RET_CONTINUE; case MK_PLUGIN_RET_EVENT_CLOSE: return -1; case MK_PLUGIN_RET_EVENT_CONTINUE: break; /* just return controller to invoker */ } sched = mk_sched_get_thread_conf(); cs = mk_session_get(socket); if (!cs) { /* Note: Linux don't set TCP_NODELAY socket flag by default */ if (mk_socket_set_tcp_nodelay(socket) != 0) { mk_warn("TCP_NODELAY failed"); } /* Create session for the client */ MK_TRACE("[FD %i] Create session", socket); cs = mk_session_create(socket, sched); if (!cs) { return -1; } } /* Read incomming data */ ret = mk_handler_read(socket, cs); if (ret > 0) { if (mk_http_pending_request(cs) == 0) { mk_epoll_change_mode(sched->epoll_fd, socket, MK_EPOLL_WRITE, MK_EPOLL_LEVEL_TRIGGERED); } else if (cs->body_length + 1 >= config->max_request_size) { /* * Request is incomplete and our buffer is full, * close connection */ mk_session_remove(socket); return -1; } else { MK_TRACE("[FD %i] waiting for pending data", socket); } } return ret; }
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; }
/* Remove PID file */ int mk_utils_remove_pid() { mk_user_undo_uidgid(); if (unlink(mk_config->pid_file_path)) { mk_warn("cannot delete pidfile\n"); } mk_config->pid_status = MK_FALSE; return 0; }
//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; }
int _mkp_network_io_bind(int socket_fd, const struct sockaddr *addr, socklen_t addrlen, int backlog) { int ret; ret = bind(socket_fd, addr, addrlen); if( ret == -1 ) { mk_warn("Error binding socket"); return ret; } ret = listen(socket_fd, backlog); if(ret == -1 ) { mk_warn("Error setting up the listener"); return -1; } return ret; }
/* * 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; }
int mk_socket_bind(int socket_fd, const struct sockaddr *addr, socklen_t addrlen, int backlog) { int ret; ret = bind(socket_fd, addr, addrlen); if( ret == -1 ) { mk_warn("Error binding socket"); return ret; } /* * Enable TCP_FASTOPEN by default: if for some reason this call fail, * it will not affect the behavior of the server, in order to succeed, * Monkey must be running in a Linux system with Kernel >= 3.7 and the * tcp_fastopen flag enabled here: * * # cat /proc/sys/net/ipv4/tcp_fastopen * * To enable this feature just do: * * # echo 1 > /proc/sys/net/ipv4/tcp_fastopen */ if (mk_config->kernel_features & MK_KERNEL_TCP_FASTOPEN) { ret = mk_socket_set_tcp_fastopen(socket_fd); if (ret == -1) { mk_warn("Could not set TCP_FASTOPEN"); } } ret = listen(socket_fd, backlog); if(ret == -1 ) { mk_warn("Error setting up the listener"); return -1; } return ret; }
/* Remove PID file */ int mk_utils_remove_pid() { unsigned long len = 0; char *filepath = NULL; mk_string_build(&filepath, &len, "%s.%d", config->pid_file_path, config->serverport); mk_user_undo_uidgid(); if (unlink(filepath)) { mk_warn("cannot delete pidfile\n"); } mk_mem_free(filepath); config->pid_status = MK_FALSE; 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; }
/* 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; }
/* Remove PID file */ int mk_utils_remove_pid() { unsigned long len = 0; char *filepath = NULL; struct mk_config_listener *listen; 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); mk_user_undo_uidgid(); if (unlink(filepath)) { mk_warn("cannot delete pidfile\n"); } mk_mem_free(filepath); config->pid_status = MK_FALSE; return 0; }
/* 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; }
void mk_server_loop(int server_fd) { int ret; int remote_fd; /* Activate TCP_DEFER_ACCEPT */ if (mk_socket_set_tcp_defer_accept(server_fd) != 0) { mk_warn("TCP_DEFER_ACCEPT failed"); } /* Rename worker */ mk_utils_worker_rename("monkey: server"); mk_info("HTTP Server started"); while (1) { remote_fd = mk_socket_accept(server_fd); if (mk_unlikely(remote_fd == -1)) { continue; } #ifdef TRACE MK_TRACE("New connection arrived: FD %i", remote_fd); int i; struct sched_list_node *node; node = sched_list; for (i=0; i < config->workers; i++) { MK_TRACE("Worker Status"); MK_TRACE(" WID %i / conx = %llu", node[i].idx, node[i].accepted_connections - node[i].closed_connections); } #endif /* Assign socket to worker thread */ ret = mk_sched_add_client(remote_fd); if (ret == -1) { close(remote_fd); } } }
/* MAIN */ int main(int argc, char **argv) { int opt; char *port_override = NULL; int workers_override = -1; int run_daemon = 0; int balancing_mode = MK_FALSE; int allow_shared_sockets = MK_FALSE; char *one_shot = NULL; char *pid_file = NULL; char *transport_layer = NULL; char *path_config = NULL; char *server_conf_file = NULL; char *plugin_load_conf_file = NULL; char *sites_conf_dir = NULL; char *plugins_conf_dir = NULL; char *mimes_conf_file = NULL; static const struct option long_opts[] = { { "configdir", required_argument, NULL, 'c' }, { "serverconf", required_argument, NULL, 's' }, { "build", no_argument, NULL, 'b' }, { "daemon", no_argument, NULL, 'D' }, { "pid-file", required_argument, NULL, 'I' }, { "port", required_argument, NULL, 'p' }, { "one-shot", required_argument, NULL, 'o' }, { "transport", required_argument, NULL, 't' }, { "workers", required_argument, NULL, 'w' }, { "version", no_argument, NULL, 'v' }, { "help", no_argument, NULL, 'h' }, { "mimes-conf-file", required_argument, NULL, 'm' }, { "plugin-load-conf-file", required_argument, NULL, 'l' }, { "plugins-conf-dir", required_argument, NULL, 'P' }, { "sites-conf-dir", required_argument, NULL, 'S' }, { "balancing-mode", no_argument, NULL, 'B' }, { "allow-shared-sockets", no_argument, NULL, 'T' }, { NULL, 0, NULL, 0 } }; while ((opt = getopt_long(argc, argv, "bDI:Svhp:o:t:w:c:s:m:l:P:S:BT", long_opts, NULL)) != -1) { switch (opt) { case 'b': mk_build_info(); exit(EXIT_SUCCESS); case 'v': mk_version(); exit(EXIT_SUCCESS); case 'h': mk_help(EXIT_SUCCESS); case 'D': run_daemon = 1; break; case 'I': pid_file = optarg; break; case 'p': port_override = optarg; break; case 'o': one_shot = optarg; break; case 't': transport_layer = mk_string_dup(optarg); break; case 'w': workers_override = atoi(optarg); break; case 'c': path_config = optarg; break; case 's': server_conf_file = optarg; break; case 'm': mimes_conf_file = optarg; break; case 'P': plugins_conf_dir = optarg; break; case 'S': sites_conf_dir = optarg; break; case 'B': balancing_mode = MK_TRUE; break; case 'T': allow_shared_sockets = MK_TRUE; break; case 'l': plugin_load_conf_file = optarg; break; case '?': mk_help(EXIT_FAILURE); } } /* setup basic configurations */ mk_config = mk_config_init(); /* Init Kernel version data */ mk_kernel_init(); mk_kernel_features(); /* set configuration path */ if (!path_config) { mk_config->path_config = MK_PATH_CONF; } else { mk_config->path_config = path_config; } /* set target configuration file for the server */ if (!server_conf_file) { mk_config->server_conf_file = MK_DEFAULT_CONFIG_FILE; } else { mk_config->server_conf_file = server_conf_file; } if (!pid_file) { mk_config->pid_file_path = NULL; } else { mk_config->pid_file_path = pid_file; } if (run_daemon) { mk_config->is_daemon = MK_TRUE; } else { mk_config->is_daemon = MK_FALSE; } if (!mimes_conf_file) { mk_config->mimes_conf_file = MK_DEFAULT_MIMES_CONF_FILE; } else { mk_config->mimes_conf_file = mimes_conf_file; } if (!plugin_load_conf_file) { mk_config->plugin_load_conf_file = MK_DEFAULT_PLUGIN_LOAD_CONF_FILE; } else { mk_config->plugin_load_conf_file = plugin_load_conf_file; } if (!sites_conf_dir) { mk_config->sites_conf_dir = MK_DEFAULT_SITES_CONF_DIR; } else { mk_config->sites_conf_dir = sites_conf_dir; } if (!plugins_conf_dir) { mk_config->plugins_conf_dir = MK_DEFAULT_PLUGINS_CONF_DIR; } else { mk_config->plugins_conf_dir = plugins_conf_dir; } /* Override some configuration */ mk_config->one_shot = one_shot; mk_config->port_override = port_override; mk_config->transport_layer = transport_layer; #ifdef TRACE monkey_init_time = time(NULL); MK_TRACE("Monkey TRACE is enabled"); env_trace_filter = getenv("MK_TRACE_FILTER"); pthread_mutex_init(&mutex_trace, (pthread_mutexattr_t *) NULL); #endif pthread_mutex_init(&mutex_port_init, (pthread_mutexattr_t *) NULL); mk_version(); mk_signal_init(); #ifdef LINUX_TRACE mk_info("Linux Trace enabled"); #endif /* Override number of thread workers */ if (workers_override >= 0) { mk_config->workers = workers_override; } else { mk_config->workers = -1; } /* Core and Scheduler setup */ mk_config_start_configure(); mk_sched_init(); if (balancing_mode == MK_TRUE) { mk_config->scheduler_mode = MK_SCHEDULER_FAIR_BALANCING; } /* Clock init that must happen before starting threads */ mk_clock_sequential_init(); /* Load plugins */ mk_plugin_api_init(); mk_plugin_load_all(); /* Running Monkey as daemon */ if (mk_config->is_daemon == MK_TRUE) { mk_utils_set_daemon(); } /* Register PID of Monkey */ mk_utils_register_pid(); /* Workers: logger and clock */ mk_clock_tid = mk_utils_worker_spawn((void *) mk_clock_worker_init, NULL); /* Init thread keys */ mk_thread_keys_init(); /* Configuration sanity check */ mk_config_sanity_check(); if (mk_config->scheduler_mode == MK_SCHEDULER_REUSEPORT && mk_config_listen_check_busy() == MK_TRUE && allow_shared_sockets == MK_FALSE) { mk_warn("Some Listen interface is busy, re-try using -T. Aborting."); exit(EXIT_FAILURE); } /* Invoke Plugin PRCTX hooks */ mk_plugin_core_process(); /* Launch monkey http workers */ MK_TLS_INIT(); mk_server_launch_workers(); /* Print server details */ mk_details(); /* Change process owner */ mk_user_set_uidgid(); /* Server loop, let's listen for incomming clients */ mk_server_loop(); mk_mem_free(mk_config); return 0; }
/* 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; }