xref: /unit/src/nxt_router.c (revision 315)
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 {
13133Sigor@sysoev.ru     nxt_str_t  type;
14133Sigor@sysoev.ru     uint32_t   workers;
15133Sigor@sysoev.ru } nxt_router_app_conf_t;
16133Sigor@sysoev.ru 
17133Sigor@sysoev.ru 
18133Sigor@sysoev.ru typedef struct {
19133Sigor@sysoev.ru     nxt_str_t  application;
20115Sigor@sysoev.ru } nxt_router_listener_conf_t;
21115Sigor@sysoev.ru 
22115Sigor@sysoev.ru 
23167Smax.romanov@nginx.com typedef struct nxt_req_app_link_s nxt_req_app_link_t;
24141Smax.romanov@nginx.com typedef struct nxt_start_worker_s nxt_start_worker_t;
25141Smax.romanov@nginx.com 
26141Smax.romanov@nginx.com struct nxt_start_worker_s {
27141Smax.romanov@nginx.com     nxt_app_t              *app;
28167Smax.romanov@nginx.com     nxt_req_app_link_t     *ra;
29141Smax.romanov@nginx.com 
30141Smax.romanov@nginx.com     nxt_work_t             work;
31141Smax.romanov@nginx.com };
32141Smax.romanov@nginx.com 
33141Smax.romanov@nginx.com 
34167Smax.romanov@nginx.com struct nxt_req_app_link_s {
35167Smax.romanov@nginx.com     nxt_req_id_t         req_id;
36167Smax.romanov@nginx.com     nxt_port_t           *app_port;
37167Smax.romanov@nginx.com     nxt_port_t           *reply_port;
38167Smax.romanov@nginx.com     nxt_app_parse_ctx_t  *ap;
39167Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
40167Smax.romanov@nginx.com 
41167Smax.romanov@nginx.com     nxt_queue_link_t     link; /* for nxt_app_t.requests */
42167Smax.romanov@nginx.com 
43167Smax.romanov@nginx.com     nxt_mp_t             *mem_pool;
44167Smax.romanov@nginx.com     nxt_work_t           work;
45167Smax.romanov@nginx.com };
46167Smax.romanov@nginx.com 
47167Smax.romanov@nginx.com 
48198Sigor@sysoev.ru typedef struct {
49198Sigor@sysoev.ru     nxt_socket_conf_t       *socket_conf;
50198Sigor@sysoev.ru     nxt_router_temp_conf_t  *temp_conf;
51198Sigor@sysoev.ru } nxt_socket_rpc_t;
52198Sigor@sysoev.ru 
53198Sigor@sysoev.ru 
54139Sigor@sysoev.ru static nxt_router_temp_conf_t *nxt_router_temp_conf(nxt_task_t *task);
55198Sigor@sysoev.ru static void nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data);
56198Sigor@sysoev.ru static void nxt_router_conf_ready(nxt_task_t *task,
57139Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
58139Sigor@sysoev.ru static void nxt_router_conf_error(nxt_task_t *task,
59139Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
60139Sigor@sysoev.ru static void nxt_router_conf_send(nxt_task_t *task,
61193Smax.romanov@nginx.com     nxt_router_temp_conf_t *tmcf, nxt_port_msg_type_t type);
6253Sigor@sysoev.ru static void nxt_router_listen_sockets_sort(nxt_router_t *router,
6353Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
6453Sigor@sysoev.ru 
65115Sigor@sysoev.ru static nxt_int_t nxt_router_conf_create(nxt_task_t *task,
66115Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, u_char *start, u_char *end);
67133Sigor@sysoev.ru static nxt_app_t *nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name);
68133Sigor@sysoev.ru static nxt_app_t *nxt_router_listener_application(nxt_router_temp_conf_t *tmcf,
69133Sigor@sysoev.ru     nxt_str_t *name);
70198Sigor@sysoev.ru static void nxt_router_listen_socket_rpc_create(nxt_task_t *task,
71198Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf);
72198Sigor@sysoev.ru static void nxt_router_listen_socket_ready(nxt_task_t *task,
73198Sigor@sysoev.ru     nxt_port_recv_msg_t *msg, void *data);
74198Sigor@sysoev.ru static void nxt_router_listen_socket_error(nxt_task_t *task,
75198Sigor@sysoev.ru     nxt_port_recv_msg_t *msg, void *data);
7665Sigor@sysoev.ru static nxt_socket_conf_t *nxt_router_socket_conf(nxt_task_t *task, nxt_mp_t *mp,
7765Sigor@sysoev.ru     nxt_sockaddr_t *sa);
7853Sigor@sysoev.ru 
7953Sigor@sysoev.ru static nxt_int_t nxt_router_engines_create(nxt_task_t *task,
8053Sigor@sysoev.ru     nxt_router_t *router, nxt_router_temp_conf_t *tmcf,
8153Sigor@sysoev.ru     const nxt_event_interface_t *interface);
82115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf,
83115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
84115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf,
85115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
86115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf,
87115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
88115Sigor@sysoev.ru static void nxt_router_engine_socket_count(nxt_queue_t *sockets);
89154Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf,
90154Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets,
91154Sigor@sysoev.ru     nxt_work_handler_t handler);
92313Sigor@sysoev.ru static nxt_int_t nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf,
93313Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
94139Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf,
95139Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets);
9653Sigor@sysoev.ru 
9753Sigor@sysoev.ru static nxt_int_t nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt,
9853Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
9953Sigor@sysoev.ru static nxt_int_t nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt,
10053Sigor@sysoev.ru     nxt_event_engine_t *engine);
101133Sigor@sysoev.ru static void nxt_router_apps_sort(nxt_router_t *router,
102133Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
10353Sigor@sysoev.ru 
104*315Sigor@sysoev.ru static void nxt_router_engines_post(nxt_router_t *router,
105*315Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
106*315Sigor@sysoev.ru static void nxt_router_engine_post(nxt_event_engine_t *engine,
107*315Sigor@sysoev.ru     nxt_work_t *jobs);
108277Sigor@sysoev.ru static void nxt_router_app_data_handler(nxt_task_t *task,
109277Sigor@sysoev.ru     nxt_port_recv_msg_t *msg);
11053Sigor@sysoev.ru 
11153Sigor@sysoev.ru static void nxt_router_thread_start(void *data);
11253Sigor@sysoev.ru static void nxt_router_listen_socket_create(nxt_task_t *task, void *obj,
11353Sigor@sysoev.ru     void *data);
11453Sigor@sysoev.ru static void nxt_router_listen_socket_update(nxt_task_t *task, void *obj,
11553Sigor@sysoev.ru     void *data);
11653Sigor@sysoev.ru static void nxt_router_listen_socket_delete(nxt_task_t *task, void *obj,
11753Sigor@sysoev.ru     void *data);
118313Sigor@sysoev.ru static void nxt_router_worker_thread_quit(nxt_task_t *task, void *obj,
119313Sigor@sysoev.ru     void *data);
12053Sigor@sysoev.ru static void nxt_router_listen_socket_close(nxt_task_t *task, void *obj,
12153Sigor@sysoev.ru     void *data);
12253Sigor@sysoev.ru static void nxt_router_listen_socket_release(nxt_task_t *task,
12353Sigor@sysoev.ru     nxt_socket_conf_joint_t *joint);
12453Sigor@sysoev.ru static void nxt_router_thread_exit_handler(nxt_task_t *task, void *obj,
12553Sigor@sysoev.ru     void *data);
12653Sigor@sysoev.ru static void nxt_router_conf_release(nxt_task_t *task,
12753Sigor@sysoev.ru     nxt_socket_conf_joint_t *joint);
12853Sigor@sysoev.ru 
129167Smax.romanov@nginx.com static void nxt_router_send_sw_request(nxt_task_t *task, void *obj,
130167Smax.romanov@nginx.com     void *data);
131167Smax.romanov@nginx.com static nxt_bool_t nxt_router_app_free(nxt_task_t *task, nxt_app_t *app);
132167Smax.romanov@nginx.com static nxt_port_t * nxt_router_app_get_port(nxt_app_t *app, uint32_t req_id);
133141Smax.romanov@nginx.com static void nxt_router_app_release_port(nxt_task_t *task, void *obj,
134141Smax.romanov@nginx.com     void *data);
135141Smax.romanov@nginx.com 
13653Sigor@sysoev.ru static void nxt_router_conn_init(nxt_task_t *task, void *obj, void *data);
13753Sigor@sysoev.ru static void nxt_router_conn_http_header_parse(nxt_task_t *task, void *obj,
13853Sigor@sysoev.ru     void *data);
139206Smax.romanov@nginx.com static void nxt_router_conn_http_body_read(nxt_task_t *task, void *obj,
140206Smax.romanov@nginx.com     void *data);
14188Smax.romanov@nginx.com static void nxt_router_process_http_request(nxt_task_t *task,
14288Smax.romanov@nginx.com     nxt_conn_t *c, nxt_app_parse_ctx_t *ap);
143141Smax.romanov@nginx.com static void nxt_router_process_http_request_mp(nxt_task_t *task,
144167Smax.romanov@nginx.com     nxt_req_app_link_t *ra, nxt_port_t *port);
145216Sigor@sysoev.ru static nxt_int_t nxt_python_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
146216Sigor@sysoev.ru     nxt_app_wmsg_t *wmsg);
147216Sigor@sysoev.ru static nxt_int_t nxt_php_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
148216Sigor@sysoev.ru     nxt_app_wmsg_t *wmsg);
149216Sigor@sysoev.ru static nxt_int_t nxt_go_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
150216Sigor@sysoev.ru     nxt_app_wmsg_t *wmsg);
15188Smax.romanov@nginx.com static void nxt_router_conn_ready(nxt_task_t *task, void *obj, void *data);
15253Sigor@sysoev.ru static void nxt_router_conn_close(nxt_task_t *task, void *obj, void *data);
15353Sigor@sysoev.ru static void nxt_router_conn_free(nxt_task_t *task, void *obj, void *data);
15453Sigor@sysoev.ru static void nxt_router_conn_error(nxt_task_t *task, void *obj, void *data);
15553Sigor@sysoev.ru static void nxt_router_conn_timeout(nxt_task_t *task, void *obj, void *data);
15662Sigor@sysoev.ru static nxt_msec_t nxt_router_conn_timeout_value(nxt_conn_t *c, uintptr_t data);
15720Sigor@sysoev.ru 
158141Smax.romanov@nginx.com static void nxt_router_gen_error(nxt_task_t *task, nxt_conn_t *c, int code,
159141Smax.romanov@nginx.com     const char* fmt, ...);
160141Smax.romanov@nginx.com 
161119Smax.romanov@nginx.com static nxt_router_t  *nxt_router;
16220Sigor@sysoev.ru 
163216Sigor@sysoev.ru 
164216Sigor@sysoev.ru static nxt_app_prepare_msg_t  nxt_app_prepare_msg[] = {
165216Sigor@sysoev.ru     nxt_python_prepare_msg,
166216Sigor@sysoev.ru     nxt_php_prepare_msg,
167216Sigor@sysoev.ru     nxt_go_prepare_msg,
168216Sigor@sysoev.ru };
169216Sigor@sysoev.ru 
170216Sigor@sysoev.ru 
17120Sigor@sysoev.ru nxt_int_t
172141Smax.romanov@nginx.com nxt_router_start(nxt_task_t *task, void *data)
17320Sigor@sysoev.ru {
174141Smax.romanov@nginx.com     nxt_int_t      ret;
175141Smax.romanov@nginx.com     nxt_router_t   *router;
176141Smax.romanov@nginx.com     nxt_runtime_t  *rt;
177141Smax.romanov@nginx.com 
178141Smax.romanov@nginx.com     rt = task->thread->runtime;
17953Sigor@sysoev.ru 
18088Smax.romanov@nginx.com     ret = nxt_app_http_init(task, rt);
18188Smax.romanov@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
18288Smax.romanov@nginx.com         return ret;
18388Smax.romanov@nginx.com     }
18488Smax.romanov@nginx.com 
18553Sigor@sysoev.ru     router = nxt_zalloc(sizeof(nxt_router_t));
18653Sigor@sysoev.ru     if (nxt_slow_path(router == NULL)) {
18753Sigor@sysoev.ru         return NXT_ERROR;
18853Sigor@sysoev.ru     }
18953Sigor@sysoev.ru 
19053Sigor@sysoev.ru     nxt_queue_init(&router->engines);
19153Sigor@sysoev.ru     nxt_queue_init(&router->sockets);
192133Sigor@sysoev.ru     nxt_queue_init(&router->apps);
19353Sigor@sysoev.ru 
194119Smax.romanov@nginx.com     nxt_router = router;
195119Smax.romanov@nginx.com 
196115Sigor@sysoev.ru     return NXT_OK;
197115Sigor@sysoev.ru }
198115Sigor@sysoev.ru 
199115Sigor@sysoev.ru 
200167Smax.romanov@nginx.com static nxt_start_worker_t *
201192Smax.romanov@nginx.com nxt_router_sw_create(nxt_task_t *task, nxt_app_t *app, nxt_req_app_link_t *ra)
202167Smax.romanov@nginx.com {
203240Sigor@sysoev.ru     nxt_port_t          *main_port;
204167Smax.romanov@nginx.com     nxt_runtime_t       *rt;
205167Smax.romanov@nginx.com     nxt_start_worker_t  *sw;
206167Smax.romanov@nginx.com 
207192Smax.romanov@nginx.com     sw = nxt_zalloc(sizeof(nxt_start_worker_t));
208167Smax.romanov@nginx.com 
209167Smax.romanov@nginx.com     if (nxt_slow_path(sw == NULL)) {
210167Smax.romanov@nginx.com         return NULL;
211167Smax.romanov@nginx.com     }
212167Smax.romanov@nginx.com 
213167Smax.romanov@nginx.com     sw->app = app;
214167Smax.romanov@nginx.com     sw->ra = ra;
215167Smax.romanov@nginx.com 
216192Smax.romanov@nginx.com     nxt_debug(task, "sw %p create, request #%uxD, app '%V' %p", sw,
217167Smax.romanov@nginx.com                     ra->req_id, &app->name, app);
218167Smax.romanov@nginx.com 
219167Smax.romanov@nginx.com     rt = task->thread->runtime;
220240Sigor@sysoev.ru     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
221167Smax.romanov@nginx.com 
222167Smax.romanov@nginx.com     sw->work.handler = nxt_router_send_sw_request;
223240Sigor@sysoev.ru     sw->work.task = &main_port->engine->task;
224167Smax.romanov@nginx.com     sw->work.obj = sw;
225167Smax.romanov@nginx.com     sw->work.data = task->thread->engine;
226167Smax.romanov@nginx.com     sw->work.next = NULL;
227167Smax.romanov@nginx.com 
228240Sigor@sysoev.ru     if (task->thread->engine != main_port->engine) {
229240Sigor@sysoev.ru         nxt_debug(task, "sw %p post send to main engine %p", sw,
230240Sigor@sysoev.ru                   main_port->engine);
231240Sigor@sysoev.ru 
232240Sigor@sysoev.ru         nxt_event_engine_post(main_port->engine, &sw->work);
233167Smax.romanov@nginx.com 
234167Smax.romanov@nginx.com     } else {
235167Smax.romanov@nginx.com         nxt_router_send_sw_request(task, sw, sw->work.data);
236167Smax.romanov@nginx.com     }
237167Smax.romanov@nginx.com 
238167Smax.romanov@nginx.com     return sw;
239167Smax.romanov@nginx.com }
240167Smax.romanov@nginx.com 
241167Smax.romanov@nginx.com 
242192Smax.romanov@nginx.com nxt_inline void
243192Smax.romanov@nginx.com nxt_router_sw_release(nxt_task_t *task, nxt_start_worker_t *sw)
244141Smax.romanov@nginx.com {
245192Smax.romanov@nginx.com     nxt_debug(task, "sw %p release", sw);
246192Smax.romanov@nginx.com 
247192Smax.romanov@nginx.com     nxt_free(sw);
248141Smax.romanov@nginx.com }
249141Smax.romanov@nginx.com 
250141Smax.romanov@nginx.com 
251167Smax.romanov@nginx.com static nxt_req_app_link_t *
252167Smax.romanov@nginx.com nxt_router_ra_create(nxt_task_t *task, nxt_req_conn_link_t *rc)
253167Smax.romanov@nginx.com {
254167Smax.romanov@nginx.com     nxt_mp_t            *mp;
255167Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
256167Smax.romanov@nginx.com 
257167Smax.romanov@nginx.com     mp = rc->conn->mem_pool;
258167Smax.romanov@nginx.com 
259167Smax.romanov@nginx.com     ra = nxt_mp_retain(mp, sizeof(nxt_req_app_link_t));
260167Smax.romanov@nginx.com 
261167Smax.romanov@nginx.com     if (nxt_slow_path(ra == NULL)) {
262167Smax.romanov@nginx.com         return NULL;
263167Smax.romanov@nginx.com     }
264167Smax.romanov@nginx.com 
265275Smax.romanov@nginx.com     nxt_debug(task, "ra #%uxD create", rc->req_id);
266167Smax.romanov@nginx.com 
267167Smax.romanov@nginx.com     nxt_memzero(ra, sizeof(nxt_req_app_link_t));
268167Smax.romanov@nginx.com 
269167Smax.romanov@nginx.com     ra->req_id = rc->req_id;
270167Smax.romanov@nginx.com     ra->app_port = NULL;
271167Smax.romanov@nginx.com     ra->rc = rc;
272167Smax.romanov@nginx.com 
273167Smax.romanov@nginx.com     ra->mem_pool = mp;
274167Smax.romanov@nginx.com 
275167Smax.romanov@nginx.com     ra->work.handler = NULL;
276167Smax.romanov@nginx.com     ra->work.task = &task->thread->engine->task;
277167Smax.romanov@nginx.com     ra->work.obj = ra;
278167Smax.romanov@nginx.com     ra->work.data = task->thread->engine;
279167Smax.romanov@nginx.com 
280167Smax.romanov@nginx.com     return ra;
281167Smax.romanov@nginx.com }
282167Smax.romanov@nginx.com 
283167Smax.romanov@nginx.com 
284167Smax.romanov@nginx.com static void
285167Smax.romanov@nginx.com nxt_router_ra_release(nxt_task_t *task, void *obj, void *data)
286167Smax.romanov@nginx.com {
287167Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
288167Smax.romanov@nginx.com     nxt_event_engine_t  *engine;
289167Smax.romanov@nginx.com 
290167Smax.romanov@nginx.com     ra = obj;
291167Smax.romanov@nginx.com     engine = data;
292167Smax.romanov@nginx.com 
293167Smax.romanov@nginx.com     if (task->thread->engine != engine) {
294167Smax.romanov@nginx.com         ra->work.handler = nxt_router_ra_release;
295167Smax.romanov@nginx.com         ra->work.task = &engine->task;
296167Smax.romanov@nginx.com         ra->work.next = NULL;
297167Smax.romanov@nginx.com 
298167Smax.romanov@nginx.com         nxt_debug(task, "ra #%uxD post release to %p", ra->req_id, engine);
299167Smax.romanov@nginx.com 
300167Smax.romanov@nginx.com         nxt_event_engine_post(engine, &ra->work);
301167Smax.romanov@nginx.com 
302167Smax.romanov@nginx.com         return;
303167Smax.romanov@nginx.com     }
304167Smax.romanov@nginx.com 
305167Smax.romanov@nginx.com     nxt_debug(task, "ra #%uxD release", ra->req_id);
306167Smax.romanov@nginx.com 
307167Smax.romanov@nginx.com     if (ra->app_port != NULL) {
308167Smax.romanov@nginx.com 
309264Smax.romanov@nginx.com         nxt_router_app_release_port(task, ra->app_port, ra->app_port->app);
310264Smax.romanov@nginx.com 
311264Smax.romanov@nginx.com #if 0
312264Smax.romanov@nginx.com         /* Uncomment to hold app port until complete response received. */
313167Smax.romanov@nginx.com         if (ra->rc->conn != NULL) {
314167Smax.romanov@nginx.com             ra->rc->app_port = ra->app_port;
315167Smax.romanov@nginx.com 
316167Smax.romanov@nginx.com         } else {
317167Smax.romanov@nginx.com             nxt_router_app_release_port(task, ra->app_port, ra->app_port->app);
318167Smax.romanov@nginx.com         }
319264Smax.romanov@nginx.com #endif
320167Smax.romanov@nginx.com     }
321167Smax.romanov@nginx.com 
322167Smax.romanov@nginx.com     nxt_mp_release(ra->mem_pool, ra);
323167Smax.romanov@nginx.com }
324167Smax.romanov@nginx.com 
325167Smax.romanov@nginx.com 
326141Smax.romanov@nginx.com void
327141Smax.romanov@nginx.com nxt_router_new_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
328141Smax.romanov@nginx.com {
329141Smax.romanov@nginx.com     nxt_port_new_port_handler(task, msg);
330141Smax.romanov@nginx.com 
331192Smax.romanov@nginx.com     if (msg->port_msg.stream == 0) {
332141Smax.romanov@nginx.com         return;
333141Smax.romanov@nginx.com     }
334141Smax.romanov@nginx.com 
335192Smax.romanov@nginx.com     if (msg->new_port == NULL || msg->new_port->type != NXT_PROCESS_WORKER) {
336192Smax.romanov@nginx.com         msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR;
337141Smax.romanov@nginx.com     }
338192Smax.romanov@nginx.com 
339192Smax.romanov@nginx.com     nxt_port_rpc_handler(task, msg);
340141Smax.romanov@nginx.com }
341141Smax.romanov@nginx.com 
342141Smax.romanov@nginx.com 
343139Sigor@sysoev.ru void
344139Sigor@sysoev.ru nxt_router_conf_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
345115Sigor@sysoev.ru {
346139Sigor@sysoev.ru     size_t                  dump_size;
347198Sigor@sysoev.ru     nxt_int_t               ret;
348139Sigor@sysoev.ru     nxt_buf_t               *b;
349139Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
350139Sigor@sysoev.ru 
351139Sigor@sysoev.ru     b = msg->buf;
352139Sigor@sysoev.ru 
353139Sigor@sysoev.ru     dump_size = nxt_buf_used_size(b);
354139Sigor@sysoev.ru 
355139Sigor@sysoev.ru     if (dump_size > 300) {
356139Sigor@sysoev.ru         dump_size = 300;
35753Sigor@sysoev.ru     }
35853Sigor@sysoev.ru 
359139Sigor@sysoev.ru     nxt_debug(task, "router conf data (%z): %*s",
360139Sigor@sysoev.ru               msg->size, dump_size, b->mem.pos);
361139Sigor@sysoev.ru 
362139Sigor@sysoev.ru     tmcf = nxt_router_temp_conf(task);
363139Sigor@sysoev.ru     if (nxt_slow_path(tmcf == NULL)) {
364139Sigor@sysoev.ru         return;
36553Sigor@sysoev.ru     }
36653Sigor@sysoev.ru 
367139Sigor@sysoev.ru     tmcf->conf->router = nxt_router;
368139Sigor@sysoev.ru     tmcf->stream = msg->port_msg.stream;
369139Sigor@sysoev.ru     tmcf->port = nxt_runtime_port_find(task->thread->runtime,
370198Sigor@sysoev.ru                                        msg->port_msg.pid,
371198Sigor@sysoev.ru                                        msg->port_msg.reply_port);
372198Sigor@sysoev.ru 
373198Sigor@sysoev.ru     ret = nxt_router_conf_create(task, tmcf, b->mem.pos, b->mem.free);
374198Sigor@sysoev.ru 
375198Sigor@sysoev.ru     if (nxt_fast_path(ret == NXT_OK)) {
376198Sigor@sysoev.ru         nxt_router_conf_apply(task, tmcf, NULL);
377198Sigor@sysoev.ru 
378198Sigor@sysoev.ru     } else {
379198Sigor@sysoev.ru         nxt_router_conf_error(task, tmcf);
380139Sigor@sysoev.ru     }
38153Sigor@sysoev.ru }
38253Sigor@sysoev.ru 
38353Sigor@sysoev.ru 
384192Smax.romanov@nginx.com void
385192Smax.romanov@nginx.com nxt_router_remove_pid_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
386192Smax.romanov@nginx.com {
387192Smax.romanov@nginx.com     nxt_port_remove_pid_handler(task, msg);
388192Smax.romanov@nginx.com 
389192Smax.romanov@nginx.com     if (msg->port_msg.stream == 0) {
390192Smax.romanov@nginx.com         return;
391192Smax.romanov@nginx.com     }
392192Smax.romanov@nginx.com 
393192Smax.romanov@nginx.com     msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR;
394192Smax.romanov@nginx.com 
395192Smax.romanov@nginx.com     nxt_port_rpc_handler(task, msg);
396192Smax.romanov@nginx.com }
397192Smax.romanov@nginx.com 
398192Smax.romanov@nginx.com 
39953Sigor@sysoev.ru static nxt_router_temp_conf_t *
400139Sigor@sysoev.ru nxt_router_temp_conf(nxt_task_t *task)
40153Sigor@sysoev.ru {
40265Sigor@sysoev.ru     nxt_mp_t                *mp, *tmp;
40353Sigor@sysoev.ru     nxt_router_conf_t       *rtcf;
40453Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
40553Sigor@sysoev.ru 
40665Sigor@sysoev.ru     mp = nxt_mp_create(1024, 128, 256, 32);
40753Sigor@sysoev.ru     if (nxt_slow_path(mp == NULL)) {
40853Sigor@sysoev.ru         return NULL;
40953Sigor@sysoev.ru     }
41053Sigor@sysoev.ru 
41165Sigor@sysoev.ru     rtcf = nxt_mp_zget(mp, sizeof(nxt_router_conf_t));
41253Sigor@sysoev.ru     if (nxt_slow_path(rtcf == NULL)) {
41353Sigor@sysoev.ru         goto fail;
41453Sigor@sysoev.ru     }
41553Sigor@sysoev.ru 
41653Sigor@sysoev.ru     rtcf->mem_pool = mp;
41753Sigor@sysoev.ru 
41865Sigor@sysoev.ru     tmp = nxt_mp_create(1024, 128, 256, 32);
41953Sigor@sysoev.ru     if (nxt_slow_path(tmp == NULL)) {
42053Sigor@sysoev.ru         goto fail;
42153Sigor@sysoev.ru     }
42253Sigor@sysoev.ru 
42365Sigor@sysoev.ru     tmcf = nxt_mp_zget(tmp, sizeof(nxt_router_temp_conf_t));
42453Sigor@sysoev.ru     if (nxt_slow_path(tmcf == NULL)) {
42553Sigor@sysoev.ru         goto temp_fail;
42653Sigor@sysoev.ru     }
42753Sigor@sysoev.ru 
42853Sigor@sysoev.ru     tmcf->mem_pool = tmp;
42953Sigor@sysoev.ru     tmcf->conf = rtcf;
430139Sigor@sysoev.ru     tmcf->count = 1;
431139Sigor@sysoev.ru     tmcf->engine = task->thread->engine;
43253Sigor@sysoev.ru 
43353Sigor@sysoev.ru     tmcf->engines = nxt_array_create(tmcf->mem_pool, 4,
43453Sigor@sysoev.ru                                      sizeof(nxt_router_engine_conf_t));
43553Sigor@sysoev.ru     if (nxt_slow_path(tmcf->engines == NULL)) {
43653Sigor@sysoev.ru         goto temp_fail;
43753Sigor@sysoev.ru     }
43853Sigor@sysoev.ru 
43953Sigor@sysoev.ru     nxt_queue_init(&tmcf->deleting);
44053Sigor@sysoev.ru     nxt_queue_init(&tmcf->keeping);
44153Sigor@sysoev.ru     nxt_queue_init(&tmcf->updating);
44253Sigor@sysoev.ru     nxt_queue_init(&tmcf->pending);
44353Sigor@sysoev.ru     nxt_queue_init(&tmcf->creating);
444133Sigor@sysoev.ru     nxt_queue_init(&tmcf->apps);
445133Sigor@sysoev.ru     nxt_queue_init(&tmcf->previous);
44653Sigor@sysoev.ru 
44753Sigor@sysoev.ru     return tmcf;
44853Sigor@sysoev.ru 
44953Sigor@sysoev.ru temp_fail:
45053Sigor@sysoev.ru 
45165Sigor@sysoev.ru     nxt_mp_destroy(tmp);
45253Sigor@sysoev.ru 
45353Sigor@sysoev.ru fail:
45453Sigor@sysoev.ru 
45565Sigor@sysoev.ru     nxt_mp_destroy(mp);
45653Sigor@sysoev.ru 
45753Sigor@sysoev.ru     return NULL;
45853Sigor@sysoev.ru }
45953Sigor@sysoev.ru 
46053Sigor@sysoev.ru 
461198Sigor@sysoev.ru static void
462198Sigor@sysoev.ru nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data)
463139Sigor@sysoev.ru {
464139Sigor@sysoev.ru     nxt_int_t                    ret;
465139Sigor@sysoev.ru     nxt_router_t                 *router;
466139Sigor@sysoev.ru     nxt_runtime_t                *rt;
467198Sigor@sysoev.ru     nxt_queue_link_t             *qlk;
468198Sigor@sysoev.ru     nxt_socket_conf_t            *skcf;
469198Sigor@sysoev.ru     nxt_router_temp_conf_t       *tmcf;
470139Sigor@sysoev.ru     const nxt_event_interface_t  *interface;
471139Sigor@sysoev.ru 
472198Sigor@sysoev.ru     tmcf = obj;
473198Sigor@sysoev.ru 
474198Sigor@sysoev.ru     qlk = nxt_queue_first(&tmcf->pending);
475198Sigor@sysoev.ru 
476198Sigor@sysoev.ru     if (qlk != nxt_queue_tail(&tmcf->pending)) {
477198Sigor@sysoev.ru         nxt_queue_remove(qlk);
478198Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->creating, qlk);
479198Sigor@sysoev.ru 
480198Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
481198Sigor@sysoev.ru 
482198Sigor@sysoev.ru         nxt_router_listen_socket_rpc_create(task, tmcf, skcf);
483198Sigor@sysoev.ru 
484198Sigor@sysoev.ru         return;
485139Sigor@sysoev.ru     }
486139Sigor@sysoev.ru 
487139Sigor@sysoev.ru     rt = task->thread->runtime;
488139Sigor@sysoev.ru 
489139Sigor@sysoev.ru     interface = nxt_service_get(rt->services, "engine", NULL);
490139Sigor@sysoev.ru 
491198Sigor@sysoev.ru     router = tmcf->conf->router;
492198Sigor@sysoev.ru 
493139Sigor@sysoev.ru     ret = nxt_router_engines_create(task, router, tmcf, interface);
494139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
495198Sigor@sysoev.ru         goto fail;
496139Sigor@sysoev.ru     }
497139Sigor@sysoev.ru 
498139Sigor@sysoev.ru     ret = nxt_router_threads_create(task, rt, tmcf);
499139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
500198Sigor@sysoev.ru         goto fail;
501139Sigor@sysoev.ru     }
502139Sigor@sysoev.ru 
503139Sigor@sysoev.ru     nxt_router_apps_sort(router, tmcf);
504139Sigor@sysoev.ru 
505*315Sigor@sysoev.ru     nxt_router_engines_post(router, tmcf);
506139Sigor@sysoev.ru 
507139Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->updating);
508139Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->creating);
509139Sigor@sysoev.ru 
510198Sigor@sysoev.ru     nxt_router_conf_ready(task, tmcf);
511198Sigor@sysoev.ru 
512198Sigor@sysoev.ru     return;
513198Sigor@sysoev.ru 
514198Sigor@sysoev.ru fail:
515198Sigor@sysoev.ru 
516198Sigor@sysoev.ru     nxt_router_conf_error(task, tmcf);
517198Sigor@sysoev.ru 
518198Sigor@sysoev.ru     return;
519139Sigor@sysoev.ru }
520139Sigor@sysoev.ru 
521139Sigor@sysoev.ru 
522139Sigor@sysoev.ru static void
523139Sigor@sysoev.ru nxt_router_conf_wait(nxt_task_t *task, void *obj, void *data)
524139Sigor@sysoev.ru {
525153Sigor@sysoev.ru     nxt_joint_job_t  *job;
526153Sigor@sysoev.ru 
527153Sigor@sysoev.ru     job = obj;
528153Sigor@sysoev.ru 
529198Sigor@sysoev.ru     nxt_router_conf_ready(task, job->tmcf);
530139Sigor@sysoev.ru }
531139Sigor@sysoev.ru 
532139Sigor@sysoev.ru 
533139Sigor@sysoev.ru static void
534198Sigor@sysoev.ru nxt_router_conf_ready(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
535139Sigor@sysoev.ru {
536139Sigor@sysoev.ru     nxt_debug(task, "temp conf count:%D", tmcf->count);
537139Sigor@sysoev.ru 
538139Sigor@sysoev.ru     if (--tmcf->count == 0) {
539193Smax.romanov@nginx.com         nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_READY_LAST);
540139Sigor@sysoev.ru     }
541139Sigor@sysoev.ru }
542139Sigor@sysoev.ru 
543139Sigor@sysoev.ru 
544139Sigor@sysoev.ru static void
545139Sigor@sysoev.ru nxt_router_conf_error(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
546139Sigor@sysoev.ru {
547148Sigor@sysoev.ru     nxt_socket_t       s;
548149Sigor@sysoev.ru     nxt_router_t       *router;
549148Sigor@sysoev.ru     nxt_queue_link_t   *qlk;
550148Sigor@sysoev.ru     nxt_socket_conf_t  *skcf;
551148Sigor@sysoev.ru 
552198Sigor@sysoev.ru     nxt_log(task, NXT_LOG_CRIT, "failed to apply new conf");
553198Sigor@sysoev.ru 
554148Sigor@sysoev.ru     for (qlk = nxt_queue_first(&tmcf->creating);
555148Sigor@sysoev.ru          qlk != nxt_queue_tail(&tmcf->creating);
556148Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
557148Sigor@sysoev.ru     {
558148Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
559148Sigor@sysoev.ru         s = skcf->listen.socket;
560148Sigor@sysoev.ru 
561148Sigor@sysoev.ru         if (s != -1) {
562148Sigor@sysoev.ru             nxt_socket_close(task, s);
563148Sigor@sysoev.ru         }
564148Sigor@sysoev.ru 
565148Sigor@sysoev.ru         nxt_free(skcf->socket);
566148Sigor@sysoev.ru     }
567148Sigor@sysoev.ru 
568149Sigor@sysoev.ru     router = tmcf->conf->router;
569149Sigor@sysoev.ru 
570149Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->keeping);
571149Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->deleting);
572149Sigor@sysoev.ru 
573148Sigor@sysoev.ru     // TODO: new engines and threads
574148Sigor@sysoev.ru 
575139Sigor@sysoev.ru     nxt_mp_destroy(tmcf->conf->mem_pool);
576139Sigor@sysoev.ru 
577193Smax.romanov@nginx.com     nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_ERROR);
578139Sigor@sysoev.ru }
579139Sigor@sysoev.ru 
580139Sigor@sysoev.ru 
581139Sigor@sysoev.ru static void
582139Sigor@sysoev.ru nxt_router_conf_send(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
583193Smax.romanov@nginx.com     nxt_port_msg_type_t type)
584139Sigor@sysoev.ru {
585193Smax.romanov@nginx.com     nxt_port_socket_write(task, tmcf->port, type, -1, tmcf->stream, 0, NULL);
586139Sigor@sysoev.ru }
587139Sigor@sysoev.ru 
588139Sigor@sysoev.ru 
589115Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_conf[] = {
590115Sigor@sysoev.ru     {
591133Sigor@sysoev.ru         nxt_string("listeners_threads"),
592115Sigor@sysoev.ru         NXT_CONF_MAP_INT32,
593115Sigor@sysoev.ru         offsetof(nxt_router_conf_t, threads),
594115Sigor@sysoev.ru     },
595115Sigor@sysoev.ru };
596115Sigor@sysoev.ru 
597115Sigor@sysoev.ru 
598133Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_app_conf[] = {
599115Sigor@sysoev.ru     {
600133Sigor@sysoev.ru         nxt_string("type"),
601115Sigor@sysoev.ru         NXT_CONF_MAP_STR,
602133Sigor@sysoev.ru         offsetof(nxt_router_app_conf_t, type),
603115Sigor@sysoev.ru     },
604115Sigor@sysoev.ru 
605115Sigor@sysoev.ru     {
606133Sigor@sysoev.ru         nxt_string("workers"),
607115Sigor@sysoev.ru         NXT_CONF_MAP_INT32,
608133Sigor@sysoev.ru         offsetof(nxt_router_app_conf_t, workers),
609133Sigor@sysoev.ru     },
610133Sigor@sysoev.ru };
611133Sigor@sysoev.ru 
612133Sigor@sysoev.ru 
613133Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_listener_conf[] = {
614133Sigor@sysoev.ru     {
615133Sigor@sysoev.ru         nxt_string("application"),
616133Sigor@sysoev.ru         NXT_CONF_MAP_STR,
617133Sigor@sysoev.ru         offsetof(nxt_router_listener_conf_t, application),
618115Sigor@sysoev.ru     },
619115Sigor@sysoev.ru };
620115Sigor@sysoev.ru 
621115Sigor@sysoev.ru 
622115Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_http_conf[] = {
623115Sigor@sysoev.ru     {
624115Sigor@sysoev.ru         nxt_string("header_buffer_size"),
625115Sigor@sysoev.ru         NXT_CONF_MAP_SIZE,
626115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, header_buffer_size),
627115Sigor@sysoev.ru     },
628115Sigor@sysoev.ru 
629115Sigor@sysoev.ru     {
630115Sigor@sysoev.ru         nxt_string("large_header_buffer_size"),
631115Sigor@sysoev.ru         NXT_CONF_MAP_SIZE,
632115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, large_header_buffer_size),
633115Sigor@sysoev.ru     },
634115Sigor@sysoev.ru 
635115Sigor@sysoev.ru     {
636206Smax.romanov@nginx.com         nxt_string("large_header_buffers"),
637206Smax.romanov@nginx.com         NXT_CONF_MAP_SIZE,
638206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, large_header_buffers),
639206Smax.romanov@nginx.com     },
640206Smax.romanov@nginx.com 
641206Smax.romanov@nginx.com     {
642206Smax.romanov@nginx.com         nxt_string("body_buffer_size"),
643206Smax.romanov@nginx.com         NXT_CONF_MAP_SIZE,
644206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, body_buffer_size),
645206Smax.romanov@nginx.com     },
646206Smax.romanov@nginx.com 
647206Smax.romanov@nginx.com     {
648206Smax.romanov@nginx.com         nxt_string("max_body_size"),
649206Smax.romanov@nginx.com         NXT_CONF_MAP_SIZE,
650206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, max_body_size),
651206Smax.romanov@nginx.com     },
652206Smax.romanov@nginx.com 
653206Smax.romanov@nginx.com     {
654115Sigor@sysoev.ru         nxt_string("header_read_timeout"),
655115Sigor@sysoev.ru         NXT_CONF_MAP_MSEC,
656115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, header_read_timeout),
657115Sigor@sysoev.ru     },
658206Smax.romanov@nginx.com 
659206Smax.romanov@nginx.com     {
660206Smax.romanov@nginx.com         nxt_string("body_read_timeout"),
661206Smax.romanov@nginx.com         NXT_CONF_MAP_MSEC,
662206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, body_read_timeout),
663206Smax.romanov@nginx.com     },
664115Sigor@sysoev.ru };
665115Sigor@sysoev.ru 
666115Sigor@sysoev.ru 
66753Sigor@sysoev.ru static nxt_int_t
668115Sigor@sysoev.ru nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
669115Sigor@sysoev.ru     u_char *start, u_char *end)
67053Sigor@sysoev.ru {
671133Sigor@sysoev.ru     u_char                      *p;
672133Sigor@sysoev.ru     size_t                      size;
673115Sigor@sysoev.ru     nxt_mp_t                    *mp;
674115Sigor@sysoev.ru     uint32_t                    next;
675115Sigor@sysoev.ru     nxt_int_t                   ret;
676115Sigor@sysoev.ru     nxt_str_t                   name;
677133Sigor@sysoev.ru     nxt_app_t                   *app, *prev;
678133Sigor@sysoev.ru     nxt_app_type_t              type;
679115Sigor@sysoev.ru     nxt_sockaddr_t              *sa;
680133Sigor@sysoev.ru     nxt_conf_value_t            *conf, *http;
681133Sigor@sysoev.ru     nxt_conf_value_t            *applications, *application;
682133Sigor@sysoev.ru     nxt_conf_value_t            *listeners, *listener;
683115Sigor@sysoev.ru     nxt_socket_conf_t           *skcf;
684216Sigor@sysoev.ru     nxt_app_lang_module_t       *lang;
685133Sigor@sysoev.ru     nxt_router_app_conf_t       apcf;
686115Sigor@sysoev.ru     nxt_router_listener_conf_t  lscf;
687115Sigor@sysoev.ru 
688115Sigor@sysoev.ru     static nxt_str_t  http_path = nxt_string("/http");
689133Sigor@sysoev.ru     static nxt_str_t  applications_path = nxt_string("/applications");
690115Sigor@sysoev.ru     static nxt_str_t  listeners_path = nxt_string("/listeners");
691115Sigor@sysoev.ru 
692208Svbart@nginx.com     conf = nxt_conf_json_parse(tmcf->mem_pool, start, end, NULL);
693115Sigor@sysoev.ru     if (conf == NULL) {
694115Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "configuration parsing error");
695115Sigor@sysoev.ru         return NXT_ERROR;
696115Sigor@sysoev.ru     }
697115Sigor@sysoev.ru 
698213Svbart@nginx.com     mp = tmcf->conf->mem_pool;
699213Svbart@nginx.com 
700213Svbart@nginx.com     ret = nxt_conf_map_object(mp, conf, nxt_router_conf,
701136Svbart@nginx.com                               nxt_nitems(nxt_router_conf), tmcf->conf);
702115Sigor@sysoev.ru     if (ret != NXT_OK) {
703133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "root map error");
704115Sigor@sysoev.ru         return NXT_ERROR;
705115Sigor@sysoev.ru     }
706115Sigor@sysoev.ru 
707117Sigor@sysoev.ru     if (tmcf->conf->threads == 0) {
708117Sigor@sysoev.ru         tmcf->conf->threads = nxt_ncpu;
709117Sigor@sysoev.ru     }
710117Sigor@sysoev.ru 
711133Sigor@sysoev.ru     applications = nxt_conf_get_path(conf, &applications_path);
712133Sigor@sysoev.ru     if (applications == NULL) {
713133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "no \"applications\" block");
714115Sigor@sysoev.ru         return NXT_ERROR;
715115Sigor@sysoev.ru     }
716115Sigor@sysoev.ru 
717133Sigor@sysoev.ru     next = 0;
718133Sigor@sysoev.ru 
719133Sigor@sysoev.ru     for ( ;; ) {
720133Sigor@sysoev.ru         application = nxt_conf_next_object_member(applications, &name, &next);
721133Sigor@sysoev.ru         if (application == NULL) {
722133Sigor@sysoev.ru             break;
723133Sigor@sysoev.ru         }
724133Sigor@sysoev.ru 
725133Sigor@sysoev.ru         nxt_debug(task, "application \"%V\"", &name);
726133Sigor@sysoev.ru 
727144Smax.romanov@nginx.com         size = nxt_conf_json_length(application, NULL);
728144Smax.romanov@nginx.com 
729144Smax.romanov@nginx.com         app = nxt_malloc(sizeof(nxt_app_t) + name.length + size);
730133Sigor@sysoev.ru         if (app == NULL) {
731133Sigor@sysoev.ru             goto fail;
732133Sigor@sysoev.ru         }
733133Sigor@sysoev.ru 
734144Smax.romanov@nginx.com         nxt_memzero(app, sizeof(nxt_app_t));
735144Smax.romanov@nginx.com 
736144Smax.romanov@nginx.com         app->name.start = nxt_pointer_to(app, sizeof(nxt_app_t));
737144Smax.romanov@nginx.com         app->conf.start = nxt_pointer_to(app, sizeof(nxt_app_t) + name.length);
738133Sigor@sysoev.ru 
739133Sigor@sysoev.ru         p = nxt_conf_json_print(app->conf.start, application, NULL);
740133Sigor@sysoev.ru         app->conf.length = p - app->conf.start;
741133Sigor@sysoev.ru 
742144Smax.romanov@nginx.com         nxt_assert(app->conf.length <= size);
743144Smax.romanov@nginx.com 
744133Sigor@sysoev.ru         nxt_debug(task, "application conf \"%V\"", &app->conf);
745133Sigor@sysoev.ru 
746133Sigor@sysoev.ru         prev = nxt_router_app_find(&tmcf->conf->router->apps, &name);
747133Sigor@sysoev.ru 
748133Sigor@sysoev.ru         if (prev != NULL && nxt_strstr_eq(&app->conf, &prev->conf)) {
749133Sigor@sysoev.ru             nxt_free(app);
750133Sigor@sysoev.ru 
751133Sigor@sysoev.ru             nxt_queue_remove(&prev->link);
752133Sigor@sysoev.ru             nxt_queue_insert_tail(&tmcf->previous, &prev->link);
753133Sigor@sysoev.ru             continue;
754133Sigor@sysoev.ru         }
755133Sigor@sysoev.ru 
756263Smax.romanov@nginx.com         apcf.workers = 1;
757263Smax.romanov@nginx.com 
758213Svbart@nginx.com         ret = nxt_conf_map_object(mp, application, nxt_router_app_conf,
759136Svbart@nginx.com                                   nxt_nitems(nxt_router_app_conf), &apcf);
760133Sigor@sysoev.ru         if (ret != NXT_OK) {
761133Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "application map error");
762133Sigor@sysoev.ru             goto app_fail;
763133Sigor@sysoev.ru         }
764115Sigor@sysoev.ru 
765133Sigor@sysoev.ru         nxt_debug(task, "application type: %V", &apcf.type);
766133Sigor@sysoev.ru         nxt_debug(task, "application workers: %D", apcf.workers);
767133Sigor@sysoev.ru 
768216Sigor@sysoev.ru         lang = nxt_app_lang_module(task->thread->runtime, &apcf.type);
769216Sigor@sysoev.ru 
770216Sigor@sysoev.ru         if (lang == NULL) {
771141Smax.romanov@nginx.com             nxt_log(task, NXT_LOG_CRIT, "unknown application type: \"%V\"",
772141Smax.romanov@nginx.com                     &apcf.type);
773141Smax.romanov@nginx.com             goto app_fail;
774141Smax.romanov@nginx.com         }
775141Smax.romanov@nginx.com 
776216Sigor@sysoev.ru         nxt_debug(task, "application language module: \"%s\"", lang->file);
777216Sigor@sysoev.ru 
778216Sigor@sysoev.ru         type = nxt_app_parse_type(&lang->type);
779216Sigor@sysoev.ru 
780216Sigor@sysoev.ru         if (type == NXT_APP_UNKNOWN) {
781216Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "unknown application type: \"%V\"",
782216Sigor@sysoev.ru                     &lang->type);
783216Sigor@sysoev.ru             goto app_fail;
784216Sigor@sysoev.ru         }
785216Sigor@sysoev.ru 
786216Sigor@sysoev.ru         if (nxt_app_prepare_msg[type] == NULL) {
787133Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "unsupported application type: \"%V\"",
788216Sigor@sysoev.ru                     &lang->type);
789133Sigor@sysoev.ru             goto app_fail;
790133Sigor@sysoev.ru         }
791133Sigor@sysoev.ru 
792133Sigor@sysoev.ru         ret = nxt_thread_mutex_create(&app->mutex);
793133Sigor@sysoev.ru         if (ret != NXT_OK) {
794133Sigor@sysoev.ru             goto app_fail;
795133Sigor@sysoev.ru         }
796133Sigor@sysoev.ru 
797141Smax.romanov@nginx.com         nxt_queue_init(&app->ports);
798141Smax.romanov@nginx.com         nxt_queue_init(&app->requests);
799141Smax.romanov@nginx.com 
800144Smax.romanov@nginx.com         app->name.length = name.length;
801144Smax.romanov@nginx.com         nxt_memcpy(app->name.start, name.start, name.length);
802144Smax.romanov@nginx.com 
803133Sigor@sysoev.ru         app->type = type;
804133Sigor@sysoev.ru         app->max_workers = apcf.workers;
805133Sigor@sysoev.ru         app->live = 1;
806216Sigor@sysoev.ru         app->prepare_msg = nxt_app_prepare_msg[type];
807133Sigor@sysoev.ru 
808133Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->apps, &app->link);
809133Sigor@sysoev.ru     }
810133Sigor@sysoev.ru 
811133Sigor@sysoev.ru     http = nxt_conf_get_path(conf, &http_path);
812133Sigor@sysoev.ru #if 0
813133Sigor@sysoev.ru     if (http == NULL) {
814133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "no \"http\" block");
815133Sigor@sysoev.ru         return NXT_ERROR;
816133Sigor@sysoev.ru     }
817133Sigor@sysoev.ru #endif
818133Sigor@sysoev.ru 
819133Sigor@sysoev.ru     listeners = nxt_conf_get_path(conf, &listeners_path);
820115Sigor@sysoev.ru     if (listeners == NULL) {
821133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "no \"listeners\" block");
822115Sigor@sysoev.ru         return NXT_ERROR;
823115Sigor@sysoev.ru     }
82453Sigor@sysoev.ru 
825133Sigor@sysoev.ru     next = 0;
82653Sigor@sysoev.ru 
827115Sigor@sysoev.ru     for ( ;; ) {
828115Sigor@sysoev.ru         listener = nxt_conf_next_object_member(listeners, &name, &next);
829115Sigor@sysoev.ru         if (listener == NULL) {
830115Sigor@sysoev.ru             break;
831115Sigor@sysoev.ru         }
83253Sigor@sysoev.ru 
833115Sigor@sysoev.ru         sa = nxt_sockaddr_parse(mp, &name);
834115Sigor@sysoev.ru         if (sa == NULL) {
835115Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "invalid listener \"%V\"", &name);
836133Sigor@sysoev.ru             goto fail;
837115Sigor@sysoev.ru         }
838115Sigor@sysoev.ru 
839115Sigor@sysoev.ru         sa->type = SOCK_STREAM;
840115Sigor@sysoev.ru 
841115Sigor@sysoev.ru         nxt_debug(task, "router listener: \"%*s\"",
842115Sigor@sysoev.ru                   sa->length, nxt_sockaddr_start(sa));
84353Sigor@sysoev.ru 
844115Sigor@sysoev.ru         skcf = nxt_router_socket_conf(task, mp, sa);
845115Sigor@sysoev.ru         if (skcf == NULL) {
846133Sigor@sysoev.ru             goto fail;
847115Sigor@sysoev.ru         }
84853Sigor@sysoev.ru 
849213Svbart@nginx.com         ret = nxt_conf_map_object(mp, listener, nxt_router_listener_conf,
850136Svbart@nginx.com                                   nxt_nitems(nxt_router_listener_conf), &lscf);
851115Sigor@sysoev.ru         if (ret != NXT_OK) {
852115Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "listener map error");
853133Sigor@sysoev.ru             goto fail;
854115Sigor@sysoev.ru         }
85553Sigor@sysoev.ru 
856133Sigor@sysoev.ru         nxt_debug(task, "application: %V", &lscf.application);
857133Sigor@sysoev.ru 
858133Sigor@sysoev.ru         // STUB, default values if http block is not defined.
859133Sigor@sysoev.ru         skcf->header_buffer_size = 2048;
860133Sigor@sysoev.ru         skcf->large_header_buffer_size = 8192;
861206Smax.romanov@nginx.com         skcf->large_header_buffers = 4;
862206Smax.romanov@nginx.com         skcf->body_buffer_size = 16 * 1024;
863206Smax.romanov@nginx.com         skcf->max_body_size = 2 * 1024 * 1024;
864133Sigor@sysoev.ru         skcf->header_read_timeout = 5000;
865206Smax.romanov@nginx.com         skcf->body_read_timeout = 5000;
86653Sigor@sysoev.ru 
867133Sigor@sysoev.ru         if (http != NULL) {
868213Svbart@nginx.com             ret = nxt_conf_map_object(mp, http, nxt_router_http_conf,
869136Svbart@nginx.com                                       nxt_nitems(nxt_router_http_conf), skcf);
870133Sigor@sysoev.ru             if (ret != NXT_OK) {
871133Sigor@sysoev.ru                 nxt_log(task, NXT_LOG_CRIT, "http map error");
872133Sigor@sysoev.ru                 goto fail;
873133Sigor@sysoev.ru             }
874115Sigor@sysoev.ru         }
875115Sigor@sysoev.ru 
876115Sigor@sysoev.ru         skcf->listen.handler = nxt_router_conn_init;
877115Sigor@sysoev.ru         skcf->router_conf = tmcf->conf;
878160Sigor@sysoev.ru         skcf->router_conf->count++;
879133Sigor@sysoev.ru         skcf->application = nxt_router_listener_application(tmcf,
880133Sigor@sysoev.ru                                                             &lscf.application);
881115Sigor@sysoev.ru 
882115Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->pending, &skcf->link);
883115Sigor@sysoev.ru     }
88453Sigor@sysoev.ru 
885198Sigor@sysoev.ru     nxt_router_listen_sockets_sort(tmcf->conf->router, tmcf);
886198Sigor@sysoev.ru 
88753Sigor@sysoev.ru     return NXT_OK;
888133Sigor@sysoev.ru 
889133Sigor@sysoev.ru app_fail:
890133Sigor@sysoev.ru 
891133Sigor@sysoev.ru     nxt_free(app);
892133Sigor@sysoev.ru 
893133Sigor@sysoev.ru fail:
894133Sigor@sysoev.ru 
895141Smax.romanov@nginx.com     nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) {
896141Smax.romanov@nginx.com 
897141Smax.romanov@nginx.com         nxt_queue_remove(&app->link);
898133Sigor@sysoev.ru         nxt_thread_mutex_destroy(&app->mutex);
899133Sigor@sysoev.ru         nxt_free(app);
900141Smax.romanov@nginx.com 
901141Smax.romanov@nginx.com     } nxt_queue_loop;
902133Sigor@sysoev.ru 
903133Sigor@sysoev.ru     return NXT_ERROR;
904133Sigor@sysoev.ru }
905133Sigor@sysoev.ru 
906133Sigor@sysoev.ru 
907133Sigor@sysoev.ru static nxt_app_t *
908133Sigor@sysoev.ru nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name)
909133Sigor@sysoev.ru {
910141Smax.romanov@nginx.com     nxt_app_t  *app;
911141Smax.romanov@nginx.com 
912141Smax.romanov@nginx.com     nxt_queue_each(app, queue, nxt_app_t, link) {
913133Sigor@sysoev.ru 
914133Sigor@sysoev.ru         if (nxt_strstr_eq(name, &app->name)) {
915133Sigor@sysoev.ru             return app;
916133Sigor@sysoev.ru         }
917141Smax.romanov@nginx.com 
918141Smax.romanov@nginx.com     } nxt_queue_loop;
919133Sigor@sysoev.ru 
920133Sigor@sysoev.ru     return NULL;
921133Sigor@sysoev.ru }
922133Sigor@sysoev.ru 
923133Sigor@sysoev.ru 
924133Sigor@sysoev.ru static nxt_app_t *
925133Sigor@sysoev.ru nxt_router_listener_application(nxt_router_temp_conf_t *tmcf, nxt_str_t *name)
926133Sigor@sysoev.ru {
927133Sigor@sysoev.ru     nxt_app_t  *app;
928133Sigor@sysoev.ru 
929133Sigor@sysoev.ru     app = nxt_router_app_find(&tmcf->apps, name);
930133Sigor@sysoev.ru 
931133Sigor@sysoev.ru     if (app == NULL) {
932134Sigor@sysoev.ru         app = nxt_router_app_find(&tmcf->previous, name);
933133Sigor@sysoev.ru     }
934133Sigor@sysoev.ru 
935133Sigor@sysoev.ru     return app;
93653Sigor@sysoev.ru }
93753Sigor@sysoev.ru 
93853Sigor@sysoev.ru 
93953Sigor@sysoev.ru static nxt_socket_conf_t *
94065Sigor@sysoev.ru nxt_router_socket_conf(nxt_task_t *task, nxt_mp_t *mp, nxt_sockaddr_t *sa)
94153Sigor@sysoev.ru {
942163Smax.romanov@nginx.com     nxt_socket_conf_t  *skcf;
943163Smax.romanov@nginx.com 
944163Smax.romanov@nginx.com     skcf = nxt_mp_zget(mp, sizeof(nxt_socket_conf_t));
945163Smax.romanov@nginx.com     if (nxt_slow_path(skcf == NULL)) {
94653Sigor@sysoev.ru         return NULL;
94753Sigor@sysoev.ru     }
94853Sigor@sysoev.ru 
949163Smax.romanov@nginx.com     skcf->sockaddr = sa;
950163Smax.romanov@nginx.com 
951163Smax.romanov@nginx.com     skcf->listen.sockaddr = sa;
952312Sigor@sysoev.ru 
953312Sigor@sysoev.ru     nxt_listen_socket_remote_size(&skcf->listen, sa);
954163Smax.romanov@nginx.com 
955163Smax.romanov@nginx.com     skcf->listen.socket = -1;
956163Smax.romanov@nginx.com     skcf->listen.backlog = NXT_LISTEN_BACKLOG;
957163Smax.romanov@nginx.com     skcf->listen.flags = NXT_NONBLOCK;
958163Smax.romanov@nginx.com     skcf->listen.read_after_accept = 1;
959163Smax.romanov@nginx.com 
960163Smax.romanov@nginx.com     return skcf;
96153Sigor@sysoev.ru }
96253Sigor@sysoev.ru 
96353Sigor@sysoev.ru 
96453Sigor@sysoev.ru static void
96553Sigor@sysoev.ru nxt_router_listen_sockets_sort(nxt_router_t *router,
96653Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf)
96753Sigor@sysoev.ru {
96853Sigor@sysoev.ru     nxt_queue_link_t   *nqlk, *oqlk, *next;
96953Sigor@sysoev.ru     nxt_socket_conf_t  *nskcf, *oskcf;
97053Sigor@sysoev.ru 
97153Sigor@sysoev.ru     for (nqlk = nxt_queue_first(&tmcf->pending);
97253Sigor@sysoev.ru          nqlk != nxt_queue_tail(&tmcf->pending);
97353Sigor@sysoev.ru          nqlk = next)
97453Sigor@sysoev.ru     {
97553Sigor@sysoev.ru         next = nxt_queue_next(nqlk);
97653Sigor@sysoev.ru         nskcf = nxt_queue_link_data(nqlk, nxt_socket_conf_t, link);
97753Sigor@sysoev.ru 
97853Sigor@sysoev.ru         for (oqlk = nxt_queue_first(&router->sockets);
97953Sigor@sysoev.ru              oqlk != nxt_queue_tail(&router->sockets);
98053Sigor@sysoev.ru              oqlk = nxt_queue_next(oqlk))
98153Sigor@sysoev.ru         {
98253Sigor@sysoev.ru             oskcf = nxt_queue_link_data(oqlk, nxt_socket_conf_t, link);
98353Sigor@sysoev.ru 
984115Sigor@sysoev.ru             if (nxt_sockaddr_cmp(nskcf->sockaddr, oskcf->sockaddr)) {
985115Sigor@sysoev.ru                 nskcf->socket = oskcf->socket;
986115Sigor@sysoev.ru                 nskcf->listen.socket = oskcf->listen.socket;
987115Sigor@sysoev.ru 
98853Sigor@sysoev.ru                 nxt_queue_remove(oqlk);
98953Sigor@sysoev.ru                 nxt_queue_insert_tail(&tmcf->keeping, oqlk);
99053Sigor@sysoev.ru 
99153Sigor@sysoev.ru                 nxt_queue_remove(nqlk);
99253Sigor@sysoev.ru                 nxt_queue_insert_tail(&tmcf->updating, nqlk);
99353Sigor@sysoev.ru 
99453Sigor@sysoev.ru                 break;
99553Sigor@sysoev.ru             }
99653Sigor@sysoev.ru         }
99753Sigor@sysoev.ru     }
99853Sigor@sysoev.ru 
99953Sigor@sysoev.ru     nxt_queue_add(&tmcf->deleting, &router->sockets);
1000115Sigor@sysoev.ru     nxt_queue_init(&router->sockets);
100153Sigor@sysoev.ru }
100253Sigor@sysoev.ru 
100353Sigor@sysoev.ru 
1004198Sigor@sysoev.ru static void
1005198Sigor@sysoev.ru nxt_router_listen_socket_rpc_create(nxt_task_t *task,
1006198Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf)
1007198Sigor@sysoev.ru {
1008198Sigor@sysoev.ru     uint32_t          stream;
1009198Sigor@sysoev.ru     nxt_buf_t         *b;
1010198Sigor@sysoev.ru     nxt_port_t        *main_port, *router_port;
1011198Sigor@sysoev.ru     nxt_runtime_t     *rt;
1012198Sigor@sysoev.ru     nxt_socket_rpc_t  *rpc;
1013198Sigor@sysoev.ru 
1014198Sigor@sysoev.ru     rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_socket_rpc_t));
1015198Sigor@sysoev.ru     if (rpc == NULL) {
1016198Sigor@sysoev.ru         goto fail;
1017198Sigor@sysoev.ru     }
1018198Sigor@sysoev.ru 
1019198Sigor@sysoev.ru     rpc->socket_conf = skcf;
1020198Sigor@sysoev.ru     rpc->temp_conf = tmcf;
1021198Sigor@sysoev.ru 
1022198Sigor@sysoev.ru     b = nxt_buf_mem_alloc(tmcf->mem_pool, skcf->sockaddr->sockaddr_size, 0);
1023198Sigor@sysoev.ru     if (b == NULL) {
1024198Sigor@sysoev.ru         goto fail;
1025198Sigor@sysoev.ru     }
1026198Sigor@sysoev.ru 
1027198Sigor@sysoev.ru     b->mem.free = nxt_cpymem(b->mem.free, skcf->sockaddr,
1028198Sigor@sysoev.ru                              skcf->sockaddr->sockaddr_size);
1029198Sigor@sysoev.ru 
1030198Sigor@sysoev.ru     rt = task->thread->runtime;
1031240Sigor@sysoev.ru     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
1032198Sigor@sysoev.ru     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
1033198Sigor@sysoev.ru 
1034198Sigor@sysoev.ru     stream = nxt_port_rpc_register_handler(task, router_port,
1035198Sigor@sysoev.ru                                            nxt_router_listen_socket_ready,
1036198Sigor@sysoev.ru                                            nxt_router_listen_socket_error,
1037198Sigor@sysoev.ru                                            main_port->pid, rpc);
1038198Sigor@sysoev.ru     if (stream == 0) {
1039198Sigor@sysoev.ru         goto fail;
1040198Sigor@sysoev.ru     }
1041198Sigor@sysoev.ru 
1042198Sigor@sysoev.ru     nxt_port_socket_write(task, main_port, NXT_PORT_MSG_SOCKET, -1,
1043198Sigor@sysoev.ru                           stream, router_port->id, b);
1044198Sigor@sysoev.ru 
1045198Sigor@sysoev.ru     return;
1046198Sigor@sysoev.ru 
1047198Sigor@sysoev.ru fail:
1048198Sigor@sysoev.ru 
1049198Sigor@sysoev.ru     nxt_router_conf_error(task, tmcf);
1050198Sigor@sysoev.ru }
1051198Sigor@sysoev.ru 
1052198Sigor@sysoev.ru 
1053198Sigor@sysoev.ru static void
1054198Sigor@sysoev.ru nxt_router_listen_socket_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
1055198Sigor@sysoev.ru     void *data)
105653Sigor@sysoev.ru {
1057115Sigor@sysoev.ru     nxt_int_t            ret;
1058115Sigor@sysoev.ru     nxt_socket_t         s;
1059198Sigor@sysoev.ru     nxt_socket_rpc_t     *rpc;
1060115Sigor@sysoev.ru     nxt_router_socket_t  *rtsk;
106153Sigor@sysoev.ru 
1062198Sigor@sysoev.ru     rpc = data;
1063198Sigor@sysoev.ru 
1064198Sigor@sysoev.ru     s = msg->fd;
1065198Sigor@sysoev.ru 
1066198Sigor@sysoev.ru     ret = nxt_socket_nonblocking(task, s);
1067198Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1068198Sigor@sysoev.ru         goto fail;
106953Sigor@sysoev.ru     }
107053Sigor@sysoev.ru 
1071229Sigor@sysoev.ru     nxt_socket_defer_accept(task, s, rpc->socket_conf->sockaddr);
1072198Sigor@sysoev.ru 
1073198Sigor@sysoev.ru     ret = nxt_listen_socket(task, s, NXT_LISTEN_BACKLOG);
1074198Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1075198Sigor@sysoev.ru         goto fail;
1076198Sigor@sysoev.ru     }
1077198Sigor@sysoev.ru 
1078198Sigor@sysoev.ru     rtsk = nxt_malloc(sizeof(nxt_router_socket_t));
1079198Sigor@sysoev.ru     if (nxt_slow_path(rtsk == NULL)) {
1080198Sigor@sysoev.ru         goto fail;
1081198Sigor@sysoev.ru     }
1082198Sigor@sysoev.ru 
1083198Sigor@sysoev.ru     rtsk->count = 0;
1084198Sigor@sysoev.ru     rtsk->fd = s;
1085198Sigor@sysoev.ru 
1086198Sigor@sysoev.ru     rpc->socket_conf->listen.socket = s;
1087198Sigor@sysoev.ru     rpc->socket_conf->socket = rtsk;
1088198Sigor@sysoev.ru 
1089198Sigor@sysoev.ru     nxt_work_queue_add(&task->thread->engine->fast_work_queue,
1090198Sigor@sysoev.ru                        nxt_router_conf_apply, task, rpc->temp_conf, NULL);
1091198Sigor@sysoev.ru 
1092198Sigor@sysoev.ru     return;
1093148Sigor@sysoev.ru 
1094148Sigor@sysoev.ru fail:
1095148Sigor@sysoev.ru 
1096148Sigor@sysoev.ru     nxt_socket_close(task, s);
1097148Sigor@sysoev.ru 
1098198Sigor@sysoev.ru     nxt_router_conf_error(task, rpc->temp_conf);
1099198Sigor@sysoev.ru }
1100198Sigor@sysoev.ru 
1101198Sigor@sysoev.ru 
1102198Sigor@sysoev.ru static void
1103198Sigor@sysoev.ru nxt_router_listen_socket_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
1104198Sigor@sysoev.ru     void *data)
1105198Sigor@sysoev.ru {
1106198Sigor@sysoev.ru     u_char                  *p;
1107198Sigor@sysoev.ru     size_t                  size;
1108198Sigor@sysoev.ru     uint8_t                 error;
1109198Sigor@sysoev.ru     nxt_buf_t               *in, *out;
1110198Sigor@sysoev.ru     nxt_sockaddr_t          *sa;
1111198Sigor@sysoev.ru     nxt_socket_rpc_t        *rpc;
1112198Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
1113198Sigor@sysoev.ru 
1114198Sigor@sysoev.ru     static nxt_str_t  socket_errors[] = {
1115198Sigor@sysoev.ru         nxt_string("ListenerSystem"),
1116198Sigor@sysoev.ru         nxt_string("ListenerNoIPv6"),
1117198Sigor@sysoev.ru         nxt_string("ListenerPort"),
1118198Sigor@sysoev.ru         nxt_string("ListenerInUse"),
1119198Sigor@sysoev.ru         nxt_string("ListenerNoAddress"),
1120198Sigor@sysoev.ru         nxt_string("ListenerNoAccess"),
1121198Sigor@sysoev.ru         nxt_string("ListenerPath"),
1122198Sigor@sysoev.ru     };
1123198Sigor@sysoev.ru 
1124198Sigor@sysoev.ru     rpc = data;
1125198Sigor@sysoev.ru     sa = rpc->socket_conf->sockaddr;
1126198Sigor@sysoev.ru 
1127198Sigor@sysoev.ru     in = msg->buf;
1128198Sigor@sysoev.ru     p = in->mem.pos;
1129198Sigor@sysoev.ru 
1130198Sigor@sysoev.ru     error = *p++;
1131198Sigor@sysoev.ru 
1132198Sigor@sysoev.ru     size = sizeof("listen socket error: ") - 1
1133198Sigor@sysoev.ru            + sizeof("{listener: \"\", code:\"\", message: \"\"}") - 1
1134198Sigor@sysoev.ru            + sa->length + socket_errors[error].length + (in->mem.free - p);
1135198Sigor@sysoev.ru 
1136198Sigor@sysoev.ru     tmcf = rpc->temp_conf;
1137198Sigor@sysoev.ru 
1138198Sigor@sysoev.ru     out = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0);
1139198Sigor@sysoev.ru     if (nxt_slow_path(out == NULL)) {
1140198Sigor@sysoev.ru         return;
1141198Sigor@sysoev.ru     }
1142198Sigor@sysoev.ru 
1143198Sigor@sysoev.ru     out->mem.free = nxt_sprintf(out->mem.free, out->mem.end,
1144198Sigor@sysoev.ru                         "listen socket error: "
1145198Sigor@sysoev.ru                         "{listener: \"%*s\", code:\"%V\", message: \"%*s\"}",
1146198Sigor@sysoev.ru                         sa->length, nxt_sockaddr_start(sa),
1147198Sigor@sysoev.ru                         &socket_errors[error], in->mem.free - p, p);
1148198Sigor@sysoev.ru 
1149198Sigor@sysoev.ru     nxt_debug(task, "%*s", out->mem.free - out->mem.pos, out->mem.pos);
1150198Sigor@sysoev.ru 
1151198Sigor@sysoev.ru     nxt_router_conf_error(task, tmcf);
115253Sigor@sysoev.ru }
115353Sigor@sysoev.ru 
115453Sigor@sysoev.ru 
115553Sigor@sysoev.ru static nxt_int_t
115653Sigor@sysoev.ru nxt_router_engines_create(nxt_task_t *task, nxt_router_t *router,
115753Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, const nxt_event_interface_t *interface)
115853Sigor@sysoev.ru {
115953Sigor@sysoev.ru     nxt_int_t                 ret;
116053Sigor@sysoev.ru     nxt_uint_t                n, threads;
116153Sigor@sysoev.ru     nxt_queue_link_t          *qlk;
116253Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
116353Sigor@sysoev.ru 
116453Sigor@sysoev.ru     threads = tmcf->conf->threads;
116553Sigor@sysoev.ru 
116653Sigor@sysoev.ru     tmcf->engines = nxt_array_create(tmcf->mem_pool, threads,
116753Sigor@sysoev.ru                                      sizeof(nxt_router_engine_conf_t));
116853Sigor@sysoev.ru     if (nxt_slow_path(tmcf->engines == NULL)) {
116953Sigor@sysoev.ru         return NXT_ERROR;
117053Sigor@sysoev.ru     }
117153Sigor@sysoev.ru 
117253Sigor@sysoev.ru     n = 0;
117353Sigor@sysoev.ru 
117453Sigor@sysoev.ru     for (qlk = nxt_queue_first(&router->engines);
117553Sigor@sysoev.ru          qlk != nxt_queue_tail(&router->engines);
117653Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
117753Sigor@sysoev.ru     {
117853Sigor@sysoev.ru         recf = nxt_array_zero_add(tmcf->engines);
117953Sigor@sysoev.ru         if (nxt_slow_path(recf == NULL)) {
118053Sigor@sysoev.ru             return NXT_ERROR;
118153Sigor@sysoev.ru         }
118253Sigor@sysoev.ru 
1183115Sigor@sysoev.ru         recf->engine = nxt_queue_link_data(qlk, nxt_event_engine_t, link0);
118453Sigor@sysoev.ru 
118553Sigor@sysoev.ru         if (n < threads) {
1186*315Sigor@sysoev.ru             recf->action = NXT_ROUTER_ENGINE_KEEP;
1187115Sigor@sysoev.ru             ret = nxt_router_engine_conf_update(tmcf, recf);
118853Sigor@sysoev.ru 
118953Sigor@sysoev.ru         } else {
1190*315Sigor@sysoev.ru             recf->action = NXT_ROUTER_ENGINE_DELETE;
1191115Sigor@sysoev.ru             ret = nxt_router_engine_conf_delete(tmcf, recf);
119253Sigor@sysoev.ru         }
119353Sigor@sysoev.ru 
119453Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
119553Sigor@sysoev.ru             return ret;
119653Sigor@sysoev.ru         }
119753Sigor@sysoev.ru 
119853Sigor@sysoev.ru         n++;
119953Sigor@sysoev.ru     }
120053Sigor@sysoev.ru 
120153Sigor@sysoev.ru     tmcf->new_threads = n;
120253Sigor@sysoev.ru 
120353Sigor@sysoev.ru     while (n < threads) {
120453Sigor@sysoev.ru         recf = nxt_array_zero_add(tmcf->engines);
120553Sigor@sysoev.ru         if (nxt_slow_path(recf == NULL)) {
120653Sigor@sysoev.ru             return NXT_ERROR;
120753Sigor@sysoev.ru         }
120853Sigor@sysoev.ru 
1209*315Sigor@sysoev.ru         recf->action = NXT_ROUTER_ENGINE_ADD;
1210*315Sigor@sysoev.ru 
121153Sigor@sysoev.ru         recf->engine = nxt_event_engine_create(task, interface, NULL, 0, 0);
121253Sigor@sysoev.ru         if (nxt_slow_path(recf->engine == NULL)) {
121353Sigor@sysoev.ru             return NXT_ERROR;
121453Sigor@sysoev.ru         }
121553Sigor@sysoev.ru 
1216115Sigor@sysoev.ru         ret = nxt_router_engine_conf_create(tmcf, recf);
121753Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
121853Sigor@sysoev.ru             return ret;
121953Sigor@sysoev.ru         }
122053Sigor@sysoev.ru 
122153Sigor@sysoev.ru         n++;
122253Sigor@sysoev.ru     }
122353Sigor@sysoev.ru 
122453Sigor@sysoev.ru     return NXT_OK;
122553Sigor@sysoev.ru }
122653Sigor@sysoev.ru 
122753Sigor@sysoev.ru 
122853Sigor@sysoev.ru static nxt_int_t
1229115Sigor@sysoev.ru nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf,
1230115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
123153Sigor@sysoev.ru {
1232115Sigor@sysoev.ru     nxt_int_t              ret;
1233115Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
123453Sigor@sysoev.ru 
1235154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating,
1236154Sigor@sysoev.ru                                           nxt_router_listen_socket_create);
1237115Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1238115Sigor@sysoev.ru         return ret;
1239115Sigor@sysoev.ru     }
1240115Sigor@sysoev.ru 
1241154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating,
1242154Sigor@sysoev.ru                                           nxt_router_listen_socket_create);
124353Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
124453Sigor@sysoev.ru         return ret;
124553Sigor@sysoev.ru     }
124653Sigor@sysoev.ru 
1247115Sigor@sysoev.ru     lock = &tmcf->conf->router->lock;
1248115Sigor@sysoev.ru 
1249115Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
1250115Sigor@sysoev.ru 
1251115Sigor@sysoev.ru     nxt_router_engine_socket_count(&tmcf->creating);
1252115Sigor@sysoev.ru     nxt_router_engine_socket_count(&tmcf->updating);
1253115Sigor@sysoev.ru 
1254115Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
1255115Sigor@sysoev.ru 
1256115Sigor@sysoev.ru     return ret;
125753Sigor@sysoev.ru }
125853Sigor@sysoev.ru 
125953Sigor@sysoev.ru 
126053Sigor@sysoev.ru static nxt_int_t
1261115Sigor@sysoev.ru nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf,
1262115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
126353Sigor@sysoev.ru {
1264115Sigor@sysoev.ru     nxt_int_t              ret;
1265115Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
126653Sigor@sysoev.ru 
1267154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating,
1268154Sigor@sysoev.ru                                           nxt_router_listen_socket_create);
126953Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
127053Sigor@sysoev.ru         return ret;
127153Sigor@sysoev.ru     }
127253Sigor@sysoev.ru 
1273154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating,
1274154Sigor@sysoev.ru                                           nxt_router_listen_socket_update);
127553Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
127653Sigor@sysoev.ru         return ret;
127753Sigor@sysoev.ru     }
127853Sigor@sysoev.ru 
1279139Sigor@sysoev.ru     ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting);
1280115Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1281115Sigor@sysoev.ru         return ret;
1282115Sigor@sysoev.ru     }
1283115Sigor@sysoev.ru 
1284115Sigor@sysoev.ru     lock = &tmcf->conf->router->lock;
1285115Sigor@sysoev.ru 
1286115Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
1287115Sigor@sysoev.ru 
1288115Sigor@sysoev.ru     nxt_router_engine_socket_count(&tmcf->creating);
1289115Sigor@sysoev.ru 
1290115Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
1291115Sigor@sysoev.ru 
1292115Sigor@sysoev.ru     return ret;
129353Sigor@sysoev.ru }
129453Sigor@sysoev.ru 
129553Sigor@sysoev.ru 
129653Sigor@sysoev.ru static nxt_int_t
1297115Sigor@sysoev.ru nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf,
1298115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
129953Sigor@sysoev.ru {
130053Sigor@sysoev.ru     nxt_int_t  ret;
130153Sigor@sysoev.ru 
1302313Sigor@sysoev.ru     ret = nxt_router_engine_quit(tmcf, recf);
1303313Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1304313Sigor@sysoev.ru         return ret;
1305313Sigor@sysoev.ru     }
1306313Sigor@sysoev.ru 
1307139Sigor@sysoev.ru     ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->updating);
130853Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
130953Sigor@sysoev.ru         return ret;
131053Sigor@sysoev.ru     }
131153Sigor@sysoev.ru 
1312139Sigor@sysoev.ru     return nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting);
131353Sigor@sysoev.ru }
131453Sigor@sysoev.ru 
131553Sigor@sysoev.ru 
131653Sigor@sysoev.ru static nxt_int_t
1317154Sigor@sysoev.ru nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf,
1318154Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets,
131953Sigor@sysoev.ru     nxt_work_handler_t handler)
132053Sigor@sysoev.ru {
1321153Sigor@sysoev.ru     nxt_joint_job_t          *job;
132253Sigor@sysoev.ru     nxt_queue_link_t         *qlk;
1323155Sigor@sysoev.ru     nxt_socket_conf_t        *skcf;
132453Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
132553Sigor@sysoev.ru 
132653Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
132753Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
132853Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
132953Sigor@sysoev.ru     {
1330154Sigor@sysoev.ru         job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t));
1331153Sigor@sysoev.ru         if (nxt_slow_path(job == NULL)) {
1332139Sigor@sysoev.ru             return NXT_ERROR;
1333139Sigor@sysoev.ru         }
1334139Sigor@sysoev.ru 
1335154Sigor@sysoev.ru         job->work.next = recf->jobs;
1336154Sigor@sysoev.ru         recf->jobs = &job->work;
1337154Sigor@sysoev.ru 
1338153Sigor@sysoev.ru         job->task = tmcf->engine->task;
1339153Sigor@sysoev.ru         job->work.handler = handler;
1340153Sigor@sysoev.ru         job->work.task = &job->task;
1341153Sigor@sysoev.ru         job->work.obj = job;
1342153Sigor@sysoev.ru         job->tmcf = tmcf;
134353Sigor@sysoev.ru 
1344154Sigor@sysoev.ru         tmcf->count++;
1345154Sigor@sysoev.ru 
1346154Sigor@sysoev.ru         joint = nxt_mp_alloc(tmcf->conf->mem_pool,
1347154Sigor@sysoev.ru                              sizeof(nxt_socket_conf_joint_t));
134853Sigor@sysoev.ru         if (nxt_slow_path(joint == NULL)) {
134953Sigor@sysoev.ru             return NXT_ERROR;
135053Sigor@sysoev.ru         }
135153Sigor@sysoev.ru 
1352153Sigor@sysoev.ru         job->work.data = joint;
135353Sigor@sysoev.ru 
135453Sigor@sysoev.ru         joint->count = 1;
1355155Sigor@sysoev.ru 
1356155Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
1357155Sigor@sysoev.ru         skcf->count++;
1358155Sigor@sysoev.ru         joint->socket_conf = skcf;
1359155Sigor@sysoev.ru 
136088Smax.romanov@nginx.com         joint->engine = recf->engine;
136153Sigor@sysoev.ru     }
136253Sigor@sysoev.ru 
136320Sigor@sysoev.ru     return NXT_OK;
136420Sigor@sysoev.ru }
136520Sigor@sysoev.ru 
136620Sigor@sysoev.ru 
1367115Sigor@sysoev.ru static void
1368115Sigor@sysoev.ru nxt_router_engine_socket_count(nxt_queue_t *sockets)
1369115Sigor@sysoev.ru {
1370115Sigor@sysoev.ru     nxt_queue_link_t   *qlk;
1371115Sigor@sysoev.ru     nxt_socket_conf_t  *skcf;
1372115Sigor@sysoev.ru 
1373115Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
1374115Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
1375115Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
1376115Sigor@sysoev.ru     {
1377115Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
1378115Sigor@sysoev.ru         skcf->socket->count++;
1379115Sigor@sysoev.ru     }
1380115Sigor@sysoev.ru }
1381115Sigor@sysoev.ru 
1382115Sigor@sysoev.ru 
138320Sigor@sysoev.ru static nxt_int_t
1384313Sigor@sysoev.ru nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf,
1385313Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
1386313Sigor@sysoev.ru {
1387313Sigor@sysoev.ru     nxt_joint_job_t  *job;
1388313Sigor@sysoev.ru 
1389313Sigor@sysoev.ru     job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t));
1390313Sigor@sysoev.ru     if (nxt_slow_path(job == NULL)) {
1391313Sigor@sysoev.ru         return NXT_ERROR;
1392313Sigor@sysoev.ru     }
1393313Sigor@sysoev.ru 
1394313Sigor@sysoev.ru     job->work.next = recf->jobs;
1395313Sigor@sysoev.ru     recf->jobs = &job->work;
1396313Sigor@sysoev.ru 
1397313Sigor@sysoev.ru     job->task = tmcf->engine->task;
1398313Sigor@sysoev.ru     job->work.handler = nxt_router_worker_thread_quit;
1399313Sigor@sysoev.ru     job->work.task = &job->task;
1400313Sigor@sysoev.ru     job->work.obj = NULL;
1401313Sigor@sysoev.ru     job->work.data = NULL;
1402313Sigor@sysoev.ru     job->tmcf = NULL;
1403313Sigor@sysoev.ru 
1404313Sigor@sysoev.ru     return NXT_OK;
1405313Sigor@sysoev.ru }
1406313Sigor@sysoev.ru 
1407313Sigor@sysoev.ru 
1408313Sigor@sysoev.ru static nxt_int_t
1409139Sigor@sysoev.ru nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf,
1410139Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets)
141120Sigor@sysoev.ru {
1412153Sigor@sysoev.ru     nxt_joint_job_t   *job;
141353Sigor@sysoev.ru     nxt_queue_link_t  *qlk;
141420Sigor@sysoev.ru 
141553Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
141653Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
141753Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
141853Sigor@sysoev.ru     {
1419154Sigor@sysoev.ru         job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t));
1420153Sigor@sysoev.ru         if (nxt_slow_path(job == NULL)) {
1421139Sigor@sysoev.ru             return NXT_ERROR;
1422139Sigor@sysoev.ru         }
1423139Sigor@sysoev.ru 
1424154Sigor@sysoev.ru         job->work.next = recf->jobs;
1425154Sigor@sysoev.ru         recf->jobs = &job->work;
1426154Sigor@sysoev.ru 
1427153Sigor@sysoev.ru         job->task = tmcf->engine->task;
1428153Sigor@sysoev.ru         job->work.handler = nxt_router_listen_socket_delete;
1429153Sigor@sysoev.ru         job->work.task = &job->task;
1430153Sigor@sysoev.ru         job->work.obj = job;
1431153Sigor@sysoev.ru         job->work.data = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
1432153Sigor@sysoev.ru         job->tmcf = tmcf;
1433154Sigor@sysoev.ru 
1434154Sigor@sysoev.ru         tmcf->count++;
143520Sigor@sysoev.ru     }
143620Sigor@sysoev.ru 
143753Sigor@sysoev.ru     return NXT_OK;
143853Sigor@sysoev.ru }
143920Sigor@sysoev.ru 
144020Sigor@sysoev.ru 
144153Sigor@sysoev.ru static nxt_int_t
144253Sigor@sysoev.ru nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt,
144353Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf)
144453Sigor@sysoev.ru {
144553Sigor@sysoev.ru     nxt_int_t                 ret;
144653Sigor@sysoev.ru     nxt_uint_t                i, threads;
144753Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
144820Sigor@sysoev.ru 
144953Sigor@sysoev.ru     recf = tmcf->engines->elts;
145053Sigor@sysoev.ru     threads = tmcf->conf->threads;
145120Sigor@sysoev.ru 
145253Sigor@sysoev.ru     for (i = tmcf->new_threads; i < threads; i++) {
145353Sigor@sysoev.ru         ret = nxt_router_thread_create(task, rt, recf[i].engine);
145453Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
145553Sigor@sysoev.ru             return ret;
145653Sigor@sysoev.ru         }
145720Sigor@sysoev.ru     }
145820Sigor@sysoev.ru 
145920Sigor@sysoev.ru     return NXT_OK;
146020Sigor@sysoev.ru }
146153Sigor@sysoev.ru 
146253Sigor@sysoev.ru 
146353Sigor@sysoev.ru static nxt_int_t
146453Sigor@sysoev.ru nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt,
146553Sigor@sysoev.ru     nxt_event_engine_t *engine)
146653Sigor@sysoev.ru {
146753Sigor@sysoev.ru     nxt_int_t            ret;
146853Sigor@sysoev.ru     nxt_thread_link_t    *link;
146953Sigor@sysoev.ru     nxt_thread_handle_t  handle;
147053Sigor@sysoev.ru 
147153Sigor@sysoev.ru     link = nxt_zalloc(sizeof(nxt_thread_link_t));
147253Sigor@sysoev.ru 
147353Sigor@sysoev.ru     if (nxt_slow_path(link == NULL)) {
147453Sigor@sysoev.ru         return NXT_ERROR;
147553Sigor@sysoev.ru     }
147653Sigor@sysoev.ru 
147753Sigor@sysoev.ru     link->start = nxt_router_thread_start;
147853Sigor@sysoev.ru     link->engine = engine;
147953Sigor@sysoev.ru     link->work.handler = nxt_router_thread_exit_handler;
148053Sigor@sysoev.ru     link->work.task = task;
148153Sigor@sysoev.ru     link->work.data = link;
148253Sigor@sysoev.ru 
148353Sigor@sysoev.ru     nxt_queue_insert_tail(&rt->engines, &engine->link);
148453Sigor@sysoev.ru 
148553Sigor@sysoev.ru     ret = nxt_thread_create(&handle, link);
148653Sigor@sysoev.ru 
148753Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
148853Sigor@sysoev.ru         nxt_queue_remove(&engine->link);
148953Sigor@sysoev.ru     }
149053Sigor@sysoev.ru 
149153Sigor@sysoev.ru     return ret;
149253Sigor@sysoev.ru }
149353Sigor@sysoev.ru 
149453Sigor@sysoev.ru 
149553Sigor@sysoev.ru static void
1496133Sigor@sysoev.ru nxt_router_apps_sort(nxt_router_t *router, nxt_router_temp_conf_t *tmcf)
1497133Sigor@sysoev.ru {
1498167Smax.romanov@nginx.com     nxt_app_t    *app;
1499167Smax.romanov@nginx.com     nxt_port_t   *port;
1500141Smax.romanov@nginx.com 
1501141Smax.romanov@nginx.com     nxt_queue_each(app, &router->apps, nxt_app_t, link) {
1502133Sigor@sysoev.ru 
1503133Sigor@sysoev.ru         nxt_queue_remove(&app->link);
1504133Sigor@sysoev.ru 
1505167Smax.romanov@nginx.com         nxt_thread_log_debug("about to remove app '%V' %p", &app->name, app);
1506167Smax.romanov@nginx.com 
1507163Smax.romanov@nginx.com         app->live = 0;
1508163Smax.romanov@nginx.com 
1509167Smax.romanov@nginx.com         if (nxt_router_app_free(NULL, app) != 0) {
1510163Smax.romanov@nginx.com             continue;
1511163Smax.romanov@nginx.com         }
1512163Smax.romanov@nginx.com 
1513167Smax.romanov@nginx.com         if (!nxt_queue_is_empty(&app->requests)) {
1514167Smax.romanov@nginx.com 
1515167Smax.romanov@nginx.com             nxt_thread_log_debug("app '%V' %p pending requests found",
1516167Smax.romanov@nginx.com                                  &app->name, app);
1517167Smax.romanov@nginx.com             continue;
1518163Smax.romanov@nginx.com         }
1519163Smax.romanov@nginx.com 
1520167Smax.romanov@nginx.com         do {
1521167Smax.romanov@nginx.com             port = nxt_router_app_get_port(app, 0);
1522167Smax.romanov@nginx.com             if (port == NULL) {
1523167Smax.romanov@nginx.com                 break;
1524167Smax.romanov@nginx.com             }
1525167Smax.romanov@nginx.com 
1526167Smax.romanov@nginx.com             nxt_thread_log_debug("port %p send quit", port);
1527167Smax.romanov@nginx.com 
1528167Smax.romanov@nginx.com             nxt_port_socket_write(&port->engine->task, port,
1529167Smax.romanov@nginx.com                                   NXT_PORT_MSG_QUIT, -1, 0, 0, NULL);
1530167Smax.romanov@nginx.com         } while (1);
1531167Smax.romanov@nginx.com 
1532141Smax.romanov@nginx.com     } nxt_queue_loop;
1533133Sigor@sysoev.ru 
1534133Sigor@sysoev.ru     nxt_queue_add(&router->apps, &tmcf->previous);
1535133Sigor@sysoev.ru     nxt_queue_add(&router->apps, &tmcf->apps);
1536133Sigor@sysoev.ru }
1537133Sigor@sysoev.ru 
1538133Sigor@sysoev.ru 
1539133Sigor@sysoev.ru static void
1540*315Sigor@sysoev.ru nxt_router_engines_post(nxt_router_t *router, nxt_router_temp_conf_t *tmcf)
154153Sigor@sysoev.ru {
154253Sigor@sysoev.ru     nxt_uint_t                n;
1543*315Sigor@sysoev.ru     nxt_event_engine_t        *engine;
154453Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
154553Sigor@sysoev.ru 
154653Sigor@sysoev.ru     recf = tmcf->engines->elts;
154753Sigor@sysoev.ru 
154853Sigor@sysoev.ru     for (n = tmcf->engines->nelts; n != 0; n--) {
1549*315Sigor@sysoev.ru         engine = recf->engine;
1550*315Sigor@sysoev.ru 
1551*315Sigor@sysoev.ru         nxt_router_engine_post(engine, recf->jobs);
1552*315Sigor@sysoev.ru 
1553*315Sigor@sysoev.ru         switch (recf->action) {
1554*315Sigor@sysoev.ru 
1555*315Sigor@sysoev.ru         case NXT_ROUTER_ENGINE_KEEP:
1556*315Sigor@sysoev.ru             break;
1557*315Sigor@sysoev.ru 
1558*315Sigor@sysoev.ru         case NXT_ROUTER_ENGINE_ADD:
1559*315Sigor@sysoev.ru             nxt_queue_insert_tail(&router->engines, &engine->link0);
1560*315Sigor@sysoev.ru             break;
1561*315Sigor@sysoev.ru 
1562*315Sigor@sysoev.ru         case NXT_ROUTER_ENGINE_DELETE:
1563*315Sigor@sysoev.ru             nxt_queue_remove(&engine->link0);
1564*315Sigor@sysoev.ru             break;
1565*315Sigor@sysoev.ru         }
1566*315Sigor@sysoev.ru 
156753Sigor@sysoev.ru         recf++;
156853Sigor@sysoev.ru     }
156953Sigor@sysoev.ru }
157053Sigor@sysoev.ru 
157153Sigor@sysoev.ru 
157253Sigor@sysoev.ru static void
1573*315Sigor@sysoev.ru nxt_router_engine_post(nxt_event_engine_t *engine, nxt_work_t *jobs)
157453Sigor@sysoev.ru {
1575154Sigor@sysoev.ru     nxt_work_t  *work, *next;
1576154Sigor@sysoev.ru 
1577*315Sigor@sysoev.ru     for (work = jobs; work != NULL; work = next) {
1578154Sigor@sysoev.ru         next = work->next;
1579154Sigor@sysoev.ru         work->next = NULL;
1580154Sigor@sysoev.ru 
1581*315Sigor@sysoev.ru         nxt_event_engine_post(engine, work);
158253Sigor@sysoev.ru     }
158353Sigor@sysoev.ru }
158453Sigor@sysoev.ru 
158553Sigor@sysoev.ru 
1586119Smax.romanov@nginx.com static nxt_port_handler_t  nxt_router_app_port_handlers[] = {
1587192Smax.romanov@nginx.com     NULL, /* NXT_PORT_MSG_QUIT         */
1588192Smax.romanov@nginx.com     NULL, /* NXT_PORT_MSG_NEW_PORT     */
1589192Smax.romanov@nginx.com     NULL, /* NXT_PORT_MSG_CHANGE_FILE  */
1590192Smax.romanov@nginx.com     /* TODO: remove mmap_handler from app ports */
1591192Smax.romanov@nginx.com     nxt_port_mmap_handler, /* NXT_PORT_MSG_MMAP         */
1592119Smax.romanov@nginx.com     nxt_router_app_data_handler,
1593192Smax.romanov@nginx.com     NULL, /* NXT_PORT_MSG_REMOVE_PID   */
1594192Smax.romanov@nginx.com     NULL, /* NXT_PORT_MSG_READY        */
1595192Smax.romanov@nginx.com     NULL, /* NXT_PORT_MSG_START_WORKER */
1596190Smax.romanov@nginx.com     nxt_port_rpc_handler,
1597190Smax.romanov@nginx.com     nxt_port_rpc_handler,
159888Smax.romanov@nginx.com };
159988Smax.romanov@nginx.com 
160088Smax.romanov@nginx.com 
160188Smax.romanov@nginx.com static void
160253Sigor@sysoev.ru nxt_router_thread_start(void *data)
160353Sigor@sysoev.ru {
1604141Smax.romanov@nginx.com     nxt_int_t           ret;
1605141Smax.romanov@nginx.com     nxt_port_t          *port;
160688Smax.romanov@nginx.com     nxt_task_t          *task;
160753Sigor@sysoev.ru     nxt_thread_t        *thread;
160853Sigor@sysoev.ru     nxt_thread_link_t   *link;
160953Sigor@sysoev.ru     nxt_event_engine_t  *engine;
161053Sigor@sysoev.ru 
161153Sigor@sysoev.ru     link = data;
161253Sigor@sysoev.ru     engine = link->engine;
161388Smax.romanov@nginx.com     task = &engine->task;
161453Sigor@sysoev.ru 
161553Sigor@sysoev.ru     thread = nxt_thread();
161653Sigor@sysoev.ru 
1617165Smax.romanov@nginx.com     nxt_event_engine_thread_adopt(engine);
1618165Smax.romanov@nginx.com 
161953Sigor@sysoev.ru     /* STUB */
162053Sigor@sysoev.ru     thread->runtime = engine->task.thread->runtime;
162153Sigor@sysoev.ru 
162253Sigor@sysoev.ru     engine->task.thread = thread;
162353Sigor@sysoev.ru     engine->task.log = thread->log;
162453Sigor@sysoev.ru     thread->engine = engine;
162563Sigor@sysoev.ru     thread->task = &engine->task;
162653Sigor@sysoev.ru     thread->fiber = &engine->fibers->fiber;
162753Sigor@sysoev.ru 
162863Sigor@sysoev.ru     engine->mem_pool = nxt_mp_create(4096, 128, 1024, 64);
162953Sigor@sysoev.ru 
1630197Smax.romanov@nginx.com     port = nxt_port_new(task, nxt_port_get_next_id(), nxt_pid,
1631197Smax.romanov@nginx.com                         NXT_PROCESS_ROUTER);
1632141Smax.romanov@nginx.com     if (nxt_slow_path(port == NULL)) {
1633141Smax.romanov@nginx.com         return;
1634141Smax.romanov@nginx.com     }
1635141Smax.romanov@nginx.com 
1636141Smax.romanov@nginx.com     ret = nxt_port_socket_init(task, port, 0);
1637141Smax.romanov@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
1638163Smax.romanov@nginx.com         nxt_mp_release(port->mem_pool, port);
1639141Smax.romanov@nginx.com         return;
1640141Smax.romanov@nginx.com     }
1641141Smax.romanov@nginx.com 
1642141Smax.romanov@nginx.com     engine->port = port;
1643141Smax.romanov@nginx.com 
1644141Smax.romanov@nginx.com     nxt_port_enable(task, port, nxt_router_app_port_handlers);
1645141Smax.romanov@nginx.com 
164653Sigor@sysoev.ru     nxt_event_engine_start(engine);
164753Sigor@sysoev.ru }
164853Sigor@sysoev.ru 
164953Sigor@sysoev.ru 
165053Sigor@sysoev.ru static void
165153Sigor@sysoev.ru nxt_router_listen_socket_create(nxt_task_t *task, void *obj, void *data)
165253Sigor@sysoev.ru {
1653153Sigor@sysoev.ru     nxt_joint_job_t          *job;
165453Sigor@sysoev.ru     nxt_listen_event_t       *listen;
165553Sigor@sysoev.ru     nxt_listen_socket_t      *ls;
165653Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
165753Sigor@sysoev.ru 
1658153Sigor@sysoev.ru     job = obj;
165953Sigor@sysoev.ru     joint = data;
166053Sigor@sysoev.ru 
166153Sigor@sysoev.ru     ls = &joint->socket_conf->listen;
166253Sigor@sysoev.ru 
1663159Sigor@sysoev.ru     nxt_queue_insert_tail(&task->thread->engine->joints, &joint->link);
1664159Sigor@sysoev.ru 
166553Sigor@sysoev.ru     listen = nxt_listen_event(task, ls);
166653Sigor@sysoev.ru     if (nxt_slow_path(listen == NULL)) {
166753Sigor@sysoev.ru         nxt_router_listen_socket_release(task, joint);
166853Sigor@sysoev.ru         return;
166953Sigor@sysoev.ru     }
167053Sigor@sysoev.ru 
167153Sigor@sysoev.ru     listen->socket.data = joint;
1672139Sigor@sysoev.ru 
1673153Sigor@sysoev.ru     job->work.next = NULL;
1674153Sigor@sysoev.ru     job->work.handler = nxt_router_conf_wait;
1675153Sigor@sysoev.ru 
1676153Sigor@sysoev.ru     nxt_event_engine_post(job->tmcf->engine, &job->work);
167753Sigor@sysoev.ru }
167853Sigor@sysoev.ru 
167953Sigor@sysoev.ru 
168053Sigor@sysoev.ru nxt_inline nxt_listen_event_t *
168153Sigor@sysoev.ru nxt_router_listen_event(nxt_queue_t *listen_connections,
168253Sigor@sysoev.ru     nxt_socket_conf_t *skcf)
168353Sigor@sysoev.ru {
1684115Sigor@sysoev.ru     nxt_socket_t        fd;
1685115Sigor@sysoev.ru     nxt_queue_link_t    *qlk;
168653Sigor@sysoev.ru     nxt_listen_event_t  *listen;
168753Sigor@sysoev.ru 
1688115Sigor@sysoev.ru     fd = skcf->socket->fd;
168953Sigor@sysoev.ru 
1690115Sigor@sysoev.ru     for (qlk = nxt_queue_first(listen_connections);
1691115Sigor@sysoev.ru          qlk != nxt_queue_tail(listen_connections);
1692115Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
169353Sigor@sysoev.ru     {
1694115Sigor@sysoev.ru         listen = nxt_queue_link_data(qlk, nxt_listen_event_t, link);
169553Sigor@sysoev.ru 
1696115Sigor@sysoev.ru         if (fd == listen->socket.fd) {
169753Sigor@sysoev.ru             return listen;
169853Sigor@sysoev.ru         }
169953Sigor@sysoev.ru     }
170053Sigor@sysoev.ru 
170153Sigor@sysoev.ru     return NULL;
170253Sigor@sysoev.ru }
170353Sigor@sysoev.ru 
170453Sigor@sysoev.ru 
170553Sigor@sysoev.ru static void
170653Sigor@sysoev.ru nxt_router_listen_socket_update(nxt_task_t *task, void *obj, void *data)
170753Sigor@sysoev.ru {
1708153Sigor@sysoev.ru     nxt_joint_job_t          *job;
170953Sigor@sysoev.ru     nxt_event_engine_t       *engine;
171053Sigor@sysoev.ru     nxt_listen_event_t       *listen;
171153Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint, *old;
171253Sigor@sysoev.ru 
1713153Sigor@sysoev.ru     job = obj;
171453Sigor@sysoev.ru     joint = data;
171553Sigor@sysoev.ru 
1716139Sigor@sysoev.ru     engine = task->thread->engine;
1717139Sigor@sysoev.ru 
1718159Sigor@sysoev.ru     nxt_queue_insert_tail(&engine->joints, &joint->link);
1719159Sigor@sysoev.ru 
172053Sigor@sysoev.ru     listen = nxt_router_listen_event(&engine->listen_connections,
172153Sigor@sysoev.ru                                      joint->socket_conf);
172253Sigor@sysoev.ru 
172353Sigor@sysoev.ru     old = listen->socket.data;
172453Sigor@sysoev.ru     listen->socket.data = joint;
1725177Sigor@sysoev.ru     listen->listen = &joint->socket_conf->listen;
172653Sigor@sysoev.ru 
1727153Sigor@sysoev.ru     job->work.next = NULL;
1728153Sigor@sysoev.ru     job->work.handler = nxt_router_conf_wait;
1729153Sigor@sysoev.ru 
1730153Sigor@sysoev.ru     nxt_event_engine_post(job->tmcf->engine, &job->work);
1731139Sigor@sysoev.ru 
1732181Smax.romanov@nginx.com     /*
1733181Smax.romanov@nginx.com      * The task is allocated from configuration temporary
1734181Smax.romanov@nginx.com      * memory pool so it can be freed after engine post operation.
1735181Smax.romanov@nginx.com      */
1736181Smax.romanov@nginx.com 
1737181Smax.romanov@nginx.com     nxt_router_conf_release(&engine->task, old);
173853Sigor@sysoev.ru }
173953Sigor@sysoev.ru 
174053Sigor@sysoev.ru 
174153Sigor@sysoev.ru static void
174253Sigor@sysoev.ru nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, void *data)
174353Sigor@sysoev.ru {
1744153Sigor@sysoev.ru     nxt_joint_job_t     *job;
1745153Sigor@sysoev.ru     nxt_socket_conf_t   *skcf;
1746153Sigor@sysoev.ru     nxt_listen_event_t  *listen;
1747153Sigor@sysoev.ru     nxt_event_engine_t  *engine;
1748153Sigor@sysoev.ru 
1749153Sigor@sysoev.ru     job = obj;
175053Sigor@sysoev.ru     skcf = data;
175153Sigor@sysoev.ru 
1752139Sigor@sysoev.ru     engine = task->thread->engine;
1753139Sigor@sysoev.ru 
175453Sigor@sysoev.ru     listen = nxt_router_listen_event(&engine->listen_connections, skcf);
175553Sigor@sysoev.ru 
175653Sigor@sysoev.ru     nxt_fd_event_delete(engine, &listen->socket);
175753Sigor@sysoev.ru 
1758163Smax.romanov@nginx.com     nxt_debug(task, "engine %p: listen socket delete: %d", engine,
1759163Smax.romanov@nginx.com               listen->socket.fd);
1760163Smax.romanov@nginx.com 
176153Sigor@sysoev.ru     listen->timer.handler = nxt_router_listen_socket_close;
176253Sigor@sysoev.ru     listen->timer.work_queue = &engine->fast_work_queue;
176353Sigor@sysoev.ru 
176453Sigor@sysoev.ru     nxt_timer_add(engine, &listen->timer, 0);
1765139Sigor@sysoev.ru 
1766153Sigor@sysoev.ru     job->work.next = NULL;
1767153Sigor@sysoev.ru     job->work.handler = nxt_router_conf_wait;
1768153Sigor@sysoev.ru 
1769153Sigor@sysoev.ru     nxt_event_engine_post(job->tmcf->engine, &job->work);
177053Sigor@sysoev.ru }
177153Sigor@sysoev.ru 
177253Sigor@sysoev.ru 
177353Sigor@sysoev.ru static void
1774313Sigor@sysoev.ru nxt_router_worker_thread_quit(nxt_task_t *task, void *obj, void *data)
1775313Sigor@sysoev.ru {
1776313Sigor@sysoev.ru     nxt_event_engine_t  *engine;
1777313Sigor@sysoev.ru 
1778313Sigor@sysoev.ru     nxt_debug(task, "router worker thread quit");
1779313Sigor@sysoev.ru 
1780313Sigor@sysoev.ru     engine = task->thread->engine;
1781313Sigor@sysoev.ru 
1782313Sigor@sysoev.ru     engine->shutdown = 1;
1783313Sigor@sysoev.ru 
1784313Sigor@sysoev.ru     if (nxt_queue_is_empty(&engine->joints)) {
1785313Sigor@sysoev.ru         nxt_thread_exit(task->thread);
1786313Sigor@sysoev.ru     }
1787313Sigor@sysoev.ru }
1788313Sigor@sysoev.ru 
1789313Sigor@sysoev.ru 
1790313Sigor@sysoev.ru static void
179153Sigor@sysoev.ru nxt_router_listen_socket_close(nxt_task_t *task, void *obj, void *data)
179253Sigor@sysoev.ru {
179353Sigor@sysoev.ru     nxt_timer_t              *timer;
179453Sigor@sysoev.ru     nxt_listen_event_t       *listen;
179553Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
179653Sigor@sysoev.ru 
179753Sigor@sysoev.ru     timer = obj;
179853Sigor@sysoev.ru     listen = nxt_timer_data(timer, nxt_listen_event_t, timer);
179953Sigor@sysoev.ru     joint = listen->socket.data;
180053Sigor@sysoev.ru 
1801163Smax.romanov@nginx.com     nxt_debug(task, "engine %p: listen socket close: %d", task->thread->engine,
1802163Smax.romanov@nginx.com               listen->socket.fd);
1803163Smax.romanov@nginx.com 
180453Sigor@sysoev.ru     nxt_queue_remove(&listen->link);
1805123Smax.romanov@nginx.com 
1806123Smax.romanov@nginx.com     /* 'task' refers to listen->task and we cannot use after nxt_free() */
1807123Smax.romanov@nginx.com     task = &task->thread->engine->task;
1808123Smax.romanov@nginx.com 
180953Sigor@sysoev.ru     nxt_free(listen);
181053Sigor@sysoev.ru 
181153Sigor@sysoev.ru     nxt_router_listen_socket_release(task, joint);
181253Sigor@sysoev.ru }
181353Sigor@sysoev.ru 
181453Sigor@sysoev.ru 
181553Sigor@sysoev.ru static void
181653Sigor@sysoev.ru nxt_router_listen_socket_release(nxt_task_t *task,
181753Sigor@sysoev.ru     nxt_socket_conf_joint_t *joint)
181853Sigor@sysoev.ru {
1819118Sigor@sysoev.ru     nxt_socket_conf_t      *skcf;
1820115Sigor@sysoev.ru     nxt_router_socket_t    *rtsk;
182153Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
182253Sigor@sysoev.ru 
1823118Sigor@sysoev.ru     skcf = joint->socket_conf;
1824118Sigor@sysoev.ru     rtsk = skcf->socket;
1825118Sigor@sysoev.ru     lock = &skcf->router_conf->router->lock;
182653Sigor@sysoev.ru 
182753Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
182853Sigor@sysoev.ru 
1829163Smax.romanov@nginx.com     nxt_debug(task, "engine %p: listen socket release: rtsk->count %D",
1830163Smax.romanov@nginx.com               task->thread->engine, rtsk->count);
1831163Smax.romanov@nginx.com 
1832115Sigor@sysoev.ru     if (--rtsk->count != 0) {
1833115Sigor@sysoev.ru         rtsk = NULL;
183453Sigor@sysoev.ru     }
183553Sigor@sysoev.ru 
183653Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
183753Sigor@sysoev.ru 
1838115Sigor@sysoev.ru     if (rtsk != NULL) {
1839115Sigor@sysoev.ru         nxt_socket_close(task, rtsk->fd);
1840115Sigor@sysoev.ru         nxt_free(rtsk);
1841118Sigor@sysoev.ru         skcf->socket = NULL;
184253Sigor@sysoev.ru     }
184353Sigor@sysoev.ru 
184453Sigor@sysoev.ru     nxt_router_conf_release(task, joint);
184553Sigor@sysoev.ru }
184653Sigor@sysoev.ru 
184753Sigor@sysoev.ru 
184853Sigor@sysoev.ru static void
184953Sigor@sysoev.ru nxt_router_conf_release(nxt_task_t *task, nxt_socket_conf_joint_t *joint)
185053Sigor@sysoev.ru {
1851156Sigor@sysoev.ru     nxt_bool_t             exit;
185253Sigor@sysoev.ru     nxt_socket_conf_t      *skcf;
185353Sigor@sysoev.ru     nxt_router_conf_t      *rtcf;
1854313Sigor@sysoev.ru     nxt_event_engine_t     *engine;
185553Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
185653Sigor@sysoev.ru 
1857163Smax.romanov@nginx.com     nxt_debug(task, "conf joint %p count: %D", joint, joint->count);
185853Sigor@sysoev.ru 
185953Sigor@sysoev.ru     if (--joint->count != 0) {
186053Sigor@sysoev.ru         return;
186153Sigor@sysoev.ru     }
186253Sigor@sysoev.ru 
186353Sigor@sysoev.ru     nxt_queue_remove(&joint->link);
186453Sigor@sysoev.ru 
186553Sigor@sysoev.ru     skcf = joint->socket_conf;
186653Sigor@sysoev.ru     rtcf = skcf->router_conf;
186753Sigor@sysoev.ru     lock = &rtcf->router->lock;
186853Sigor@sysoev.ru 
186953Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
187053Sigor@sysoev.ru 
1871163Smax.romanov@nginx.com     nxt_debug(task, "conf skcf %p: %D, rtcf %p: %D", skcf, skcf->count,
1872163Smax.romanov@nginx.com               rtcf, rtcf->count);
1873163Smax.romanov@nginx.com 
187453Sigor@sysoev.ru     if (--skcf->count != 0) {
187553Sigor@sysoev.ru         rtcf = NULL;
187653Sigor@sysoev.ru 
187753Sigor@sysoev.ru     } else {
187853Sigor@sysoev.ru         nxt_queue_remove(&skcf->link);
187953Sigor@sysoev.ru 
188053Sigor@sysoev.ru         if (--rtcf->count != 0) {
188153Sigor@sysoev.ru             rtcf = NULL;
188253Sigor@sysoev.ru         }
188353Sigor@sysoev.ru     }
188453Sigor@sysoev.ru 
188553Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
188653Sigor@sysoev.ru 
1887141Smax.romanov@nginx.com     /* TODO remove engine->port */
1888141Smax.romanov@nginx.com     /* TODO excude from connected ports */
1889141Smax.romanov@nginx.com 
1890156Sigor@sysoev.ru     /* The joint content can be used before memory pool destruction. */
1891313Sigor@sysoev.ru     engine = joint->engine;
1892313Sigor@sysoev.ru     exit = (engine->shutdown && nxt_queue_is_empty(&engine->joints));
1893156Sigor@sysoev.ru 
189453Sigor@sysoev.ru     if (rtcf != NULL) {
1895115Sigor@sysoev.ru         nxt_debug(task, "old router conf is destroyed");
1896131Smax.romanov@nginx.com 
1897131Smax.romanov@nginx.com         nxt_mp_thread_adopt(rtcf->mem_pool);
1898131Smax.romanov@nginx.com 
189965Sigor@sysoev.ru         nxt_mp_destroy(rtcf->mem_pool);
190053Sigor@sysoev.ru     }
190153Sigor@sysoev.ru 
1902156Sigor@sysoev.ru     if (exit) {
190353Sigor@sysoev.ru         nxt_thread_exit(task->thread);
190453Sigor@sysoev.ru     }
190553Sigor@sysoev.ru }
190653Sigor@sysoev.ru 
190753Sigor@sysoev.ru 
190853Sigor@sysoev.ru static void
190953Sigor@sysoev.ru nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, void *data)
191053Sigor@sysoev.ru {
1911141Smax.romanov@nginx.com     nxt_port_t           *port;
191253Sigor@sysoev.ru     nxt_thread_link_t    *link;
191353Sigor@sysoev.ru     nxt_event_engine_t   *engine;
191453Sigor@sysoev.ru     nxt_thread_handle_t  handle;
191553Sigor@sysoev.ru 
191658Svbart@nginx.com     handle = (nxt_thread_handle_t) obj;
191753Sigor@sysoev.ru     link = data;
191853Sigor@sysoev.ru 
191953Sigor@sysoev.ru     nxt_thread_wait(handle);
192053Sigor@sysoev.ru 
192153Sigor@sysoev.ru     engine = link->engine;
192253Sigor@sysoev.ru 
192353Sigor@sysoev.ru     nxt_queue_remove(&engine->link);
192453Sigor@sysoev.ru 
1925141Smax.romanov@nginx.com     port = engine->port;
1926141Smax.romanov@nginx.com 
1927141Smax.romanov@nginx.com     // TODO notify all apps
1928141Smax.romanov@nginx.com 
1929163Smax.romanov@nginx.com     nxt_mp_thread_adopt(port->mem_pool);
1930163Smax.romanov@nginx.com     nxt_port_release(port);
1931163Smax.romanov@nginx.com 
1932163Smax.romanov@nginx.com     nxt_mp_thread_adopt(engine->mem_pool);
193363Sigor@sysoev.ru     nxt_mp_destroy(engine->mem_pool);
193453Sigor@sysoev.ru 
193553Sigor@sysoev.ru     nxt_event_engine_free(engine);
193653Sigor@sysoev.ru 
193753Sigor@sysoev.ru     nxt_free(link);
193853Sigor@sysoev.ru }
193953Sigor@sysoev.ru 
194053Sigor@sysoev.ru 
1941206Smax.romanov@nginx.com static const nxt_conn_state_t  nxt_router_conn_read_header_state
194253Sigor@sysoev.ru     nxt_aligned(64) =
194353Sigor@sysoev.ru {
194453Sigor@sysoev.ru     .ready_handler = nxt_router_conn_http_header_parse,
194553Sigor@sysoev.ru     .close_handler = nxt_router_conn_close,
194653Sigor@sysoev.ru     .error_handler = nxt_router_conn_error,
194753Sigor@sysoev.ru 
194853Sigor@sysoev.ru     .timer_handler = nxt_router_conn_timeout,
194953Sigor@sysoev.ru     .timer_value = nxt_router_conn_timeout_value,
195053Sigor@sysoev.ru     .timer_data = offsetof(nxt_socket_conf_t, header_read_timeout),
195153Sigor@sysoev.ru };
195253Sigor@sysoev.ru 
195353Sigor@sysoev.ru 
1954206Smax.romanov@nginx.com static const nxt_conn_state_t  nxt_router_conn_read_body_state
1955206Smax.romanov@nginx.com     nxt_aligned(64) =
1956206Smax.romanov@nginx.com {
1957206Smax.romanov@nginx.com     .ready_handler = nxt_router_conn_http_body_read,
1958206Smax.romanov@nginx.com     .close_handler = nxt_router_conn_close,
1959206Smax.romanov@nginx.com     .error_handler = nxt_router_conn_error,
1960206Smax.romanov@nginx.com 
1961206Smax.romanov@nginx.com     .timer_handler = nxt_router_conn_timeout,
1962206Smax.romanov@nginx.com     .timer_value = nxt_router_conn_timeout_value,
1963206Smax.romanov@nginx.com     .timer_data = offsetof(nxt_socket_conf_t, body_read_timeout),
1964206Smax.romanov@nginx.com     .timer_autoreset = 1,
1965206Smax.romanov@nginx.com };
1966206Smax.romanov@nginx.com 
1967206Smax.romanov@nginx.com 
196853Sigor@sysoev.ru static void
196953Sigor@sysoev.ru nxt_router_conn_init(nxt_task_t *task, void *obj, void *data)
197053Sigor@sysoev.ru {
197153Sigor@sysoev.ru     size_t                   size;
197262Sigor@sysoev.ru     nxt_conn_t               *c;
197353Sigor@sysoev.ru     nxt_event_engine_t       *engine;
197453Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
197553Sigor@sysoev.ru 
197653Sigor@sysoev.ru     c = obj;
197753Sigor@sysoev.ru     joint = data;
197853Sigor@sysoev.ru 
197953Sigor@sysoev.ru     nxt_debug(task, "router conn init");
198053Sigor@sysoev.ru 
198153Sigor@sysoev.ru     joint->count++;
198253Sigor@sysoev.ru 
198353Sigor@sysoev.ru     size = joint->socket_conf->header_buffer_size;
198453Sigor@sysoev.ru     c->read = nxt_buf_mem_alloc(c->mem_pool, size, 0);
198553Sigor@sysoev.ru 
198653Sigor@sysoev.ru     c->socket.data = NULL;
198753Sigor@sysoev.ru 
198853Sigor@sysoev.ru     engine = task->thread->engine;
198953Sigor@sysoev.ru     c->read_work_queue = &engine->fast_work_queue;
199053Sigor@sysoev.ru     c->write_work_queue = &engine->fast_work_queue;
199153Sigor@sysoev.ru 
1992206Smax.romanov@nginx.com     c->read_state = &nxt_router_conn_read_header_state;
199353Sigor@sysoev.ru 
199462Sigor@sysoev.ru     nxt_conn_read(engine, c);
199553Sigor@sysoev.ru }
199653Sigor@sysoev.ru 
199753Sigor@sysoev.ru 
199862Sigor@sysoev.ru static const nxt_conn_state_t  nxt_router_conn_write_state
199953Sigor@sysoev.ru     nxt_aligned(64) =
200053Sigor@sysoev.ru {
200188Smax.romanov@nginx.com     .ready_handler = nxt_router_conn_ready,
200253Sigor@sysoev.ru     .close_handler = nxt_router_conn_close,
200353Sigor@sysoev.ru     .error_handler = nxt_router_conn_error,
200453Sigor@sysoev.ru };
200553Sigor@sysoev.ru 
200653Sigor@sysoev.ru 
200753Sigor@sysoev.ru static void
2008119Smax.romanov@nginx.com nxt_router_app_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
200988Smax.romanov@nginx.com {
201088Smax.romanov@nginx.com     size_t               dump_size;
2011194Smax.romanov@nginx.com     nxt_buf_t            *b, *last;
201288Smax.romanov@nginx.com     nxt_conn_t           *c;
201388Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
201488Smax.romanov@nginx.com     nxt_event_engine_t   *engine;
201588Smax.romanov@nginx.com 
201688Smax.romanov@nginx.com     b = msg->buf;
201788Smax.romanov@nginx.com     engine = task->thread->engine;
201888Smax.romanov@nginx.com 
201988Smax.romanov@nginx.com     rc = nxt_event_engine_request_find(engine, msg->port_msg.stream);
202088Smax.romanov@nginx.com     if (nxt_slow_path(rc == NULL)) {
202188Smax.romanov@nginx.com         nxt_debug(task, "request id %08uxD not found", msg->port_msg.stream);
202288Smax.romanov@nginx.com 
202388Smax.romanov@nginx.com         return;
202488Smax.romanov@nginx.com     }
202588Smax.romanov@nginx.com 
202688Smax.romanov@nginx.com     c = rc->conn;
202788Smax.romanov@nginx.com 
202888Smax.romanov@nginx.com     dump_size = nxt_buf_used_size(b);
202988Smax.romanov@nginx.com 
203088Smax.romanov@nginx.com     if (dump_size > 300) {
203188Smax.romanov@nginx.com         dump_size = 300;
203288Smax.romanov@nginx.com     }
203388Smax.romanov@nginx.com 
2034119Smax.romanov@nginx.com     nxt_debug(task, "%srouter app data (%z): %*s",
203588Smax.romanov@nginx.com               msg->port_msg.last ? "last " : "", msg->size, dump_size,
203688Smax.romanov@nginx.com               b->mem.pos);
203788Smax.romanov@nginx.com 
203888Smax.romanov@nginx.com     if (msg->size == 0) {
203988Smax.romanov@nginx.com         b = NULL;
204088Smax.romanov@nginx.com     }
204188Smax.romanov@nginx.com 
204288Smax.romanov@nginx.com     if (msg->port_msg.last != 0) {
204388Smax.romanov@nginx.com         nxt_debug(task, "router data create last buf");
204488Smax.romanov@nginx.com 
204588Smax.romanov@nginx.com         last = nxt_buf_sync_alloc(c->mem_pool, NXT_BUF_SYNC_LAST);
204688Smax.romanov@nginx.com         if (nxt_slow_path(last == NULL)) {
204788Smax.romanov@nginx.com             /* TODO pogorevaTb */
204888Smax.romanov@nginx.com         }
204988Smax.romanov@nginx.com 
205088Smax.romanov@nginx.com         nxt_buf_chain_add(&b, last);
2051167Smax.romanov@nginx.com 
2052167Smax.romanov@nginx.com         if (rc->app_port != NULL) {
2053167Smax.romanov@nginx.com             nxt_router_app_release_port(task, rc->app_port, rc->app_port->app);
2054167Smax.romanov@nginx.com 
2055167Smax.romanov@nginx.com             rc->app_port = NULL;
2056167Smax.romanov@nginx.com         }
2057206Smax.romanov@nginx.com 
2058206Smax.romanov@nginx.com         rc->conn = NULL;
205988Smax.romanov@nginx.com     }
206088Smax.romanov@nginx.com 
206188Smax.romanov@nginx.com     if (b == NULL) {
206288Smax.romanov@nginx.com         return;
206388Smax.romanov@nginx.com     }
206488Smax.romanov@nginx.com 
2065206Smax.romanov@nginx.com     if (msg->buf == b) {
2066206Smax.romanov@nginx.com         /* Disable instant buffer completion/re-using by port. */
2067206Smax.romanov@nginx.com         msg->buf = NULL;
2068206Smax.romanov@nginx.com     }
2069194Smax.romanov@nginx.com 
207088Smax.romanov@nginx.com     if (c->write == NULL) {
207188Smax.romanov@nginx.com         c->write = b;
207288Smax.romanov@nginx.com         c->write_state = &nxt_router_conn_write_state;
207388Smax.romanov@nginx.com 
207488Smax.romanov@nginx.com         nxt_conn_write(task->thread->engine, c);
2075277Sigor@sysoev.ru 
207688Smax.romanov@nginx.com     } else {
207788Smax.romanov@nginx.com         nxt_debug(task, "router data attach out bufs to existing chain");
207888Smax.romanov@nginx.com 
207988Smax.romanov@nginx.com         nxt_buf_chain_add(&c->write, b);
208088Smax.romanov@nginx.com     }
208188Smax.romanov@nginx.com }
208288Smax.romanov@nginx.com 
2083277Sigor@sysoev.ru 
2084141Smax.romanov@nginx.com nxt_inline const char *
2085141Smax.romanov@nginx.com nxt_router_text_by_code(int code)
2086141Smax.romanov@nginx.com {
2087141Smax.romanov@nginx.com     switch (code) {
2088141Smax.romanov@nginx.com     case 400: return "Bad request";
2089141Smax.romanov@nginx.com     case 404: return "Not found";
2090141Smax.romanov@nginx.com     case 403: return "Forbidden";
2091206Smax.romanov@nginx.com     case 408: return "Request Timeout";
2092206Smax.romanov@nginx.com     case 411: return "Length Required";
2093206Smax.romanov@nginx.com     case 413: return "Request Entity Too Large";
2094141Smax.romanov@nginx.com     case 500:
2095141Smax.romanov@nginx.com     default:  return "Internal server error";
2096141Smax.romanov@nginx.com     }
2097141Smax.romanov@nginx.com }
2098141Smax.romanov@nginx.com 
2099163Smax.romanov@nginx.com 
2100163Smax.romanov@nginx.com static nxt_buf_t *
2101163Smax.romanov@nginx.com nxt_router_get_error_buf(nxt_task_t *task, nxt_mp_t *mp, int code,
2102163Smax.romanov@nginx.com     const char* fmt, va_list args)
210388Smax.romanov@nginx.com {
2104163Smax.romanov@nginx.com     nxt_buf_t   *b, *last;
2105163Smax.romanov@nginx.com     const char  *msg;
2106163Smax.romanov@nginx.com 
2107163Smax.romanov@nginx.com     b = nxt_buf_mem_ts_alloc(task, mp, 16384);
2108141Smax.romanov@nginx.com     if (nxt_slow_path(b == NULL)) {
2109163Smax.romanov@nginx.com         return NULL;
2110141Smax.romanov@nginx.com     }
2111141Smax.romanov@nginx.com 
2112141Smax.romanov@nginx.com     b->mem.free = nxt_sprintf(b->mem.free, b->mem.end,
2113141Smax.romanov@nginx.com         "HTTP/1.0 %d %s\r\n"
2114141Smax.romanov@nginx.com         "Content-Type: text/plain\r\n"
2115141Smax.romanov@nginx.com         "Connection: close\r\n\r\n",
2116141Smax.romanov@nginx.com         code, nxt_router_text_by_code(code));
2117141Smax.romanov@nginx.com 
2118141Smax.romanov@nginx.com     msg = (const char *) b->mem.free;
2119141Smax.romanov@nginx.com 
2120141Smax.romanov@nginx.com     b->mem.free = nxt_vsprintf(b->mem.free, b->mem.end, fmt, args);
2121206Smax.romanov@nginx.com     b->mem.free[0] = '\0';
2122141Smax.romanov@nginx.com 
2123141Smax.romanov@nginx.com     nxt_log_alert(task->log, "error %d: %s", code, msg);
2124141Smax.romanov@nginx.com 
2125163Smax.romanov@nginx.com     last = nxt_buf_mem_ts_alloc(task, mp, 0);
2126163Smax.romanov@nginx.com 
2127141Smax.romanov@nginx.com     if (nxt_slow_path(last == NULL)) {
2128163Smax.romanov@nginx.com         nxt_mp_release(mp, b);
2129163Smax.romanov@nginx.com         return NULL;
2130141Smax.romanov@nginx.com     }
2131141Smax.romanov@nginx.com 
2132163Smax.romanov@nginx.com     nxt_buf_set_sync(last);
2133163Smax.romanov@nginx.com     nxt_buf_set_last(last);
2134163Smax.romanov@nginx.com 
2135141Smax.romanov@nginx.com     nxt_buf_chain_add(&b, last);
2136141Smax.romanov@nginx.com 
2137163Smax.romanov@nginx.com     return b;
2138163Smax.romanov@nginx.com }
2139163Smax.romanov@nginx.com 
2140163Smax.romanov@nginx.com 
2141163Smax.romanov@nginx.com 
2142163Smax.romanov@nginx.com static void
2143163Smax.romanov@nginx.com nxt_router_gen_error(nxt_task_t *task, nxt_conn_t *c, int code,
2144163Smax.romanov@nginx.com     const char* fmt, ...)
2145163Smax.romanov@nginx.com {
2146163Smax.romanov@nginx.com     va_list    args;
2147163Smax.romanov@nginx.com     nxt_buf_t  *b;
2148163Smax.romanov@nginx.com 
2149163Smax.romanov@nginx.com     va_start(args, fmt);
2150163Smax.romanov@nginx.com     b = nxt_router_get_error_buf(task, c->mem_pool, code, fmt, args);
2151163Smax.romanov@nginx.com     va_end(args);
2152163Smax.romanov@nginx.com 
2153206Smax.romanov@nginx.com     if (c->socket.data != NULL) {
2154206Smax.romanov@nginx.com         nxt_mp_free(c->mem_pool, c->socket.data);
2155206Smax.romanov@nginx.com         c->socket.data = NULL;
2156206Smax.romanov@nginx.com     }
2157206Smax.romanov@nginx.com 
2158273Smax.romanov@nginx.com     if (c->socket.fd == -1) {
2159273Smax.romanov@nginx.com         nxt_mp_release(c->mem_pool, b->next);
2160273Smax.romanov@nginx.com         nxt_mp_release(c->mem_pool, b);
2161273Smax.romanov@nginx.com         return;
2162273Smax.romanov@nginx.com     }
2163273Smax.romanov@nginx.com 
2164141Smax.romanov@nginx.com     if (c->write == NULL) {
2165141Smax.romanov@nginx.com         c->write = b;
2166141Smax.romanov@nginx.com         c->write_state = &nxt_router_conn_write_state;
2167141Smax.romanov@nginx.com 
2168141Smax.romanov@nginx.com         nxt_conn_write(task->thread->engine, c);
2169277Sigor@sysoev.ru 
2170141Smax.romanov@nginx.com     } else {
2171141Smax.romanov@nginx.com         nxt_debug(task, "router data attach out bufs to existing chain");
2172141Smax.romanov@nginx.com 
2173141Smax.romanov@nginx.com         nxt_buf_chain_add(&c->write, b);
2174141Smax.romanov@nginx.com     }
2175141Smax.romanov@nginx.com }
2176141Smax.romanov@nginx.com 
2177141Smax.romanov@nginx.com 
2178141Smax.romanov@nginx.com static void
2179192Smax.romanov@nginx.com nxt_router_sw_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, void *data)
2180192Smax.romanov@nginx.com {
2181192Smax.romanov@nginx.com     nxt_start_worker_t  *sw;
2182192Smax.romanov@nginx.com 
2183192Smax.romanov@nginx.com     sw = data;
2184192Smax.romanov@nginx.com 
2185192Smax.romanov@nginx.com     nxt_assert(sw != NULL);
2186192Smax.romanov@nginx.com     nxt_assert(sw->app->pending_workers != 0);
2187192Smax.romanov@nginx.com 
2188192Smax.romanov@nginx.com     msg->new_port->app = sw->app;
2189192Smax.romanov@nginx.com 
2190192Smax.romanov@nginx.com     sw->app->pending_workers--;
2191192Smax.romanov@nginx.com     sw->app->workers++;
2192192Smax.romanov@nginx.com 
2193192Smax.romanov@nginx.com     nxt_debug(task, "sw %p got port %p", sw, msg->new_port);
2194192Smax.romanov@nginx.com 
2195192Smax.romanov@nginx.com     nxt_router_app_release_port(task, msg->new_port, sw->app);
2196192Smax.romanov@nginx.com 
2197192Smax.romanov@nginx.com     nxt_router_sw_release(task, sw);
2198192Smax.romanov@nginx.com }
2199192Smax.romanov@nginx.com 
2200192Smax.romanov@nginx.com 
2201192Smax.romanov@nginx.com static void
2202192Smax.romanov@nginx.com nxt_router_sw_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, void *data)
2203192Smax.romanov@nginx.com {
2204192Smax.romanov@nginx.com     nxt_start_worker_t  *sw;
2205192Smax.romanov@nginx.com 
2206192Smax.romanov@nginx.com     sw = data;
2207192Smax.romanov@nginx.com 
2208192Smax.romanov@nginx.com     nxt_assert(sw != NULL);
2209192Smax.romanov@nginx.com     nxt_assert(sw->app->pending_workers != 0);
2210192Smax.romanov@nginx.com 
2211192Smax.romanov@nginx.com     sw->app->pending_workers--;
2212192Smax.romanov@nginx.com 
2213277Sigor@sysoev.ru     nxt_debug(task, "sw %p error, failed to start app '%V'",
2214277Sigor@sysoev.ru               sw, &sw->app->name);
2215192Smax.romanov@nginx.com 
2216192Smax.romanov@nginx.com     nxt_router_sw_release(task, sw);
2217192Smax.romanov@nginx.com }
2218192Smax.romanov@nginx.com 
2219192Smax.romanov@nginx.com 
2220192Smax.romanov@nginx.com static void
2221141Smax.romanov@nginx.com nxt_router_send_sw_request(nxt_task_t *task, void *obj, void *data)
2222141Smax.romanov@nginx.com {
2223174Sigor@sysoev.ru     size_t              size;
2224192Smax.romanov@nginx.com     uint32_t            stream;
2225141Smax.romanov@nginx.com     nxt_buf_t           *b;
2226141Smax.romanov@nginx.com     nxt_app_t           *app;
2227274Smax.romanov@nginx.com     nxt_port_t          *main_port, *router_port, *app_port;
2228141Smax.romanov@nginx.com     nxt_runtime_t       *rt;
2229141Smax.romanov@nginx.com     nxt_start_worker_t  *sw;
2230274Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
2231141Smax.romanov@nginx.com 
2232141Smax.romanov@nginx.com     sw = obj;
2233141Smax.romanov@nginx.com     app = sw->app;
2234141Smax.romanov@nginx.com 
2235274Smax.romanov@nginx.com     if (nxt_queue_is_empty(&app->requests)) {
2236274Smax.romanov@nginx.com         ra = sw->ra;
2237274Smax.romanov@nginx.com         app_port = nxt_router_app_get_port(app, ra->req_id);
2238274Smax.romanov@nginx.com 
2239274Smax.romanov@nginx.com         if (app_port != NULL) {
2240274Smax.romanov@nginx.com             nxt_debug(task, "app '%V' %p process request #%uxD",
2241274Smax.romanov@nginx.com                       &app->name, app, ra->req_id);
2242274Smax.romanov@nginx.com 
2243274Smax.romanov@nginx.com             ra->app_port = app_port;
2244274Smax.romanov@nginx.com 
2245274Smax.romanov@nginx.com             nxt_router_process_http_request_mp(task, ra, app_port);
2246274Smax.romanov@nginx.com 
2247274Smax.romanov@nginx.com             nxt_router_ra_release(task, ra, ra->work.data);
2248274Smax.romanov@nginx.com             nxt_router_sw_release(task, sw);
2249274Smax.romanov@nginx.com 
2250274Smax.romanov@nginx.com             return;
2251274Smax.romanov@nginx.com         }
2252274Smax.romanov@nginx.com     }
2253274Smax.romanov@nginx.com 
2254167Smax.romanov@nginx.com     nxt_queue_insert_tail(&app->requests, &sw->ra->link);
2255167Smax.romanov@nginx.com 
2256163Smax.romanov@nginx.com     if (app->workers + app->pending_workers >= app->max_workers) {
2257244Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p %uD/%uD running/pending workers, "
2258244Smax.romanov@nginx.com                   "max_workers (%uD) reached", &app->name, app,
2259244Smax.romanov@nginx.com                    app->workers, app->pending_workers, app->max_workers);
2260192Smax.romanov@nginx.com 
2261192Smax.romanov@nginx.com         nxt_router_sw_release(task, sw);
2262163Smax.romanov@nginx.com 
2263163Smax.romanov@nginx.com         return;
2264163Smax.romanov@nginx.com     }
2265163Smax.romanov@nginx.com 
2266163Smax.romanov@nginx.com     app->pending_workers++;
2267163Smax.romanov@nginx.com 
2268192Smax.romanov@nginx.com     nxt_debug(task, "sw %p send", sw);
226988Smax.romanov@nginx.com 
2270119Smax.romanov@nginx.com     rt = task->thread->runtime;
2271240Sigor@sysoev.ru     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
2272192Smax.romanov@nginx.com     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
2273141Smax.romanov@nginx.com 
2274174Sigor@sysoev.ru     size = app->name.length + 1 + app->conf.length;
2275174Sigor@sysoev.ru 
2276240Sigor@sysoev.ru     b = nxt_buf_mem_alloc(main_port->mem_pool, size, 0);
2277174Sigor@sysoev.ru 
2278174Sigor@sysoev.ru     nxt_buf_cpystr(b, &app->name);
2279174Sigor@sysoev.ru     *b->mem.free++ = '\0';
2280141Smax.romanov@nginx.com     nxt_buf_cpystr(b, &app->conf);
2281141Smax.romanov@nginx.com 
2282192Smax.romanov@nginx.com     stream = nxt_port_rpc_register_handler(task, router_port,
2283192Smax.romanov@nginx.com                                            nxt_router_sw_ready,
2284192Smax.romanov@nginx.com                                            nxt_router_sw_error,
2285240Sigor@sysoev.ru                                            main_port->pid, sw);
2286240Sigor@sysoev.ru 
2287240Sigor@sysoev.ru     nxt_port_socket_write(task, main_port, NXT_PORT_MSG_START_WORKER, -1,
2288192Smax.romanov@nginx.com                           stream, router_port->id, b);
2289141Smax.romanov@nginx.com }
2290141Smax.romanov@nginx.com 
2291141Smax.romanov@nginx.com 
2292163Smax.romanov@nginx.com static nxt_bool_t
2293167Smax.romanov@nginx.com nxt_router_app_free(nxt_task_t *task, nxt_app_t *app)
2294163Smax.romanov@nginx.com {
2295192Smax.romanov@nginx.com     nxt_queue_link_t    *lnk;
2296192Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
2297167Smax.romanov@nginx.com 
2298167Smax.romanov@nginx.com     nxt_thread_log_debug("app '%V' %p state: %d/%uD/%uD/%d", &app->name, app,
2299167Smax.romanov@nginx.com                          app->live, app->workers, app->pending_workers,
2300167Smax.romanov@nginx.com                          nxt_queue_is_empty(&app->requests));
2301167Smax.romanov@nginx.com 
2302277Sigor@sysoev.ru     if (app->live == 0
2303277Sigor@sysoev.ru         && app->workers == 0
2304277Sigor@sysoev.ru         && app->pending_workers == 0
2305277Sigor@sysoev.ru         && nxt_queue_is_empty(&app->requests))
2306277Sigor@sysoev.ru     {
2307163Smax.romanov@nginx.com         nxt_thread_mutex_destroy(&app->mutex);
2308163Smax.romanov@nginx.com         nxt_free(app);
2309163Smax.romanov@nginx.com 
2310163Smax.romanov@nginx.com         return 1;
2311163Smax.romanov@nginx.com     }
2312163Smax.romanov@nginx.com 
2313277Sigor@sysoev.ru     if (app->live == 1
2314277Sigor@sysoev.ru         && nxt_queue_is_empty(&app->requests) == 0
2315277Sigor@sysoev.ru         && app->workers + app->pending_workers < app->max_workers)
2316277Sigor@sysoev.ru     {
2317167Smax.romanov@nginx.com         lnk = nxt_queue_first(&app->requests);
2318167Smax.romanov@nginx.com         nxt_queue_remove(lnk);
2319167Smax.romanov@nginx.com 
2320167Smax.romanov@nginx.com         ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link);
2321167Smax.romanov@nginx.com 
2322192Smax.romanov@nginx.com         nxt_router_sw_create(task, app, ra);
2323167Smax.romanov@nginx.com     }
2324167Smax.romanov@nginx.com 
2325163Smax.romanov@nginx.com     return 0;
2326163Smax.romanov@nginx.com }
2327163Smax.romanov@nginx.com 
2328163Smax.romanov@nginx.com 
2329141Smax.romanov@nginx.com static nxt_port_t *
2330167Smax.romanov@nginx.com nxt_router_app_get_port(nxt_app_t *app, uint32_t req_id)
2331141Smax.romanov@nginx.com {
2332141Smax.romanov@nginx.com     nxt_port_t        *port;
2333141Smax.romanov@nginx.com     nxt_queue_link_t  *lnk;
2334141Smax.romanov@nginx.com 
2335141Smax.romanov@nginx.com     port = NULL;
2336141Smax.romanov@nginx.com 
2337141Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
2338141Smax.romanov@nginx.com 
2339141Smax.romanov@nginx.com     if (!nxt_queue_is_empty(&app->ports)) {
2340141Smax.romanov@nginx.com         lnk = nxt_queue_first(&app->ports);
2341141Smax.romanov@nginx.com         nxt_queue_remove(lnk);
2342141Smax.romanov@nginx.com 
2343141Smax.romanov@nginx.com         lnk->next = NULL;
2344141Smax.romanov@nginx.com 
2345141Smax.romanov@nginx.com         port = nxt_queue_link_data(lnk, nxt_port_t, app_link);
2346167Smax.romanov@nginx.com 
2347167Smax.romanov@nginx.com         port->app_req_id = req_id;
2348141Smax.romanov@nginx.com     }
2349141Smax.romanov@nginx.com 
2350141Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
2351141Smax.romanov@nginx.com 
2352141Smax.romanov@nginx.com     return port;
2353141Smax.romanov@nginx.com }
2354141Smax.romanov@nginx.com 
2355141Smax.romanov@nginx.com 
2356141Smax.romanov@nginx.com static void
2357141Smax.romanov@nginx.com nxt_router_app_release_port(nxt_task_t *task, void *obj, void *data)
2358141Smax.romanov@nginx.com {
2359141Smax.romanov@nginx.com     nxt_app_t            *app;
2360141Smax.romanov@nginx.com     nxt_port_t           *port;
2361141Smax.romanov@nginx.com     nxt_work_t           *work;
2362141Smax.romanov@nginx.com     nxt_queue_link_t     *lnk;
2363167Smax.romanov@nginx.com     nxt_req_app_link_t   *ra;
2364141Smax.romanov@nginx.com 
2365141Smax.romanov@nginx.com     port = obj;
2366141Smax.romanov@nginx.com     app = data;
2367141Smax.romanov@nginx.com 
2368141Smax.romanov@nginx.com     nxt_assert(app != NULL);
2369141Smax.romanov@nginx.com     nxt_assert(app == port->app);
2370141Smax.romanov@nginx.com     nxt_assert(port->app_link.next == NULL);
2371141Smax.romanov@nginx.com 
2372141Smax.romanov@nginx.com 
2373141Smax.romanov@nginx.com     if (task->thread->engine != port->engine) {
2374163Smax.romanov@nginx.com         work = &port->work;
2375141Smax.romanov@nginx.com 
2376141Smax.romanov@nginx.com         nxt_debug(task, "post release port to engine %p", port->engine);
2377141Smax.romanov@nginx.com 
2378141Smax.romanov@nginx.com         work->next = NULL;
2379141Smax.romanov@nginx.com         work->handler = nxt_router_app_release_port;
2380166Smax.romanov@nginx.com         work->task = &port->engine->task;
2381141Smax.romanov@nginx.com         work->obj = port;
2382141Smax.romanov@nginx.com         work->data = app;
2383141Smax.romanov@nginx.com 
2384141Smax.romanov@nginx.com         nxt_event_engine_post(port->engine, work);
2385141Smax.romanov@nginx.com 
2386141Smax.romanov@nginx.com         return;
2387141Smax.romanov@nginx.com     }
2388141Smax.romanov@nginx.com 
2389141Smax.romanov@nginx.com     if (!nxt_queue_is_empty(&app->requests)) {
2390141Smax.romanov@nginx.com         lnk = nxt_queue_first(&app->requests);
2391141Smax.romanov@nginx.com         nxt_queue_remove(lnk);
2392141Smax.romanov@nginx.com 
2393167Smax.romanov@nginx.com         ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link);
2394167Smax.romanov@nginx.com 
2395167Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p process next request #%uxD",
2396167Smax.romanov@nginx.com                   &app->name, app, ra->req_id);
2397167Smax.romanov@nginx.com 
2398167Smax.romanov@nginx.com         ra->app_port = port;
2399182Smax.romanov@nginx.com         port->app_req_id = ra->req_id;
2400167Smax.romanov@nginx.com 
2401167Smax.romanov@nginx.com         nxt_router_process_http_request_mp(task, ra, port);
2402167Smax.romanov@nginx.com 
2403167Smax.romanov@nginx.com         nxt_router_ra_release(task, ra, ra->work.data);
2404141Smax.romanov@nginx.com 
2405141Smax.romanov@nginx.com         return;
2406141Smax.romanov@nginx.com     }
2407141Smax.romanov@nginx.com 
2408167Smax.romanov@nginx.com     port->app_req_id = 0;
2409167Smax.romanov@nginx.com 
2410163Smax.romanov@nginx.com     if (port->pair[1] == -1) {
2411167Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p port already closed (pid %PI dead?)",
2412167Smax.romanov@nginx.com                   &app->name, app, port->pid);
2413163Smax.romanov@nginx.com 
2414163Smax.romanov@nginx.com         app->workers--;
2415167Smax.romanov@nginx.com         nxt_router_app_free(task, app);
2416163Smax.romanov@nginx.com 
2417163Smax.romanov@nginx.com         port->app = NULL;
2418163Smax.romanov@nginx.com 
2419163Smax.romanov@nginx.com         nxt_port_release(port);
2420163Smax.romanov@nginx.com 
2421163Smax.romanov@nginx.com         return;
2422163Smax.romanov@nginx.com     }
2423163Smax.romanov@nginx.com 
2424163Smax.romanov@nginx.com     if (!app->live) {
2425167Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p is not alive, send QUIT to port",
2426167Smax.romanov@nginx.com                   &app->name, app);
2427163Smax.romanov@nginx.com 
2428163Smax.romanov@nginx.com         nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT,
2429163Smax.romanov@nginx.com                               -1, 0, 0, NULL);
2430163Smax.romanov@nginx.com 
2431163Smax.romanov@nginx.com         return;
2432163Smax.romanov@nginx.com     }
2433163Smax.romanov@nginx.com 
2434167Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p requests queue is empty, keep the port",
2435167Smax.romanov@nginx.com               &app->name, app);
2436141Smax.romanov@nginx.com 
2437141Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
2438141Smax.romanov@nginx.com 
2439141Smax.romanov@nginx.com     nxt_queue_insert_head(&app->ports, &port->app_link);
2440141Smax.romanov@nginx.com 
2441141Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
2442141Smax.romanov@nginx.com }
2443141Smax.romanov@nginx.com 
2444141Smax.romanov@nginx.com 
2445163Smax.romanov@nginx.com nxt_bool_t
2446141Smax.romanov@nginx.com nxt_router_app_remove_port(nxt_port_t *port)
2447141Smax.romanov@nginx.com {
2448163Smax.romanov@nginx.com     nxt_app_t   *app;
2449163Smax.romanov@nginx.com     nxt_bool_t  busy;
2450141Smax.romanov@nginx.com 
2451141Smax.romanov@nginx.com     app = port->app;
2452167Smax.romanov@nginx.com     busy = port->app_req_id != 0;
2453163Smax.romanov@nginx.com 
2454163Smax.romanov@nginx.com     if (app == NULL) {
2455167Smax.romanov@nginx.com         nxt_thread_log_debug("port %p app remove, no app", port);
2456167Smax.romanov@nginx.com 
2457163Smax.romanov@nginx.com         nxt_assert(port->app_link.next == NULL);
2458163Smax.romanov@nginx.com 
2459163Smax.romanov@nginx.com         return 1;
2460141Smax.romanov@nginx.com     }
2461141Smax.romanov@nginx.com 
2462141Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
2463141Smax.romanov@nginx.com 
2464163Smax.romanov@nginx.com     if (port->app_link.next != NULL) {
2465163Smax.romanov@nginx.com 
2466163Smax.romanov@nginx.com         nxt_queue_remove(&port->app_link);
2467163Smax.romanov@nginx.com         port->app_link.next = NULL;
2468163Smax.romanov@nginx.com 
2469163Smax.romanov@nginx.com     }
2470141Smax.romanov@nginx.com 
2471141Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
2472163Smax.romanov@nginx.com 
2473163Smax.romanov@nginx.com     if (busy == 0) {
2474167Smax.romanov@nginx.com         nxt_thread_log_debug("port %p app remove, free, app '%V' %p", port,
2475167Smax.romanov@nginx.com                              &app->name, app);
2476163Smax.romanov@nginx.com 
2477163Smax.romanov@nginx.com         app->workers--;
2478167Smax.romanov@nginx.com         nxt_router_app_free(&port->engine->task, app);
2479163Smax.romanov@nginx.com 
2480163Smax.romanov@nginx.com         return 1;
2481163Smax.romanov@nginx.com     }
2482163Smax.romanov@nginx.com 
2483167Smax.romanov@nginx.com     nxt_thread_log_debug("port %p app remove, busy, app '%V' %p, req #%uxD",
2484167Smax.romanov@nginx.com                          port, &app->name, app, port->app_req_id);
2485167Smax.romanov@nginx.com 
2486163Smax.romanov@nginx.com     return 0;
2487141Smax.romanov@nginx.com }
2488141Smax.romanov@nginx.com 
2489141Smax.romanov@nginx.com 
2490167Smax.romanov@nginx.com static nxt_int_t
2491167Smax.romanov@nginx.com nxt_router_app_port(nxt_task_t *task, nxt_req_app_link_t *ra)
2492141Smax.romanov@nginx.com {
2493141Smax.romanov@nginx.com     nxt_app_t                *app;
2494141Smax.romanov@nginx.com     nxt_conn_t               *c;
2495167Smax.romanov@nginx.com     nxt_port_t               *port;
2496141Smax.romanov@nginx.com     nxt_start_worker_t       *sw;
2497141Smax.romanov@nginx.com     nxt_socket_conf_joint_t  *joint;
2498141Smax.romanov@nginx.com 
2499141Smax.romanov@nginx.com     port = NULL;
2500167Smax.romanov@nginx.com     c = ra->rc->conn;
2501141Smax.romanov@nginx.com 
2502141Smax.romanov@nginx.com     joint = c->listen->socket.data;
2503141Smax.romanov@nginx.com     app = joint->socket_conf->application;
2504141Smax.romanov@nginx.com 
2505141Smax.romanov@nginx.com     if (app == NULL) {
2506167Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 500,
2507141Smax.romanov@nginx.com                              "Application is NULL in socket_conf");
2508141Smax.romanov@nginx.com         return NXT_ERROR;
2509141Smax.romanov@nginx.com     }
2510141Smax.romanov@nginx.com 
2511141Smax.romanov@nginx.com 
2512167Smax.romanov@nginx.com     port = nxt_router_app_get_port(app, ra->req_id);
2513141Smax.romanov@nginx.com 
2514141Smax.romanov@nginx.com     if (port != NULL) {
2515163Smax.romanov@nginx.com         nxt_debug(task, "already have port for app '%V'", &app->name);
2516163Smax.romanov@nginx.com 
2517167Smax.romanov@nginx.com         ra->app_port = port;
2518141Smax.romanov@nginx.com         return NXT_OK;
2519141Smax.romanov@nginx.com     }
2520141Smax.romanov@nginx.com 
2521192Smax.romanov@nginx.com     sw = nxt_router_sw_create(task, app, ra);
2522141Smax.romanov@nginx.com 
2523141Smax.romanov@nginx.com     if (nxt_slow_path(sw == NULL)) {
2524167Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 500,
2525141Smax.romanov@nginx.com                              "Failed to allocate start worker struct");
2526141Smax.romanov@nginx.com         return NXT_ERROR;
2527141Smax.romanov@nginx.com     }
2528141Smax.romanov@nginx.com 
2529141Smax.romanov@nginx.com     return NXT_AGAIN;
253088Smax.romanov@nginx.com }
253188Smax.romanov@nginx.com 
253288Smax.romanov@nginx.com 
253388Smax.romanov@nginx.com static void
253453Sigor@sysoev.ru nxt_router_conn_http_header_parse(nxt_task_t *task, void *obj, void *data)
253553Sigor@sysoev.ru {
2536206Smax.romanov@nginx.com     size_t                    size;
253753Sigor@sysoev.ru     nxt_int_t                 ret;
2538206Smax.romanov@nginx.com     nxt_buf_t                 *buf;
253962Sigor@sysoev.ru     nxt_conn_t                *c;
2540268Sigor@sysoev.ru     nxt_sockaddr_t            *local;
254188Smax.romanov@nginx.com     nxt_app_parse_ctx_t       *ap;
2542206Smax.romanov@nginx.com     nxt_app_request_body_t    *b;
254353Sigor@sysoev.ru     nxt_socket_conf_joint_t   *joint;
254488Smax.romanov@nginx.com     nxt_app_request_header_t  *h;
254553Sigor@sysoev.ru 
254653Sigor@sysoev.ru     c = obj;
254788Smax.romanov@nginx.com     ap = data;
2548206Smax.romanov@nginx.com     buf = c->read;
2549206Smax.romanov@nginx.com     joint = c->listen->socket.data;
255053Sigor@sysoev.ru 
255153Sigor@sysoev.ru     nxt_debug(task, "router conn http header parse");
255253Sigor@sysoev.ru 
255388Smax.romanov@nginx.com     if (ap == NULL) {
2554206Smax.romanov@nginx.com         ap = nxt_mp_zalloc(c->mem_pool, sizeof(nxt_app_parse_ctx_t));
255588Smax.romanov@nginx.com         if (nxt_slow_path(ap == NULL)) {
255653Sigor@sysoev.ru             nxt_router_conn_close(task, c, data);
255753Sigor@sysoev.ru             return;
255853Sigor@sysoev.ru         }
255953Sigor@sysoev.ru 
256088Smax.romanov@nginx.com         ret = nxt_app_http_req_init(task, ap);
256161Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
256261Sigor@sysoev.ru             nxt_router_conn_close(task, c, data);
256361Sigor@sysoev.ru             return;
256461Sigor@sysoev.ru         }
256588Smax.romanov@nginx.com 
256688Smax.romanov@nginx.com         c->socket.data = ap;
2567113Smax.romanov@nginx.com 
2568113Smax.romanov@nginx.com         ap->r.remote.start = nxt_sockaddr_address(c->remote);
2569113Smax.romanov@nginx.com         ap->r.remote.length = c->remote->address_length;
2570206Smax.romanov@nginx.com 
2571268Sigor@sysoev.ru         local = joint->socket_conf->sockaddr;
2572268Sigor@sysoev.ru         ap->r.local.start = nxt_sockaddr_address(local);
2573268Sigor@sysoev.ru         ap->r.local.length = local->address_length;
2574268Sigor@sysoev.ru 
2575206Smax.romanov@nginx.com         ap->r.header.buf = buf;
257653Sigor@sysoev.ru     }
257753Sigor@sysoev.ru 
257888Smax.romanov@nginx.com     h = &ap->r.header;
2579206Smax.romanov@nginx.com     b = &ap->r.body;
2580206Smax.romanov@nginx.com 
2581206Smax.romanov@nginx.com     ret = nxt_app_http_req_header_parse(task, ap, buf);
2582206Smax.romanov@nginx.com 
2583206Smax.romanov@nginx.com     nxt_debug(task, "http parse request header: %d", ret);
258453Sigor@sysoev.ru 
258553Sigor@sysoev.ru     switch (nxt_expect(NXT_DONE, ret)) {
258653Sigor@sysoev.ru 
258753Sigor@sysoev.ru     case NXT_DONE:
258888Smax.romanov@nginx.com         nxt_debug(task, "router request header parsing complete, "
258988Smax.romanov@nginx.com                   "content length: %O, preread: %uz",
2590206Smax.romanov@nginx.com                   h->parsed_content_length, nxt_buf_mem_used_size(&buf->mem));
2591206Smax.romanov@nginx.com 
2592206Smax.romanov@nginx.com         if (b->done) {
2593206Smax.romanov@nginx.com             nxt_router_process_http_request(task, c, ap);
2594206Smax.romanov@nginx.com 
2595206Smax.romanov@nginx.com             return;
2596206Smax.romanov@nginx.com         }
2597206Smax.romanov@nginx.com 
2598277Sigor@sysoev.ru         if (joint->socket_conf->max_body_size > 0
2599277Sigor@sysoev.ru             && (size_t) h->parsed_content_length
2600277Sigor@sysoev.ru                > joint->socket_conf->max_body_size)
2601277Sigor@sysoev.ru         {
2602206Smax.romanov@nginx.com             nxt_router_gen_error(task, c, 413, "Content-Length too big");
2603206Smax.romanov@nginx.com             return;
2604206Smax.romanov@nginx.com         }
2605206Smax.romanov@nginx.com 
2606206Smax.romanov@nginx.com         if (nxt_buf_mem_free_size(&buf->mem) == 0) {
2607206Smax.romanov@nginx.com             size = nxt_min(joint->socket_conf->body_buffer_size,
2608206Smax.romanov@nginx.com                            (size_t) h->parsed_content_length);
2609206Smax.romanov@nginx.com 
2610206Smax.romanov@nginx.com             buf->next = nxt_buf_mem_alloc(c->mem_pool, size, 0);
2611206Smax.romanov@nginx.com             if (nxt_slow_path(buf->next == NULL)) {
2612206Smax.romanov@nginx.com                 nxt_router_gen_error(task, c, 500, "Failed to allocate "
2613206Smax.romanov@nginx.com                                      "buffer for request body");
2614206Smax.romanov@nginx.com                 return;
2615206Smax.romanov@nginx.com             }
2616206Smax.romanov@nginx.com 
2617206Smax.romanov@nginx.com             c->read = buf->next;
2618206Smax.romanov@nginx.com 
2619206Smax.romanov@nginx.com             b->preread_size += nxt_buf_mem_used_size(&buf->mem);
2620206Smax.romanov@nginx.com         }
2621206Smax.romanov@nginx.com 
2622206Smax.romanov@nginx.com         if (b->buf == NULL) {
2623206Smax.romanov@nginx.com             b->buf = c->read;
2624206Smax.romanov@nginx.com         }
2625206Smax.romanov@nginx.com 
2626206Smax.romanov@nginx.com         c->read_state = &nxt_router_conn_read_body_state;
2627206Smax.romanov@nginx.com         break;
2628206Smax.romanov@nginx.com 
2629206Smax.romanov@nginx.com     case NXT_ERROR:
2630206Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 400, "Request header parse error");
2631206Smax.romanov@nginx.com         return;
2632206Smax.romanov@nginx.com 
2633206Smax.romanov@nginx.com     default:  /* NXT_AGAIN */
2634206Smax.romanov@nginx.com 
2635206Smax.romanov@nginx.com         if (c->read->mem.free == c->read->mem.end) {
2636206Smax.romanov@nginx.com             size = joint->socket_conf->large_header_buffer_size;
2637206Smax.romanov@nginx.com 
2638277Sigor@sysoev.ru             if (size <= (size_t) nxt_buf_mem_used_size(&buf->mem)
2639277Sigor@sysoev.ru                 || ap->r.header.bufs
2640277Sigor@sysoev.ru                    >= joint->socket_conf->large_header_buffers)
2641277Sigor@sysoev.ru             {
2642206Smax.romanov@nginx.com                 nxt_router_gen_error(task, c, 413,
2643206Smax.romanov@nginx.com                                      "Too long request headers");
2644206Smax.romanov@nginx.com                 return;
2645206Smax.romanov@nginx.com             }
2646206Smax.romanov@nginx.com 
2647206Smax.romanov@nginx.com             buf->next = nxt_buf_mem_alloc(c->mem_pool, size, 0);
2648206Smax.romanov@nginx.com             if (nxt_slow_path(buf->next == NULL)) {
2649206Smax.romanov@nginx.com                 nxt_router_gen_error(task, c, 500,
2650206Smax.romanov@nginx.com                                      "Failed to allocate large header "
2651206Smax.romanov@nginx.com                                      "buffer");
2652206Smax.romanov@nginx.com                 return;
2653206Smax.romanov@nginx.com             }
2654206Smax.romanov@nginx.com 
2655206Smax.romanov@nginx.com             ap->r.header.bufs++;
2656206Smax.romanov@nginx.com 
2657206Smax.romanov@nginx.com             size = c->read->mem.free - c->read->mem.pos;
2658206Smax.romanov@nginx.com 
2659206Smax.romanov@nginx.com             c->read = nxt_buf_cpy(buf->next, c->read->mem.pos, size);
2660206Smax.romanov@nginx.com         }
2661206Smax.romanov@nginx.com 
2662206Smax.romanov@nginx.com     }
2663206Smax.romanov@nginx.com 
2664206Smax.romanov@nginx.com     nxt_conn_read(task->thread->engine, c);
2665206Smax.romanov@nginx.com }
2666206Smax.romanov@nginx.com 
2667206Smax.romanov@nginx.com 
2668206Smax.romanov@nginx.com static void
2669206Smax.romanov@nginx.com nxt_router_conn_http_body_read(nxt_task_t *task, void *obj, void *data)
2670206Smax.romanov@nginx.com {
2671206Smax.romanov@nginx.com     size_t                    size;
2672206Smax.romanov@nginx.com     nxt_int_t                 ret;
2673206Smax.romanov@nginx.com     nxt_buf_t                 *buf;
2674206Smax.romanov@nginx.com     nxt_conn_t                *c;
2675206Smax.romanov@nginx.com     nxt_app_parse_ctx_t       *ap;
2676206Smax.romanov@nginx.com     nxt_app_request_body_t    *b;
2677206Smax.romanov@nginx.com     nxt_socket_conf_joint_t   *joint;
2678206Smax.romanov@nginx.com     nxt_app_request_header_t  *h;
2679206Smax.romanov@nginx.com 
2680206Smax.romanov@nginx.com     c = obj;
2681206Smax.romanov@nginx.com     ap = data;
2682206Smax.romanov@nginx.com     buf = c->read;
2683206Smax.romanov@nginx.com 
2684206Smax.romanov@nginx.com     nxt_debug(task, "router conn http body read");
2685206Smax.romanov@nginx.com 
2686206Smax.romanov@nginx.com     nxt_assert(ap != NULL);
2687206Smax.romanov@nginx.com 
2688206Smax.romanov@nginx.com     b = &ap->r.body;
2689206Smax.romanov@nginx.com     h = &ap->r.header;
2690206Smax.romanov@nginx.com 
2691206Smax.romanov@nginx.com     ret = nxt_app_http_req_body_read(task, ap, buf);
2692206Smax.romanov@nginx.com 
2693206Smax.romanov@nginx.com     nxt_debug(task, "http read request body: %d", ret);
2694206Smax.romanov@nginx.com 
2695206Smax.romanov@nginx.com     switch (nxt_expect(NXT_DONE, ret)) {
2696206Smax.romanov@nginx.com 
2697206Smax.romanov@nginx.com     case NXT_DONE:
269888Smax.romanov@nginx.com         nxt_router_process_http_request(task, c, ap);
269988Smax.romanov@nginx.com         return;
270053Sigor@sysoev.ru 
270153Sigor@sysoev.ru     case NXT_ERROR:
2702206Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 500, "Read body error");
270353Sigor@sysoev.ru         return;
270453Sigor@sysoev.ru 
270553Sigor@sysoev.ru     default:  /* NXT_AGAIN */
270653Sigor@sysoev.ru 
2707206Smax.romanov@nginx.com         if (nxt_buf_mem_free_size(&buf->mem) == 0) {
2708206Smax.romanov@nginx.com             joint = c->listen->socket.data;
2709206Smax.romanov@nginx.com 
2710206Smax.romanov@nginx.com             b->preread_size += nxt_buf_mem_used_size(&buf->mem);
2711206Smax.romanov@nginx.com 
2712206Smax.romanov@nginx.com             size = nxt_min(joint->socket_conf->body_buffer_size,
2713206Smax.romanov@nginx.com                            (size_t) h->parsed_content_length - b->preread_size);
2714206Smax.romanov@nginx.com 
2715206Smax.romanov@nginx.com             buf->next = nxt_buf_mem_alloc(c->mem_pool, size, 0);
2716206Smax.romanov@nginx.com             if (nxt_slow_path(buf->next == NULL)) {
2717206Smax.romanov@nginx.com                 nxt_router_gen_error(task, c, 500, "Failed to allocate "
2718206Smax.romanov@nginx.com                                      "buffer for request body");
2719206Smax.romanov@nginx.com                 return;
272088Smax.romanov@nginx.com             }
2721206Smax.romanov@nginx.com 
2722206Smax.romanov@nginx.com             c->read = buf->next;
272388Smax.romanov@nginx.com         }
272488Smax.romanov@nginx.com 
2725206Smax.romanov@nginx.com         nxt_debug(task, "router request body read again, rest: %uz",
2726206Smax.romanov@nginx.com                   h->parsed_content_length - b->preread_size);
272788Smax.romanov@nginx.com     }
272888Smax.romanov@nginx.com 
272988Smax.romanov@nginx.com     nxt_conn_read(task->thread->engine, c);
273088Smax.romanov@nginx.com }
273188Smax.romanov@nginx.com 
273288Smax.romanov@nginx.com 
273388Smax.romanov@nginx.com static void
273488Smax.romanov@nginx.com nxt_router_process_http_request(nxt_task_t *task, nxt_conn_t *c,
273588Smax.romanov@nginx.com     nxt_app_parse_ctx_t *ap)
273688Smax.romanov@nginx.com {
2737167Smax.romanov@nginx.com     nxt_mp_t             *port_mp;
2738122Smax.romanov@nginx.com     nxt_int_t            res;
2739167Smax.romanov@nginx.com     nxt_port_t           *port;
274088Smax.romanov@nginx.com     nxt_req_id_t         req_id;
274188Smax.romanov@nginx.com     nxt_event_engine_t   *engine;
2742167Smax.romanov@nginx.com     nxt_req_app_link_t   *ra;
274388Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
274488Smax.romanov@nginx.com 
274588Smax.romanov@nginx.com     engine = task->thread->engine;
274688Smax.romanov@nginx.com 
274788Smax.romanov@nginx.com     do {
2748138Sigor@sysoev.ru         req_id = nxt_random(&task->thread->random);
274988Smax.romanov@nginx.com     } while (nxt_event_engine_request_find(engine, req_id) != NULL);
275088Smax.romanov@nginx.com 
275188Smax.romanov@nginx.com     rc = nxt_conn_request_add(c, req_id);
2752122Smax.romanov@nginx.com 
275388Smax.romanov@nginx.com     if (nxt_slow_path(rc == NULL)) {
2754141Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 500, "Failed to allocate "
2755141Smax.romanov@nginx.com                              "req->conn link");
2756141Smax.romanov@nginx.com 
2757141Smax.romanov@nginx.com         return;
275888Smax.romanov@nginx.com     }
275988Smax.romanov@nginx.com 
276088Smax.romanov@nginx.com     nxt_event_engine_request_add(engine, rc);
276188Smax.romanov@nginx.com 
276288Smax.romanov@nginx.com     nxt_debug(task, "req_id %uxD linked to conn %p at engine %p",
276388Smax.romanov@nginx.com               req_id, c, engine);
276453Sigor@sysoev.ru 
2765273Smax.romanov@nginx.com     c->socket.data = NULL;
2766167Smax.romanov@nginx.com 
2767167Smax.romanov@nginx.com     ra = nxt_router_ra_create(task, rc);
2768167Smax.romanov@nginx.com 
2769167Smax.romanov@nginx.com     ra->ap = ap;
2770167Smax.romanov@nginx.com     ra->reply_port = engine->port;
2771167Smax.romanov@nginx.com 
2772167Smax.romanov@nginx.com     res = nxt_router_app_port(task, ra);
2773141Smax.romanov@nginx.com 
2774141Smax.romanov@nginx.com     if (res != NXT_OK) {
2775141Smax.romanov@nginx.com         return;
2776141Smax.romanov@nginx.com     }
2777141Smax.romanov@nginx.com 
2778167Smax.romanov@nginx.com     port = ra->app_port;
2779141Smax.romanov@nginx.com 
2780141Smax.romanov@nginx.com     if (nxt_slow_path(port == NULL)) {
2781141Smax.romanov@nginx.com         nxt_router_gen_error(task, rc->conn, 500, "Application port not found");
2782141Smax.romanov@nginx.com         return;
2783141Smax.romanov@nginx.com     }
2784141Smax.romanov@nginx.com 
2785122Smax.romanov@nginx.com     port_mp = port->mem_pool;
2786167Smax.romanov@nginx.com     port->mem_pool = c->mem_pool;
2787167Smax.romanov@nginx.com 
2788167Smax.romanov@nginx.com     nxt_router_process_http_request_mp(task, ra, port);
2789167Smax.romanov@nginx.com 
2790167Smax.romanov@nginx.com     port->mem_pool = port_mp;
2791167Smax.romanov@nginx.com 
2792167Smax.romanov@nginx.com 
2793167Smax.romanov@nginx.com     nxt_router_ra_release(task, ra, ra->work.data);
2794167Smax.romanov@nginx.com }
2795167Smax.romanov@nginx.com 
2796167Smax.romanov@nginx.com 
2797167Smax.romanov@nginx.com static void
2798167Smax.romanov@nginx.com nxt_router_process_http_request_mp(nxt_task_t *task, nxt_req_app_link_t *ra,
2799167Smax.romanov@nginx.com     nxt_port_t *port)
2800167Smax.romanov@nginx.com {
2801167Smax.romanov@nginx.com     nxt_int_t            res;
2802167Smax.romanov@nginx.com     nxt_port_t           *c_port, *reply_port;
2803167Smax.romanov@nginx.com     nxt_conn_t           *c;
2804167Smax.romanov@nginx.com     nxt_app_wmsg_t       wmsg;
2805167Smax.romanov@nginx.com     nxt_app_parse_ctx_t  *ap;
2806167Smax.romanov@nginx.com 
2807167Smax.romanov@nginx.com     reply_port = ra->reply_port;
2808167Smax.romanov@nginx.com     ap = ra->ap;
2809167Smax.romanov@nginx.com     c = ra->rc->conn;
2810141Smax.romanov@nginx.com 
2811141Smax.romanov@nginx.com     c_port = nxt_process_connected_port_find(port->process, reply_port->pid,
2812141Smax.romanov@nginx.com                                              reply_port->id);
2813141Smax.romanov@nginx.com     if (nxt_slow_path(c_port != reply_port)) {
2814141Smax.romanov@nginx.com         res = nxt_port_send_port(task, port, reply_port, 0);
2815122Smax.romanov@nginx.com 
2816122Smax.romanov@nginx.com         if (nxt_slow_path(res != NXT_OK)) {
2817167Smax.romanov@nginx.com             nxt_router_gen_error(task, c, 500,
2818141Smax.romanov@nginx.com                                  "Failed to send reply port to application");
2819167Smax.romanov@nginx.com             return;
2820122Smax.romanov@nginx.com         }
2821122Smax.romanov@nginx.com 
2822141Smax.romanov@nginx.com         nxt_process_connected_port_add(port->process, reply_port);
282388Smax.romanov@nginx.com     }
282488Smax.romanov@nginx.com 
282588Smax.romanov@nginx.com     wmsg.port = port;
282688Smax.romanov@nginx.com     wmsg.write = NULL;
282788Smax.romanov@nginx.com     wmsg.buf = &wmsg.write;
2828167Smax.romanov@nginx.com     wmsg.stream = ra->req_id;
2829167Smax.romanov@nginx.com 
2830216Sigor@sysoev.ru     res = port->app->prepare_msg(task, &ap->r, &wmsg);
2831122Smax.romanov@nginx.com 
2832122Smax.romanov@nginx.com     if (nxt_slow_path(res != NXT_OK)) {
2833167Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 500,
2834141Smax.romanov@nginx.com                              "Failed to prepare message for application");
2835167Smax.romanov@nginx.com         return;
2836122Smax.romanov@nginx.com     }
283788Smax.romanov@nginx.com 
283888Smax.romanov@nginx.com     nxt_debug(task, "about to send %d bytes buffer to worker port %d",
283988Smax.romanov@nginx.com                     nxt_buf_used_size(wmsg.write),
284088Smax.romanov@nginx.com                     wmsg.port->socket.fd);
284188Smax.romanov@nginx.com 
2842122Smax.romanov@nginx.com     res = nxt_port_socket_write(task, wmsg.port, NXT_PORT_MSG_DATA,
2843167Smax.romanov@nginx.com                                  -1, ra->req_id, reply_port->id, wmsg.write);
2844122Smax.romanov@nginx.com 
2845122Smax.romanov@nginx.com     if (nxt_slow_path(res != NXT_OK)) {
2846167Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 500,
2847141Smax.romanov@nginx.com                              "Failed to send message to application");
2848167Smax.romanov@nginx.com         return;
2849122Smax.romanov@nginx.com     }
285053Sigor@sysoev.ru }
285153Sigor@sysoev.ru 
285253Sigor@sysoev.ru 
2853216Sigor@sysoev.ru static nxt_int_t
2854216Sigor@sysoev.ru nxt_python_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
2855216Sigor@sysoev.ru     nxt_app_wmsg_t *wmsg)
2856216Sigor@sysoev.ru {
2857216Sigor@sysoev.ru     nxt_int_t                 rc;
2858216Sigor@sysoev.ru     nxt_buf_t                 *b;
2859216Sigor@sysoev.ru     nxt_http_field_t          *field;
2860216Sigor@sysoev.ru     nxt_app_request_header_t  *h;
2861216Sigor@sysoev.ru 
2862216Sigor@sysoev.ru     static const nxt_str_t prefix = nxt_string("HTTP_");
2863216Sigor@sysoev.ru     static const nxt_str_t eof = nxt_null_string;
2864216Sigor@sysoev.ru 
2865216Sigor@sysoev.ru     h = &r->header;
2866216Sigor@sysoev.ru 
2867216Sigor@sysoev.ru #define RC(S)                                                                 \
2868216Sigor@sysoev.ru     do {                                                                      \
2869216Sigor@sysoev.ru         rc = (S);                                                             \
2870216Sigor@sysoev.ru         if (nxt_slow_path(rc != NXT_OK)) {                                    \
2871216Sigor@sysoev.ru             goto fail;                                                        \
2872216Sigor@sysoev.ru         }                                                                     \
2873216Sigor@sysoev.ru     } while(0)
2874216Sigor@sysoev.ru 
2875216Sigor@sysoev.ru #define NXT_WRITE(N)                                                          \
2876216Sigor@sysoev.ru     RC(nxt_app_msg_write_str(task, wmsg, N))
2877216Sigor@sysoev.ru 
2878216Sigor@sysoev.ru     /* TODO error handle, async mmap buffer assignment */
2879216Sigor@sysoev.ru 
2880216Sigor@sysoev.ru     NXT_WRITE(&h->method);
2881216Sigor@sysoev.ru     NXT_WRITE(&h->target);
2882277Sigor@sysoev.ru 
2883216Sigor@sysoev.ru     if (h->path.start == h->target.start) {
2884216Sigor@sysoev.ru         NXT_WRITE(&eof);
2885277Sigor@sysoev.ru 
2886216Sigor@sysoev.ru     } else {
2887216Sigor@sysoev.ru         NXT_WRITE(&h->path);
2888216Sigor@sysoev.ru     }
2889216Sigor@sysoev.ru 
2890216Sigor@sysoev.ru     if (h->query.start != NULL) {
2891216Sigor@sysoev.ru         RC(nxt_app_msg_write_size(task, wmsg,
2892216Sigor@sysoev.ru                                   h->query.start - h->target.start + 1));
2893216Sigor@sysoev.ru     } else {
2894216Sigor@sysoev.ru         RC(nxt_app_msg_write_size(task, wmsg, 0));
2895216Sigor@sysoev.ru     }
2896216Sigor@sysoev.ru 
2897216Sigor@sysoev.ru     NXT_WRITE(&h->version);
2898216Sigor@sysoev.ru 
2899216Sigor@sysoev.ru     NXT_WRITE(&r->remote);
2900268Sigor@sysoev.ru     NXT_WRITE(&r->local);
2901216Sigor@sysoev.ru 
2902216Sigor@sysoev.ru     NXT_WRITE(&h->host);
2903216Sigor@sysoev.ru     NXT_WRITE(&h->content_type);
2904216Sigor@sysoev.ru     NXT_WRITE(&h->content_length);
2905216Sigor@sysoev.ru 
2906216Sigor@sysoev.ru     nxt_list_each(field, h->fields) {
2907216Sigor@sysoev.ru         RC(nxt_app_msg_write_prefixed_upcase(task, wmsg,
2908216Sigor@sysoev.ru                                              &prefix, &field->name));
2909216Sigor@sysoev.ru         NXT_WRITE(&field->value);
2910216Sigor@sysoev.ru 
2911216Sigor@sysoev.ru     } nxt_list_loop;
2912216Sigor@sysoev.ru 
2913216Sigor@sysoev.ru     /* end-of-headers mark */
2914216Sigor@sysoev.ru     NXT_WRITE(&eof);
2915216Sigor@sysoev.ru 
2916216Sigor@sysoev.ru     RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size));
2917216Sigor@sysoev.ru 
2918216Sigor@sysoev.ru     for(b = r->body.buf; b != NULL; b = b->next) {
2919216Sigor@sysoev.ru         RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos,
2920216Sigor@sysoev.ru                                  nxt_buf_mem_used_size(&b->mem)));
2921216Sigor@sysoev.ru     }
2922216Sigor@sysoev.ru 
2923216Sigor@sysoev.ru #undef NXT_WRITE
2924216Sigor@sysoev.ru #undef RC
2925216Sigor@sysoev.ru 
2926216Sigor@sysoev.ru     return NXT_OK;
2927216Sigor@sysoev.ru 
2928216Sigor@sysoev.ru fail:
2929216Sigor@sysoev.ru 
2930216Sigor@sysoev.ru     return NXT_ERROR;
2931216Sigor@sysoev.ru }
2932216Sigor@sysoev.ru 
2933216Sigor@sysoev.ru 
2934216Sigor@sysoev.ru static nxt_int_t
2935216Sigor@sysoev.ru nxt_php_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
2936216Sigor@sysoev.ru     nxt_app_wmsg_t *wmsg)
2937216Sigor@sysoev.ru {
2938216Sigor@sysoev.ru     nxt_int_t                 rc;
2939216Sigor@sysoev.ru     nxt_buf_t                 *b;
2940305Smax.romanov@nginx.com     nxt_bool_t                method_is_post;
2941216Sigor@sysoev.ru     nxt_http_field_t          *field;
2942216Sigor@sysoev.ru     nxt_app_request_header_t  *h;
2943216Sigor@sysoev.ru 
2944216Sigor@sysoev.ru     static const nxt_str_t prefix = nxt_string("HTTP_");
2945216Sigor@sysoev.ru     static const nxt_str_t eof = nxt_null_string;
2946216Sigor@sysoev.ru 
2947216Sigor@sysoev.ru     h = &r->header;
2948216Sigor@sysoev.ru 
2949216Sigor@sysoev.ru #define RC(S)                                                                 \
2950216Sigor@sysoev.ru     do {                                                                      \
2951216Sigor@sysoev.ru         rc = (S);                                                             \
2952216Sigor@sysoev.ru         if (nxt_slow_path(rc != NXT_OK)) {                                    \
2953216Sigor@sysoev.ru             goto fail;                                                        \
2954216Sigor@sysoev.ru         }                                                                     \
2955216Sigor@sysoev.ru     } while(0)
2956216Sigor@sysoev.ru 
2957216Sigor@sysoev.ru #define NXT_WRITE(N)                                                          \
2958216Sigor@sysoev.ru     RC(nxt_app_msg_write_str(task, wmsg, N))
2959216Sigor@sysoev.ru 
2960216Sigor@sysoev.ru     /* TODO error handle, async mmap buffer assignment */
2961216Sigor@sysoev.ru 
2962216Sigor@sysoev.ru     NXT_WRITE(&h->method);
2963216Sigor@sysoev.ru     NXT_WRITE(&h->target);
2964277Sigor@sysoev.ru 
2965216Sigor@sysoev.ru     if (h->path.start == h->target.start) {
2966216Sigor@sysoev.ru         NXT_WRITE(&eof);
2967277Sigor@sysoev.ru 
2968216Sigor@sysoev.ru     } else {
2969216Sigor@sysoev.ru         NXT_WRITE(&h->path);
2970216Sigor@sysoev.ru     }
2971216Sigor@sysoev.ru 
2972216Sigor@sysoev.ru     if (h->query.start != NULL) {
2973216Sigor@sysoev.ru         RC(nxt_app_msg_write_size(task, wmsg,
2974216Sigor@sysoev.ru                                   h->query.start - h->target.start + 1));
2975216Sigor@sysoev.ru     } else {
2976216Sigor@sysoev.ru         RC(nxt_app_msg_write_size(task, wmsg, 0));
2977216Sigor@sysoev.ru     }
2978216Sigor@sysoev.ru 
2979216Sigor@sysoev.ru     NXT_WRITE(&h->version);
2980216Sigor@sysoev.ru 
2981216Sigor@sysoev.ru     // PHP_SELF
2982216Sigor@sysoev.ru     // SCRIPT_NAME
2983216Sigor@sysoev.ru     // SCRIPT_FILENAME
2984216Sigor@sysoev.ru     // DOCUMENT_ROOT
2985216Sigor@sysoev.ru 
2986216Sigor@sysoev.ru     NXT_WRITE(&r->remote);
2987268Sigor@sysoev.ru     NXT_WRITE(&r->local);
2988216Sigor@sysoev.ru 
2989216Sigor@sysoev.ru     NXT_WRITE(&h->host);
2990216Sigor@sysoev.ru     NXT_WRITE(&h->cookie);
2991216Sigor@sysoev.ru     NXT_WRITE(&h->content_type);
2992216Sigor@sysoev.ru     NXT_WRITE(&h->content_length);
2993216Sigor@sysoev.ru 
2994216Sigor@sysoev.ru     RC(nxt_app_msg_write_size(task, wmsg, h->parsed_content_length));
2995305Smax.romanov@nginx.com     RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size));
2996305Smax.romanov@nginx.com 
2997305Smax.romanov@nginx.com     method_is_post = h->method.length == 4 &&
2998305Smax.romanov@nginx.com                      h->method.start[0] == 'P' &&
2999305Smax.romanov@nginx.com                      h->method.start[1] == 'O' &&
3000305Smax.romanov@nginx.com                      h->method.start[2] == 'S' &&
3001305Smax.romanov@nginx.com                      h->method.start[3] == 'T';
3002305Smax.romanov@nginx.com 
3003305Smax.romanov@nginx.com     if (method_is_post) {
3004305Smax.romanov@nginx.com         for(b = r->body.buf; b != NULL; b = b->next) {
3005305Smax.romanov@nginx.com             RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos,
3006305Smax.romanov@nginx.com                                      nxt_buf_mem_used_size(&b->mem)));
3007305Smax.romanov@nginx.com         }
3008305Smax.romanov@nginx.com     }
3009216Sigor@sysoev.ru 
3010216Sigor@sysoev.ru     nxt_list_each(field, h->fields) {
3011216Sigor@sysoev.ru         RC(nxt_app_msg_write_prefixed_upcase(task, wmsg,
3012216Sigor@sysoev.ru                                              &prefix, &field->name));
3013216Sigor@sysoev.ru         NXT_WRITE(&field->value);
3014216Sigor@sysoev.ru 
3015216Sigor@sysoev.ru     } nxt_list_loop;
3016216Sigor@sysoev.ru 
3017216Sigor@sysoev.ru     /* end-of-headers mark */
3018216Sigor@sysoev.ru     NXT_WRITE(&eof);
3019216Sigor@sysoev.ru 
3020305Smax.romanov@nginx.com     if (!method_is_post) {
3021305Smax.romanov@nginx.com         for(b = r->body.buf; b != NULL; b = b->next) {
3022305Smax.romanov@nginx.com             RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos,
3023305Smax.romanov@nginx.com                                      nxt_buf_mem_used_size(&b->mem)));
3024305Smax.romanov@nginx.com         }
3025216Sigor@sysoev.ru     }
3026216Sigor@sysoev.ru 
3027216Sigor@sysoev.ru #undef NXT_WRITE
3028216Sigor@sysoev.ru #undef RC
3029216Sigor@sysoev.ru 
3030216Sigor@sysoev.ru     return NXT_OK;
3031216Sigor@sysoev.ru 
3032216Sigor@sysoev.ru fail:
3033216Sigor@sysoev.ru 
3034216Sigor@sysoev.ru     return NXT_ERROR;
3035216Sigor@sysoev.ru }
3036216Sigor@sysoev.ru 
3037216Sigor@sysoev.ru 
3038216Sigor@sysoev.ru static nxt_int_t
3039216Sigor@sysoev.ru nxt_go_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, nxt_app_wmsg_t *wmsg)
3040216Sigor@sysoev.ru {
3041216Sigor@sysoev.ru     nxt_int_t                 rc;
3042216Sigor@sysoev.ru     nxt_buf_t                 *b;
3043216Sigor@sysoev.ru     nxt_http_field_t          *field;
3044216Sigor@sysoev.ru     nxt_app_request_header_t  *h;
3045216Sigor@sysoev.ru 
3046216Sigor@sysoev.ru     static const nxt_str_t eof = nxt_null_string;
3047216Sigor@sysoev.ru 
3048216Sigor@sysoev.ru     h = &r->header;
3049216Sigor@sysoev.ru 
3050216Sigor@sysoev.ru #define RC(S)                                                                 \
3051216Sigor@sysoev.ru     do {                                                                      \
3052216Sigor@sysoev.ru         rc = (S);                                                             \
3053216Sigor@sysoev.ru         if (nxt_slow_path(rc != NXT_OK)) {                                    \
3054216Sigor@sysoev.ru             goto fail;                                                        \
3055216Sigor@sysoev.ru         }                                                                     \
3056216Sigor@sysoev.ru     } while(0)
3057216Sigor@sysoev.ru 
3058216Sigor@sysoev.ru #define NXT_WRITE(N)                                                          \
3059216Sigor@sysoev.ru     RC(nxt_app_msg_write_str(task, wmsg, N))
3060216Sigor@sysoev.ru 
3061216Sigor@sysoev.ru     /* TODO error handle, async mmap buffer assignment */
3062216Sigor@sysoev.ru 
3063216Sigor@sysoev.ru     NXT_WRITE(&h->method);
3064216Sigor@sysoev.ru     NXT_WRITE(&h->target);
3065277Sigor@sysoev.ru 
3066216Sigor@sysoev.ru     if (h->path.start == h->target.start) {
3067216Sigor@sysoev.ru         NXT_WRITE(&eof);
3068277Sigor@sysoev.ru 
3069216Sigor@sysoev.ru     } else {
3070216Sigor@sysoev.ru         NXT_WRITE(&h->path);
3071216Sigor@sysoev.ru     }
3072216Sigor@sysoev.ru 
3073216Sigor@sysoev.ru     if (h->query.start != NULL) {
3074216Sigor@sysoev.ru         RC(nxt_app_msg_write_size(task, wmsg,
3075216Sigor@sysoev.ru                                   h->query.start - h->target.start + 1));
3076216Sigor@sysoev.ru     } else {
3077216Sigor@sysoev.ru         RC(nxt_app_msg_write_size(task, wmsg, 0));
3078216Sigor@sysoev.ru     }
3079216Sigor@sysoev.ru 
3080216Sigor@sysoev.ru     NXT_WRITE(&h->version);
3081253Smax.romanov@nginx.com     NXT_WRITE(&r->remote);
3082216Sigor@sysoev.ru 
3083216Sigor@sysoev.ru     NXT_WRITE(&h->host);
3084216Sigor@sysoev.ru     NXT_WRITE(&h->cookie);
3085216Sigor@sysoev.ru     NXT_WRITE(&h->content_type);
3086216Sigor@sysoev.ru     NXT_WRITE(&h->content_length);
3087216Sigor@sysoev.ru 
3088216Sigor@sysoev.ru     RC(nxt_app_msg_write_size(task, wmsg, h->parsed_content_length));
3089216Sigor@sysoev.ru 
3090216Sigor@sysoev.ru     nxt_list_each(field, h->fields) {
3091216Sigor@sysoev.ru         NXT_WRITE(&field->name);
3092216Sigor@sysoev.ru         NXT_WRITE(&field->value);
3093216Sigor@sysoev.ru 
3094216Sigor@sysoev.ru     } nxt_list_loop;
3095216Sigor@sysoev.ru 
3096216Sigor@sysoev.ru     /* end-of-headers mark */
3097216Sigor@sysoev.ru     NXT_WRITE(&eof);
3098216Sigor@sysoev.ru 
3099216Sigor@sysoev.ru     RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size));
3100216Sigor@sysoev.ru 
3101216Sigor@sysoev.ru     for(b = r->body.buf; b != NULL; b = b->next) {
3102216Sigor@sysoev.ru         RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos,
3103216Sigor@sysoev.ru                                  nxt_buf_mem_used_size(&b->mem)));
3104216Sigor@sysoev.ru     }
3105216Sigor@sysoev.ru 
3106216Sigor@sysoev.ru #undef NXT_WRITE
3107216Sigor@sysoev.ru #undef RC
3108216Sigor@sysoev.ru 
3109216Sigor@sysoev.ru     return NXT_OK;
3110216Sigor@sysoev.ru 
3111216Sigor@sysoev.ru fail:
3112216Sigor@sysoev.ru 
3113216Sigor@sysoev.ru     return NXT_ERROR;
3114216Sigor@sysoev.ru }
3115216Sigor@sysoev.ru 
3116216Sigor@sysoev.ru 
311762Sigor@sysoev.ru static const nxt_conn_state_t  nxt_router_conn_close_state
311853Sigor@sysoev.ru     nxt_aligned(64) =
311953Sigor@sysoev.ru {
312053Sigor@sysoev.ru     .ready_handler = nxt_router_conn_free,
312153Sigor@sysoev.ru };
312253Sigor@sysoev.ru 
312353Sigor@sysoev.ru 
312453Sigor@sysoev.ru static void
312588Smax.romanov@nginx.com nxt_router_conn_ready(nxt_task_t *task, void *obj, void *data)
312688Smax.romanov@nginx.com {
312788Smax.romanov@nginx.com     nxt_buf_t         *b;
312888Smax.romanov@nginx.com     nxt_bool_t        last;
312988Smax.romanov@nginx.com     nxt_conn_t        *c;
313088Smax.romanov@nginx.com     nxt_work_queue_t  *wq;
313188Smax.romanov@nginx.com 
313288Smax.romanov@nginx.com     nxt_debug(task, "router conn ready %p", obj);
313388Smax.romanov@nginx.com 
313488Smax.romanov@nginx.com     c = obj;
313588Smax.romanov@nginx.com     b = c->write;
313688Smax.romanov@nginx.com 
313788Smax.romanov@nginx.com     wq = &task->thread->engine->fast_work_queue;
313888Smax.romanov@nginx.com 
313988Smax.romanov@nginx.com     last = 0;
314088Smax.romanov@nginx.com 
314188Smax.romanov@nginx.com     while (b != NULL) {
314288Smax.romanov@nginx.com         if (!nxt_buf_is_sync(b)) {
314388Smax.romanov@nginx.com             if (nxt_buf_used_size(b) > 0) {
314488Smax.romanov@nginx.com                 break;
314588Smax.romanov@nginx.com             }
314688Smax.romanov@nginx.com         }
314788Smax.romanov@nginx.com 
314888Smax.romanov@nginx.com         if (nxt_buf_is_last(b)) {
314988Smax.romanov@nginx.com             last = 1;
315088Smax.romanov@nginx.com         }
315188Smax.romanov@nginx.com 
315288Smax.romanov@nginx.com         nxt_work_queue_add(wq, b->completion_handler, task, b, b->parent);
315388Smax.romanov@nginx.com 
315488Smax.romanov@nginx.com         b = b->next;
315588Smax.romanov@nginx.com     }
315688Smax.romanov@nginx.com 
315788Smax.romanov@nginx.com     c->write = b;
315888Smax.romanov@nginx.com 
315988Smax.romanov@nginx.com     if (b != NULL) {
316088Smax.romanov@nginx.com         nxt_debug(task, "router conn %p has more data to write", obj);
316188Smax.romanov@nginx.com 
316288Smax.romanov@nginx.com         nxt_conn_write(task->thread->engine, c);
3163277Sigor@sysoev.ru 
316488Smax.romanov@nginx.com     } else {
316588Smax.romanov@nginx.com         nxt_debug(task, "router conn %p no more data to write, last = %d", obj,
316688Smax.romanov@nginx.com                   last);
316788Smax.romanov@nginx.com 
316888Smax.romanov@nginx.com         if (last != 0) {
316988Smax.romanov@nginx.com             nxt_debug(task, "enqueue router conn close %p (ready handler)", c);
317088Smax.romanov@nginx.com 
317188Smax.romanov@nginx.com             nxt_work_queue_add(wq, nxt_router_conn_close, task, c,
317288Smax.romanov@nginx.com                                c->socket.data);
317388Smax.romanov@nginx.com         }
317488Smax.romanov@nginx.com     }
317588Smax.romanov@nginx.com }
317688Smax.romanov@nginx.com 
317788Smax.romanov@nginx.com 
317888Smax.romanov@nginx.com static void
317953Sigor@sysoev.ru nxt_router_conn_close(nxt_task_t *task, void *obj, void *data)
318053Sigor@sysoev.ru {
318162Sigor@sysoev.ru     nxt_conn_t  *c;
318253Sigor@sysoev.ru 
318353Sigor@sysoev.ru     c = obj;
318453Sigor@sysoev.ru 
318553Sigor@sysoev.ru     nxt_debug(task, "router conn close");
318653Sigor@sysoev.ru 
318753Sigor@sysoev.ru     c->write_state = &nxt_router_conn_close_state;
318853Sigor@sysoev.ru 
318962Sigor@sysoev.ru     nxt_conn_close(task->thread->engine, c);
319053Sigor@sysoev.ru }
319153Sigor@sysoev.ru 
319253Sigor@sysoev.ru 
319353Sigor@sysoev.ru static void
3194164Smax.romanov@nginx.com nxt_router_conn_mp_cleanup(nxt_task_t *task, void *obj, void *data)
3195164Smax.romanov@nginx.com {
3196164Smax.romanov@nginx.com     nxt_socket_conf_joint_t  *joint;
3197164Smax.romanov@nginx.com 
3198164Smax.romanov@nginx.com     joint = obj;
3199164Smax.romanov@nginx.com 
3200164Smax.romanov@nginx.com     nxt_router_conf_release(task, joint);
3201164Smax.romanov@nginx.com }
3202164Smax.romanov@nginx.com 
3203164Smax.romanov@nginx.com 
3204164Smax.romanov@nginx.com static void
320553Sigor@sysoev.ru nxt_router_conn_free(nxt_task_t *task, void *obj, void *data)
320653Sigor@sysoev.ru {
320762Sigor@sysoev.ru     nxt_conn_t               *c;
320888Smax.romanov@nginx.com     nxt_req_conn_link_t      *rc;
320953Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
321053Sigor@sysoev.ru 
321153Sigor@sysoev.ru     c = obj;
321253Sigor@sysoev.ru 
321353Sigor@sysoev.ru     nxt_debug(task, "router conn close done");
321453Sigor@sysoev.ru 
321588Smax.romanov@nginx.com     nxt_queue_each(rc, &c->requests, nxt_req_conn_link_t, link) {
321688Smax.romanov@nginx.com 
321788Smax.romanov@nginx.com         nxt_debug(task, "conn %p close, req %uxD", c, rc->req_id);
321888Smax.romanov@nginx.com 
3219141Smax.romanov@nginx.com         if (rc->app_port != NULL) {
3220141Smax.romanov@nginx.com             nxt_router_app_release_port(task, rc->app_port, rc->app_port->app);
3221141Smax.romanov@nginx.com 
3222141Smax.romanov@nginx.com             rc->app_port = NULL;
3223141Smax.romanov@nginx.com         }
3224141Smax.romanov@nginx.com 
3225167Smax.romanov@nginx.com         rc->conn = NULL;
3226167Smax.romanov@nginx.com 
322788Smax.romanov@nginx.com         nxt_event_engine_request_remove(task->thread->engine, rc);
322888Smax.romanov@nginx.com 
322988Smax.romanov@nginx.com     } nxt_queue_loop;
323088Smax.romanov@nginx.com 
3231122Smax.romanov@nginx.com     nxt_queue_remove(&c->link);
3232122Smax.romanov@nginx.com 
3233131Smax.romanov@nginx.com     joint = c->listen->socket.data;
3234131Smax.romanov@nginx.com 
3235131Smax.romanov@nginx.com     task = &task->thread->engine->task;
3236131Smax.romanov@nginx.com 
3237164Smax.romanov@nginx.com     nxt_mp_cleanup(c->mem_pool, nxt_router_conn_mp_cleanup, task, joint, NULL);
3238164Smax.romanov@nginx.com 
3239164Smax.romanov@nginx.com     nxt_mp_release(c->mem_pool, c);
324053Sigor@sysoev.ru }
324153Sigor@sysoev.ru 
324253Sigor@sysoev.ru 
324353Sigor@sysoev.ru static void
324453Sigor@sysoev.ru nxt_router_conn_error(nxt_task_t *task, void *obj, void *data)
324553Sigor@sysoev.ru {
324662Sigor@sysoev.ru     nxt_conn_t  *c;
324753Sigor@sysoev.ru 
324853Sigor@sysoev.ru     c = obj;
324953Sigor@sysoev.ru 
325053Sigor@sysoev.ru     nxt_debug(task, "router conn error");
325153Sigor@sysoev.ru 
3252273Smax.romanov@nginx.com     if (c->socket.fd != -1) {
3253273Smax.romanov@nginx.com         c->write_state = &nxt_router_conn_close_state;
3254273Smax.romanov@nginx.com 
3255273Smax.romanov@nginx.com         nxt_conn_close(task->thread->engine, c);
3256273Smax.romanov@nginx.com     }
325753Sigor@sysoev.ru }
325853Sigor@sysoev.ru 
325953Sigor@sysoev.ru 
326053Sigor@sysoev.ru static void
326153Sigor@sysoev.ru nxt_router_conn_timeout(nxt_task_t *task, void *obj, void *data)
326253Sigor@sysoev.ru {
326362Sigor@sysoev.ru     nxt_conn_t   *c;
326462Sigor@sysoev.ru     nxt_timer_t  *timer;
326553Sigor@sysoev.ru 
326653Sigor@sysoev.ru     timer = obj;
326753Sigor@sysoev.ru 
326853Sigor@sysoev.ru     nxt_debug(task, "router conn timeout");
326953Sigor@sysoev.ru 
327062Sigor@sysoev.ru     c = nxt_read_timer_conn(timer);
327153Sigor@sysoev.ru 
3272206Smax.romanov@nginx.com     if (c->read_state == &nxt_router_conn_read_header_state) {
3273206Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 408, "Read header timeout");
3274206Smax.romanov@nginx.com 
3275206Smax.romanov@nginx.com     } else {
3276206Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 408, "Read body timeout");
3277206Smax.romanov@nginx.com     }
327853Sigor@sysoev.ru }
327953Sigor@sysoev.ru 
328053Sigor@sysoev.ru 
328153Sigor@sysoev.ru static nxt_msec_t
328262Sigor@sysoev.ru nxt_router_conn_timeout_value(nxt_conn_t *c, uintptr_t data)
328353Sigor@sysoev.ru {
328453Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
328553Sigor@sysoev.ru 
328653Sigor@sysoev.ru     joint = c->listen->socket.data;
328753Sigor@sysoev.ru 
328853Sigor@sysoev.ru     return nxt_value_at(nxt_msec_t, joint->socket_conf, data);
328953Sigor@sysoev.ru }
3290