10Sigor@sysoev.ru
20Sigor@sysoev.ru /*
384Smax.romanov@nginx.com * Copyright (C) Max Romanov
40Sigor@sysoev.ru * Copyright (C) Igor Sysoev
50Sigor@sysoev.ru * Copyright (C) Valentin V. Bartenev
60Sigor@sysoev.ru * Copyright (C) NGINX, Inc.
70Sigor@sysoev.ru */
80Sigor@sysoev.ru
90Sigor@sysoev.ru #include <nxt_main.h>
1020Sigor@sysoev.ru #include <nxt_runtime.h>
11240Sigor@sysoev.ru #include <nxt_main_process.h>
12431Sigor@sysoev.ru #include <nxt_router.h>
13431Sigor@sysoev.ru #include <nxt_http.h>
14444Sigor@sysoev.ru #include <nxt_application.h>
15743Smax.romanov@nginx.com #include <nxt_unit.h>
16723Smax.romanov@nginx.com #include <nxt_port_memory_int.h>
171579St.nateldemoura@f5.com #include <nxt_isolation.h>
180Sigor@sysoev.ru
19216Sigor@sysoev.ru #include <glob.h>
200Sigor@sysoev.ru
211489St.nateldemoura@f5.com #if (NXT_HAVE_PR_SET_NO_NEW_PRIVS)
221489St.nateldemoura@f5.com #include <sys/prctl.h>
231489St.nateldemoura@f5.com #endif
241489St.nateldemoura@f5.com
25216Sigor@sysoev.ru
26216Sigor@sysoev.ru typedef struct {
27356Svbart@nginx.com nxt_app_type_t type;
28356Svbart@nginx.com nxt_str_t version;
29356Svbart@nginx.com nxt_str_t file;
301489St.nateldemoura@f5.com nxt_array_t *mounts;
31216Sigor@sysoev.ru } nxt_module_t;
32216Sigor@sysoev.ru
33216Sigor@sysoev.ru
341488St.nateldemoura@f5.com static nxt_int_t nxt_discovery_start(nxt_task_t *task,
351488St.nateldemoura@f5.com nxt_process_data_t *data);
36216Sigor@sysoev.ru static nxt_buf_t *nxt_discovery_modules(nxt_task_t *task, const char *path);
37216Sigor@sysoev.ru static nxt_int_t nxt_discovery_module(nxt_task_t *task, nxt_mp_t *mp,
38216Sigor@sysoev.ru nxt_array_t *modules, const char *name);
39549Svbart@nginx.com static void nxt_discovery_completion_handler(nxt_task_t *task, void *obj,
40549Svbart@nginx.com void *data);
41549Svbart@nginx.com static void nxt_discovery_quit(nxt_task_t *task, nxt_port_recv_msg_t *msg,
42549Svbart@nginx.com void *data);
43216Sigor@sysoev.ru static nxt_app_module_t *nxt_app_module_load(nxt_task_t *task,
44216Sigor@sysoev.ru const char *name);
451998St.nateldemoura@f5.com static nxt_int_t nxt_proto_setup(nxt_task_t *task, nxt_process_t *process);
461998St.nateldemoura@f5.com static nxt_int_t nxt_proto_start(nxt_task_t *task, nxt_process_data_t *data);
471488St.nateldemoura@f5.com static nxt_int_t nxt_app_setup(nxt_task_t *task, nxt_process_t *process);
48678Svbart@nginx.com static nxt_int_t nxt_app_set_environment(nxt_conf_value_t *environment);
491998St.nateldemoura@f5.com static void nxt_proto_start_process_handler(nxt_task_t *task,
501998St.nateldemoura@f5.com nxt_port_recv_msg_t *msg);
511998St.nateldemoura@f5.com static void nxt_proto_quit_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg);
521998St.nateldemoura@f5.com static void nxt_proto_process_created_handler(nxt_task_t *task,
531998St.nateldemoura@f5.com nxt_port_recv_msg_t *msg);
541998St.nateldemoura@f5.com static void nxt_proto_quit_children(nxt_task_t *task);
551998St.nateldemoura@f5.com static nxt_process_t *nxt_proto_process_find(nxt_task_t *task, nxt_pid_t pid);
561998St.nateldemoura@f5.com static void nxt_proto_process_add(nxt_task_t *task, nxt_process_t *process);
571998St.nateldemoura@f5.com static nxt_process_t *nxt_proto_process_remove(nxt_task_t *task, nxt_pid_t pid);
581489St.nateldemoura@f5.com static u_char *nxt_cstr_dup(nxt_mp_t *mp, u_char *dst, u_char *src);
591998St.nateldemoura@f5.com static void nxt_proto_signal_handler(nxt_task_t *task, void *obj, void *data);
601998St.nateldemoura@f5.com static void nxt_proto_sigterm_handler(nxt_task_t *task, void *obj, void *data);
611998St.nateldemoura@f5.com static void nxt_proto_sigchld_handler(nxt_task_t *task, void *obj, void *data);
621489St.nateldemoura@f5.com
631489St.nateldemoura@f5.com
641488St.nateldemoura@f5.com nxt_str_t nxt_server = nxt_string(NXT_SERVER);
650Sigor@sysoev.ru
66216Sigor@sysoev.ru
67258Sigor@sysoev.ru static uint32_t compat[] = {
68360Sigor@sysoev.ru NXT_VERNUM, NXT_DEBUG,
69258Sigor@sysoev.ru };
70258Sigor@sysoev.ru
71258Sigor@sysoev.ru
721998St.nateldemoura@f5.com static nxt_lvlhsh_t nxt_proto_processes;
731998St.nateldemoura@f5.com static nxt_queue_t nxt_proto_children;
741998St.nateldemoura@f5.com static nxt_bool_t nxt_proto_exiting;
751998St.nateldemoura@f5.com
761998St.nateldemoura@f5.com static nxt_app_module_t *nxt_app;
771998St.nateldemoura@f5.com static nxt_common_app_conf_t *nxt_app_conf;
78417Svbart@nginx.com
79417Svbart@nginx.com
801488St.nateldemoura@f5.com static const nxt_port_handlers_t nxt_discovery_process_port_handlers = {
811488St.nateldemoura@f5.com .quit = nxt_signal_quit_handler,
821488St.nateldemoura@f5.com .new_port = nxt_port_new_port_handler,
831488St.nateldemoura@f5.com .change_file = nxt_port_change_log_file_handler,
841488St.nateldemoura@f5.com .mmap = nxt_port_mmap_handler,
851488St.nateldemoura@f5.com .data = nxt_port_data_handler,
861488St.nateldemoura@f5.com .remove_pid = nxt_port_remove_pid_handler,
871488St.nateldemoura@f5.com .rpc_ready = nxt_port_rpc_handler,
881488St.nateldemoura@f5.com .rpc_error = nxt_port_rpc_handler,
891488St.nateldemoura@f5.com };
901488St.nateldemoura@f5.com
911488St.nateldemoura@f5.com
921998St.nateldemoura@f5.com const nxt_sig_event_t nxt_prototype_signals[] = {
931998St.nateldemoura@f5.com nxt_event_signal(SIGHUP, nxt_proto_signal_handler),
941998St.nateldemoura@f5.com nxt_event_signal(SIGINT, nxt_proto_sigterm_handler),
951998St.nateldemoura@f5.com nxt_event_signal(SIGQUIT, nxt_proto_sigterm_handler),
961998St.nateldemoura@f5.com nxt_event_signal(SIGTERM, nxt_proto_sigterm_handler),
971998St.nateldemoura@f5.com nxt_event_signal(SIGCHLD, nxt_proto_sigchld_handler),
981998St.nateldemoura@f5.com nxt_event_signal_end,
991998St.nateldemoura@f5.com };
1001998St.nateldemoura@f5.com
1011998St.nateldemoura@f5.com
1021998St.nateldemoura@f5.com static const nxt_port_handlers_t nxt_proto_process_port_handlers = {
1031998St.nateldemoura@f5.com .quit = nxt_proto_quit_handler,
1041998St.nateldemoura@f5.com .change_file = nxt_port_change_log_file_handler,
1051998St.nateldemoura@f5.com .new_port = nxt_port_new_port_handler,
1061998St.nateldemoura@f5.com .process_created = nxt_proto_process_created_handler,
1071998St.nateldemoura@f5.com .process_ready = nxt_port_process_ready_handler,
1081998St.nateldemoura@f5.com .remove_pid = nxt_port_remove_pid_handler,
1091998St.nateldemoura@f5.com .start_process = nxt_proto_start_process_handler,
1101998St.nateldemoura@f5.com .rpc_ready = nxt_port_rpc_handler,
1111998St.nateldemoura@f5.com .rpc_error = nxt_port_rpc_handler,
1121998St.nateldemoura@f5.com };
1131998St.nateldemoura@f5.com
1141998St.nateldemoura@f5.com
1151488St.nateldemoura@f5.com static const nxt_port_handlers_t nxt_app_process_port_handlers = {
1161488St.nateldemoura@f5.com .quit = nxt_signal_quit_handler,
1171488St.nateldemoura@f5.com .rpc_ready = nxt_port_rpc_handler,
1181488St.nateldemoura@f5.com .rpc_error = nxt_port_rpc_handler,
1191488St.nateldemoura@f5.com };
1201488St.nateldemoura@f5.com
1211488St.nateldemoura@f5.com
1221488St.nateldemoura@f5.com const nxt_process_init_t nxt_discovery_process = {
1231488St.nateldemoura@f5.com .name = "discovery",
1241488St.nateldemoura@f5.com .type = NXT_PROCESS_DISCOVERY,
1251488St.nateldemoura@f5.com .prefork = NULL,
1261488St.nateldemoura@f5.com .restart = 0,
1271488St.nateldemoura@f5.com .setup = nxt_process_core_setup,
1281488St.nateldemoura@f5.com .start = nxt_discovery_start,
1291488St.nateldemoura@f5.com .port_handlers = &nxt_discovery_process_port_handlers,
1301488St.nateldemoura@f5.com .signals = nxt_process_signals,
1311488St.nateldemoura@f5.com };
1321488St.nateldemoura@f5.com
1331488St.nateldemoura@f5.com
1341998St.nateldemoura@f5.com const nxt_process_init_t nxt_proto_process = {
1351998St.nateldemoura@f5.com .type = NXT_PROCESS_PROTOTYPE,
1361998St.nateldemoura@f5.com .prefork = nxt_isolation_main_prefork,
1371998St.nateldemoura@f5.com .restart = 0,
1381998St.nateldemoura@f5.com .setup = nxt_proto_setup,
1391998St.nateldemoura@f5.com .start = nxt_proto_start,
1401998St.nateldemoura@f5.com .port_handlers = &nxt_proto_process_port_handlers,
1411998St.nateldemoura@f5.com .signals = nxt_prototype_signals,
1421998St.nateldemoura@f5.com };
1431998St.nateldemoura@f5.com
1441998St.nateldemoura@f5.com
1451488St.nateldemoura@f5.com const nxt_process_init_t nxt_app_process = {
1461488St.nateldemoura@f5.com .type = NXT_PROCESS_APP,
1471488St.nateldemoura@f5.com .setup = nxt_app_setup,
1481998St.nateldemoura@f5.com .start = NULL,
1491998St.nateldemoura@f5.com .prefork = NULL,
1501488St.nateldemoura@f5.com .restart = 0,
1511488St.nateldemoura@f5.com .port_handlers = &nxt_app_process_port_handlers,
1521488St.nateldemoura@f5.com .signals = nxt_process_signals,
1531488St.nateldemoura@f5.com };
1541488St.nateldemoura@f5.com
1551488St.nateldemoura@f5.com
1561488St.nateldemoura@f5.com static nxt_int_t
nxt_discovery_start(nxt_task_t * task,nxt_process_data_t * data)1571488St.nateldemoura@f5.com nxt_discovery_start(nxt_task_t *task, nxt_process_data_t *data)
158216Sigor@sysoev.ru {
159549Svbart@nginx.com uint32_t stream;
160549Svbart@nginx.com nxt_buf_t *b;
161549Svbart@nginx.com nxt_int_t ret;
162549Svbart@nginx.com nxt_port_t *main_port, *discovery_port;
163549Svbart@nginx.com nxt_runtime_t *rt;
164216Sigor@sysoev.ru
1651488St.nateldemoura@f5.com nxt_log(task, NXT_LOG_INFO, "discovery started");
166216Sigor@sysoev.ru
167233Sigor@sysoev.ru rt = task->thread->runtime;
168216Sigor@sysoev.ru
169233Sigor@sysoev.ru b = nxt_discovery_modules(task, rt->modules);
170250Sigor@sysoev.ru if (nxt_slow_path(b == NULL)) {
171549Svbart@nginx.com return NXT_ERROR;
172250Sigor@sysoev.ru }
173233Sigor@sysoev.ru
174240Sigor@sysoev.ru main_port = rt->port_by_type[NXT_PROCESS_MAIN];
175549Svbart@nginx.com discovery_port = rt->port_by_type[NXT_PROCESS_DISCOVERY];
176216Sigor@sysoev.ru
177549Svbart@nginx.com stream = nxt_port_rpc_register_handler(task, discovery_port,
178549Svbart@nginx.com nxt_discovery_quit,
179549Svbart@nginx.com nxt_discovery_quit,
180549Svbart@nginx.com main_port->pid, NULL);
181549Svbart@nginx.com
182645Svbart@nginx.com if (nxt_slow_path(stream == 0)) {
183645Svbart@nginx.com return NXT_ERROR;
184645Svbart@nginx.com }
185645Svbart@nginx.com
186549Svbart@nginx.com ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_MODULES, -1,
187549Svbart@nginx.com stream, discovery_port->id, b);
188549Svbart@nginx.com
189549Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) {
190549Svbart@nginx.com nxt_port_rpc_cancel(task, discovery_port, stream);
191549Svbart@nginx.com return NXT_ERROR;
192549Svbart@nginx.com }
193216Sigor@sysoev.ru
194216Sigor@sysoev.ru return NXT_OK;
195216Sigor@sysoev.ru }
196216Sigor@sysoev.ru
197216Sigor@sysoev.ru
198216Sigor@sysoev.ru static nxt_buf_t *
nxt_discovery_modules(nxt_task_t * task,const char * path)199216Sigor@sysoev.ru nxt_discovery_modules(nxt_task_t *task, const char *path)
200216Sigor@sysoev.ru {
2011489St.nateldemoura@f5.com char *name;
2021489St.nateldemoura@f5.com u_char *p, *end;
2031489St.nateldemoura@f5.com size_t size;
2041489St.nateldemoura@f5.com glob_t glb;
2051489St.nateldemoura@f5.com nxt_mp_t *mp;
2061489St.nateldemoura@f5.com nxt_buf_t *b;
2071489St.nateldemoura@f5.com nxt_int_t ret;
2081489St.nateldemoura@f5.com nxt_uint_t i, n, j;
2091489St.nateldemoura@f5.com nxt_array_t *modules, *mounts;
2101489St.nateldemoura@f5.com nxt_module_t *module;
2111489St.nateldemoura@f5.com nxt_fs_mount_t *mnt;
212216Sigor@sysoev.ru
213216Sigor@sysoev.ru b = NULL;
214216Sigor@sysoev.ru
215216Sigor@sysoev.ru mp = nxt_mp_create(1024, 128, 256, 32);
216216Sigor@sysoev.ru if (mp == NULL) {
217216Sigor@sysoev.ru return b;
218216Sigor@sysoev.ru }
219216Sigor@sysoev.ru
220216Sigor@sysoev.ru ret = glob(path, 0, NULL, &glb);
221216Sigor@sysoev.ru
222250Sigor@sysoev.ru n = glb.gl_pathc;
223250Sigor@sysoev.ru
224250Sigor@sysoev.ru if (ret != 0) {
225250Sigor@sysoev.ru nxt_log(task, NXT_LOG_NOTICE,
226250Sigor@sysoev.ru "no modules matching: \"%s\" found", path);
227250Sigor@sysoev.ru n = 0;
228250Sigor@sysoev.ru }
229216Sigor@sysoev.ru
230250Sigor@sysoev.ru modules = nxt_array_create(mp, n, sizeof(nxt_module_t));
231250Sigor@sysoev.ru if (modules == NULL) {
232250Sigor@sysoev.ru goto fail;
233250Sigor@sysoev.ru }
234250Sigor@sysoev.ru
235250Sigor@sysoev.ru for (i = 0; i < n; i++) {
236250Sigor@sysoev.ru name = glb.gl_pathv[i];
237250Sigor@sysoev.ru
238250Sigor@sysoev.ru ret = nxt_discovery_module(task, mp, modules, name);
239250Sigor@sysoev.ru if (ret != NXT_OK) {
240216Sigor@sysoev.ru goto fail;
241216Sigor@sysoev.ru }
242250Sigor@sysoev.ru }
243216Sigor@sysoev.ru
244703Svbart@nginx.com size = nxt_length("[]");
245250Sigor@sysoev.ru module = modules->elts;
246250Sigor@sysoev.ru n = modules->nelts;
247216Sigor@sysoev.ru
248250Sigor@sysoev.ru for (i = 0; i < n; i++) {
249356Svbart@nginx.com nxt_debug(task, "module: %d %V %V",
250356Svbart@nginx.com module[i].type, &module[i].version, &module[i].file);
251216Sigor@sysoev.ru
252703Svbart@nginx.com size += nxt_length("{\"type\": ,");
253703Svbart@nginx.com size += nxt_length(" \"version\": \"\",");
2541489St.nateldemoura@f5.com size += nxt_length(" \"file\": \"\",");
2551489St.nateldemoura@f5.com size += nxt_length(" \"mounts\": []},");
256216Sigor@sysoev.ru
257356Svbart@nginx.com size += NXT_INT_T_LEN
258250Sigor@sysoev.ru + module[i].version.length
259250Sigor@sysoev.ru + module[i].file.length;
2601489St.nateldemoura@f5.com
2611489St.nateldemoura@f5.com mounts = module[i].mounts;
2621489St.nateldemoura@f5.com
2631489St.nateldemoura@f5.com size += mounts->nelts * nxt_length("{\"src\": \"\", \"dst\": \"\", "
2641673St.nateldemoura@f5.com "\"type\": , \"name\": \"\", "
2651673St.nateldemoura@f5.com "\"flags\": , \"data\": \"\"},");
2661489St.nateldemoura@f5.com
2671489St.nateldemoura@f5.com mnt = mounts->elts;
2681489St.nateldemoura@f5.com
2691489St.nateldemoura@f5.com for (j = 0; j < mounts->nelts; j++) {
2701489St.nateldemoura@f5.com size += nxt_strlen(mnt[j].src) + nxt_strlen(mnt[j].dst)
2711673St.nateldemoura@f5.com + nxt_strlen(mnt[j].name) + (2 * NXT_INT_T_LEN)
2721489St.nateldemoura@f5.com + (mnt[j].data == NULL ? 0 : nxt_strlen(mnt[j].data));
2731489St.nateldemoura@f5.com }
274250Sigor@sysoev.ru }
275216Sigor@sysoev.ru
276250Sigor@sysoev.ru b = nxt_buf_mem_alloc(mp, size, 0);
277250Sigor@sysoev.ru if (b == NULL) {
278250Sigor@sysoev.ru goto fail;
279250Sigor@sysoev.ru }
280216Sigor@sysoev.ru
281250Sigor@sysoev.ru b->completion_handler = nxt_discovery_completion_handler;
282216Sigor@sysoev.ru
283250Sigor@sysoev.ru p = b->mem.free;
284250Sigor@sysoev.ru end = b->mem.end;
285250Sigor@sysoev.ru *p++ = '[';
286216Sigor@sysoev.ru
287250Sigor@sysoev.ru for (i = 0; i < n; i++) {
2881489St.nateldemoura@f5.com mounts = module[i].mounts;
2891489St.nateldemoura@f5.com
2901489St.nateldemoura@f5.com p = nxt_sprintf(p, end, "{\"type\": %d, \"version\": \"%V\", "
2911489St.nateldemoura@f5.com "\"file\": \"%V\", \"mounts\": [",
2921489St.nateldemoura@f5.com module[i].type, &module[i].version, &module[i].file);
2931489St.nateldemoura@f5.com
2941489St.nateldemoura@f5.com mnt = mounts->elts;
2951489St.nateldemoura@f5.com for (j = 0; j < mounts->nelts; j++) {
2961489St.nateldemoura@f5.com p = nxt_sprintf(p, end,
2971489St.nateldemoura@f5.com "{\"src\": \"%s\", \"dst\": \"%s\", "
2981673St.nateldemoura@f5.com "\"name\": \"%s\", \"type\": %d, \"flags\": %d, "
2991489St.nateldemoura@f5.com "\"data\": \"%s\"},",
3001673St.nateldemoura@f5.com mnt[j].src, mnt[j].dst, mnt[j].name, mnt[j].type,
3011673St.nateldemoura@f5.com mnt[j].flags,
3021489St.nateldemoura@f5.com mnt[j].data == NULL ? (u_char *) "" : mnt[j].data);
3031489St.nateldemoura@f5.com }
3041489St.nateldemoura@f5.com
3051489St.nateldemoura@f5.com *p++ = ']';
3061489St.nateldemoura@f5.com *p++ = '}';
3071489St.nateldemoura@f5.com *p++ = ',';
308250Sigor@sysoev.ru }
309216Sigor@sysoev.ru
310250Sigor@sysoev.ru *p++ = ']';
3111489St.nateldemoura@f5.com
3121515Smax.romanov@nginx.com if (nxt_slow_path(p > end)) {
3131489St.nateldemoura@f5.com nxt_alert(task, "discovery write past the buffer");
3141489St.nateldemoura@f5.com goto fail;
3151489St.nateldemoura@f5.com }
3161489St.nateldemoura@f5.com
317250Sigor@sysoev.ru b->mem.free = p;
318216Sigor@sysoev.ru
319216Sigor@sysoev.ru fail:
320216Sigor@sysoev.ru
321216Sigor@sysoev.ru globfree(&glb);
322216Sigor@sysoev.ru
323216Sigor@sysoev.ru return b;
324216Sigor@sysoev.ru }
325216Sigor@sysoev.ru
326216Sigor@sysoev.ru
327216Sigor@sysoev.ru static nxt_int_t
nxt_discovery_module(nxt_task_t * task,nxt_mp_t * mp,nxt_array_t * modules,const char * name)328216Sigor@sysoev.ru nxt_discovery_module(nxt_task_t *task, nxt_mp_t *mp, nxt_array_t *modules,
329216Sigor@sysoev.ru const char *name)
330216Sigor@sysoev.ru {
3311489St.nateldemoura@f5.com void *dl;
3321489St.nateldemoura@f5.com nxt_str_t version;
3331489St.nateldemoura@f5.com nxt_int_t ret;
3341489St.nateldemoura@f5.com nxt_uint_t i, j, n;
3351489St.nateldemoura@f5.com nxt_array_t *mounts;
3361489St.nateldemoura@f5.com nxt_module_t *module;
3371489St.nateldemoura@f5.com nxt_app_type_t type;
3381489St.nateldemoura@f5.com nxt_fs_mount_t *to;
3391489St.nateldemoura@f5.com nxt_app_module_t *app;
3401489St.nateldemoura@f5.com const nxt_fs_mount_t *from;
341216Sigor@sysoev.ru
342216Sigor@sysoev.ru /*
343216Sigor@sysoev.ru * Only memory allocation failure should return NXT_ERROR.
344216Sigor@sysoev.ru * Any module processing errors are ignored.
345216Sigor@sysoev.ru */
346216Sigor@sysoev.ru ret = NXT_ERROR;
347216Sigor@sysoev.ru
348216Sigor@sysoev.ru dl = dlopen(name, RTLD_GLOBAL | RTLD_NOW);
349216Sigor@sysoev.ru
350216Sigor@sysoev.ru if (dl == NULL) {
351564Svbart@nginx.com nxt_alert(task, "dlopen(\"%s\"), failed: \"%s\"", name, dlerror());
352216Sigor@sysoev.ru return NXT_OK;
353216Sigor@sysoev.ru }
354216Sigor@sysoev.ru
355216Sigor@sysoev.ru app = dlsym(dl, "nxt_app_module");
356216Sigor@sysoev.ru
357216Sigor@sysoev.ru if (app != NULL) {
358612Salexander.borisov@nginx.com nxt_log(task, NXT_LOG_NOTICE, "module: %V %s \"%s\"",
359612Salexander.borisov@nginx.com &app->type, app->version, name);
360258Sigor@sysoev.ru
361258Sigor@sysoev.ru if (app->compat_length != sizeof(compat)
362258Sigor@sysoev.ru || nxt_memcmp(app->compat, compat, sizeof(compat)) != 0)
363258Sigor@sysoev.ru {
364258Sigor@sysoev.ru nxt_log(task, NXT_LOG_NOTICE, "incompatible module %s", name);
365258Sigor@sysoev.ru
366258Sigor@sysoev.ru goto done;
367258Sigor@sysoev.ru }
368216Sigor@sysoev.ru
369356Svbart@nginx.com type = nxt_app_parse_type(app->type.start, app->type.length);
370356Svbart@nginx.com
371356Svbart@nginx.com if (type == NXT_APP_UNKNOWN) {
372494Spluknet@nginx.com nxt_log(task, NXT_LOG_NOTICE, "unknown module type %V", &app->type);
373356Svbart@nginx.com
374356Svbart@nginx.com goto done;
375356Svbart@nginx.com }
376356Svbart@nginx.com
377216Sigor@sysoev.ru module = modules->elts;
378216Sigor@sysoev.ru n = modules->nelts;
379216Sigor@sysoev.ru
380612Salexander.borisov@nginx.com version.start = (u_char *) app->version;
381612Salexander.borisov@nginx.com version.length = nxt_strlen(app->version);
382612Salexander.borisov@nginx.com
383216Sigor@sysoev.ru for (i = 0; i < n; i++) {
384356Svbart@nginx.com if (type == module[i].type
385612Salexander.borisov@nginx.com && nxt_strstr_eq(&module[i].version, &version))
386258Sigor@sysoev.ru {
387216Sigor@sysoev.ru nxt_log(task, NXT_LOG_NOTICE,
388216Sigor@sysoev.ru "ignoring %s module with the same "
389267Sigor@sysoev.ru "application language version %V %V as in %V",
390655Svbart@nginx.com name, &app->type, &version, &module[i].file);
391216Sigor@sysoev.ru
392216Sigor@sysoev.ru goto done;
393216Sigor@sysoev.ru }
394216Sigor@sysoev.ru }
395216Sigor@sysoev.ru
396216Sigor@sysoev.ru module = nxt_array_add(modules);
397216Sigor@sysoev.ru if (module == NULL) {
398216Sigor@sysoev.ru goto fail;
399216Sigor@sysoev.ru }
400216Sigor@sysoev.ru
401356Svbart@nginx.com module->type = type;
402216Sigor@sysoev.ru
403612Salexander.borisov@nginx.com nxt_str_dup(mp, &module->version, &version);
404612Salexander.borisov@nginx.com if (module->version.start == NULL) {
405216Sigor@sysoev.ru goto fail;
406216Sigor@sysoev.ru }
407216Sigor@sysoev.ru
408216Sigor@sysoev.ru module->file.length = nxt_strlen(name);
409216Sigor@sysoev.ru
410216Sigor@sysoev.ru module->file.start = nxt_mp_alloc(mp, module->file.length);
411216Sigor@sysoev.ru if (module->file.start == NULL) {
412216Sigor@sysoev.ru goto fail;
413216Sigor@sysoev.ru }
414216Sigor@sysoev.ru
415216Sigor@sysoev.ru nxt_memcpy(module->file.start, name, module->file.length);
416216Sigor@sysoev.ru
4171489St.nateldemoura@f5.com module->mounts = nxt_array_create(mp, app->nmounts,
4181489St.nateldemoura@f5.com sizeof(nxt_fs_mount_t));
4191489St.nateldemoura@f5.com
4201489St.nateldemoura@f5.com if (nxt_slow_path(module->mounts == NULL)) {
4211489St.nateldemoura@f5.com goto fail;
4221489St.nateldemoura@f5.com }
4231489St.nateldemoura@f5.com
4241489St.nateldemoura@f5.com mounts = module->mounts;
4251489St.nateldemoura@f5.com
4261489St.nateldemoura@f5.com for (j = 0; j < app->nmounts; j++) {
4271489St.nateldemoura@f5.com from = &app->mounts[j];
4281489St.nateldemoura@f5.com to = nxt_array_zero_add(mounts);
4291489St.nateldemoura@f5.com if (nxt_slow_path(to == NULL)) {
4301489St.nateldemoura@f5.com goto fail;
4311489St.nateldemoura@f5.com }
4321489St.nateldemoura@f5.com
4331489St.nateldemoura@f5.com to->src = nxt_cstr_dup(mp, to->src, from->src);
4341489St.nateldemoura@f5.com if (nxt_slow_path(to->src == NULL)) {
4351489St.nateldemoura@f5.com goto fail;
4361489St.nateldemoura@f5.com }
4371489St.nateldemoura@f5.com
4381489St.nateldemoura@f5.com to->dst = nxt_cstr_dup(mp, to->dst, from->dst);
4391489St.nateldemoura@f5.com if (nxt_slow_path(to->dst == NULL)) {
4401489St.nateldemoura@f5.com goto fail;
4411489St.nateldemoura@f5.com }
4421489St.nateldemoura@f5.com
4431673St.nateldemoura@f5.com to->name = nxt_cstr_dup(mp, to->name, from->name);
4441673St.nateldemoura@f5.com if (nxt_slow_path(to->name == NULL)) {
4451489St.nateldemoura@f5.com goto fail;
4461489St.nateldemoura@f5.com }
4471489St.nateldemoura@f5.com
4481673St.nateldemoura@f5.com to->type = from->type;
4491673St.nateldemoura@f5.com
4501489St.nateldemoura@f5.com if (from->data != NULL) {
4511489St.nateldemoura@f5.com to->data = nxt_cstr_dup(mp, to->data, from->data);
4521489St.nateldemoura@f5.com if (nxt_slow_path(to->data == NULL)) {
4531489St.nateldemoura@f5.com goto fail;
4541489St.nateldemoura@f5.com }
4551489St.nateldemoura@f5.com }
4561489St.nateldemoura@f5.com
4571489St.nateldemoura@f5.com to->flags = from->flags;
4581489St.nateldemoura@f5.com }
4591489St.nateldemoura@f5.com
460216Sigor@sysoev.ru } else {
461564Svbart@nginx.com nxt_alert(task, "dlsym(\"%s\"), failed: \"%s\"", name, dlerror());
462216Sigor@sysoev.ru }
463216Sigor@sysoev.ru
464216Sigor@sysoev.ru done:
465216Sigor@sysoev.ru
466216Sigor@sysoev.ru ret = NXT_OK;
467216Sigor@sysoev.ru
468216Sigor@sysoev.ru fail:
469216Sigor@sysoev.ru
470216Sigor@sysoev.ru if (dlclose(dl) != 0) {
471564Svbart@nginx.com nxt_alert(task, "dlclose(\"%s\"), failed: \"%s\"", name, dlerror());
472216Sigor@sysoev.ru }
473216Sigor@sysoev.ru
474216Sigor@sysoev.ru return ret;
475216Sigor@sysoev.ru }
476216Sigor@sysoev.ru
477216Sigor@sysoev.ru
478549Svbart@nginx.com static void
nxt_discovery_completion_handler(nxt_task_t * task,void * obj,void * data)479549Svbart@nginx.com nxt_discovery_completion_handler(nxt_task_t *task, void *obj, void *data)
480549Svbart@nginx.com {
481549Svbart@nginx.com nxt_mp_t *mp;
482549Svbart@nginx.com nxt_buf_t *b;
483549Svbart@nginx.com
484549Svbart@nginx.com b = obj;
485549Svbart@nginx.com mp = b->data;
486549Svbart@nginx.com
487549Svbart@nginx.com nxt_mp_destroy(mp);
488549Svbart@nginx.com }
489549Svbart@nginx.com
490549Svbart@nginx.com
491549Svbart@nginx.com static void
nxt_discovery_quit(nxt_task_t * task,nxt_port_recv_msg_t * msg,void * data)492549Svbart@nginx.com nxt_discovery_quit(nxt_task_t *task, nxt_port_recv_msg_t *msg, void *data)
493549Svbart@nginx.com {
4941488St.nateldemoura@f5.com nxt_signal_quit_handler(task, msg);
495549Svbart@nginx.com }
496549Svbart@nginx.com
497549Svbart@nginx.com
4981488St.nateldemoura@f5.com static nxt_int_t
nxt_proto_setup(nxt_task_t * task,nxt_process_t * process)4991998St.nateldemoura@f5.com nxt_proto_setup(nxt_task_t *task, nxt_process_t *process)
5000Sigor@sysoev.ru {
501216Sigor@sysoev.ru nxt_int_t ret;
502216Sigor@sysoev.ru nxt_app_lang_module_t *lang;
503216Sigor@sysoev.ru nxt_common_app_conf_t *app_conf;
504141Smax.romanov@nginx.com
5051488St.nateldemoura@f5.com app_conf = process->data.app;
506141Smax.romanov@nginx.com
5071998St.nateldemoura@f5.com nxt_queue_init(&nxt_proto_children);
5081998St.nateldemoura@f5.com
5091998St.nateldemoura@f5.com nxt_app_conf = app_conf;
5101998St.nateldemoura@f5.com
511216Sigor@sysoev.ru lang = nxt_app_lang_module(task->thread->runtime, &app_conf->type);
512216Sigor@sysoev.ru if (nxt_slow_path(lang == NULL)) {
513564Svbart@nginx.com nxt_alert(task, "unknown application type: \"%V\"", &app_conf->type);
514216Sigor@sysoev.ru return NXT_ERROR;
515216Sigor@sysoev.ru }
516216Sigor@sysoev.ru
517216Sigor@sysoev.ru nxt_app = lang->module;
518216Sigor@sysoev.ru
519216Sigor@sysoev.ru if (nxt_app == NULL) {
520354Svbart@nginx.com nxt_debug(task, "application language module: %s \"%s\"",
521354Svbart@nginx.com lang->version, lang->file);
522216Sigor@sysoev.ru
523216Sigor@sysoev.ru nxt_app = nxt_app_module_load(task, lang->file);
5241239Smax.romanov@nginx.com if (nxt_slow_path(nxt_app == NULL)) {
5251239Smax.romanov@nginx.com return NXT_ERROR;
5261239Smax.romanov@nginx.com }
527216Sigor@sysoev.ru }
528216Sigor@sysoev.ru
5291489St.nateldemoura@f5.com if (nxt_slow_path(nxt_app_set_environment(app_conf->environment)
5301489St.nateldemoura@f5.com != NXT_OK))
5311489St.nateldemoura@f5.com {
5321489St.nateldemoura@f5.com nxt_alert(task, "failed to set environment");
5331489St.nateldemoura@f5.com return NXT_ERROR;
5341489St.nateldemoura@f5.com }
5351489St.nateldemoura@f5.com
5361488St.nateldemoura@f5.com if (nxt_app->setup != NULL) {
5371488St.nateldemoura@f5.com ret = nxt_app->setup(task, process, app_conf);
538977Smax.romanov@gmail.com if (nxt_slow_path(ret != NXT_OK)) {
5391104Smax.romanov@nginx.com return ret;
540977Smax.romanov@gmail.com }
541977Smax.romanov@gmail.com }
542977Smax.romanov@gmail.com
5431489St.nateldemoura@f5.com #if (NXT_HAVE_ISOLATION_ROOTFS)
5441489St.nateldemoura@f5.com if (process->isolation.rootfs != NULL) {
5451489St.nateldemoura@f5.com if (process->isolation.mounts != NULL) {
5461579St.nateldemoura@f5.com ret = nxt_isolation_prepare_rootfs(task, process);
5471489St.nateldemoura@f5.com if (nxt_slow_path(ret != NXT_OK)) {
5481489St.nateldemoura@f5.com return ret;
5491489St.nateldemoura@f5.com }
5501489St.nateldemoura@f5.com }
5511489St.nateldemoura@f5.com
5521579St.nateldemoura@f5.com ret = nxt_isolation_change_root(task, process);
5531489St.nateldemoura@f5.com if (nxt_slow_path(ret != NXT_OK)) {
5541489St.nateldemoura@f5.com return NXT_ERROR;
5551489St.nateldemoura@f5.com }
5561489St.nateldemoura@f5.com }
5571489St.nateldemoura@f5.com #endif
5581489St.nateldemoura@f5.com
559277Sigor@sysoev.ru if (app_conf->working_directory != NULL
560277Sigor@sysoev.ru && app_conf->working_directory[0] != 0)
561271Smax.romanov@nginx.com {
562271Smax.romanov@nginx.com ret = chdir(app_conf->working_directory);
563271Smax.romanov@nginx.com
564271Smax.romanov@nginx.com if (nxt_slow_path(ret != 0)) {
565271Smax.romanov@nginx.com nxt_log(task, NXT_LOG_WARN, "chdir(%s) failed %E",
566271Smax.romanov@nginx.com app_conf->working_directory, nxt_errno);
567271Smax.romanov@nginx.com
568271Smax.romanov@nginx.com return NXT_ERROR;
569271Smax.romanov@nginx.com }
570271Smax.romanov@nginx.com }
571271Smax.romanov@nginx.com
5721998St.nateldemoura@f5.com process->state = NXT_PROCESS_STATE_CREATED;
5731998St.nateldemoura@f5.com
5741998St.nateldemoura@f5.com return NXT_OK;
5751998St.nateldemoura@f5.com }
5761998St.nateldemoura@f5.com
5771998St.nateldemoura@f5.com
5781998St.nateldemoura@f5.com static nxt_int_t
nxt_proto_start(nxt_task_t * task,nxt_process_data_t * data)5791998St.nateldemoura@f5.com nxt_proto_start(nxt_task_t *task, nxt_process_data_t *data)
5801998St.nateldemoura@f5.com {
5811998St.nateldemoura@f5.com nxt_debug(task, "prototype waiting for clone messages");
5821998St.nateldemoura@f5.com
5831998St.nateldemoura@f5.com return NXT_OK;
5841998St.nateldemoura@f5.com }
5851998St.nateldemoura@f5.com
5861998St.nateldemoura@f5.com
5871998St.nateldemoura@f5.com static void
nxt_proto_start_process_handler(nxt_task_t * task,nxt_port_recv_msg_t * msg)5881998St.nateldemoura@f5.com nxt_proto_start_process_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
5891998St.nateldemoura@f5.com {
5901998St.nateldemoura@f5.com u_char *p;
5911998St.nateldemoura@f5.com nxt_int_t ret;
5921998St.nateldemoura@f5.com nxt_port_t *port;
5931998St.nateldemoura@f5.com nxt_runtime_t *rt;
5941998St.nateldemoura@f5.com nxt_process_t *process;
5951998St.nateldemoura@f5.com nxt_process_init_t *init;
5961998St.nateldemoura@f5.com
5971998St.nateldemoura@f5.com rt = task->thread->runtime;
5981998St.nateldemoura@f5.com
5991998St.nateldemoura@f5.com process = nxt_process_new(rt);
6001998St.nateldemoura@f5.com if (nxt_slow_path(process == NULL)) {
6011998St.nateldemoura@f5.com goto failed;
6021998St.nateldemoura@f5.com }
6031998St.nateldemoura@f5.com
6041998St.nateldemoura@f5.com process->mem_pool = nxt_mp_create(1024, 128, 256, 32);
6051998St.nateldemoura@f5.com if (nxt_slow_path(process->mem_pool == NULL)) {
6061998St.nateldemoura@f5.com nxt_process_use(task, process, -1);
6071998St.nateldemoura@f5.com goto failed;
6081998St.nateldemoura@f5.com }
6091998St.nateldemoura@f5.com
6101998St.nateldemoura@f5.com process->parent_port = rt->port_by_type[NXT_PROCESS_PROTOTYPE];
6111998St.nateldemoura@f5.com
6121488St.nateldemoura@f5.com init = nxt_process_init(process);
6131998St.nateldemoura@f5.com *init = nxt_app_process;
6141998St.nateldemoura@f5.com
6151998St.nateldemoura@f5.com process->name = nxt_mp_alloc(process->mem_pool, nxt_app_conf->name.length
6161998St.nateldemoura@f5.com + sizeof("\"\" application") + 1);
6171998St.nateldemoura@f5.com
6181998St.nateldemoura@f5.com if (nxt_slow_path(process->name == NULL)) {
6191998St.nateldemoura@f5.com nxt_process_use(task, process, -1);
6201998St.nateldemoura@f5.com
6211998St.nateldemoura@f5.com goto failed;
6221998St.nateldemoura@f5.com }
623141Smax.romanov@nginx.com
6241488St.nateldemoura@f5.com init->start = nxt_app->start;
625141Smax.romanov@nginx.com
6261998St.nateldemoura@f5.com init->name = (const char *) nxt_app_conf->name.start;
6271998St.nateldemoura@f5.com
6281998St.nateldemoura@f5.com p = (u_char *) process->name;
6291998St.nateldemoura@f5.com *p++ = '"';
6301998St.nateldemoura@f5.com p = nxt_cpymem(p, nxt_app_conf->name.start, nxt_app_conf->name.length);
6311998St.nateldemoura@f5.com p = nxt_cpymem(p, "\" application", 13);
6321998St.nateldemoura@f5.com *p = '\0';
6331998St.nateldemoura@f5.com
6341998St.nateldemoura@f5.com process->user_cred = &rt->user_cred;
6351998St.nateldemoura@f5.com
6361998St.nateldemoura@f5.com process->data.app = nxt_app_conf;
6371998St.nateldemoura@f5.com process->stream = msg->port_msg.stream;
6381998St.nateldemoura@f5.com
6391998St.nateldemoura@f5.com ret = nxt_process_start(task, process);
6401998St.nateldemoura@f5.com if (nxt_slow_path(ret == NXT_ERROR)) {
6411998St.nateldemoura@f5.com nxt_process_use(task, process, -1);
6421998St.nateldemoura@f5.com
6431998St.nateldemoura@f5.com goto failed;
6441998St.nateldemoura@f5.com }
6451998St.nateldemoura@f5.com
6461998St.nateldemoura@f5.com nxt_proto_process_add(task, process);
6471998St.nateldemoura@f5.com
6481998St.nateldemoura@f5.com return;
6491998St.nateldemoura@f5.com
6501998St.nateldemoura@f5.com failed:
6511998St.nateldemoura@f5.com
6521998St.nateldemoura@f5.com port = nxt_runtime_port_find(rt, msg->port_msg.pid,
6531998St.nateldemoura@f5.com msg->port_msg.reply_port);
6541998St.nateldemoura@f5.com
6551998St.nateldemoura@f5.com if (nxt_fast_path(port != NULL)) {
6561998St.nateldemoura@f5.com nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_ERROR,
6571998St.nateldemoura@f5.com -1, msg->port_msg.stream, 0, NULL);
6581998St.nateldemoura@f5.com }
6591998St.nateldemoura@f5.com }
6601998St.nateldemoura@f5.com
6611998St.nateldemoura@f5.com
6621998St.nateldemoura@f5.com static void
nxt_proto_quit_handler(nxt_task_t * task,nxt_port_recv_msg_t * msg)6631998St.nateldemoura@f5.com nxt_proto_quit_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
6641998St.nateldemoura@f5.com {
6651998St.nateldemoura@f5.com nxt_debug(task, "prototype quit handler");
6661998St.nateldemoura@f5.com
6671998St.nateldemoura@f5.com nxt_proto_quit_children(task);
6681998St.nateldemoura@f5.com
6691998St.nateldemoura@f5.com nxt_proto_exiting = 1;
6701998St.nateldemoura@f5.com
6711998St.nateldemoura@f5.com if (nxt_queue_is_empty(&nxt_proto_children)) {
6721998St.nateldemoura@f5.com nxt_process_quit(task, 0);
6731998St.nateldemoura@f5.com }
6741998St.nateldemoura@f5.com }
6751998St.nateldemoura@f5.com
6761998St.nateldemoura@f5.com
6771998St.nateldemoura@f5.com static void
nxt_proto_quit_children(nxt_task_t * task)6781998St.nateldemoura@f5.com nxt_proto_quit_children(nxt_task_t *task)
6791998St.nateldemoura@f5.com {
6801998St.nateldemoura@f5.com nxt_port_t *port;
6811998St.nateldemoura@f5.com nxt_process_t *process;
6821998St.nateldemoura@f5.com
6831998St.nateldemoura@f5.com nxt_queue_each(process, &nxt_proto_children, nxt_process_t, link) {
6841998St.nateldemoura@f5.com port = nxt_process_port_first(process);
6851998St.nateldemoura@f5.com
6861998St.nateldemoura@f5.com (void) nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT,
6871998St.nateldemoura@f5.com -1, 0, 0, NULL);
6881998St.nateldemoura@f5.com }
6891998St.nateldemoura@f5.com nxt_queue_loop;
6901998St.nateldemoura@f5.com }
6911998St.nateldemoura@f5.com
6921998St.nateldemoura@f5.com
6931998St.nateldemoura@f5.com static void
nxt_proto_process_created_handler(nxt_task_t * task,nxt_port_recv_msg_t * msg)6941998St.nateldemoura@f5.com nxt_proto_process_created_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
6951998St.nateldemoura@f5.com {
6961998St.nateldemoura@f5.com nxt_pid_t isolated_pid, pid;
6971998St.nateldemoura@f5.com nxt_process_t *process;
6981998St.nateldemoura@f5.com
6991998St.nateldemoura@f5.com isolated_pid = nxt_recv_msg_cmsg_pid(msg);
7001998St.nateldemoura@f5.com
7011998St.nateldemoura@f5.com process = nxt_proto_process_find(task, isolated_pid);
7021998St.nateldemoura@f5.com if (nxt_slow_path(process == NULL)) {
7031998St.nateldemoura@f5.com return;
7041998St.nateldemoura@f5.com }
7051998St.nateldemoura@f5.com
7061488St.nateldemoura@f5.com process->state = NXT_PROCESS_STATE_CREATED;
70720Sigor@sysoev.ru
7081998St.nateldemoura@f5.com pid = msg->port_msg.pid;
7091998St.nateldemoura@f5.com
7101998St.nateldemoura@f5.com if (process->pid != pid) {
7111998St.nateldemoura@f5.com nxt_debug(task, "app process %PI (aka %PI) is created", isolated_pid,
7121998St.nateldemoura@f5.com pid);
7131998St.nateldemoura@f5.com
7141998St.nateldemoura@f5.com nxt_runtime_process_remove(task->thread->runtime, process);
7151998St.nateldemoura@f5.com
7161998St.nateldemoura@f5.com process->pid = pid;
7171998St.nateldemoura@f5.com
7181998St.nateldemoura@f5.com nxt_runtime_process_add(task, process);
7191998St.nateldemoura@f5.com
7201998St.nateldemoura@f5.com } else {
7211998St.nateldemoura@f5.com nxt_debug(task, "app process %PI is created", isolated_pid);
7221998St.nateldemoura@f5.com }
7231998St.nateldemoura@f5.com }
7241998St.nateldemoura@f5.com
7251998St.nateldemoura@f5.com
7261998St.nateldemoura@f5.com static void
nxt_proto_signal_handler(nxt_task_t * task,void * obj,void * data)7271998St.nateldemoura@f5.com nxt_proto_signal_handler(nxt_task_t *task, void *obj, void *data)
7281998St.nateldemoura@f5.com {
7291998St.nateldemoura@f5.com nxt_trace(task, "signal signo:%d (%s) received, ignored",
7301998St.nateldemoura@f5.com (int) (uintptr_t) obj, data);
7311998St.nateldemoura@f5.com }
7321998St.nateldemoura@f5.com
7331998St.nateldemoura@f5.com
7341998St.nateldemoura@f5.com static void
nxt_proto_sigterm_handler(nxt_task_t * task,void * obj,void * data)7351998St.nateldemoura@f5.com nxt_proto_sigterm_handler(nxt_task_t *task, void *obj, void *data)
736