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); 451488St.nateldemoura@f5.com static nxt_int_t nxt_app_setup(nxt_task_t *task, nxt_process_t *process); 46678Svbart@nginx.com static nxt_int_t nxt_app_set_environment(nxt_conf_value_t *environment); 471489St.nateldemoura@f5.com static u_char *nxt_cstr_dup(nxt_mp_t *mp, u_char *dst, u_char *src); 481489St.nateldemoura@f5.com 491489St.nateldemoura@f5.com 501488St.nateldemoura@f5.com nxt_str_t nxt_server = nxt_string(NXT_SERVER); 510Sigor@sysoev.ru 52216Sigor@sysoev.ru 53258Sigor@sysoev.ru static uint32_t compat[] = { 54360Sigor@sysoev.ru NXT_VERNUM, NXT_DEBUG, 55258Sigor@sysoev.ru }; 56258Sigor@sysoev.ru 57258Sigor@sysoev.ru 58743Smax.romanov@nginx.com static nxt_app_module_t *nxt_app; 59417Svbart@nginx.com 60417Svbart@nginx.com 611488St.nateldemoura@f5.com static const nxt_port_handlers_t nxt_discovery_process_port_handlers = { 621488St.nateldemoura@f5.com .quit = nxt_signal_quit_handler, 631488St.nateldemoura@f5.com .new_port = nxt_port_new_port_handler, 641488St.nateldemoura@f5.com .change_file = nxt_port_change_log_file_handler, 651488St.nateldemoura@f5.com .mmap = nxt_port_mmap_handler, 661488St.nateldemoura@f5.com .data = nxt_port_data_handler, 671488St.nateldemoura@f5.com .remove_pid = nxt_port_remove_pid_handler, 681488St.nateldemoura@f5.com .rpc_ready = nxt_port_rpc_handler, 691488St.nateldemoura@f5.com .rpc_error = nxt_port_rpc_handler, 701488St.nateldemoura@f5.com }; 711488St.nateldemoura@f5.com 721488St.nateldemoura@f5.com 731488St.nateldemoura@f5.com static const nxt_port_handlers_t nxt_app_process_port_handlers = { 741488St.nateldemoura@f5.com .quit = nxt_signal_quit_handler, 751488St.nateldemoura@f5.com .rpc_ready = nxt_port_rpc_handler, 761488St.nateldemoura@f5.com .rpc_error = nxt_port_rpc_handler, 771488St.nateldemoura@f5.com }; 781488St.nateldemoura@f5.com 791488St.nateldemoura@f5.com 801488St.nateldemoura@f5.com const nxt_process_init_t nxt_discovery_process = { 811488St.nateldemoura@f5.com .name = "discovery", 821488St.nateldemoura@f5.com .type = NXT_PROCESS_DISCOVERY, 831488St.nateldemoura@f5.com .prefork = NULL, 841488St.nateldemoura@f5.com .restart = 0, 851488St.nateldemoura@f5.com .setup = nxt_process_core_setup, 861488St.nateldemoura@f5.com .start = nxt_discovery_start, 871488St.nateldemoura@f5.com .port_handlers = &nxt_discovery_process_port_handlers, 881488St.nateldemoura@f5.com .signals = nxt_process_signals, 891488St.nateldemoura@f5.com }; 901488St.nateldemoura@f5.com 911488St.nateldemoura@f5.com 921488St.nateldemoura@f5.com const nxt_process_init_t nxt_app_process = { 931488St.nateldemoura@f5.com .type = NXT_PROCESS_APP, 941488St.nateldemoura@f5.com .setup = nxt_app_setup, 951579St.nateldemoura@f5.com .prefork = nxt_isolation_main_prefork, 961488St.nateldemoura@f5.com .restart = 0, 971488St.nateldemoura@f5.com .start = NULL, /* set to module->start */ 981488St.nateldemoura@f5.com .port_handlers = &nxt_app_process_port_handlers, 991488St.nateldemoura@f5.com .signals = nxt_process_signals, 1001488St.nateldemoura@f5.com }; 1011488St.nateldemoura@f5.com 1021488St.nateldemoura@f5.com 1031488St.nateldemoura@f5.com static nxt_int_t 1041488St.nateldemoura@f5.com nxt_discovery_start(nxt_task_t *task, nxt_process_data_t *data) 105216Sigor@sysoev.ru { 106549Svbart@nginx.com uint32_t stream; 107549Svbart@nginx.com nxt_buf_t *b; 108549Svbart@nginx.com nxt_int_t ret; 109549Svbart@nginx.com nxt_port_t *main_port, *discovery_port; 110549Svbart@nginx.com nxt_runtime_t *rt; 111216Sigor@sysoev.ru 1121488St.nateldemoura@f5.com nxt_log(task, NXT_LOG_INFO, "discovery started"); 113216Sigor@sysoev.ru 114233Sigor@sysoev.ru rt = task->thread->runtime; 115216Sigor@sysoev.ru 116233Sigor@sysoev.ru b = nxt_discovery_modules(task, rt->modules); 117250Sigor@sysoev.ru if (nxt_slow_path(b == NULL)) { 118549Svbart@nginx.com return NXT_ERROR; 119250Sigor@sysoev.ru } 120233Sigor@sysoev.ru 121240Sigor@sysoev.ru main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 122549Svbart@nginx.com discovery_port = rt->port_by_type[NXT_PROCESS_DISCOVERY]; 123216Sigor@sysoev.ru 124549Svbart@nginx.com stream = nxt_port_rpc_register_handler(task, discovery_port, 125549Svbart@nginx.com nxt_discovery_quit, 126549Svbart@nginx.com nxt_discovery_quit, 127549Svbart@nginx.com main_port->pid, NULL); 128549Svbart@nginx.com 129645Svbart@nginx.com if (nxt_slow_path(stream == 0)) { 130645Svbart@nginx.com return NXT_ERROR; 131645Svbart@nginx.com } 132645Svbart@nginx.com 133549Svbart@nginx.com ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_MODULES, -1, 134549Svbart@nginx.com stream, discovery_port->id, b); 135549Svbart@nginx.com 136549Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 137549Svbart@nginx.com nxt_port_rpc_cancel(task, discovery_port, stream); 138549Svbart@nginx.com return NXT_ERROR; 139549Svbart@nginx.com } 140216Sigor@sysoev.ru 141216Sigor@sysoev.ru return NXT_OK; 142216Sigor@sysoev.ru } 143216Sigor@sysoev.ru 144216Sigor@sysoev.ru 145216Sigor@sysoev.ru static nxt_buf_t * 146216Sigor@sysoev.ru nxt_discovery_modules(nxt_task_t *task, const char *path) 147216Sigor@sysoev.ru { 1481489St.nateldemoura@f5.com char *name; 1491489St.nateldemoura@f5.com u_char *p, *end; 1501489St.nateldemoura@f5.com size_t size; 1511489St.nateldemoura@f5.com glob_t glb; 1521489St.nateldemoura@f5.com nxt_mp_t *mp; 1531489St.nateldemoura@f5.com nxt_buf_t *b; 1541489St.nateldemoura@f5.com nxt_int_t ret; 1551489St.nateldemoura@f5.com nxt_uint_t i, n, j; 1561489St.nateldemoura@f5.com nxt_array_t *modules, *mounts; 1571489St.nateldemoura@f5.com nxt_module_t *module; 1581489St.nateldemoura@f5.com nxt_fs_mount_t *mnt; 159216Sigor@sysoev.ru 160216Sigor@sysoev.ru b = NULL; 161216Sigor@sysoev.ru 162216Sigor@sysoev.ru mp = nxt_mp_create(1024, 128, 256, 32); 163216Sigor@sysoev.ru if (mp == NULL) { 164216Sigor@sysoev.ru return b; 165216Sigor@sysoev.ru } 166216Sigor@sysoev.ru 167216Sigor@sysoev.ru ret = glob(path, 0, NULL, &glb); 168216Sigor@sysoev.ru 169250Sigor@sysoev.ru n = glb.gl_pathc; 170250Sigor@sysoev.ru 171250Sigor@sysoev.ru if (ret != 0) { 172250Sigor@sysoev.ru nxt_log(task, NXT_LOG_NOTICE, 173250Sigor@sysoev.ru "no modules matching: \"%s\" found", path); 174250Sigor@sysoev.ru n = 0; 175250Sigor@sysoev.ru } 176216Sigor@sysoev.ru 177250Sigor@sysoev.ru modules = nxt_array_create(mp, n, sizeof(nxt_module_t)); 178250Sigor@sysoev.ru if (modules == NULL) { 179250Sigor@sysoev.ru goto fail; 180250Sigor@sysoev.ru } 181250Sigor@sysoev.ru 182250Sigor@sysoev.ru for (i = 0; i < n; i++) { 183250Sigor@sysoev.ru name = glb.gl_pathv[i]; 184250Sigor@sysoev.ru 185250Sigor@sysoev.ru ret = nxt_discovery_module(task, mp, modules, name); 186250Sigor@sysoev.ru if (ret != NXT_OK) { 187216Sigor@sysoev.ru goto fail; 188216Sigor@sysoev.ru } 189250Sigor@sysoev.ru } 190216Sigor@sysoev.ru 191703Svbart@nginx.com size = nxt_length("[]"); 192250Sigor@sysoev.ru module = modules->elts; 193250Sigor@sysoev.ru n = modules->nelts; 194216Sigor@sysoev.ru 195250Sigor@sysoev.ru for (i = 0; i < n; i++) { 196356Svbart@nginx.com nxt_debug(task, "module: %d %V %V", 197356Svbart@nginx.com module[i].type, &module[i].version, &module[i].file); 198216Sigor@sysoev.ru 199703Svbart@nginx.com size += nxt_length("{\"type\": ,"); 200703Svbart@nginx.com size += nxt_length(" \"version\": \"\","); 2011489St.nateldemoura@f5.com size += nxt_length(" \"file\": \"\","); 2021489St.nateldemoura@f5.com size += nxt_length(" \"mounts\": []},"); 203216Sigor@sysoev.ru 204356Svbart@nginx.com size += NXT_INT_T_LEN 205250Sigor@sysoev.ru + module[i].version.length 206250Sigor@sysoev.ru + module[i].file.length; 2071489St.nateldemoura@f5.com 2081489St.nateldemoura@f5.com mounts = module[i].mounts; 2091489St.nateldemoura@f5.com 2101489St.nateldemoura@f5.com size += mounts->nelts * nxt_length("{\"src\": \"\", \"dst\": \"\", " 211*1673St.nateldemoura@f5.com "\"type\": , \"name\": \"\", " 212*1673St.nateldemoura@f5.com "\"flags\": , \"data\": \"\"},"); 2131489St.nateldemoura@f5.com 2141489St.nateldemoura@f5.com mnt = mounts->elts; 2151489St.nateldemoura@f5.com 2161489St.nateldemoura@f5.com for (j = 0; j < mounts->nelts; j++) { 2171489St.nateldemoura@f5.com size += nxt_strlen(mnt[j].src) + nxt_strlen(mnt[j].dst) 218*1673St.nateldemoura@f5.com + nxt_strlen(mnt[j].name) + (2 * NXT_INT_T_LEN) 2191489St.nateldemoura@f5.com + (mnt[j].data == NULL ? 0 : nxt_strlen(mnt[j].data)); 2201489St.nateldemoura@f5.com } 221250Sigor@sysoev.ru } 222216Sigor@sysoev.ru 223250Sigor@sysoev.ru b = nxt_buf_mem_alloc(mp, size, 0); 224250Sigor@sysoev.ru if (b == NULL) { 225250Sigor@sysoev.ru goto fail; 226250Sigor@sysoev.ru } 227216Sigor@sysoev.ru 228250Sigor@sysoev.ru b->completion_handler = nxt_discovery_completion_handler; 229216Sigor@sysoev.ru 230250Sigor@sysoev.ru p = b->mem.free; 231250Sigor@sysoev.ru end = b->mem.end; 232250Sigor@sysoev.ru *p++ = '['; 233216Sigor@sysoev.ru 234250Sigor@sysoev.ru for (i = 0; i < n; i++) { 2351489St.nateldemoura@f5.com mounts = module[i].mounts; 2361489St.nateldemoura@f5.com 2371489St.nateldemoura@f5.com p = nxt_sprintf(p, end, "{\"type\": %d, \"version\": \"%V\", " 2381489St.nateldemoura@f5.com "\"file\": \"%V\", \"mounts\": [", 2391489St.nateldemoura@f5.com module[i].type, &module[i].version, &module[i].file); 2401489St.nateldemoura@f5.com 2411489St.nateldemoura@f5.com mnt = mounts->elts; 2421489St.nateldemoura@f5.com for (j = 0; j < mounts->nelts; j++) { 2431489St.nateldemoura@f5.com p = nxt_sprintf(p, end, 2441489St.nateldemoura@f5.com "{\"src\": \"%s\", \"dst\": \"%s\", " 245*1673St.nateldemoura@f5.com "\"name\": \"%s\", \"type\": %d, \"flags\": %d, " 2461489St.nateldemoura@f5.com "\"data\": \"%s\"},", 247*1673St.nateldemoura@f5.com mnt[j].src, mnt[j].dst, mnt[j].name, mnt[j].type, 248*1673St.nateldemoura@f5.com mnt[j].flags, 2491489St.nateldemoura@f5.com mnt[j].data == NULL ? (u_char *) "" : mnt[j].data); 2501489St.nateldemoura@f5.com } 2511489St.nateldemoura@f5.com 2521489St.nateldemoura@f5.com *p++ = ']'; 2531489St.nateldemoura@f5.com *p++ = '}'; 2541489St.nateldemoura@f5.com *p++ = ','; 255250Sigor@sysoev.ru } 256216Sigor@sysoev.ru 257250Sigor@sysoev.ru *p++ = ']'; 2581489St.nateldemoura@f5.com 2591515Smax.romanov@nginx.com if (nxt_slow_path(p > end)) { 2601489St.nateldemoura@f5.com nxt_alert(task, "discovery write past the buffer"); 2611489St.nateldemoura@f5.com goto fail; 2621489St.nateldemoura@f5.com } 2631489St.nateldemoura@f5.com 264250Sigor@sysoev.ru b->mem.free = p; 265216Sigor@sysoev.ru 266216Sigor@sysoev.ru fail: 267216Sigor@sysoev.ru 268216Sigor@sysoev.ru globfree(&glb); 269216Sigor@sysoev.ru 270216Sigor@sysoev.ru return b; 271216Sigor@sysoev.ru } 272216Sigor@sysoev.ru 273216Sigor@sysoev.ru 274216Sigor@sysoev.ru static nxt_int_t 275216Sigor@sysoev.ru nxt_discovery_module(nxt_task_t *task, nxt_mp_t *mp, nxt_array_t *modules, 276216Sigor@sysoev.ru const char *name) 277216Sigor@sysoev.ru { 2781489St.nateldemoura@f5.com void *dl; 2791489St.nateldemoura@f5.com nxt_str_t version; 2801489St.nateldemoura@f5.com nxt_int_t ret; 2811489St.nateldemoura@f5.com nxt_uint_t i, j, n; 2821489St.nateldemoura@f5.com nxt_array_t *mounts; 2831489St.nateldemoura@f5.com nxt_module_t *module; 2841489St.nateldemoura@f5.com nxt_app_type_t type; 2851489St.nateldemoura@f5.com nxt_fs_mount_t *to; 2861489St.nateldemoura@f5.com nxt_app_module_t *app; 2871489St.nateldemoura@f5.com const nxt_fs_mount_t *from; 288216Sigor@sysoev.ru 289216Sigor@sysoev.ru /* 290216Sigor@sysoev.ru * Only memory allocation failure should return NXT_ERROR. 291216Sigor@sysoev.ru * Any module processing errors are ignored. 292216Sigor@sysoev.ru */ 293216Sigor@sysoev.ru ret = NXT_ERROR; 294216Sigor@sysoev.ru 295216Sigor@sysoev.ru dl = dlopen(name, RTLD_GLOBAL | RTLD_NOW); 296216Sigor@sysoev.ru 297216Sigor@sysoev.ru if (dl == NULL) { 298564Svbart@nginx.com nxt_alert(task, "dlopen(\"%s\"), failed: \"%s\"", name, dlerror()); 299216Sigor@sysoev.ru return NXT_OK; 300216Sigor@sysoev.ru } 301216Sigor@sysoev.ru 302216Sigor@sysoev.ru app = dlsym(dl, "nxt_app_module"); 303216Sigor@sysoev.ru 304216Sigor@sysoev.ru if (app != NULL) { 305612Salexander.borisov@nginx.com nxt_log(task, NXT_LOG_NOTICE, "module: %V %s \"%s\"", 306612Salexander.borisov@nginx.com &app->type, app->version, name); 307258Sigor@sysoev.ru 308258Sigor@sysoev.ru if (app->compat_length != sizeof(compat) 309258Sigor@sysoev.ru || nxt_memcmp(app->compat, compat, sizeof(compat)) != 0) 310258Sigor@sysoev.ru { 311258Sigor@sysoev.ru nxt_log(task, NXT_LOG_NOTICE, "incompatible module %s", name); 312258Sigor@sysoev.ru 313258Sigor@sysoev.ru goto done; 314258Sigor@sysoev.ru } 315216Sigor@sysoev.ru 316356Svbart@nginx.com type = nxt_app_parse_type(app->type.start, app->type.length); 317356Svbart@nginx.com 318356Svbart@nginx.com if (type == NXT_APP_UNKNOWN) { 319494Spluknet@nginx.com nxt_log(task, NXT_LOG_NOTICE, "unknown module type %V", &app->type); 320356Svbart@nginx.com 321356Svbart@nginx.com goto done; 322356Svbart@nginx.com } 323356Svbart@nginx.com 324216Sigor@sysoev.ru module = modules->elts; 325216Sigor@sysoev.ru n = modules->nelts; 326216Sigor@sysoev.ru 327612Salexander.borisov@nginx.com version.start = (u_char *) app->version; 328612Salexander.borisov@nginx.com version.length = nxt_strlen(app->version); 329612Salexander.borisov@nginx.com 330216Sigor@sysoev.ru for (i = 0; i < n; i++) { 331356Svbart@nginx.com if (type == module[i].type 332612Salexander.borisov@nginx.com && nxt_strstr_eq(&module[i].version, &version)) 333258Sigor@sysoev.ru { 334216Sigor@sysoev.ru nxt_log(task, NXT_LOG_NOTICE, 335216Sigor@sysoev.ru "ignoring %s module with the same " 336267Sigor@sysoev.ru "application language version %V %V as in %V", 337655Svbart@nginx.com name, &app->type, &version, &module[i].file); 338216Sigor@sysoev.ru 339216Sigor@sysoev.ru goto done; 340216Sigor@sysoev.ru } 341216Sigor@sysoev.ru } 342216Sigor@sysoev.ru 343216Sigor@sysoev.ru module = nxt_array_add(modules); 344216Sigor@sysoev.ru if (module == NULL) { 345216Sigor@sysoev.ru goto fail; 346216Sigor@sysoev.ru } 347216Sigor@sysoev.ru 348356Svbart@nginx.com module->type = type; 349216Sigor@sysoev.ru 350612Salexander.borisov@nginx.com nxt_str_dup(mp, &module->version, &version); 351612Salexander.borisov@nginx.com if (module->version.start == NULL) { 352216Sigor@sysoev.ru goto fail; 353216Sigor@sysoev.ru } 354216Sigor@sysoev.ru 355216Sigor@sysoev.ru module->file.length = nxt_strlen(name); 356216Sigor@sysoev.ru 357216Sigor@sysoev.ru module->file.start = nxt_mp_alloc(mp, module->file.length); 358216Sigor@sysoev.ru if (module->file.start == NULL) { 359216Sigor@sysoev.ru goto fail; 360216Sigor@sysoev.ru } 361216Sigor@sysoev.ru 362216Sigor@sysoev.ru nxt_memcpy(module->file.start, name, module->file.length); 363216Sigor@sysoev.ru 3641489St.nateldemoura@f5.com module->mounts = nxt_array_create(mp, app->nmounts, 3651489St.nateldemoura@f5.com sizeof(nxt_fs_mount_t)); 3661489St.nateldemoura@f5.com 3671489St.nateldemoura@f5.com if (nxt_slow_path(module->mounts == NULL)) { 3681489St.nateldemoura@f5.com goto fail; 3691489St.nateldemoura@f5.com } 3701489St.nateldemoura@f5.com 3711489St.nateldemoura@f5.com mounts = module->mounts; 3721489St.nateldemoura@f5.com 3731489St.nateldemoura@f5.com for (j = 0; j < app->nmounts; j++) { 3741489St.nateldemoura@f5.com from = &app->mounts[j]; 3751489St.nateldemoura@f5.com to = nxt_array_zero_add(mounts); 3761489St.nateldemoura@f5.com if (nxt_slow_path(to == NULL)) { 3771489St.nateldemoura@f5.com goto fail; 3781489St.nateldemoura@f5.com } 3791489St.nateldemoura@f5.com 3801489St.nateldemoura@f5.com to->src = nxt_cstr_dup(mp, to->src, from->src); 3811489St.nateldemoura@f5.com if (nxt_slow_path(to->src == NULL)) { 3821489St.nateldemoura@f5.com goto fail; 3831489St.nateldemoura@f5.com } 3841489St.nateldemoura@f5.com 3851489St.nateldemoura@f5.com to->dst = nxt_cstr_dup(mp, to->dst, from->dst); 3861489St.nateldemoura@f5.com if (nxt_slow_path(to->dst == NULL)) { 3871489St.nateldemoura@f5.com goto fail; 3881489St.nateldemoura@f5.com } 3891489St.nateldemoura@f5.com 390*1673St.nateldemoura@f5.com to->name = nxt_cstr_dup(mp, to->name, from->name); 391*1673St.nateldemoura@f5.com if (nxt_slow_path(to->name == NULL)) { 3921489St.nateldemoura@f5.com goto fail; 3931489St.nateldemoura@f5.com } 3941489St.nateldemoura@f5.com 395*1673St.nateldemoura@f5.com to->type = from->type; 396*1673St.nateldemoura@f5.com 3971489St.nateldemoura@f5.com if (from->data != NULL) { 3981489St.nateldemoura@f5.com to->data = nxt_cstr_dup(mp, to->data, from->data); 3991489St.nateldemoura@f5.com if (nxt_slow_path(to->data == NULL)) { 4001489St.nateldemoura@f5.com goto fail; 4011489St.nateldemoura@f5.com } 4021489St.nateldemoura@f5.com } 4031489St.nateldemoura@f5.com 4041489St.nateldemoura@f5.com to->flags = from->flags; 4051489St.nateldemoura@f5.com } 4061489St.nateldemoura@f5.com 407216Sigor@sysoev.ru } else { 408564Svbart@nginx.com nxt_alert(task, "dlsym(\"%s\"), failed: \"%s\"", name, dlerror()); 409216Sigor@sysoev.ru } 410216Sigor@sysoev.ru 411216Sigor@sysoev.ru done: 412216Sigor@sysoev.ru 413216Sigor@sysoev.ru ret = NXT_OK; 414216Sigor@sysoev.ru 415216Sigor@sysoev.ru fail: 416216Sigor@sysoev.ru 417216Sigor@sysoev.ru if (dlclose(dl) != 0) { 418564Svbart@nginx.com nxt_alert(task, "dlclose(\"%s\"), failed: \"%s\"", name, dlerror()); 419216Sigor@sysoev.ru } 420216Sigor@sysoev.ru 421216Sigor@sysoev.ru return ret; 422216Sigor@sysoev.ru } 423216Sigor@sysoev.ru 424216Sigor@sysoev.ru 425549Svbart@nginx.com static void 426549Svbart@nginx.com nxt_discovery_completion_handler(nxt_task_t *task, void *obj, void *data) 427549Svbart@nginx.com { 428549Svbart@nginx.com nxt_mp_t *mp; 429549Svbart@nginx.com nxt_buf_t *b; 430549Svbart@nginx.com 431549Svbart@nginx.com b = obj; 432549Svbart@nginx.com mp = b->data; 433549Svbart@nginx.com 434549Svbart@nginx.com nxt_mp_destroy(mp); 435549Svbart@nginx.com } 436549Svbart@nginx.com 437549Svbart@nginx.com 438549Svbart@nginx.com static void 439549Svbart@nginx.com nxt_discovery_quit(nxt_task_t *task, nxt_port_recv_msg_t *msg, void *data) 440549Svbart@nginx.com { 4411488St.nateldemoura@f5.com nxt_signal_quit_handler(task, msg); 442549Svbart@nginx.com } 443549Svbart@nginx.com 444549Svbart@nginx.com 4451488St.nateldemoura@f5.com static nxt_int_t 4461488St.nateldemoura@f5.com nxt_app_setup(nxt_task_t *task, nxt_process_t *process) 4470Sigor@sysoev.ru { 448216Sigor@sysoev.ru nxt_int_t ret; 4491488St.nateldemoura@f5.com nxt_process_init_t *init; 450216Sigor@sysoev.ru nxt_app_lang_module_t *lang; 451216Sigor@sysoev.ru nxt_common_app_conf_t *app_conf; 452141Smax.romanov@nginx.com 4531488St.nateldemoura@f5.com app_conf = process->data.app; 454141Smax.romanov@nginx.com 455216Sigor@sysoev.ru lang = nxt_app_lang_module(task->thread->runtime, &app_conf->type); 456216Sigor@sysoev.ru if (nxt_slow_path(lang == NULL)) { 457564Svbart@nginx.com nxt_alert(task, "unknown application type: \"%V\"", &app_conf->type); 458216Sigor@sysoev.ru return NXT_ERROR; 459216Sigor@sysoev.ru } 460216Sigor@sysoev.ru 461216Sigor@sysoev.ru nxt_app = lang->module; 462216Sigor@sysoev.ru 463216Sigor@sysoev.ru if (nxt_app == NULL) { 464354Svbart@nginx.com nxt_debug(task, "application language module: %s \"%s\"", 465354Svbart@nginx.com lang->version, lang->file); 466216Sigor@sysoev.ru 467216Sigor@sysoev.ru nxt_app = nxt_app_module_load(task, lang->file); 4681239Smax.romanov@nginx.com if (nxt_slow_path(nxt_app == NULL)) { 4691239Smax.romanov@nginx.com return NXT_ERROR; 4701239Smax.romanov@nginx.com } 471216Sigor@sysoev.ru } 472216Sigor@sysoev.ru 4731489St.nateldemoura@f5.com if (nxt_slow_path(nxt_app_set_environment(app_conf->environment) 4741489St.nateldemoura@f5.com != NXT_OK)) 4751489St.nateldemoura@f5.com { 4761489St.nateldemoura@f5.com nxt_alert(task, "failed to set environment"); 4771489St.nateldemoura@f5.com return NXT_ERROR; 4781489St.nateldemoura@f5.com } 4791489St.nateldemoura@f5.com 4801488St.nateldemoura@f5.com if (nxt_app->setup != NULL) { 4811488St.nateldemoura@f5.com ret = nxt_app->setup(task, process, app_conf); 482977Smax.romanov@gmail.com 483977Smax.romanov@gmail.com if (nxt_slow_path(ret != NXT_OK)) { 4841104Smax.romanov@nginx.com return ret; 485977Smax.romanov@gmail.com } 486977Smax.romanov@gmail.com } 487977Smax.romanov@gmail.com 4881489St.nateldemoura@f5.com #if (NXT_HAVE_ISOLATION_ROOTFS) 4891489St.nateldemoura@f5.com if (process->isolation.rootfs != NULL) { 4901489St.nateldemoura@f5.com if (process->isolation.mounts != NULL) { 4911579St.nateldemoura@f5.com ret = nxt_isolation_prepare_rootfs(task, process); 4921489St.nateldemoura@f5.com if (nxt_slow_path(ret != NXT_OK)) { 4931489St.nateldemoura@f5.com return ret; 4941489St.nateldemoura@f5.com } 4951489St.nateldemoura@f5.com } 4961489St.nateldemoura@f5.com 4971579St.nateldemoura@f5.com ret = nxt_isolation_change_root(task, process); 4981489St.nateldemoura@f5.com if (nxt_slow_path(ret != NXT_OK)) { 4991489St.nateldemoura@f5.com return NXT_ERROR; 5001489St.nateldemoura@f5.com } 5011489St.nateldemoura@f5.com } 5021489St.nateldemoura@f5.com #endif 5031489St.nateldemoura@f5.com 504277Sigor@sysoev.ru if (app_conf->working_directory != NULL 505277Sigor@sysoev.ru && app_conf->working_directory[0] != 0) 506271Smax.romanov@nginx.com { 507271Smax.romanov@nginx.com ret = chdir(app_conf->working_directory); 508271Smax.romanov@nginx.com 509271Smax.romanov@nginx.com if (nxt_slow_path(ret != 0)) { 510271Smax.romanov@nginx.com nxt_log(task, NXT_LOG_WARN, "chdir(%s) failed %E", 511271Smax.romanov@nginx.com app_conf->working_directory, nxt_errno); 512271Smax.romanov@nginx.com 513271Smax.romanov@nginx.com return NXT_ERROR; 514271Smax.romanov@nginx.com } 515271Smax.romanov@nginx.com } 516271Smax.romanov@nginx.com 5171488St.nateldemoura@f5.com init = nxt_process_init(process); 518141Smax.romanov@nginx.com 5191488St.nateldemoura@f5.com init->start = nxt_app->start; 520141Smax.romanov@nginx.com 5211488St.nateldemoura@f5.com process->state = NXT_PROCESS_STATE_CREATED; 52220Sigor@sysoev.ru 5231488St.nateldemoura@f5.com return NXT_OK; 52420Sigor@sysoev.ru } 52520Sigor@sysoev.ru 52620Sigor@sysoev.ru 527216Sigor@sysoev.ru static nxt_app_module_t * 528216Sigor@sysoev.ru nxt_app_module_load(nxt_task_t *task, const char *name) 529216Sigor@sysoev.ru { 530216Sigor@sysoev.ru void *dl; 531216Sigor@sysoev.ru 532216Sigor@sysoev.ru dl = dlopen(name, RTLD_GLOBAL | RTLD_LAZY); 533216Sigor@sysoev.ru 534216Sigor@sysoev.ru if (dl != NULL) { 535216Sigor@sysoev.ru return dlsym(dl, "nxt_app_module"); 536216Sigor@sysoev.ru } 537216Sigor@sysoev.ru 538564Svbart@nginx.com nxt_alert(task, "dlopen(\"%s\"), failed: \"%s\"", name, dlerror()); 539216Sigor@sysoev.ru 540216Sigor@sysoev.ru return NULL; 541216Sigor@sysoev.ru } 542216Sigor@sysoev.ru 543216Sigor@sysoev.ru 544678Svbart@nginx.com static nxt_int_t 545678Svbart@nginx.com nxt_app_set_environment(nxt_conf_value_t *environment) 546678Svbart@nginx.com { 547678Svbart@nginx.com char *env, *p; 548678Svbart@nginx.com uint32_t next; 549678Svbart@nginx.com nxt_str_t name, value; 550678Svbart@nginx.com nxt_conf_value_t *value_obj; 551678Svbart@nginx.com 552678Svbart@nginx.com if (environment != NULL) { 553678Svbart@nginx.com next = 0; 554678Svbart@nginx.com 555678Svbart@nginx.com for ( ;; ) { 556678Svbart@nginx.com value_obj = nxt_conf_next_object_member(environment, &name, &next); 557678Svbart@nginx.com if (value_obj == NULL) { 558678Svbart@nginx.com break; 559678Svbart@nginx.com } 560678Svbart@nginx.com 561678Svbart@nginx.com nxt_conf_get_string(value_obj, &value); 562678Svbart@nginx.com 563678Svbart@nginx.com env = nxt_malloc(name.length + value.length + 2); 564678Svbart@nginx.com if (nxt_slow_path(env == NULL)) { 565678Svbart@nginx.com return NXT_ERROR; 566678Svbart@nginx.com } 567678Svbart@nginx.com 568678Svbart@nginx.com p = nxt_cpymem(env, name.start, name.length); 569678Svbart@nginx.com *p++ = '='; 570678Svbart@nginx.com p = nxt_cpymem(p, value.start, value.length); 571678Svbart@nginx.com *p = '\0'; 572678Svbart@nginx.com 573678Svbart@nginx.com if (nxt_slow_path(putenv(env) != 0)) { 574678Svbart@nginx.com return NXT_ERROR; 575678Svbart@nginx.com } 576678Svbart@nginx.com } 577678Svbart@nginx.com } 578678Svbart@nginx.com 579678Svbart@nginx.com return NXT_OK; 580678Svbart@nginx.com } 581678Svbart@nginx.com 582678Svbart@nginx.com 5831489St.nateldemoura@f5.com static u_char * 5841489St.nateldemoura@f5.com nxt_cstr_dup(nxt_mp_t *mp, u_char *dst, u_char *src) 5851489St.nateldemoura@f5.com { 5861489St.nateldemoura@f5.com u_char *p; 5871489St.nateldemoura@f5.com size_t len; 5881489St.nateldemoura@f5.com 5891489St.nateldemoura@f5.com len = nxt_strlen(src); 5901489St.nateldemoura@f5.com 5911489St.nateldemoura@f5.com if (dst == NULL) { 5921489St.nateldemoura@f5.com dst = nxt_mp_alloc(mp, len + 1); 5931489St.nateldemoura@f5.com if (nxt_slow_path(dst == NULL)) { 5941489St.nateldemoura@f5.com return NULL; 5951489St.nateldemoura@f5.com } 5961489St.nateldemoura@f5.com } 5971489St.nateldemoura@f5.com 5981489St.nateldemoura@f5.com p = nxt_cpymem(dst, src, len); 5991489St.nateldemoura@f5.com *p = '\0'; 6001489St.nateldemoura@f5.com 6011489St.nateldemoura@f5.com return dst; 6021489St.nateldemoura@f5.com } 6031489St.nateldemoura@f5.com 6041488St.nateldemoura@f5.com 605216Sigor@sysoev.ru nxt_app_lang_module_t * 606216Sigor@sysoev.ru nxt_app_lang_module(nxt_runtime_t *rt, nxt_str_t *name) 607216Sigor@sysoev.ru { 608216Sigor@sysoev.ru u_char *p, *end, *version; 609356Svbart@nginx.com size_t version_length; 610216Sigor@sysoev.ru nxt_uint_t i, n; 611356Svbart@nginx.com nxt_app_type_t type; 612216Sigor@sysoev.ru nxt_app_lang_module_t *lang; 613216Sigor@sysoev.ru 614216Sigor@sysoev.ru end = name->start + name->length; 615216Sigor@sysoev.ru version = end; 616216Sigor@sysoev.ru 617216Sigor@sysoev.ru for (p = name->start; p < end; p++) { 618216Sigor@sysoev.ru if (*p == ' ') { 619216Sigor@sysoev.ru version = p + 1; 620216Sigor@sysoev.ru break; 621216Sigor@sysoev.ru } 622216Sigor@sysoev.ru 623216Sigor@sysoev.ru if (*p >= '0' && *p <= '9') { 624216Sigor@sysoev.ru version = p; 625216Sigor@sysoev.ru break; 626216Sigor@sysoev.ru } 627216Sigor@sysoev.ru } 628216Sigor@sysoev.ru 629356Svbart@nginx.com type = nxt_app_parse_type(name->start, p - name->start); 630356Svbart@nginx.com 631356Svbart@nginx.com if (type == NXT_APP_UNKNOWN) { 632356Svbart@nginx.com return NULL; 633356Svbart@nginx.com } 634356Svbart@nginx.com 635216Sigor@sysoev.ru version_length = end - version; 636216Sigor@sysoev.ru 637216Sigor@sysoev.ru lang = rt->languages->elts; 638216Sigor@sysoev.ru n = rt->languages->nelts; 639216Sigor@sysoev.ru 640216Sigor@sysoev.ru for (i = 0; i < n; i++) { 641354Svbart@nginx.com 642354Svbart@nginx.com /* 643354Svbart@nginx.com * Versions are sorted in descending order 644354Svbart@nginx.com * so first match chooses the highest version. 645354Svbart@nginx.com */ 646354Svbart@nginx.com 647356Svbart@nginx.com if (lang[i].type == type 648354Svbart@nginx.com && nxt_strvers_match(lang[i].version, version, version_length)) 649216Sigor@sysoev.ru { 650216Sigor@sysoev.ru return &lang[i]; 651216Sigor@sysoev.ru } 652216Sigor@sysoev.ru } 653216Sigor@sysoev.ru 654216Sigor@sysoev.ru return NULL; 655216Sigor@sysoev.ru } 656216Sigor@sysoev.ru 657216Sigor@sysoev.ru 658510Salexander.borisov@nginx.com nxt_app_type_t 659356Svbart@nginx.com nxt_app_parse_type(u_char *p, size_t length) 660141Smax.romanov@nginx.com { 661356Svbart@nginx.com nxt_str_t str; 662356Svbart@nginx.com 663356Svbart@nginx.com str.length = length; 664356Svbart@nginx.com str.start = p; 665356Svbart@nginx.com 666804Svbart@nginx.com if (nxt_str_eq(&str, "external", 8) || nxt_str_eq(&str, "go", 2)) { 667804Svbart@nginx.com return NXT_APP_EXTERNAL; 668804Svbart@nginx.com 669804Svbart@nginx.com } else if (nxt_str_eq(&str, "python", 6)) { 670141Smax.romanov@nginx.com return NXT_APP_PYTHON; 671141Smax.romanov@nginx.com 672356Svbart@nginx.com } else if (nxt_str_eq(&str, "php", 3)) { 673141Smax.romanov@nginx.com return NXT_APP_PHP; 674141Smax.romanov@nginx.com 675510Salexander.borisov@nginx.com } else if (nxt_str_eq(&str, "perl", 4)) { 676510Salexander.borisov@nginx.com return NXT_APP_PERL; 677584Salexander.borisov@nginx.com 678584Salexander.borisov@nginx.com } else if (nxt_str_eq(&str, "ruby", 4)) { 679584Salexander.borisov@nginx.com return NXT_APP_RUBY; 680977Smax.romanov@gmail.com 681977Smax.romanov@gmail.com } else if (nxt_str_eq(&str, "java", 4)) { 682977Smax.romanov@gmail.com return NXT_APP_JAVA; 683141Smax.romanov@nginx.com } 684141Smax.romanov@nginx.com 685141Smax.romanov@nginx.com return NXT_APP_UNKNOWN; 686141Smax.romanov@nginx.com } 687743Smax.romanov@nginx.com 688743Smax.romanov@nginx.com 689743Smax.romanov@nginx.com nxt_int_t 690743Smax.romanov@nginx.com nxt_unit_default_init(nxt_task_t *task, nxt_unit_init_t *init) 691743Smax.romanov@nginx.com { 6921543Smax.romanov@nginx.com nxt_port_t *my_port, *main_port, *router_port; 693743Smax.romanov@nginx.com nxt_runtime_t *rt; 694743Smax.romanov@nginx.com 695743Smax.romanov@nginx.com nxt_memzero(init, sizeof(nxt_unit_init_t)); 696743Smax.romanov@nginx.com 697743Smax.romanov@nginx.com rt = task->thread->runtime; 698743Smax.romanov@nginx.com 699743Smax.romanov@nginx.com main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 700743Smax.romanov@nginx.com if (nxt_slow_path(main_port == NULL)) { 701743Smax.romanov@nginx.com return NXT_ERROR; 702743Smax.romanov@nginx.com } 703743Smax.romanov@nginx.com 7041543Smax.romanov@nginx.com router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 7051543Smax.romanov@nginx.com if (nxt_slow_path(router_port == NULL)) { 7061543Smax.romanov@nginx.com return NXT_ERROR; 7071543Smax.romanov@nginx.com } 7081543Smax.romanov@nginx.com 709743Smax.romanov@nginx.com my_port = nxt_runtime_port_find(rt, nxt_pid, 0); 710743Smax.romanov@nginx.com if (nxt_slow_path(my_port == NULL)) { 711743Smax.romanov@nginx.com return NXT_ERROR; 712743Smax.romanov@nginx.com } 713743Smax.romanov@nginx.com 714743Smax.romanov@nginx.com init->ready_port.id.pid = main_port->pid; 715743Smax.romanov@nginx.com init->ready_port.id.id = main_port->id; 7161518Smax.romanov@nginx.com init->ready_port.in_fd = -1; 717743Smax.romanov@nginx.com init->ready_port.out_fd = main_port->pair[1]; 718743Smax.romanov@nginx.com 7191488St.nateldemoura@f5.com init->ready_stream = my_port->process->stream; 720743Smax.romanov@nginx.com 7211543Smax.romanov@nginx.com init->router_port.id.pid = router_port->pid; 7221543Smax.romanov@nginx.com init->router_port.id.id = router_port->id; 7231543Smax.romanov@nginx.com init->router_port.in_fd = -1; 7241543Smax.romanov@nginx.com init->router_port.out_fd = router_port->pair[1]; 7251543Smax.romanov@nginx.com 726743Smax.romanov@nginx.com init->read_port.id.pid = my_port->pid; 727743Smax.romanov@nginx.com init->read_port.id.id = my_port->id; 728743Smax.romanov@nginx.com init->read_port.in_fd = my_port->pair[0]; 7291668Smax.romanov@nginx.com init->read_port.out_fd = my_port->pair[1]; 730743Smax.romanov@nginx.com 731743Smax.romanov@nginx.com init->log_fd = 2; 732743Smax.romanov@nginx.com 733743Smax.romanov@nginx.com return NXT_OK; 734743Smax.romanov@nginx.com } 735