Deleted Added
1
2/*
3 * Copyright (C) Max Romanov
4 * Copyright (C) Igor Sysoev
5 * Copyright (C) Valentin V. Bartenev
6 * Copyright (C) NGINX, Inc.
7 */
8
9#include <nxt_main.h>
10#include <nxt_runtime.h>
11#include <nxt_application.h>
12#include <nxt_master_process.h>
13
14#include <glob.h>
15
16
17typedef struct {
18 nxt_str_t type;
19 nxt_str_t version;
20 nxt_str_t file;
21} nxt_module_t;
22
23
24static nxt_buf_t *nxt_discovery_modules(nxt_task_t *task, const char *path);
25static nxt_int_t nxt_discovery_module(nxt_task_t *task, nxt_mp_t *mp,
26 nxt_array_t *modules, const char *name);
27static nxt_app_module_t *nxt_app_module_load(nxt_task_t *task,
28 const char *name);
29
30
31static nxt_thread_mutex_t nxt_app_mutex;
32static nxt_thread_cond_t nxt_app_cond;
33
34static nxt_http_fields_hash_entry_t nxt_app_request_fields[];
35static nxt_http_fields_hash_t *nxt_app_request_fields_hash;
36
37static nxt_application_module_t *nxt_app;
38
39
40nxt_int_t
41nxt_discovery_start(nxt_task_t *task, void *data)
42{
43 nxt_buf_t *b;
44 nxt_port_t *main_port;
45 nxt_runtime_t *rt;
46
47 nxt_debug(task, "DISCOVERY");
48
49 b = nxt_discovery_modules(task, "build/nginext.*");
50
51 rt = task->thread->runtime;
52 main_port = rt->port_by_type[NXT_PROCESS_MASTER];
53
54 nxt_port_socket_write(task, main_port, NXT_PORT_MSG_MODULES, -1,
55 0, -1, b);
56
57 return NXT_OK;
58}
59
60
61static void
62nxt_discovery_completion_handler(nxt_task_t *task, void *obj, void *data)
63{
64 nxt_mp_t *mp;
65 nxt_buf_t *b;
66
67 b = obj;
68 mp = b->data;
69
70 nxt_mp_destroy(mp);
71
72 exit(0);
73}
74
75
76static nxt_buf_t *
77nxt_discovery_modules(nxt_task_t *task, const char *path)
78{
79 char *name;
80 u_char *p, *end;
81 size_t size;
82 glob_t glb;
83 nxt_mp_t *mp;
84 nxt_buf_t *b;
85 nxt_int_t ret;
86 nxt_uint_t i, n;
87 nxt_array_t *modules;
88 nxt_module_t *module;
89
90 b = NULL;
91
92 mp = nxt_mp_create(1024, 128, 256, 32);
93 if (mp == NULL) {
94 return b;
95 }
96
97 ret = glob(path, 0, NULL, &glb);
98
99 if (ret == 0) {
100 n = glb.gl_pathc;
101
102 modules = nxt_array_create(mp, n, sizeof(nxt_module_t));
103 if (modules == NULL) {
104 goto fail;
105 }
106
107 for (i = 0; i < n; i++) {
108 name = glb.gl_pathv[i];
109
110 ret = nxt_discovery_module(task, mp, modules, name);
111 if (ret != NXT_OK) {
112 goto fail;
113 }
114 }
115
116 size = sizeof("[]") - 1;
117 module = modules->elts;
118 n = modules->nelts;
119
120 for (i = 0; i < n; i++) {
121 nxt_debug(task, "module: %V %V %V",
122 &module[i].type, &module[i].version, &module[i].file);
123
124 size += sizeof("{\"type\": \"\",") - 1;
125 size += sizeof(" \"version\": \"\",") - 1;
126 size += sizeof(" \"file\": \"\"},") - 1;
127
128 size += module[i].type.length
129 + module[i].version.length
130 + module[i].file.length;
131 }
132
133 b = nxt_buf_mem_alloc(mp, size, 0);
134 if (b == NULL) {
135 goto fail;
136 }
137
138 b->completion_handler = nxt_discovery_completion_handler;
139
140 p = b->mem.free;
141 end = b->mem.end;
142 *p++ = '[';
143
144 for (i = 0; i < n; i++) {
145 p = nxt_sprintf(p, end,
146 "{\"type\": \"%V\", \"version\": \"%V\", \"file\": \"%V\"},",
147 &module[i].type, &module[i].version, &module[i].file);
148 }
149
150 *p++ = ']';
151 b->mem.free = p;
152 }
153
154fail:
155
156 globfree(&glb);
157
158 return b;
159}
160
161
162static nxt_int_t
163nxt_discovery_module(nxt_task_t *task, nxt_mp_t *mp, nxt_array_t *modules,
164 const char *name)
165{
166 void *dl;
167 nxt_str_t *s;
168 nxt_int_t ret;
169 nxt_uint_t i, n;
170 nxt_module_t *module;
171 nxt_application_module_t *app;
172
173 /*
174 * Only memory allocation failure should return NXT_ERROR.
175 * Any module processing errors are ignored.
176 */
177 ret = NXT_ERROR;
178
179 dl = dlopen(name, RTLD_GLOBAL | RTLD_NOW);
180
181 if (dl == NULL) {
182 nxt_log(task, NXT_LOG_CRIT, "dlopen(\"%s\"), failed: \"%s\"",
183 name, dlerror());
184 return NXT_OK;
185 }
186
187 app = dlsym(dl, "nxt_app_module");
188
189 if (app != NULL) {
190 nxt_log(task, NXT_LOG_NOTICE, "module: %V \"%s\"",
191 &app->version, name);
192
193 module = modules->elts;
194 n = modules->nelts;
195
196 for (i = 0; i < n; i++) {
197 if (nxt_strstr_eq(&app->version, &module[i].version)) {
198 nxt_log(task, NXT_LOG_NOTICE,
199 "ignoring %s module with the same "
200 "application language version %V as in %s",
201 name, &module[i].version, &module[i].file);
202
203 goto done;
204 }
205 }
206
207 module = nxt_array_add(modules);
208 if (module == NULL) {
209 goto fail;
210 }
211
212 s = nxt_str_dup(mp, &module->type, &app->type);
213 if (s == NULL) {
214 goto fail;
215 }
216
217 s = nxt_str_dup(mp, &module->version, &app->version);
218 if (s == NULL) {
219 goto fail;
220 }
221
222 module->file.length = nxt_strlen(name);
223
224 module->file.start = nxt_mp_alloc(mp, module->file.length);
225 if (module->file.start == NULL) {
226 goto fail;
227 }
228
229 nxt_memcpy(module->file.start, name, module->file.length);
230
231 } else {
232 nxt_log(task, NXT_LOG_CRIT, "dlsym(\"%s\"), failed: \"%s\"",
233 name, dlerror());
234 }
235
236done:
237
238 ret = NXT_OK;
239
240fail:
241
242 if (dlclose(dl) != 0) {
243 nxt_log(task, NXT_LOG_CRIT, "dlclose(\"%s\"), failed: \"%s\"",
244 name, dlerror());
245 }
246
247 return ret;
248}
249
250
251nxt_int_t
252nxt_app_start(nxt_task_t *task, void *data)
253{
254 nxt_int_t ret;
255 nxt_app_lang_module_t *lang;
256 nxt_common_app_conf_t *app_conf;
257
258 app_conf = data;
259
260 lang = nxt_app_lang_module(task->thread->runtime, &app_conf->type);
261 if (nxt_slow_path(lang == NULL)) {
262 nxt_log(task, NXT_LOG_CRIT, "unknown application type: \"%V\"",
263 &app_conf->type);
264 return NXT_ERROR;
265 }
266
267 nxt_app = lang->module;
268
269 if (nxt_app == NULL) {
270 nxt_debug(task, "application language module: %V \"%s\"",
271 &lang->version, lang->file);
272
273 nxt_app = nxt_app_module_load(task, lang->file);
274 }
275
276 if (nxt_slow_path(nxt_thread_mutex_create(&nxt_app_mutex) != NXT_OK)) {
277 return NXT_ERROR;
278 }
279
280 if (nxt_slow_path(nxt_thread_cond_create(&nxt_app_cond) != NXT_OK)) {
281 return NXT_ERROR;
282 }
283
284 ret = nxt_app->init(task, data);
285
286 if (nxt_slow_path(ret != NXT_OK)) {
287 nxt_debug(task, "application init failed");
288
289 } else {
290 nxt_debug(task, "application init done");
291 }
292
293 return ret;
294}
295
296
297static nxt_app_module_t *
298nxt_app_module_load(nxt_task_t *task, const char *name)
299{
300 void *dl;
301
302 dl = dlopen(name, RTLD_GLOBAL | RTLD_LAZY);
303
304 if (dl != NULL) {
305 return dlsym(dl, "nxt_app_module");
306 }
307
308 nxt_log(task, NXT_LOG_CRIT, "dlopen(\"%s\"), failed: \"%s\"",
309 name, dlerror());
310
311 return NULL;
312}
313
314
315nxt_int_t
316nxt_app_http_init(nxt_task_t *task, nxt_runtime_t *rt)
317{
318 nxt_http_fields_hash_t *hash;
319
320 hash = nxt_http_fields_hash_create(nxt_app_request_fields, rt->mem_pool);
321 if (nxt_slow_path(hash == NULL)) {
322 return NXT_ERROR;

--- 612 unchanged lines hidden (view full) ---

935
936 msg->buf = &b->next;
937 }
938
939 return NXT_OK;
940}
941
942
943nxt_app_lang_module_t *
944nxt_app_lang_module(nxt_runtime_t *rt, nxt_str_t *name)
945{
946 u_char *p, *end, *version;
947 size_t type_length, version_length;
948 nxt_uint_t i, n;
949 nxt_app_lang_module_t *lang;
950
951 end = name->start + name->length;
952 version = end;
953
954 for (p = name->start; p < end; p++) {
955 if (*p == ' ') {
956 version = p + 1;
957 break;
958 }
959
960 if (*p >= '0' && *p <= '9') {
961 version = p;
962 break;
963 }
964 }
965
966 type_length = p - name->start;
967 version_length = end - version;
968
969 lang = rt->languages->elts;
970 n = rt->languages->nelts;
971
972 for (i = 0; i < n; i++) {
973 if (nxt_str_eq(&lang[i].type, name->start, type_length)
974 && nxt_str_start(&lang[i].version, version, version_length))
975 {
976 return &lang[i];
977 }
978 }
979
980 return NULL;
981}
982
983
984nxt_app_type_t
985nxt_app_parse_type(nxt_str_t *str)
986{
987 if (nxt_str_eq(str, "python", 6)) {
988 return NXT_APP_PYTHON;
989
990 } else if (nxt_str_eq(str, "php", 3)) {
991 return NXT_APP_PHP;
992
993 } else if (nxt_str_eq(str, "go", 2)) {
994 return NXT_APP_GO;
995
996 }
997
998 return NXT_APP_UNKNOWN;
999}