xref: /unit/src/nxt_application.c (revision 2426:d5e936f09dc0)
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 
262174Smax.romanov@gmail.com #ifdef WCOREDUMP
272174Smax.romanov@gmail.com #define NXT_WCOREDUMP(s) WCOREDUMP(s)
282174Smax.romanov@gmail.com #else
292174Smax.romanov@gmail.com #define NXT_WCOREDUMP(s) 0
302174Smax.romanov@gmail.com #endif
312174Smax.romanov@gmail.com 
322174Smax.romanov@gmail.com 
33216Sigor@sysoev.ru typedef struct {
34356Svbart@nginx.com     nxt_app_type_t  type;
35356Svbart@nginx.com     nxt_str_t       version;
36356Svbart@nginx.com     nxt_str_t       file;
371489St.nateldemoura@f5.com     nxt_array_t     *mounts;
38216Sigor@sysoev.ru } nxt_module_t;
39216Sigor@sysoev.ru 
40216Sigor@sysoev.ru 
411488St.nateldemoura@f5.com static nxt_int_t nxt_discovery_start(nxt_task_t *task,
421488St.nateldemoura@f5.com     nxt_process_data_t *data);
43216Sigor@sysoev.ru static nxt_buf_t *nxt_discovery_modules(nxt_task_t *task, const char *path);
44216Sigor@sysoev.ru static nxt_int_t nxt_discovery_module(nxt_task_t *task, nxt_mp_t *mp,
45216Sigor@sysoev.ru     nxt_array_t *modules, const char *name);
46549Svbart@nginx.com static void nxt_discovery_completion_handler(nxt_task_t *task, void *obj,
47549Svbart@nginx.com     void *data);
48549Svbart@nginx.com static void nxt_discovery_quit(nxt_task_t *task, nxt_port_recv_msg_t *msg,
49549Svbart@nginx.com     void *data);
50216Sigor@sysoev.ru static nxt_app_module_t *nxt_app_module_load(nxt_task_t *task,
51216Sigor@sysoev.ru     const char *name);
521998St.nateldemoura@f5.com static nxt_int_t nxt_proto_setup(nxt_task_t *task, nxt_process_t *process);
531998St.nateldemoura@f5.com static nxt_int_t nxt_proto_start(nxt_task_t *task, nxt_process_data_t *data);
541488St.nateldemoura@f5.com static nxt_int_t nxt_app_setup(nxt_task_t *task, nxt_process_t *process);
55678Svbart@nginx.com static nxt_int_t nxt_app_set_environment(nxt_conf_value_t *environment);
561998St.nateldemoura@f5.com static void nxt_proto_start_process_handler(nxt_task_t *task,
571998St.nateldemoura@f5.com     nxt_port_recv_msg_t *msg);
581998St.nateldemoura@f5.com static void nxt_proto_quit_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg);
591998St.nateldemoura@f5.com static void nxt_proto_process_created_handler(nxt_task_t *task,
601998St.nateldemoura@f5.com     nxt_port_recv_msg_t *msg);
611998St.nateldemoura@f5.com static void nxt_proto_quit_children(nxt_task_t *task);
621998St.nateldemoura@f5.com static nxt_process_t *nxt_proto_process_find(nxt_task_t *task, nxt_pid_t pid);
631998St.nateldemoura@f5.com static void nxt_proto_process_add(nxt_task_t *task, nxt_process_t *process);
641998St.nateldemoura@f5.com static nxt_process_t *nxt_proto_process_remove(nxt_task_t *task, nxt_pid_t pid);
651489St.nateldemoura@f5.com static u_char *nxt_cstr_dup(nxt_mp_t *mp, u_char *dst, u_char *src);
661998St.nateldemoura@f5.com static void nxt_proto_signal_handler(nxt_task_t *task, void *obj, void *data);
671998St.nateldemoura@f5.com static void nxt_proto_sigterm_handler(nxt_task_t *task, void *obj, void *data);
681998St.nateldemoura@f5.com static void nxt_proto_sigchld_handler(nxt_task_t *task, void *obj, void *data);
691489St.nateldemoura@f5.com 
701489St.nateldemoura@f5.com 
711488St.nateldemoura@f5.com nxt_str_t  nxt_server = nxt_string(NXT_SERVER);
720Sigor@sysoev.ru 
73216Sigor@sysoev.ru 
74258Sigor@sysoev.ru static uint32_t  compat[] = {
75360Sigor@sysoev.ru     NXT_VERNUM, NXT_DEBUG,
76258Sigor@sysoev.ru };
77258Sigor@sysoev.ru 
78258Sigor@sysoev.ru 
791998St.nateldemoura@f5.com static nxt_lvlhsh_t           nxt_proto_processes;
801998St.nateldemoura@f5.com static nxt_queue_t            nxt_proto_children;
811998St.nateldemoura@f5.com static nxt_bool_t             nxt_proto_exiting;
821998St.nateldemoura@f5.com 
831998St.nateldemoura@f5.com static nxt_app_module_t       *nxt_app;
841998St.nateldemoura@f5.com static nxt_common_app_conf_t  *nxt_app_conf;
85417Svbart@nginx.com 
86417Svbart@nginx.com 
871488St.nateldemoura@f5.com static const nxt_port_handlers_t  nxt_discovery_process_port_handlers = {
881488St.nateldemoura@f5.com     .quit         = nxt_signal_quit_handler,
891488St.nateldemoura@f5.com     .new_port     = nxt_port_new_port_handler,
901488St.nateldemoura@f5.com     .change_file  = nxt_port_change_log_file_handler,
911488St.nateldemoura@f5.com     .mmap         = nxt_port_mmap_handler,
921488St.nateldemoura@f5.com     .data         = nxt_port_data_handler,
931488St.nateldemoura@f5.com     .remove_pid   = nxt_port_remove_pid_handler,
941488St.nateldemoura@f5.com     .rpc_ready    = nxt_port_rpc_handler,
951488St.nateldemoura@f5.com     .rpc_error    = nxt_port_rpc_handler,
961488St.nateldemoura@f5.com };
971488St.nateldemoura@f5.com 
981488St.nateldemoura@f5.com 
991998St.nateldemoura@f5.com const nxt_sig_event_t  nxt_prototype_signals[] = {
1001998St.nateldemoura@f5.com     nxt_event_signal(SIGHUP,  nxt_proto_signal_handler),
1011998St.nateldemoura@f5.com     nxt_event_signal(SIGINT,  nxt_proto_sigterm_handler),
1021998St.nateldemoura@f5.com     nxt_event_signal(SIGQUIT, nxt_proto_sigterm_handler),
1031998St.nateldemoura@f5.com     nxt_event_signal(SIGTERM, nxt_proto_sigterm_handler),
1041998St.nateldemoura@f5.com     nxt_event_signal(SIGCHLD, nxt_proto_sigchld_handler),
1051998St.nateldemoura@f5.com     nxt_event_signal_end,
1061998St.nateldemoura@f5.com };
1071998St.nateldemoura@f5.com 
1081998St.nateldemoura@f5.com 
1091998St.nateldemoura@f5.com static const nxt_port_handlers_t  nxt_proto_process_port_handlers = {
1101998St.nateldemoura@f5.com     .quit            = nxt_proto_quit_handler,
1111998St.nateldemoura@f5.com     .change_file     = nxt_port_change_log_file_handler,
1121998St.nateldemoura@f5.com     .new_port        = nxt_port_new_port_handler,
1131998St.nateldemoura@f5.com     .process_created = nxt_proto_process_created_handler,
1141998St.nateldemoura@f5.com     .process_ready   = nxt_port_process_ready_handler,
1151998St.nateldemoura@f5.com     .remove_pid      = nxt_port_remove_pid_handler,
1161998St.nateldemoura@f5.com     .start_process   = nxt_proto_start_process_handler,
1171998St.nateldemoura@f5.com     .rpc_ready       = nxt_port_rpc_handler,
1181998St.nateldemoura@f5.com     .rpc_error       = nxt_port_rpc_handler,
1191998St.nateldemoura@f5.com };
1201998St.nateldemoura@f5.com 
1211998St.nateldemoura@f5.com 
1221488St.nateldemoura@f5.com static const nxt_port_handlers_t  nxt_app_process_port_handlers = {
1231488St.nateldemoura@f5.com     .quit         = nxt_signal_quit_handler,
1241488St.nateldemoura@f5.com     .rpc_ready    = nxt_port_rpc_handler,
1251488St.nateldemoura@f5.com     .rpc_error    = nxt_port_rpc_handler,
1261488St.nateldemoura@f5.com };
1271488St.nateldemoura@f5.com 
1281488St.nateldemoura@f5.com 
1291488St.nateldemoura@f5.com const nxt_process_init_t  nxt_discovery_process = {
1301488St.nateldemoura@f5.com     .name           = "discovery",
1311488St.nateldemoura@f5.com     .type           = NXT_PROCESS_DISCOVERY,
1321488St.nateldemoura@f5.com     .prefork        = NULL,
1331488St.nateldemoura@f5.com     .restart        = 0,
1341488St.nateldemoura@f5.com     .setup          = nxt_process_core_setup,
1351488St.nateldemoura@f5.com     .start          = nxt_discovery_start,
1361488St.nateldemoura@f5.com     .port_handlers  = &nxt_discovery_process_port_handlers,
1371488St.nateldemoura@f5.com     .signals        = nxt_process_signals,
1381488St.nateldemoura@f5.com };
1391488St.nateldemoura@f5.com 
1401488St.nateldemoura@f5.com 
1411998St.nateldemoura@f5.com const nxt_process_init_t  nxt_proto_process = {
1421998St.nateldemoura@f5.com     .type           = NXT_PROCESS_PROTOTYPE,
1431998St.nateldemoura@f5.com     .prefork        = nxt_isolation_main_prefork,
1441998St.nateldemoura@f5.com     .restart        = 0,
1451998St.nateldemoura@f5.com     .setup          = nxt_proto_setup,
1461998St.nateldemoura@f5.com     .start          = nxt_proto_start,
1471998St.nateldemoura@f5.com     .port_handlers  = &nxt_proto_process_port_handlers,
1481998St.nateldemoura@f5.com     .signals        = nxt_prototype_signals,
1491998St.nateldemoura@f5.com };
1501998St.nateldemoura@f5.com 
1511998St.nateldemoura@f5.com 
1521488St.nateldemoura@f5.com const nxt_process_init_t  nxt_app_process = {
1531488St.nateldemoura@f5.com     .type           = NXT_PROCESS_APP,
1541488St.nateldemoura@f5.com     .setup          = nxt_app_setup,
1551998St.nateldemoura@f5.com     .start          = NULL,
1561998St.nateldemoura@f5.com     .prefork        = NULL,
1571488St.nateldemoura@f5.com     .restart        = 0,
1581488St.nateldemoura@f5.com     .port_handlers  = &nxt_app_process_port_handlers,
1591488St.nateldemoura@f5.com     .signals        = nxt_process_signals,
1601488St.nateldemoura@f5.com };
1611488St.nateldemoura@f5.com 
1621488St.nateldemoura@f5.com 
1631488St.nateldemoura@f5.com static nxt_int_t
nxt_discovery_start(nxt_task_t * task,nxt_process_data_t * data)1641488St.nateldemoura@f5.com nxt_discovery_start(nxt_task_t *task, nxt_process_data_t *data)
165216Sigor@sysoev.ru {
166549Svbart@nginx.com     uint32_t       stream;
167549Svbart@nginx.com     nxt_buf_t      *b;
168549Svbart@nginx.com     nxt_int_t      ret;
169549Svbart@nginx.com     nxt_port_t     *main_port, *discovery_port;
170549Svbart@nginx.com     nxt_runtime_t  *rt;
171216Sigor@sysoev.ru 
1721488St.nateldemoura@f5.com     nxt_log(task, NXT_LOG_INFO, "discovery started");
173216Sigor@sysoev.ru 
174233Sigor@sysoev.ru     rt = task->thread->runtime;
175216Sigor@sysoev.ru 
176233Sigor@sysoev.ru     b = nxt_discovery_modules(task, rt->modules);
177250Sigor@sysoev.ru     if (nxt_slow_path(b == NULL)) {
178549Svbart@nginx.com         return NXT_ERROR;
179250Sigor@sysoev.ru     }
180233Sigor@sysoev.ru 
181240Sigor@sysoev.ru     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
182549Svbart@nginx.com     discovery_port = rt->port_by_type[NXT_PROCESS_DISCOVERY];
183216Sigor@sysoev.ru 
184549Svbart@nginx.com     stream = nxt_port_rpc_register_handler(task, discovery_port,
185549Svbart@nginx.com                                            nxt_discovery_quit,
186549Svbart@nginx.com                                            nxt_discovery_quit,
187549Svbart@nginx.com                                            main_port->pid, NULL);
188549Svbart@nginx.com 
189645Svbart@nginx.com     if (nxt_slow_path(stream == 0)) {
190645Svbart@nginx.com         return NXT_ERROR;
191645Svbart@nginx.com     }
192645Svbart@nginx.com 
193549Svbart@nginx.com     ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_MODULES, -1,
194549Svbart@nginx.com                                 stream, discovery_port->id, b);
195549Svbart@nginx.com 
196549Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
197549Svbart@nginx.com         nxt_port_rpc_cancel(task, discovery_port, stream);
198549Svbart@nginx.com         return NXT_ERROR;
199549Svbart@nginx.com     }
200216Sigor@sysoev.ru 
201216Sigor@sysoev.ru     return NXT_OK;
202216Sigor@sysoev.ru }
203216Sigor@sysoev.ru 
204216Sigor@sysoev.ru 
205216Sigor@sysoev.ru static nxt_buf_t *
nxt_discovery_modules(nxt_task_t * task,const char * path)206216Sigor@sysoev.ru nxt_discovery_modules(nxt_task_t *task, const char *path)
207216Sigor@sysoev.ru {
2081489St.nateldemoura@f5.com     char            *name;
2091489St.nateldemoura@f5.com     u_char          *p, *end;
2101489St.nateldemoura@f5.com     size_t          size;
2111489St.nateldemoura@f5.com     glob_t          glb;
2121489St.nateldemoura@f5.com     nxt_mp_t        *mp;
2131489St.nateldemoura@f5.com     nxt_buf_t       *b;
2141489St.nateldemoura@f5.com     nxt_int_t       ret;
2151489St.nateldemoura@f5.com     nxt_uint_t      i, n, j;
2161489St.nateldemoura@f5.com     nxt_array_t     *modules, *mounts;
2171489St.nateldemoura@f5.com     nxt_module_t    *module;
2181489St.nateldemoura@f5.com     nxt_fs_mount_t  *mnt;
219216Sigor@sysoev.ru 
220216Sigor@sysoev.ru     b = NULL;
221216Sigor@sysoev.ru 
222216Sigor@sysoev.ru     mp = nxt_mp_create(1024, 128, 256, 32);
223216Sigor@sysoev.ru     if (mp == NULL) {
224216Sigor@sysoev.ru         return b;
225216Sigor@sysoev.ru     }
226216Sigor@sysoev.ru 
227216Sigor@sysoev.ru     ret = glob(path, 0, NULL, &glb);
228216Sigor@sysoev.ru 
229250Sigor@sysoev.ru     n = glb.gl_pathc;
230250Sigor@sysoev.ru 
231250Sigor@sysoev.ru     if (ret != 0) {
232250Sigor@sysoev.ru         nxt_log(task, NXT_LOG_NOTICE,
233250Sigor@sysoev.ru                 "no modules matching: \"%s\" found", path);
234250Sigor@sysoev.ru         n = 0;
235250Sigor@sysoev.ru     }
236216Sigor@sysoev.ru 
237250Sigor@sysoev.ru     modules = nxt_array_create(mp, n, sizeof(nxt_module_t));
238250Sigor@sysoev.ru     if (modules == NULL) {
239250Sigor@sysoev.ru         goto fail;
240250Sigor@sysoev.ru     }
241250Sigor@sysoev.ru 
242250Sigor@sysoev.ru     for (i = 0; i < n; i++) {
243250Sigor@sysoev.ru         name = glb.gl_pathv[i];
244250Sigor@sysoev.ru 
245250Sigor@sysoev.ru         ret = nxt_discovery_module(task, mp, modules, name);
246250Sigor@sysoev.ru         if (ret != NXT_OK) {
247216Sigor@sysoev.ru             goto fail;
248216Sigor@sysoev.ru         }
249250Sigor@sysoev.ru     }
250216Sigor@sysoev.ru 
251703Svbart@nginx.com     size = nxt_length("[]");
252250Sigor@sysoev.ru     module = modules->elts;
253250Sigor@sysoev.ru     n = modules->nelts;
254216Sigor@sysoev.ru 
255250Sigor@sysoev.ru     for (i = 0; i < n; i++) {
256356Svbart@nginx.com         nxt_debug(task, "module: %d %V %V",
257356Svbart@nginx.com                   module[i].type, &module[i].version, &module[i].file);
258216Sigor@sysoev.ru 
259703Svbart@nginx.com         size += nxt_length("{\"type\": ,");
260703Svbart@nginx.com         size += nxt_length(" \"version\": \"\",");
2611489St.nateldemoura@f5.com         size += nxt_length(" \"file\": \"\",");
2621489St.nateldemoura@f5.com         size += nxt_length(" \"mounts\": []},");
263216Sigor@sysoev.ru 
264356Svbart@nginx.com         size += NXT_INT_T_LEN
265250Sigor@sysoev.ru                 + module[i].version.length
266250Sigor@sysoev.ru                 + module[i].file.length;
2671489St.nateldemoura@f5.com 
2681489St.nateldemoura@f5.com         mounts = module[i].mounts;
2691489St.nateldemoura@f5.com 
2701489St.nateldemoura@f5.com         size += mounts->nelts * nxt_length("{\"src\": \"\", \"dst\": \"\", "
2711673St.nateldemoura@f5.com                                             "\"type\": , \"name\": \"\", "
2721673St.nateldemoura@f5.com                                             "\"flags\": , \"data\": \"\"},");
2731489St.nateldemoura@f5.com 
2741489St.nateldemoura@f5.com         mnt = mounts->elts;
2751489St.nateldemoura@f5.com 
2761489St.nateldemoura@f5.com         for (j = 0; j < mounts->nelts; j++) {
2771489St.nateldemoura@f5.com             size += nxt_strlen(mnt[j].src) + nxt_strlen(mnt[j].dst)
2781673St.nateldemoura@f5.com                     + nxt_strlen(mnt[j].name) + (2 * NXT_INT_T_LEN)
2791489St.nateldemoura@f5.com                     + (mnt[j].data == NULL ? 0 : nxt_strlen(mnt[j].data));
2801489St.nateldemoura@f5.com         }
281250Sigor@sysoev.ru     }
282216Sigor@sysoev.ru 
283250Sigor@sysoev.ru     b = nxt_buf_mem_alloc(mp, size, 0);
284250Sigor@sysoev.ru     if (b == NULL) {
285250Sigor@sysoev.ru         goto fail;
286250Sigor@sysoev.ru     }
287216Sigor@sysoev.ru 
288250Sigor@sysoev.ru     b->completion_handler = nxt_discovery_completion_handler;
289216Sigor@sysoev.ru 
290250Sigor@sysoev.ru     p = b->mem.free;
291250Sigor@sysoev.ru     end = b->mem.end;
292250Sigor@sysoev.ru     *p++ = '[';
293216Sigor@sysoev.ru 
294250Sigor@sysoev.ru     for (i = 0; i < n; i++) {
2951489St.nateldemoura@f5.com         mounts = module[i].mounts;
2961489St.nateldemoura@f5.com 
2971489St.nateldemoura@f5.com         p = nxt_sprintf(p, end, "{\"type\": %d, \"version\": \"%V\", "
2981489St.nateldemoura@f5.com                         "\"file\": \"%V\", \"mounts\": [",
2991489St.nateldemoura@f5.com                         module[i].type, &module[i].version, &module[i].file);
3001489St.nateldemoura@f5.com 
3011489St.nateldemoura@f5.com         mnt = mounts->elts;
3021489St.nateldemoura@f5.com         for (j = 0; j < mounts->nelts; j++) {
3031489St.nateldemoura@f5.com             p = nxt_sprintf(p, end,
3041489St.nateldemoura@f5.com                             "{\"src\": \"%s\", \"dst\": \"%s\", "
3051673St.nateldemoura@f5.com                             "\"name\": \"%s\", \"type\": %d, \"flags\": %d, "
3061489St.nateldemoura@f5.com                             "\"data\": \"%s\"},",
3071673St.nateldemoura@f5.com                             mnt[j].src, mnt[j].dst, mnt[j].name, mnt[j].type,
3081673St.nateldemoura@f5.com                             mnt[j].flags,
3091489St.nateldemoura@f5.com                             mnt[j].data == NULL ? (u_char *) "" : mnt[j].data);
3101489St.nateldemoura@f5.com         }
3111489St.nateldemoura@f5.com 
3121489St.nateldemoura@f5.com         *p++ = ']';
3131489St.nateldemoura@f5.com         *p++ = '}';
3141489St.nateldemoura@f5.com         *p++ = ',';
315250Sigor@sysoev.ru     }
316216Sigor@sysoev.ru 
317250Sigor@sysoev.ru     *p++ = ']';
3181489St.nateldemoura@f5.com 
3191515Smax.romanov@nginx.com     if (nxt_slow_path(p > end)) {
3201489St.nateldemoura@f5.com         nxt_alert(task, "discovery write past the buffer");
3211489St.nateldemoura@f5.com         goto fail;
3221489St.nateldemoura@f5.com     }
3231489St.nateldemoura@f5.com 
324250Sigor@sysoev.ru     b->mem.free = p;
325216Sigor@sysoev.ru 
326216Sigor@sysoev.ru fail:
327216Sigor@sysoev.ru 
328216Sigor@sysoev.ru     globfree(&glb);
329216Sigor@sysoev.ru 
330216Sigor@sysoev.ru     return b;
331216Sigor@sysoev.ru }
332216Sigor@sysoev.ru 
333216Sigor@sysoev.ru 
334216Sigor@sysoev.ru static nxt_int_t
nxt_discovery_module(nxt_task_t * task,nxt_mp_t * mp,nxt_array_t * modules,const char * name)335216Sigor@sysoev.ru nxt_discovery_module(nxt_task_t *task, nxt_mp_t *mp, nxt_array_t *modules,
336216Sigor@sysoev.ru     const char *name)
337216Sigor@sysoev.ru {
3381489St.nateldemoura@f5.com     void                  *dl;
3391489St.nateldemoura@f5.com     nxt_str_t             version;
3401489St.nateldemoura@f5.com     nxt_int_t             ret;
3411489St.nateldemoura@f5.com     nxt_uint_t            i, j, n;
3421489St.nateldemoura@f5.com     nxt_array_t           *mounts;
3431489St.nateldemoura@f5.com     nxt_module_t          *module;
3441489St.nateldemoura@f5.com     nxt_app_type_t        type;
3451489St.nateldemoura@f5.com     nxt_fs_mount_t        *to;
3461489St.nateldemoura@f5.com     nxt_app_module_t      *app;
3471489St.nateldemoura@f5.com     const nxt_fs_mount_t  *from;
348216Sigor@sysoev.ru 
349216Sigor@sysoev.ru     /*
350216Sigor@sysoev.ru      * Only memory allocation failure should return NXT_ERROR.
351216Sigor@sysoev.ru      * Any module processing errors are ignored.
352216Sigor@sysoev.ru      */
353216Sigor@sysoev.ru     ret = NXT_ERROR;
354216Sigor@sysoev.ru 
355216Sigor@sysoev.ru     dl = dlopen(name, RTLD_GLOBAL | RTLD_NOW);
356216Sigor@sysoev.ru 
357216Sigor@sysoev.ru     if (dl == NULL) {
358564Svbart@nginx.com         nxt_alert(task, "dlopen(\"%s\"), failed: \"%s\"", name, dlerror());
359216Sigor@sysoev.ru         return NXT_OK;
360216Sigor@sysoev.ru     }
361216Sigor@sysoev.ru 
362216Sigor@sysoev.ru     app = dlsym(dl, "nxt_app_module");
363216Sigor@sysoev.ru 
364216Sigor@sysoev.ru     if (app != NULL) {
365612Salexander.borisov@nginx.com         nxt_log(task, NXT_LOG_NOTICE, "module: %V %s \"%s\"",
366612Salexander.borisov@nginx.com                 &app->type, app->version, name);
367258Sigor@sysoev.ru 
368258Sigor@sysoev.ru         if (app->compat_length != sizeof(compat)
3692231Salx@nginx.com             || memcmp(app->compat, compat, sizeof(compat)) != 0)
370258Sigor@sysoev.ru         {
371258Sigor@sysoev.ru             nxt_log(task, NXT_LOG_NOTICE, "incompatible module %s", name);
372258Sigor@sysoev.ru 
373258Sigor@sysoev.ru             goto done;
374258Sigor@sysoev.ru         }
375216Sigor@sysoev.ru 
376356Svbart@nginx.com         type = nxt_app_parse_type(app->type.start, app->type.length);
377356Svbart@nginx.com 
378356Svbart@nginx.com         if (type == NXT_APP_UNKNOWN) {
379494Spluknet@nginx.com             nxt_log(task, NXT_LOG_NOTICE, "unknown module type %V", &app->type);
380356Svbart@nginx.com 
381356Svbart@nginx.com             goto done;
382356Svbart@nginx.com         }
383356Svbart@nginx.com 
384216Sigor@sysoev.ru         module = modules->elts;
385216Sigor@sysoev.ru         n = modules->nelts;
386216Sigor@sysoev.ru 
387612Salexander.borisov@nginx.com         version.start = (u_char *) app->version;
388612Salexander.borisov@nginx.com         version.length = nxt_strlen(app->version);
389612Salexander.borisov@nginx.com 
390216Sigor@sysoev.ru         for (i = 0; i < n; i++) {
391356Svbart@nginx.com             if (type == module[i].type
392612Salexander.borisov@nginx.com                 && nxt_strstr_eq(&module[i].version, &version))
393258Sigor@sysoev.ru             {
394216Sigor@sysoev.ru                 nxt_log(task, NXT_LOG_NOTICE,
395216Sigor@sysoev.ru                         "ignoring %s module with the same "
396267Sigor@sysoev.ru                         "application language version %V %V as in %V",
397655Svbart@nginx.com                         name, &app->type, &version, &module[i].file);
398216Sigor@sysoev.ru 
399216Sigor@sysoev.ru                 goto done;
400216Sigor@sysoev.ru             }
401216Sigor@sysoev.ru         }
402216Sigor@sysoev.ru 
403216Sigor@sysoev.ru         module = nxt_array_add(modules);
404216Sigor@sysoev.ru         if (module == NULL) {
405216Sigor@sysoev.ru             goto fail;
406216Sigor@sysoev.ru         }
407216Sigor@sysoev.ru 
408356Svbart@nginx.com         module->type = type;
409216Sigor@sysoev.ru 
410612Salexander.borisov@nginx.com         nxt_str_dup(mp, &module->version, &version);
411612Salexander.borisov@nginx.com         if (module->version.start == NULL) {
412216Sigor@sysoev.ru             goto fail;
413216Sigor@sysoev.ru         }
414216Sigor@sysoev.ru 
415216Sigor@sysoev.ru         module->file.length = nxt_strlen(name);
416216Sigor@sysoev.ru 
417216Sigor@sysoev.ru         module->file.start = nxt_mp_alloc(mp, module->file.length);
418216Sigor@sysoev.ru         if (module->file.start == NULL) {
419216Sigor@sysoev.ru             goto fail;
420216Sigor@sysoev.ru         }
421216Sigor@sysoev.ru 
422216Sigor@sysoev.ru         nxt_memcpy(module->file.start, name, module->file.length);
423216Sigor@sysoev.ru 
4241489St.nateldemoura@f5.com         module->mounts = nxt_array_create(mp, app->nmounts,
4251489St.nateldemoura@f5.com                                           sizeof(nxt_fs_mount_t));
4261489St.nateldemoura@f5.com 
4271489St.nateldemoura@f5.com         if (nxt_slow_path(module->mounts == NULL)) {
4281489St.nateldemoura@f5.com             goto fail;
4291489St.nateldemoura@f5.com         }
4301489St.nateldemoura@f5.com 
4311489St.nateldemoura@f5.com         mounts = module->mounts;
4321489St.nateldemoura@f5.com 
4331489St.nateldemoura@f5.com         for (j = 0; j < app->nmounts; j++) {
4341489St.nateldemoura@f5.com             from = &app->mounts[j];
4351489St.nateldemoura@f5.com             to = nxt_array_zero_add(mounts);
4361489St.nateldemoura@f5.com             if (nxt_slow_path(to == NULL)) {
4371489St.nateldemoura@f5.com                 goto fail;
4381489St.nateldemoura@f5.com             }
4391489St.nateldemoura@f5.com 
4401489St.nateldemoura@f5.com             to->src = nxt_cstr_dup(mp, to->src, from->src);
4411489St.nateldemoura@f5.com             if (nxt_slow_path(to->src == NULL)) {
4421489St.nateldemoura@f5.com                 goto fail;
4431489St.nateldemoura@f5.com             }
4441489St.nateldemoura@f5.com 
4451489St.nateldemoura@f5.com             to->dst = nxt_cstr_dup(mp, to->dst, from->dst);
4461489St.nateldemoura@f5.com             if (nxt_slow_path(to->dst == NULL)) {
4471489St.nateldemoura@f5.com                 goto fail;
4481489St.nateldemoura@f5.com             }
4491489St.nateldemoura@f5.com 
4501673St.nateldemoura@f5.com             to->name = nxt_cstr_dup(mp, to->name, from->name);
4511673St.nateldemoura@f5.com             if (nxt_slow_path(to->name == NULL)) {
4521489St.nateldemoura@f5.com                 goto fail;
4531489St.nateldemoura@f5.com             }
4541489St.nateldemoura@f5.com 
4551673St.nateldemoura@f5.com             to->type = from->type;
4561673St.nateldemoura@f5.com 
4571489St.nateldemoura@f5.com             if (from->data != NULL) {
4581489St.nateldemoura@f5.com                 to->data = nxt_cstr_dup(mp, to->data, from->data);
4591489St.nateldemoura@f5.com                 if (nxt_slow_path(to->data == NULL)) {
4601489St.nateldemoura@f5.com                     goto fail;
4611489St.nateldemoura@f5.com                 }
4621489St.nateldemoura@f5.com             }
4631489St.nateldemoura@f5.com 
4641489St.nateldemoura@f5.com             to->flags = from->flags;
4651489St.nateldemoura@f5.com         }
4661489St.nateldemoura@f5.com 
467216Sigor@sysoev.ru     } else {
468564Svbart@nginx.com         nxt_alert(task, "dlsym(\"%s\"), failed: \"%s\"", name, dlerror());
469216Sigor@sysoev.ru     }
470216Sigor@sysoev.ru 
471216Sigor@sysoev.ru done:
472216Sigor@sysoev.ru 
473216Sigor@sysoev.ru     ret = NXT_OK;
474216Sigor@sysoev.ru 
475216Sigor@sysoev.ru fail:
476216Sigor@sysoev.ru 
477216Sigor@sysoev.ru     if (dlclose(dl) != 0) {
478564Svbart@nginx.com         nxt_alert(task, "dlclose(\"%s\"), failed: \"%s\"", name, dlerror());
479216Sigor@sysoev.ru     }
480216Sigor@sysoev.ru 
481216Sigor@sysoev.ru     return ret;
482216Sigor@sysoev.ru }
483216Sigor@sysoev.ru 
484216Sigor@sysoev.ru 
485549Svbart@nginx.com static void
nxt_discovery_completion_handler(nxt_task_t * task,void * obj,void * data)486549Svbart@nginx.com nxt_discovery_completion_handler(nxt_task_t *task, void *obj, void *data)
487549Svbart@nginx.com {
488549Svbart@nginx.com     nxt_mp_t   *mp;
489549Svbart@nginx.com     nxt_buf_t  *b;
490549Svbart@nginx.com 
491549Svbart@nginx.com     b = obj;
492549Svbart@nginx.com     mp = b->data;
493549Svbart@nginx.com 
494549Svbart@nginx.com     nxt_mp_destroy(mp);
495549Svbart@nginx.com }
496549Svbart@nginx.com 
497549Svbart@nginx.com 
498549Svbart@nginx.com static void
nxt_discovery_quit(nxt_task_t * task,nxt_port_recv_msg_t * msg,void * data)499549Svbart@nginx.com nxt_discovery_quit(nxt_task_t *task, nxt_port_recv_msg_t *msg, void *data)
500549Svbart@nginx.com {
5011488St.nateldemoura@f5.com     nxt_signal_quit_handler(task, msg);
502549Svbart@nginx.com }
503549Svbart@nginx.com 
504549Svbart@nginx.com 
5051488St.nateldemoura@f5.com static nxt_int_t
nxt_proto_setup(nxt_task_t * task,nxt_process_t * process)5061998St.nateldemoura@f5.com nxt_proto_setup(nxt_task_t *task, nxt_process_t *process)
5070Sigor@sysoev.ru {
508216Sigor@sysoev.ru     nxt_int_t              ret;
509216Sigor@sysoev.ru     nxt_app_lang_module_t  *lang;
510216Sigor@sysoev.ru     nxt_common_app_conf_t  *app_conf;
511141Smax.romanov@nginx.com 
5121488St.nateldemoura@f5.com     app_conf = process->data.app;
513141Smax.romanov@nginx.com 
5141998St.nateldemoura@f5.com     nxt_queue_init(&nxt_proto_children);
5151998St.nateldemoura@f5.com 
5161998St.nateldemoura@f5.com     nxt_app_conf = app_conf;
5171998St.nateldemoura@f5.com 
518216Sigor@sysoev.ru     lang = nxt_app_lang_module(task->thread->runtime, &app_conf->type);
519216Sigor@sysoev.ru     if (nxt_slow_path(lang == NULL)) {
520564Svbart@nginx.com         nxt_alert(task, "unknown application type: \"%V\"", &app_conf->type);
521216Sigor@sysoev.ru         return NXT_ERROR;
522216Sigor@sysoev.ru     }
523216Sigor@sysoev.ru 
524216Sigor@sysoev.ru     nxt_app = lang->module;
525216Sigor@sysoev.ru 
526216Sigor@sysoev.ru     if (nxt_app == NULL) {
527354Svbart@nginx.com         nxt_debug(task, "application language module: %s \"%s\"",
528354Svbart@nginx.com                   lang->version, lang->file);
529216Sigor@sysoev.ru 
530216Sigor@sysoev.ru         nxt_app = nxt_app_module_load(task, lang->file);
5311239Smax.romanov@nginx.com         if (nxt_slow_path(nxt_app == NULL)) {
5321239Smax.romanov@nginx.com             return NXT_ERROR;
5331239Smax.romanov@nginx.com         }
534216Sigor@sysoev.ru     }
535216Sigor@sysoev.ru 
5361489St.nateldemoura@f5.com     if (nxt_slow_path(nxt_app_set_environment(app_conf->environment)
5371489St.nateldemoura@f5.com                       != NXT_OK))
5381489St.nateldemoura@f5.com     {
5391489St.nateldemoura@f5.com         nxt_alert(task, "failed to set environment");
5401489St.nateldemoura@f5.com         return NXT_ERROR;
5411489St.nateldemoura@f5.com     }
5421489St.nateldemoura@f5.com 
5431488St.nateldemoura@f5.com     if (nxt_app->setup != NULL) {
5441488St.nateldemoura@f5.com         ret = nxt_app->setup(task, process, app_conf);
545977Smax.romanov@gmail.com         if (nxt_slow_path(ret != NXT_OK)) {
5461104Smax.romanov@nginx.com             return ret;
547977Smax.romanov@gmail.com         }
548977Smax.romanov@gmail.com     }
549977Smax.romanov@gmail.com 
5501489St.nateldemoura@f5.com #if (NXT_HAVE_ISOLATION_ROOTFS)
5511489St.nateldemoura@f5.com     if (process->isolation.rootfs != NULL) {
5521489St.nateldemoura@f5.com         if (process->isolation.mounts != NULL) {
5531579St.nateldemoura@f5.com             ret = nxt_isolation_prepare_rootfs(task, process);
5541489St.nateldemoura@f5.com             if (nxt_slow_path(ret != NXT_OK)) {
5551489St.nateldemoura@f5.com                 return ret;
5561489St.nateldemoura@f5.com             }
5571489St.nateldemoura@f5.com         }
5581489St.nateldemoura@f5.com 
5591579St.nateldemoura@f5.com         ret = nxt_isolation_change_root(task, process);
5601489St.nateldemoura@f5.com         if (nxt_slow_path(ret != NXT_OK)) {
5611489St.nateldemoura@f5.com             return NXT_ERROR;
5621489St.nateldemoura@f5.com         }
5631489St.nateldemoura@f5.com     }
5641489St.nateldemoura@f5.com #endif
5651489St.nateldemoura@f5.com 
566277Sigor@sysoev.ru     if (app_conf->working_directory != NULL
567277Sigor@sysoev.ru         && app_conf->working_directory[0] != 0)
568271Smax.romanov@nginx.com     {
569271Smax.romanov@nginx.com         ret = chdir(app_conf->working_directory);
570271Smax.romanov@nginx.com 
571271Smax.romanov@nginx.com         if (nxt_slow_path(ret != 0)) {
572271Smax.romanov@nginx.com             nxt_log(task, NXT_LOG_WARN, "chdir(%s) failed %E",
573271Smax.romanov@nginx.com                     app_conf->working_directory, nxt_errno);
574271Smax.romanov@nginx.com 
575271Smax.romanov@nginx.com             return NXT_ERROR;
576271Smax.romanov@nginx.com         }
577271Smax.romanov@nginx.com     }
578271Smax.romanov@nginx.com 
5791998St.nateldemoura@f5.com     process->state = NXT_PROCESS_STATE_CREATED;
5801998St.nateldemoura@f5.com 
5811998St.nateldemoura@f5.com     return NXT_OK;
5821998St.nateldemoura@f5.com }
5831998St.nateldemoura@f5.com 
5841998St.nateldemoura@f5.com 
5851998St.nateldemoura@f5.com static nxt_int_t
nxt_proto_start(nxt_task_t * task,nxt_process_data_t * data)5861998St.nateldemoura@f5.com nxt_proto_start(nxt_task_t *task, nxt_process_data_t *data)
5871998St.nateldemoura@f5.com {
5881998St.nateldemoura@f5.com     nxt_debug(task, "prototype waiting for clone messages");
5891998St.nateldemoura@f5.com 
5901998St.nateldemoura@f5.com     return NXT_OK;
5911998St.nateldemoura@f5.com }
5921998St.nateldemoura@f5.com 
5931998St.nateldemoura@f5.com 
5941998St.nateldemoura@f5.com static void
nxt_proto_start_process_handler(nxt_task_t * task,nxt_port_recv_msg_t * msg)5951998St.nateldemoura@f5.com nxt_proto_start_process_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
5961998St.nateldemoura@f5.com {
5971998St.nateldemoura@f5.com     u_char              *p;
5981998St.nateldemoura@f5.com     nxt_int_t           ret;
5991998St.nateldemoura@f5.com     nxt_port_t          *port;
6001998St.nateldemoura@f5.com     nxt_runtime_t       *rt;
6011998St.nateldemoura@f5.com     nxt_process_t       *process;
6021998St.nateldemoura@f5.com     nxt_process_init_t  *init;
6031998St.nateldemoura@f5.com 
6041998St.nateldemoura@f5.com     rt = task->thread->runtime;
6051998St.nateldemoura@f5.com 
6061998St.nateldemoura@f5.com     process = nxt_process_new(rt);
6071998St.nateldemoura@f5.com     if (nxt_slow_path(process == NULL)) {
6081998St.nateldemoura@f5.com         goto failed;
6091998St.nateldemoura@f5.com     }
6101998St.nateldemoura@f5.com 
6111998St.nateldemoura@f5.com     process->mem_pool = nxt_mp_create(1024, 128, 256, 32);
6121998St.nateldemoura@f5.com     if (nxt_slow_path(process->mem_pool == NULL)) {
6131998St.nateldemoura@f5.com         nxt_process_use(task, process, -1);
6141998St.nateldemoura@f5.com         goto failed;
6151998St.nateldemoura@f5.com     }
6161998St.nateldemoura@f5.com 
6171998St.nateldemoura@f5.com     process->parent_port = rt->port_by_type[NXT_PROCESS_PROTOTYPE];
6181998St.nateldemoura@f5.com 
6191488St.nateldemoura@f5.com     init = nxt_process_init(process);
6201998St.nateldemoura@f5.com     *init = nxt_app_process;
6211998St.nateldemoura@f5.com 
6221998St.nateldemoura@f5.com     process->name = nxt_mp_alloc(process->mem_pool, nxt_app_conf->name.length
6231998St.nateldemoura@f5.com                                  + sizeof("\"\" application") + 1);
6241998St.nateldemoura@f5.com 
6251998St.nateldemoura@f5.com     if (nxt_slow_path(process->name == NULL)) {
6261998St.nateldemoura@f5.com         nxt_process_use(task, process, -1);
6271998St.nateldemoura@f5.com 
6281998St.nateldemoura@f5.com         goto failed;
6291998St.nateldemoura@f5.com     }
630141Smax.romanov@nginx.com 
6311488St.nateldemoura@f5.com     init->start = nxt_app->start;
632141Smax.romanov@nginx.com 
6331998St.nateldemoura@f5.com     init->name = (const char *) nxt_app_conf->name.start;
6341998St.nateldemoura@f5.com 
6351998St.nateldemoura@f5.com     p = (u_char *) process->name;
6361998St.nateldemoura@f5.com     *p++ = '"';
6371998St.nateldemoura@f5.com     p = nxt_cpymem(p, nxt_app_conf->name.start, nxt_app_conf->name.length);
6381998St.nateldemoura@f5.com     p = nxt_cpymem(p, "\" application", 13);
6391998St.nateldemoura@f5.com     *p = '\0';
6401998St.nateldemoura@f5.com 
6411998St.nateldemoura@f5.com     process->user_cred = &rt->user_cred;
6421998St.nateldemoura@f5.com 
6431998St.nateldemoura@f5.com     process->data.app = nxt_app_conf;
6441998St.nateldemoura@f5.com     process->stream = msg->port_msg.stream;
6451998St.nateldemoura@f5.com 
6462174Smax.romanov@gmail.com     init->siblings = &nxt_proto_children;
6472174Smax.romanov@gmail.com 
6481998St.nateldemoura@f5.com     ret = nxt_process_start(task, process);
6491998St.nateldemoura@f5.com     if (nxt_slow_path(ret == NXT_ERROR)) {
6501998St.nateldemoura@f5.com         nxt_process_use(task, process, -1);
6511998St.nateldemoura@f5.com 
6521998St.nateldemoura@f5.com         goto failed;
6531998St.nateldemoura@f5.com     }
6541998St.nateldemoura@f5.com 
6551998St.nateldemoura@f5.com     nxt_proto_process_add(task, process);
6561998St.nateldemoura@f5.com 
6571998St.nateldemoura@f5.com     return;
6581998St.nateldemoura@f5.com 
6591998St.nateldemoura@f5.com failed:
6601998St.nateldemoura@f5.com 
6611998St.nateldemoura@f5.com     port = nxt_runtime_port_find(rt, msg->port_msg.pid,
6621998St.nateldemoura@f5.com                                  msg->port_msg.reply_port);
6631998St.nateldemoura@f5.com 
6641998St.nateldemoura@f5.com     if (nxt_fast_path(port != NULL)) {
6651998St.nateldemoura@f5.com         nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_ERROR,
6661998St.nateldemoura@f5.com                               -1, msg->port_msg.stream, 0, NULL);
6671998St.nateldemoura@f5.com     }
6681998St.nateldemoura@f5.com }
6691998St.nateldemoura@f5.com 
6701998St.nateldemoura@f5.com 
6711998St.nateldemoura@f5.com static void
nxt_proto_quit_handler(nxt_task_t * task,nxt_port_recv_msg_t * msg)6721998St.nateldemoura@f5.com nxt_proto_quit_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
6731998St.nateldemoura@f5.com {
6741998St.nateldemoura@f5.com     nxt_debug(task, "prototype quit handler");
6751998St.nateldemoura@f5.com 
6761998St.nateldemoura@f5.com     nxt_proto_quit_children(task);
6771998St.nateldemoura@f5.com 
6781998St.nateldemoura@f5.com     nxt_proto_exiting = 1;
6791998St.nateldemoura@f5.com 
6801998St.nateldemoura@f5.com     if (nxt_queue_is_empty(&nxt_proto_children)) {
6811998St.nateldemoura@f5.com         nxt_process_quit(task, 0);
6821998St.nateldemoura@f5.com     }
6831998St.nateldemoura@f5.com }
6841998St.nateldemoura@f5.com 
6851998St.nateldemoura@f5.com 
6861998St.nateldemoura@f5.com static void
nxt_proto_quit_children(nxt_task_t * task)6871998St.nateldemoura@f5.com nxt_proto_quit_children(nxt_task_t *task)
6881998St.nateldemoura@f5.com {
6891998St.nateldemoura@f5.com     nxt_port_t     *port;
6901998St.nateldemoura@f5.com     nxt_process_t  *process;
6911998St.nateldemoura@f5.com 
6921998St.nateldemoura@f5.com     nxt_queue_each(process, &nxt_proto_children, nxt_process_t, link) {
6931998St.nateldemoura@f5.com         port = nxt_process_port_first(process);
6941998St.nateldemoura@f5.com 
6951998St.nateldemoura@f5.com         (void) nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT,
6961998St.nateldemoura@f5.com                                      -1, 0, 0, NULL);
6971998St.nateldemoura@f5.com     }
6981998St.nateldemoura@f5.com     nxt_queue_loop;
6991998St.nateldemoura@f5.com }
7001998St.nateldemoura@f5.com 
7011998St.nateldemoura@f5.com 
7021998St.nateldemoura@f5.com static void
nxt_proto_process_created_handler(nxt_task_t * task,nxt_port_recv_msg_t * msg)7031998St.nateldemoura@f5.com nxt_proto_process_created_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
7041998St.nateldemoura@f5.com {
7051998St.nateldemoura@f5.com     nxt_pid_t      isolated_pid, pid;
7061998St.nateldemoura@f5.com     nxt_process_t  *process;
7071998St.nateldemoura@f5.com 
7081998St.nateldemoura@f5.com     isolated_pid = nxt_recv_msg_cmsg_pid(msg);
7091998St.nateldemoura@f5.com 
7101998St.nateldemoura@f5.com     process = nxt_proto_process_find(task, isolated_pid);
7111998St.nateldemoura@f5.com     if (nxt_slow_path(process == NULL)) {
7121998St.nateldemoura@f5.com         return;
7131998St.nateldemoura@f5.com     }
7141998St.nateldemoura@f5.com 
7151488St.nateldemoura@f5.com     process->state = NXT_PROCESS_STATE_CREATED;
71620Sigor@sysoev.ru 
7171998St.nateldemoura@f5.com     pid = msg->port_msg.pid;
7181998St.nateldemoura@f5.com 
7191998St.nateldemoura@f5.com     if (process->pid != pid) {
7201998St.nateldemoura@f5.com         nxt_debug(task, "app process %PI (aka %PI) is created", isolated_pid,
7211998St.nateldemoura@f5.com                   pid);
7221998St.nateldemoura@f5.com 
7232174Smax.romanov@gmail.com         process->pid = pid;
7241998St.nateldemoura@f5.com 
7252174Smax.romanov@gmail.com     } else {
726