xref: /unit/src/nxt_router.c (revision 351)
120Sigor@sysoev.ru 
220Sigor@sysoev.ru /*
320Sigor@sysoev.ru  * Copyright (C) Igor Sysoev
420Sigor@sysoev.ru  * Copyright (C) Valentin V. Bartenev
520Sigor@sysoev.ru  * Copyright (C) NGINX, Inc.
620Sigor@sysoev.ru  */
720Sigor@sysoev.ru 
853Sigor@sysoev.ru #include <nxt_router.h>
9115Sigor@sysoev.ru #include <nxt_conf.h>
1020Sigor@sysoev.ru 
1120Sigor@sysoev.ru 
12115Sigor@sysoev.ru typedef struct {
13318Smax.romanov@nginx.com     nxt_str_t         type;
14318Smax.romanov@nginx.com     uint32_t          workers;
15318Smax.romanov@nginx.com     nxt_msec_t        timeout;
16318Smax.romanov@nginx.com     uint32_t          requests;
17318Smax.romanov@nginx.com     nxt_conf_value_t  *limits_value;
18133Sigor@sysoev.ru } nxt_router_app_conf_t;
19133Sigor@sysoev.ru 
20133Sigor@sysoev.ru 
21133Sigor@sysoev.ru typedef struct {
22133Sigor@sysoev.ru     nxt_str_t  application;
23115Sigor@sysoev.ru } nxt_router_listener_conf_t;
24115Sigor@sysoev.ru 
25115Sigor@sysoev.ru 
26167Smax.romanov@nginx.com typedef struct nxt_req_app_link_s nxt_req_app_link_t;
27141Smax.romanov@nginx.com 
28141Smax.romanov@nginx.com 
29318Smax.romanov@nginx.com typedef struct {
30318Smax.romanov@nginx.com     uint32_t             stream;
31318Smax.romanov@nginx.com     nxt_conn_t           *conn;
32343Smax.romanov@nginx.com     nxt_app_t            *app;
33318Smax.romanov@nginx.com     nxt_port_t           *app_port;
34346Smax.romanov@nginx.com     nxt_app_parse_ctx_t  *ap;
35318Smax.romanov@nginx.com     nxt_req_app_link_t   *ra;
36318Smax.romanov@nginx.com 
37318Smax.romanov@nginx.com     nxt_queue_link_t     link;     /* for nxt_conn_t.requests */
38318Smax.romanov@nginx.com } nxt_req_conn_link_t;
39318Smax.romanov@nginx.com 
40318Smax.romanov@nginx.com 
41167Smax.romanov@nginx.com struct nxt_req_app_link_s {
42318Smax.romanov@nginx.com     uint32_t             stream;
43167Smax.romanov@nginx.com     nxt_port_t           *app_port;
44318Smax.romanov@nginx.com     nxt_pid_t            app_pid;
45167Smax.romanov@nginx.com     nxt_port_t           *reply_port;
46167Smax.romanov@nginx.com     nxt_app_parse_ctx_t  *ap;
47167Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
48167Smax.romanov@nginx.com 
49167Smax.romanov@nginx.com     nxt_queue_link_t     link; /* for nxt_app_t.requests */
50167Smax.romanov@nginx.com 
51167Smax.romanov@nginx.com     nxt_mp_t             *mem_pool;
52167Smax.romanov@nginx.com     nxt_work_t           work;
53345Smax.romanov@nginx.com 
54345Smax.romanov@nginx.com     int                  err_code;
55345Smax.romanov@nginx.com     const char           *err_str;
56167Smax.romanov@nginx.com };
57167Smax.romanov@nginx.com 
58167Smax.romanov@nginx.com 
59198Sigor@sysoev.ru typedef struct {
60198Sigor@sysoev.ru     nxt_socket_conf_t       *socket_conf;
61198Sigor@sysoev.ru     nxt_router_temp_conf_t  *temp_conf;
62198Sigor@sysoev.ru } nxt_socket_rpc_t;
63198Sigor@sysoev.ru 
64198Sigor@sysoev.ru 
65343Smax.romanov@nginx.com static nxt_int_t nxt_router_start_worker(nxt_task_t *task, nxt_app_t *app);
66343Smax.romanov@nginx.com 
67345Smax.romanov@nginx.com static void nxt_router_ra_error(nxt_task_t *task, nxt_req_app_link_t *ra,
68345Smax.romanov@nginx.com     int code, const char* str);
69345Smax.romanov@nginx.com 
70139Sigor@sysoev.ru static nxt_router_temp_conf_t *nxt_router_temp_conf(nxt_task_t *task);
71198Sigor@sysoev.ru static void nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data);
72198Sigor@sysoev.ru static void nxt_router_conf_ready(nxt_task_t *task,
73139Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
74139Sigor@sysoev.ru static void nxt_router_conf_error(nxt_task_t *task,
75139Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
76139Sigor@sysoev.ru static void nxt_router_conf_send(nxt_task_t *task,
77193Smax.romanov@nginx.com     nxt_router_temp_conf_t *tmcf, nxt_port_msg_type_t type);
7853Sigor@sysoev.ru static void nxt_router_listen_sockets_sort(nxt_router_t *router,
7953Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
8053Sigor@sysoev.ru 
81115Sigor@sysoev.ru static nxt_int_t nxt_router_conf_create(nxt_task_t *task,
82115Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, u_char *start, u_char *end);
83133Sigor@sysoev.ru static nxt_app_t *nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name);
84133Sigor@sysoev.ru static nxt_app_t *nxt_router_listener_application(nxt_router_temp_conf_t *tmcf,
85133Sigor@sysoev.ru     nxt_str_t *name);
86198Sigor@sysoev.ru static void nxt_router_listen_socket_rpc_create(nxt_task_t *task,
87198Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf);
88198Sigor@sysoev.ru static void nxt_router_listen_socket_ready(nxt_task_t *task,
89198Sigor@sysoev.ru     nxt_port_recv_msg_t *msg, void *data);
90198Sigor@sysoev.ru static void nxt_router_listen_socket_error(nxt_task_t *task,
91198Sigor@sysoev.ru     nxt_port_recv_msg_t *msg, void *data);
9265Sigor@sysoev.ru static nxt_socket_conf_t *nxt_router_socket_conf(nxt_task_t *task, nxt_mp_t *mp,
9365Sigor@sysoev.ru     nxt_sockaddr_t *sa);
9453Sigor@sysoev.ru 
9553Sigor@sysoev.ru static nxt_int_t nxt_router_engines_create(nxt_task_t *task,
9653Sigor@sysoev.ru     nxt_router_t *router, nxt_router_temp_conf_t *tmcf,
9753Sigor@sysoev.ru     const nxt_event_interface_t *interface);
98115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf,
99115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
100115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf,
101115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
102115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf,
103115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
104115Sigor@sysoev.ru static void nxt_router_engine_socket_count(nxt_queue_t *sockets);
105154Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf,
106154Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets,
107154Sigor@sysoev.ru     nxt_work_handler_t handler);
108313Sigor@sysoev.ru static nxt_int_t nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf,
109313Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
110139Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf,
111139Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets);
11253Sigor@sysoev.ru 
11353Sigor@sysoev.ru static nxt_int_t nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt,
11453Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
11553Sigor@sysoev.ru static nxt_int_t nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt,
11653Sigor@sysoev.ru     nxt_event_engine_t *engine);
117343Smax.romanov@nginx.com static void nxt_router_apps_sort(nxt_task_t *task, nxt_router_t *router,
118133Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
11953Sigor@sysoev.ru 
120315Sigor@sysoev.ru static void nxt_router_engines_post(nxt_router_t *router,
121315Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
122315Sigor@sysoev.ru static void nxt_router_engine_post(nxt_event_engine_t *engine,
123315Sigor@sysoev.ru     nxt_work_t *jobs);
12453Sigor@sysoev.ru 
12553Sigor@sysoev.ru static void nxt_router_thread_start(void *data);
12653Sigor@sysoev.ru static void nxt_router_listen_socket_create(nxt_task_t *task, void *obj,
12753Sigor@sysoev.ru     void *data);
12853Sigor@sysoev.ru static void nxt_router_listen_socket_update(nxt_task_t *task, void *obj,
12953Sigor@sysoev.ru     void *data);
13053Sigor@sysoev.ru static void nxt_router_listen_socket_delete(nxt_task_t *task, void *obj,
13153Sigor@sysoev.ru     void *data);
132313Sigor@sysoev.ru static void nxt_router_worker_thread_quit(nxt_task_t *task, void *obj,
133313Sigor@sysoev.ru     void *data);
13453Sigor@sysoev.ru static void nxt_router_listen_socket_close(nxt_task_t *task, void *obj,
13553Sigor@sysoev.ru     void *data);
13653Sigor@sysoev.ru static void nxt_router_listen_socket_release(nxt_task_t *task,
13753Sigor@sysoev.ru     nxt_socket_conf_joint_t *joint);
13853Sigor@sysoev.ru static void nxt_router_thread_exit_handler(nxt_task_t *task, void *obj,
13953Sigor@sysoev.ru     void *data);
14053Sigor@sysoev.ru static void nxt_router_conf_release(nxt_task_t *task,
14153Sigor@sysoev.ru     nxt_socket_conf_joint_t *joint);
14253Sigor@sysoev.ru 
143343Smax.romanov@nginx.com static void nxt_router_app_port_ready(nxt_task_t *task,
144343Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg, void *data);
145343Smax.romanov@nginx.com static void nxt_router_app_port_error(nxt_task_t *task,
146343Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg, void *data);
147343Smax.romanov@nginx.com 
148343Smax.romanov@nginx.com static nxt_port_t * nxt_router_app_get_idle_port(nxt_app_t *app);
149343Smax.romanov@nginx.com static void nxt_router_app_port_release(nxt_task_t *task, nxt_port_t *port,
150343Smax.romanov@nginx.com     uint32_t request_failed, uint32_t got_response);
151141Smax.romanov@nginx.com 
15253Sigor@sysoev.ru static void nxt_router_conn_init(nxt_task_t *task, void *obj, void *data);
15353Sigor@sysoev.ru static void nxt_router_conn_http_header_parse(nxt_task_t *task, void *obj,
15453Sigor@sysoev.ru     void *data);
155206Smax.romanov@nginx.com static void nxt_router_conn_http_body_read(nxt_task_t *task, void *obj,
156206Smax.romanov@nginx.com     void *data);
15788Smax.romanov@nginx.com static void nxt_router_process_http_request(nxt_task_t *task,
15888Smax.romanov@nginx.com     nxt_conn_t *c, nxt_app_parse_ctx_t *ap);
159141Smax.romanov@nginx.com static void nxt_router_process_http_request_mp(nxt_task_t *task,
160343Smax.romanov@nginx.com     nxt_req_app_link_t *ra);
161216Sigor@sysoev.ru static nxt_int_t nxt_python_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
162216Sigor@sysoev.ru     nxt_app_wmsg_t *wmsg);
163216Sigor@sysoev.ru static nxt_int_t nxt_php_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
164216Sigor@sysoev.ru     nxt_app_wmsg_t *wmsg);
165216Sigor@sysoev.ru static nxt_int_t nxt_go_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
166216Sigor@sysoev.ru     nxt_app_wmsg_t *wmsg);
16788Smax.romanov@nginx.com static void nxt_router_conn_ready(nxt_task_t *task, void *obj, void *data);
16853Sigor@sysoev.ru static void nxt_router_conn_close(nxt_task_t *task, void *obj, void *data);
16953Sigor@sysoev.ru static void nxt_router_conn_free(nxt_task_t *task, void *obj, void *data);
17053Sigor@sysoev.ru static void nxt_router_conn_error(nxt_task_t *task, void *obj, void *data);
17153Sigor@sysoev.ru static void nxt_router_conn_timeout(nxt_task_t *task, void *obj, void *data);
172318Smax.romanov@nginx.com static void nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data);
17362Sigor@sysoev.ru static nxt_msec_t nxt_router_conn_timeout_value(nxt_conn_t *c, uintptr_t data);
17420Sigor@sysoev.ru 
175141Smax.romanov@nginx.com static void nxt_router_gen_error(nxt_task_t *task, nxt_conn_t *c, int code,
176345Smax.romanov@nginx.com     const char* str);
177141Smax.romanov@nginx.com 
178119Smax.romanov@nginx.com static nxt_router_t  *nxt_router;
17920Sigor@sysoev.ru 
180216Sigor@sysoev.ru 
181216Sigor@sysoev.ru static nxt_app_prepare_msg_t  nxt_app_prepare_msg[] = {
182216Sigor@sysoev.ru     nxt_python_prepare_msg,
183216Sigor@sysoev.ru     nxt_php_prepare_msg,
184216Sigor@sysoev.ru     nxt_go_prepare_msg,
185216Sigor@sysoev.ru };
186216Sigor@sysoev.ru 
187216Sigor@sysoev.ru 
18820Sigor@sysoev.ru nxt_int_t
189141Smax.romanov@nginx.com nxt_router_start(nxt_task_t *task, void *data)
19020Sigor@sysoev.ru {
191141Smax.romanov@nginx.com     nxt_int_t      ret;
192141Smax.romanov@nginx.com     nxt_router_t   *router;
193141Smax.romanov@nginx.com     nxt_runtime_t  *rt;
194141Smax.romanov@nginx.com 
195141Smax.romanov@nginx.com     rt = task->thread->runtime;
19653Sigor@sysoev.ru 
19788Smax.romanov@nginx.com     ret = nxt_app_http_init(task, rt);
19888Smax.romanov@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
19988Smax.romanov@nginx.com         return ret;
20088Smax.romanov@nginx.com     }
20188Smax.romanov@nginx.com 
20253Sigor@sysoev.ru     router = nxt_zalloc(sizeof(nxt_router_t));
20353Sigor@sysoev.ru     if (nxt_slow_path(router == NULL)) {
20453Sigor@sysoev.ru         return NXT_ERROR;
20553Sigor@sysoev.ru     }
20653Sigor@sysoev.ru 
20753Sigor@sysoev.ru     nxt_queue_init(&router->engines);
20853Sigor@sysoev.ru     nxt_queue_init(&router->sockets);
209133Sigor@sysoev.ru     nxt_queue_init(&router->apps);
21053Sigor@sysoev.ru 
211119Smax.romanov@nginx.com     nxt_router = router;
212119Smax.romanov@nginx.com 
213115Sigor@sysoev.ru     return NXT_OK;
214115Sigor@sysoev.ru }
215115Sigor@sysoev.ru 
216115Sigor@sysoev.ru 
217343Smax.romanov@nginx.com static void
218343Smax.romanov@nginx.com nxt_router_start_worker_handler(nxt_task_t *task, nxt_port_t *port, void *data)
219167Smax.romanov@nginx.com {
220343Smax.romanov@nginx.com     size_t         size;
221343Smax.romanov@nginx.com     uint32_t       stream;
222343Smax.romanov@nginx.com     nxt_app_t      *app;
223343Smax.romanov@nginx.com     nxt_buf_t      *b;
224343Smax.romanov@nginx.com     nxt_port_t     *main_port;
225343Smax.romanov@nginx.com     nxt_runtime_t  *rt;
226343Smax.romanov@nginx.com 
227343Smax.romanov@nginx.com     app = data;
228167Smax.romanov@nginx.com 
229167Smax.romanov@nginx.com     rt = task->thread->runtime;
230240Sigor@sysoev.ru     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
231167Smax.romanov@nginx.com 
232343Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p start worker", &app->name, app);
233343Smax.romanov@nginx.com 
234343Smax.romanov@nginx.com     size = app->name.length + 1 + app->conf.length;
235343Smax.romanov@nginx.com 
236343Smax.romanov@nginx.com     b = nxt_buf_mem_ts_alloc(task, task->thread->engine->mem_pool, size);
237343Smax.romanov@nginx.com 
238343Smax.romanov@nginx.com     if (nxt_slow_path(b == NULL)) {
239343Smax.romanov@nginx.com         goto failed;
240167Smax.romanov@nginx.com     }
241167Smax.romanov@nginx.com 
242343Smax.romanov@nginx.com     nxt_buf_cpystr(b, &app->name);
243343Smax.romanov@nginx.com     *b->mem.free++ = '\0';
244343Smax.romanov@nginx.com     nxt_buf_cpystr(b, &app->conf);
245343Smax.romanov@nginx.com 
246343Smax.romanov@nginx.com     stream = nxt_port_rpc_register_handler(task, port,
247343Smax.romanov@nginx.com                                            nxt_router_app_port_ready,
248343Smax.romanov@nginx.com                                            nxt_router_app_port_error,
249343Smax.romanov@nginx.com                                            -1, app);
250343Smax.romanov@nginx.com 
251343Smax.romanov@nginx.com     if (nxt_slow_path(stream == 0)) {
252343Smax.romanov@nginx.com         nxt_mp_release(b->data, b);
253343Smax.romanov@nginx.com 
254343Smax.romanov@nginx.com         goto failed;
255343Smax.romanov@nginx.com     }
256343Smax.romanov@nginx.com 
257343Smax.romanov@nginx.com     nxt_port_socket_write(task, main_port, NXT_PORT_MSG_START_WORKER, -1,
258343Smax.romanov@nginx.com                           stream, port->id, b);
259343Smax.romanov@nginx.com 
260343Smax.romanov@nginx.com     return;
261343Smax.romanov@nginx.com 
262343Smax.romanov@nginx.com failed:
263343Smax.romanov@nginx.com 
264343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
265343Smax.romanov@nginx.com 
266343Smax.romanov@nginx.com     app->pending_workers--;
267343Smax.romanov@nginx.com 
268343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
269343Smax.romanov@nginx.com 
270343Smax.romanov@nginx.com     nxt_router_app_use(task, app, -1);
271167Smax.romanov@nginx.com }
272167Smax.romanov@nginx.com 
273167Smax.romanov@nginx.com 
274343Smax.romanov@nginx.com static nxt_int_t
275343Smax.romanov@nginx.com nxt_router_start_worker(nxt_task_t *task, nxt_app_t *app)
276141Smax.romanov@nginx.com {
277343Smax.romanov@nginx.com     nxt_int_t      res;
278343Smax.romanov@nginx.com     nxt_port_t     *router_port;
279343Smax.romanov@nginx.com     nxt_runtime_t  *rt;
280343Smax.romanov@nginx.com 
281343Smax.romanov@nginx.com     rt = task->thread->runtime;
282343Smax.romanov@nginx.com     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
283343Smax.romanov@nginx.com 
284343Smax.romanov@nginx.com     nxt_router_app_use(task, app, 1);
285343Smax.romanov@nginx.com 
286343Smax.romanov@nginx.com     res = nxt_port_post(task, router_port, nxt_router_start_worker_handler,
287343Smax.romanov@nginx.com                         app);
288343Smax.romanov@nginx.com 
289343Smax.romanov@nginx.com     if (res == NXT_OK) {
290343Smax.romanov@nginx.com         return res;
291318Smax.romanov@nginx.com     }
292318Smax.romanov@nginx.com 
293343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
294343Smax.romanov@nginx.com 
295343Smax.romanov@nginx.com     app->pending_workers--;
296343Smax.romanov@nginx.com 
297343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
298343Smax.romanov@nginx.com 
299343Smax.romanov@nginx.com     nxt_router_app_use(task, app, -1);
300343Smax.romanov@nginx.com 
301343Smax.romanov@nginx.com     return NXT_ERROR;
302318Smax.romanov@nginx.com }
303318Smax.romanov@nginx.com 
304318Smax.romanov@nginx.com 
305*351Smax.romanov@nginx.com nxt_inline void
306*351Smax.romanov@nginx.com nxt_router_ra_init(nxt_task_t *task, nxt_req_app_link_t *ra,
307*351Smax.romanov@nginx.com     nxt_req_conn_link_t *rc)
308167Smax.romanov@nginx.com {
309318Smax.romanov@nginx.com     nxt_event_engine_t  *engine;
310*351Smax.romanov@nginx.com 
311318Smax.romanov@nginx.com     engine = task->thread->engine;
312167Smax.romanov@nginx.com 
313167Smax.romanov@nginx.com     nxt_memzero(ra, sizeof(nxt_req_app_link_t));
314167Smax.romanov@nginx.com 
315318Smax.romanov@nginx.com     ra->stream = rc->stream;
316318Smax.romanov@nginx.com     ra->app_pid = -1;
317167Smax.romanov@nginx.com     ra->rc = rc;
318318Smax.romanov@nginx.com     rc->ra = ra;
319318Smax.romanov@nginx.com     ra->reply_port = engine->port;
320*351Smax.romanov@nginx.com     ra->ap = rc->ap;
321167Smax.romanov@nginx.com 
322167Smax.romanov@nginx.com     ra->work.handler = NULL;
323318Smax.romanov@nginx.com     ra->work.task = &engine->task;
324167Smax.romanov@nginx.com     ra->work.obj = ra;
325318Smax.romanov@nginx.com     ra->work.data = engine;
326*351Smax.romanov@nginx.com }
327*351Smax.romanov@nginx.com 
328*351Smax.romanov@nginx.com 
329*351Smax.romanov@nginx.com nxt_inline nxt_req_app_link_t *
330*351Smax.romanov@nginx.com nxt_router_ra_create(nxt_task_t *task, nxt_req_app_link_t *ra_src)
331*351Smax.romanov@nginx.com {
332*351Smax.romanov@nginx.com     nxt_mp_t            *mp;
333*351Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
334*351Smax.romanov@nginx.com 
335*351Smax.romanov@nginx.com     mp = ra_src->ap->mem_pool;
336*351Smax.romanov@nginx.com 
337*351Smax.romanov@nginx.com     ra = nxt_mp_retain(mp, sizeof(nxt_req_app_link_t));
338*351Smax.romanov@nginx.com 
339*351Smax.romanov@nginx.com     if (nxt_slow_path(ra == NULL)) {
340*351Smax.romanov@nginx.com 
341*351Smax.romanov@nginx.com         ra_src->rc->ra = NULL;
342*351Smax.romanov@nginx.com         ra_src->rc = NULL;
343*351Smax.romanov@nginx.com 
344*351Smax.romanov@nginx.com         return NULL;
345*351Smax.romanov@nginx.com     }
346*351Smax.romanov@nginx.com 
347*351Smax.romanov@nginx.com     nxt_router_ra_init(task, ra, ra_src->rc);
348*351Smax.romanov@nginx.com 
349*351Smax.romanov@nginx.com     ra->mem_pool = mp;
350167Smax.romanov@nginx.com 
351167Smax.romanov@nginx.com     return ra;
352167Smax.romanov@nginx.com }
353167Smax.romanov@nginx.com 
354167Smax.romanov@nginx.com 
355167Smax.romanov@nginx.com static void
356167Smax.romanov@nginx.com nxt_router_ra_release(nxt_task_t *task, void *obj, void *data)
357167Smax.romanov@nginx.com {
358343Smax.romanov@nginx.com     nxt_req_app_link_t   *ra;
359343Smax.romanov@nginx.com     nxt_event_engine_t   *engine;
360343Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
361318Smax.romanov@nginx.com 
362318Smax.romanov@nginx.com     ra = obj;
363318Smax.romanov@nginx.com     engine = data;
364318Smax.romanov@nginx.com 
365343Smax.romanov@nginx.com     if (task->thread->engine != engine) {
366343Smax.romanov@nginx.com         if (ra->app_port != NULL) {
367343Smax.romanov@nginx.com             ra->app_pid = ra->app_port->pid;
368318Smax.romanov@nginx.com         }
369318Smax.romanov@nginx.com 
370318Smax.romanov@nginx.com         ra->work.handler = nxt_router_ra_release;
371318Smax.romanov@nginx.com         ra->work.task = &engine->task;
372318Smax.romanov@nginx.com         ra->work.next = NULL;
373318Smax.romanov@nginx.com 
374318Smax.romanov@nginx.com         nxt_debug(task, "ra stream #%uD post release to %p",
375318Smax.romanov@nginx.com                   ra->stream, engine);
376318Smax.romanov@nginx.com 
377318Smax.romanov@nginx.com         nxt_event_engine_post(engine, &ra->work);
378318Smax.romanov@nginx.com 
379318Smax.romanov@nginx.com         return;
380318Smax.romanov@nginx.com     }
381318Smax.romanov@nginx.com 
382343Smax.romanov@nginx.com     nxt_debug(task, "ra stream #%uD release", ra->stream);
383343Smax.romanov@nginx.com 
384343Smax.romanov@nginx.com     rc = ra->rc;
385343Smax.romanov@nginx.com 
386343Smax.romanov@nginx.com     if (rc != NULL) {
387343Smax.romanov@nginx.com         if (ra->app_pid != -1) {
388343Smax.romanov@nginx.com             nxt_port_rpc_ex_set_peer(task, engine->port, rc, ra->app_pid);
389343Smax.romanov@nginx.com         }
390343Smax.romanov@nginx.com 
391343Smax.romanov@nginx.com         rc->app_port = ra->app_port;
392343Smax.romanov@nginx.com 
393343Smax.romanov@nginx.com         ra->app_port = NULL;
394343Smax.romanov@nginx.com         rc->ra = NULL;
395343Smax.romanov@nginx.com         ra->rc = NULL;
396318Smax.romanov@nginx.com     }
397318Smax.romanov@nginx.com 
398343Smax.romanov@nginx.com     if (ra->app_port != NULL) {
399343Smax.romanov@nginx.com         nxt_router_app_port_release(task, ra->app_port, 0, 1);
400343Smax.romanov@nginx.com 
401343Smax.romanov@nginx.com         ra->app_port = NULL;
402343Smax.romanov@nginx.com     }
403318Smax.romanov@nginx.com 
404*351Smax.romanov@nginx.com     if (ra->mem_pool != NULL) {
405*351Smax.romanov@nginx.com         nxt_mp_release(ra->mem_pool, ra);
406*351Smax.romanov@nginx.com     }
407318Smax.romanov@nginx.com }
408318Smax.romanov@nginx.com 
409318Smax.romanov@nginx.com 
410318Smax.romanov@nginx.com static void
411318Smax.romanov@nginx.com nxt_router_ra_abort(nxt_task_t *task, void *obj, void *data)
412318Smax.romanov@nginx.com {
413343Smax.romanov@nginx.com     nxt_conn_t           *c;
414343Smax.romanov@nginx.com     nxt_req_app_link_t   *ra;
415343Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
416343Smax.romanov@nginx.com     nxt_event_engine_t   *engine;
417167Smax.romanov@nginx.com 
418167Smax.romanov@nginx.com     ra = obj;
419167Smax.romanov@nginx.com     engine = data;
420167Smax.romanov@nginx.com 
421167Smax.romanov@nginx.com     if (task->thread->engine != engine) {
422318Smax.romanov@nginx.com         ra->work.handler = nxt_router_ra_abort;
423167Smax.romanov@nginx.com         ra->work.task = &engine->task;
424167Smax.romanov@nginx.com         ra->work.next = NULL;
425167Smax.romanov@nginx.com 
426318Smax.romanov@nginx.com         nxt_debug(task, "ra stream #%uD post abort to %p", ra->stream, engine);
427167Smax.romanov@nginx.com 
428167Smax.romanov@nginx.com         nxt_event_engine_post(engine, &ra->work);
429167Smax.romanov@nginx.com 
430167Smax.romanov@nginx.com         return;
431167Smax.romanov@nginx.com     }
432167Smax.romanov@nginx.com 
433318Smax.romanov@nginx.com     nxt_debug(task, "ra stream #%uD abort", ra->stream);
434318Smax.romanov@nginx.com 
435343Smax.romanov@nginx.com     rc = ra->rc;
436343Smax.romanov@nginx.com 
437343Smax.romanov@nginx.com     if (rc != NULL) {
438343Smax.romanov@nginx.com         c = rc->conn;
439318Smax.romanov@nginx.com 
440318Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 500,
441318Smax.romanov@nginx.com                              "Failed to start application worker");
442343Smax.romanov@nginx.com 
443343Smax.romanov@nginx.com         rc->ra = NULL;
444343Smax.romanov@nginx.com         ra->rc = NULL;
445343Smax.romanov@nginx.com     }
446343Smax.romanov@nginx.com 
447343Smax.romanov@nginx.com     if (ra->app_port != NULL) {
448343Smax.romanov@nginx.com         nxt_router_app_port_release(task, ra->app_port, 0, 1);
449343Smax.romanov@nginx.com 
450343Smax.romanov@nginx.com         ra->app_port = NULL;
451167Smax.romanov@nginx.com     }
452167Smax.romanov@nginx.com 
453*351Smax.romanov@nginx.com     if (ra->mem_pool != NULL) {
454*351Smax.romanov@nginx.com         nxt_mp_release(ra->mem_pool, ra);
455*351Smax.romanov@nginx.com     }
456167Smax.romanov@nginx.com }
457167Smax.romanov@nginx.com 
458167Smax.romanov@nginx.com 
459345Smax.romanov@nginx.com static void
460345Smax.romanov@nginx.com nxt_router_ra_error_handler(nxt_task_t *task, void *obj, void *data)
461345Smax.romanov@nginx.com {
462345Smax.romanov@nginx.com     nxt_req_app_link_t   *ra;
463345Smax.romanov@nginx.com 
464345Smax.romanov@nginx.com     ra = obj;
465345Smax.romanov@nginx.com 
466345Smax.romanov@nginx.com     nxt_router_ra_error(task, ra, ra->err_code, ra->err_str);
467345Smax.romanov@nginx.com }
468345Smax.romanov@nginx.com 
469345Smax.romanov@nginx.com 
470345Smax.romanov@nginx.com static void
471345Smax.romanov@nginx.com nxt_router_ra_error(nxt_task_t *task, nxt_req_app_link_t *ra, int code,
472345Smax.romanov@nginx.com     const char* str)
473345Smax.romanov@nginx.com {
474345Smax.romanov@nginx.com     nxt_conn_t           *c;
475345Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
476345Smax.romanov@nginx.com     nxt_event_engine_t   *engine;
477345Smax.romanov@nginx.com 
478345Smax.romanov@nginx.com     engine = ra->work.data;
479345Smax.romanov@nginx.com 
480345Smax.romanov@nginx.com     if (task->thread->engine != engine) {
481345Smax.romanov@nginx.com         ra->err_code = code;
482345Smax.romanov@nginx.com         ra->err_str = str;
483345Smax.romanov@nginx.com 
484345Smax.romanov@nginx.com         ra->work.handler = nxt_router_ra_error_handler;
485345Smax.romanov@nginx.com         ra->work.task = &engine->task;
486345Smax.romanov@nginx.com         ra->work.next = NULL;
487345Smax.romanov@nginx.com 
488345Smax.romanov@nginx.com         nxt_debug(task, "ra stream #%uD post error to %p", ra->stream, engine);
489345Smax.romanov@nginx.com 
490345Smax.romanov@nginx.com         nxt_event_engine_post(engine, &ra->work);
491345Smax.romanov@nginx.com 
492345Smax.romanov@nginx.com         return;
493345Smax.romanov@nginx.com     }
494345Smax.romanov@nginx.com 
495345Smax.romanov@nginx.com     nxt_debug(task, "ra stream #%uD error", ra->stream);
496345Smax.romanov@nginx.com 
497345Smax.romanov@nginx.com     rc = ra->rc;
498345Smax.romanov@nginx.com 
499345Smax.romanov@nginx.com     if (rc != NULL) {
500345Smax.romanov@nginx.com         c = rc->conn;
501345Smax.romanov@nginx.com 
502345Smax.romanov@nginx.com         nxt_router_gen_error(task, c, code, str);
503345Smax.romanov@nginx.com 
504345Smax.romanov@nginx.com         rc->ra = NULL;
505345Smax.romanov@nginx.com         ra->rc = NULL;
506345Smax.romanov@nginx.com     }
507345Smax.romanov@nginx.com 
508345Smax.romanov@nginx.com     if (ra->app_port != NULL) {
509345Smax.romanov@nginx.com         nxt_router_app_port_release(task, ra->app_port, 0, 1);
510345Smax.romanov@nginx.com 
511345Smax.romanov@nginx.com         ra->app_port = NULL;
512345Smax.romanov@nginx.com     }
513345Smax.romanov@nginx.com 
514*351Smax.romanov@nginx.com     if (ra->mem_pool != NULL) {
515*351Smax.romanov@nginx.com         nxt_mp_release(ra->mem_pool, ra);
516*351Smax.romanov@nginx.com     }
517345Smax.romanov@nginx.com }
518345Smax.romanov@nginx.com 
519345Smax.romanov@nginx.com 
520343Smax.romanov@nginx.com nxt_inline void
521343Smax.romanov@nginx.com nxt_router_rc_unlink(nxt_task_t *task, nxt_req_conn_link_t *rc)
522343Smax.romanov@nginx.com {
523343Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
524343Smax.romanov@nginx.com 
525343Smax.romanov@nginx.com     if (rc->app_port != NULL) {
526343Smax.romanov@nginx.com         nxt_router_app_port_release(task, rc->app_port, 0, 1);
527343Smax.romanov@nginx.com 
528343Smax.romanov@nginx.com         rc->app_port = NULL;
529343Smax.romanov@nginx.com     }
530343Smax.romanov@nginx.com 
531343Smax.romanov@nginx.com     ra = rc->ra;
532343Smax.romanov@nginx.com 
533343Smax.romanov@nginx.com     if (ra != NULL) {
534343Smax.romanov@nginx.com         rc->ra = NULL;
535343Smax.romanov@nginx.com         ra->rc = NULL;
536343Smax.romanov@nginx.com 
537343Smax.romanov@nginx.com         nxt_thread_mutex_lock(&rc->app->mutex);
538343Smax.romanov@nginx.com 
539343Smax.romanov@nginx.com         if (ra->link.next != NULL) {
540343Smax.romanov@nginx.com             nxt_queue_remove(&ra->link);
541343Smax.romanov@nginx.com 
542343Smax.romanov@nginx.com             ra->link.next = NULL;
543343Smax.romanov@nginx.com 
544343Smax.romanov@nginx.com         } else {
545343Smax.romanov@nginx.com             ra = NULL;
546343Smax.romanov@nginx.com         }
547343Smax.romanov@nginx.com 
548343Smax.romanov@nginx.com         nxt_thread_mutex_unlock(&rc->app->mutex);
549343Smax.romanov@nginx.com     }
550343Smax.romanov@nginx.com 
551343Smax.romanov@nginx.com     if (ra != NULL) {
552343Smax.romanov@nginx.com         nxt_router_ra_release(task, ra, ra->work.data);
553343Smax.romanov@nginx.com     }
554343Smax.romanov@nginx.com 
555343Smax.romanov@nginx.com     if (rc->app != NULL) {
556343Smax.romanov@nginx.com         nxt_router_app_use(task, rc->app, -1);
557343Smax.romanov@nginx.com 
558343Smax.romanov@nginx.com         rc->app = NULL;
559343Smax.romanov@nginx.com     }
560343Smax.romanov@nginx.com 
561346Smax.romanov@nginx.com     if (rc->ap != NULL) {
562346Smax.romanov@nginx.com         nxt_app_http_req_done(task, rc->ap);
563346Smax.romanov@nginx.com 
564346Smax.romanov@nginx.com         rc->ap = NULL;
565346Smax.romanov@nginx.com     }
566346Smax.romanov@nginx.com 
567343Smax.romanov@nginx.com     nxt_queue_remove(&rc->link);
568343Smax.romanov@nginx.com 
569343Smax.romanov@nginx.com     rc->conn = NULL;
570343Smax.romanov@nginx.com }
571343Smax.romanov@nginx.com 
572343Smax.romanov@nginx.com 
573141Smax.romanov@nginx.com void
574141Smax.romanov@nginx.com nxt_router_new_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
575141Smax.romanov@nginx.com {
576141Smax.romanov@nginx.com     nxt_port_new_port_handler(task, msg);
577141Smax.romanov@nginx.com 
578192Smax.romanov@nginx.com     if (msg->port_msg.stream == 0) {
579141Smax.romanov@nginx.com         return;
580141Smax.romanov@nginx.com     }
581141Smax.romanov@nginx.com 
582347Smax.romanov@nginx.com     if (msg->u.new_port == NULL ||
583347Smax.romanov@nginx.com         msg->u.new_port->type != NXT_PROCESS_WORKER)
584347Smax.romanov@nginx.com     {
585192Smax.romanov@nginx.com         msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR;
586141Smax.romanov@nginx.com     }
587192Smax.romanov@nginx.com 
588192Smax.romanov@nginx.com     nxt_port_rpc_handler(task, msg);
589141Smax.romanov@nginx.com }
590141Smax.romanov@nginx.com 
591141Smax.romanov@nginx.com 
592139Sigor@sysoev.ru void
593139Sigor@sysoev.ru nxt_router_conf_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
594115Sigor@sysoev.ru {
595139Sigor@sysoev.ru     size_t                  dump_size;
596198Sigor@sysoev.ru     nxt_int_t               ret;
597139Sigor@sysoev.ru     nxt_buf_t               *b;
598139Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
599139Sigor@sysoev.ru 
600139Sigor@sysoev.ru     b = msg->buf;
601139Sigor@sysoev.ru 
602139Sigor@sysoev.ru     dump_size = nxt_buf_used_size(b);
603139Sigor@sysoev.ru 
604139Sigor@sysoev.ru     if (dump_size > 300) {
605139Sigor@sysoev.ru         dump_size = 300;
60653Sigor@sysoev.ru     }
60753Sigor@sysoev.ru 
608139Sigor@sysoev.ru     nxt_debug(task, "router conf data (%z): %*s",
609139Sigor@sysoev.ru               msg->size, dump_size, b->mem.pos);
610139Sigor@sysoev.ru 
611139Sigor@sysoev.ru     tmcf = nxt_router_temp_conf(task);
612139Sigor@sysoev.ru     if (nxt_slow_path(tmcf == NULL)) {
613139Sigor@sysoev.ru         return;
61453Sigor@sysoev.ru     }
61553Sigor@sysoev.ru 
616139Sigor@sysoev.ru     tmcf->conf->router = nxt_router;
617139Sigor@sysoev.ru     tmcf->stream = msg->port_msg.stream;
618139Sigor@sysoev.ru     tmcf->port = nxt_runtime_port_find(task->thread->runtime,
619198Sigor@sysoev.ru                                        msg->port_msg.pid,
620198Sigor@sysoev.ru                                        msg->port_msg.reply_port);
621198Sigor@sysoev.ru 
622198Sigor@sysoev.ru     ret = nxt_router_conf_create(task, tmcf, b->mem.pos, b->mem.free);
623198Sigor@sysoev.ru 
624198Sigor@sysoev.ru     if (nxt_fast_path(ret == NXT_OK)) {
625198Sigor@sysoev.ru         nxt_router_conf_apply(task, tmcf, NULL);
626198Sigor@sysoev.ru 
627198Sigor@sysoev.ru     } else {
628198Sigor@sysoev.ru         nxt_router_conf_error(task, tmcf);
629139Sigor@sysoev.ru     }
63053Sigor@sysoev.ru }
63153Sigor@sysoev.ru 
63253Sigor@sysoev.ru 
633347Smax.romanov@nginx.com static void
634347Smax.romanov@nginx.com nxt_router_worker_remove_pid(nxt_task_t *task, nxt_port_t *port, void *data)
635347Smax.romanov@nginx.com {
636347Smax.romanov@nginx.com     union {
637347Smax.romanov@nginx.com         nxt_pid_t  removed_pid;
638347Smax.romanov@nginx.com         void       *data;
639347Smax.romanov@nginx.com     } u;
640347Smax.romanov@nginx.com 
641347Smax.romanov@nginx.com     u.data = data;
642347Smax.romanov@nginx.com 
643347Smax.romanov@nginx.com     nxt_port_rpc_remove_peer(task, port, u.removed_pid);
644347Smax.romanov@nginx.com }
645347Smax.romanov@nginx.com 
646347Smax.romanov@nginx.com 
647192Smax.romanov@nginx.com void
648192Smax.romanov@nginx.com nxt_router_remove_pid_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
649192Smax.romanov@nginx.com {
650347Smax.romanov@nginx.com     nxt_event_engine_t  *engine;
651318Smax.romanov@nginx.com 
652192Smax.romanov@nginx.com     nxt_port_remove_pid_handler(task, msg);
653192Smax.romanov@nginx.com 
654192Smax.romanov@nginx.com     if (msg->port_msg.stream == 0) {
655192Smax.romanov@nginx.com         return;
656192Smax.romanov@nginx.com     }
657192Smax.romanov@nginx.com 
658318Smax.romanov@nginx.com     nxt_queue_each(engine, &nxt_router->engines, nxt_event_engine_t, link0)
659318Smax.romanov@nginx.com     {
660347Smax.romanov@nginx.com         nxt_port_post(task, engine->port, nxt_router_worker_remove_pid,
661347Smax.romanov@nginx.com                       msg->u.data);
662318Smax.romanov@nginx.com     }
663318Smax.romanov@nginx.com     nxt_queue_loop;
664318Smax.romanov@nginx.com 
665192Smax.romanov@nginx.com     msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR;
666192Smax.romanov@nginx.com 
667192Smax.romanov@nginx.com     nxt_port_rpc_handler(task, msg);
668192Smax.romanov@nginx.com }
669192Smax.romanov@nginx.com 
670192Smax.romanov@nginx.com 
67153Sigor@sysoev.ru static nxt_router_temp_conf_t *
672139Sigor@sysoev.ru nxt_router_temp_conf(nxt_task_t *task)
67353Sigor@sysoev.ru {
67465Sigor@sysoev.ru     nxt_mp_t                *mp, *tmp;
67553Sigor@sysoev.ru     nxt_router_conf_t       *rtcf;
67653Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
67753Sigor@sysoev.ru 
67865Sigor@sysoev.ru     mp = nxt_mp_create(1024, 128, 256, 32);
67953Sigor@sysoev.ru     if (nxt_slow_path(mp == NULL)) {
68053Sigor@sysoev.ru         return NULL;
68153Sigor@sysoev.ru     }
68253Sigor@sysoev.ru 
68365Sigor@sysoev.ru     rtcf = nxt_mp_zget(mp, sizeof(nxt_router_conf_t));
68453Sigor@sysoev.ru     if (nxt_slow_path(rtcf == NULL)) {
68553Sigor@sysoev.ru         goto fail;
68653Sigor@sysoev.ru     }
68753Sigor@sysoev.ru 
68853Sigor@sysoev.ru     rtcf->mem_pool = mp;
68953Sigor@sysoev.ru 
69065Sigor@sysoev.ru     tmp = nxt_mp_create(1024, 128, 256, 32);
69153Sigor@sysoev.ru     if (nxt_slow_path(tmp == NULL)) {
69253Sigor@sysoev.ru         goto fail;
69353Sigor@sysoev.ru     }
69453Sigor@sysoev.ru 
69565Sigor@sysoev.ru     tmcf = nxt_mp_zget(tmp, sizeof(nxt_router_temp_conf_t));
69653Sigor@sysoev.ru     if (nxt_slow_path(tmcf == NULL)) {
69753Sigor@sysoev.ru         goto temp_fail;
69853Sigor@sysoev.ru     }
69953Sigor@sysoev.ru 
70053Sigor@sysoev.ru     tmcf->mem_pool = tmp;
70153Sigor@sysoev.ru     tmcf->conf = rtcf;
702139Sigor@sysoev.ru     tmcf->count = 1;
703139Sigor@sysoev.ru     tmcf->engine = task->thread->engine;
70453Sigor@sysoev.ru 
70553Sigor@sysoev.ru     tmcf->engines = nxt_array_create(tmcf->mem_pool, 4,
70653Sigor@sysoev.ru                                      sizeof(nxt_router_engine_conf_t));
70753Sigor@sysoev.ru     if (nxt_slow_path(tmcf->engines == NULL)) {
70853Sigor@sysoev.ru         goto temp_fail;
70953Sigor@sysoev.ru     }
71053Sigor@sysoev.ru 
71153Sigor@sysoev.ru     nxt_queue_init(&tmcf->deleting);
71253Sigor@sysoev.ru     nxt_queue_init(&tmcf->keeping);
71353Sigor@sysoev.ru     nxt_queue_init(&tmcf->updating);
71453Sigor@sysoev.ru     nxt_queue_init(&tmcf->pending);
71553Sigor@sysoev.ru     nxt_queue_init(&tmcf->creating);
716133Sigor@sysoev.ru     nxt_queue_init(&tmcf->apps);
717133Sigor@sysoev.ru     nxt_queue_init(&tmcf->previous);
71853Sigor@sysoev.ru 
71953Sigor@sysoev.ru     return tmcf;
72053Sigor@sysoev.ru 
72153Sigor@sysoev.ru temp_fail:
72253Sigor@sysoev.ru 
72365Sigor@sysoev.ru     nxt_mp_destroy(tmp);
72453Sigor@sysoev.ru 
72553Sigor@sysoev.ru fail:
72653Sigor@sysoev.ru 
72765Sigor@sysoev.ru     nxt_mp_destroy(mp);
72853Sigor@sysoev.ru 
72953Sigor@sysoev.ru     return NULL;
73053Sigor@sysoev.ru }
73153Sigor@sysoev.ru 
73253Sigor@sysoev.ru 
733198Sigor@sysoev.ru static void
734198Sigor@sysoev.ru nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data)
735139Sigor@sysoev.ru {
736139Sigor@sysoev.ru     nxt_int_t                    ret;
737139Sigor@sysoev.ru     nxt_router_t                 *router;
738139Sigor@sysoev.ru     nxt_runtime_t                *rt;
739198Sigor@sysoev.ru     nxt_queue_link_t             *qlk;
740198Sigor@sysoev.ru     nxt_socket_conf_t            *skcf;
741198Sigor@sysoev.ru     nxt_router_temp_conf_t       *tmcf;
742139Sigor@sysoev.ru     const nxt_event_interface_t  *interface;
743139Sigor@sysoev.ru 
744198Sigor@sysoev.ru     tmcf = obj;
745198Sigor@sysoev.ru 
746198Sigor@sysoev.ru     qlk = nxt_queue_first(&tmcf->pending);
747198Sigor@sysoev.ru 
748198Sigor@sysoev.ru     if (qlk != nxt_queue_tail(&tmcf->pending)) {
749198Sigor@sysoev.ru         nxt_queue_remove(qlk);
750198Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->creating, qlk);
751198Sigor@sysoev.ru 
752198Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
753198Sigor@sysoev.ru 
754198Sigor@sysoev.ru         nxt_router_listen_socket_rpc_create(task, tmcf, skcf);
755198Sigor@sysoev.ru 
756198Sigor@sysoev.ru         return;
757139Sigor@sysoev.ru     }
758139Sigor@sysoev.ru 
759139Sigor@sysoev.ru     rt = task->thread->runtime;
760139Sigor@sysoev.ru 
761139Sigor@sysoev.ru     interface = nxt_service_get(rt->services, "engine", NULL);
762139Sigor@sysoev.ru 
763198Sigor@sysoev.ru     router = tmcf->conf->router;
764198Sigor@sysoev.ru 
765139Sigor@sysoev.ru     ret = nxt_router_engines_create(task, router, tmcf, interface);
766139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
767198Sigor@sysoev.ru         goto fail;
768139Sigor@sysoev.ru     }
769139Sigor@sysoev.ru 
770139Sigor@sysoev.ru     ret = nxt_router_threads_create(task, rt, tmcf);
771139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
772198Sigor@sysoev.ru         goto fail;
773139Sigor@sysoev.ru     }
774139Sigor@sysoev.ru 
775343Smax.romanov@nginx.com     nxt_router_apps_sort(task, router, tmcf);
776139Sigor@sysoev.ru 
777315Sigor@sysoev.ru     nxt_router_engines_post(router, tmcf);
778139Sigor@sysoev.ru 
779139Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->updating);
780139Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->creating);
781139Sigor@sysoev.ru 
782198Sigor@sysoev.ru     nxt_router_conf_ready(task, tmcf);
783198Sigor@sysoev.ru 
784198Sigor@sysoev.ru     return;
785198Sigor@sysoev.ru 
786198Sigor@sysoev.ru fail:
787198Sigor@sysoev.ru 
788198Sigor@sysoev.ru     nxt_router_conf_error(task, tmcf);
789198Sigor@sysoev.ru 
790198Sigor@sysoev.ru     return;
791139Sigor@sysoev.ru }
792139Sigor@sysoev.ru 
793139Sigor@sysoev.ru 
794139Sigor@sysoev.ru static void
795139Sigor@sysoev.ru nxt_router_conf_wait(nxt_task_t *task, void *obj, void *data)
796139Sigor@sysoev.ru {
797153Sigor@sysoev.ru     nxt_joint_job_t  *job;
798153Sigor@sysoev.ru 
799153Sigor@sysoev.ru     job = obj;
800153Sigor@sysoev.ru 
801198Sigor@sysoev.ru     nxt_router_conf_ready(task, job->tmcf);
802139Sigor@sysoev.ru }
803139Sigor@sysoev.ru 
804139Sigor@sysoev.ru 
805139Sigor@sysoev.ru static void
806198Sigor@sysoev.ru nxt_router_conf_ready(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
807139Sigor@sysoev.ru {
808139Sigor@sysoev.ru     nxt_debug(task, "temp conf count:%D", tmcf->count);
809139Sigor@sysoev.ru 
810139Sigor@sysoev.ru     if (--tmcf->count == 0) {
811193Smax.romanov@nginx.com         nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_READY_LAST);
812139Sigor@sysoev.ru     }
813139Sigor@sysoev.ru }
814139Sigor@sysoev.ru 
815139Sigor@sysoev.ru 
816139Sigor@sysoev.ru static void
817139Sigor@sysoev.ru nxt_router_conf_error(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
818139Sigor@sysoev.ru {
819148Sigor@sysoev.ru     nxt_socket_t       s;
820149Sigor@sysoev.ru     nxt_router_t       *router;
821148Sigor@sysoev.ru     nxt_queue_link_t   *qlk;
822148Sigor@sysoev.ru     nxt_socket_conf_t  *skcf;
823148Sigor@sysoev.ru 
824198Sigor@sysoev.ru     nxt_log(task, NXT_LOG_CRIT, "failed to apply new conf");
825198Sigor@sysoev.ru 
826148Sigor@sysoev.ru     for (qlk = nxt_queue_first(&tmcf->creating);
827148Sigor@sysoev.ru          qlk != nxt_queue_tail(&tmcf->creating);
828148Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
829148Sigor@sysoev.ru     {
830148Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
831148Sigor@sysoev.ru         s = skcf->listen.socket;
832148Sigor@sysoev.ru 
833148Sigor@sysoev.ru         if (s != -1) {
834148Sigor@sysoev.ru             nxt_socket_close(task, s);
835148Sigor@sysoev.ru         }
836148Sigor@sysoev.ru 
837148Sigor@sysoev.ru         nxt_free(skcf->socket);
838148Sigor@sysoev.ru     }
839148Sigor@sysoev.ru 
840149Sigor@sysoev.ru     router = tmcf->conf->router;
841149Sigor@sysoev.ru 
842149Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->keeping);
843149Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->deleting);
844149Sigor@sysoev.ru 
845148Sigor@sysoev.ru     // TODO: new engines and threads
846148Sigor@sysoev.ru 
847139Sigor@sysoev.ru     nxt_mp_destroy(tmcf->conf->mem_pool);
848139Sigor@sysoev.ru 
849193Smax.romanov@nginx.com     nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_ERROR);
850139Sigor@sysoev.ru }
851139Sigor@sysoev.ru 
852139Sigor@sysoev.ru 
853139Sigor@sysoev.ru static void
854139Sigor@sysoev.ru nxt_router_conf_send(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
855193Smax.romanov@nginx.com     nxt_port_msg_type_t type)
856139Sigor@sysoev.ru {
857193Smax.romanov@nginx.com     nxt_port_socket_write(task, tmcf->port, type, -1, tmcf->stream, 0, NULL);
858139Sigor@sysoev.ru }
859139Sigor@sysoev.ru 
860139Sigor@sysoev.ru 
861115Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_conf[] = {
862115Sigor@sysoev.ru     {
863133Sigor@sysoev.ru         nxt_string("listeners_threads"),
864115Sigor@sysoev.ru         NXT_CONF_MAP_INT32,
865115Sigor@sysoev.ru         offsetof(nxt_router_conf_t, threads),
866115Sigor@sysoev.ru     },
867115Sigor@sysoev.ru };
868115Sigor@sysoev.ru 
869115Sigor@sysoev.ru 
870133Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_app_conf[] = {
871115Sigor@sysoev.ru     {
872133Sigor@sysoev.ru         nxt_string("type"),
873115Sigor@sysoev.ru         NXT_CONF_MAP_STR,
874133Sigor@sysoev.ru         offsetof(nxt_router_app_conf_t, type),
875115Sigor@sysoev.ru     },
876115Sigor@sysoev.ru 
877115Sigor@sysoev.ru     {
878133Sigor@sysoev.ru         nxt_string("workers"),
879115Sigor@sysoev.ru         NXT_CONF_MAP_INT32,
880133Sigor@sysoev.ru         offsetof(nxt_router_app_conf_t, workers),
881133Sigor@sysoev.ru     },
882318Smax.romanov@nginx.com 
883318Smax.romanov@nginx.com     {
884318Smax.romanov@nginx.com         nxt_string("limits"),
885318Smax.romanov@nginx.com         NXT_CONF_MAP_PTR,
886318Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, limits_value),
887318Smax.romanov@nginx.com     },
888318Smax.romanov@nginx.com };
889318Smax.romanov@nginx.com 
890318Smax.romanov@nginx.com 
891318Smax.romanov@nginx.com static nxt_conf_map_t  nxt_router_app_limits_conf[] = {
892318Smax.romanov@nginx.com     {
893318Smax.romanov@nginx.com         nxt_string("timeout"),
894318Smax.romanov@nginx.com         NXT_CONF_MAP_MSEC,
895318Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, timeout),
896318Smax.romanov@nginx.com     },
897318Smax.romanov@nginx.com 
898318Smax.romanov@nginx.com     {
899318Smax.romanov@nginx.com         nxt_string("requests"),
900318Smax.romanov@nginx.com         NXT_CONF_MAP_INT32,
901318Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, requests),
902318Smax.romanov@nginx.com     },
903133Sigor@sysoev.ru };
904133Sigor@sysoev.ru 
905133Sigor@sysoev.ru 
906133Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_listener_conf[] = {
907133Sigor@sysoev.ru     {
908133Sigor@sysoev.ru         nxt_string("application"),
909133Sigor@sysoev.ru         NXT_CONF_MAP_STR,
910133Sigor@sysoev.ru         offsetof(nxt_router_listener_conf_t, application),
911115Sigor@sysoev.ru     },
912115Sigor@sysoev.ru };
913115Sigor@sysoev.ru 
914115Sigor@sysoev.ru 
915115Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_http_conf[] = {
916115Sigor@sysoev.ru     {
917115Sigor@sysoev.ru         nxt_string("header_buffer_size"),
918115Sigor@sysoev.ru         NXT_CONF_MAP_SIZE,
919115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, header_buffer_size),
920115Sigor@sysoev.ru     },
921115Sigor@sysoev.ru 
922115Sigor@sysoev.ru     {
923115Sigor@sysoev.ru         nxt_string("large_header_buffer_size"),
924115Sigor@sysoev.ru         NXT_CONF_MAP_SIZE,
925115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, large_header_buffer_size),
926115Sigor@sysoev.ru     },
927115Sigor@sysoev.ru 
928115Sigor@sysoev.ru     {
929206Smax.romanov@nginx.com         nxt_string("large_header_buffers"),
930206Smax.romanov@nginx.com         NXT_CONF_MAP_SIZE,
931206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, large_header_buffers),
932206Smax.romanov@nginx.com     },
933206Smax.romanov@nginx.com 
934206Smax.romanov@nginx.com     {
935206Smax.romanov@nginx.com         nxt_string("body_buffer_size"),
936206Smax.romanov@nginx.com         NXT_CONF_MAP_SIZE,
937206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, body_buffer_size),
938206Smax.romanov@nginx.com     },
939206Smax.romanov@nginx.com 
940206Smax.romanov@nginx.com     {
941206Smax.romanov@nginx.com         nxt_string("max_body_size"),
942206Smax.romanov@nginx.com         NXT_CONF_MAP_SIZE,
943206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, max_body_size),
944206Smax.romanov@nginx.com     },
945206Smax.romanov@nginx.com 
946206Smax.romanov@nginx.com     {
947115Sigor@sysoev.ru         nxt_string("header_read_timeout"),
948115Sigor@sysoev.ru         NXT_CONF_MAP_MSEC,
949115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, header_read_timeout),
950115Sigor@sysoev.ru     },
951206Smax.romanov@nginx.com 
952206Smax.romanov@nginx.com     {
953206Smax.romanov@nginx.com         nxt_string("body_read_timeout"),
954206Smax.romanov@nginx.com         NXT_CONF_MAP_MSEC,
955206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, body_read_timeout),
956206Smax.romanov@nginx.com     },
957115Sigor@sysoev.ru };
958115Sigor@sysoev.ru 
959115Sigor@sysoev.ru 
96053Sigor@sysoev.ru static nxt_int_t
961115Sigor@sysoev.ru nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
962115Sigor@sysoev.ru     u_char *start, u_char *end)
96353Sigor@sysoev.ru {
964133Sigor@sysoev.ru     u_char                      *p;
965133Sigor@sysoev.ru     size_t                      size;
966115Sigor@sysoev.ru     nxt_mp_t                    *mp;
967115Sigor@sysoev.ru     uint32_t                    next;
968115Sigor@sysoev.ru     nxt_int_t                   ret;
969115Sigor@sysoev.ru     nxt_str_t                   name;
970133Sigor@sysoev.ru     nxt_app_t                   *app, *prev;
971133Sigor@sysoev.ru     nxt_app_type_t              type;
972115Sigor@sysoev.ru     nxt_sockaddr_t              *sa;
973133Sigor@sysoev.ru     nxt_conf_value_t            *conf, *http;
974133Sigor@sysoev.ru     nxt_conf_value_t            *applications, *application;
975133Sigor@sysoev.ru     nxt_conf_value_t            *listeners, *listener;
976115Sigor@sysoev.ru     nxt_socket_conf_t           *skcf;
977216Sigor@sysoev.ru     nxt_app_lang_module_t       *lang;
978133Sigor@sysoev.ru     nxt_router_app_conf_t       apcf;
979115Sigor@sysoev.ru     nxt_router_listener_conf_t  lscf;
980115Sigor@sysoev.ru 
981115Sigor@sysoev.ru     static nxt_str_t  http_path = nxt_string("/http");
982133Sigor@sysoev.ru     static nxt_str_t  applications_path = nxt_string("/applications");
983115Sigor@sysoev.ru     static nxt_str_t  listeners_path = nxt_string("/listeners");
984115Sigor@sysoev.ru 
985208Svbart@nginx.com     conf = nxt_conf_json_parse(tmcf->mem_pool, start, end, NULL);
986115Sigor@sysoev.ru     if (conf == NULL) {
987115Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "configuration parsing error");
988115Sigor@sysoev.ru         return NXT_ERROR;
989115Sigor@sysoev.ru     }
990115Sigor@sysoev.ru 
991213Svbart@nginx.com     mp = tmcf->conf->mem_pool;
992213Svbart@nginx.com 
993213Svbart@nginx.com     ret = nxt_conf_map_object(mp, conf, nxt_router_conf,
994136Svbart@nginx.com                               nxt_nitems(nxt_router_conf), tmcf->conf);
995115Sigor@sysoev.ru     if (ret != NXT_OK) {
996133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "root map error");
997115Sigor@sysoev.ru         return NXT_ERROR;
998115Sigor@sysoev.ru     }
999115Sigor@sysoev.ru 
1000117Sigor@sysoev.ru     if (tmcf->conf->threads == 0) {
1001117Sigor@sysoev.ru         tmcf->conf->threads = nxt_ncpu;
1002117Sigor@sysoev.ru     }
1003117Sigor@sysoev.ru 
1004133Sigor@sysoev.ru     applications = nxt_conf_get_path(conf, &applications_path);
1005133Sigor@sysoev.ru     if (applications == NULL) {
1006133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "no \"applications\" block");
1007115Sigor@sysoev.ru         return NXT_ERROR;
1008115Sigor@sysoev.ru     }
1009115Sigor@sysoev.ru 
1010133Sigor@sysoev.ru     next = 0;
1011133Sigor@sysoev.ru 
1012133Sigor@sysoev.ru     for ( ;; ) {
1013133Sigor@sysoev.ru         application = nxt_conf_next_object_member(applications, &name, &next);
1014133Sigor@sysoev.ru         if (application == NULL) {
1015133Sigor@sysoev.ru             break;
1016133Sigor@sysoev.ru         }
1017133Sigor@sysoev.ru 
1018133Sigor@sysoev.ru         nxt_debug(task, "application \"%V\"", &name);
1019133Sigor@sysoev.ru 
1020144Smax.romanov@nginx.com         size = nxt_conf_json_length(application, NULL);
1021144Smax.romanov@nginx.com 
1022144Smax.romanov@nginx.com         app = nxt_malloc(sizeof(nxt_app_t) + name.length + size);
1023133Sigor@sysoev.ru         if (app == NULL) {
1024133Sigor@sysoev.ru             goto fail;
1025133Sigor@sysoev.ru         }
1026133Sigor@sysoev.ru 
1027144Smax.romanov@nginx.com         nxt_memzero(app, sizeof(nxt_app_t));
1028144Smax.romanov@nginx.com 
1029144Smax.romanov@nginx.com         app->name.start = nxt_pointer_to(app, sizeof(nxt_app_t));
1030144Smax.romanov@nginx.com         app->conf.start = nxt_pointer_to(app, sizeof(nxt_app_t) + name.length);
1031133Sigor@sysoev.ru 
1032133Sigor@sysoev.ru         p = nxt_conf_json_print(app->conf.start, application, NULL);
1033133Sigor@sysoev.ru         app->conf.length = p - app->conf.start;
1034133Sigor@sysoev.ru 
1035144Smax.romanov@nginx.com         nxt_assert(app->conf.length <= size);
1036144Smax.romanov@nginx.com 
1037133Sigor@sysoev.ru         nxt_debug(task, "application conf \"%V\"", &app->conf);
1038133Sigor@sysoev.ru 
1039133Sigor@sysoev.ru         prev = nxt_router_app_find(&tmcf->conf->router->apps, &name);
1040133Sigor@sysoev.ru 
1041133Sigor@sysoev.ru         if (prev != NULL && nxt_strstr_eq(&app->conf, &prev->conf)) {
1042133Sigor@sysoev.ru             nxt_free(app);
1043133Sigor@sysoev.ru 
1044133Sigor@sysoev.ru             nxt_queue_remove(&prev->link);
1045133Sigor@sysoev.ru             nxt_queue_insert_tail(&tmcf->previous, &prev->link);
1046133Sigor@sysoev.ru             continue;
1047133Sigor@sysoev.ru         }
1048133Sigor@sysoev.ru 
1049263Smax.romanov@nginx.com         apcf.workers = 1;
1050318Smax.romanov@nginx.com         apcf.timeout = 0;
1051318Smax.romanov@nginx.com         apcf.requests = 0;
1052318Smax.romanov@nginx.com         apcf.limits_value = NULL;
1053263Smax.romanov@nginx.com 
1054213Svbart@nginx.com         ret = nxt_conf_map_object(mp, application, nxt_router_app_conf,
1055136Svbart@nginx.com                                   nxt_nitems(nxt_router_app_conf), &apcf);
1056133Sigor@sysoev.ru         if (ret != NXT_OK) {
1057133Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "application map error");
1058133Sigor@sysoev.ru             goto app_fail;
1059133Sigor@sysoev.ru         }
1060115Sigor@sysoev.ru 
1061318Smax.romanov@nginx.com         if (apcf.limits_value != NULL) {
1062318Smax.romanov@nginx.com 
1063318Smax.romanov@nginx.com             if (nxt_conf_type(apcf.limits_value) != NXT_CONF_OBJECT) {
1064318Smax.romanov@nginx.com                 nxt_log(task, NXT_LOG_CRIT, "application limits is not object");
1065318Smax.romanov@nginx.com                 goto app_fail;
1066318Smax.romanov@nginx.com             }
1067318Smax.romanov@nginx.com 
1068318Smax.romanov@nginx.com             ret = nxt_conf_map_object(mp, apcf.limits_value,
1069318Smax.romanov@nginx.com                                       nxt_router_app_limits_conf,
1070318Smax.romanov@nginx.com                                       nxt_nitems(nxt_router_app_limits_conf),
1071318Smax.romanov@nginx.com                                       &apcf);
1072318Smax.romanov@nginx.com             if (ret != NXT_OK) {
1073318Smax.romanov@nginx.com                 nxt_log(task, NXT_LOG_CRIT, "application limits map error");
1074318Smax.romanov@nginx.com                 goto app_fail;
1075318Smax.romanov@nginx.com             }
1076318Smax.romanov@nginx.com         }
1077318Smax.romanov@nginx.com 
1078133Sigor@sysoev.ru         nxt_debug(task, "application type: %V", &apcf.type);
1079133Sigor@sysoev.ru         nxt_debug(task, "application workers: %D", apcf.workers);
1080318Smax.romanov@nginx.com         nxt_debug(task, "application timeout: %D", apcf.timeout);
1081318Smax.romanov@nginx.com         nxt_debug(task, "application requests: %D", apcf.requests);
1082133Sigor@sysoev.ru 
1083216Sigor@sysoev.ru         lang = nxt_app_lang_module(task->thread->runtime, &apcf.type);
1084216Sigor@sysoev.ru 
1085216Sigor@sysoev.ru         if (lang == NULL) {
1086141Smax.romanov@nginx.com             nxt_log(task, NXT_LOG_CRIT, "unknown application type: \"%V\"",
1087141Smax.romanov@nginx.com                     &apcf.type);
1088141Smax.romanov@nginx.com             goto app_fail;
1089141Smax.romanov@nginx.com         }
1090141Smax.romanov@nginx.com 
1091216Sigor@sysoev.ru         nxt_debug(task, "application language module: \"%s\"", lang->file);
1092216Sigor@sysoev.ru 
1093216Sigor@sysoev.ru         type = nxt_app_parse_type(&lang->type);
1094216Sigor@sysoev.ru 
1095216Sigor@sysoev.ru         if (type == NXT_APP_UNKNOWN) {
1096216Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "unknown application type: \"%V\"",
1097216Sigor@sysoev.ru                     &lang->type);
1098216Sigor@sysoev.ru             goto app_fail;
1099216Sigor@sysoev.ru         }
1100216Sigor@sysoev.ru 
1101216Sigor@sysoev.ru         if (nxt_app_prepare_msg[type] == NULL) {
1102133Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "unsupported application type: \"%V\"",
1103216Sigor@sysoev.ru                     &lang->type);
1104133Sigor@sysoev.ru             goto app_fail;
1105133Sigor@sysoev.ru         }
1106133Sigor@sysoev.ru 
1107133Sigor@sysoev.ru         ret = nxt_thread_mutex_create(&app->mutex);
1108133Sigor@sysoev.ru         if (ret != NXT_OK) {
1109133Sigor@sysoev.ru             goto app_fail;
1110133Sigor@sysoev.ru         }
1111133Sigor@sysoev.ru 
1112141Smax.romanov@nginx.com         nxt_queue_init(&app->ports);
1113141Smax.romanov@nginx.com         nxt_queue_init(&app->requests);
1114141Smax.romanov@nginx.com 
1115144Smax.romanov@nginx.com         app->name.length = name.length;
1116144Smax.romanov@nginx.com         nxt_memcpy(app->name.start, name.start, name.length);
1117144Smax.romanov@nginx.com 
1118133Sigor@sysoev.ru         app->type = type;
1119133Sigor@sysoev.ru         app->max_workers = apcf.workers;
1120318Smax.romanov@nginx.com         app->timeout = apcf.timeout;
1121133Sigor@sysoev.ru         app->live = 1;
1122343Smax.romanov@nginx.com         app->max_pending_responses = 2;
1123216Sigor@sysoev.ru         app->prepare_msg = nxt_app_prepare_msg[type];
1124133Sigor@sysoev.ru 
1125133Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->apps, &app->link);
1126343Smax.romanov@nginx.com 
1127343Smax.romanov@nginx.com         nxt_router_app_use(task, app, 1);
1128133Sigor@sysoev.ru     }
1129133Sigor@sysoev.ru 
1130133Sigor@sysoev.ru     http = nxt_conf_get_path(conf, &http_path);
1131133Sigor@sysoev.ru #if 0
1132133Sigor@sysoev.ru     if (http == NULL) {
1133133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "no \"http\" block");
1134133Sigor@sysoev.ru         return NXT_ERROR;
1135133Sigor@sysoev.ru     }
1136133Sigor@sysoev.ru #endif
1137133Sigor@sysoev.ru 
1138133Sigor@sysoev.ru     listeners = nxt_conf_get_path(conf, &listeners_path);
1139115Sigor@sysoev.ru     if (listeners == NULL) {
1140133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "no \"listeners\" block");
1141115Sigor@sysoev.ru         return NXT_ERROR;
1142115Sigor@sysoev.ru     }
114353Sigor@sysoev.ru 
1144133Sigor@sysoev.ru     next = 0;
114553Sigor@sysoev.ru 
1146115Sigor@sysoev.ru     for ( ;; ) {
1147115Sigor@sysoev.ru         listener = nxt_conf_next_object_member(listeners, &name, &next);
1148115Sigor@sysoev.ru         if (listener == NULL) {
1149115Sigor@sysoev.ru             break;
1150115Sigor@sysoev.ru         }
115153Sigor@sysoev.ru 
1152115Sigor@sysoev.ru         sa = nxt_sockaddr_parse(mp, &name);
1153115Sigor@sysoev.ru         if (sa == NULL) {
1154115Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "invalid listener \"%V\"", &name);
1155133Sigor@sysoev.ru             goto fail;
1156115Sigor@sysoev.ru         }
1157115Sigor@sysoev.ru 
1158115Sigor@sysoev.ru         sa->type = SOCK_STREAM;
1159115Sigor@sysoev.ru 
1160115Sigor@sysoev.ru         nxt_debug(task, "router listener: \"%*s\"",
1161115Sigor@sysoev.ru                   sa->length, nxt_sockaddr_start(sa));
116253Sigor@sysoev.ru 
1163115Sigor@sysoev.ru         skcf = nxt_router_socket_conf(task, mp, sa);
1164115Sigor@sysoev.ru         if (skcf == NULL) {
1165133Sigor@sysoev.ru             goto fail;
1166115Sigor@sysoev.ru         }
116753Sigor@sysoev.ru 
1168213Svbart@nginx.com         ret = nxt_conf_map_object(mp, listener, nxt_router_listener_conf,
1169136Svbart@nginx.com                                   nxt_nitems(nxt_router_listener_conf), &lscf);
1170115Sigor@sysoev.ru         if (ret != NXT_OK) {
1171115Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "listener map error");
1172133Sigor@sysoev.ru             goto fail;
1173115Sigor@sysoev.ru         }
117453Sigor@sysoev.ru 
1175133Sigor@sysoev.ru         nxt_debug(task, "application: %V", &lscf.application);
1176133Sigor@sysoev.ru 
1177133Sigor@sysoev.ru         // STUB, default values if http block is not defined.
1178133Sigor@sysoev.ru         skcf->header_buffer_size = 2048;
1179133Sigor@sysoev.ru         skcf->large_header_buffer_size = 8192;
1180206Smax.romanov@nginx.com         skcf->large_header_buffers = 4;
1181206Smax.romanov@nginx.com         skcf->body_buffer_size = 16 * 1024;
1182206Smax.romanov@nginx.com         skcf->max_body_size = 2 * 1024 * 1024;
1183133Sigor@sysoev.ru         skcf->header_read_timeout = 5000;
1184206Smax.romanov@nginx.com         skcf->body_read_timeout = 5000;
118553Sigor@sysoev.ru 
1186133Sigor@sysoev.ru         if (http != NULL) {
1187213Svbart@nginx.com             ret = nxt_conf_map_object(mp, http, nxt_router_http_conf,
1188136Svbart@nginx.com                                       nxt_nitems(nxt_router_http_conf), skcf);
1189133Sigor@sysoev.ru             if (ret != NXT_OK) {
1190133Sigor@sysoev.ru                 nxt_log(task, NXT_LOG_CRIT, "http map error");
1191133Sigor@sysoev.ru                 goto fail;
1192133Sigor@sysoev.ru             }
1193115Sigor@sysoev.ru         }
1194115Sigor@sysoev.ru 
1195115Sigor@sysoev.ru         skcf->listen.handler = nxt_router_conn_init;
1196115Sigor@sysoev.ru         skcf->router_conf = tmcf->conf;
1197160Sigor@sysoev.ru         skcf->router_conf->count++;
1198133Sigor@sysoev.ru         skcf->application = nxt_router_listener_application(tmcf,
1199133Sigor@sysoev.ru                                                             &lscf.application);
1200115Sigor@sysoev.ru 
1201115Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->pending, &skcf->link);
1202115Sigor@sysoev.ru     }
120353Sigor@sysoev.ru 
1204198Sigor@sysoev.ru     nxt_router_listen_sockets_sort(tmcf->conf->router, tmcf);
1205198Sigor@sysoev.ru 
120653Sigor@sysoev.ru     return NXT_OK;
1207133Sigor@sysoev.ru 
1208133Sigor@sysoev.ru app_fail:
1209133Sigor@sysoev.ru 
1210133Sigor@sysoev.ru     nxt_free(app);
1211133Sigor@sysoev.ru 
1212133Sigor@sysoev.ru fail:
1213133Sigor@sysoev.ru 
1214141Smax.romanov@nginx.com     nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) {
1215141Smax.romanov@nginx.com 
1216141Smax.romanov@nginx.com         nxt_queue_remove(&app->link);
1217133Sigor@sysoev.ru         nxt_thread_mutex_destroy(&app->mutex);
1218133Sigor@sysoev.ru         nxt_free(app);
1219141Smax.romanov@nginx.com 
1220141Smax.romanov@nginx.com     } nxt_queue_loop;
1221133Sigor@sysoev.ru 
1222133Sigor@sysoev.ru     return NXT_ERROR;
1223133Sigor@sysoev.ru }
1224133Sigor@sysoev.ru 
1225133Sigor@sysoev.ru 
1226133Sigor@sysoev.ru static nxt_app_t *
1227133Sigor@sysoev.ru nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name)
1228133Sigor@sysoev.ru {
1229141Smax.romanov@nginx.com     nxt_app_t  *app;
1230141Smax.romanov@nginx.com 
1231141Smax.romanov@nginx.com     nxt_queue_each(app, queue, nxt_app_t, link) {
1232133Sigor@sysoev.ru 
1233133Sigor@sysoev.ru         if (nxt_strstr_eq(name, &app->name)) {
1234133Sigor@sysoev.ru             return app;
1235133Sigor@sysoev.ru         }
1236141Smax.romanov@nginx.com 
1237141Smax.romanov@nginx.com     } nxt_queue_loop;
1238133Sigor@sysoev.ru 
1239133Sigor@sysoev.ru     return NULL;
1240133Sigor@sysoev.ru }
1241133Sigor@sysoev.ru 
1242133Sigor@sysoev.ru 
1243133Sigor@sysoev.ru static nxt_app_t *
1244133Sigor@sysoev.ru nxt_router_listener_application(nxt_router_temp_conf_t *tmcf, nxt_str_t *name)
1245133Sigor@sysoev.ru {
1246133Sigor@sysoev.ru     nxt_app_t  *app;
1247133Sigor@sysoev.ru 
1248133Sigor@sysoev.ru     app = nxt_router_app_find(&tmcf->apps, name);
1249133Sigor@sysoev.ru 
1250133Sigor@sysoev.ru     if (app == NULL) {
1251134Sigor@sysoev.ru         app = nxt_router_app_find(&tmcf->previous, name);
1252133Sigor@sysoev.ru     }
1253133Sigor@sysoev.ru 
1254133Sigor@sysoev.ru     return app;
125553Sigor@sysoev.ru }
125653Sigor@sysoev.ru 
125753Sigor@sysoev.ru 
125853Sigor@sysoev.ru static nxt_socket_conf_t *
125965Sigor@sysoev.ru nxt_router_socket_conf(nxt_task_t *task, nxt_mp_t *mp, nxt_sockaddr_t *sa)
126053Sigor@sysoev.ru {
1261163Smax.romanov@nginx.com     nxt_socket_conf_t  *skcf;
1262163Smax.romanov@nginx.com 
1263163Smax.romanov@nginx.com     skcf = nxt_mp_zget(mp, sizeof(nxt_socket_conf_t));
1264163Smax.romanov@nginx.com     if (nxt_slow_path(skcf == NULL)) {
126553Sigor@sysoev.ru         return NULL;
126653Sigor@sysoev.ru     }
126753Sigor@sysoev.ru 
1268163Smax.romanov@nginx.com     skcf->sockaddr = sa;
1269163Smax.romanov@nginx.com 
1270163Smax.romanov@nginx.com     skcf->listen.sockaddr = sa;
1271312Sigor@sysoev.ru 
1272312Sigor@sysoev.ru     nxt_listen_socket_remote_size(&skcf->listen, sa);
1273163Smax.romanov@nginx.com 
1274163Smax.romanov@nginx.com     skcf->listen.socket = -1;
1275163Smax.romanov@nginx.com     skcf->listen.backlog = NXT_LISTEN_BACKLOG;
1276163Smax.romanov@nginx.com     skcf->listen.flags = NXT_NONBLOCK;
1277163Smax.romanov@nginx.com     skcf->listen.read_after_accept = 1;
1278163Smax.romanov@nginx.com 
1279163Smax.romanov@nginx.com     return skcf;
128053Sigor@sysoev.ru }
128153Sigor@sysoev.ru 
128253Sigor@sysoev.ru 
128353Sigor@sysoev.ru static void
128453Sigor@sysoev.ru nxt_router_listen_sockets_sort(nxt_router_t *router,
128553Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf)
128653Sigor@sysoev.ru {
128753Sigor@sysoev.ru     nxt_queue_link_t   *nqlk, *oqlk, *next;
128853Sigor@sysoev.ru     nxt_socket_conf_t  *nskcf, *oskcf;
128953Sigor@sysoev.ru 
129053Sigor@sysoev.ru     for (nqlk = nxt_queue_first(&tmcf->pending);
129153Sigor@sysoev.ru          nqlk != nxt_queue_tail(&tmcf->pending);
129253Sigor@sysoev.ru          nqlk = next)
129353Sigor@sysoev.ru     {
129453Sigor@sysoev.ru         next = nxt_queue_next(nqlk);
129553Sigor@sysoev.ru         nskcf = nxt_queue_link_data(nqlk, nxt_socket_conf_t, link);
129653Sigor@sysoev.ru 
129753Sigor@sysoev.ru         for (oqlk = nxt_queue_first(&router->sockets);
129853Sigor@sysoev.ru              oqlk != nxt_queue_tail(&router->sockets);
129953Sigor@sysoev.ru              oqlk = nxt_queue_next(oqlk))
130053Sigor@sysoev.ru         {
130153Sigor@sysoev.ru             oskcf = nxt_queue_link_data(oqlk, nxt_socket_conf_t, link);
130253Sigor@sysoev.ru 
1303115Sigor@sysoev.ru             if (nxt_sockaddr_cmp(nskcf->sockaddr, oskcf->sockaddr)) {
1304115Sigor@sysoev.ru                 nskcf->socket = oskcf->socket;
1305115Sigor@sysoev.ru                 nskcf->listen.socket = oskcf->listen.socket;
1306115Sigor@sysoev.ru 
130753Sigor@sysoev.ru                 nxt_queue_remove(oqlk);
130853Sigor@sysoev.ru                 nxt_queue_insert_tail(&tmcf->keeping, oqlk);
130953Sigor@sysoev.ru 
131053Sigor@sysoev.ru                 nxt_queue_remove(nqlk);
131153Sigor@sysoev.ru                 nxt_queue_insert_tail(&tmcf->updating, nqlk);
131253Sigor@sysoev.ru 
131353Sigor@sysoev.ru                 break;
131453Sigor@sysoev.ru             }
131553Sigor@sysoev.ru         }
131653Sigor@sysoev.ru     }
131753Sigor@sysoev.ru 
131853Sigor@sysoev.ru     nxt_queue_add(&tmcf->deleting, &router->sockets);
1319115Sigor@sysoev.ru     nxt_queue_init(&router->sockets);
132053Sigor@sysoev.ru }
132153Sigor@sysoev.ru 
132253Sigor@sysoev.ru 
1323198Sigor@sysoev.ru static void
1324198Sigor@sysoev.ru nxt_router_listen_socket_rpc_create(nxt_task_t *task,
1325198Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf)
1326198Sigor@sysoev.ru {
1327198Sigor@sysoev.ru     uint32_t          stream;
1328198Sigor@sysoev.ru     nxt_buf_t         *b;
1329198Sigor@sysoev.ru     nxt_port_t        *main_port, *router_port;
1330198Sigor@sysoev.ru     nxt_runtime_t     *rt;
1331198Sigor@sysoev.ru     nxt_socket_rpc_t  *rpc;
1332198Sigor@sysoev.ru 
1333198Sigor@sysoev.ru     rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_socket_rpc_t));
1334198Sigor@sysoev.ru     if (rpc == NULL) {
1335198Sigor@sysoev.ru         goto fail;
1336198Sigor@sysoev.ru     }
1337198Sigor@sysoev.ru 
1338198Sigor@sysoev.ru     rpc->socket_conf = skcf;
1339198Sigor@sysoev.ru     rpc->temp_conf = tmcf;
1340198Sigor@sysoev.ru 
1341198Sigor@sysoev.ru     b = nxt_buf_mem_alloc(tmcf->mem_pool, skcf->sockaddr->sockaddr_size, 0);
1342198Sigor@sysoev.ru     if (b == NULL) {
1343198Sigor@sysoev.ru         goto fail;
1344198Sigor@sysoev.ru     }
1345198Sigor@sysoev.ru 
1346198Sigor@sysoev.ru     b->mem.free = nxt_cpymem(b->mem.free, skcf->sockaddr,
1347198Sigor@sysoev.ru                              skcf->sockaddr->sockaddr_size);
1348198Sigor@sysoev.ru 
1349198Sigor@sysoev.ru     rt = task->thread->runtime;
1350240Sigor@sysoev.ru     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
1351198Sigor@sysoev.ru     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
1352198Sigor@sysoev.ru 
1353198Sigor@sysoev.ru     stream = nxt_port_rpc_register_handler(task, router_port,
1354198Sigor@sysoev.ru                                            nxt_router_listen_socket_ready,
1355198Sigor@sysoev.ru                                            nxt_router_listen_socket_error,
1356198Sigor@sysoev.ru                                            main_port->pid, rpc);
1357198Sigor@sysoev.ru     if (stream == 0) {
1358198Sigor@sysoev.ru         goto fail;
1359198Sigor@sysoev.ru     }
1360198Sigor@sysoev.ru 
1361198Sigor@sysoev.ru     nxt_port_socket_write(task, main_port, NXT_PORT_MSG_SOCKET, -1,
1362198Sigor@sysoev.ru                           stream, router_port->id, b);
1363198Sigor@sysoev.ru 
1364198Sigor@sysoev.ru     return;
1365198Sigor@sysoev.ru 
1366198Sigor@sysoev.ru fail:
1367198Sigor@sysoev.ru 
1368198Sigor@sysoev.ru     nxt_router_conf_error(task, tmcf);
1369198Sigor@sysoev.ru }
1370198Sigor@sysoev.ru 
1371198Sigor@sysoev.ru 
1372198Sigor@sysoev.ru static void
1373198Sigor@sysoev.ru nxt_router_listen_socket_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
1374198Sigor@sysoev.ru     void *data)
137553Sigor@sysoev.ru {
1376115Sigor@sysoev.ru     nxt_int_t            ret;
1377115Sigor@sysoev.ru     nxt_socket_t         s;
1378198Sigor@sysoev.ru     nxt_socket_rpc_t     *rpc;
1379115Sigor@sysoev.ru     nxt_router_socket_t  *rtsk;
138053Sigor@sysoev.ru 
1381198Sigor@sysoev.ru     rpc = data;
1382198Sigor@sysoev.ru 
1383198Sigor@sysoev.ru     s = msg->fd;
1384198Sigor@sysoev.ru 
1385198Sigor@sysoev.ru     ret = nxt_socket_nonblocking(task, s);
1386198Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1387198Sigor@sysoev.ru         goto fail;
138853Sigor@sysoev.ru     }
138953Sigor@sysoev.ru 
1390229Sigor@sysoev.ru     nxt_socket_defer_accept(task, s, rpc->socket_conf->sockaddr);
1391198Sigor@sysoev.ru 
1392198Sigor@sysoev.ru     ret = nxt_listen_socket(task, s, NXT_LISTEN_BACKLOG);
1393198Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1394198Sigor@sysoev.ru         goto fail;
1395198Sigor@sysoev.ru     }
1396198Sigor@sysoev.ru 
1397198Sigor@sysoev.ru     rtsk = nxt_malloc(sizeof(nxt_router_socket_t));
1398198Sigor@sysoev.ru     if (nxt_slow_path(rtsk == NULL)) {
1399198Sigor@sysoev.ru         goto fail;
1400198Sigor@sysoev.ru     }
1401198Sigor@sysoev.ru 
1402198Sigor@sysoev.ru     rtsk->count = 0;
1403198Sigor@sysoev.ru     rtsk->fd = s;
1404198Sigor@sysoev.ru 
1405198Sigor@sysoev.ru     rpc->socket_conf->listen.socket = s;
1406198Sigor@sysoev.ru     rpc->socket_conf->socket = rtsk;
1407198Sigor@sysoev.ru 
1408198Sigor@sysoev.ru     nxt_work_queue_add(&task->thread->engine->fast_work_queue,
1409198Sigor@sysoev.ru                        nxt_router_conf_apply, task, rpc->temp_conf, NULL);
1410198Sigor@sysoev.ru 
1411198Sigor@sysoev.ru     return;
1412148Sigor@sysoev.ru 
1413148Sigor@sysoev.ru fail:
1414148Sigor@sysoev.ru 
1415148Sigor@sysoev.ru     nxt_socket_close(task, s);
1416148Sigor@sysoev.ru 
1417198Sigor@sysoev.ru     nxt_router_conf_error(task, rpc->temp_conf);
1418198Sigor@sysoev.ru }
1419198Sigor@sysoev.ru 
1420198Sigor@sysoev.ru 
1421198Sigor@sysoev.ru static void
1422198Sigor@sysoev.ru nxt_router_listen_socket_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
1423198Sigor@sysoev.ru     void *data)
1424198Sigor@sysoev.ru {
1425198Sigor@sysoev.ru     u_char                  *p;
1426198Sigor@sysoev.ru     size_t                  size;
1427198Sigor@sysoev.ru     uint8_t                 error;
1428198Sigor@sysoev.ru     nxt_buf_t               *in, *out;
1429198Sigor@sysoev.ru     nxt_sockaddr_t          *sa;
1430198Sigor@sysoev.ru     nxt_socket_rpc_t        *rpc;
1431198Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
1432198Sigor@sysoev.ru 
1433198Sigor@sysoev.ru     static nxt_str_t  socket_errors[] = {
1434198Sigor@sysoev.ru         nxt_string("ListenerSystem"),
1435198Sigor@sysoev.ru         nxt_string("ListenerNoIPv6"),
1436198Sigor@sysoev.ru         nxt_string("ListenerPort"),
1437198Sigor@sysoev.ru         nxt_string("ListenerInUse"),
1438198Sigor@sysoev.ru         nxt_string("ListenerNoAddress"),
1439198Sigor@sysoev.ru         nxt_string("ListenerNoAccess"),
1440198Sigor@sysoev.ru         nxt_string("ListenerPath"),
1441198Sigor@sysoev.ru     };
1442198Sigor@sysoev.ru 
1443198Sigor@sysoev.ru     rpc = data;
1444198Sigor@sysoev.ru     sa = rpc->socket_conf->sockaddr;
1445198Sigor@sysoev.ru 
1446198Sigor@sysoev.ru     in = msg->buf;
1447198Sigor@sysoev.ru     p = in->mem.pos;
1448198Sigor@sysoev.ru 
1449198Sigor@sysoev.ru     error = *p++;
1450198Sigor@sysoev.ru 
1451198Sigor@sysoev.ru     size = sizeof("listen socket error: ") - 1
1452198Sigor@sysoev.ru            + sizeof("{listener: \"\", code:\"\", message: \"\"}") - 1
1453198Sigor@sysoev.ru            + sa->length + socket_errors[error].length + (in->mem.free - p);
1454198Sigor@sysoev.ru 
1455198Sigor@sysoev.ru     tmcf = rpc->temp_conf;
1456198Sigor@sysoev.ru 
1457198Sigor@sysoev.ru     out = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0);
1458198Sigor@sysoev.ru     if (nxt_slow_path(out == NULL)) {
1459198Sigor@sysoev.ru         return;
1460198Sigor@sysoev.ru     }
1461198Sigor@sysoev.ru 
1462198Sigor@sysoev.ru     out->mem.free = nxt_sprintf(out->mem.free, out->mem.end,
1463198Sigor@sysoev.ru                         "listen socket error: "
1464198Sigor@sysoev.ru                         "{listener: \"%*s\", code:\"%V\", message: \"%*s\"}",
1465198Sigor@sysoev.ru                         sa->length, nxt_sockaddr_start(sa),
1466198Sigor@sysoev.ru                         &socket_errors[error], in->mem.free - p, p);
1467198Sigor@sysoev.ru 
1468198Sigor@sysoev.ru     nxt_debug(task, "%*s", out->mem.free - out->mem.pos, out->mem.pos);
1469198Sigor@sysoev.ru 
1470198Sigor@sysoev.ru     nxt_router_conf_error(task, tmcf);
147153Sigor@sysoev.ru }
147253Sigor@sysoev.ru 
147353Sigor@sysoev.ru 
147453Sigor@sysoev.ru static nxt_int_t
147553Sigor@sysoev.ru nxt_router_engines_create(nxt_task_t *task, nxt_router_t *router,
147653Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, const nxt_event_interface_t *interface)
147753Sigor@sysoev.ru {
147853Sigor@sysoev.ru     nxt_int_t                 ret;
147953Sigor@sysoev.ru     nxt_uint_t                n, threads;
148053Sigor@sysoev.ru     nxt_queue_link_t          *qlk;
148153Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
148253Sigor@sysoev.ru 
148353Sigor@sysoev.ru     threads = tmcf->conf->threads;
148453Sigor@sysoev.ru 
148553Sigor@sysoev.ru     tmcf->engines = nxt_array_create(tmcf->mem_pool, threads,
148653Sigor@sysoev.ru                                      sizeof(nxt_router_engine_conf_t));
148753Sigor@sysoev.ru     if (nxt_slow_path(tmcf->engines == NULL)) {
148853Sigor@sysoev.ru         return NXT_ERROR;
148953Sigor@sysoev.ru     }
149053Sigor@sysoev.ru 
149153Sigor@sysoev.ru     n = 0;
149253Sigor@sysoev.ru 
149353Sigor@sysoev.ru     for (qlk = nxt_queue_first(&router->engines);
149453Sigor@sysoev.ru          qlk != nxt_queue_tail(&router->engines);
149553Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
149653Sigor@sysoev.ru     {
149753Sigor@sysoev.ru         recf = nxt_array_zero_add(tmcf->engines);
149853Sigor@sysoev.ru         if (nxt_slow_path(recf == NULL)) {
149953Sigor@sysoev.ru             return NXT_ERROR;
150053Sigor@sysoev.ru         }
150153Sigor@sysoev.ru 
1502115Sigor@sysoev.ru         recf->engine = nxt_queue_link_data(qlk, nxt_event_engine_t, link0);
150353Sigor@sysoev.ru 
150453Sigor@sysoev.ru         if (n < threads) {
1505315Sigor@sysoev.ru             recf->action = NXT_ROUTER_ENGINE_KEEP;
1506115Sigor@sysoev.ru             ret = nxt_router_engine_conf_update(tmcf, recf);
150753Sigor@sysoev.ru 
150853Sigor@sysoev.ru         } else {
1509315Sigor@sysoev.ru             recf->action = NXT_ROUTER_ENGINE_DELETE;
1510115Sigor@sysoev.ru             ret = nxt_router_engine_conf_delete(tmcf, recf);
151153Sigor@sysoev.ru         }
151253Sigor@sysoev.ru 
151353Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
151453Sigor@sysoev.ru             return ret;
151553Sigor@sysoev.ru         }
151653Sigor@sysoev.ru 
151753Sigor@sysoev.ru         n++;
151853Sigor@sysoev.ru     }
151953Sigor@sysoev.ru 
152053Sigor@sysoev.ru     tmcf->new_threads = n;
152153Sigor@sysoev.ru 
152253Sigor@sysoev.ru     while (n < threads) {
152353Sigor@sysoev.ru         recf = nxt_array_zero_add(tmcf->engines);
152453Sigor@sysoev.ru         if (nxt_slow_path(recf == NULL)) {
152553Sigor@sysoev.ru             return NXT_ERROR;
152653Sigor@sysoev.ru         }
152753Sigor@sysoev.ru 
1528315Sigor@sysoev.ru         recf->action = NXT_ROUTER_ENGINE_ADD;
1529315Sigor@sysoev.ru 
153053Sigor@sysoev.ru         recf->engine = nxt_event_engine_create(task, interface, NULL, 0, 0);
153153Sigor@sysoev.ru         if (nxt_slow_path(recf->engine == NULL)) {
153253Sigor@sysoev.ru             return NXT_ERROR;
153353Sigor@sysoev.ru         }
153453Sigor@sysoev.ru 
1535115Sigor@sysoev.ru         ret = nxt_router_engine_conf_create(tmcf, recf);
153653Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
153753Sigor@sysoev.ru             return ret;
153853Sigor@sysoev.ru         }
153953Sigor@sysoev.ru 
154053Sigor@sysoev.ru         n++;
154153Sigor@sysoev.ru     }
154253Sigor@sysoev.ru 
154353Sigor@sysoev.ru     return NXT_OK;
154453Sigor@sysoev.ru }
154553Sigor@sysoev.ru 
154653Sigor@sysoev.ru 
154753Sigor@sysoev.ru static nxt_int_t
1548115Sigor@sysoev.ru nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf,
1549115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
155053Sigor@sysoev.ru {
1551115Sigor@sysoev.ru     nxt_int_t              ret;
1552115Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
155353Sigor@sysoev.ru 
1554154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating,
1555154Sigor@sysoev.ru                                           nxt_router_listen_socket_create);
1556115Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1557115Sigor@sysoev.ru         return ret;
1558115Sigor@sysoev.ru     }
1559115Sigor@sysoev.ru 
1560154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating,
1561154Sigor@sysoev.ru                                           nxt_router_listen_socket_create);
156253Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
156353Sigor@sysoev.ru         return ret;
156453Sigor@sysoev.ru     }
156553Sigor@sysoev.ru 
1566115Sigor@sysoev.ru     lock = &tmcf->conf->router->lock;
1567115Sigor@sysoev.ru 
1568115Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
1569115Sigor@sysoev.ru 
1570115Sigor@sysoev.ru     nxt_router_engine_socket_count(&tmcf->creating);
1571115Sigor@sysoev.ru     nxt_router_engine_socket_count(&tmcf->updating);
1572115Sigor@sysoev.ru 
1573115Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
1574115Sigor@sysoev.ru 
1575115Sigor@sysoev.ru     return ret;
157653Sigor@sysoev.ru }
157753Sigor@sysoev.ru 
157853Sigor@sysoev.ru 
157953Sigor@sysoev.ru static nxt_int_t
1580115Sigor@sysoev.ru nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf,
1581115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
158253Sigor@sysoev.ru {
1583115Sigor@sysoev.ru     nxt_int_t              ret;
1584115Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
158553Sigor@sysoev.ru 
1586154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating,
1587154Sigor@sysoev.ru                                           nxt_router_listen_socket_create);
158853Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
158953Sigor@sysoev.ru         return ret;
159053Sigor@sysoev.ru     }
159153Sigor@sysoev.ru 
1592154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating,
1593154Sigor@sysoev.ru                                           nxt_router_listen_socket_update);
159453Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
159553Sigor@sysoev.ru         return ret;
159653Sigor@sysoev.ru     }
159753Sigor@sysoev.ru 
1598139Sigor@sysoev.ru     ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting);
1599115Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1600115Sigor@sysoev.ru         return ret;
1601115Sigor@sysoev.ru     }
1602115Sigor@sysoev.ru 
1603115Sigor@sysoev.ru     lock = &tmcf->conf->router->lock;
1604115Sigor@sysoev.ru 
1605115Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
1606115Sigor@sysoev.ru 
1607115Sigor@sysoev.ru     nxt_router_engine_socket_count(&tmcf->creating);
1608115Sigor@sysoev.ru 
1609115Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
1610115Sigor@sysoev.ru 
1611115Sigor@sysoev.ru     return ret;
161253Sigor@sysoev.ru }
161353Sigor@sysoev.ru 
161453Sigor@sysoev.ru 
161553Sigor@sysoev.ru static nxt_int_t
1616115Sigor@sysoev.ru nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf,
1617115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
161853Sigor@sysoev.ru {
161953Sigor@sysoev.ru     nxt_int_t  ret;
162053Sigor@sysoev.ru 
1621313Sigor@sysoev.ru     ret = nxt_router_engine_quit(tmcf, recf);
1622313Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1623313Sigor@sysoev.ru         return ret;
1624313Sigor@sysoev.ru     }
1625313Sigor@sysoev.ru 
1626139Sigor@sysoev.ru     ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->updating);
162753Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
162853Sigor@sysoev.ru         return ret;
162953Sigor@sysoev.ru     }
163053Sigor@sysoev.ru 
1631139Sigor@sysoev.ru     return nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting);
163253Sigor@sysoev.ru }
163353Sigor@sysoev.ru 
163453Sigor@sysoev.ru 
163553Sigor@sysoev.ru static nxt_int_t
1636154Sigor@sysoev.ru nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf,
1637154Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets,
163853Sigor@sysoev.ru     nxt_work_handler_t handler)
163953Sigor@sysoev.ru {
1640153Sigor@sysoev.ru     nxt_joint_job_t          *job;
164153Sigor@sysoev.ru     nxt_queue_link_t         *qlk;
1642155Sigor@sysoev.ru     nxt_socket_conf_t        *skcf;
164353Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
164453Sigor@sysoev.ru 
164553Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
164653Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
164753Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
164853Sigor@sysoev.ru     {
1649154Sigor@sysoev.ru         job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t));
1650153Sigor@sysoev.ru         if (nxt_slow_path(job == NULL)) {
1651139Sigor@sysoev.ru             return NXT_ERROR;
1652139Sigor@sysoev.ru         }
1653139Sigor@sysoev.ru 
1654154Sigor@sysoev.ru         job->work.next = recf->jobs;
1655154Sigor@sysoev.ru         recf->jobs = &job->work;
1656154Sigor@sysoev.ru 
1657153Sigor@sysoev.ru         job->task = tmcf->engine->task;
1658153Sigor@sysoev.ru         job->work.handler = handler;
1659153Sigor@sysoev.ru         job->work.task = &job->task;
1660153Sigor@sysoev.ru         job->work.obj = job;
1661153Sigor@sysoev.ru         job->tmcf = tmcf;
166253Sigor@sysoev.ru 
1663154Sigor@sysoev.ru         tmcf->count++;
1664154Sigor@sysoev.ru 
1665154Sigor@sysoev.ru         joint = nxt_mp_alloc(tmcf->conf->mem_pool,
1666154Sigor@sysoev.ru                              sizeof(nxt_socket_conf_joint_t));
166753Sigor@sysoev.ru         if (nxt_slow_path(joint == NULL)) {
166853Sigor@sysoev.ru             return NXT_ERROR;
166953Sigor@sysoev.ru         }
167053Sigor@sysoev.ru 
1671153Sigor@sysoev.ru         job->work.data = joint;
167253Sigor@sysoev.ru 
167353Sigor@sysoev.ru         joint->count = 1;
1674155Sigor@sysoev.ru 
1675155Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
1676155Sigor@sysoev.ru         skcf->count++;
1677155Sigor@sysoev.ru         joint->socket_conf = skcf;
1678155Sigor@sysoev.ru 
167988Smax.romanov@nginx.com         joint->engine = recf->engine;
168053Sigor@sysoev.ru     }
168153Sigor@sysoev.ru 
168220Sigor@sysoev.ru     return NXT_OK;
168320Sigor@sysoev.ru }
168420Sigor@sysoev.ru 
168520Sigor@sysoev.ru 
1686115Sigor@sysoev.ru static void
1687115Sigor@sysoev.ru nxt_router_engine_socket_count(nxt_queue_t *sockets)
1688115Sigor@sysoev.ru {
1689115Sigor@sysoev.ru     nxt_queue_link_t   *qlk;
1690115Sigor@sysoev.ru     nxt_socket_conf_t  *skcf;
1691115Sigor@sysoev.ru 
1692115Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
1693115Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
1694115Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
1695115Sigor@sysoev.ru     {
1696115Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
1697115Sigor@sysoev.ru         skcf->socket->count++;
1698115Sigor@sysoev.ru     }
1699115Sigor@sysoev.ru }
1700115Sigor@sysoev.ru 
1701115Sigor@sysoev.ru 
170220Sigor@sysoev.ru static nxt_int_t
1703313Sigor@sysoev.ru nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf,
1704313Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
1705313Sigor@sysoev.ru {
1706313Sigor@sysoev.ru     nxt_joint_job_t  *job;
1707313Sigor@sysoev.ru 
1708313Sigor@sysoev.ru     job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t));
1709313Sigor@sysoev.ru     if (nxt_slow_path(job == NULL)) {
1710313Sigor@sysoev.ru         return NXT_ERROR;
1711313Sigor@sysoev.ru     }
1712313Sigor@sysoev.ru 
1713313Sigor@sysoev.ru     job->work.next = recf->jobs;
1714313Sigor@sysoev.ru     recf->jobs = &job->work;
1715313Sigor@sysoev.ru 
1716313Sigor@sysoev.ru     job->task = tmcf->engine->task;
1717313Sigor@sysoev.ru     job->work.handler = nxt_router_worker_thread_quit;
1718313Sigor@sysoev.ru     job->work.task = &job->task;
1719313Sigor@sysoev.ru     job->work.obj = NULL;
1720313Sigor@sysoev.ru     job->work.data = NULL;
1721313Sigor@sysoev.ru     job->tmcf = NULL;
1722313Sigor@sysoev.ru 
1723313Sigor@sysoev.ru     return NXT_OK;
1724313Sigor@sysoev.ru }
1725313Sigor@sysoev.ru 
1726313Sigor@sysoev.ru 
1727313Sigor@sysoev.ru static nxt_int_t
1728139Sigor@sysoev.ru nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf,
1729139Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets)
173020Sigor@sysoev.ru {
1731153Sigor@sysoev.ru     nxt_joint_job_t   *job;
173253Sigor@sysoev.ru     nxt_queue_link_t  *qlk;
173320Sigor@sysoev.ru 
173453Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
173553Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
173653Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
173753Sigor@sysoev.ru     {
1738154Sigor@sysoev.ru         job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t));
1739153Sigor@sysoev.ru         if (nxt_slow_path(job == NULL)) {
1740139Sigor@sysoev.ru             return NXT_ERROR;
1741139Sigor@sysoev.ru         }
1742139Sigor@sysoev.ru 
1743154Sigor@sysoev.ru         job->work.next = recf->jobs;
1744154Sigor@sysoev.ru         recf->jobs = &job->work;
1745154Sigor@sysoev.ru 
1746153Sigor@sysoev.ru         job->task = tmcf->engine->task;
1747153Sigor@sysoev.ru         job->work.handler = nxt_router_listen_socket_delete;
1748153Sigor@sysoev.ru         job->work.task = &job->task;
1749153Sigor@sysoev.ru         job->work.obj = job;
1750153Sigor@sysoev.ru         job->work.data = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
1751153Sigor@sysoev.ru         job->tmcf = tmcf;
1752154Sigor@sysoev.ru 
1753154Sigor@sysoev.ru         tmcf->count++;
175420Sigor@sysoev.ru     }
175520Sigor@sysoev.ru 
175653Sigor@sysoev.ru     return NXT_OK;
175753Sigor@sysoev.ru }
175820Sigor@sysoev.ru 
175920Sigor@sysoev.ru 
176053Sigor@sysoev.ru static nxt_int_t
176153Sigor@sysoev.ru nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt,
176253Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf)
176353Sigor@sysoev.ru {
176453Sigor@sysoev.ru     nxt_int_t                 ret;
176553Sigor@sysoev.ru     nxt_uint_t                i, threads;
176653Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
176720Sigor@sysoev.ru 
176853Sigor@sysoev.ru     recf = tmcf->engines->elts;
176953Sigor@sysoev.ru     threads = tmcf->conf->threads;
177020Sigor@sysoev.ru 
177153Sigor@sysoev.ru     for (i = tmcf->new_threads; i < threads; i++) {
177253Sigor@sysoev.ru         ret = nxt_router_thread_create(task, rt, recf[i].engine);
177353Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
177453Sigor@sysoev.ru             return ret;
177553Sigor@sysoev.ru         }
177620Sigor@sysoev.ru     }
177720Sigor@sysoev.ru 
177820Sigor@sysoev.ru     return NXT_OK;
177920Sigor@sysoev.ru }
178053Sigor@sysoev.ru 
178153Sigor@sysoev.ru 
178253Sigor@sysoev.ru static nxt_int_t
178353Sigor@sysoev.ru nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt,
178453Sigor@sysoev.ru     nxt_event_engine_t *engine)
178553Sigor@sysoev.ru {
178653Sigor@sysoev.ru     nxt_int_t            ret;
178753Sigor@sysoev.ru     nxt_thread_link_t    *link;
178853Sigor@sysoev.ru     nxt_thread_handle_t  handle;
178953Sigor@sysoev.ru 
179053Sigor@sysoev.ru     link = nxt_zalloc(sizeof(nxt_thread_link_t));
179153Sigor@sysoev.ru 
179253Sigor@sysoev.ru     if (nxt_slow_path(link == NULL)) {
179353Sigor@sysoev.ru         return NXT_ERROR;
179453Sigor@sysoev.ru     }
179553Sigor@sysoev.ru 
179653Sigor@sysoev.ru     link->start = nxt_router_thread_start;
179753Sigor@sysoev.ru     link->engine = engine;
179853Sigor@sysoev.ru     link->work.handler = nxt_router_thread_exit_handler;
179953Sigor@sysoev.ru     link->work.task = task;
180053Sigor@sysoev.ru     link->work.data = link;
180153Sigor@sysoev.ru 
180253Sigor@sysoev.ru     nxt_queue_insert_tail(&rt->engines, &engine->link);
180353Sigor@sysoev.ru 
180453Sigor@sysoev.ru     ret = nxt_thread_create(&handle, link);
180553Sigor@sysoev.ru 
180653Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
180753Sigor@sysoev.ru         nxt_queue_remove(&engine->link);
180853Sigor@sysoev.ru     }
180953Sigor@sysoev.ru 
181053Sigor@sysoev.ru     return ret;
181153Sigor@sysoev.ru }
181253Sigor@sysoev.ru 
181353Sigor@sysoev.ru 
181453Sigor@sysoev.ru static void
1815343Smax.romanov@nginx.com nxt_router_apps_sort(nxt_task_t *task, nxt_router_t *router,
1816343Smax.romanov@nginx.com     nxt_router_temp_conf_t *tmcf)
1817133Sigor@sysoev.ru {
1818343Smax.romanov@nginx.com     nxt_app_t   *app;
1819343Smax.romanov@nginx.com     nxt_port_t  *port;
1820141Smax.romanov@nginx.com 
1821141Smax.romanov@nginx.com     nxt_queue_each(app, &router->apps, nxt_app_t, link) {
1822133Sigor@sysoev.ru 
1823133Sigor@sysoev.ru         nxt_queue_remove(&app->link);
1824133Sigor@sysoev.ru 
1825343Smax.romanov@nginx.com         nxt_debug(task, "about to free app '%V' %p", &app->name, app);
1826167Smax.romanov@nginx.com 
1827163Smax.romanov@nginx.com         app->live = 0;
1828163Smax.romanov@nginx.com 
1829167Smax.romanov@nginx.com         do {
1830343Smax.romanov@nginx.com             port = nxt_router_app_get_idle_port(app);
1831167Smax.romanov@nginx.com             if (port == NULL) {
1832167Smax.romanov@nginx.com                 break;
1833167Smax.romanov@nginx.com             }
1834167Smax.romanov@nginx.com 
1835343Smax.romanov@nginx.com             nxt_debug(task, "port %p send quit", port);
1836343Smax.romanov@nginx.com 
1837343Smax.romanov@nginx.com             nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0,
1838343Smax.romanov@nginx.com                                   NULL);
1839343Smax.romanov@nginx.com 
1840343Smax.romanov@nginx.com             nxt_port_use(task, port, -1);
1841167Smax.romanov@nginx.com         } while (1);
1842167Smax.romanov@nginx.com 
1843343Smax.romanov@nginx.com         nxt_router_app_use(task, app, -1);
1844343Smax.romanov@nginx.com 
1845141Smax.romanov@nginx.com     } nxt_queue_loop;
1846133Sigor@sysoev.ru 
1847133Sigor@sysoev.ru     nxt_queue_add(&router->apps, &tmcf->previous);
1848133Sigor@sysoev.ru     nxt_queue_add(&router->apps, &tmcf->apps);
1849133Sigor@sysoev.ru }
1850133Sigor@sysoev.ru 
1851133Sigor@sysoev.ru 
1852133Sigor@sysoev.ru static void
1853315Sigor@sysoev.ru nxt_router_engines_post(nxt_router_t *router, nxt_router_temp_conf_t *tmcf)
185453Sigor@sysoev.ru {
185553Sigor@sysoev.ru     nxt_uint_t                n;
1856315Sigor@sysoev.ru     nxt_event_engine_t        *engine;
185753Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
185853Sigor@sysoev.ru 
185953Sigor@sysoev.ru     recf = tmcf->engines->elts;
186053Sigor@sysoev.ru 
186153Sigor@sysoev.ru     for (n = tmcf->engines->nelts; n != 0; n--) {
1862315Sigor@sysoev.ru         engine = recf->engine;
1863315Sigor@sysoev.ru 
1864315Sigor@sysoev.ru         switch (recf->action) {
1865315Sigor@sysoev.ru 
1866315Sigor@sysoev.ru         case NXT_ROUTER_ENGINE_KEEP:
1867315Sigor@sysoev.ru             break;
1868315Sigor@sysoev.ru 
1869315Sigor@sysoev.ru         case NXT_ROUTER_ENGINE_ADD:
1870315Sigor@sysoev.ru             nxt_queue_insert_tail(&router->engines, &engine->link0);
1871315Sigor@sysoev.ru             break;
1872315Sigor@sysoev.ru 
1873315Sigor@sysoev.ru         case NXT_ROUTER_ENGINE_DELETE:
1874315Sigor@sysoev.ru             nxt_queue_remove(&engine->link0);
1875315Sigor@sysoev.ru             break;
1876315Sigor@sysoev.ru         }
1877315Sigor@sysoev.ru 
1878316Sigor@sysoev.ru         nxt_router_engine_post(engine, recf->jobs);
1879316Sigor@sysoev.ru 
188053Sigor@sysoev.ru         recf++;
188153Sigor@sysoev.ru     }
188253Sigor@sysoev.ru }
188353Sigor@sysoev.ru 
188453Sigor@sysoev.ru 
188553Sigor@sysoev.ru static void
1886315Sigor@sysoev.ru nxt_router_engine_post(nxt_event_engine_t *engine, nxt_work_t *jobs)
188753Sigor@sysoev.ru {
1888154Sigor@sysoev.ru     nxt_work_t  *work, *next;
1889154Sigor@sysoev.ru 
1890315Sigor@sysoev.ru     for (work = jobs; work != NULL; work = next) {
1891154Sigor@sysoev.ru         next = work->next;
1892154Sigor@sysoev.ru         work->next = NULL;
1893154Sigor@sysoev.ru 
1894315Sigor@sysoev.ru         nxt_event_engine_post(engine, work);
189553Sigor@sysoev.ru     }
189653Sigor@sysoev.ru }
189753Sigor@sysoev.ru 
189853Sigor@sysoev.ru 
1899320Smax.romanov@nginx.com static nxt_port_handlers_t  nxt_router_app_port_handlers = {
1900320Smax.romanov@nginx.com     .mmap = nxt_port_mmap_handler,
1901320Smax.romanov@nginx.com     .data = nxt_port_rpc_handler,
190288Smax.romanov@nginx.com };
190388Smax.romanov@nginx.com 
190488Smax.romanov@nginx.com 
190588Smax.romanov@nginx.com static void
190653Sigor@sysoev.ru nxt_router_thread_start(void *data)
190753Sigor@sysoev.ru {
1908141Smax.romanov@nginx.com     nxt_int_t           ret;
1909141Smax.romanov@nginx.com     nxt_port_t          *port;
191088Smax.romanov@nginx.com     nxt_task_t          *task;
191153Sigor@sysoev.ru     nxt_thread_t        *thread;
191253Sigor@sysoev.ru     nxt_thread_link_t   *link;
191353Sigor@sysoev.ru     nxt_event_engine_t  *engine;
191453Sigor@sysoev.ru 
191553Sigor@sysoev.ru     link = data;
191653Sigor@sysoev.ru     engine = link->engine;
191788Smax.romanov@nginx.com     task = &engine->task;
191853Sigor@sysoev.ru 
191953Sigor@sysoev.ru     thread = nxt_thread();
192053Sigor@sysoev.ru 
1921165Smax.romanov@nginx.com     nxt_event_engine_thread_adopt(engine);
1922165Smax.romanov@nginx.com 
192353Sigor@sysoev.ru     /* STUB */
192453Sigor@sysoev.ru     thread->runtime = engine->task.thread->runtime;
192553Sigor@sysoev.ru 
192653Sigor@sysoev.ru     engine->task.thread = thread;
192753Sigor@sysoev.ru     engine->task.log = thread->log;
192853Sigor@sysoev.ru     thread->engine = engine;
192963Sigor@sysoev.ru     thread->task = &engine->task;
1930326Svbart@nginx.com #if 0
193153Sigor@sysoev.ru     thread->fiber = &engine->fibers->fiber;
1932326Svbart@nginx.com #endif
193353Sigor@sysoev.ru 
193463Sigor@sysoev.ru     engine->mem_pool = nxt_mp_create(4096, 128, 1024, 64);
1935337Sigor@sysoev.ru     if (nxt_slow_path(engine->mem_pool == NULL)) {
1936337Sigor@sysoev.ru         return;
1937337Sigor@sysoev.ru     }
193853Sigor@sysoev.ru 
1939197Smax.romanov@nginx.com     port = nxt_port_new(task, nxt_port_get_next_id(), nxt_pid,
1940197Smax.romanov@nginx.com                         NXT_PROCESS_ROUTER);
1941141Smax.romanov@nginx.com     if (nxt_slow_path(port == NULL)) {
1942141Smax.romanov@nginx.com         return;
1943141Smax.romanov@nginx.com     }
1944141Smax.romanov@nginx.com 
1945141Smax.romanov@nginx.com     ret = nxt_port_socket_init(task, port, 0);
1946141Smax.romanov@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
1947343Smax.romanov@nginx.com         nxt_port_use(task, port, -1);
1948141Smax.romanov@nginx.com         return;
1949141Smax.romanov@nginx.com     }
1950141Smax.romanov@nginx.com 
1951141Smax.romanov@nginx.com     engine->port = port;
1952141Smax.romanov@nginx.com 
1953320Smax.romanov@nginx.com     nxt_port_enable(task, port, &nxt_router_app_port_handlers);
1954141Smax.romanov@nginx.com 
195553Sigor@sysoev.ru     nxt_event_engine_start(engine);
195653Sigor@sysoev.ru }
195753Sigor@sysoev.ru 
195853Sigor@sysoev.ru 
195953Sigor@sysoev.ru static void
196053Sigor@sysoev.ru nxt_router_listen_socket_create(nxt_task_t *task, void *obj, void *data)
196153Sigor@sysoev.ru {
1962153Sigor@sysoev.ru     nxt_joint_job_t          *job;
196353Sigor@sysoev.ru     nxt_listen_event_t       *listen;
196453Sigor@sysoev.ru     nxt_listen_socket_t      *ls;
196553Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
196653Sigor@sysoev.ru 
1967153Sigor@sysoev.ru     job = obj;
196853Sigor@sysoev.ru     joint = data;
196953Sigor@sysoev.ru 
197053Sigor@sysoev.ru     ls = &joint->socket_conf->listen;
197153Sigor@sysoev.ru 
1972159Sigor@sysoev.ru     nxt_queue_insert_tail(&task->thread->engine->joints, &joint->link);
1973159Sigor@sysoev.ru 
197453Sigor@sysoev.ru     listen = nxt_listen_event(task, ls);
197553Sigor@sysoev.ru     if (nxt_slow_path(listen == NULL)) {
197653Sigor@sysoev.ru         nxt_router_listen_socket_release(task, joint);
197753Sigor@sysoev.ru         return;
197853Sigor@sysoev.ru     }
197953Sigor@sysoev.ru 
198053Sigor@sysoev.ru     listen->socket.data = joint;
1981139Sigor@sysoev.ru 
1982153Sigor@sysoev.ru     job->work.next = NULL;
1983153Sigor@sysoev.ru     job->work.handler = nxt_router_conf_wait;
1984153Sigor@sysoev.ru 
1985153Sigor@sysoev.ru     nxt_event_engine_post(job->tmcf->engine, &job->work);
198653Sigor@sysoev.ru }
198753Sigor@sysoev.ru 
198853Sigor@sysoev.ru 
198953Sigor@sysoev.ru nxt_inline nxt_listen_event_t *
199053Sigor@sysoev.ru nxt_router_listen_event(nxt_queue_t *listen_connections,
199153Sigor@sysoev.ru     nxt_socket_conf_t *skcf)
199253Sigor@sysoev.ru {
1993115Sigor@sysoev.ru     nxt_socket_t        fd;
1994115Sigor@sysoev.ru     nxt_queue_link_t    *qlk;
199553Sigor@sysoev.ru     nxt_listen_event_t  *listen;
199653Sigor@sysoev.ru 
1997115Sigor@sysoev.ru     fd = skcf->socket->fd;
199853Sigor@sysoev.ru 
1999115Sigor@sysoev.ru     for (qlk = nxt_queue_first(listen_connections);
2000115Sigor@sysoev.ru          qlk != nxt_queue_tail(listen_connections);
2001115Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
200253Sigor@sysoev.ru     {
2003115Sigor@sysoev.ru         listen = nxt_queue_link_data(qlk, nxt_listen_event_t, link);
200453Sigor@sysoev.ru 
2005115Sigor@sysoev.ru         if (fd == listen->socket.fd) {
200653Sigor@sysoev.ru             return listen;
200753Sigor@sysoev.ru         }
200853Sigor@sysoev.ru     }
200953Sigor@sysoev.ru 
201053Sigor@sysoev.ru     return NULL;
201153Sigor@sysoev.ru }
201253Sigor@sysoev.ru 
201353Sigor@sysoev.ru 
201453Sigor@sysoev.ru static void
201553Sigor@sysoev.ru nxt_router_listen_socket_update(nxt_task_t *task, void *obj, void *data)
201653Sigor@sysoev.ru {
2017153Sigor@sysoev.ru     nxt_joint_job_t          *job;
201853Sigor@sysoev.ru     nxt_event_engine_t       *engine;
201953Sigor@sysoev.ru     nxt_listen_event_t       *listen;
202053Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint, *old;
202153Sigor@sysoev.ru 
2022153Sigor@sysoev.ru     job = obj;
202353Sigor@sysoev.ru     joint = data;
202453Sigor@sysoev.ru 
2025139Sigor@sysoev.ru     engine = task->thread->engine;
2026139Sigor@sysoev.ru 
2027159Sigor@sysoev.ru     nxt_queue_insert_tail(&engine->joints, &joint->link);
2028159Sigor@sysoev.ru 
202953Sigor@sysoev.ru     listen = nxt_router_listen_event(&engine->listen_connections,
203053Sigor@sysoev.ru                                      joint->socket_conf);
203153Sigor@sysoev.ru 
203253Sigor@sysoev.ru     old = listen->socket.data;
203353Sigor@sysoev.ru     listen->socket.data = joint;
2034177Sigor@sysoev.ru     listen->listen = &joint->socket_conf->listen;
203553Sigor@sysoev.ru 
2036153Sigor@sysoev.ru     job->work.next = NULL;
2037153Sigor@sysoev.ru     job->work.handler = nxt_router_conf_wait;
2038153Sigor@sysoev.ru 
2039153Sigor@sysoev.ru     nxt_event_engine_post(job->tmcf->engine, &job->work);
2040139Sigor@sysoev.ru 
2041181Smax.romanov@nginx.com     /*
2042181Smax.romanov@nginx.com      * The task is allocated from configuration temporary
2043181Smax.romanov@nginx.com      * memory pool so it can be freed after engine post operation.
2044181Smax.romanov@nginx.com      */
2045181Smax.romanov@nginx.com 
2046181Smax.romanov@nginx.com     nxt_router_conf_release(&engine->task, old);
204753Sigor@sysoev.ru }
204853Sigor@sysoev.ru 
204953Sigor@sysoev.ru 
205053Sigor@sysoev.ru static void
205153Sigor@sysoev.ru nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, void *data)
205253Sigor@sysoev.ru {
2053153Sigor@sysoev.ru     nxt_joint_job_t     *job;
2054153Sigor@sysoev.ru     nxt_socket_conf_t   *skcf;
2055153Sigor@sysoev.ru     nxt_listen_event_t  *listen;
2056153Sigor@sysoev.ru     nxt_event_engine_t  *engine;
2057153Sigor@sysoev.ru 
2058153Sigor@sysoev.ru     job = obj;
205953Sigor@sysoev.ru     skcf = data;
206053Sigor@sysoev.ru 
2061139Sigor@sysoev.ru     engine = task->thread->engine;
2062139Sigor@sysoev.ru 
206353Sigor@sysoev.ru     listen = nxt_router_listen_event(&engine->listen_connections, skcf);
206453Sigor@sysoev.ru 
206553Sigor@sysoev.ru     nxt_fd_event_delete(engine, &listen->socket);
206653Sigor@sysoev.ru 
2067163Smax.romanov@nginx.com     nxt_debug(task, "engine %p: listen socket delete: %d", engine,
2068163Smax.romanov@nginx.com               listen->socket.fd);
2069163Smax.romanov@nginx.com 
207053Sigor@sysoev.ru     listen->timer.handler = nxt_router_listen_socket_close;
207153Sigor@sysoev.ru     listen->timer.work_queue = &engine->fast_work_queue;
207253Sigor@sysoev.ru 
207353Sigor@sysoev.ru     nxt_timer_add(engine, &listen->timer, 0);
2074139Sigor@sysoev.ru 
2075153Sigor@sysoev.ru     job->work.next = NULL;
2076153Sigor@sysoev.ru     job->work.handler = nxt_router_conf_wait;
2077153Sigor@sysoev.ru 
2078153Sigor@sysoev.ru     nxt_event_engine_post(job->tmcf->engine, &job->work);
207953Sigor@sysoev.ru }
208053Sigor@sysoev.ru 
208153Sigor@sysoev.ru 
208253Sigor@sysoev.ru static void
2083313Sigor@sysoev.ru nxt_router_worker_thread_quit(nxt_task_t *task, void *obj, void *data)
2084313Sigor@sysoev.ru {
2085313Sigor@sysoev.ru     nxt_event_engine_t  *engine;
2086313Sigor@sysoev.ru 
2087313Sigor@sysoev.ru     nxt_debug(task, "router worker thread quit");
2088313Sigor@sysoev.ru 
2089313Sigor@sysoev.ru     engine = task->thread->engine;
2090313Sigor@sysoev.ru 
2091313Sigor@sysoev.ru     engine->shutdown = 1;
2092313Sigor@sysoev.ru 
2093313Sigor@sysoev.ru     if (nxt_queue_is_empty(&engine->joints)) {
2094313Sigor@sysoev.ru         nxt_thread_exit(task->thread);
2095313Sigor@sysoev.ru     }
2096313Sigor@sysoev.ru }
2097313Sigor@sysoev.ru 
2098313Sigor@sysoev.ru 
2099313Sigor@sysoev.ru static void
210053Sigor@sysoev.ru nxt_router_listen_socket_close(nxt_task_t *task, void *obj, void *data)
210153Sigor@sysoev.ru {
210253Sigor@sysoev.ru     nxt_timer_t              *timer;
210353Sigor@sysoev.ru     nxt_listen_event_t       *listen;
210453Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
210553Sigor@sysoev.ru 
210653Sigor@sysoev.ru     timer = obj;
210753Sigor@sysoev.ru     listen = nxt_timer_data(timer, nxt_listen_event_t, timer);
210853Sigor@sysoev.ru     joint = listen->socket.data;
210953Sigor@sysoev.ru 
2110163Smax.romanov@nginx.com     nxt_debug(task, "engine %p: listen socket close: %d", task->thread->engine,
2111163Smax.romanov@nginx.com               listen->socket.fd);
2112163Smax.romanov@nginx.com 
211353Sigor@sysoev.ru     nxt_queue_remove(&listen->link);
2114123Smax.romanov@nginx.com 
2115123Smax.romanov@nginx.com     /* 'task' refers to listen->task and we cannot use after nxt_free() */
2116123Smax.romanov@nginx.com     task = &task->thread->engine->task;
2117123Smax.romanov@nginx.com 
211853Sigor@sysoev.ru     nxt_free(listen);
211953Sigor@sysoev.ru 
212053Sigor@sysoev.ru     nxt_router_listen_socket_release(task, joint);
212153Sigor@sysoev.ru }
212253Sigor@sysoev.ru 
212353Sigor@sysoev.ru 
212453Sigor@sysoev.ru static void
212553Sigor@sysoev.ru nxt_router_listen_socket_release(nxt_task_t *task,
212653Sigor@sysoev.ru     nxt_socket_conf_joint_t *joint)
212753Sigor@sysoev.ru {
2128118Sigor@sysoev.ru     nxt_socket_conf_t      *skcf;
2129115Sigor@sysoev.ru     nxt_router_socket_t    *rtsk;
213053Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
213153Sigor@sysoev.ru 
2132118Sigor@sysoev.ru     skcf = joint->socket_conf;
2133118Sigor@sysoev.ru     rtsk = skcf->socket;
2134118Sigor@sysoev.ru     lock = &skcf->router_conf->router->lock;
213553Sigor@sysoev.ru 
213653Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
213753Sigor@sysoev.ru 
2138163Smax.romanov@nginx.com     nxt_debug(task, "engine %p: listen socket release: rtsk->count %D",
2139163Smax.romanov@nginx.com               task->thread->engine, rtsk->count);
2140163Smax.romanov@nginx.com 
2141115Sigor@sysoev.ru     if (--rtsk->count != 0) {
2142115Sigor@sysoev.ru         rtsk = NULL;
214353Sigor@sysoev.ru     }
214453Sigor@sysoev.ru 
214553Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
214653Sigor@sysoev.ru 
2147115Sigor@sysoev.ru     if (rtsk != NULL) {
2148115Sigor@sysoev.ru         nxt_socket_close(task, rtsk->fd);
2149115Sigor@sysoev.ru         nxt_free(rtsk);
2150118Sigor@sysoev.ru         skcf->socket = NULL;
215153Sigor@sysoev.ru     }
215253Sigor@sysoev.ru 
215353Sigor@sysoev.ru     nxt_router_conf_release(task, joint);
215453Sigor@sysoev.ru }
215553Sigor@sysoev.ru 
215653Sigor@sysoev.ru 
215753Sigor@sysoev.ru static void
215853Sigor@sysoev.ru nxt_router_conf_release(nxt_task_t *task, nxt_socket_conf_joint_t *joint)
215953Sigor@sysoev.ru {
2160156Sigor@sysoev.ru     nxt_bool_t             exit;
216153Sigor@sysoev.ru     nxt_socket_conf_t      *skcf;
216253Sigor@sysoev.ru     nxt_router_conf_t      *rtcf;
2163313Sigor@sysoev.ru     nxt_event_engine_t     *engine;
216453Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
216553Sigor@sysoev.ru 
2166163Smax.romanov@nginx.com     nxt_debug(task, "conf joint %p count: %D", joint, joint->count);
216753Sigor@sysoev.ru 
216853Sigor@sysoev.ru     if (--joint->count != 0) {
216953Sigor@sysoev.ru         return;
217053Sigor@sysoev.ru     }
217153Sigor@sysoev.ru 
217253Sigor@sysoev.ru     nxt_queue_remove(&joint->link);
217353Sigor@sysoev.ru 
217453Sigor@sysoev.ru     skcf = joint->socket_conf;
217553Sigor@sysoev.ru     rtcf = skcf->router_conf;
217653Sigor@sysoev.ru     lock = &rtcf->router->lock;
217753Sigor@sysoev.ru 
217853Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
217953Sigor@sysoev.ru 
2180163Smax.romanov@nginx.com     nxt_debug(task, "conf skcf %p: %D, rtcf %p: %D", skcf, skcf->count,
2181163Smax.romanov@nginx.com               rtcf, rtcf->count);
2182163Smax.romanov@nginx.com 
218353Sigor@sysoev.ru     if (--skcf->count != 0) {
218453Sigor@sysoev.ru         rtcf = NULL;
218553Sigor@sysoev.ru 
218653Sigor@sysoev.ru     } else {
218753Sigor@sysoev.ru         nxt_queue_remove(&skcf->link);
218853Sigor@sysoev.ru 
218953Sigor@sysoev.ru         if (--rtcf->count != 0) {
219053Sigor@sysoev.ru             rtcf = NULL;
219153Sigor@sysoev.ru         }
219253Sigor@sysoev.ru     }
219353Sigor@sysoev.ru 
219453Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
219553Sigor@sysoev.ru 
2196141Smax.romanov@nginx.com     /* TODO remove engine->port */
2197141Smax.romanov@nginx.com     /* TODO excude from connected ports */
2198141Smax.romanov@nginx.com 
2199156Sigor@sysoev.ru     /* The joint content can be used before memory pool destruction. */
2200313Sigor@sysoev.ru     engine = joint->engine;
2201313Sigor@sysoev.ru     exit = (engine->shutdown && nxt_queue_is_empty(&engine->joints));
2202156Sigor@sysoev.ru 
220353Sigor@sysoev.ru     if (rtcf != NULL) {
2204115Sigor@sysoev.ru         nxt_debug(task, "old router conf is destroyed");
2205131Smax.romanov@nginx.com 
2206131Smax.romanov@nginx.com         nxt_mp_thread_adopt(rtcf->mem_pool);
2207131Smax.romanov@nginx.com 
220865Sigor@sysoev.ru         nxt_mp_destroy(rtcf->mem_pool);
220953Sigor@sysoev.ru     }
221053Sigor@sysoev.ru 
2211156Sigor@sysoev.ru     if (exit) {
221253Sigor@sysoev.ru         nxt_thread_exit(task->thread);
221353Sigor@sysoev.ru     }
221453Sigor@sysoev.ru }
221553Sigor@sysoev.ru 
221653Sigor@sysoev.ru 
221753Sigor@sysoev.ru static void
221853Sigor@sysoev.ru nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, void *data)
221953Sigor@sysoev.ru {
2220141Smax.romanov@nginx.com     nxt_port_t           *port;
222153Sigor@sysoev.ru     nxt_thread_link_t    *link;
222253Sigor@sysoev.ru     nxt_event_engine_t   *engine;
222353Sigor@sysoev.ru     nxt_thread_handle_t  handle;
222453Sigor@sysoev.ru 
222558Svbart@nginx.com     handle = (nxt_thread_handle_t) obj;
222653Sigor@sysoev.ru     link = data;
222753Sigor@sysoev.ru 
222853Sigor@sysoev.ru     nxt_thread_wait(handle);
222953Sigor@sysoev.ru 
223053Sigor@sysoev.ru     engine = link->engine;
223153Sigor@sysoev.ru 
223253Sigor@sysoev.ru     nxt_queue_remove(&engine->link);
223353Sigor@sysoev.ru 
2234141Smax.romanov@nginx.com     port = engine->port;
2235141Smax.romanov@nginx.com 
2236141Smax.romanov@nginx.com     // TODO notify all apps
2237141Smax.romanov@nginx.com 
2238343Smax.romanov@nginx.com     port->engine = task->thread->engine;
2239163Smax.romanov@nginx.com     nxt_mp_thread_adopt(port->mem_pool);
2240343Smax.romanov@nginx.com     nxt_port_use(task, port, -1);
2241163Smax.romanov@nginx.com 
2242163Smax.romanov@nginx.com     nxt_mp_thread_adopt(engine->mem_pool);
224363Sigor@sysoev.ru     nxt_mp_destroy(engine->mem_pool);
224453Sigor@sysoev.ru 
224553Sigor@sysoev.ru     nxt_event_engine_free(engine);
224653Sigor@sysoev.ru 
224753Sigor@sysoev.ru     nxt_free(link);
224853Sigor@sysoev.ru }
224953Sigor@sysoev.ru 
225053Sigor@sysoev.ru 
2251206Smax.romanov@nginx.com static const nxt_conn_state_t  nxt_router_conn_read_header_state
225253Sigor@sysoev.ru     nxt_aligned(64) =
225353Sigor@sysoev.ru {
225453Sigor@sysoev.ru     .ready_handler = nxt_router_conn_http_header_parse,
225553Sigor@sysoev.ru     .close_handler = nxt_router_conn_close,
225653Sigor@sysoev.ru     .error_handler = nxt_router_conn_error,
225753Sigor@sysoev.ru 
225853Sigor@sysoev.ru     .timer_handler = nxt_router_conn_timeout,
225953Sigor@sysoev.ru     .timer_value = nxt_router_conn_timeout_value,
226053Sigor@sysoev.ru     .timer_data = offsetof(nxt_socket_conf_t, header_read_timeout),
226153Sigor@sysoev.ru };
226253Sigor@sysoev.ru 
226353Sigor@sysoev.ru 
2264206Smax.romanov@nginx.com static const nxt_conn_state_t  nxt_router_conn_read_body_state
2265206Smax.romanov@nginx.com     nxt_aligned(64) =
2266206Smax.romanov@nginx.com {
2267206Smax.romanov@nginx.com     .ready_handler = nxt_router_conn_http_body_read,
2268206Smax.romanov@nginx.com     .close_handler = nxt_router_conn_close,
2269206Smax.romanov@nginx.com     .error_handler = nxt_router_conn_error,
2270206Smax.romanov@nginx.com 
2271206Smax.romanov@nginx.com     .timer_handler = nxt_router_conn_timeout,
2272206Smax.romanov@nginx.com     .timer_value = nxt_router_conn_timeout_value,
2273206Smax.romanov@nginx.com     .timer_data = offsetof(nxt_socket_conf_t, body_read_timeout),
2274206Smax.romanov@nginx.com     .timer_autoreset = 1,
2275206Smax.romanov@nginx.com };
2276206Smax.romanov@nginx.com 
2277206Smax.romanov@nginx.com 
227853Sigor@sysoev.ru static void
227953Sigor@sysoev.ru nxt_router_conn_init(nxt_task_t *task, void *obj, void *data)
228053Sigor@sysoev.ru {
228153Sigor@sysoev.ru     size_t                   size;
228262Sigor@sysoev.ru     nxt_conn_t               *c;
228353Sigor@sysoev.ru     nxt_event_engine_t       *engine;
228453Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
228553Sigor@sysoev.ru 
228653Sigor@sysoev.ru     c = obj;
228753Sigor@sysoev.ru     joint = data;
228853Sigor@sysoev.ru 
228953Sigor@sysoev.ru     nxt_debug(task, "router conn init");
229053Sigor@sysoev.ru 
229153Sigor@sysoev.ru     joint->count++;
229253Sigor@sysoev.ru 
229353Sigor@sysoev.ru     size = joint->socket_conf->header_buffer_size;
229453Sigor@sysoev.ru     c->read = nxt_buf_mem_alloc(c->mem_pool, size, 0);
229553Sigor@sysoev.ru 
229653Sigor@sysoev.ru     c->socket.data = NULL;
229753Sigor@sysoev.ru 
229853Sigor@sysoev.ru     engine = task->thread->engine;
229953Sigor@sysoev.ru     c->read_work_queue = &engine->fast_work_queue;
230053Sigor@sysoev.ru     c->write_work_queue = &engine->fast_work_queue;
230153Sigor@sysoev.ru 
2302206Smax.romanov@nginx.com     c->read_state = &nxt_router_conn_read_header_state;
230353Sigor@sysoev.ru 
230462Sigor@sysoev.ru     nxt_conn_read(engine, c);
230553Sigor@sysoev.ru }
230653Sigor@sysoev.ru 
230753Sigor@sysoev.ru 
230862Sigor@sysoev.ru static const nxt_conn_state_t  nxt_router_conn_write_state
230953Sigor@sysoev.ru     nxt_aligned(64) =
231053Sigor@sysoev.ru {
231188Smax.romanov@nginx.com     .ready_handler = nxt_router_conn_ready,
231253Sigor@sysoev.ru     .close_handler = nxt_router_conn_close,
231353Sigor@sysoev.ru     .error_handler = nxt_router_conn_error,
231453Sigor@sysoev.ru };
231553Sigor@sysoev.ru 
231653Sigor@sysoev.ru 
231753Sigor@sysoev.ru static void
2318318Smax.romanov@nginx.com nxt_router_response_ready_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2319318Smax.romanov@nginx.com     void *data)
232088Smax.romanov@nginx.com {
232188Smax.romanov@nginx.com     size_t               dump_size;
2322194Smax.romanov@nginx.com     nxt_buf_t            *b, *last;
232388Smax.romanov@nginx.com     nxt_conn_t           *c;
232488Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
232588Smax.romanov@nginx.com 
232688Smax.romanov@nginx.com     b = msg->buf;
2327318Smax.romanov@nginx.com     rc = data;
232888Smax.romanov@nginx.com 
232988Smax.romanov@nginx.com     c = rc->conn;
233088Smax.romanov@nginx.com 
233188Smax.romanov@nginx.com     dump_size = nxt_buf_used_size(b);
233288Smax.romanov@nginx.com 
233388Smax.romanov@nginx.com     if (dump_size > 300) {
233488Smax.romanov@nginx.com         dump_size = 300;
233588Smax.romanov@nginx.com     }
233688Smax.romanov@nginx.com 
2337119Smax.romanov@nginx.com     nxt_debug(task, "%srouter app data (%z): %*s",
233888Smax.romanov@nginx.com               msg->port_msg.last ? "last " : "", msg->size, dump_size,
233988Smax.romanov@nginx.com               b->mem.pos);
234088Smax.romanov@nginx.com 
234188Smax.romanov@nginx.com     if (msg->size == 0) {
234288Smax.romanov@nginx.com         b = NULL;
234388Smax.romanov@nginx.com     }
234488Smax.romanov@nginx.com 
234588Smax.romanov@nginx.com     if (msg->port_msg.last != 0) {
234688Smax.romanov@nginx.com         nxt_debug(task, "router data create last buf");
234788Smax.romanov@nginx.com 
234888Smax.romanov@nginx.com         last = nxt_buf_sync_alloc(c->mem_pool, NXT_BUF_SYNC_LAST);
234988Smax.romanov@nginx.com         if (nxt_slow_path(last == NULL)) {
235088Smax.romanov@nginx.com             /* TODO pogorevaTb */
235188Smax.romanov@nginx.com         }
235288Smax.romanov@nginx.com 
235388Smax.romanov@nginx.com         nxt_buf_chain_add(&b, last);
2354167Smax.romanov@nginx.com 
2355343Smax.romanov@nginx.com         nxt_router_rc_unlink(task, rc);
235688Smax.romanov@nginx.com     }
235788Smax.romanov@nginx.com 
235888Smax.romanov@nginx.com     if (b == NULL) {
235988Smax.romanov@nginx.com         return;
236088Smax.romanov@nginx.com     }
236188Smax.romanov@nginx.com 
2362206Smax.romanov@nginx.com     if (msg->buf == b) {
2363206Smax.romanov@nginx.com         /* Disable instant buffer completion/re-using by port. */
2364206Smax.romanov@nginx.com         msg->buf = NULL;
2365206Smax.romanov@nginx.com     }
2366194Smax.romanov@nginx.com 
236788Smax.romanov@nginx.com     if (c->write == NULL) {
236888Smax.romanov@nginx.com         c->write = b;
236988Smax.romanov@nginx.com         c->write_state = &nxt_router_conn_write_state;
237088Smax.romanov@nginx.com 
237188Smax.romanov@nginx.com         nxt_conn_write(task->thread->engine, c);
2372277Sigor@sysoev.ru 
237388Smax.romanov@nginx.com     } else {
237488Smax.romanov@nginx.com         nxt_debug(task, "router data attach out bufs to existing chain");
237588Smax.romanov@nginx.com 
237688Smax.romanov@nginx.com         nxt_buf_chain_add(&c->write, b);
237788Smax.romanov@nginx.com     }
237888Smax.romanov@nginx.com }
237988Smax.romanov@nginx.com 
2380277Sigor@sysoev.ru 
2381318Smax.romanov@nginx.com static void
2382318Smax.romanov@nginx.com nxt_router_response_error_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2383318Smax.romanov@nginx.com     void *data)
2384318Smax.romanov@nginx.com {
2385318Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
2386318Smax.romanov@nginx.com 
2387318Smax.romanov@nginx.com     rc = data;
2388318Smax.romanov@nginx.com 
2389318Smax.romanov@nginx.com     nxt_router_gen_error(task, rc->conn, 500,
2390318Smax.romanov@nginx.com                          "Application terminated unexpectedly");
2391318Smax.romanov@nginx.com 
2392343Smax.romanov@nginx.com     nxt_router_rc_unlink(task, rc);
2393318Smax.romanov@nginx.com }
2394318Smax.romanov@nginx.com 
2395318Smax.romanov@nginx.com 
2396141Smax.romanov@nginx.com nxt_inline const char *
2397141Smax.romanov@nginx.com nxt_router_text_by_code(int code)
2398141Smax.romanov@nginx.com {
2399141Smax.romanov@nginx.com     switch (code) {
2400141Smax.romanov@nginx.com     case 400: return "Bad request";
2401141Smax.romanov@nginx.com     case 404: return "Not found";
2402141Smax.romanov@nginx.com     case 403: return "Forbidden";
2403206Smax.romanov@nginx.com     case 408: return "Request Timeout";
2404206Smax.romanov@nginx.com     case 411: return "Length Required";
2405206Smax.romanov@nginx.com     case 413: return "Request Entity Too Large";
2406141Smax.romanov@nginx.com     case 500:
2407141Smax.romanov@nginx.com     default:  return "Internal server error";
2408141Smax.romanov@nginx.com     }
2409141Smax.romanov@nginx.com }
2410141Smax.romanov@nginx.com 
2411163Smax.romanov@nginx.com 
2412163Smax.romanov@nginx.com static nxt_buf_t *
2413163Smax.romanov@nginx.com nxt_router_get_error_buf(nxt_task_t *task, nxt_mp_t *mp, int code,
2414345Smax.romanov@nginx.com     const char* str)
241588Smax.romanov@nginx.com {
2416345Smax.romanov@nginx.com     nxt_buf_t  *b, *last;
2417345Smax.romanov@nginx.com 
2418345Smax.romanov@nginx.com     b = nxt_buf_mem_alloc(mp, 16384, 0);
2419141Smax.romanov@nginx.com     if (nxt_slow_path(b == NULL)) {
2420163Smax.romanov@nginx.com         return NULL;
2421141Smax.romanov@nginx.com     }
2422141Smax.romanov@nginx.com 
2423141Smax.romanov@nginx.com     b->mem.free = nxt_sprintf(b->mem.free, b->mem.end,
2424141Smax.romanov@nginx.com         "HTTP/1.0 %d %s\r\n"
2425141Smax.romanov@nginx.com         "Content-Type: text/plain\r\n"
2426141Smax.romanov@nginx.com         "Connection: close\r\n\r\n",
2427141Smax.romanov@nginx.com         code, nxt_router_text_by_code(code));
2428141Smax.romanov@nginx.com 
2429345Smax.romanov@nginx.com     b->mem.free = nxt_cpymem(b->mem.free, str, nxt_strlen(str));
2430345Smax.romanov@nginx.com 
2431345Smax.romanov@nginx.com     nxt_log_alert(task->log, "error %d: %s", code, str);
2432345Smax.romanov@nginx.com 
2433345Smax.romanov@nginx.com     last = nxt_buf_sync_alloc(mp, NXT_BUF_SYNC_LAST);
2434163Smax.romanov@nginx.com 
2435141Smax.romanov@nginx.com     if (nxt_slow_path(last == NULL)) {
2436345Smax.romanov@nginx.com         nxt_mp_free(mp, b);
2437163Smax.romanov@nginx.com         return NULL;
2438141Smax.romanov@nginx.com     }
2439141Smax.romanov@nginx.com 
2440141Smax.romanov@nginx.com     nxt_buf_chain_add(&b, last);
2441141Smax.romanov@nginx.com 
2442163Smax.romanov@nginx.com     return b;
2443163Smax.romanov@nginx.com }
2444163Smax.romanov@nginx.com 
2445163Smax.romanov@nginx.com 
2446163Smax.romanov@nginx.com 
2447163Smax.romanov@nginx.com static void
2448163Smax.romanov@nginx.com nxt_router_gen_error(nxt_task_t *task, nxt_conn_t *c, int code,
2449345Smax.romanov@nginx.com     const char* str)
2450163Smax.romanov@nginx.com {
2451318Smax.romanov@nginx.com     nxt_mp_t   *mp;
2452163Smax.romanov@nginx.com     nxt_buf_t  *b;
2453163Smax.romanov@nginx.com 
2454318Smax.romanov@nginx.com     /* TODO: fix when called in the middle of response */
2455318Smax.romanov@nginx.com 
2456345Smax.romanov@nginx.com     mp = c->mem_pool;
2457345Smax.romanov@nginx.com 
2458345Smax.romanov@nginx.com     b = nxt_router_get_error_buf(task, mp, code, str);
2459163Smax.romanov@nginx.com 
2460273Smax.romanov@nginx.com     if (c->socket.fd == -1) {
2461345Smax.romanov@nginx.com         nxt_mp_free(mp, b->next);
2462345Smax.romanov@nginx.com         nxt_mp_free(mp, b);
2463273Smax.romanov@nginx.com         return;
2464273Smax.romanov@nginx.com     }
2465273Smax.romanov@nginx.com 
2466141Smax.romanov@nginx.com     if (c->write == NULL) {
2467141Smax.romanov@nginx.com         c->write = b;
2468141Smax.romanov@nginx.com         c->write_state = &nxt_router_conn_write_state;
2469141Smax.romanov@nginx.com 
2470141Smax.romanov@nginx.com         nxt_conn_write(task->thread->engine, c);
2471277Sigor@sysoev.ru 
2472141Smax.romanov@nginx.com     } else {
2473141Smax.romanov@nginx.com         nxt_debug(task, "router data attach out bufs to existing chain");
2474141Smax.romanov@nginx.com 
2475141Smax.romanov@nginx.com         nxt_buf_chain_add(&c->write, b);
2476141Smax.romanov@nginx.com     }
2477141Smax.romanov@nginx.com }
2478141Smax.romanov@nginx.com 
2479141Smax.romanov@nginx.com 
2480141Smax.romanov@nginx.com static void
2481343Smax.romanov@nginx.com nxt_router_app_port_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2482343Smax.romanov@nginx.com     void *data)
2483192Smax.romanov@nginx.com {
2484343Smax.romanov@nginx.com     nxt_app_t   *app;
2485343Smax.romanov@nginx.com     nxt_port_t  *port;
2486343Smax.romanov@nginx.com 
2487343Smax.romanov@nginx.com     app = data;
2488347Smax.romanov@nginx.com     port = msg->u.new_port;
2489343Smax.romanov@nginx.com 
2490343Smax.romanov@nginx.com     nxt_assert(app != NULL);
2491343Smax.romanov@nginx.com     nxt_assert(port != NULL);
2492343Smax.romanov@nginx.com 
2493343Smax.romanov@nginx.com     port->app = app;
2494343Smax.romanov@nginx.com 
2495343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
2496343Smax.romanov@nginx.com 
2497343Smax.romanov@nginx.com     nxt_assert(app->pending_workers != 0);
2498343Smax.romanov@nginx.com 
2499343Smax.romanov@nginx.com     app->pending_workers--;
2500343Smax.romanov@nginx.com     app->workers++;
2501343Smax.romanov@nginx.com 
2502343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
2503343Smax.romanov@nginx.com 
2504343Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p new port ready", &app->name, app);
2505343Smax.romanov@nginx.com 
2506343Smax.romanov@nginx.com     nxt_router_app_port_release(task, port, 0, 0);
2507192Smax.romanov@nginx.com }
2508192Smax.romanov@nginx.com 
2509192Smax.romanov@nginx.com 
2510192Smax.romanov@nginx.com static void
2511343Smax.romanov@nginx.com nxt_router_app_port_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2512343Smax.romanov@nginx.com     void *data)
2513192Smax.romanov@nginx.com {
2514318Smax.romanov@nginx.com     nxt_app_t           *app;
2515318Smax.romanov@nginx.com     nxt_queue_link_t    *lnk;
2516318Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
2517343Smax.romanov@nginx.com 
2518343Smax.romanov@nginx.com     app = data;
2519343Smax.romanov@nginx.com 
2520343Smax.romanov@nginx.com     nxt_assert(app != NULL);
2521343Smax.romanov@nginx.com 
2522343Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p start error", &app->name, app);
2523343Smax.romanov@nginx.com 
2524343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
2525343Smax.romanov@nginx.com 
2526343Smax.romanov@nginx.com     nxt_assert(app->pending_workers != 0);
2527343Smax.romanov@nginx.com 
2528343Smax.romanov@nginx.com     app->pending_workers--;
2529318Smax.romanov@nginx.com 
2530318Smax.romanov@nginx.com     if (!nxt_queue_is_empty(&app->requests)) {
2531318Smax.romanov@nginx.com         lnk = nxt_queue_last(&app->requests);
2532318Smax.romanov@nginx.com         nxt_queue_remove(lnk);
2533343Smax.romanov@nginx.com         lnk->next = NULL;
2534318Smax.romanov@nginx.com 
2535318Smax.romanov@nginx.com         ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link);
2536318Smax.romanov@nginx.com 
2537343Smax.romanov@nginx.com     } else {
2538343Smax.romanov@nginx.com         ra = NULL;
2539343Smax.romanov@nginx.com     }
2540343Smax.romanov@nginx.com 
2541343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
2542343Smax.romanov@nginx.com 
2543343Smax.romanov@nginx.com     if (ra != NULL) {
2544318Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p abort next stream #%uD",
2545318Smax.romanov@nginx.com                   &app->name, app, ra->stream);
2546318Smax.romanov@nginx.com 
2547318Smax.romanov@nginx.com         nxt_router_ra_abort(task, ra, ra->work.data);
2548318Smax.romanov@nginx.com     }
2549192Smax.romanov@nginx.com 
2550343Smax.romanov@nginx.com     nxt_router_app_use(task, app, -1);
2551192Smax.romanov@nginx.com }
2552192Smax.romanov@nginx.com 
2553192Smax.romanov@nginx.com 
2554343Smax.romanov@nginx.com void
2555343Smax.romanov@nginx.com nxt_router_app_use(nxt_task_t *task, nxt_app_t *app, int i)
2556141Smax.romanov@nginx.com {
2557343Smax.romanov@nginx.com     int  c;
2558343Smax.romanov@nginx.com 
2559343Smax.romanov@nginx.com     c = nxt_atomic_fetch_add(&app->use_count, i);
2560343Smax.romanov@nginx.com 
2561343Smax.romanov@nginx.com     if (i < 0 && c == -i) {
2562343Smax.romanov@nginx.com 
2563343Smax.romanov@nginx.com         nxt_assert(app->live == 0);
2564343Smax.romanov@nginx.com         nxt_assert(app->workers == 0);
2565343Smax.romanov@nginx.com         nxt_assert(app->pending_workers == 0);
2566343Smax.romanov@nginx.com         nxt_assert(nxt_queue_is_empty(&app->requests) != 0);
2567343Smax.romanov@nginx.com         nxt_assert(nxt_queue_is_empty(&app->ports) != 0);
2568343Smax.romanov@nginx.com 
2569163Smax.romanov@nginx.com         nxt_thread_mutex_destroy(&app->mutex);
2570163Smax.romanov@nginx.com         nxt_free(app);
2571163Smax.romanov@nginx.com     }
2572343Smax.romanov@nginx.com }
2573343Smax.romanov@nginx.com 
2574343Smax.romanov@nginx.com 
2575343Smax.romanov@nginx.com nxt_inline nxt_port_t *
2576343Smax.romanov@nginx.com nxt_router_app_get_port_unsafe(nxt_app_t *app, int *use_delta)
2577343Smax.romanov@nginx.com {
2578343Smax.romanov@nginx.com     nxt_port_t        *port;
2579343Smax.romanov@nginx.com     nxt_queue_link_t  *lnk;
2580343Smax.romanov@nginx.com 
2581343Smax.romanov@nginx.com     lnk = nxt_queue_first(&app->ports);
2582343Smax.romanov@nginx.com     nxt_queue_remove(lnk);
2583343Smax.romanov@nginx.com 
2584343Smax.romanov@nginx.com     port = nxt_queue_link_data(lnk, nxt_port_t, app_link);
2585343Smax.romanov@nginx.com 
2586343Smax.romanov@nginx.com     port->app_requests++;
2587343Smax.romanov@nginx.com 
2588343Smax.romanov@nginx.com     if (app->live &&
2589343Smax.romanov@nginx.com          (app->max_pending_responses == 0 ||
2590343Smax.romanov@nginx.com             (port->app_requests - port->app_responses) <
2591343Smax.romanov@nginx.com                 app->max_pending_responses) )
2592277Sigor@sysoev.ru     {
2593343Smax.romanov@nginx.com         nxt_queue_insert_tail(&app->ports, lnk);
2594343Smax.romanov@nginx.com 
2595343Smax.romanov@nginx.com     } else {
2596343Smax.romanov@nginx.com         lnk->next = NULL;
2597343Smax.romanov@nginx.com 
2598343Smax.romanov@nginx.com         (*use_delta)--;
2599167Smax.romanov@nginx.com     }
2600167Smax.romanov@nginx.com 
2601343Smax.romanov@nginx.com     return port;
2602163Smax.romanov@nginx.com }
2603163Smax.romanov@nginx.com 
2604163Smax.romanov@nginx.com 
2605141Smax.romanov@nginx.com static nxt_port_t *
2606343Smax.romanov@nginx.com nxt_router_app_get_idle_port(nxt_app_t *app)
2607141Smax.romanov@nginx.com {
2608343Smax.romanov@nginx.com     nxt_port_t  *port;
2609141Smax.romanov@nginx.com 
2610141Smax.romanov@nginx.com     port = NULL;
2611141Smax.romanov@nginx.com 
2612141Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
2613141Smax.romanov@nginx.com 
2614343Smax.romanov@nginx.com     nxt_queue_each(port, &app->ports, nxt_port_t, app_link) {
2615343Smax.romanov@nginx.com 
2616343Smax.romanov@nginx.com         if (port->app_requests > port->app_responses) {
2617343Smax.romanov@nginx.com             port = NULL;
2618343Smax.romanov@nginx.com 
2619343Smax.romanov@nginx.com             continue;
2620343Smax.romanov@nginx.com         }
2621343Smax.romanov@nginx.com 
2622343Smax.romanov@nginx.com         nxt_queue_remove(&port->app_link);
2623343Smax.romanov@nginx.com         port->app_link.next = NULL;
2624343Smax.romanov@nginx.com 
2625343Smax.romanov@nginx.com         break;
2626343Smax.romanov@nginx.com 
2627343Smax.romanov@nginx.com     } nxt_queue_loop;
2628141Smax.romanov@nginx.com 
2629141Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
2630141Smax.romanov@nginx.com 
2631141Smax.romanov@nginx.com     return port;
2632141Smax.romanov@nginx.com }
2633141Smax.romanov@nginx.com 
2634141Smax.romanov@nginx.com 
2635141Smax.romanov@nginx.com static void
2636343Smax.romanov@nginx.com nxt_router_app_process_request(nxt_task_t *task, void *obj, void *data)
2637141Smax.romanov@nginx.com {
2638343Smax.romanov@nginx.com     nxt_app_t           *app;
2639343Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
2640343Smax.romanov@nginx.com 
2641343Smax.romanov@nginx.com     app = obj;
2642343Smax.romanov@nginx.com     ra = data;
2643141Smax.romanov@nginx.com 
2644141Smax.romanov@nginx.com     nxt_assert(app != NULL);
2645343Smax.romanov@nginx.com     nxt_assert(ra != NULL);
2646343Smax.romanov@nginx.com     nxt_assert(ra->app_port != NULL);
2647343Smax.romanov@nginx.com 
2648343Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p process next stream #%uD",
2649343Smax.romanov@nginx.com               &app->name, app, ra->stream);
2650343Smax.romanov@nginx.com 
2651343Smax.romanov@nginx.com     nxt_router_process_http_request_mp(task, ra);
2652343Smax.romanov@nginx.com }
2653343Smax.romanov@nginx.com 
2654343Smax.romanov@nginx.com 
2655343Smax.romanov@nginx.com static void
2656343Smax.romanov@nginx.com nxt_router_app_port_release(nxt_task_t *task, nxt_port_t *port,
2657343Smax.romanov@nginx.com     uint32_t request_failed, uint32_t got_response)
2658343Smax.romanov@nginx.com {
2659343Smax.romanov@nginx.com     int                 use_delta, ra_use_delta;
2660343Smax.romanov@nginx.com     nxt_app_t           *app;
2661343Smax.romanov@nginx.com     nxt_queue_link_t    *lnk;
2662343Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
2663343Smax.romanov@nginx.com 
2664343Smax.romanov@nginx.com     nxt_assert(port != NULL);
2665343Smax.romanov@nginx.com     nxt_assert(port->app != NULL);
2666343Smax.romanov@nginx.com 
2667343Smax.romanov@nginx.com     app = port->app;
2668343Smax.romanov@nginx.com 
2669343Smax.romanov@nginx.com     use_delta = (request_failed == 0 && got_response == 0) ? 0 : -1;
2670343Smax.romanov@nginx.com 
2671343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
2672343Smax.romanov@nginx.com 
2673343Smax.romanov@nginx.com     port->app_requests -= request_failed;
2674343Smax.romanov@nginx.com     port->app_responses += got_response;
2675343Smax.romanov@nginx.com 
2676343Smax.romanov@nginx.com     if (app->live != 0 &&
2677343Smax.romanov@nginx.com         port->pair[1] != -1 &&
2678343Smax.romanov@nginx.com         port->app_link.next == NULL &&
2679343Smax.romanov@nginx.com         (app->max_pending_responses == 0 ||
2680343Smax.romanov@nginx.com             (port->app_requests - port->app_responses) <
2681343Smax.romanov@nginx.com                 app->max_pending_responses) )
2682343Smax.romanov@nginx.com     {
2683343Smax.romanov@nginx.com         nxt_queue_insert_tail(&app->ports, &port->app_link);
2684343Smax.romanov@nginx.com         use_delta++;
2685141Smax.romanov@nginx.com     }
2686141Smax.romanov@nginx.com 
2687343Smax.romanov@nginx.com     if (app->live != 0 &&
2688343Smax.romanov@nginx.com         !nxt_queue_is_empty(&app->ports) &&
2689343Smax.romanov@nginx.com         !nxt_queue_is_empty(&app->requests))
2690343Smax.romanov@nginx.com     {
2691141Smax.romanov@nginx.com         lnk = nxt_queue_first(&app->requests);
2692141Smax.romanov@nginx.com         nxt_queue_remove(lnk);
2693343Smax.romanov@nginx.com         lnk->next = NULL;
2694141Smax.romanov@nginx.com 
2695167Smax.romanov@nginx.com         ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link);
2696167Smax.romanov@nginx.com 
2697343Smax.romanov@nginx.com         ra_use_delta = 1;
2698343Smax.romanov@nginx.com         ra->app_port = nxt_router_app_get_port_unsafe(app, &ra_use_delta);
2699343Smax.romanov@nginx.com 
2700343Smax.romanov@nginx.com     } else {
2701343Smax.romanov@nginx.com         ra = NULL;
2702343Smax.romanov@nginx.com         ra_use_delta = 0;
2703141Smax.romanov@nginx.com     }
2704141Smax.romanov@nginx.com 
2705343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
2706343Smax.romanov@nginx.com 
2707343Smax.romanov@nginx.com     if (ra != NULL) {
2708343Smax.romanov@nginx.com         nxt_work_queue_add(&task->thread->engine->fast_work_queue,
2709343Smax.romanov@nginx.com                            nxt_router_app_process_request,
2710343Smax.romanov@nginx.com                            &task->thread->engine->task, app, ra);
2711343Smax.romanov@nginx.com 
2712343Smax.romanov@nginx.com         goto adjust_use;
2713343Smax.romanov@nginx.com     }
2714343Smax.romanov@nginx.com 
2715343Smax.romanov@nginx.com     /* ? */
2716163Smax.romanov@nginx.com     if (port->pair[1] == -1) {
2717343Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p port %p already closed (pid %PI dead?)",
2718343Smax.romanov@nginx.com                   &app->name, app, port, port->pid);
2719343Smax.romanov@nginx.com 
2720343Smax.romanov@nginx.com         goto adjust_use;
2721163Smax.romanov@nginx.com     }
2722163Smax.romanov@nginx.com 
2723343Smax.romanov@nginx.com     if (app->live == 0) {
2724167Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p is not alive, send QUIT to port",
2725167Smax.romanov@nginx.com                   &app->name, app);
2726163Smax.romanov@nginx.com 
2727163Smax.romanov@nginx.com         nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT,
2728163Smax.romanov@nginx.com                               -1, 0, 0, NULL);
2729163Smax.romanov@nginx.com 
2730343Smax.romanov@nginx.com         goto adjust_use;
2731163Smax.romanov@nginx.com     }
2732163Smax.romanov@nginx.com 
2733167Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p requests queue is empty, keep the port",
2734167Smax.romanov@nginx.com               &app->name, app);
2735141Smax.romanov@nginx.com 
2736343Smax.romanov@nginx.com adjust_use:
2737343Smax.romanov@nginx.com 
2738343Smax.romanov@nginx.com     if (use_delta != 0) {
2739343Smax.romanov@nginx.com         nxt_port_use(task, port, use_delta);
2740343Smax.romanov@nginx.com     }
2741343Smax.romanov@nginx.com 
2742343Smax.romanov@nginx.com     if (ra_use_delta != 0) {
2743343Smax.romanov@nginx.com         nxt_port_use(task, ra->app_port, ra_use_delta);
2744343Smax.romanov@nginx.com     }
2745141Smax.romanov@nginx.com }
2746141Smax.romanov@nginx.com 
2747141Smax.romanov@nginx.com 
2748343Smax.romanov@nginx.com void
2749343Smax.romanov@nginx.com nxt_router_app_port_close(nxt_task_t *task, nxt_port_t *port)
2750141Smax.romanov@nginx.com {
2751163Smax.romanov@nginx.com     nxt_app_t   *app;
2752343Smax.romanov@nginx.com     nxt_bool_t  unchain, start_worker;
2753141Smax.romanov@nginx.com 
2754141Smax.romanov@nginx.com     app = port->app;
2755343Smax.romanov@nginx.com 
2756343Smax.romanov@nginx.com     nxt_assert(app != NULL);
2757141Smax.romanov@nginx.com 
2758141Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
2759141Smax.romanov@nginx.com 
2760343Smax.romanov@nginx.com     unchain = port->app_link.next != NULL;
2761343Smax.romanov@nginx.com 
2762343Smax.romanov@nginx.com     if (unchain) {
2763163Smax.romanov@nginx.com         nxt_queue_remove(&port->app_link);
2764163Smax.romanov@nginx.com         port->app_link.next = NULL;
2765343Smax.romanov@nginx.com     }
2766343Smax.romanov@nginx.com 
2767343Smax.romanov@nginx.com     app->workers--;
2768343Smax.romanov@nginx.com 
2769343Smax.romanov@nginx.com     start_worker = app->live != 0 &&
2770343Smax.romanov@nginx.com                    nxt_queue_is_empty(&app->requests) == 0 &&
2771343Smax.romanov@nginx.com                    app->workers + app->pending_workers < app->max_workers;
2772343Smax.romanov@nginx.com 
2773343Smax.romanov@nginx.com     if (start_worker) {
2774343Smax.romanov@nginx.com         app->pending_workers++;
2775163Smax.romanov@nginx.com     }
2776141Smax.romanov@nginx.com 
2777141Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
2778163Smax.romanov@nginx.com 
2779343Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p port %p close", &app->name, app, port);
2780343Smax.romanov@nginx.com 
2781343Smax.romanov@nginx.com     if (unchain) {
2782343Smax.romanov@nginx.com         nxt_port_use(task, port, -1);
2783163Smax.romanov@nginx.com     }
2784163Smax.romanov@nginx.com 
2785343Smax.romanov@nginx.com     if (start_worker) {
2786343Smax.romanov@nginx.com         nxt_router_start_worker(task, app);
2787343Smax.romanov@nginx.com     }
2788141Smax.romanov@nginx.com }
2789141Smax.romanov@nginx.com 
2790141Smax.romanov@nginx.com 
2791167Smax.romanov@nginx.com static nxt_int_t
2792167Smax.romanov@nginx.com nxt_router_app_port(nxt_task_t *task, nxt_req_app_link_t *ra)
2793141Smax.romanov@nginx.com {
2794343Smax.romanov@nginx.com     int                      use_delta;
2795343Smax.romanov@nginx.com     nxt_int_t                res;
2796141Smax.romanov@nginx.com     nxt_app_t                *app;
2797343Smax.romanov@nginx.com     nxt_bool_t               can_start_worker;
2798141Smax.romanov@nginx.com     nxt_conn_t               *c;
2799167Smax.romanov@nginx.com     nxt_port_t               *port;
2800318Smax.romanov@nginx.com     nxt_event_engine_t       *engine;
2801141Smax.romanov@nginx.com     nxt_socket_conf_joint_t  *joint;
2802141Smax.romanov@nginx.com 
2803141Smax.romanov@nginx.com     port = NULL;
2804343Smax.romanov@nginx.com     use_delta = 1;
2805167Smax.romanov@nginx.com     c = ra->rc->conn;
2806141Smax.romanov@nginx.com 
2807141Smax.romanov@nginx.com     joint = c->listen->socket.data;
2808141Smax.romanov@nginx.com     app = joint->socket_conf->application;
2809141Smax.romanov@nginx.com 
2810141Smax.romanov@nginx.com     if (app == NULL) {
2811167Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 500,
2812141Smax.romanov@nginx.com                              "Application is NULL in socket_conf");
2813141Smax.romanov@nginx.com         return NXT_ERROR;
2814141Smax.romanov@nginx.com     }
2815141Smax.romanov@nginx.com 
2816343Smax.romanov@nginx.com     ra->rc->app = app;
2817343Smax.romanov@nginx.com 
2818343Smax.romanov@nginx.com     nxt_router_app_use(task, app, 1);
2819343Smax.romanov@nginx.com 
2820318Smax.romanov@nginx.com     engine = task->thread->engine;
2821318Smax.romanov@nginx.com 
2822318Smax.romanov@nginx.com     nxt_timer_disable(engine, &c->read_timer);
2823318Smax.romanov@nginx.com 
2824318Smax.romanov@nginx.com     if (app->timeout != 0) {
2825318Smax.romanov@nginx.com         c->read_timer.handler = nxt_router_app_timeout;
2826318Smax.romanov@nginx.com         nxt_timer_add(engine, &c->read_timer, app->timeout);
2827318Smax.romanov@nginx.com     }
2828318Smax.romanov@nginx.com 
2829*351Smax.romanov@nginx.com     can_start_worker = 0;
2830*351Smax.romanov@nginx.com 
2831343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
2832343Smax.romanov@nginx.com 
2833343Smax.romanov@nginx.com     if (!nxt_queue_is_empty(&app->ports)) {
2834343Smax.romanov@nginx.com         port = nxt_router_app_get_port_unsafe(app, &use_delta);
2835343Smax.romanov@nginx.com 
2836343Smax.romanov@nginx.com     } else {
2837*351Smax.romanov@nginx.com         ra = nxt_router_ra_create(task, ra);
2838*351Smax.romanov@nginx.com 
2839*351Smax.romanov@nginx.com         if (nxt_fast_path(ra != NULL)) {
2840*351Smax.romanov@nginx.com             nxt_queue_insert_tail(&app->requests, &ra->link);
2841*351Smax.romanov@nginx.com 
2842*351Smax.romanov@nginx.com             can_start_worker = (app->workers + app->pending_workers) <
2843*351Smax.romanov@nginx.com                                   app->max_workers;
2844*351Smax.romanov@nginx.com             if (can_start_worker) {
2845*351Smax.romanov@nginx.com                 app->pending_workers++;
2846*351Smax.romanov@nginx.com             }
2847343Smax.romanov@nginx.com         }
2848343Smax.romanov@nginx.com 
2849343Smax.romanov@nginx.com         port = NULL;
2850343Smax.romanov@nginx.com     }
2851343Smax.romanov@nginx.com 
2852343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
2853141Smax.romanov@nginx.com 
2854*351Smax.romanov@nginx.com     if (nxt_slow_path(ra == NULL)) {
2855*351Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 500, "Failed to allocate "
2856*351Smax.romanov@nginx.com                              "req<->app link");
2857*351Smax.romanov@nginx.com         return NXT_ERROR;
2858*351Smax.romanov@nginx.com     }
2859*351Smax.romanov@nginx.com 
2860141Smax.romanov@nginx.com     if (port != NULL) {
2861343Smax.romanov@nginx.com         nxt_debug(task, "already have port for app '%V' %p ", &app->name, app);
2862163Smax.romanov@nginx.com 
2863167Smax.romanov@nginx.com         ra->app_port = port;
2864343Smax.romanov@nginx.com 
2865343Smax.romanov@nginx.com         if (use_delta != 0) {
2866343Smax.romanov@nginx.com             nxt_port_use(task, port, use_delta);
2867343Smax.romanov@nginx.com         }
2868141Smax.romanov@nginx.com         return NXT_OK;
2869141Smax.romanov@nginx.com     }
2870141Smax.romanov@nginx.com 
2871*351Smax.romanov@nginx.com     nxt_debug(task, "ra stream #%uD allocated", ra->stream);
2872*351Smax.romanov@nginx.com 
2873343Smax.romanov@nginx.com     if (!can_start_worker) {
2874343Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p too many running or pending workers",
2875343Smax.romanov@nginx.com                   &app->name, app);
2876343Smax.romanov@nginx.com 
2877343Smax.romanov@nginx.com         return NXT_AGAIN;
2878343Smax.romanov@nginx.com     }
2879343Smax.romanov@nginx.com 
2880343Smax.romanov@nginx.com     res = nxt_router_start_worker(task, app);
2881343Smax.romanov@nginx.com 
2882343Smax.romanov@nginx.com     if (nxt_slow_path(res != NXT_OK)) {
2883343Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 500, "Failed to start worker");
2884343Smax.romanov@nginx.com 
2885141Smax.romanov@nginx.com         return NXT_ERROR;
2886141Smax.romanov@nginx.com     }
2887141Smax.romanov@nginx.com 
2888141Smax.romanov@nginx.com     return NXT_AGAIN;
288988Smax.romanov@nginx.com }
289088Smax.romanov@nginx.com 
289188Smax.romanov@nginx.com 
289288Smax.romanov@nginx.com static void
289353Sigor@sysoev.ru nxt_router_conn_http_header_parse(nxt_task_t *task, void *obj, void *data)
289453Sigor@sysoev.ru {
2895206Smax.romanov@nginx.com     size_t                    size;
289653Sigor@sysoev.ru     nxt_int_t                 ret;
2897206Smax.romanov@nginx.com     nxt_buf_t                 *buf;
289862Sigor@sysoev.ru     nxt_conn_t                *c;
2899268Sigor@sysoev.ru     nxt_sockaddr_t            *local;
290088Smax.romanov@nginx.com     nxt_app_parse_ctx_t       *ap;
2901206Smax.romanov@nginx.com     nxt_app_request_body_t    *b;
290253Sigor@sysoev.ru     nxt_socket_conf_joint_t   *joint;
290388Smax.romanov@nginx.com     nxt_app_request_header_t  *h;
290453Sigor@sysoev.ru 
290553Sigor@sysoev.ru     c = obj;
290688Smax.romanov@nginx.com     ap = data;
2907206Smax.romanov@nginx.com     buf = c->read;
2908206Smax.romanov@nginx.com     joint = c->listen->socket.data;
290953Sigor@sysoev.ru 
291053Sigor@sysoev.ru     nxt_debug(task, "router conn http header parse");
291153Sigor@sysoev.ru 
291288Smax.romanov@nginx.com     if (ap == NULL) {
2913319Smax.romanov@nginx.com         ap = nxt_app_http_req_init(task);
291488Smax.romanov@nginx.com         if (nxt_slow_path(ap == NULL)) {
2915319Smax.romanov@nginx.com             nxt_router_gen_error(task, c, 500,
2916319Smax.romanov@nginx.com                                  "Failed to allocate parse context");
291761Sigor@sysoev.ru             return;
291861Sigor@sysoev.ru         }
291988Smax.romanov@nginx.com 
292088Smax.romanov@nginx.com         c->socket.data = ap;
2921113Smax.romanov@nginx.com 
2922113Smax.romanov@nginx.com         ap->r.remote.start = nxt_sockaddr_address(c->remote);
2923113Smax.romanov@nginx.com         ap->r.remote.length = c->remote->address_length;
2924206Smax.romanov@nginx.com 
2925268Sigor@sysoev.ru         local = joint->socket_conf->sockaddr;
2926268Sigor@sysoev.ru         ap->r.local.start = nxt_sockaddr_address(local);
2927268Sigor@sysoev.ru         ap->r.local.length = local->address_length;
2928268Sigor@sysoev.ru 
2929206Smax.romanov@nginx.com         ap->r.header.buf = buf;
293053Sigor@sysoev.ru     }
293153Sigor@sysoev.ru 
293288Smax.romanov@nginx.com     h = &ap->r.header;
2933206Smax.romanov@nginx.com     b = &ap->r.body;
2934206Smax.romanov@nginx.com 
2935206Smax.romanov@nginx.com     ret = nxt_app_http_req_header_parse(task, ap, buf);
2936206Smax.romanov@nginx.com 
2937206Smax.romanov@nginx.com     nxt_debug(task, "http parse request header: %d", ret);
293853Sigor@sysoev.ru 
293953Sigor@sysoev.ru     switch (nxt_expect(NXT_DONE, ret)) {
294053Sigor@sysoev.ru 
294153Sigor@sysoev.ru     case NXT_DONE:
294288Smax.romanov@nginx.com         nxt_debug(task, "router request header parsing complete, "
294388Smax.romanov@nginx.com                   "content length: %O, preread: %uz",
2944206Smax.romanov@nginx.com                   h->parsed_content_length, nxt_buf_mem_used_size(&buf->mem));
2945206Smax.romanov@nginx.com 
2946206Smax.romanov@nginx.com         if (b->done) {
2947206Smax.romanov@nginx.com             nxt_router_process_http_request(task, c, ap);
2948206Smax.romanov@nginx.com 
2949206Smax.romanov@nginx.com             return;
2950206Smax.romanov@nginx.com         }
2951206Smax.romanov@nginx.com 
2952277Sigor@sysoev.ru         if (joint->socket_conf->max_body_size > 0
2953277Sigor@sysoev.ru             && (size_t) h->parsed_content_length
2954277Sigor@sysoev.ru                > joint->socket_conf->max_body_size)
2955277Sigor@sysoev.ru         {
2956206Smax.romanov@nginx.com             nxt_router_gen_error(task, c, 413, "Content-Length too big");
2957206Smax.romanov@nginx.com             return;
2958206Smax.romanov@nginx.com         }
2959206Smax.romanov@nginx.com 
2960206Smax.romanov@nginx.com         if (nxt_buf_mem_free_size(&buf->mem) == 0) {
2961206Smax.romanov@nginx.com             size = nxt_min(joint->socket_conf->body_buffer_size,
2962206Smax.romanov@nginx.com                            (size_t) h->parsed_content_length);
2963206Smax.romanov@nginx.com 
2964206Smax.romanov@nginx.com             buf->next = nxt_buf_mem_alloc(c->mem_pool, size, 0);
2965206Smax.romanov@nginx.com             if (nxt_slow_path(buf->next == NULL)) {
2966206Smax.romanov@nginx.com                 nxt_router_gen_error(task, c, 500, "Failed to allocate "
2967206Smax.romanov@nginx.com                                      "buffer for request body");
2968206Smax.romanov@nginx.com                 return;
2969206Smax.romanov@nginx.com             }
2970206Smax.romanov@nginx.com 
2971206Smax.romanov@nginx.com             c->read = buf->next;
2972206Smax.romanov@nginx.com 
2973206Smax.romanov@nginx.com             b->preread_size += nxt_buf_mem_used_size(&buf->mem);
2974206Smax.romanov@nginx.com         }
2975206Smax.romanov@nginx.com 
2976206Smax.romanov@nginx.com         if (b->buf == NULL) {
2977206Smax.romanov@nginx.com             b->buf = c->read;
2978206Smax.romanov@nginx.com         }
2979206Smax.romanov@nginx.com 
2980206Smax.romanov@nginx.com         c->read_state = &nxt_router_conn_read_body_state;
2981206Smax.romanov@nginx.com         break;
2982206Smax.romanov@nginx.com 
2983206Smax.romanov@nginx.com     case NXT_ERROR:
2984206Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 400, "Request header parse error");
2985206Smax.romanov@nginx.com         return;
2986206Smax.romanov@nginx.com 
2987206Smax.romanov@nginx.com     default:  /* NXT_AGAIN */
2988206Smax.romanov@nginx.com 
2989206Smax.romanov@nginx.com         if (c->read->mem.free == c->read->mem.end) {
2990206Smax.romanov@nginx.com             size = joint->socket_conf->large_header_buffer_size;
2991206Smax.romanov@nginx.com 
2992277Sigor@sysoev.ru             if (size <= (size_t) nxt_buf_mem_used_size(&buf->mem)
2993277Sigor@sysoev.ru                 || ap->r.header.bufs
2994277Sigor@sysoev.ru                    >= joint->socket_conf->large_header_buffers)
2995277Sigor@sysoev.ru             {
2996206Smax.romanov@nginx.com                 nxt_router_gen_error(task, c, 413,
2997206Smax.romanov@nginx.com                                      "Too long request headers");
2998206Smax.romanov@nginx.com                 return;
2999206Smax.romanov@nginx.com             }
3000206Smax.romanov@nginx.com 
3001206Smax.romanov@nginx.com             buf->next = nxt_buf_mem_alloc(c->mem_pool, size, 0);
3002206Smax.romanov@nginx.com             if (nxt_slow_path(buf->next == NULL)) {
3003206Smax.romanov@nginx.com                 nxt_router_gen_error(task, c, 500,
3004206Smax.romanov@nginx.com                                      "Failed to allocate large header "
3005206Smax.romanov@nginx.com                                      "buffer");
3006206Smax.romanov@nginx.com                 return;
3007206Smax.romanov@nginx.com             }
3008206Smax.romanov@nginx.com 
3009206Smax.romanov@nginx.com             ap->r.header.bufs++;
3010206Smax.romanov@nginx.com 
3011206Smax.romanov@nginx.com             size = c->read->mem.free - c->read->mem.pos;
3012206Smax.romanov@nginx.com 
3013206Smax.romanov@nginx.com             c->read = nxt_buf_cpy(buf->next, c->read->mem.pos, size);
3014206Smax.romanov@nginx.com         }
3015206Smax.romanov@nginx.com 
3016206Smax.romanov@nginx.com     }
3017206Smax.romanov@nginx.com 
3018206Smax.romanov@nginx.com     nxt_conn_read(task->thread->engine, c);
3019206Smax.romanov@nginx.com }
3020206Smax.romanov@nginx.com 
3021206Smax.romanov@nginx.com 
3022206Smax.romanov@nginx.com static void
3023206Smax.romanov@nginx.com nxt_router_conn_http_body_read(nxt_task_t *task, void *obj, void *data)
3024206Smax.romanov@nginx.com {
3025206Smax.romanov@nginx.com     size_t                    size;
3026206Smax.romanov@nginx.com     nxt_int_t                 ret;
3027206Smax.romanov@nginx.com     nxt_buf_t                 *buf;
3028206Smax.romanov@nginx.com     nxt_conn_t                *c;
3029206Smax.romanov@nginx.com     nxt_app_parse_ctx_t       *ap;
3030206Smax.romanov@nginx.com     nxt_app_request_body_t    *b;
3031206Smax.romanov@nginx.com     nxt_socket_conf_joint_t   *joint;
3032206Smax.romanov@nginx.com     nxt_app_request_header_t  *h;
3033206Smax.romanov@nginx.com 
3034206Smax.romanov@nginx.com     c = obj;
3035206Smax.romanov@nginx.com     ap = data;
3036206Smax.romanov@nginx.com     buf = c->read;
3037206Smax.romanov@nginx.com 
3038206Smax.romanov@nginx.com     nxt_debug(task, "router conn http body read");
3039206Smax.romanov@nginx.com 
3040206Smax.romanov@nginx.com     nxt_assert(ap != NULL);
3041206Smax.romanov@nginx.com 
3042206Smax.romanov@nginx.com     b = &ap->r.body;
3043206Smax.romanov@nginx.com     h = &ap->r.header;
3044206Smax.romanov@nginx.com 
3045206Smax.romanov@nginx.com     ret = nxt_app_http_req_body_read(task, ap, buf);
3046206Smax.romanov@nginx.com 
3047206Smax.romanov@nginx.com     nxt_debug(task, "http read request body: %d", ret);
3048206Smax.romanov@nginx.com 
3049206Smax.romanov@nginx.com     switch (nxt_expect(NXT_DONE, ret)) {
3050206Smax.romanov@nginx.com 
3051206Smax.romanov@nginx.com     case NXT_DONE:
305288Smax.romanov@nginx.com         nxt_router_process_http_request(task, c, ap);
305388Smax.romanov@nginx.com         return;
305453Sigor@sysoev.ru 
305553Sigor@sysoev.ru     case NXT_ERROR:
3056206Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 500, "Read body error");
305753Sigor@sysoev.ru         return;
305853Sigor@sysoev.ru 
305953Sigor@sysoev.ru     default:  /* NXT_AGAIN */
306053Sigor@sysoev.ru 
3061206Smax.romanov@nginx.com         if (nxt_buf_mem_free_size(&buf->mem) == 0) {
3062206Smax.romanov@nginx.com             joint = c->listen->socket.data;
3063206Smax.romanov@nginx.com 
3064206Smax.romanov@nginx.com             b->preread_size += nxt_buf_mem_used_size(&buf->mem);
3065206Smax.romanov@nginx.com 
3066206Smax.romanov@nginx.com             size = nxt_min(joint->socket_conf->body_buffer_size,
3067206Smax.romanov@nginx.com                            (size_t) h->parsed_content_length - b->preread_size);
3068206Smax.romanov@nginx.com 
3069206Smax.romanov@nginx.com             buf->next = nxt_buf_mem_alloc(c->mem_pool, size, 0);
3070206Smax.romanov@nginx.com             if (nxt_slow_path(buf->next == NULL)) {
3071206Smax.romanov@nginx.com                 nxt_router_gen_error(task, c, 500, "Failed to allocate "
3072206Smax.romanov@nginx.com                                      "buffer for request body");
3073206Smax.romanov@nginx.com                 return;
307488Smax.romanov@nginx.com             }
3075206Smax.romanov@nginx.com 
3076206Smax.romanov@nginx.com             c->read = buf->next;
307788Smax.romanov@nginx.com         }
307888Smax.romanov@nginx.com 
3079206Smax.romanov@nginx.com         nxt_debug(task, "router request body read again, rest: %uz",
3080206Smax.romanov@nginx.com                   h->parsed_content_length - b->preread_size);
308188Smax.romanov@nginx.com     }
308288Smax.romanov@nginx.com 
308388Smax.romanov@nginx.com     nxt_conn_read(task->thread->engine, c);
308488Smax.romanov@nginx.com }
308588Smax.romanov@nginx.com 
308688Smax.romanov@nginx.com 
308788Smax.romanov@nginx.com static void
308888Smax.romanov@nginx.com nxt_router_process_http_request(nxt_task_t *task, nxt_conn_t *c,
308988Smax.romanov@nginx.com     nxt_app_parse_ctx_t *ap)
309088Smax.romanov@nginx.com {
3091122Smax.romanov@nginx.com     nxt_int_t            res;
3092167Smax.romanov@nginx.com     nxt_port_t           *port;
309388Smax.romanov@nginx.com     nxt_event_engine_t   *engine;
3094*351Smax.romanov@nginx.com     nxt_req_app_link_t   ra_local, *ra;
309588Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
309688Smax.romanov@nginx.com 
309788Smax.romanov@nginx.com     engine = task->thread->engine;
309888Smax.romanov@nginx.com 
3099318Smax.romanov@nginx.com     rc = nxt_port_rpc_register_handler_ex(task, engine->port,
3100318Smax.romanov@nginx.com                                           nxt_router_response_ready_handler,
3101318Smax.romanov@nginx.com                                           nxt_router_response_error_handler,
3102318Smax.romanov@nginx.com                                           sizeof(nxt_req_conn_link_t));
3103122Smax.romanov@nginx.com 
310488Smax.romanov@nginx.com     if (nxt_slow_path(rc == NULL)) {
3105141Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 500, "Failed to allocate "
3106346Smax.romanov@nginx.com                              "req<->conn link");
3107141Smax.romanov@nginx.com 
3108141Smax.romanov@nginx.com         return;
310988Smax.romanov@nginx.com     }
311088Smax.romanov@nginx.com 
3111318Smax.romanov@nginx.com     rc->stream = nxt_port_rpc_ex_stream(rc);
3112318Smax.romanov@nginx.com     rc->conn = c;
3113318Smax.romanov@nginx.com 
3114318Smax.romanov@nginx.com     nxt_queue_insert_tail(&c->requests, &rc->link);
3115318Smax.romanov@nginx.com 
3116318Smax.romanov@nginx.com     nxt_debug(task, "stream #%uD linked to conn %p at engine %p",
3117318Smax.romanov@nginx.com               rc->stream, c, engine);
311853Sigor@sysoev.ru 
3119346Smax.romanov@nginx.com     rc->ap = ap;
3120346Smax.romanov@nginx.com     c->socket.data = NULL;
3121346Smax.romanov@nginx.com 
3122*351Smax.romanov@nginx.com     ra = &ra_local;
3123*351Smax.romanov@nginx.com     nxt_router_ra_init(task, ra, rc);
3124167Smax.romanov@nginx.com 
3125167Smax.romanov@nginx.com     res = nxt_router_app_port(task, ra);
3126141Smax.romanov@nginx.com 
3127141Smax.romanov@nginx.com     if (res != NXT_OK) {
3128141Smax.romanov@nginx.com         return;
3129141Smax.romanov@nginx.com     }
3130141Smax.romanov@nginx.com 
3131167Smax.romanov@nginx.com     port = ra->app_port;
3132141Smax.romanov@nginx.com 
3133141Smax.romanov@nginx.com     if (nxt_slow_path(port == NULL)) {
3134318Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 500, "Application port not found");
3135141Smax.romanov@nginx.com         return;
3136141Smax.romanov@nginx.com     }
3137141Smax.romanov@nginx.com 
3138318Smax.romanov@nginx.com     nxt_port_rpc_ex_set_peer(task, engine->port, rc, port->pid);
3139318Smax.romanov@nginx.com 
3140343Smax.romanov@nginx.com     nxt_router_process_http_request_mp(task, ra);
3141167Smax.romanov@nginx.com }
3142167Smax.romanov@nginx.com 
3143167Smax.romanov@nginx.com 
3144167Smax.romanov@nginx.com static void
3145343Smax.romanov@nginx.com nxt_router_process_http_request_mp(nxt_task_t *task, nxt_req_app_link_t *ra)
3146167Smax.romanov@nginx.com {
3147343Smax.romanov@nginx.com     uint32_t             request_failed;
3148167Smax.romanov@nginx.com     nxt_int_t            res;
3149343Smax.romanov@nginx.com     nxt_port_t           *port, *c_port, *reply_port;
3150167Smax.romanov@nginx.com     nxt_app_wmsg_t       wmsg;
3151167Smax.romanov@nginx.com     nxt_app_parse_ctx_t  *ap;
3152167Smax.romanov@nginx.com 
3153343Smax.romanov@nginx.com     nxt_assert(ra->app_port != NULL);
3154343Smax.romanov@nginx.com 
3155343Smax.romanov@nginx.com     port = ra->app_port;
3156167Smax.romanov@nginx.com     reply_port = ra->reply_port;
3157167Smax.romanov@nginx.com     ap = ra->ap;
3158141Smax.romanov@nginx.com 
3159343Smax.romanov@nginx.com     request_failed = 1;
3160343Smax.romanov@nginx.com 
3161141Smax.romanov@nginx.com     c_port = nxt_process_connected_port_find(port->process, reply_port->pid,
3162141Smax.romanov@nginx.com                                              reply_port->id);
3163141Smax.romanov@nginx.com     if (nxt_slow_path(c_port != reply_port)) {
3164141Smax.romanov@nginx.com         res = nxt_port_send_port(task, port, reply_port, 0);
3165122Smax.romanov@nginx.com 
3166122Smax.romanov@nginx.com         if (nxt_slow_path(res != NXT_OK)) {
3167345Smax.romanov@nginx.com             nxt_router_ra_error(task, ra, 500,
3168345Smax.romanov@nginx.com                                 "Failed to send reply port to application");
3169345Smax.romanov@nginx.com             ra = NULL;
3170343Smax.romanov@nginx.com             goto release_port;
3171122Smax.romanov@nginx.com         }
3172122Smax.romanov@nginx.com 
3173141Smax.romanov@nginx.com         nxt_process_connected_port_add(port->process, reply_port);
317488Smax.romanov@nginx.com     }
317588Smax.romanov@nginx.com 
317688Smax.romanov@nginx.com     wmsg.port = port;
317788Smax.romanov@nginx.com     wmsg.write = NULL;
317888Smax.romanov@nginx.com     wmsg.buf = &wmsg.write;
3179318Smax.romanov@nginx.com     wmsg.stream = ra->stream;
3180167Smax.romanov@nginx.com 
3181216Sigor@sysoev.ru     res = port->app->prepare_msg(task, &ap->r, &wmsg);
3182122Smax.romanov@nginx.com 
3183122Smax.romanov@nginx.com     if (nxt_slow_path(res != NXT_OK)) {
3184345Smax.romanov@nginx.com         nxt_router_ra_error(task, ra, 500,
3185345Smax.romanov@nginx.com                             "Failed to prepare message for application");
3186345Smax.romanov@nginx.com         ra = NULL;
3187343Smax.romanov@nginx.com         goto release_port;
3188122Smax.romanov@nginx.com     }
318988Smax.romanov@nginx.com 
319088Smax.romanov@nginx.com     nxt_debug(task, "about to send %d bytes buffer to worker port %d",
319188Smax.romanov@nginx.com                     nxt_buf_used_size(wmsg.write),
319288Smax.romanov@nginx.com                     wmsg.port->socket.fd);
319388Smax.romanov@nginx.com 
3194343Smax.romanov@nginx.com     request_failed = 0;
3195343Smax.romanov@nginx.com 
3196122Smax.romanov@nginx.com     res = nxt_port_socket_write(task, wmsg.port, NXT_PORT_MSG_DATA,
3197318Smax.romanov@nginx.com                                  -1, ra->stream, reply_port->id, wmsg.write);
3198122Smax.romanov@nginx.com 
3199122Smax.romanov@nginx.com     if (nxt_slow_path(res != NXT_OK)) {
3200345Smax.romanov@nginx.com         nxt_router_ra_error(task, ra, 500,
3201345Smax.romanov@nginx.com                             "Failed to send message to application");
3202345Smax.romanov@nginx.com         ra = NULL;
3203343Smax.romanov@nginx.com         goto release_port;
3204122Smax.romanov@nginx.com     }
3205343Smax.romanov@nginx.com 
3206343Smax.romanov@nginx.com release_port:
3207343Smax.romanov@nginx.com 
3208345Smax.romanov@nginx.com     nxt_router_app_port_release(task, port, request_failed, 0);
3209345Smax.romanov@nginx.com 
3210345Smax.romanov@nginx.com     if (ra != NULL) {
3211345Smax.romanov@nginx.com         if (request_failed != 0) {
3212345Smax.romanov@nginx.com             ra->app_port = 0;
3213345Smax.romanov@nginx.com         }
3214345Smax.romanov@nginx.com 
3215345Smax.romanov@nginx.com         nxt_router_ra_release(task, ra, ra->work.data);
3216343Smax.romanov@nginx.com     }
321753Sigor@sysoev.ru }
321853Sigor@sysoev.ru 
321953Sigor@sysoev.ru 
3220216Sigor@sysoev.ru static nxt_int_t
3221216Sigor@sysoev.ru nxt_python_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
3222216Sigor@sysoev.ru     nxt_app_wmsg_t *wmsg)
3223216Sigor@sysoev.ru {
3224216Sigor@sysoev.ru     nxt_int_t                 rc;
3225216Sigor@sysoev.ru     nxt_buf_t                 *b;
3226216Sigor@sysoev.ru     nxt_http_field_t          *field;
3227216Sigor@sysoev.ru     nxt_app_request_header_t  *h;
3228216Sigor@sysoev.ru 
3229216Sigor@sysoev.ru     static const nxt_str_t prefix = nxt_string("HTTP_");
3230216Sigor@sysoev.ru     static const nxt_str_t eof = nxt_null_string;
3231216Sigor@sysoev.ru 
3232216Sigor@sysoev.ru     h = &r->header;
3233216Sigor@sysoev.ru 
3234216Sigor@sysoev.ru #define RC(S)                                                                 \
3235216Sigor@sysoev.ru     do {                                                                      \
3236216Sigor@sysoev.ru         rc = (S);                                                             \
3237216Sigor@sysoev.ru         if (nxt_slow_path(rc != NXT_OK)) {                                    \
3238216Sigor@sysoev.ru             goto fail;                                                        \
3239216Sigor@sysoev.ru         }                                                                     \
3240216Sigor@sysoev.ru     } while(0)
3241216Sigor@sysoev.ru 
3242216Sigor@sysoev.ru #define NXT_WRITE(N)                                                          \
3243216Sigor@sysoev.ru     RC(nxt_app_msg_write_str(task, wmsg, N))
3244216Sigor@sysoev.ru 
3245216Sigor@sysoev.ru     /* TODO error handle, async mmap buffer assignment */
3246216Sigor@sysoev.ru 
3247216Sigor@sysoev.ru     NXT_WRITE(&h->method);
3248216Sigor@sysoev.ru     NXT_WRITE(&h->target);
3249277Sigor@sysoev.ru 
3250216Sigor@sysoev.ru     if (h->path.start == h->target.start) {
3251216Sigor@sysoev.ru         NXT_WRITE(&eof);
3252277Sigor@sysoev.ru 
3253216Sigor@sysoev.ru     } else {
3254216Sigor@sysoev.ru         NXT_WRITE(&h->path);
3255216Sigor@sysoev.ru     }
3256216Sigor@sysoev.ru 
3257216Sigor@sysoev.ru     if (h->query.start != NULL) {
3258216Sigor@sysoev.ru         RC(nxt_app_msg_write_size(task, wmsg,
3259216Sigor@sysoev.ru                                   h->query.start - h->target.start + 1));
3260216Sigor@sysoev.ru     } else {
3261216Sigor@sysoev.ru         RC(nxt_app_msg_write_size(task, wmsg, 0));
3262216Sigor@sysoev.ru     }
3263216Sigor@sysoev.ru 
3264216Sigor@sysoev.ru     NXT_WRITE(&h->version);
3265216Sigor@sysoev.ru 
3266216Sigor@sysoev.ru     NXT_WRITE(&r->remote);
3267268Sigor@sysoev.ru     NXT_WRITE(&r->local);
3268216Sigor@sysoev.ru 
3269216Sigor@sysoev.ru     NXT_WRITE(&h->host);
3270216Sigor@sysoev.ru     NXT_WRITE(&h->content_type);
3271216Sigor@sysoev.ru     NXT_WRITE(&h->content_length);
3272216Sigor@sysoev.ru 
3273216Sigor@sysoev.ru     nxt_list_each(field, h->fields) {
3274216Sigor@sysoev.ru         RC(nxt_app_msg_write_prefixed_upcase(task, wmsg,
3275216Sigor@sysoev.ru                                              &prefix, &field->name));
3276216Sigor@sysoev.ru         NXT_WRITE(&field->value);
3277216Sigor@sysoev.ru 
3278216Sigor@sysoev.ru     } nxt_list_loop;
3279216Sigor@sysoev.ru 
3280216Sigor@sysoev.ru     /* end-of-headers mark */
3281216Sigor@sysoev.ru     NXT_WRITE(&eof);
3282216Sigor@sysoev.ru 
3283216Sigor@sysoev.ru     RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size));
3284216Sigor@sysoev.ru 
3285216Sigor@sysoev.ru     for(b = r->body.buf; b != NULL; b = b->next) {
3286216Sigor@sysoev.ru         RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos,
3287216Sigor@sysoev.ru                                  nxt_buf_mem_used_size(&b->mem)));
3288216Sigor@sysoev.ru     }
3289216Sigor@sysoev.ru 
3290216Sigor@sysoev.ru #undef NXT_WRITE
3291216Sigor@sysoev.ru #undef RC
3292216Sigor@sysoev.ru 
3293216Sigor@sysoev.ru     return NXT_OK;
3294216Sigor@sysoev.ru 
3295216Sigor@sysoev.ru fail:
3296216Sigor@sysoev.ru 
3297216Sigor@sysoev.ru     return NXT_ERROR;
3298216Sigor@sysoev.ru }
3299216Sigor@sysoev.ru 
3300216Sigor@sysoev.ru 
3301216Sigor@sysoev.ru static nxt_int_t
3302216Sigor@sysoev.ru nxt_php_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
3303216Sigor@sysoev.ru     nxt_app_wmsg_t *wmsg)
3304216Sigor@sysoev.ru {
3305216Sigor@sysoev.ru     nxt_int_t                 rc;
3306216Sigor@sysoev.ru     nxt_buf_t                 *b;
3307305Smax.romanov@nginx.com     nxt_bool_t                method_is_post;
3308216Sigor@sysoev.ru     nxt_http_field_t          *field;
3309216Sigor@sysoev.ru     nxt_app_request_header_t  *h;
3310216Sigor@sysoev.ru 
3311216Sigor@sysoev.ru     static const nxt_str_t prefix = nxt_string("HTTP_");
3312216Sigor@sysoev.ru     static const nxt_str_t eof = nxt_null_string;
3313216Sigor@sysoev.ru 
3314216Sigor@sysoev.ru     h = &r->header;
3315216Sigor@sysoev.ru 
3316216Sigor@sysoev.ru #define RC(S)                                                                 \
3317216Sigor@sysoev.ru     do {                                                                      \
3318216Sigor@sysoev.ru         rc = (S);                                                             \
3319216Sigor@sysoev.ru         if (nxt_slow_path(rc != NXT_OK)) {                                    \
3320216Sigor@sysoev.ru             goto fail;                                                        \
3321216Sigor@sysoev.ru         }                                                                     \
3322216Sigor@sysoev.ru     } while(0)
3323216Sigor@sysoev.ru 
3324216Sigor@sysoev.ru #define NXT_WRITE(N)                                                          \
3325216Sigor@sysoev.ru     RC(nxt_app_msg_write_str(task, wmsg, N))
3326216Sigor@sysoev.ru 
3327216Sigor@sysoev.ru     /* TODO error handle, async mmap buffer assignment */
3328216Sigor@sysoev.ru 
3329216Sigor@sysoev.ru     NXT_WRITE(&h->method);
3330216Sigor@sysoev.ru     NXT_WRITE(&h->target);
3331277Sigor@sysoev.ru 
3332216Sigor@sysoev.ru     if (h->path.start == h->target.start) {
3333216Sigor@sysoev.ru         NXT_WRITE(&eof);
3334277Sigor@sysoev.ru 
3335216Sigor@sysoev.ru     } else {
3336216Sigor@sysoev.ru         NXT_WRITE(&h->path);
3337216Sigor@sysoev.ru     }
3338216Sigor@sysoev.ru 
3339216Sigor@sysoev.ru     if (h->query.start != NULL) {
3340216Sigor@sysoev.ru         RC(nxt_app_msg_write_size(task, wmsg,
3341216Sigor@sysoev.ru                                   h->query.start - h->target.start + 1));
3342216Sigor@sysoev.ru     } else {
3343216Sigor@sysoev.ru         RC(nxt_app_msg_write_size(task, wmsg, 0));
3344216Sigor@sysoev.ru     }
3345216Sigor@sysoev.ru 
3346216Sigor@sysoev.ru     NXT_WRITE(&h->version);
3347216Sigor@sysoev.ru 
3348216Sigor@sysoev.ru     // PHP_SELF
3349216Sigor@sysoev.ru     // SCRIPT_NAME
3350216Sigor@sysoev.ru     // SCRIPT_FILENAME
3351216Sigor@sysoev.ru     // DOCUMENT_ROOT
3352216Sigor@sysoev.ru 
3353216Sigor@sysoev.ru     NXT_WRITE(&r->remote);
3354268Sigor@sysoev.ru     NXT_WRITE(&r->local);
3355216Sigor@sysoev.ru 
3356216Sigor@sysoev.ru     NXT_WRITE(&h->host);
3357216Sigor@sysoev.ru     NXT_WRITE(&h->cookie);
3358216Sigor@sysoev.ru     NXT_WRITE(&h->content_type);
3359216Sigor@sysoev.ru     NXT_WRITE(&h->content_length);
3360216Sigor@sysoev.ru 
3361216Sigor@sysoev.ru     RC(nxt_app_msg_write_size(task, wmsg, h->parsed_content_length));
3362305Smax.romanov@nginx.com     RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size));
3363305Smax.romanov@nginx.com 
3364305Smax.romanov@nginx.com     method_is_post = h->method.length == 4 &&
3365305Smax.romanov@nginx.com                      h->method.start[0] == 'P' &&
3366305Smax.romanov@nginx.com                      h->method.start[1] == 'O' &&
3367305Smax.romanov@nginx.com                      h->method.start[2] == 'S' &&
3368305Smax.romanov@nginx.com                      h->method.start[3] == 'T';
3369305Smax.romanov@nginx.com 
3370305Smax.romanov@nginx.com     if (method_is_post) {
3371305Smax.romanov@nginx.com         for(b = r->body.buf; b != NULL; b = b->next) {
3372305Smax.romanov@nginx.com             RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos,
3373305Smax.romanov@nginx.com                                      nxt_buf_mem_used_size(&b->mem)));
3374305Smax.romanov@nginx.com         }
3375305Smax.romanov@nginx.com     }
3376216Sigor@sysoev.ru 
3377216Sigor@sysoev.ru     nxt_list_each(field, h->fields) {
3378216Sigor@sysoev.ru         RC(nxt_app_msg_write_prefixed_upcase(task, wmsg,
3379216Sigor@sysoev.ru                                              &prefix, &field->name));
3380216Sigor@sysoev.ru         NXT_WRITE(&field->value);
3381216Sigor@sysoev.ru 
3382216Sigor@sysoev.ru     } nxt_list_loop;
3383216Sigor@sysoev.ru 
3384216Sigor@sysoev.ru     /* end-of-headers mark */
3385216Sigor@sysoev.ru     NXT_WRITE(&eof);
3386216Sigor@sysoev.ru 
3387305Smax.romanov@nginx.com     if (!method_is_post) {
3388305Smax.romanov@nginx.com         for(b = r->body.buf; b != NULL; b = b->next) {
3389305Smax.romanov@nginx.com             RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos,
3390305Smax.romanov@nginx.com                                      nxt_buf_mem_used_size(&b->mem)));
3391305Smax.romanov@nginx.com         }
3392216Sigor@sysoev.ru     }
3393216Sigor@sysoev.ru 
3394216Sigor@sysoev.ru #undef NXT_WRITE
3395216Sigor@sysoev.ru #undef RC
3396216Sigor@sysoev.ru 
3397216Sigor@sysoev.ru     return NXT_OK;
3398216Sigor@sysoev.ru 
3399216Sigor@sysoev.ru fail:
3400216Sigor@sysoev.ru 
3401216Sigor@sysoev.ru     return NXT_ERROR;
3402216Sigor@sysoev.ru }
3403216Sigor@sysoev.ru 
3404216Sigor@sysoev.ru 
3405216Sigor@sysoev.ru static nxt_int_t
3406216Sigor@sysoev.ru nxt_go_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, nxt_app_wmsg_t *wmsg)
3407216Sigor@sysoev.ru {
3408216Sigor@sysoev.ru     nxt_int_t                 rc;
3409216Sigor@sysoev.ru     nxt_buf_t                 *b;
3410216Sigor@sysoev.ru     nxt_http_field_t          *field;
3411216Sigor@sysoev.ru     nxt_app_request_header_t  *h;
3412216Sigor@sysoev.ru 
3413216Sigor@sysoev.ru     static const nxt_str_t eof = nxt_null_string;
3414216Sigor@sysoev.ru 
3415216Sigor@sysoev.ru     h = &r->header;
3416216Sigor@sysoev.ru 
3417216Sigor@sysoev.ru #define RC(S)                                                                 \
3418216Sigor@sysoev.ru     do {                                                                      \
3419216Sigor@sysoev.ru         rc = (S);                                                             \
3420216Sigor@sysoev.ru         if (nxt_slow_path(rc != NXT_OK)) {                                    \
3421216Sigor@sysoev.ru             goto fail;                                                        \
3422216Sigor@sysoev.ru         }                                                                     \
3423216Sigor@sysoev.ru     } while(0)
3424216Sigor@sysoev.ru 
3425216Sigor@sysoev.ru #define NXT_WRITE(N)                                                          \
3426216Sigor@sysoev.ru     RC(nxt_app_msg_write_str(task, wmsg, N))
3427216Sigor@sysoev.ru 
3428216Sigor@sysoev.ru     /* TODO error handle, async mmap buffer assignment */
3429216Sigor@sysoev.ru 
3430216Sigor@sysoev.ru     NXT_WRITE(&h->method);
3431216Sigor@sysoev.ru     NXT_WRITE(&h->target);
3432277Sigor@sysoev.ru 
3433216Sigor@sysoev.ru     if (h->path.start == h->target.start) {
3434216Sigor@sysoev.ru         NXT_WRITE(&eof);
3435277Sigor@sysoev.ru 
3436216Sigor@sysoev.ru     } else {
3437216Sigor@sysoev.ru         NXT_WRITE(&h->path);
3438216Sigor@sysoev.ru     }
3439216Sigor@sysoev.ru 
3440216Sigor@sysoev.ru     if (h->query.start != NULL) {
3441216Sigor@sysoev.ru         RC(nxt_app_msg_write_size(task, wmsg,
3442216Sigor@sysoev.ru                                   h->query.start - h->target.start + 1));
3443216Sigor@sysoev.ru     } else {
3444216Sigor@sysoev.ru         RC(nxt_app_msg_write_size(task, wmsg, 0));
3445216Sigor@sysoev.ru     }
3446216Sigor@sysoev.ru 
3447216Sigor@sysoev.ru     NXT_WRITE(&h->version);
3448253Smax.romanov@nginx.com     NXT_WRITE(&r->remote);
3449216Sigor@sysoev.ru 
3450216Sigor@sysoev.ru     NXT_WRITE(&h->host);
3451216Sigor@sysoev.ru     NXT_WRITE(&h->cookie);
3452216Sigor@sysoev.ru     NXT_WRITE(&h->content_type);
3453216Sigor@sysoev.ru     NXT_WRITE(&h->content_length);
3454216Sigor@sysoev.ru 
3455216Sigor@sysoev.ru     RC(nxt_app_msg_write_size(task, wmsg, h->parsed_content_length));
3456216Sigor@sysoev.ru 
3457216Sigor@sysoev.ru     nxt_list_each(field, h->fields) {
3458216Sigor@sysoev.ru         NXT_WRITE(&field->name);
3459216Sigor@sysoev.ru         NXT_WRITE(&field->value);
3460216Sigor@sysoev.ru 
3461216Sigor@sysoev.ru     } nxt_list_loop;
3462216Sigor@sysoev.ru 
3463216Sigor@sysoev.ru     /* end-of-headers mark */
3464216Sigor@sysoev.ru     NXT_WRITE(&eof);
3465216Sigor@sysoev.ru 
3466216Sigor@sysoev.ru     RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size));
3467216Sigor@sysoev.ru 
3468216Sigor@sysoev.ru     for(b = r->body.buf; b != NULL; b = b->next) {
3469216Sigor@sysoev.ru         RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos,
3470216Sigor@sysoev.ru                                  nxt_buf_mem_used_size(&b->mem)));
3471216Sigor@sysoev.ru     }
3472216Sigor@sysoev.ru 
3473216Sigor@sysoev.ru #undef NXT_WRITE
3474216Sigor@sysoev.ru #undef RC
3475216Sigor@sysoev.ru 
3476216Sigor@sysoev.ru     return NXT_OK;
3477216Sigor@sysoev.ru 
3478216Sigor@sysoev.ru fail:
3479216Sigor@sysoev.ru 
3480216Sigor@sysoev.ru     return NXT_ERROR;
3481216Sigor@sysoev.ru }
3482216Sigor@sysoev.ru 
3483216Sigor@sysoev.ru 
348462Sigor@sysoev.ru static const nxt_conn_state_t  nxt_router_conn_close_state
348553Sigor@sysoev.ru     nxt_aligned(64) =
348653Sigor@sysoev.ru {
348753Sigor@sysoev.ru     .ready_handler = nxt_router_conn_free,
348853Sigor@sysoev.ru };
348953Sigor@sysoev.ru 
349053Sigor@sysoev.ru 
349153Sigor@sysoev.ru static void
349288Smax.romanov@nginx.com nxt_router_conn_ready(nxt_task_t *task, void *obj, void *data)
349388Smax.romanov@nginx.com {
349488Smax.romanov@nginx.com     nxt_buf_t         *b;
349588Smax.romanov@nginx.com     nxt_bool_t        last;
349688Smax.romanov@nginx.com     nxt_conn_t        *c;
349788Smax.romanov@nginx.com     nxt_work_queue_t  *wq;
349888Smax.romanov@nginx.com 
349988Smax.romanov@nginx.com     nxt_debug(task, "router conn ready %p", obj);
350088Smax.romanov@nginx.com 
350188Smax.romanov@nginx.com     c = obj;
350288Smax.romanov@nginx.com     b = c->write;
350388Smax.romanov@nginx.com 
350488Smax.romanov@nginx.com     wq = &task->thread->engine->fast_work_queue;
350588Smax.romanov@nginx.com 
350688Smax.romanov@nginx.com     last = 0;
350788Smax.romanov@nginx.com 
350888Smax.romanov@nginx.com     while (b != NULL) {
350988Smax.romanov@nginx.com         if (!nxt_buf_is_sync(b)) {
351088Smax.romanov@nginx.com             if (nxt_buf_used_size(b) > 0) {
351188Smax.romanov@nginx.com                 break;
351288Smax.romanov@nginx.com             }
351388Smax.romanov@nginx.com         }
351488Smax.romanov@nginx.com 
351588Smax.romanov@nginx.com         if (nxt_buf_is_last(b)) {
351688Smax.romanov@nginx.com             last = 1;
351788Smax.romanov@nginx.com         }
351888Smax.romanov@nginx.com 
351988Smax.romanov@nginx.com         nxt_work_queue_add(wq, b->completion_handler, task, b, b->parent);
352088Smax.romanov@nginx.com 
352188Smax.romanov@nginx.com         b = b->next;
352288Smax.romanov@nginx.com     }
352388Smax.romanov@nginx.com 
352488Smax.romanov@nginx.com     c->write = b;
352588Smax.romanov@nginx.com 
352688Smax.romanov@nginx.com     if (b != NULL) {
352788Smax.romanov@nginx.com         nxt_debug(task, "router conn %p has more data to write", obj);
352888Smax.romanov@nginx.com 
352988Smax.romanov@nginx.com         nxt_conn_write(task->thread->engine, c);
3530277Sigor@sysoev.ru 
353188Smax.romanov@nginx.com     } else {
353288Smax.romanov@nginx.com         nxt_debug(task, "router conn %p no more data to write, last = %d", obj,
353388Smax.romanov@nginx.com                   last);
353488Smax.romanov@nginx.com 
353588Smax.romanov@nginx.com         if (last != 0) {
353688Smax.romanov@nginx.com             nxt_debug(task, "enqueue router conn close %p (ready handler)", c);
353788Smax.romanov@nginx.com 
353888Smax.romanov@nginx.com             nxt_work_queue_add(wq, nxt_router_conn_close, task, c,
353988Smax.romanov@nginx.com                                c->socket.data);
354088Smax.romanov@nginx.com         }
354188Smax.romanov@nginx.com     }
354288Smax.romanov@nginx.com }
354388Smax.romanov@nginx.com 
354488Smax.romanov@nginx.com 
354588Smax.romanov@nginx.com static void
354653Sigor@sysoev.ru nxt_router_conn_close(nxt_task_t *task, void *obj, void *data)
354753Sigor@sysoev.ru {
354862Sigor@sysoev.ru     nxt_conn_t  *c;
354953Sigor@sysoev.ru 
355053Sigor@sysoev.ru     c = obj;
355153Sigor@sysoev.ru 
355253Sigor@sysoev.ru     nxt_debug(task, "router conn close");
355353Sigor@sysoev.ru 
355453Sigor@sysoev.ru     c->write_state = &nxt_router_conn_close_state;
355553Sigor@sysoev.ru 
355662Sigor@sysoev.ru     nxt_conn_close(task->thread->engine, c);
355753Sigor@sysoev.ru }
355853Sigor@sysoev.ru 
355953Sigor@sysoev.ru 
356053Sigor@sysoev.ru static void
3561164Smax.romanov@nginx.com nxt_router_conn_mp_cleanup(nxt_task_t *task, void *obj, void *data)
3562164Smax.romanov@nginx.com {
3563164Smax.romanov@nginx.com     nxt_socket_conf_joint_t  *joint;
3564164Smax.romanov@nginx.com 
3565164Smax.romanov@nginx.com     joint = obj;
3566164Smax.romanov@nginx.com 
3567164Smax.romanov@nginx.com     nxt_router_conf_release(task, joint);
3568164Smax.romanov@nginx.com }
3569164Smax.romanov@nginx.com 
3570164Smax.romanov@nginx.com 
3571164Smax.romanov@nginx.com static void
357253Sigor@sysoev.ru nxt_router_conn_free(nxt_task_t *task, void *obj, void *data)
357353Sigor@sysoev.ru {
357462Sigor@sysoev.ru     nxt_conn_t               *c;
3575337Sigor@sysoev.ru     nxt_event_engine_t       *engine;
357688Smax.romanov@nginx.com     nxt_req_conn_link_t      *rc;
3577319Smax.romanov@nginx.com     nxt_app_parse_ctx_t      *ap;
357853Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
357953Sigor@sysoev.ru 
358053Sigor@sysoev.ru     c = obj;
3581319Smax.romanov@nginx.com     ap = data;
358253Sigor@sysoev.ru 
358353Sigor@sysoev.ru     nxt_debug(task, "router conn close done");
358453Sigor@sysoev.ru 
3585319Smax.romanov@nginx.com     if (ap != NULL) {
3586319Smax.romanov@nginx.com         nxt_app_http_req_done(task, ap);
3587319Smax.romanov@nginx.com 
3588319Smax.romanov@nginx.com         c->socket.data = NULL;
3589319Smax.romanov@nginx.com     }
3590319Smax.romanov@nginx.com 
359188Smax.romanov@nginx.com     nxt_queue_each(rc, &c->requests, nxt_req_conn_link_t, link) {
359288Smax.romanov@nginx.com 
3593318Smax.romanov@nginx.com         nxt_debug(task, "conn %p close, stream #%uD", c, rc->stream);
359488Smax.romanov@nginx.com 
3595343Smax.romanov@nginx.com         nxt_router_rc_unlink(task, rc);
3596318Smax.romanov@nginx.com 
3597318Smax.romanov@nginx.com         nxt_port_rpc_cancel(task, task->thread->engine->port, rc->stream);
359888Smax.romanov@nginx.com 
359988Smax.romanov@nginx.com     } nxt_queue_loop;
360088Smax.romanov@nginx.com 
3601122Smax.romanov@nginx.com     nxt_queue_remove(&c->link);
3602122Smax.romanov@nginx.com 
3603337Sigor@sysoev.ru     engine = task->thread->engine;
3604337Sigor@sysoev.ru 
3605337Sigor@sysoev.ru     nxt_sockaddr_cache_free(engine, c);
3606337Sigor@sysoev.ru 
3607131Smax.romanov@nginx.com     joint = c->listen->socket.data;
3608131Smax.romanov@nginx.com 
3609337Sigor@sysoev.ru     nxt_mp_cleanup(c->mem_pool, nxt_router_conn_mp_cleanup,
3610337Sigor@sysoev.ru                    &engine->task, joint, NULL);
3611164Smax.romanov@nginx.com 
3612164Smax.romanov@nginx.com     nxt_mp_release(c->mem_pool, c);
361353Sigor@sysoev.ru }
361453Sigor@sysoev.ru 
361553Sigor@sysoev.ru 
361653Sigor@sysoev.ru static void
361753Sigor@sysoev.ru nxt_router_conn_error(nxt_task_t *task, void *obj, void *data)
361853Sigor@sysoev.ru {
361962Sigor@sysoev.ru     nxt_conn_t  *c;
362053Sigor@sysoev.ru 
362153Sigor@sysoev.ru     c = obj;
362253Sigor@sysoev.ru 
362353Sigor@sysoev.ru     nxt_debug(task, "router conn error");
362453Sigor@sysoev.ru 
3625273Smax.romanov@nginx.com     if (c->socket.fd != -1) {
3626273Smax.romanov@nginx.com         c->write_state = &nxt_router_conn_close_state;
3627273Smax.romanov@nginx.com 
3628273Smax.romanov@nginx.com         nxt_conn_close(task->thread->engine, c);
3629273Smax.romanov@nginx.com     }
363053Sigor@sysoev.ru }
363153Sigor@sysoev.ru 
363253Sigor@sysoev.ru 
363353Sigor@sysoev.ru static void
363453Sigor@sysoev.ru nxt_router_conn_timeout(nxt_task_t *task, void *obj, void *data)
363553Sigor@sysoev.ru {
363662Sigor@sysoev.ru     nxt_conn_t   *c;
363762Sigor@sysoev.ru     nxt_timer_t  *timer;
363853Sigor@sysoev.ru 
363953Sigor@sysoev.ru     timer = obj;
364053Sigor@sysoev.ru 
364153Sigor@sysoev.ru     nxt_debug(task, "router conn timeout");
364253Sigor@sysoev.ru 
364362Sigor@sysoev.ru     c = nxt_read_timer_conn(timer);
364453Sigor@sysoev.ru 
3645206Smax.romanov@nginx.com     if (c->read_state == &nxt_router_conn_read_header_state) {
3646206Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 408, "Read header timeout");
3647206Smax.romanov@nginx.com 
3648206Smax.romanov@nginx.com     } else {
3649206Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 408, "Read body timeout");
3650206Smax.romanov@nginx.com     }
365153Sigor@sysoev.ru }
365253Sigor@sysoev.ru 
365353Sigor@sysoev.ru 
3654318Smax.romanov@nginx.com static void
3655318Smax.romanov@nginx.com nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data)
3656318Smax.romanov@nginx.com {
3657318Smax.romanov@nginx.com     nxt_conn_t   *c;
3658318Smax.romanov@nginx.com     nxt_timer_t  *timer;
3659318Smax.romanov@nginx.com 
3660318Smax.romanov@nginx.com     timer = obj;
3661318Smax.romanov@nginx.com 
3662318Smax.romanov@nginx.com     nxt_debug(task, "router app timeout");
3663318Smax.romanov@nginx.com 
3664318Smax.romanov@nginx.com     c = nxt_read_timer_conn(timer);
3665318Smax.romanov@nginx.com 
3666318Smax.romanov@nginx.com     nxt_router_gen_error(task, c, 408, "Application timeout");
3667318Smax.romanov@nginx.com }
3668318Smax.romanov@nginx.com 
3669318Smax.romanov@nginx.com 
367053Sigor@sysoev.ru static nxt_msec_t
367162Sigor@sysoev.ru nxt_router_conn_timeout_value(nxt_conn_t *c, uintptr_t data)
367253Sigor@sysoev.ru {
367353Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
367453Sigor@sysoev.ru 
367553Sigor@sysoev.ru     joint = c->listen->socket.data;
367653Sigor@sysoev.ru 
367753Sigor@sysoev.ru     return nxt_value_at(nxt_msec_t, joint->socket_conf, data);
367853Sigor@sysoev.ru }
3679