xref: /unit/src/nxt_router.c (revision 359)
120Sigor@sysoev.ru 
220Sigor@sysoev.ru /*
320Sigor@sysoev.ru  * Copyright (C) Igor Sysoev
420Sigor@sysoev.ru  * Copyright (C) Valentin V. Bartenev
520Sigor@sysoev.ru  * Copyright (C) NGINX, Inc.
620Sigor@sysoev.ru  */
720Sigor@sysoev.ru 
853Sigor@sysoev.ru #include <nxt_router.h>
9115Sigor@sysoev.ru #include <nxt_conf.h>
1020Sigor@sysoev.ru 
1120Sigor@sysoev.ru 
12115Sigor@sysoev.ru typedef struct {
13318Smax.romanov@nginx.com     nxt_str_t         type;
14318Smax.romanov@nginx.com     uint32_t          workers;
15318Smax.romanov@nginx.com     nxt_msec_t        timeout;
16318Smax.romanov@nginx.com     uint32_t          requests;
17318Smax.romanov@nginx.com     nxt_conf_value_t  *limits_value;
18133Sigor@sysoev.ru } nxt_router_app_conf_t;
19133Sigor@sysoev.ru 
20133Sigor@sysoev.ru 
21133Sigor@sysoev.ru typedef struct {
22133Sigor@sysoev.ru     nxt_str_t  application;
23115Sigor@sysoev.ru } nxt_router_listener_conf_t;
24115Sigor@sysoev.ru 
25115Sigor@sysoev.ru 
26167Smax.romanov@nginx.com typedef struct nxt_req_app_link_s nxt_req_app_link_t;
27141Smax.romanov@nginx.com 
28141Smax.romanov@nginx.com 
29318Smax.romanov@nginx.com typedef struct {
30318Smax.romanov@nginx.com     uint32_t             stream;
31318Smax.romanov@nginx.com     nxt_conn_t           *conn;
32343Smax.romanov@nginx.com     nxt_app_t            *app;
33318Smax.romanov@nginx.com     nxt_port_t           *app_port;
34346Smax.romanov@nginx.com     nxt_app_parse_ctx_t  *ap;
35318Smax.romanov@nginx.com     nxt_req_app_link_t   *ra;
36318Smax.romanov@nginx.com 
37318Smax.romanov@nginx.com     nxt_queue_link_t     link;     /* for nxt_conn_t.requests */
38318Smax.romanov@nginx.com } nxt_req_conn_link_t;
39318Smax.romanov@nginx.com 
40318Smax.romanov@nginx.com 
41167Smax.romanov@nginx.com struct nxt_req_app_link_s {
42318Smax.romanov@nginx.com     uint32_t             stream;
43167Smax.romanov@nginx.com     nxt_port_t           *app_port;
44318Smax.romanov@nginx.com     nxt_pid_t            app_pid;
45167Smax.romanov@nginx.com     nxt_port_t           *reply_port;
46167Smax.romanov@nginx.com     nxt_app_parse_ctx_t  *ap;
47167Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
48167Smax.romanov@nginx.com 
49167Smax.romanov@nginx.com     nxt_queue_link_t     link; /* for nxt_app_t.requests */
50167Smax.romanov@nginx.com 
51167Smax.romanov@nginx.com     nxt_mp_t             *mem_pool;
52167Smax.romanov@nginx.com     nxt_work_t           work;
53345Smax.romanov@nginx.com 
54345Smax.romanov@nginx.com     int                  err_code;
55345Smax.romanov@nginx.com     const char           *err_str;
56167Smax.romanov@nginx.com };
57167Smax.romanov@nginx.com 
58167Smax.romanov@nginx.com 
59198Sigor@sysoev.ru typedef struct {
60198Sigor@sysoev.ru     nxt_socket_conf_t       *socket_conf;
61198Sigor@sysoev.ru     nxt_router_temp_conf_t  *temp_conf;
62198Sigor@sysoev.ru } nxt_socket_rpc_t;
63198Sigor@sysoev.ru 
64198Sigor@sysoev.ru 
65343Smax.romanov@nginx.com static nxt_int_t nxt_router_start_worker(nxt_task_t *task, nxt_app_t *app);
66343Smax.romanov@nginx.com 
67345Smax.romanov@nginx.com static void nxt_router_ra_error(nxt_task_t *task, nxt_req_app_link_t *ra,
68345Smax.romanov@nginx.com     int code, const char* str);
69345Smax.romanov@nginx.com 
70139Sigor@sysoev.ru static nxt_router_temp_conf_t *nxt_router_temp_conf(nxt_task_t *task);
71198Sigor@sysoev.ru static void nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data);
72198Sigor@sysoev.ru static void nxt_router_conf_ready(nxt_task_t *task,
73139Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
74139Sigor@sysoev.ru static void nxt_router_conf_error(nxt_task_t *task,
75139Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
76139Sigor@sysoev.ru static void nxt_router_conf_send(nxt_task_t *task,
77193Smax.romanov@nginx.com     nxt_router_temp_conf_t *tmcf, nxt_port_msg_type_t type);
7853Sigor@sysoev.ru 
79115Sigor@sysoev.ru static nxt_int_t nxt_router_conf_create(nxt_task_t *task,
80115Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, u_char *start, u_char *end);
81133Sigor@sysoev.ru static nxt_app_t *nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name);
82133Sigor@sysoev.ru static nxt_app_t *nxt_router_listener_application(nxt_router_temp_conf_t *tmcf,
83133Sigor@sysoev.ru     nxt_str_t *name);
84198Sigor@sysoev.ru static void nxt_router_listen_socket_rpc_create(nxt_task_t *task,
85198Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf);
86198Sigor@sysoev.ru static void nxt_router_listen_socket_ready(nxt_task_t *task,
87198Sigor@sysoev.ru     nxt_port_recv_msg_t *msg, void *data);
88198Sigor@sysoev.ru static void nxt_router_listen_socket_error(nxt_task_t *task,
89198Sigor@sysoev.ru     nxt_port_recv_msg_t *msg, void *data);
90*359Sigor@sysoev.ru static nxt_socket_conf_t *nxt_router_socket_conf(nxt_task_t *task,
91*359Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_str_t *name);
92*359Sigor@sysoev.ru static nxt_int_t nxt_router_listen_socket_find(nxt_router_temp_conf_t *tmcf,
93*359Sigor@sysoev.ru     nxt_socket_conf_t *nskcf, nxt_sockaddr_t *sa);
9453Sigor@sysoev.ru 
9553Sigor@sysoev.ru static nxt_int_t nxt_router_engines_create(nxt_task_t *task,
9653Sigor@sysoev.ru     nxt_router_t *router, nxt_router_temp_conf_t *tmcf,
9753Sigor@sysoev.ru     const nxt_event_interface_t *interface);
98115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf,
99115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
100115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf,
101115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
102115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf,
103115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
104154Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf,
105154Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets,
106154Sigor@sysoev.ru     nxt_work_handler_t handler);
107313Sigor@sysoev.ru static nxt_int_t nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf,
108313Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
109139Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf,
110139Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets);
11153Sigor@sysoev.ru 
11253Sigor@sysoev.ru static nxt_int_t nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt,
11353Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
11453Sigor@sysoev.ru static nxt_int_t nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt,
11553Sigor@sysoev.ru     nxt_event_engine_t *engine);
116343Smax.romanov@nginx.com static void nxt_router_apps_sort(nxt_task_t *task, nxt_router_t *router,
117133Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
11853Sigor@sysoev.ru 
119315Sigor@sysoev.ru static void nxt_router_engines_post(nxt_router_t *router,
120315Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
121315Sigor@sysoev.ru static void nxt_router_engine_post(nxt_event_engine_t *engine,
122315Sigor@sysoev.ru     nxt_work_t *jobs);
12353Sigor@sysoev.ru 
12453Sigor@sysoev.ru static void nxt_router_thread_start(void *data);
12553Sigor@sysoev.ru static void nxt_router_listen_socket_create(nxt_task_t *task, void *obj,
12653Sigor@sysoev.ru     void *data);
12753Sigor@sysoev.ru static void nxt_router_listen_socket_update(nxt_task_t *task, void *obj,
12853Sigor@sysoev.ru     void *data);
12953Sigor@sysoev.ru static void nxt_router_listen_socket_delete(nxt_task_t *task, void *obj,
13053Sigor@sysoev.ru     void *data);
131313Sigor@sysoev.ru static void nxt_router_worker_thread_quit(nxt_task_t *task, void *obj,
132313Sigor@sysoev.ru     void *data);
13353Sigor@sysoev.ru static void nxt_router_listen_socket_close(nxt_task_t *task, void *obj,
13453Sigor@sysoev.ru     void *data);
13553Sigor@sysoev.ru static void nxt_router_thread_exit_handler(nxt_task_t *task, void *obj,
13653Sigor@sysoev.ru     void *data);
137*359Sigor@sysoev.ru static void nxt_router_listen_socket_release(nxt_task_t *task,
138*359Sigor@sysoev.ru     nxt_socket_conf_t *skcf);
13953Sigor@sysoev.ru static void nxt_router_conf_release(nxt_task_t *task,
14053Sigor@sysoev.ru     nxt_socket_conf_joint_t *joint);
14153Sigor@sysoev.ru 
142343Smax.romanov@nginx.com static void nxt_router_app_port_ready(nxt_task_t *task,
143343Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg, void *data);
144343Smax.romanov@nginx.com static void nxt_router_app_port_error(nxt_task_t *task,
145343Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg, void *data);
146343Smax.romanov@nginx.com 
147343Smax.romanov@nginx.com static nxt_port_t * nxt_router_app_get_idle_port(nxt_app_t *app);
148343Smax.romanov@nginx.com static void nxt_router_app_port_release(nxt_task_t *task, nxt_port_t *port,
149343Smax.romanov@nginx.com     uint32_t request_failed, uint32_t got_response);
150141Smax.romanov@nginx.com 
15153Sigor@sysoev.ru static void nxt_router_conn_init(nxt_task_t *task, void *obj, void *data);
15253Sigor@sysoev.ru static void nxt_router_conn_http_header_parse(nxt_task_t *task, void *obj,
15353Sigor@sysoev.ru     void *data);
154*359Sigor@sysoev.ru static nxt_sockaddr_t *nxt_router_local_addr(nxt_task_t *task, nxt_conn_t *c);
155206Smax.romanov@nginx.com static void nxt_router_conn_http_body_read(nxt_task_t *task, void *obj,
156206Smax.romanov@nginx.com     void *data);
15788Smax.romanov@nginx.com static void nxt_router_process_http_request(nxt_task_t *task,
15888Smax.romanov@nginx.com     nxt_conn_t *c, nxt_app_parse_ctx_t *ap);
159141Smax.romanov@nginx.com static void nxt_router_process_http_request_mp(nxt_task_t *task,
160343Smax.romanov@nginx.com     nxt_req_app_link_t *ra);
161216Sigor@sysoev.ru static nxt_int_t nxt_python_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
162216Sigor@sysoev.ru     nxt_app_wmsg_t *wmsg);
163216Sigor@sysoev.ru static nxt_int_t nxt_php_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
164216Sigor@sysoev.ru     nxt_app_wmsg_t *wmsg);
165216Sigor@sysoev.ru static nxt_int_t nxt_go_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
166216Sigor@sysoev.ru     nxt_app_wmsg_t *wmsg);
16788Smax.romanov@nginx.com static void nxt_router_conn_ready(nxt_task_t *task, void *obj, void *data);
16853Sigor@sysoev.ru static void nxt_router_conn_close(nxt_task_t *task, void *obj, void *data);
16953Sigor@sysoev.ru static void nxt_router_conn_free(nxt_task_t *task, void *obj, void *data);
17053Sigor@sysoev.ru static void nxt_router_conn_error(nxt_task_t *task, void *obj, void *data);
17153Sigor@sysoev.ru static void nxt_router_conn_timeout(nxt_task_t *task, void *obj, void *data);
172318Smax.romanov@nginx.com static void nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data);
17362Sigor@sysoev.ru static nxt_msec_t nxt_router_conn_timeout_value(nxt_conn_t *c, uintptr_t data);
17420Sigor@sysoev.ru 
175141Smax.romanov@nginx.com static void nxt_router_gen_error(nxt_task_t *task, nxt_conn_t *c, int code,
176345Smax.romanov@nginx.com     const char* str);
177141Smax.romanov@nginx.com 
178119Smax.romanov@nginx.com static nxt_router_t  *nxt_router;
17920Sigor@sysoev.ru 
180216Sigor@sysoev.ru 
181216Sigor@sysoev.ru static nxt_app_prepare_msg_t  nxt_app_prepare_msg[] = {
182216Sigor@sysoev.ru     nxt_python_prepare_msg,
183216Sigor@sysoev.ru     nxt_php_prepare_msg,
184216Sigor@sysoev.ru     nxt_go_prepare_msg,
185216Sigor@sysoev.ru };
186216Sigor@sysoev.ru 
187216Sigor@sysoev.ru 
18820Sigor@sysoev.ru nxt_int_t
189141Smax.romanov@nginx.com nxt_router_start(nxt_task_t *task, void *data)
19020Sigor@sysoev.ru {
191141Smax.romanov@nginx.com     nxt_int_t      ret;
192141Smax.romanov@nginx.com     nxt_router_t   *router;
193141Smax.romanov@nginx.com     nxt_runtime_t  *rt;
194141Smax.romanov@nginx.com 
195141Smax.romanov@nginx.com     rt = task->thread->runtime;
19653Sigor@sysoev.ru 
19788Smax.romanov@nginx.com     ret = nxt_app_http_init(task, rt);
19888Smax.romanov@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
19988Smax.romanov@nginx.com         return ret;
20088Smax.romanov@nginx.com     }
20188Smax.romanov@nginx.com 
20253Sigor@sysoev.ru     router = nxt_zalloc(sizeof(nxt_router_t));
20353Sigor@sysoev.ru     if (nxt_slow_path(router == NULL)) {
20453Sigor@sysoev.ru         return NXT_ERROR;
20553Sigor@sysoev.ru     }
20653Sigor@sysoev.ru 
20753Sigor@sysoev.ru     nxt_queue_init(&router->engines);
20853Sigor@sysoev.ru     nxt_queue_init(&router->sockets);
209133Sigor@sysoev.ru     nxt_queue_init(&router->apps);
21053Sigor@sysoev.ru 
211119Smax.romanov@nginx.com     nxt_router = router;
212119Smax.romanov@nginx.com 
213115Sigor@sysoev.ru     return NXT_OK;
214115Sigor@sysoev.ru }
215115Sigor@sysoev.ru 
216115Sigor@sysoev.ru 
217343Smax.romanov@nginx.com static void
218343Smax.romanov@nginx.com nxt_router_start_worker_handler(nxt_task_t *task, nxt_port_t *port, void *data)
219167Smax.romanov@nginx.com {
220343Smax.romanov@nginx.com     size_t         size;
221343Smax.romanov@nginx.com     uint32_t       stream;
222343Smax.romanov@nginx.com     nxt_app_t      *app;
223343Smax.romanov@nginx.com     nxt_buf_t      *b;
224343Smax.romanov@nginx.com     nxt_port_t     *main_port;
225343Smax.romanov@nginx.com     nxt_runtime_t  *rt;
226343Smax.romanov@nginx.com 
227343Smax.romanov@nginx.com     app = data;
228167Smax.romanov@nginx.com 
229167Smax.romanov@nginx.com     rt = task->thread->runtime;
230240Sigor@sysoev.ru     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
231167Smax.romanov@nginx.com 
232343Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p start worker", &app->name, app);
233343Smax.romanov@nginx.com 
234343Smax.romanov@nginx.com     size = app->name.length + 1 + app->conf.length;
235343Smax.romanov@nginx.com 
236343Smax.romanov@nginx.com     b = nxt_buf_mem_ts_alloc(task, task->thread->engine->mem_pool, size);
237343Smax.romanov@nginx.com 
238343Smax.romanov@nginx.com     if (nxt_slow_path(b == NULL)) {
239343Smax.romanov@nginx.com         goto failed;
240167Smax.romanov@nginx.com     }
241167Smax.romanov@nginx.com 
242343Smax.romanov@nginx.com     nxt_buf_cpystr(b, &app->name);
243343Smax.romanov@nginx.com     *b->mem.free++ = '\0';
244343Smax.romanov@nginx.com     nxt_buf_cpystr(b, &app->conf);
245343Smax.romanov@nginx.com 
246343Smax.romanov@nginx.com     stream = nxt_port_rpc_register_handler(task, port,
247343Smax.romanov@nginx.com                                            nxt_router_app_port_ready,
248343Smax.romanov@nginx.com                                            nxt_router_app_port_error,
249343Smax.romanov@nginx.com                                            -1, app);
250343Smax.romanov@nginx.com 
251343Smax.romanov@nginx.com     if (nxt_slow_path(stream == 0)) {
252343Smax.romanov@nginx.com         nxt_mp_release(b->data, b);
253343Smax.romanov@nginx.com 
254343Smax.romanov@nginx.com         goto failed;
255343Smax.romanov@nginx.com     }
256343Smax.romanov@nginx.com 
257343Smax.romanov@nginx.com     nxt_port_socket_write(task, main_port, NXT_PORT_MSG_START_WORKER, -1,
258343Smax.romanov@nginx.com                           stream, port->id, b);
259343Smax.romanov@nginx.com 
260343Smax.romanov@nginx.com     return;
261343Smax.romanov@nginx.com 
262343Smax.romanov@nginx.com failed:
263343Smax.romanov@nginx.com 
264343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
265343Smax.romanov@nginx.com 
266343Smax.romanov@nginx.com     app->pending_workers--;
267343Smax.romanov@nginx.com 
268343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
269343Smax.romanov@nginx.com 
270343Smax.romanov@nginx.com     nxt_router_app_use(task, app, -1);
271167Smax.romanov@nginx.com }
272167Smax.romanov@nginx.com 
273167Smax.romanov@nginx.com 
274343Smax.romanov@nginx.com static nxt_int_t
275343Smax.romanov@nginx.com nxt_router_start_worker(nxt_task_t *task, nxt_app_t *app)
276141Smax.romanov@nginx.com {
277343Smax.romanov@nginx.com     nxt_int_t      res;
278343Smax.romanov@nginx.com     nxt_port_t     *router_port;
279343Smax.romanov@nginx.com     nxt_runtime_t  *rt;
280343Smax.romanov@nginx.com 
281343Smax.romanov@nginx.com     rt = task->thread->runtime;
282343Smax.romanov@nginx.com     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
283343Smax.romanov@nginx.com 
284343Smax.romanov@nginx.com     nxt_router_app_use(task, app, 1);
285343Smax.romanov@nginx.com 
286343Smax.romanov@nginx.com     res = nxt_port_post(task, router_port, nxt_router_start_worker_handler,
287343Smax.romanov@nginx.com                         app);
288343Smax.romanov@nginx.com 
289343Smax.romanov@nginx.com     if (res == NXT_OK) {
290343Smax.romanov@nginx.com         return res;
291318Smax.romanov@nginx.com     }
292318Smax.romanov@nginx.com 
293343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
294343Smax.romanov@nginx.com 
295343Smax.romanov@nginx.com     app->pending_workers--;
296343Smax.romanov@nginx.com 
297343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
298343Smax.romanov@nginx.com 
299343Smax.romanov@nginx.com     nxt_router_app_use(task, app, -1);
300343Smax.romanov@nginx.com 
301343Smax.romanov@nginx.com     return NXT_ERROR;
302318Smax.romanov@nginx.com }
303318Smax.romanov@nginx.com 
304318Smax.romanov@nginx.com 
305351Smax.romanov@nginx.com nxt_inline void
306351Smax.romanov@nginx.com nxt_router_ra_init(nxt_task_t *task, nxt_req_app_link_t *ra,
307351Smax.romanov@nginx.com     nxt_req_conn_link_t *rc)
308167Smax.romanov@nginx.com {
309318Smax.romanov@nginx.com     nxt_event_engine_t  *engine;
310351Smax.romanov@nginx.com 
311318Smax.romanov@nginx.com     engine = task->thread->engine;
312167Smax.romanov@nginx.com 
313167Smax.romanov@nginx.com     nxt_memzero(ra, sizeof(nxt_req_app_link_t));
314167Smax.romanov@nginx.com 
315318Smax.romanov@nginx.com     ra->stream = rc->stream;
316318Smax.romanov@nginx.com     ra->app_pid = -1;
317167Smax.romanov@nginx.com     ra->rc = rc;
318318Smax.romanov@nginx.com     rc->ra = ra;
319318Smax.romanov@nginx.com     ra->reply_port = engine->port;
320351Smax.romanov@nginx.com     ra->ap = rc->ap;
321167Smax.romanov@nginx.com 
322167Smax.romanov@nginx.com     ra->work.handler = NULL;
323318Smax.romanov@nginx.com     ra->work.task = &engine->task;
324167Smax.romanov@nginx.com     ra->work.obj = ra;
325318Smax.romanov@nginx.com     ra->work.data = engine;
326351Smax.romanov@nginx.com }
327351Smax.romanov@nginx.com 
328351Smax.romanov@nginx.com 
329351Smax.romanov@nginx.com nxt_inline nxt_req_app_link_t *
330351Smax.romanov@nginx.com nxt_router_ra_create(nxt_task_t *task, nxt_req_app_link_t *ra_src)
331351Smax.romanov@nginx.com {
332351Smax.romanov@nginx.com     nxt_mp_t            *mp;
333351Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
334351Smax.romanov@nginx.com 
335351Smax.romanov@nginx.com     mp = ra_src->ap->mem_pool;
336351Smax.romanov@nginx.com 
337351Smax.romanov@nginx.com     ra = nxt_mp_retain(mp, sizeof(nxt_req_app_link_t));
338351Smax.romanov@nginx.com 
339351Smax.romanov@nginx.com     if (nxt_slow_path(ra == NULL)) {
340351Smax.romanov@nginx.com 
341351Smax.romanov@nginx.com         ra_src->rc->ra = NULL;
342351Smax.romanov@nginx.com         ra_src->rc = NULL;
343351Smax.romanov@nginx.com 
344351Smax.romanov@nginx.com         return NULL;
345351Smax.romanov@nginx.com     }
346351Smax.romanov@nginx.com 
347351Smax.romanov@nginx.com     nxt_router_ra_init(task, ra, ra_src->rc);
348351Smax.romanov@nginx.com 
349351Smax.romanov@nginx.com     ra->mem_pool = mp;
350167Smax.romanov@nginx.com 
351167Smax.romanov@nginx.com     return ra;
352167Smax.romanov@nginx.com }
353167Smax.romanov@nginx.com 
354167Smax.romanov@nginx.com 
355167Smax.romanov@nginx.com static void
356167Smax.romanov@nginx.com nxt_router_ra_release(nxt_task_t *task, void *obj, void *data)
357167Smax.romanov@nginx.com {
358343Smax.romanov@nginx.com     nxt_req_app_link_t   *ra;
359343Smax.romanov@nginx.com     nxt_event_engine_t   *engine;
360343Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
361318Smax.romanov@nginx.com 
362318Smax.romanov@nginx.com     ra = obj;
363318Smax.romanov@nginx.com     engine = data;
364318Smax.romanov@nginx.com 
365343Smax.romanov@nginx.com     if (task->thread->engine != engine) {
366343Smax.romanov@nginx.com         if (ra->app_port != NULL) {
367343Smax.romanov@nginx.com             ra->app_pid = ra->app_port->pid;
368318Smax.romanov@nginx.com         }
369318Smax.romanov@nginx.com 
370318Smax.romanov@nginx.com         ra->work.handler = nxt_router_ra_release;
371318Smax.romanov@nginx.com         ra->work.task = &engine->task;
372318Smax.romanov@nginx.com         ra->work.next = NULL;
373318Smax.romanov@nginx.com 
374318Smax.romanov@nginx.com         nxt_debug(task, "ra stream #%uD post release to %p",
375318Smax.romanov@nginx.com                   ra->stream, engine);
376318Smax.romanov@nginx.com 
377318Smax.romanov@nginx.com         nxt_event_engine_post(engine, &ra->work);
378318Smax.romanov@nginx.com 
379318Smax.romanov@nginx.com         return;
380318Smax.romanov@nginx.com     }
381318Smax.romanov@nginx.com 
382343Smax.romanov@nginx.com     nxt_debug(task, "ra stream #%uD release", ra->stream);
383343Smax.romanov@nginx.com 
384343Smax.romanov@nginx.com     rc = ra->rc;
385343Smax.romanov@nginx.com 
386343Smax.romanov@nginx.com     if (rc != NULL) {
387343Smax.romanov@nginx.com         if (ra->app_pid != -1) {
388343Smax.romanov@nginx.com             nxt_port_rpc_ex_set_peer(task, engine->port, rc, ra->app_pid);
389343Smax.romanov@nginx.com         }
390343Smax.romanov@nginx.com 
391343Smax.romanov@nginx.com         rc->app_port = ra->app_port;
392343Smax.romanov@nginx.com 
393343Smax.romanov@nginx.com         ra->app_port = NULL;
394343Smax.romanov@nginx.com         rc->ra = NULL;
395343Smax.romanov@nginx.com         ra->rc = NULL;
396318Smax.romanov@nginx.com     }
397318Smax.romanov@nginx.com 
398343Smax.romanov@nginx.com     if (ra->app_port != NULL) {
399343Smax.romanov@nginx.com         nxt_router_app_port_release(task, ra->app_port, 0, 1);
400343Smax.romanov@nginx.com 
401343Smax.romanov@nginx.com         ra->app_port = NULL;
402343Smax.romanov@nginx.com     }
403318Smax.romanov@nginx.com 
404351Smax.romanov@nginx.com     if (ra->mem_pool != NULL) {
405351Smax.romanov@nginx.com         nxt_mp_release(ra->mem_pool, ra);
406351Smax.romanov@nginx.com     }
407318Smax.romanov@nginx.com }
408318Smax.romanov@nginx.com 
409318Smax.romanov@nginx.com 
410318Smax.romanov@nginx.com static void
411318Smax.romanov@nginx.com nxt_router_ra_abort(nxt_task_t *task, void *obj, void *data)
412318Smax.romanov@nginx.com {
413343Smax.romanov@nginx.com     nxt_conn_t           *c;
414343Smax.romanov@nginx.com     nxt_req_app_link_t   *ra;
415343Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
416343Smax.romanov@nginx.com     nxt_event_engine_t   *engine;
417167Smax.romanov@nginx.com 
418167Smax.romanov@nginx.com     ra = obj;
419167Smax.romanov@nginx.com     engine = data;
420167Smax.romanov@nginx.com 
421167Smax.romanov@nginx.com     if (task->thread->engine != engine) {
422318Smax.romanov@nginx.com         ra->work.handler = nxt_router_ra_abort;
423167Smax.romanov@nginx.com         ra->work.task = &engine->task;
424167Smax.romanov@nginx.com         ra->work.next = NULL;
425167Smax.romanov@nginx.com 
426318Smax.romanov@nginx.com         nxt_debug(task, "ra stream #%uD post abort to %p", ra->stream, engine);
427167Smax.romanov@nginx.com 
428167Smax.romanov@nginx.com         nxt_event_engine_post(engine, &ra->work);
429167Smax.romanov@nginx.com 
430167Smax.romanov@nginx.com         return;
431167Smax.romanov@nginx.com     }
432167Smax.romanov@nginx.com 
433318Smax.romanov@nginx.com     nxt_debug(task, "ra stream #%uD abort", ra->stream);
434318Smax.romanov@nginx.com 
435343Smax.romanov@nginx.com     rc = ra->rc;
436343Smax.romanov@nginx.com 
437343Smax.romanov@nginx.com     if (rc != NULL) {
438343Smax.romanov@nginx.com         c = rc->conn;
439318Smax.romanov@nginx.com 
440318Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 500,
441318Smax.romanov@nginx.com                              "Failed to start application worker");
442343Smax.romanov@nginx.com 
443343Smax.romanov@nginx.com         rc->ra = NULL;
444343Smax.romanov@nginx.com         ra->rc = NULL;
445343Smax.romanov@nginx.com     }
446343Smax.romanov@nginx.com 
447343Smax.romanov@nginx.com     if (ra->app_port != NULL) {
448343Smax.romanov@nginx.com         nxt_router_app_port_release(task, ra->app_port, 0, 1);
449343Smax.romanov@nginx.com 
450343Smax.romanov@nginx.com         ra->app_port = NULL;
451167Smax.romanov@nginx.com     }
452167Smax.romanov@nginx.com 
453351Smax.romanov@nginx.com     if (ra->mem_pool != NULL) {
454351Smax.romanov@nginx.com         nxt_mp_release(ra->mem_pool, ra);
455351Smax.romanov@nginx.com     }
456167Smax.romanov@nginx.com }
457167Smax.romanov@nginx.com 
458167Smax.romanov@nginx.com 
459345Smax.romanov@nginx.com static void
460345Smax.romanov@nginx.com nxt_router_ra_error_handler(nxt_task_t *task, void *obj, void *data)
461345Smax.romanov@nginx.com {
462345Smax.romanov@nginx.com     nxt_req_app_link_t   *ra;
463345Smax.romanov@nginx.com 
464345Smax.romanov@nginx.com     ra = obj;
465345Smax.romanov@nginx.com 
466345Smax.romanov@nginx.com     nxt_router_ra_error(task, ra, ra->err_code, ra->err_str);
467345Smax.romanov@nginx.com }
468345Smax.romanov@nginx.com 
469345Smax.romanov@nginx.com 
470345Smax.romanov@nginx.com static void
471345Smax.romanov@nginx.com nxt_router_ra_error(nxt_task_t *task, nxt_req_app_link_t *ra, int code,
472345Smax.romanov@nginx.com     const char* str)
473345Smax.romanov@nginx.com {
474345Smax.romanov@nginx.com     nxt_conn_t           *c;
475345Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
476345Smax.romanov@nginx.com     nxt_event_engine_t   *engine;
477345Smax.romanov@nginx.com 
478345Smax.romanov@nginx.com     engine = ra->work.data;
479345Smax.romanov@nginx.com 
480345Smax.romanov@nginx.com     if (task->thread->engine != engine) {
481345Smax.romanov@nginx.com         ra->err_code = code;
482345Smax.romanov@nginx.com         ra->err_str = str;
483345Smax.romanov@nginx.com 
484345Smax.romanov@nginx.com         ra->work.handler = nxt_router_ra_error_handler;
485345Smax.romanov@nginx.com         ra->work.task = &engine->task;
486345Smax.romanov@nginx.com         ra->work.next = NULL;
487345Smax.romanov@nginx.com 
488345Smax.romanov@nginx.com         nxt_debug(task, "ra stream #%uD post error to %p", ra->stream, engine);
489345Smax.romanov@nginx.com 
490345Smax.romanov@nginx.com         nxt_event_engine_post(engine, &ra->work);
491345Smax.romanov@nginx.com 
492345Smax.romanov@nginx.com         return;
493345Smax.romanov@nginx.com     }
494345Smax.romanov@nginx.com 
495345Smax.romanov@nginx.com     nxt_debug(task, "ra stream #%uD error", ra->stream);
496345Smax.romanov@nginx.com 
497345Smax.romanov@nginx.com     rc = ra->rc;
498345Smax.romanov@nginx.com 
499345Smax.romanov@nginx.com     if (rc != NULL) {
500345Smax.romanov@nginx.com         c = rc->conn;
501345Smax.romanov@nginx.com 
502345Smax.romanov@nginx.com         nxt_router_gen_error(task, c, code, str);
503345Smax.romanov@nginx.com 
504345Smax.romanov@nginx.com         rc->ra = NULL;
505345Smax.romanov@nginx.com         ra->rc = NULL;
506345Smax.romanov@nginx.com     }
507345Smax.romanov@nginx.com 
508345Smax.romanov@nginx.com     if (ra->app_port != NULL) {
509345Smax.romanov@nginx.com         nxt_router_app_port_release(task, ra->app_port, 0, 1);
510345Smax.romanov@nginx.com 
511345Smax.romanov@nginx.com         ra->app_port = NULL;
512345Smax.romanov@nginx.com     }
513345Smax.romanov@nginx.com 
514351Smax.romanov@nginx.com     if (ra->mem_pool != NULL) {
515351Smax.romanov@nginx.com         nxt_mp_release(ra->mem_pool, ra);
516351Smax.romanov@nginx.com     }
517345Smax.romanov@nginx.com }
518345Smax.romanov@nginx.com 
519345Smax.romanov@nginx.com 
520343Smax.romanov@nginx.com nxt_inline void
521343Smax.romanov@nginx.com nxt_router_rc_unlink(nxt_task_t *task, nxt_req_conn_link_t *rc)
522343Smax.romanov@nginx.com {
523343Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
524343Smax.romanov@nginx.com 
525343Smax.romanov@nginx.com     if (rc->app_port != NULL) {
526343Smax.romanov@nginx.com         nxt_router_app_port_release(task, rc->app_port, 0, 1);
527343Smax.romanov@nginx.com 
528343Smax.romanov@nginx.com         rc->app_port = NULL;
529343Smax.romanov@nginx.com     }
530343Smax.romanov@nginx.com 
531343Smax.romanov@nginx.com     ra = rc->ra;
532343Smax.romanov@nginx.com 
533343Smax.romanov@nginx.com     if (ra != NULL) {
534343Smax.romanov@nginx.com         rc->ra = NULL;
535343Smax.romanov@nginx.com         ra->rc = NULL;
536343Smax.romanov@nginx.com 
537343Smax.romanov@nginx.com         nxt_thread_mutex_lock(&rc->app->mutex);
538343Smax.romanov@nginx.com 
539343Smax.romanov@nginx.com         if (ra->link.next != NULL) {
540343Smax.romanov@nginx.com             nxt_queue_remove(&ra->link);
541343Smax.romanov@nginx.com 
542343Smax.romanov@nginx.com             ra->link.next = NULL;
543343Smax.romanov@nginx.com 
544343Smax.romanov@nginx.com         } else {
545343Smax.romanov@nginx.com             ra = NULL;
546343Smax.romanov@nginx.com         }
547343Smax.romanov@nginx.com 
548343Smax.romanov@nginx.com         nxt_thread_mutex_unlock(&rc->app->mutex);
549343Smax.romanov@nginx.com     }
550343Smax.romanov@nginx.com 
551343Smax.romanov@nginx.com     if (ra != NULL) {
552343Smax.romanov@nginx.com         nxt_router_ra_release(task, ra, ra->work.data);
553343Smax.romanov@nginx.com     }
554343Smax.romanov@nginx.com 
555343Smax.romanov@nginx.com     if (rc->app != NULL) {
556343Smax.romanov@nginx.com         nxt_router_app_use(task, rc->app, -1);
557343Smax.romanov@nginx.com 
558343Smax.romanov@nginx.com         rc->app = NULL;
559343Smax.romanov@nginx.com     }
560343Smax.romanov@nginx.com 
561346Smax.romanov@nginx.com     if (rc->ap != NULL) {
562346Smax.romanov@nginx.com         nxt_app_http_req_done(task, rc->ap);
563346Smax.romanov@nginx.com 
564346Smax.romanov@nginx.com         rc->ap = NULL;
565346Smax.romanov@nginx.com     }
566346Smax.romanov@nginx.com 
567343Smax.romanov@nginx.com     nxt_queue_remove(&rc->link);
568343Smax.romanov@nginx.com 
569343Smax.romanov@nginx.com     rc->conn = NULL;
570343Smax.romanov@nginx.com }
571343Smax.romanov@nginx.com 
572343Smax.romanov@nginx.com 
573141Smax.romanov@nginx.com void
574141Smax.romanov@nginx.com nxt_router_new_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
575141Smax.romanov@nginx.com {
576141Smax.romanov@nginx.com     nxt_port_new_port_handler(task, msg);
577141Smax.romanov@nginx.com 
578192Smax.romanov@nginx.com     if (msg->port_msg.stream == 0) {
579141Smax.romanov@nginx.com         return;
580141Smax.romanov@nginx.com     }
581141Smax.romanov@nginx.com 
582347Smax.romanov@nginx.com     if (msg->u.new_port == NULL ||
583347Smax.romanov@nginx.com         msg->u.new_port->type != NXT_PROCESS_WORKER)
584347Smax.romanov@nginx.com     {
585192Smax.romanov@nginx.com         msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR;
586141Smax.romanov@nginx.com     }
587192Smax.romanov@nginx.com 
588192Smax.romanov@nginx.com     nxt_port_rpc_handler(task, msg);
589141Smax.romanov@nginx.com }
590141Smax.romanov@nginx.com 
591141Smax.romanov@nginx.com 
592139Sigor@sysoev.ru void
593139Sigor@sysoev.ru nxt_router_conf_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
594115Sigor@sysoev.ru {
595198Sigor@sysoev.ru     nxt_int_t               ret;
596139Sigor@sysoev.ru     nxt_buf_t               *b;
597139Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
598139Sigor@sysoev.ru 
599139Sigor@sysoev.ru     tmcf = nxt_router_temp_conf(task);
600139Sigor@sysoev.ru     if (nxt_slow_path(tmcf == NULL)) {
601139Sigor@sysoev.ru         return;
60253Sigor@sysoev.ru     }
60353Sigor@sysoev.ru 
604352Smax.romanov@nginx.com     b = nxt_buf_chk_make_plain(tmcf->conf->mem_pool, msg->buf, msg->size);
605352Smax.romanov@nginx.com 
606352Smax.romanov@nginx.com     nxt_assert(b != NULL);
607352Smax.romanov@nginx.com 
608139Sigor@sysoev.ru     tmcf->conf->router = nxt_router;
609139Sigor@sysoev.ru     tmcf->stream = msg->port_msg.stream;
610139Sigor@sysoev.ru     tmcf->port = nxt_runtime_port_find(task->thread->runtime,
611198Sigor@sysoev.ru                                        msg->port_msg.pid,
612198Sigor@sysoev.ru                                        msg->port_msg.reply_port);
613198Sigor@sysoev.ru 
614198Sigor@sysoev.ru     ret = nxt_router_conf_create(task, tmcf, b->mem.pos, b->mem.free);
615198Sigor@sysoev.ru 
616198Sigor@sysoev.ru     if (nxt_fast_path(ret == NXT_OK)) {
617198Sigor@sysoev.ru         nxt_router_conf_apply(task, tmcf, NULL);
618198Sigor@sysoev.ru 
619198Sigor@sysoev.ru     } else {
620198Sigor@sysoev.ru         nxt_router_conf_error(task, tmcf);
621139Sigor@sysoev.ru     }
62253Sigor@sysoev.ru }
62353Sigor@sysoev.ru 
62453Sigor@sysoev.ru 
625347Smax.romanov@nginx.com static void
626347Smax.romanov@nginx.com nxt_router_worker_remove_pid(nxt_task_t *task, nxt_port_t *port, void *data)
627347Smax.romanov@nginx.com {
628347Smax.romanov@nginx.com     union {
629347Smax.romanov@nginx.com         nxt_pid_t  removed_pid;
630347Smax.romanov@nginx.com         void       *data;
631347Smax.romanov@nginx.com     } u;
632347Smax.romanov@nginx.com 
633347Smax.romanov@nginx.com     u.data = data;
634347Smax.romanov@nginx.com 
635347Smax.romanov@nginx.com     nxt_port_rpc_remove_peer(task, port, u.removed_pid);
636347Smax.romanov@nginx.com }
637347Smax.romanov@nginx.com 
638347Smax.romanov@nginx.com 
639192Smax.romanov@nginx.com void
640192Smax.romanov@nginx.com nxt_router_remove_pid_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
641192Smax.romanov@nginx.com {
642347Smax.romanov@nginx.com     nxt_event_engine_t  *engine;
643318Smax.romanov@nginx.com 
644192Smax.romanov@nginx.com     nxt_port_remove_pid_handler(task, msg);
645192Smax.romanov@nginx.com 
646192Smax.romanov@nginx.com     if (msg->port_msg.stream == 0) {
647192Smax.romanov@nginx.com         return;
648192Smax.romanov@nginx.com     }
649192Smax.romanov@nginx.com 
650318Smax.romanov@nginx.com     nxt_queue_each(engine, &nxt_router->engines, nxt_event_engine_t, link0)
651318Smax.romanov@nginx.com     {
652347Smax.romanov@nginx.com         nxt_port_post(task, engine->port, nxt_router_worker_remove_pid,
653347Smax.romanov@nginx.com                       msg->u.data);
654318Smax.romanov@nginx.com     }
655318Smax.romanov@nginx.com     nxt_queue_loop;
656318Smax.romanov@nginx.com 
657192Smax.romanov@nginx.com     msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR;
658192Smax.romanov@nginx.com 
659192Smax.romanov@nginx.com     nxt_port_rpc_handler(task, msg);
660192Smax.romanov@nginx.com }
661192Smax.romanov@nginx.com 
662192Smax.romanov@nginx.com 
66353Sigor@sysoev.ru static nxt_router_temp_conf_t *
664139Sigor@sysoev.ru nxt_router_temp_conf(nxt_task_t *task)
66553Sigor@sysoev.ru {
66665Sigor@sysoev.ru     nxt_mp_t                *mp, *tmp;
66753Sigor@sysoev.ru     nxt_router_conf_t       *rtcf;
66853Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
66953Sigor@sysoev.ru 
67065Sigor@sysoev.ru     mp = nxt_mp_create(1024, 128, 256, 32);
67153Sigor@sysoev.ru     if (nxt_slow_path(mp == NULL)) {
67253Sigor@sysoev.ru         return NULL;
67353Sigor@sysoev.ru     }
67453Sigor@sysoev.ru 
67565Sigor@sysoev.ru     rtcf = nxt_mp_zget(mp, sizeof(nxt_router_conf_t));
67653Sigor@sysoev.ru     if (nxt_slow_path(rtcf == NULL)) {
67753Sigor@sysoev.ru         goto fail;
67853Sigor@sysoev.ru     }
67953Sigor@sysoev.ru 
68053Sigor@sysoev.ru     rtcf->mem_pool = mp;
68153Sigor@sysoev.ru 
68265Sigor@sysoev.ru     tmp = nxt_mp_create(1024, 128, 256, 32);
68353Sigor@sysoev.ru     if (nxt_slow_path(tmp == NULL)) {
68453Sigor@sysoev.ru         goto fail;
68553Sigor@sysoev.ru     }
68653Sigor@sysoev.ru 
68765Sigor@sysoev.ru     tmcf = nxt_mp_zget(tmp, sizeof(nxt_router_temp_conf_t));
68853Sigor@sysoev.ru     if (nxt_slow_path(tmcf == NULL)) {
68953Sigor@sysoev.ru         goto temp_fail;
69053Sigor@sysoev.ru     }
69153Sigor@sysoev.ru 
69253Sigor@sysoev.ru     tmcf->mem_pool = tmp;
69353Sigor@sysoev.ru     tmcf->conf = rtcf;
694139Sigor@sysoev.ru     tmcf->count = 1;
695139Sigor@sysoev.ru     tmcf->engine = task->thread->engine;
69653Sigor@sysoev.ru 
69753Sigor@sysoev.ru     tmcf->engines = nxt_array_create(tmcf->mem_pool, 4,
69853Sigor@sysoev.ru                                      sizeof(nxt_router_engine_conf_t));
69953Sigor@sysoev.ru     if (nxt_slow_path(tmcf->engines == NULL)) {
70053Sigor@sysoev.ru         goto temp_fail;
70153Sigor@sysoev.ru     }
70253Sigor@sysoev.ru 
70353Sigor@sysoev.ru     nxt_queue_init(&tmcf->deleting);
70453Sigor@sysoev.ru     nxt_queue_init(&tmcf->keeping);
70553Sigor@sysoev.ru     nxt_queue_init(&tmcf->updating);
70653Sigor@sysoev.ru     nxt_queue_init(&tmcf->pending);
70753Sigor@sysoev.ru     nxt_queue_init(&tmcf->creating);
708133Sigor@sysoev.ru     nxt_queue_init(&tmcf->apps);
709133Sigor@sysoev.ru     nxt_queue_init(&tmcf->previous);
71053Sigor@sysoev.ru 
71153Sigor@sysoev.ru     return tmcf;
71253Sigor@sysoev.ru 
71353Sigor@sysoev.ru temp_fail:
71453Sigor@sysoev.ru 
71565Sigor@sysoev.ru     nxt_mp_destroy(tmp);
71653Sigor@sysoev.ru 
71753Sigor@sysoev.ru fail:
71853Sigor@sysoev.ru 
71965Sigor@sysoev.ru     nxt_mp_destroy(mp);
72053Sigor@sysoev.ru 
72153Sigor@sysoev.ru     return NULL;
72253Sigor@sysoev.ru }
72353Sigor@sysoev.ru 
72453Sigor@sysoev.ru 
725198Sigor@sysoev.ru static void
726198Sigor@sysoev.ru nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data)
727139Sigor@sysoev.ru {
728139Sigor@sysoev.ru     nxt_int_t                    ret;
729139Sigor@sysoev.ru     nxt_router_t                 *router;
730139Sigor@sysoev.ru     nxt_runtime_t                *rt;
731198Sigor@sysoev.ru     nxt_queue_link_t             *qlk;
732198Sigor@sysoev.ru     nxt_socket_conf_t            *skcf;
733198Sigor@sysoev.ru     nxt_router_temp_conf_t       *tmcf;
734139Sigor@sysoev.ru     const nxt_event_interface_t  *interface;
735139Sigor@sysoev.ru 
736198Sigor@sysoev.ru     tmcf = obj;
737198Sigor@sysoev.ru 
738198Sigor@sysoev.ru     qlk = nxt_queue_first(&tmcf->pending);
739198Sigor@sysoev.ru 
740198Sigor@sysoev.ru     if (qlk != nxt_queue_tail(&tmcf->pending)) {
741198Sigor@sysoev.ru         nxt_queue_remove(qlk);
742198Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->creating, qlk);
743198Sigor@sysoev.ru 
744198Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
745198Sigor@sysoev.ru 
746198Sigor@sysoev.ru         nxt_router_listen_socket_rpc_create(task, tmcf, skcf);
747198Sigor@sysoev.ru 
748198Sigor@sysoev.ru         return;
749139Sigor@sysoev.ru     }
750139Sigor@sysoev.ru 
751139Sigor@sysoev.ru     rt = task->thread->runtime;
752139Sigor@sysoev.ru 
753139Sigor@sysoev.ru     interface = nxt_service_get(rt->services, "engine", NULL);
754139Sigor@sysoev.ru 
755198Sigor@sysoev.ru     router = tmcf->conf->router;
756198Sigor@sysoev.ru 
757139Sigor@sysoev.ru     ret = nxt_router_engines_create(task, router, tmcf, interface);
758139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
759198Sigor@sysoev.ru         goto fail;
760139Sigor@sysoev.ru     }
761139Sigor@sysoev.ru 
762139Sigor@sysoev.ru     ret = nxt_router_threads_create(task, rt, tmcf);
763139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
764198Sigor@sysoev.ru         goto fail;
765139Sigor@sysoev.ru     }
766139Sigor@sysoev.ru 
767343Smax.romanov@nginx.com     nxt_router_apps_sort(task, router, tmcf);
768139Sigor@sysoev.ru 
769315Sigor@sysoev.ru     nxt_router_engines_post(router, tmcf);
770139Sigor@sysoev.ru 
771139Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->updating);
772139Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->creating);
773139Sigor@sysoev.ru 
774198Sigor@sysoev.ru     nxt_router_conf_ready(task, tmcf);
775198Sigor@sysoev.ru 
776198Sigor@sysoev.ru     return;
777198Sigor@sysoev.ru 
778198Sigor@sysoev.ru fail:
779198Sigor@sysoev.ru 
780198Sigor@sysoev.ru     nxt_router_conf_error(task, tmcf);
781198Sigor@sysoev.ru 
782198Sigor@sysoev.ru     return;
783139Sigor@sysoev.ru }
784139Sigor@sysoev.ru 
785139Sigor@sysoev.ru 
786139Sigor@sysoev.ru static void
787139Sigor@sysoev.ru nxt_router_conf_wait(nxt_task_t *task, void *obj, void *data)
788139Sigor@sysoev.ru {
789153Sigor@sysoev.ru     nxt_joint_job_t  *job;
790153Sigor@sysoev.ru 
791153Sigor@sysoev.ru     job = obj;
792153Sigor@sysoev.ru 
793198Sigor@sysoev.ru     nxt_router_conf_ready(task, job->tmcf);
794139Sigor@sysoev.ru }
795139Sigor@sysoev.ru 
796139Sigor@sysoev.ru 
797139Sigor@sysoev.ru static void
798198Sigor@sysoev.ru nxt_router_conf_ready(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
799139Sigor@sysoev.ru {
800139Sigor@sysoev.ru     nxt_debug(task, "temp conf count:%D", tmcf->count);
801139Sigor@sysoev.ru 
802139Sigor@sysoev.ru     if (--tmcf->count == 0) {
803193Smax.romanov@nginx.com         nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_READY_LAST);
804139Sigor@sysoev.ru     }
805139Sigor@sysoev.ru }
806139Sigor@sysoev.ru 
807139Sigor@sysoev.ru 
808139Sigor@sysoev.ru static void
809139Sigor@sysoev.ru nxt_router_conf_error(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
810139Sigor@sysoev.ru {
811148Sigor@sysoev.ru     nxt_socket_t       s;
812149Sigor@sysoev.ru     nxt_router_t       *router;
813148Sigor@sysoev.ru     nxt_queue_link_t   *qlk;
814148Sigor@sysoev.ru     nxt_socket_conf_t  *skcf;
815148Sigor@sysoev.ru 
816198Sigor@sysoev.ru     nxt_log(task, NXT_LOG_CRIT, "failed to apply new conf");
817198Sigor@sysoev.ru 
818148Sigor@sysoev.ru     for (qlk = nxt_queue_first(&tmcf->creating);
819148Sigor@sysoev.ru          qlk != nxt_queue_tail(&tmcf->creating);
820148Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
821148Sigor@sysoev.ru     {
822148Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
823*359Sigor@sysoev.ru         s = skcf->listen->socket;
824148Sigor@sysoev.ru 
825148Sigor@sysoev.ru         if (s != -1) {
826148Sigor@sysoev.ru             nxt_socket_close(task, s);
827148Sigor@sysoev.ru         }
828148Sigor@sysoev.ru 
829*359Sigor@sysoev.ru         nxt_free(skcf->listen);
830148Sigor@sysoev.ru     }
831148Sigor@sysoev.ru 
832149Sigor@sysoev.ru     router = tmcf->conf->router;
833149Sigor@sysoev.ru 
834149Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->keeping);
835149Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->deleting);
836149Sigor@sysoev.ru 
837148Sigor@sysoev.ru     // TODO: new engines and threads
838148Sigor@sysoev.ru 
839139Sigor@sysoev.ru     nxt_mp_destroy(tmcf->conf->mem_pool);
840139Sigor@sysoev.ru 
841193Smax.romanov@nginx.com     nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_ERROR);
842139Sigor@sysoev.ru }
843139Sigor@sysoev.ru 
844139Sigor@sysoev.ru 
845139Sigor@sysoev.ru static void
846139Sigor@sysoev.ru nxt_router_conf_send(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
847193Smax.romanov@nginx.com     nxt_port_msg_type_t type)
848139Sigor@sysoev.ru {
849193Smax.romanov@nginx.com     nxt_port_socket_write(task, tmcf->port, type, -1, tmcf->stream, 0, NULL);
850139Sigor@sysoev.ru }
851139Sigor@sysoev.ru 
852139Sigor@sysoev.ru 
853115Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_conf[] = {
854115Sigor@sysoev.ru     {
855133Sigor@sysoev.ru         nxt_string("listeners_threads"),
856115Sigor@sysoev.ru         NXT_CONF_MAP_INT32,
857115Sigor@sysoev.ru         offsetof(nxt_router_conf_t, threads),
858115Sigor@sysoev.ru     },
859115Sigor@sysoev.ru };
860115Sigor@sysoev.ru 
861115Sigor@sysoev.ru 
862133Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_app_conf[] = {
863115Sigor@sysoev.ru     {
864133Sigor@sysoev.ru         nxt_string("type"),
865115Sigor@sysoev.ru         NXT_CONF_MAP_STR,
866133Sigor@sysoev.ru         offsetof(nxt_router_app_conf_t, type),
867115Sigor@sysoev.ru     },
868115Sigor@sysoev.ru 
869115Sigor@sysoev.ru     {
870133Sigor@sysoev.ru         nxt_string("workers"),
871115Sigor@sysoev.ru         NXT_CONF_MAP_INT32,
872133Sigor@sysoev.ru         offsetof(nxt_router_app_conf_t, workers),
873133Sigor@sysoev.ru     },
874318Smax.romanov@nginx.com 
875318Smax.romanov@nginx.com     {
876318Smax.romanov@nginx.com         nxt_string("limits"),
877318Smax.romanov@nginx.com         NXT_CONF_MAP_PTR,
878318Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, limits_value),
879318Smax.romanov@nginx.com     },
880318Smax.romanov@nginx.com };
881318Smax.romanov@nginx.com 
882318Smax.romanov@nginx.com 
883318Smax.romanov@nginx.com static nxt_conf_map_t  nxt_router_app_limits_conf[] = {
884318Smax.romanov@nginx.com     {
885318Smax.romanov@nginx.com         nxt_string("timeout"),
886318Smax.romanov@nginx.com         NXT_CONF_MAP_MSEC,
887318Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, timeout),
888318Smax.romanov@nginx.com     },
889318Smax.romanov@nginx.com 
890318Smax.romanov@nginx.com     {
891318Smax.romanov@nginx.com         nxt_string("requests"),
892318Smax.romanov@nginx.com         NXT_CONF_MAP_INT32,
893318Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, requests),
894318Smax.romanov@nginx.com     },
895133Sigor@sysoev.ru };
896133Sigor@sysoev.ru 
897133Sigor@sysoev.ru 
898133Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_listener_conf[] = {
899133Sigor@sysoev.ru     {
900133Sigor@sysoev.ru         nxt_string("application"),
901133Sigor@sysoev.ru         NXT_CONF_MAP_STR,
902133Sigor@sysoev.ru         offsetof(nxt_router_listener_conf_t, application),
903115Sigor@sysoev.ru     },
904115Sigor@sysoev.ru };
905115Sigor@sysoev.ru 
906115Sigor@sysoev.ru 
907115Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_http_conf[] = {
908115Sigor@sysoev.ru     {
909115Sigor@sysoev.ru         nxt_string("header_buffer_size"),
910115Sigor@sysoev.ru         NXT_CONF_MAP_SIZE,
911115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, header_buffer_size),
912115Sigor@sysoev.ru     },
913115Sigor@sysoev.ru 
914115Sigor@sysoev.ru     {
915115Sigor@sysoev.ru         nxt_string("large_header_buffer_size"),
916115Sigor@sysoev.ru         NXT_CONF_MAP_SIZE,
917115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, large_header_buffer_size),
918115Sigor@sysoev.ru     },
919115Sigor@sysoev.ru 
920115Sigor@sysoev.ru     {
921206Smax.romanov@nginx.com         nxt_string("large_header_buffers"),
922206Smax.romanov@nginx.com         NXT_CONF_MAP_SIZE,
923206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, large_header_buffers),
924206Smax.romanov@nginx.com     },
925206Smax.romanov@nginx.com 
926206Smax.romanov@nginx.com     {
927206Smax.romanov@nginx.com         nxt_string("body_buffer_size"),
928206Smax.romanov@nginx.com         NXT_CONF_MAP_SIZE,
929206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, body_buffer_size),
930206Smax.romanov@nginx.com     },
931206Smax.romanov@nginx.com 
932206Smax.romanov@nginx.com     {
933206Smax.romanov@nginx.com         nxt_string("max_body_size"),
934206Smax.romanov@nginx.com         NXT_CONF_MAP_SIZE,
935206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, max_body_size),
936206Smax.romanov@nginx.com     },
937206Smax.romanov@nginx.com 
938206Smax.romanov@nginx.com     {
939115Sigor@sysoev.ru         nxt_string("header_read_timeout"),
940115Sigor@sysoev.ru         NXT_CONF_MAP_MSEC,
941115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, header_read_timeout),
942115Sigor@sysoev.ru     },
943206Smax.romanov@nginx.com 
944206Smax.romanov@nginx.com     {
945206Smax.romanov@nginx.com         nxt_string("body_read_timeout"),
946206Smax.romanov@nginx.com         NXT_CONF_MAP_MSEC,
947206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, body_read_timeout),
948206Smax.romanov@nginx.com     },
949115Sigor@sysoev.ru };
950115Sigor@sysoev.ru 
951115Sigor@sysoev.ru 
95253Sigor@sysoev.ru static nxt_int_t
953115Sigor@sysoev.ru nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
954115Sigor@sysoev.ru     u_char *start, u_char *end)
95553Sigor@sysoev.ru {
956133Sigor@sysoev.ru     u_char                      *p;
957133Sigor@sysoev.ru     size_t                      size;
958115Sigor@sysoev.ru     nxt_mp_t                    *mp;
959115Sigor@sysoev.ru     uint32_t                    next;
960115Sigor@sysoev.ru     nxt_int_t                   ret;
961115Sigor@sysoev.ru     nxt_str_t                   name;
962133Sigor@sysoev.ru     nxt_app_t                   *app, *prev;
963*359Sigor@sysoev.ru     nxt_router_t                *router;
964133Sigor@sysoev.ru     nxt_conf_value_t            *conf, *http;
965133Sigor@sysoev.ru     nxt_conf_value_t            *applications, *application;
966133Sigor@sysoev.ru     nxt_conf_value_t            *listeners, *listener;
967115Sigor@sysoev.ru     nxt_socket_conf_t           *skcf;
968216Sigor@sysoev.ru     nxt_app_lang_module_t       *lang;
969133Sigor@sysoev.ru     nxt_router_app_conf_t       apcf;
970115Sigor@sysoev.ru     nxt_router_listener_conf_t  lscf;
971115Sigor@sysoev.ru 
972115Sigor@sysoev.ru     static nxt_str_t  http_path = nxt_string("/http");
973133Sigor@sysoev.ru     static nxt_str_t  applications_path = nxt_string("/applications");
974115Sigor@sysoev.ru     static nxt_str_t  listeners_path = nxt_string("/listeners");
975115Sigor@sysoev.ru 
976208Svbart@nginx.com     conf = nxt_conf_json_parse(tmcf->mem_pool, start, end, NULL);
977115Sigor@sysoev.ru     if (conf == NULL) {
978115Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "configuration parsing error");
979115Sigor@sysoev.ru         return NXT_ERROR;
980115Sigor@sysoev.ru     }
981115Sigor@sysoev.ru 
982213Svbart@nginx.com     mp = tmcf->conf->mem_pool;
983213Svbart@nginx.com 
984213Svbart@nginx.com     ret = nxt_conf_map_object(mp, conf, nxt_router_conf,
985136Svbart@nginx.com                               nxt_nitems(nxt_router_conf), tmcf->conf);
986115Sigor@sysoev.ru     if (ret != NXT_OK) {
987133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "root map error");
988115Sigor@sysoev.ru         return NXT_ERROR;
989115Sigor@sysoev.ru     }
990115Sigor@sysoev.ru 
991117Sigor@sysoev.ru     if (tmcf->conf->threads == 0) {
992117Sigor@sysoev.ru         tmcf->conf->threads = nxt_ncpu;
993117Sigor@sysoev.ru     }
994117Sigor@sysoev.ru 
995133Sigor@sysoev.ru     applications = nxt_conf_get_path(conf, &applications_path);
996133Sigor@sysoev.ru     if (applications == NULL) {
997133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "no \"applications\" block");
998115Sigor@sysoev.ru         return NXT_ERROR;
999115Sigor@sysoev.ru     }
1000115Sigor@sysoev.ru 
1001*359Sigor@sysoev.ru     router = tmcf->conf->router;
1002*359Sigor@sysoev.ru 
1003133Sigor@sysoev.ru     next = 0;
1004133Sigor@sysoev.ru 
1005133Sigor@sysoev.ru     for ( ;; ) {
1006133Sigor@sysoev.ru         application = nxt_conf_next_object_member(applications, &name, &next);
1007133Sigor@sysoev.ru         if (application == NULL) {
1008133Sigor@sysoev.ru             break;
1009133Sigor@sysoev.ru         }
1010133Sigor@sysoev.ru 
1011133Sigor@sysoev.ru         nxt_debug(task, "application \"%V\"", &name);
1012133Sigor@sysoev.ru 
1013144Smax.romanov@nginx.com         size = nxt_conf_json_length(application, NULL);
1014144Smax.romanov@nginx.com 
1015144Smax.romanov@nginx.com         app = nxt_malloc(sizeof(nxt_app_t) + name.length + size);
1016133Sigor@sysoev.ru         if (app == NULL) {
1017133Sigor@sysoev.ru             goto fail;
1018133Sigor@sysoev.ru         }
1019133Sigor@sysoev.ru 
1020144Smax.romanov@nginx.com         nxt_memzero(app, sizeof(nxt_app_t));
1021144Smax.romanov@nginx.com 
1022144Smax.romanov@nginx.com         app->name.start = nxt_pointer_to(app, sizeof(nxt_app_t));
1023144Smax.romanov@nginx.com         app->conf.start = nxt_pointer_to(app, sizeof(nxt_app_t) + name.length);
1024133Sigor@sysoev.ru 
1025133Sigor@sysoev.ru         p = nxt_conf_json_print(app->conf.start, application, NULL);
1026133Sigor@sysoev.ru         app->conf.length = p - app->conf.start;
1027133Sigor@sysoev.ru 
1028144Smax.romanov@nginx.com         nxt_assert(app->conf.length <= size);
1029144Smax.romanov@nginx.com 
1030133Sigor@sysoev.ru         nxt_debug(task, "application conf \"%V\"", &app->conf);
1031133Sigor@sysoev.ru 
1032*359Sigor@sysoev.ru         prev = nxt_router_app_find(&router->apps, &name);
1033133Sigor@sysoev.ru 
1034133Sigor@sysoev.ru         if (prev != NULL && nxt_strstr_eq(&app->conf, &prev->conf)) {
1035133Sigor@sysoev.ru             nxt_free(app);
1036133Sigor@sysoev.ru 
1037133Sigor@sysoev.ru             nxt_queue_remove(&prev->link);
1038133Sigor@sysoev.ru             nxt_queue_insert_tail(&tmcf->previous, &prev->link);
1039133Sigor@sysoev.ru             continue;
1040133Sigor@sysoev.ru         }
1041133Sigor@sysoev.ru 
1042263Smax.romanov@nginx.com         apcf.workers = 1;
1043318Smax.romanov@nginx.com         apcf.timeout = 0;
1044318Smax.romanov@nginx.com         apcf.requests = 0;
1045318Smax.romanov@nginx.com         apcf.limits_value = NULL;
1046263Smax.romanov@nginx.com 
1047213Svbart@nginx.com         ret = nxt_conf_map_object(mp, application, nxt_router_app_conf,
1048136Svbart@nginx.com                                   nxt_nitems(nxt_router_app_conf), &apcf);
1049133Sigor@sysoev.ru         if (ret != NXT_OK) {
1050133Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "application map error");
1051133Sigor@sysoev.ru             goto app_fail;
1052133Sigor@sysoev.ru         }
1053115Sigor@sysoev.ru 
1054318Smax.romanov@nginx.com         if (apcf.limits_value != NULL) {
1055318Smax.romanov@nginx.com 
1056318Smax.romanov@nginx.com             if (nxt_conf_type(apcf.limits_value) != NXT_CONF_OBJECT) {
1057318Smax.romanov@nginx.com                 nxt_log(task, NXT_LOG_CRIT, "application limits is not object");
1058318Smax.romanov@nginx.com                 goto app_fail;
1059318Smax.romanov@nginx.com             }
1060318Smax.romanov@nginx.com 
1061318Smax.romanov@nginx.com             ret = nxt_conf_map_object(mp, apcf.limits_value,
1062318Smax.romanov@nginx.com                                       nxt_router_app_limits_conf,
1063318Smax.romanov@nginx.com                                       nxt_nitems(nxt_router_app_limits_conf),
1064318Smax.romanov@nginx.com                                       &apcf);
1065318Smax.romanov@nginx.com             if (ret != NXT_OK) {
1066318Smax.romanov@nginx.com                 nxt_log(task, NXT_LOG_CRIT, "application limits map error");
1067318Smax.romanov@nginx.com                 goto app_fail;
1068318Smax.romanov@nginx.com             }
1069318Smax.romanov@nginx.com         }
1070318Smax.romanov@nginx.com 
1071133Sigor@sysoev.ru         nxt_debug(task, "application type: %V", &apcf.type);
1072133Sigor@sysoev.ru         nxt_debug(task, "application workers: %D", apcf.workers);
1073318Smax.romanov@nginx.com         nxt_debug(task, "application timeout: %D", apcf.timeout);
1074318Smax.romanov@nginx.com         nxt_debug(task, "application requests: %D", apcf.requests);
1075133Sigor@sysoev.ru 
1076216Sigor@sysoev.ru         lang = nxt_app_lang_module(task->thread->runtime, &apcf.type);
1077216Sigor@sysoev.ru 
1078216Sigor@sysoev.ru         if (lang == NULL) {
1079141Smax.romanov@nginx.com             nxt_log(task, NXT_LOG_CRIT, "unknown application type: \"%V\"",
1080141Smax.romanov@nginx.com                     &apcf.type);
1081141Smax.romanov@nginx.com             goto app_fail;
1082141Smax.romanov@nginx.com         }
1083141Smax.romanov@nginx.com 
1084216Sigor@sysoev.ru         nxt_debug(task, "application language module: \"%s\"", lang->file);
1085216Sigor@sysoev.ru 
1086133Sigor@sysoev.ru         ret = nxt_thread_mutex_create(&app->mutex);
1087133Sigor@sysoev.ru         if (ret != NXT_OK) {
1088133Sigor@sysoev.ru             goto app_fail;
1089133Sigor@sysoev.ru         }
1090133Sigor@sysoev.ru 
1091141Smax.romanov@nginx.com         nxt_queue_init(&app->ports);
1092141Smax.romanov@nginx.com         nxt_queue_init(&app->requests);
1093141Smax.romanov@nginx.com 
1094144Smax.romanov@nginx.com         app->name.length = name.length;
1095144Smax.romanov@nginx.com         nxt_memcpy(app->name.start, name.start, name.length);
1096144Smax.romanov@nginx.com 
1097356Svbart@nginx.com         app->type = lang->type;
1098133Sigor@sysoev.ru         app->max_workers = apcf.workers;
1099318Smax.romanov@nginx.com         app->timeout = apcf.timeout;
1100133Sigor@sysoev.ru         app->live = 1;
1101343Smax.romanov@nginx.com         app->max_pending_responses = 2;
1102356Svbart@nginx.com         app->prepare_msg = nxt_app_prepare_msg[lang->type];
1103133Sigor@sysoev.ru 
1104133Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->apps, &app->link);
1105343Smax.romanov@nginx.com 
1106343Smax.romanov@nginx.com         nxt_router_app_use(task, app, 1);
1107133Sigor@sysoev.ru     }
1108133Sigor@sysoev.ru 
1109133Sigor@sysoev.ru     http = nxt_conf_get_path(conf, &http_path);
1110133Sigor@sysoev.ru #if 0
1111133Sigor@sysoev.ru     if (http == NULL) {
1112133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "no \"http\" block");
1113133Sigor@sysoev.ru         return NXT_ERROR;
1114133Sigor@sysoev.ru     }
1115133Sigor@sysoev.ru #endif
1116133Sigor@sysoev.ru 
1117133Sigor@sysoev.ru     listeners = nxt_conf_get_path(conf, &listeners_path);
1118115Sigor@sysoev.ru     if (listeners == NULL) {
1119133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "no \"listeners\" block");
1120115Sigor@sysoev.ru         return NXT_ERROR;
1121115Sigor@sysoev.ru     }
112253Sigor@sysoev.ru 
1123133Sigor@sysoev.ru     next = 0;
112453Sigor@sysoev.ru 
1125115Sigor@sysoev.ru     for ( ;; ) {
1126115Sigor@sysoev.ru         listener = nxt_conf_next_object_member(listeners, &name, &next);
1127115Sigor@sysoev.ru         if (listener == NULL) {
1128115Sigor@sysoev.ru             break;
1129115Sigor@sysoev.ru         }
113053Sigor@sysoev.ru 
1131*359Sigor@sysoev.ru         skcf = nxt_router_socket_conf(task, tmcf, &name);
1132115Sigor@sysoev.ru         if (skcf == NULL) {
1133133Sigor@sysoev.ru             goto fail;
1134115Sigor@sysoev.ru         }
113553Sigor@sysoev.ru 
1136213Svbart@nginx.com         ret = nxt_conf_map_object(mp, listener, nxt_router_listener_conf,
1137136Svbart@nginx.com                                   nxt_nitems(nxt_router_listener_conf), &lscf);
1138115Sigor@sysoev.ru         if (ret != NXT_OK) {
1139115Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "listener map error");
1140133Sigor@sysoev.ru             goto fail;
1141115Sigor@sysoev.ru         }
114253Sigor@sysoev.ru 
1143133Sigor@sysoev.ru         nxt_debug(task, "application: %V", &lscf.application);
1144133Sigor@sysoev.ru 
1145133Sigor@sysoev.ru         // STUB, default values if http block is not defined.
1146133Sigor@sysoev.ru         skcf->header_buffer_size = 2048;
1147133Sigor@sysoev.ru         skcf->large_header_buffer_size = 8192;
1148206Smax.romanov@nginx.com         skcf->large_header_buffers = 4;
1149206Smax.romanov@nginx.com         skcf->body_buffer_size = 16 * 1024;
1150206Smax.romanov@nginx.com         skcf->max_body_size = 2 * 1024 * 1024;
1151133Sigor@sysoev.ru         skcf->header_read_timeout = 5000;
1152206Smax.romanov@nginx.com         skcf->body_read_timeout = 5000;
115353Sigor@sysoev.ru 
1154133Sigor@sysoev.ru         if (http != NULL) {
1155213Svbart@nginx.com             ret = nxt_conf_map_object(mp, http, nxt_router_http_conf,
1156136Svbart@nginx.com                                       nxt_nitems(nxt_router_http_conf), skcf);
1157133Sigor@sysoev.ru             if (ret != NXT_OK) {
1158133Sigor@sysoev.ru                 nxt_log(task, NXT_LOG_CRIT, "http map error");
1159133Sigor@sysoev.ru                 goto fail;
1160133Sigor@sysoev.ru             }
1161115Sigor@sysoev.ru         }
1162115Sigor@sysoev.ru 
1163*359Sigor@sysoev.ru         skcf->listen->handler = nxt_router_conn_init;
1164115Sigor@sysoev.ru         skcf->router_conf = tmcf->conf;
1165160Sigor@sysoev.ru         skcf->router_conf->count++;
1166133Sigor@sysoev.ru         skcf->application = nxt_router_listener_application(tmcf,
1167133Sigor@sysoev.ru                                                             &lscf.application);
1168115Sigor@sysoev.ru     }
116953Sigor@sysoev.ru 
1170*359Sigor@sysoev.ru     nxt_queue_add(&tmcf->deleting, &router->sockets);
1171*359Sigor@sysoev.ru     nxt_queue_init(&router->sockets);
1172198Sigor@sysoev.ru 
117353Sigor@sysoev.ru     return NXT_OK;
1174133Sigor@sysoev.ru 
1175133Sigor@sysoev.ru app_fail:
1176133Sigor@sysoev.ru 
1177133Sigor@sysoev.ru     nxt_free(app);
1178133Sigor@sysoev.ru 
1179133Sigor@sysoev.ru fail:
1180133Sigor@sysoev.ru 
1181141Smax.romanov@nginx.com     nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) {
1182141Smax.romanov@nginx.com 
1183141Smax.romanov@nginx.com         nxt_queue_remove(&app->link);
1184133Sigor@sysoev.ru         nxt_thread_mutex_destroy(&app->mutex);
1185133Sigor@sysoev.ru         nxt_free(app);
1186141Smax.romanov@nginx.com 
1187141Smax.romanov@nginx.com     } nxt_queue_loop;
1188133Sigor@sysoev.ru 
1189133Sigor@sysoev.ru     return NXT_ERROR;
1190133Sigor@sysoev.ru }
1191133Sigor@sysoev.ru 
1192133Sigor@sysoev.ru 
1193133Sigor@sysoev.ru static nxt_app_t *
1194133Sigor@sysoev.ru nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name)
1195133Sigor@sysoev.ru {
1196141Smax.romanov@nginx.com     nxt_app_t  *app;
1197141Smax.romanov@nginx.com 
1198141Smax.romanov@nginx.com     nxt_queue_each(app, queue, nxt_app_t, link) {
1199133Sigor@sysoev.ru 
1200133Sigor@sysoev.ru         if (nxt_strstr_eq(name, &app->name)) {
1201133Sigor@sysoev.ru             return app;
1202133Sigor@sysoev.ru         }
1203141Smax.romanov@nginx.com 
1204141Smax.romanov@nginx.com     } nxt_queue_loop;
1205133Sigor@sysoev.ru 
1206133Sigor@sysoev.ru     return NULL;
1207133Sigor@sysoev.ru }
1208133Sigor@sysoev.ru 
1209133Sigor@sysoev.ru 
1210133Sigor@sysoev.ru static nxt_app_t *
1211133Sigor@sysoev.ru nxt_router_listener_application(nxt_router_temp_conf_t *tmcf, nxt_str_t *name)
1212133Sigor@sysoev.ru {
1213133Sigor@sysoev.ru     nxt_app_t  *app;
1214133Sigor@sysoev.ru 
1215133Sigor@sysoev.ru     app = nxt_router_app_find(&tmcf->apps, name);
1216133Sigor@sysoev.ru 
1217133Sigor@sysoev.ru     if (app == NULL) {
1218134Sigor@sysoev.ru         app = nxt_router_app_find(&tmcf->previous, name);
1219133Sigor@sysoev.ru     }
1220133Sigor@sysoev.ru 
1221133Sigor@sysoev.ru     return app;
122253Sigor@sysoev.ru }
122353Sigor@sysoev.ru 
122453Sigor@sysoev.ru 
122553Sigor@sysoev.ru static nxt_socket_conf_t *
1226*359Sigor@sysoev.ru nxt_router_socket_conf(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
1227*359Sigor@sysoev.ru     nxt_str_t *name)
122853Sigor@sysoev.ru {
1229*359Sigor@sysoev.ru     size_t               size;
1230*359Sigor@sysoev.ru     nxt_int_t            ret;
1231*359Sigor@sysoev.ru     nxt_bool_t           wildcard;
1232*359Sigor@sysoev.ru     nxt_sockaddr_t       *sa;
1233*359Sigor@sysoev.ru     nxt_socket_conf_t    *skcf;
1234*359Sigor@sysoev.ru     nxt_listen_socket_t  *ls;
1235*359Sigor@sysoev.ru 
1236*359Sigor@sysoev.ru     sa = nxt_sockaddr_parse(tmcf->mem_pool, name);
1237*359Sigor@sysoev.ru     if (nxt_slow_path(sa == NULL)) {
1238*359Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "invalid listener \"%V\"", name);
1239*359Sigor@sysoev.ru         return NULL;
1240*359Sigor@sysoev.ru     }
1241*359Sigor@sysoev.ru 
1242*359Sigor@sysoev.ru     sa->type = SOCK_STREAM;
1243*359Sigor@sysoev.ru 
1244*359Sigor@sysoev.ru     nxt_debug(task, "router listener: \"%*s\"",
1245*359Sigor@sysoev.ru               sa->length, nxt_sockaddr_start(sa));
1246*359Sigor@sysoev.ru 
1247*359Sigor@sysoev.ru     skcf = nxt_mp_zget(tmcf->conf->mem_pool, sizeof(nxt_socket_conf_t));
1248163Smax.romanov@nginx.com     if (nxt_slow_path(skcf == NULL)) {
124953Sigor@sysoev.ru         return NULL;
125053Sigor@sysoev.ru     }
125153Sigor@sysoev.ru 
1252*359Sigor@sysoev.ru     size = nxt_sockaddr_size(sa);
1253*359Sigor@sysoev.ru 
1254*359Sigor@sysoev.ru     ret = nxt_router_listen_socket_find(tmcf, skcf, sa);
1255*359Sigor@sysoev.ru 
1256*359Sigor@sysoev.ru     if (ret != NXT_OK) {
1257*359Sigor@sysoev.ru 
1258*359Sigor@sysoev.ru         ls = nxt_zalloc(sizeof(nxt_listen_socket_t) + size);
1259*359Sigor@sysoev.ru         if (nxt_slow_path(ls == NULL)) {
1260*359Sigor@sysoev.ru             return NULL;
1261*359Sigor@sysoev.ru         }
1262*359Sigor@sysoev.ru 
1263*359Sigor@sysoev.ru         skcf->listen = ls;
1264*359Sigor@sysoev.ru 
1265*359Sigor@sysoev.ru         ls->sockaddr = nxt_pointer_to(ls, sizeof(nxt_listen_socket_t));
1266*359Sigor@sysoev.ru         nxt_memcpy(ls->sockaddr, sa, size);
1267*359Sigor@sysoev.ru 
1268*359Sigor@sysoev.ru         nxt_listen_socket_remote_size(ls);
1269*359Sigor@sysoev.ru 
1270*359Sigor@sysoev.ru         ls->socket = -1;
1271*359Sigor@sysoev.ru         ls->backlog = NXT_LISTEN_BACKLOG;
1272*359Sigor@sysoev.ru         ls->flags = NXT_NONBLOCK;
1273*359Sigor@sysoev.ru         ls->read_after_accept = 1;
1274*359Sigor@sysoev.ru     }
1275*359Sigor@sysoev.ru 
1276*359Sigor@sysoev.ru     switch (sa->u.sockaddr.sa_family) {
1277*359Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN)
1278*359Sigor@sysoev.ru     case AF_UNIX:
1279*359Sigor@sysoev.ru         wildcard = 0;
1280*359Sigor@sysoev.ru         break;
1281*359Sigor@sysoev.ru #endif
1282*359Sigor@sysoev.ru #if (NXT_INET6)
1283*359Sigor@sysoev.ru     case AF_INET6:
1284*359Sigor@sysoev.ru         wildcard = IN6_IS_ADDR_UNSPECIFIED(&sa->u.sockaddr_in6.sin6_addr);
1285*359Sigor@sysoev.ru         break;
1286*359Sigor@sysoev.ru #endif
1287*359Sigor@sysoev.ru     case AF_INET:
1288*359Sigor@sysoev.ru     default:
1289*359Sigor@sysoev.ru         wildcard = (sa->u.sockaddr_in.sin_addr.s_addr == INADDR_ANY);
1290*359Sigor@sysoev.ru         break;
1291*359Sigor@sysoev.ru     }
1292*359Sigor@sysoev.ru 
1293*359Sigor@sysoev.ru     if (!wildcard) {
1294*359Sigor@sysoev.ru         skcf->sockaddr = nxt_mp_zget(tmcf->conf->mem_pool, size);
1295*359Sigor@sysoev.ru         if (nxt_slow_path(skcf->sockaddr == NULL)) {
1296*359Sigor@sysoev.ru             return NULL;
1297*359Sigor@sysoev.ru         }
1298*359Sigor@sysoev.ru 
1299*359Sigor@sysoev.ru         nxt_memcpy(skcf->sockaddr, sa, size);
1300*359Sigor@sysoev.ru     }
1301163Smax.romanov@nginx.com 
1302163Smax.romanov@nginx.com     return skcf;
130353Sigor@sysoev.ru }
130453Sigor@sysoev.ru 
130553Sigor@sysoev.ru 
1306*359Sigor@sysoev.ru static nxt_int_t
1307*359Sigor@sysoev.ru nxt_router_listen_socket_find(nxt_router_temp_conf_t *tmcf,
1308*359Sigor@sysoev.ru     nxt_socket_conf_t *nskcf, nxt_sockaddr_t *sa)
130953Sigor@sysoev.ru {
1310*359Sigor@sysoev.ru     nxt_router_t       *router;
1311*359Sigor@sysoev.ru     nxt_queue_link_t   *qlk;
1312*359Sigor@sysoev.ru     nxt_socket_conf_t  *skcf;
1313*359Sigor@sysoev.ru 
1314*359Sigor@sysoev.ru     router = tmcf->conf->router;
1315*359Sigor@sysoev.ru 
1316*359Sigor@sysoev.ru     for (qlk = nxt_queue_first(&router->sockets);
1317*359Sigor@sysoev.ru          qlk != nxt_queue_tail(&router->sockets);
1318*359Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
131953Sigor@sysoev.ru     {
1320*359Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
1321*359Sigor@sysoev.ru 
1322*359Sigor@sysoev.ru         if (nxt_sockaddr_cmp(skcf->listen->sockaddr, sa)) {
1323*359Sigor@sysoev.ru             nskcf->listen = skcf->listen;
1324*359Sigor@sysoev.ru 
1325*359Sigor@sysoev.ru             nxt_queue_remove(qlk);
1326*359Sigor@sysoev.ru             nxt_queue_insert_tail(&tmcf->keeping, qlk);
1327*359Sigor@sysoev.ru 
1328*359Sigor@sysoev.ru             nxt_queue_insert_tail(&tmcf->updating, &nskcf->link);
1329*359Sigor@sysoev.ru 
1330*359Sigor@sysoev.ru             return NXT_OK;
133153Sigor@sysoev.ru         }
133253Sigor@sysoev.ru     }
133353Sigor@sysoev.ru 
1334*359Sigor@sysoev.ru     nxt_queue_insert_tail(&tmcf->pending, &nskcf->link);
1335*359Sigor@sysoev.ru 
1336*359Sigor@sysoev.ru     return NXT_DECLINED;
133753Sigor@sysoev.ru }
133853Sigor@sysoev.ru 
133953Sigor@sysoev.ru 
1340198Sigor@sysoev.ru static void
1341198Sigor@sysoev.ru nxt_router_listen_socket_rpc_create(nxt_task_t *task,
1342198Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf)
1343198Sigor@sysoev.ru {
1344358Sigor@sysoev.ru     size_t            size;
1345198Sigor@sysoev.ru     uint32_t          stream;
1346198Sigor@sysoev.ru     nxt_buf_t         *b;
1347198Sigor@sysoev.ru     nxt_port_t        *main_port, *router_port;
1348198Sigor@sysoev.ru     nxt_runtime_t     *rt;
1349198Sigor@sysoev.ru     nxt_socket_rpc_t  *rpc;
1350198Sigor@sysoev.ru 
1351198Sigor@sysoev.ru     rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_socket_rpc_t));
1352198Sigor@sysoev.ru     if (rpc == NULL) {
1353198Sigor@sysoev.ru         goto fail;
1354198Sigor@sysoev.ru     }
1355198Sigor@sysoev.ru 
1356198Sigor@sysoev.ru     rpc->socket_conf = skcf;
1357198Sigor@sysoev.ru     rpc->temp_conf = tmcf;
1358198Sigor@sysoev.ru 
1359*359Sigor@sysoev.ru     size = nxt_sockaddr_size(skcf->listen->sockaddr);
1360358Sigor@sysoev.ru 
1361358Sigor@sysoev.ru     b = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0);
1362198Sigor@sysoev.ru     if (b == NULL) {
1363198Sigor@sysoev.ru         goto fail;
1364198Sigor@sysoev.ru     }
1365198Sigor@sysoev.ru 
1366*359Sigor@sysoev.ru     b->mem.free = nxt_cpymem(b->mem.free, skcf->listen->sockaddr, size);
1367198Sigor@sysoev.ru 
1368198Sigor@sysoev.ru     rt = task->thread->runtime;
1369240Sigor@sysoev.ru     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
1370198Sigor@sysoev.ru     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
1371198Sigor@sysoev.ru 
1372198Sigor@sysoev.ru     stream = nxt_port_rpc_register_handler(task, router_port,
1373198Sigor@sysoev.ru                                            nxt_router_listen_socket_ready,
1374198Sigor@sysoev.ru                                            nxt_router_listen_socket_error,
1375198Sigor@sysoev.ru                                            main_port->pid, rpc);
1376198Sigor@sysoev.ru     if (stream == 0) {
1377198Sigor@sysoev.ru         goto fail;
1378198Sigor@sysoev.ru     }
1379198Sigor@sysoev.ru 
1380198Sigor@sysoev.ru     nxt_port_socket_write(task, main_port, NXT_PORT_MSG_SOCKET, -1,
1381198Sigor@sysoev.ru                           stream, router_port->id, b);
1382198Sigor@sysoev.ru 
1383198Sigor@sysoev.ru     return;
1384198Sigor@sysoev.ru 
1385198Sigor@sysoev.ru fail:
1386198Sigor@sysoev.ru 
1387198Sigor@sysoev.ru     nxt_router_conf_error(task, tmcf);
1388198Sigor@sysoev.ru }
1389198Sigor@sysoev.ru 
1390198Sigor@sysoev.ru 
1391198Sigor@sysoev.ru static void
1392198Sigor@sysoev.ru nxt_router_listen_socket_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
1393198Sigor@sysoev.ru     void *data)
139453Sigor@sysoev.ru {
1395*359Sigor@sysoev.ru     nxt_int_t         ret;
1396*359Sigor@sysoev.ru     nxt_socket_t      s;
1397*359Sigor@sysoev.ru     nxt_socket_rpc_t  *rpc;
139853Sigor@sysoev.ru 
1399198Sigor@sysoev.ru     rpc = data;
1400198Sigor@sysoev.ru 
1401198Sigor@sysoev.ru     s = msg->fd;
1402198Sigor@sysoev.ru 
1403198Sigor@sysoev.ru     ret = nxt_socket_nonblocking(task, s);
1404198Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1405198Sigor@sysoev.ru         goto fail;
140653Sigor@sysoev.ru     }
140753Sigor@sysoev.ru 
1408*359Sigor@sysoev.ru     nxt_socket_defer_accept(task, s, rpc->socket_conf->listen->sockaddr);
1409198Sigor@sysoev.ru 
1410198Sigor@sysoev.ru     ret = nxt_listen_socket(task, s, NXT_LISTEN_BACKLOG);
1411198Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1412198Sigor@sysoev.ru         goto fail;
1413198Sigor@sysoev.ru     }
1414198Sigor@sysoev.ru 
1415*359Sigor@sysoev.ru     rpc->socket_conf->listen->socket = s;
1416198Sigor@sysoev.ru 
1417198Sigor@sysoev.ru     nxt_work_queue_add(&task->thread->engine->fast_work_queue,
1418198Sigor@sysoev.ru                        nxt_router_conf_apply, task, rpc->temp_conf, NULL);
1419198Sigor@sysoev.ru 
1420198Sigor@sysoev.ru     return;
1421148Sigor@sysoev.ru 
1422148Sigor@sysoev.ru fail:
1423148Sigor@sysoev.ru 
1424148Sigor@sysoev.ru     nxt_socket_close(task, s);
1425148Sigor@sysoev.ru 
1426198Sigor@sysoev.ru     nxt_router_conf_error(task, rpc->temp_conf);
1427198Sigor@sysoev.ru }
1428198Sigor@sysoev.ru 
1429198Sigor@sysoev.ru 
1430198Sigor@sysoev.ru static void
1431198Sigor@sysoev.ru nxt_router_listen_socket_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
1432198Sigor@sysoev.ru     void *data)
1433198Sigor@sysoev.ru {
1434198Sigor@sysoev.ru     u_char                  *p;
1435198Sigor@sysoev.ru     size_t                  size;
1436198Sigor@sysoev.ru     uint8_t                 error;
1437198Sigor@sysoev.ru     nxt_buf_t               *in, *out;
1438198Sigor@sysoev.ru     nxt_sockaddr_t          *sa;
1439198Sigor@sysoev.ru     nxt_socket_rpc_t        *rpc;
1440198Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
1441198Sigor@sysoev.ru 
1442198Sigor@sysoev.ru     static nxt_str_t  socket_errors[] = {
1443198Sigor@sysoev.ru         nxt_string("ListenerSystem"),
1444198Sigor@sysoev.ru         nxt_string("ListenerNoIPv6"),
1445198Sigor@sysoev.ru         nxt_string("ListenerPort"),
1446198Sigor@sysoev.ru         nxt_string("ListenerInUse"),
1447198Sigor@sysoev.ru         nxt_string("ListenerNoAddress"),
1448198Sigor@sysoev.ru         nxt_string("ListenerNoAccess"),
1449198Sigor@sysoev.ru         nxt_string("ListenerPath"),
1450198Sigor@sysoev.ru     };
1451198Sigor@sysoev.ru 
1452198Sigor@sysoev.ru     rpc = data;
1453*359Sigor@sysoev.ru     sa = rpc->socket_conf->listen->sockaddr;
1454352Smax.romanov@nginx.com     tmcf = rpc->temp_conf;
1455352Smax.romanov@nginx.com 
1456352Smax.romanov@nginx.com     in = nxt_buf_chk_make_plain(tmcf->mem_pool, msg->buf, msg->size);
1457352Smax.romanov@nginx.com 
1458352Smax.romanov@nginx.com     nxt_assert(in != NULL);
1459352Smax.romanov@nginx.com 
1460198Sigor@sysoev.ru     p = in->mem.pos;
1461198Sigor@sysoev.ru 
1462198Sigor@sysoev.ru     error = *p++;
1463198Sigor@sysoev.ru 
1464198Sigor@sysoev.ru     size = sizeof("listen socket error: ") - 1
1465198Sigor@sysoev.ru            + sizeof("{listener: \"\", code:\"\", message: \"\"}") - 1
1466198Sigor@sysoev.ru            + sa->length + socket_errors[error].length + (in->mem.free - p);
1467198Sigor@sysoev.ru 
1468198Sigor@sysoev.ru     out = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0);
1469198Sigor@sysoev.ru     if (nxt_slow_path(out == NULL)) {
1470198Sigor@sysoev.ru         return;
1471198Sigor@sysoev.ru     }
1472198Sigor@sysoev.ru 
1473198Sigor@sysoev.ru     out->mem.free = nxt_sprintf(out->mem.free, out->mem.end,
1474198Sigor@sysoev.ru                         "listen socket error: "
1475198Sigor@sysoev.ru                         "{listener: \"%*s\", code:\"%V\", message: \"%*s\"}",
1476198Sigor@sysoev.ru                         sa->length, nxt_sockaddr_start(sa),
1477198Sigor@sysoev.ru                         &socket_errors[error], in->mem.free - p, p);
1478198Sigor@sysoev.ru 
1479198Sigor@sysoev.ru     nxt_debug(task, "%*s", out->mem.free - out->mem.pos, out->mem.pos);
1480198Sigor@sysoev.ru 
1481198Sigor@sysoev.ru     nxt_router_conf_error(task, tmcf);
148253Sigor@sysoev.ru }
148353Sigor@sysoev.ru 
148453Sigor@sysoev.ru 
148553Sigor@sysoev.ru static nxt_int_t
148653Sigor@sysoev.ru nxt_router_engines_create(nxt_task_t *task, nxt_router_t *router,
148753Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, const nxt_event_interface_t *interface)
148853Sigor@sysoev.ru {
148953Sigor@sysoev.ru     nxt_int_t                 ret;
149053Sigor@sysoev.ru     nxt_uint_t                n, threads;
149153Sigor@sysoev.ru     nxt_queue_link_t          *qlk;
149253Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
149353Sigor@sysoev.ru 
149453Sigor@sysoev.ru     threads = tmcf->conf->threads;
149553Sigor@sysoev.ru 
149653Sigor@sysoev.ru     tmcf->engines = nxt_array_create(tmcf->mem_pool, threads,
149753Sigor@sysoev.ru                                      sizeof(nxt_router_engine_conf_t));
149853Sigor@sysoev.ru     if (nxt_slow_path(tmcf->engines == NULL)) {
149953Sigor@sysoev.ru         return NXT_ERROR;
150053Sigor@sysoev.ru     }
150153Sigor@sysoev.ru 
150253Sigor@sysoev.ru     n = 0;
150353Sigor@sysoev.ru 
150453Sigor@sysoev.ru     for (qlk = nxt_queue_first(&router->engines);
150553Sigor@sysoev.ru          qlk != nxt_queue_tail(&router->engines);
150653Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
150753Sigor@sysoev.ru     {
150853Sigor@sysoev.ru         recf = nxt_array_zero_add(tmcf->engines);
150953Sigor@sysoev.ru         if (nxt_slow_path(recf == NULL)) {
151053Sigor@sysoev.ru             return NXT_ERROR;
151153Sigor@sysoev.ru         }
151253Sigor@sysoev.ru 
1513115Sigor@sysoev.ru         recf->engine = nxt_queue_link_data(qlk, nxt_event_engine_t, link0);
151453Sigor@sysoev.ru 
151553Sigor@sysoev.ru         if (n < threads) {
1516315Sigor@sysoev.ru             recf->action = NXT_ROUTER_ENGINE_KEEP;
1517115Sigor@sysoev.ru             ret = nxt_router_engine_conf_update(tmcf, recf);
151853Sigor@sysoev.ru 
151953Sigor@sysoev.ru         } else {
1520315Sigor@sysoev.ru             recf->action = NXT_ROUTER_ENGINE_DELETE;
1521115Sigor@sysoev.ru             ret = nxt_router_engine_conf_delete(tmcf, recf);
152253Sigor@sysoev.ru         }
152353Sigor@sysoev.ru 
152453Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
152553Sigor@sysoev.ru             return ret;
152653Sigor@sysoev.ru         }
152753Sigor@sysoev.ru 
152853Sigor@sysoev.ru         n++;
152953Sigor@sysoev.ru     }
153053Sigor@sysoev.ru 
153153Sigor@sysoev.ru     tmcf->new_threads = n;
153253Sigor@sysoev.ru 
153353Sigor@sysoev.ru     while (n < threads) {
153453Sigor@sysoev.ru         recf = nxt_array_zero_add(tmcf->engines);
153553Sigor@sysoev.ru         if (nxt_slow_path(recf == NULL)) {
153653Sigor@sysoev.ru             return NXT_ERROR;
153753Sigor@sysoev.ru         }
153853Sigor@sysoev.ru 
1539315Sigor@sysoev.ru         recf->action = NXT_ROUTER_ENGINE_ADD;
1540315Sigor@sysoev.ru 
154153Sigor@sysoev.ru         recf->engine = nxt_event_engine_create(task, interface, NULL, 0, 0);
154253Sigor@sysoev.ru         if (nxt_slow_path(recf->engine == NULL)) {
154353Sigor@sysoev.ru             return NXT_ERROR;
154453Sigor@sysoev.ru         }
154553Sigor@sysoev.ru 
1546115Sigor@sysoev.ru         ret = nxt_router_engine_conf_create(tmcf, recf);
154753Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
154853Sigor@sysoev.ru             return ret;
154953Sigor@sysoev.ru         }
155053Sigor@sysoev.ru 
155153Sigor@sysoev.ru         n++;
155253Sigor@sysoev.ru     }
155353Sigor@sysoev.ru 
155453Sigor@sysoev.ru     return NXT_OK;
155553Sigor@sysoev.ru }
155653Sigor@sysoev.ru 
155753Sigor@sysoev.ru 
155853Sigor@sysoev.ru static nxt_int_t
1559115Sigor@sysoev.ru nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf,
1560115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
156153Sigor@sysoev.ru {
1562*359Sigor@sysoev.ru     nxt_int_t  ret;
156353Sigor@sysoev.ru 
1564154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating,
1565154Sigor@sysoev.ru                                           nxt_router_listen_socket_create);
1566115Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1567115Sigor@sysoev.ru         return ret;
1568115Sigor@sysoev.ru     }
1569115Sigor@sysoev.ru 
1570154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating,
1571154Sigor@sysoev.ru                                           nxt_router_listen_socket_create);
157253Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
157353Sigor@sysoev.ru         return ret;
157453Sigor@sysoev.ru     }
157553Sigor@sysoev.ru 
1576115Sigor@sysoev.ru     return ret;
157753Sigor@sysoev.ru }
157853Sigor@sysoev.ru 
157953Sigor@sysoev.ru 
158053Sigor@sysoev.ru static nxt_int_t
1581115Sigor@sysoev.ru nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf,
1582115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
158353Sigor@sysoev.ru {
1584*359Sigor@sysoev.ru     nxt_int_t  ret;
158553Sigor@sysoev.ru 
1586154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating,
1587154Sigor@sysoev.ru                                           nxt_router_listen_socket_create);
158853Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
158953Sigor@sysoev.ru         return ret;
159053Sigor@sysoev.ru     }
159153Sigor@sysoev.ru 
1592154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating,
1593154Sigor@sysoev.ru                                           nxt_router_listen_socket_update);
159453Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
159553Sigor@sysoev.ru         return ret;
159653Sigor@sysoev.ru     }
159753Sigor@sysoev.ru 
1598139Sigor@sysoev.ru     ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting);
1599115Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1600115Sigor@sysoev.ru         return ret;
1601115Sigor@sysoev.ru     }
1602115Sigor@sysoev.ru 
1603115Sigor@sysoev.ru     return ret;
160453Sigor@sysoev.ru }
160553Sigor@sysoev.ru 
160653Sigor@sysoev.ru 
160753Sigor@sysoev.ru static nxt_int_t
1608115Sigor@sysoev.ru nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf,
1609115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
161053Sigor@sysoev.ru {
161153Sigor@sysoev.ru     nxt_int_t  ret;
161253Sigor@sysoev.ru 
1613313Sigor@sysoev.ru     ret = nxt_router_engine_quit(tmcf, recf);
1614313Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1615313Sigor@sysoev.ru         return ret;
1616313Sigor@sysoev.ru     }
1617313Sigor@sysoev.ru 
1618139Sigor@sysoev.ru     ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->updating);
161953Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
162053Sigor@sysoev.ru         return ret;
162153Sigor@sysoev.ru     }
162253Sigor@sysoev.ru 
1623139Sigor@sysoev.ru     return nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting);
162453Sigor@sysoev.ru }
162553Sigor@sysoev.ru 
162653Sigor@sysoev.ru 
162753Sigor@sysoev.ru static nxt_int_t
1628154Sigor@sysoev.ru nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf,
1629154Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets,
163053Sigor@sysoev.ru     nxt_work_handler_t handler)
163153Sigor@sysoev.ru {
1632153Sigor@sysoev.ru     nxt_joint_job_t          *job;
163353Sigor@sysoev.ru     nxt_queue_link_t         *qlk;
1634155Sigor@sysoev.ru     nxt_socket_conf_t        *skcf;
163553Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
163653Sigor@sysoev.ru 
163753Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
163853Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
163953Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
164053Sigor@sysoev.ru     {
1641154Sigor@sysoev.ru         job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t));
1642153Sigor@sysoev.ru         if (nxt_slow_path(job == NULL)) {
1643139Sigor@sysoev.ru             return NXT_ERROR;
1644139Sigor@sysoev.ru         }
1645139Sigor@sysoev.ru 
1646154Sigor@sysoev.ru         job->work.next = recf->jobs;
1647154Sigor@sysoev.ru         recf->jobs = &job->work;
1648154Sigor@sysoev.ru 
1649153Sigor@sysoev.ru         job->task = tmcf->engine->task;
1650153Sigor@sysoev.ru         job->work.handler = handler;
1651153Sigor@sysoev.ru         job->work.task = &job->task;
1652153Sigor@sysoev.ru         job->work.obj = job;
1653153Sigor@sysoev.ru         job->tmcf = tmcf;
165453Sigor@sysoev.ru 
1655154Sigor@sysoev.ru         tmcf->count++;
1656154Sigor@sysoev.ru 
1657154Sigor@sysoev.ru         joint = nxt_mp_alloc(tmcf->conf->mem_pool,
1658154Sigor@sysoev.ru                              sizeof(nxt_socket_conf_joint_t));
165953Sigor@sysoev.ru         if (nxt_slow_path(joint == NULL)) {
166053Sigor@sysoev.ru             return NXT_ERROR;
166153Sigor@sysoev.ru         }
166253Sigor@sysoev.ru 
1663153Sigor@sysoev.ru         job->work.data = joint;
166453Sigor@sysoev.ru 
166553Sigor@sysoev.ru         joint->count = 1;
1666155Sigor@sysoev.ru 
1667155Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
1668155Sigor@sysoev.ru         skcf->count++;
1669155Sigor@sysoev.ru         joint->socket_conf = skcf;
1670155Sigor@sysoev.ru 
167188Smax.romanov@nginx.com         joint->engine = recf->engine;
167253Sigor@sysoev.ru     }
167353Sigor@sysoev.ru 
167420Sigor@sysoev.ru     return NXT_OK;
167520Sigor@sysoev.ru }
167620Sigor@sysoev.ru 
167720Sigor@sysoev.ru 
167820Sigor@sysoev.ru static nxt_int_t
1679313Sigor@sysoev.ru nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf,
1680313Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
1681313Sigor@sysoev.ru {
1682313Sigor@sysoev.ru     nxt_joint_job_t  *job;
1683313Sigor@sysoev.ru 
1684313Sigor@sysoev.ru     job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t));
1685313Sigor@sysoev.ru     if (nxt_slow_path(job == NULL)) {
1686313Sigor@sysoev.ru         return NXT_ERROR;
1687313Sigor@sysoev.ru     }
1688313Sigor@sysoev.ru 
1689313Sigor@sysoev.ru     job->work.next = recf->jobs;
1690313Sigor@sysoev.ru     recf->jobs = &job->work;
1691313Sigor@sysoev.ru 
1692313Sigor@sysoev.ru     job->task = tmcf->engine->task;
1693313Sigor@sysoev.ru     job->work.handler = nxt_router_worker_thread_quit;
1694313Sigor@sysoev.ru     job->work.task = &job->task;
1695313Sigor@sysoev.ru     job->work.obj = NULL;
1696313Sigor@sysoev.ru     job->work.data = NULL;
1697313Sigor@sysoev.ru     job->tmcf = NULL;
1698313Sigor@sysoev.ru 
1699313Sigor@sysoev.ru     return NXT_OK;
1700313Sigor@sysoev.ru }
1701313Sigor@sysoev.ru 
1702313Sigor@sysoev.ru 
1703313Sigor@sysoev.ru static nxt_int_t
1704139Sigor@sysoev.ru nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf,
1705139Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets)
170620Sigor@sysoev.ru {
1707153Sigor@sysoev.ru     nxt_joint_job_t   *job;
170853Sigor@sysoev.ru     nxt_queue_link_t  *qlk;
170920Sigor@sysoev.ru 
171053Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
171153Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
171253Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
171353Sigor@sysoev.ru     {
1714154Sigor@sysoev.ru         job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t));
1715153Sigor@sysoev.ru         if (nxt_slow_path(job == NULL)) {
1716139Sigor@sysoev.ru             return NXT_ERROR;
1717139Sigor@sysoev.ru         }
1718139Sigor@sysoev.ru 
1719154Sigor@sysoev.ru         job->work.next = recf->jobs;
1720154Sigor@sysoev.ru         recf->jobs = &job->work;
1721154Sigor@sysoev.ru 
1722153Sigor@sysoev.ru         job->task = tmcf->engine->task;
1723153Sigor@sysoev.ru         job->work.handler = nxt_router_listen_socket_delete;
1724153Sigor@sysoev.ru         job->work.task = &job->task;
1725153Sigor@sysoev.ru         job->work.obj = job;
1726153Sigor@sysoev.ru         job->work.data = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
1727153Sigor@sysoev.ru         job->tmcf = tmcf;
1728154Sigor@sysoev.ru 
1729154Sigor@sysoev.ru         tmcf->count++;
173020Sigor@sysoev.ru     }
173120Sigor@sysoev.ru 
173253Sigor@sysoev.ru     return NXT_OK;
173353Sigor@sysoev.ru }
173420Sigor@sysoev.ru 
173520Sigor@sysoev.ru 
173653Sigor@sysoev.ru static nxt_int_t
173753Sigor@sysoev.ru nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt,
173853Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf)
173953Sigor@sysoev.ru {
174053Sigor@sysoev.ru     nxt_int_t                 ret;
174153Sigor@sysoev.ru     nxt_uint_t                i, threads;
174253Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
174320Sigor@sysoev.ru 
174453Sigor@sysoev.ru     recf = tmcf->engines->elts;
174553Sigor@sysoev.ru     threads = tmcf->conf->threads;
174620Sigor@sysoev.ru 
174753Sigor@sysoev.ru     for (i = tmcf->new_threads; i < threads; i++) {
174853Sigor@sysoev.ru         ret = nxt_router_thread_create(task, rt, recf[i].engine);
174953Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
175053Sigor@sysoev.ru             return ret;
175153Sigor@sysoev.ru         }
175220Sigor@sysoev.ru     }
175320Sigor@sysoev.ru 
175420Sigor@sysoev.ru     return NXT_OK;
175520Sigor@sysoev.ru }
175653Sigor@sysoev.ru 
175753Sigor@sysoev.ru 
175853Sigor@sysoev.ru static nxt_int_t
175953Sigor@sysoev.ru nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt,
176053Sigor@sysoev.ru     nxt_event_engine_t *engine)
176153Sigor@sysoev.ru {
176253Sigor@sysoev.ru     nxt_int_t            ret;
176353Sigor@sysoev.ru     nxt_thread_link_t    *link;
176453Sigor@sysoev.ru     nxt_thread_handle_t  handle;
176553Sigor@sysoev.ru 
176653Sigor@sysoev.ru     link = nxt_zalloc(sizeof(nxt_thread_link_t));
176753Sigor@sysoev.ru 
176853Sigor@sysoev.ru     if (nxt_slow_path(link == NULL)) {
176953Sigor@sysoev.ru         return NXT_ERROR;
177053Sigor@sysoev.ru     }
177153Sigor@sysoev.ru 
177253Sigor@sysoev.ru     link->start = nxt_router_thread_start;
177353Sigor@sysoev.ru     link->engine = engine;
177453Sigor@sysoev.ru     link->work.handler = nxt_router_thread_exit_handler;
177553Sigor@sysoev.ru     link->work.task = task;
177653Sigor@sysoev.ru     link->work.data = link;
177753Sigor@sysoev.ru 
177853Sigor@sysoev.ru     nxt_queue_insert_tail(&rt->engines, &engine->link);
177953Sigor@sysoev.ru 
178053Sigor@sysoev.ru     ret = nxt_thread_create(&handle, link);
178153Sigor@sysoev.ru 
178253Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
178353Sigor@sysoev.ru         nxt_queue_remove(&engine->link);
178453Sigor@sysoev.ru     }
178553Sigor@sysoev.ru 
178653Sigor@sysoev.ru     return ret;
178753Sigor@sysoev.ru }
178853Sigor@sysoev.ru 
178953Sigor@sysoev.ru 
179053Sigor@sysoev.ru static void
1791343Smax.romanov@nginx.com nxt_router_apps_sort(nxt_task_t *task, nxt_router_t *router,
1792343Smax.romanov@nginx.com     nxt_router_temp_conf_t *tmcf)
1793133Sigor@sysoev.ru {
1794343Smax.romanov@nginx.com     nxt_app_t   *app;
1795343Smax.romanov@nginx.com     nxt_port_t  *port;
1796141Smax.romanov@nginx.com 
1797141Smax.romanov@nginx.com     nxt_queue_each(app, &router->apps, nxt_app_t, link) {
1798133Sigor@sysoev.ru 
1799133Sigor@sysoev.ru         nxt_queue_remove(&app->link);
1800133Sigor@sysoev.ru 
1801343Smax.romanov@nginx.com         nxt_debug(task, "about to free app '%V' %p", &app->name, app);
1802167Smax.romanov@nginx.com 
1803163Smax.romanov@nginx.com         app->live = 0;
1804163Smax.romanov@nginx.com 
1805167Smax.romanov@nginx.com         do {
1806343Smax.romanov@nginx.com             port = nxt_router_app_get_idle_port(app);
1807167Smax.romanov@nginx.com             if (port == NULL) {
1808167Smax.romanov@nginx.com                 break;
1809167Smax.romanov@nginx.com             }
1810167Smax.romanov@nginx.com 
1811343Smax.romanov@nginx.com             nxt_debug(task, "port %p send quit", port);
1812343Smax.romanov@nginx.com 
1813343Smax.romanov@nginx.com             nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0,
1814343Smax.romanov@nginx.com                                   NULL);
1815343Smax.romanov@nginx.com 
1816343Smax.romanov@nginx.com             nxt_port_use(task, port, -1);
1817167Smax.romanov@nginx.com         } while (1);
1818167Smax.romanov@nginx.com 
1819343Smax.romanov@nginx.com         nxt_router_app_use(task, app, -1);
1820343Smax.romanov@nginx.com 
1821141Smax.romanov@nginx.com     } nxt_queue_loop;
1822133Sigor@sysoev.ru 
1823133Sigor@sysoev.ru     nxt_queue_add(&router->apps, &tmcf->previous);
1824133Sigor@sysoev.ru     nxt_queue_add(&router->apps, &tmcf->apps);
1825133Sigor@sysoev.ru }
1826133Sigor@sysoev.ru 
1827133Sigor@sysoev.ru 
1828133Sigor@sysoev.ru static void
1829315Sigor@sysoev.ru nxt_router_engines_post(nxt_router_t *router, nxt_router_temp_conf_t *tmcf)
183053Sigor@sysoev.ru {
183153Sigor@sysoev.ru     nxt_uint_t                n;
1832315Sigor@sysoev.ru     nxt_event_engine_t        *engine;
183353Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
183453Sigor@sysoev.ru 
183553Sigor@sysoev.ru     recf = tmcf->engines->elts;
183653Sigor@sysoev.ru 
183753Sigor@sysoev.ru     for (n = tmcf->engines->nelts; n != 0; n--) {
1838315Sigor@sysoev.ru         engine = recf->engine;
1839315Sigor@sysoev.ru 
1840315Sigor@sysoev.ru         switch (recf->action) {
1841315Sigor@sysoev.ru 
1842315Sigor@sysoev.ru         case NXT_ROUTER_ENGINE_KEEP:
1843315Sigor@sysoev.ru             break;
1844315Sigor@sysoev.ru 
1845315Sigor@sysoev.ru         case NXT_ROUTER_ENGINE_ADD:
1846315Sigor@sysoev.ru             nxt_queue_insert_tail(&router->engines, &engine->link0);
1847315Sigor@sysoev.ru             break;
1848315Sigor@sysoev.ru 
1849315Sigor@sysoev.ru         case NXT_ROUTER_ENGINE_DELETE:
1850315Sigor@sysoev.ru             nxt_queue_remove(&engine->link0);
1851315Sigor@sysoev.ru             break;
1852315Sigor@sysoev.ru         }
1853315Sigor@sysoev.ru 
1854316Sigor@sysoev.ru         nxt_router_engine_post(engine, recf->jobs);
1855316Sigor@sysoev.ru 
185653Sigor@sysoev.ru         recf++;
185753Sigor@sysoev.ru     }
185853Sigor@sysoev.ru }
185953Sigor@sysoev.ru 
186053Sigor@sysoev.ru 
186153Sigor@sysoev.ru static void
1862315Sigor@sysoev.ru nxt_router_engine_post(nxt_event_engine_t *engine, nxt_work_t *jobs)
186353Sigor@sysoev.ru {
1864154Sigor@sysoev.ru     nxt_work_t  *work, *next;
1865154Sigor@sysoev.ru 
1866315Sigor@sysoev.ru     for (work = jobs; work != NULL; work = next) {
1867154Sigor@sysoev.ru         next = work->next;
1868154Sigor@sysoev.ru         work->next = NULL;
1869154Sigor@sysoev.ru 
1870315Sigor@sysoev.ru         nxt_event_engine_post(engine, work);
187153Sigor@sysoev.ru     }
187253Sigor@sysoev.ru }
187353Sigor@sysoev.ru 
187453Sigor@sysoev.ru 
1875320Smax.romanov@nginx.com static nxt_port_handlers_t  nxt_router_app_port_handlers = {
1876320Smax.romanov@nginx.com     .mmap = nxt_port_mmap_handler,
1877320Smax.romanov@nginx.com     .data = nxt_port_rpc_handler,
187888Smax.romanov@nginx.com };
187988Smax.romanov@nginx.com 
188088Smax.romanov@nginx.com 
188188Smax.romanov@nginx.com static void
188253Sigor@sysoev.ru nxt_router_thread_start(void *data)
188353Sigor@sysoev.ru {
1884141Smax.romanov@nginx.com     nxt_int_t           ret;
1885141Smax.romanov@nginx.com     nxt_port_t          *port;
188688Smax.romanov@nginx.com     nxt_task_t          *task;
188753Sigor@sysoev.ru     nxt_thread_t        *thread;
188853Sigor@sysoev.ru     nxt_thread_link_t   *link;
188953Sigor@sysoev.ru     nxt_event_engine_t  *engine;
189053Sigor@sysoev.ru 
189153Sigor@sysoev.ru     link = data;
189253Sigor@sysoev.ru     engine = link->engine;
189388Smax.romanov@nginx.com     task = &engine->task;
189453Sigor@sysoev.ru 
189553Sigor@sysoev.ru     thread = nxt_thread();
189653Sigor@sysoev.ru 
1897165Smax.romanov@nginx.com     nxt_event_engine_thread_adopt(engine);
1898165Smax.romanov@nginx.com 
189953Sigor@sysoev.ru     /* STUB */
190053Sigor@sysoev.ru     thread->runtime = engine->task.thread->runtime;
190153Sigor@sysoev.ru 
190253Sigor@sysoev.ru     engine->task.thread = thread;
190353Sigor@sysoev.ru     engine->task.log = thread->log;
190453Sigor@sysoev.ru     thread->engine = engine;
190563Sigor@sysoev.ru     thread->task = &engine->task;
1906326Svbart@nginx.com #if 0
190753Sigor@sysoev.ru     thread->fiber = &engine->fibers->fiber;
1908326Svbart@nginx.com #endif
190953Sigor@sysoev.ru 
191063Sigor@sysoev.ru     engine->mem_pool = nxt_mp_create(4096, 128, 1024, 64);
1911337Sigor@sysoev.ru     if (nxt_slow_path(engine->mem_pool == NULL)) {
1912337Sigor@sysoev.ru         return;
1913337Sigor@sysoev.ru     }
191453Sigor@sysoev.ru 
1915197Smax.romanov@nginx.com     port = nxt_port_new(task, nxt_port_get_next_id(), nxt_pid,
1916197Smax.romanov@nginx.com                         NXT_PROCESS_ROUTER);
1917141Smax.romanov@nginx.com     if (nxt_slow_path(port == NULL)) {
1918141Smax.romanov@nginx.com         return;
1919141Smax.romanov@nginx.com     }
1920141Smax.romanov@nginx.com 
1921141Smax.romanov@nginx.com     ret = nxt_port_socket_init(task, port, 0);
1922141Smax.romanov@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
1923343Smax.romanov@nginx.com         nxt_port_use(task, port, -1);
1924141Smax.romanov@nginx.com         return;
1925141Smax.romanov@nginx.com     }
1926141Smax.romanov@nginx.com 
1927141Smax.romanov@nginx.com     engine->port = port;
1928141Smax.romanov@nginx.com 
1929320Smax.romanov@nginx.com     nxt_port_enable(task, port, &nxt_router_app_port_handlers);
1930141Smax.romanov@nginx.com 
193153Sigor@sysoev.ru     nxt_event_engine_start(engine);
193253Sigor@sysoev.ru }
193353Sigor@sysoev.ru 
193453Sigor@sysoev.ru 
193553Sigor@sysoev.ru static void
193653Sigor@sysoev.ru nxt_router_listen_socket_create(nxt_task_t *task, void *obj, void *data)
193753Sigor@sysoev.ru {
1938153Sigor@sysoev.ru     nxt_joint_job_t          *job;
1939*359Sigor@sysoev.ru     nxt_socket_conf_t        *skcf;
1940*359Sigor@sysoev.ru     nxt_listen_event_t       *lev;
194153Sigor@sysoev.ru     nxt_listen_socket_t      *ls;
1942*359Sigor@sysoev.ru     nxt_thread_spinlock_t    *lock;
194353Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
194453Sigor@sysoev.ru 
1945153Sigor@sysoev.ru     job = obj;
194653Sigor@sysoev.ru     joint = data;
194753Sigor@sysoev.ru 
1948159Sigor@sysoev.ru     nxt_queue_insert_tail(&task->thread->engine->joints, &joint->link);
1949159Sigor@sysoev.ru 
1950*359Sigor@sysoev.ru     skcf = joint->socket_conf;
1951*359Sigor@sysoev.ru     ls = skcf->listen;
1952*359Sigor@sysoev.ru 
1953*359Sigor@sysoev.ru     lev = nxt_listen_event(task, ls);
1954*359Sigor@sysoev.ru     if (nxt_slow_path(lev == NULL)) {
1955*359Sigor@sysoev.ru         nxt_router_listen_socket_release(task, skcf);
195653Sigor@sysoev.ru         return;
195753Sigor@sysoev.ru     }
195853Sigor@sysoev.ru 
1959*359Sigor@sysoev.ru     lev->socket.data = joint;
1960*359Sigor@sysoev.ru 
1961*359Sigor@sysoev.ru     lock = &skcf->router_conf->router->lock;
1962*359Sigor@sysoev.ru 
1963*359Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
1964*359Sigor@sysoev.ru     ls->count++;
1965*359Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
1966139Sigor@sysoev.ru 
1967153Sigor@sysoev.ru     job->work.next = NULL;
1968153Sigor@sysoev.ru     job->work.handler = nxt_router_conf_wait;
1969153Sigor@sysoev.ru 
1970153Sigor@sysoev.ru     nxt_event_engine_post(job->tmcf->engine, &job->work);
197153Sigor@sysoev.ru }
197253Sigor@sysoev.ru 
197353Sigor@sysoev.ru 
197453Sigor@sysoev.ru nxt_inline nxt_listen_event_t *
197553Sigor@sysoev.ru nxt_router_listen_event(nxt_queue_t *listen_connections,
197653Sigor@sysoev.ru     nxt_socket_conf_t *skcf)
197753Sigor@sysoev.ru {
1978115Sigor@sysoev.ru     nxt_socket_t        fd;
1979115Sigor@sysoev.ru     nxt_queue_link_t    *qlk;
1980*359Sigor@sysoev.ru     nxt_listen_event_t  *lev;
1981*359Sigor@sysoev.ru 
1982*359Sigor@sysoev.ru     fd = skcf->listen->socket;
198353Sigor@sysoev.ru 
1984115Sigor@sysoev.ru     for (qlk = nxt_queue_first(listen_connections);
1985115Sigor@sysoev.ru          qlk != nxt_queue_tail(listen_connections);
1986115Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
198753Sigor@sysoev.ru     {
1988*359Sigor@sysoev.ru         lev = nxt_queue_link_data(qlk, nxt_listen_event_t, link);
1989*359Sigor@sysoev.ru 
1990*359Sigor@sysoev.ru         if (fd == lev->socket.fd) {
1991*359Sigor@sysoev.ru             return lev;
199253Sigor@sysoev.ru         }
199353Sigor@sysoev.ru     }
199453Sigor@sysoev.ru 
199553Sigor@sysoev.ru     return NULL;
199653Sigor@sysoev.ru }
199753Sigor@sysoev.ru 
199853Sigor@sysoev.ru 
199953Sigor@sysoev.ru static void
200053Sigor@sysoev.ru nxt_router_listen_socket_update(nxt_task_t *task, void *obj, void *data)
200153Sigor@sysoev.ru {
2002153Sigor@sysoev.ru     nxt_joint_job_t          *job;
200353Sigor@sysoev.ru     nxt_event_engine_t       *engine;
2004*359Sigor@sysoev.ru     nxt_listen_event_t       *lev;
200553Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint, *old;
200653Sigor@sysoev.ru 
2007153Sigor@sysoev.ru     job = obj;
200853Sigor@sysoev.ru     joint = data;
200953Sigor@sysoev.ru 
2010139Sigor@sysoev.ru     engine = task->thread->engine;
2011139Sigor@sysoev.ru 
2012159Sigor@sysoev.ru     nxt_queue_insert_tail(&engine->joints, &joint->link);
2013159Sigor@sysoev.ru 
2014*359Sigor@sysoev.ru     lev = nxt_router_listen_event(&engine->listen_connections,
2015*359Sigor@sysoev.ru                                   joint->socket_conf);
2016*359Sigor@sysoev.ru 
2017*359Sigor@sysoev.ru     old = lev->socket.data;
2018*359Sigor@sysoev.ru     lev->socket.data = joint;
2019*359Sigor@sysoev.ru     lev->listen = joint->socket_conf->listen;
202053Sigor@sysoev.ru 
2021153Sigor@sysoev.ru     job->work.next = NULL;
2022153Sigor@sysoev.ru     job->work.handler = nxt_router_conf_wait;
2023153Sigor@sysoev.ru 
2024153Sigor@sysoev.ru     nxt_event_engine_post(job->tmcf->engine, &job->work);
2025139Sigor@sysoev.ru 
2026181Smax.romanov@nginx.com     /*
2027181Smax.romanov@nginx.com      * The task is allocated from configuration temporary
2028181Smax.romanov@nginx.com      * memory pool so it can be freed after engine post operation.
2029181Smax.romanov@nginx.com      */
2030181Smax.romanov@nginx.com 
2031181Smax.romanov@nginx.com     nxt_router_conf_release(&engine->task, old);
203253Sigor@sysoev.ru }
203353Sigor@sysoev.ru 
203453Sigor@sysoev.ru 
203553Sigor@sysoev.ru static void
203653Sigor@sysoev.ru nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, void *data)
203753Sigor@sysoev.ru {
2038153Sigor@sysoev.ru     nxt_joint_job_t     *job;
2039153Sigor@sysoev.ru     nxt_socket_conf_t   *skcf;
2040*359Sigor@sysoev.ru     nxt_listen_event_t  *lev;
2041153Sigor@sysoev.ru     nxt_event_engine_t  *engine;
2042153Sigor@sysoev.ru 
2043153Sigor@sysoev.ru     job = obj;
204453Sigor@sysoev.ru     skcf = data;
204553Sigor@sysoev.ru 
2046139Sigor@sysoev.ru     engine = task->thread->engine;
2047139Sigor@sysoev.ru 
2048*359Sigor@sysoev.ru     lev = nxt_router_listen_event(&engine->listen_connections, skcf);
2049*359Sigor@sysoev.ru 
2050*359Sigor@sysoev.ru     nxt_fd_event_delete(engine, &lev->socket);
205153Sigor@sysoev.ru 
2052163Smax.romanov@nginx.com     nxt_debug(task, "engine %p: listen socket delete: %d", engine,
2053*359Sigor@sysoev.ru               lev->socket.fd);
2054*359Sigor@sysoev.ru 
2055*359Sigor@sysoev.ru     lev->timer.handler = nxt_router_listen_socket_close;
2056*359Sigor@sysoev.ru     lev->timer.work_queue = &engine->fast_work_queue;
2057*359Sigor@sysoev.ru 
2058*359Sigor@sysoev.ru     nxt_timer_add(engine, &lev->timer, 0);
2059139Sigor@sysoev.ru 
2060153Sigor@sysoev.ru     job->work.next = NULL;
2061153Sigor@sysoev.ru     job->work.handler = nxt_router_conf_wait;
2062153Sigor@sysoev.ru 
2063153Sigor@sysoev.ru     nxt_event_engine_post(job->tmcf->engine, &job->work);
206453Sigor@sysoev.ru }
206553Sigor@sysoev.ru 
206653Sigor@sysoev.ru 
206753Sigor@sysoev.ru static void
2068313Sigor@sysoev.ru nxt_router_worker_thread_quit(nxt_task_t *task, void *obj, void *data)
2069313Sigor@sysoev.ru {
2070313Sigor@sysoev.ru     nxt_event_engine_t  *engine;
2071313Sigor@sysoev.ru 
2072313Sigor@sysoev.ru     nxt_debug(task, "router worker thread quit");
2073313Sigor@sysoev.ru 
2074313Sigor@sysoev.ru     engine = task->thread->engine;
2075313Sigor@sysoev.ru 
2076313Sigor@sysoev.ru     engine->shutdown = 1;
2077313Sigor@sysoev.ru 
2078313Sigor@sysoev.ru     if (nxt_queue_is_empty(&engine->joints)) {
2079313Sigor@sysoev.ru         nxt_thread_exit(task->thread);
2080313Sigor@sysoev.ru     }
2081313Sigor@sysoev.ru }
2082313Sigor@sysoev.ru 
2083313Sigor@sysoev.ru 
2084313Sigor@sysoev.ru static void
208553Sigor@sysoev.ru nxt_router_listen_socket_close(nxt_task_t *task, void *obj, void *data)
208653Sigor@sysoev.ru {
208753Sigor@sysoev.ru     nxt_timer_t              *timer;
2088*359Sigor@sysoev.ru     nxt_listen_event_t       *lev;
208953Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
209053Sigor@sysoev.ru 
209153Sigor@sysoev.ru     timer = obj;
2092*359Sigor@sysoev.ru     lev = nxt_timer_data(timer, nxt_listen_event_t, timer);
2093*359Sigor@sysoev.ru     joint = lev->socket.data;
209453Sigor@sysoev.ru 
2095163Smax.romanov@nginx.com     nxt_debug(task, "engine %p: listen socket close: %d", task->thread->engine,
2096*359Sigor@sysoev.ru               lev->socket.fd);
2097*359Sigor@sysoev.ru 
2098*359Sigor@sysoev.ru     nxt_queue_remove(&lev->link);
2099*359Sigor@sysoev.ru 
2100*359Sigor@sysoev.ru     /* 'task' refers to lev->task and we cannot use after nxt_free() */
2101123Smax.romanov@nginx.com     task = &task->thread->engine->task;
2102123Smax.romanov@nginx.com 
2103*359Sigor@sysoev.ru     nxt_router_listen_socket_release(task, joint->socket_conf);
2104*359Sigor@sysoev.ru 
2105*359Sigor@sysoev.ru     nxt_free(lev);
2106*359Sigor@sysoev.ru 
2107*359Sigor@sysoev.ru     nxt_router_conf_release(task, joint);
210853Sigor@sysoev.ru }
210953Sigor@sysoev.ru 
211053Sigor@sysoev.ru 
211153Sigor@sysoev.ru static void
2112*359Sigor@sysoev.ru nxt_router_listen_socket_release(nxt_task_t *task, nxt_socket_conf_t *skcf)
211353Sigor@sysoev.ru {
2114*359Sigor@sysoev.ru     nxt_listen_socket_t    *ls;
211553Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
211653Sigor@sysoev.ru 
2117*359Sigor@sysoev.ru     ls = skcf->listen;
2118118Sigor@sysoev.ru     lock = &skcf->router_conf->router->lock;
211953Sigor@sysoev.ru 
212053Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
212153Sigor@sysoev.ru 
2122*359Sigor@sysoev.ru     nxt_debug(task, "engine %p: listen socket release: ls->count %D",
2123*359Sigor@sysoev.ru               task->thread->engine, ls->count);
2124*359Sigor@sysoev.ru 
2125*359Sigor@sysoev.ru     if (--ls->count != 0) {
2126*359Sigor@sysoev.ru         ls = NULL;
212753Sigor@sysoev.ru     }
212853Sigor@sysoev.ru 
212953Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
213053Sigor@sysoev.ru 
2131*359Sigor@sysoev.ru     if (ls != NULL) {
2132*359Sigor@sysoev.ru         nxt_socket_close(task, ls->socket);
2133*359Sigor@sysoev.ru         nxt_free(ls);
213453Sigor@sysoev.ru     }
213553Sigor@sysoev.ru }
213653Sigor@sysoev.ru 
213753Sigor@sysoev.ru 
213853Sigor@sysoev.ru static void
213953Sigor@sysoev.ru nxt_router_conf_release(nxt_task_t *task, nxt_socket_conf_joint_t *joint)
214053Sigor@sysoev.ru {
2141156Sigor@sysoev.ru     nxt_bool_t             exit;
214253Sigor@sysoev.ru     nxt_socket_conf_t      *skcf;
214353Sigor@sysoev.ru     nxt_router_conf_t      *rtcf;
2144313Sigor@sysoev.ru     nxt_event_engine_t     *engine;
214553Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
214653Sigor@sysoev.ru 
2147163Smax.romanov@nginx.com     nxt_debug(task, "conf joint %p count: %D", joint, joint->count);
214853Sigor@sysoev.ru 
214953Sigor@sysoev.ru     if (--joint->count != 0) {
215053Sigor@sysoev.ru         return;
215153Sigor@sysoev.ru     }
215253Sigor@sysoev.ru 
215353Sigor@sysoev.ru     nxt_queue_remove(&joint->link);
215453Sigor@sysoev.ru 
215553Sigor@sysoev.ru     skcf = joint->socket_conf;
215653Sigor@sysoev.ru     rtcf = skcf->router_conf;
215753Sigor@sysoev.ru     lock = &rtcf->router->lock;
215853Sigor@sysoev.ru 
215953Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
216053Sigor@sysoev.ru 
2161163Smax.romanov@nginx.com     nxt_debug(task, "conf skcf %p: %D, rtcf %p: %D", skcf, skcf->count,
2162163Smax.romanov@nginx.com               rtcf, rtcf->count);
2163163Smax.romanov@nginx.com 
216453Sigor@sysoev.ru     if (--skcf->count != 0) {
216553Sigor@sysoev.ru         rtcf = NULL;
216653Sigor@sysoev.ru 
216753Sigor@sysoev.ru     } else {
216853Sigor@sysoev.ru         nxt_queue_remove(&skcf->link);
216953Sigor@sysoev.ru 
217053Sigor@sysoev.ru         if (--rtcf->count != 0) {
217153Sigor@sysoev.ru             rtcf = NULL;
217253Sigor@sysoev.ru         }
217353Sigor@sysoev.ru     }
217453Sigor@sysoev.ru 
217553Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
217653Sigor@sysoev.ru 
2177141Smax.romanov@nginx.com     /* TODO remove engine->port */
2178141Smax.romanov@nginx.com     /* TODO excude from connected ports */
2179141Smax.romanov@nginx.com 
2180156Sigor@sysoev.ru     /* The joint content can be used before memory pool destruction. */
2181313Sigor@sysoev.ru     engine = joint->engine;
2182313Sigor@sysoev.ru     exit = (engine->shutdown && nxt_queue_is_empty(&engine->joints));
2183156Sigor@sysoev.ru 
218453Sigor@sysoev.ru     if (rtcf != NULL) {
2185115Sigor@sysoev.ru         nxt_debug(task, "old router conf is destroyed");
2186131Smax.romanov@nginx.com 
2187131Smax.romanov@nginx.com         nxt_mp_thread_adopt(rtcf->mem_pool);
2188131Smax.romanov@nginx.com 
218965Sigor@sysoev.ru         nxt_mp_destroy(rtcf->mem_pool);
219053Sigor@sysoev.ru     }
219153Sigor@sysoev.ru 
2192156Sigor@sysoev.ru     if (exit) {
219353Sigor@sysoev.ru         nxt_thread_exit(task->thread);
219453Sigor@sysoev.ru     }
219553Sigor@sysoev.ru }
219653Sigor@sysoev.ru 
219753Sigor@sysoev.ru 
219853Sigor@sysoev.ru static void
219953Sigor@sysoev.ru nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, void *data)
220053Sigor@sysoev.ru {
2201141Smax.romanov@nginx.com     nxt_port_t           *port;
220253Sigor@sysoev.ru     nxt_thread_link_t    *link;
220353Sigor@sysoev.ru     nxt_event_engine_t   *engine;
220453Sigor@sysoev.ru     nxt_thread_handle_t  handle;
220553Sigor@sysoev.ru 
220658Svbart@nginx.com     handle = (nxt_thread_handle_t) obj;
220753Sigor@sysoev.ru     link = data;
220853Sigor@sysoev.ru 
220953Sigor@sysoev.ru     nxt_thread_wait(handle);
221053Sigor@sysoev.ru 
221153Sigor@sysoev.ru     engine = link->engine;
221253Sigor@sysoev.ru 
221353Sigor@sysoev.ru     nxt_queue_remove(&engine->link);
221453Sigor@sysoev.ru 
2215141Smax.romanov@nginx.com     port = engine->port;
2216141Smax.romanov@nginx.com 
2217141Smax.romanov@nginx.com     // TODO notify all apps
2218141Smax.romanov@nginx.com 
2219343Smax.romanov@nginx.com     port->engine = task->thread->engine;
2220163Smax.romanov@nginx.com     nxt_mp_thread_adopt(port->mem_pool);
2221343Smax.romanov@nginx.com     nxt_port_use(task, port, -1);
2222163Smax.romanov@nginx.com 
2223163Smax.romanov@nginx.com     nxt_mp_thread_adopt(engine->mem_pool);
222463Sigor@sysoev.ru     nxt_mp_destroy(engine->mem_pool);
222553Sigor@sysoev.ru 
222653Sigor@sysoev.ru     nxt_event_engine_free(engine);
222753Sigor@sysoev.ru 
222853Sigor@sysoev.ru     nxt_free(link);
222953Sigor@sysoev.ru }
223053Sigor@sysoev.ru 
223153Sigor@sysoev.ru 
2232206Smax.romanov@nginx.com static const nxt_conn_state_t  nxt_router_conn_read_header_state
223353Sigor@sysoev.ru     nxt_aligned(64) =
223453Sigor@sysoev.ru {
223553Sigor@sysoev.ru     .ready_handler = nxt_router_conn_http_header_parse,
223653Sigor@sysoev.ru     .close_handler = nxt_router_conn_close,
223753Sigor@sysoev.ru     .error_handler = nxt_router_conn_error,
223853Sigor@sysoev.ru 
223953Sigor@sysoev.ru     .timer_handler = nxt_router_conn_timeout,
224053Sigor@sysoev.ru     .timer_value = nxt_router_conn_timeout_value,
224153Sigor@sysoev.ru     .timer_data = offsetof(nxt_socket_conf_t, header_read_timeout),
224253Sigor@sysoev.ru };
224353Sigor@sysoev.ru 
224453Sigor@sysoev.ru 
2245206Smax.romanov@nginx.com static const nxt_conn_state_t  nxt_router_conn_read_body_state
2246206Smax.romanov@nginx.com     nxt_aligned(64) =
2247206Smax.romanov@nginx.com {
2248206Smax.romanov@nginx.com     .ready_handler = nxt_router_conn_http_body_read,
2249206Smax.romanov@nginx.com     .close_handler = nxt_router_conn_close,
2250206Smax.romanov@nginx.com     .error_handler = nxt_router_conn_error,
2251206Smax.romanov@nginx.com 
2252206Smax.romanov@nginx.com     .timer_handler = nxt_router_conn_timeout,
2253206Smax.romanov@nginx.com     .timer_value = nxt_router_conn_timeout_value,
2254206Smax.romanov@nginx.com     .timer_data = offsetof(nxt_socket_conf_t, body_read_timeout),
2255206Smax.romanov@nginx.com     .timer_autoreset = 1,
2256206Smax.romanov@nginx.com };
2257206Smax.romanov@nginx.com 
2258206Smax.romanov@nginx.com 
225953Sigor@sysoev.ru static void
226053Sigor@sysoev.ru nxt_router_conn_init(nxt_task_t *task, void *obj, void *data)
226153Sigor@sysoev.ru {
226253Sigor@sysoev.ru     size_t                   size;
226362Sigor@sysoev.ru     nxt_conn_t               *c;
2264*359Sigor@sysoev.ru     nxt_socket_conf_t        *skcf;
226553Sigor@sysoev.ru     nxt_event_engine_t       *engine;
226653Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
226753Sigor@sysoev.ru 
226853Sigor@sysoev.ru     c = obj;
226953Sigor@sysoev.ru     joint = data;
227053Sigor@sysoev.ru 
227153Sigor@sysoev.ru     nxt_debug(task, "router conn init");
227253Sigor@sysoev.ru 
2273*359Sigor@sysoev.ru     c->joint = joint;
227453Sigor@sysoev.ru     joint->count++;
227553Sigor@sysoev.ru 
2276*359Sigor@sysoev.ru     skcf = joint->socket_conf;
2277*359Sigor@sysoev.ru     c->local = skcf->sockaddr;
2278*359Sigor@sysoev.ru 
2279*359Sigor@sysoev.ru     size = skcf->header_buffer_size;
228053Sigor@sysoev.ru     c->read = nxt_buf_mem_alloc(c->mem_pool, size, 0);
228153Sigor@sysoev.ru 
228253Sigor@sysoev.ru     c->socket.data = NULL;
228353Sigor@sysoev.ru 
228453Sigor@sysoev.ru     engine = task->thread->engine;
228553Sigor@sysoev.ru     c->read_work_queue = &engine->fast_work_queue;
228653Sigor@sysoev.ru     c->write_work_queue = &engine->fast_work_queue;
228753Sigor@sysoev.ru 
2288206Smax.romanov@nginx.com     c->read_state = &nxt_router_conn_read_header_state;
228953Sigor@sysoev.ru 
229062Sigor@sysoev.ru     nxt_conn_read(engine, c);
229153Sigor@sysoev.ru }
229253Sigor@sysoev.ru 
229353Sigor@sysoev.ru 
229462Sigor@sysoev.ru static const nxt_conn_state_t  nxt_router_conn_write_state
229553Sigor@sysoev.ru     nxt_aligned(64) =
229653Sigor@sysoev.ru {
229788Smax.romanov@nginx.com     .ready_handler = nxt_router_conn_ready,
229853Sigor@sysoev.ru     .close_handler = nxt_router_conn_close,
229953Sigor@sysoev.ru     .error_handler = nxt_router_conn_error,
230053Sigor@sysoev.ru };
230153Sigor@sysoev.ru 
230253Sigor@sysoev.ru 
230353Sigor@sysoev.ru static void
2304318Smax.romanov@nginx.com nxt_router_response_ready_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2305318Smax.romanov@nginx.com     void *data)
230688Smax.romanov@nginx.com {
230788Smax.romanov@nginx.com     size_t               dump_size;
2308194Smax.romanov@nginx.com     nxt_buf_t            *b, *last;
230988Smax.romanov@nginx.com     nxt_conn_t           *c;
231088Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
231188Smax.romanov@nginx.com 
231288Smax.romanov@nginx.com     b = msg->buf;
2313318Smax.romanov@nginx.com     rc = data;
231488Smax.romanov@nginx.com 
231588Smax.romanov@nginx.com     c = rc->conn;
231688Smax.romanov@nginx.com 
231788Smax.romanov@nginx.com     dump_size = nxt_buf_used_size(b);
231888Smax.romanov@nginx.com 
231988Smax.romanov@nginx.com     if (dump_size > 300) {
232088Smax.romanov@nginx.com         dump_size = 300;
232188Smax.romanov@nginx.com     }
232288Smax.romanov@nginx.com 
2323119Smax.romanov@nginx.com     nxt_debug(task, "%srouter app data (%z): %*s",
232488Smax.romanov@nginx.com               msg->port_msg.last ? "last " : "", msg->size, dump_size,
232588Smax.romanov@nginx.com               b->mem.pos);
232688Smax.romanov@nginx.com 
232788Smax.romanov@nginx.com     if (msg->size == 0) {
232888Smax.romanov@nginx.com         b = NULL;
232988Smax.romanov@nginx.com     }
233088Smax.romanov@nginx.com 
233188Smax.romanov@nginx.com     if (msg->port_msg.last != 0) {
233288Smax.romanov@nginx.com         nxt_debug(task, "router data create last buf");
233388Smax.romanov@nginx.com 
233488Smax.romanov@nginx.com         last = nxt_buf_sync_alloc(c->mem_pool, NXT_BUF_SYNC_LAST);
233588Smax.romanov@nginx.com         if (nxt_slow_path(last == NULL)) {
233688Smax.romanov@nginx.com             /* TODO pogorevaTb */
233788Smax.romanov@nginx.com         }
233888Smax.romanov@nginx.com 
233988Smax.romanov@nginx.com         nxt_buf_chain_add(&b, last);
2340167Smax.romanov@nginx.com 
2341343Smax.romanov@nginx.com         nxt_router_rc_unlink(task, rc);
234288Smax.romanov@nginx.com     }
234388Smax.romanov@nginx.com 
234488Smax.romanov@nginx.com     if (b == NULL) {
234588Smax.romanov@nginx.com         return;
234688Smax.romanov@nginx.com     }
234788Smax.romanov@nginx.com 
2348206Smax.romanov@nginx.com     if (msg->buf == b) {
2349206Smax.romanov@nginx.com         /* Disable instant buffer completion/re-using by port. */
2350206Smax.romanov@nginx.com         msg->buf = NULL;
2351206Smax.romanov@nginx.com     }
2352194Smax.romanov@nginx.com 
235388Smax.romanov@nginx.com     if (c->write == NULL) {
235488Smax.romanov@nginx.com         c->write = b;
235588Smax.romanov@nginx.com         c->write_state = &nxt_router_conn_write_state;
235688Smax.romanov@nginx.com 
235788Smax.romanov@nginx.com         nxt_conn_write(task->thread->engine, c);
2358277Sigor@sysoev.ru 
235988Smax.romanov@nginx.com     } else {
236088Smax.romanov@nginx.com         nxt_debug(task, "router data attach out bufs to existing chain");
236188Smax.romanov@nginx.com 
236288Smax.romanov@nginx.com         nxt_buf_chain_add(&c->write, b);
236388Smax.romanov@nginx.com     }
236488Smax.romanov@nginx.com }
236588Smax.romanov@nginx.com 
2366277Sigor@sysoev.ru 
2367318Smax.romanov@nginx.com static void
2368318Smax.romanov@nginx.com nxt_router_response_error_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2369318Smax.romanov@nginx.com     void *data)
2370318Smax.romanov@nginx.com {
2371318Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
2372318Smax.romanov@nginx.com 
2373318Smax.romanov@nginx.com     rc = data;
2374318Smax.romanov@nginx.com 
2375318Smax.romanov@nginx.com     nxt_router_gen_error(task, rc->conn, 500,
2376318Smax.romanov@nginx.com                          "Application terminated unexpectedly");
2377318Smax.romanov@nginx.com 
2378343Smax.romanov@nginx.com     nxt_router_rc_unlink(task, rc);
2379318Smax.romanov@nginx.com }
2380318Smax.romanov@nginx.com 
2381318Smax.romanov@nginx.com 
2382141Smax.romanov@nginx.com nxt_inline const char *
2383141Smax.romanov@nginx.com nxt_router_text_by_code(int code)
2384141Smax.romanov@nginx.com {
2385141Smax.romanov@nginx.com     switch (code) {
2386141Smax.romanov@nginx.com     case 400: return "Bad request";
2387141Smax.romanov@nginx.com     case 404: return "Not found";
2388141Smax.romanov@nginx.com     case 403: return "Forbidden";
2389206Smax.romanov@nginx.com     case 408: return "Request Timeout";
2390206Smax.romanov@nginx.com     case 411: return "Length Required";
2391206Smax.romanov@nginx.com     case 413: return "Request Entity Too Large";
2392141Smax.romanov@nginx.com     case 500:
2393141Smax.romanov@nginx.com     default:  return "Internal server error";
2394141Smax.romanov@nginx.com     }
2395141Smax.romanov@nginx.com }
2396141Smax.romanov@nginx.com 
2397163Smax.romanov@nginx.com 
2398163Smax.romanov@nginx.com static nxt_buf_t *
2399163Smax.romanov@nginx.com nxt_router_get_error_buf(nxt_task_t *task, nxt_mp_t *mp, int code,
2400345Smax.romanov@nginx.com     const char* str)
240188Smax.romanov@nginx.com {
2402345Smax.romanov@nginx.com     nxt_buf_t  *b, *last;
2403345Smax.romanov@nginx.com 
2404345Smax.romanov@nginx.com     b = nxt_buf_mem_alloc(mp, 16384, 0);
2405141Smax.romanov@nginx.com     if (nxt_slow_path(b == NULL)) {
2406163Smax.romanov@nginx.com         return NULL;
2407141Smax.romanov@nginx.com     }
2408141Smax.romanov@nginx.com 
2409141Smax.romanov@nginx.com     b->mem.free = nxt_sprintf(b->mem.free, b->mem.end,
2410141Smax.romanov@nginx.com         "HTTP/1.0 %d %s\r\n"
2411141Smax.romanov@nginx.com         "Content-Type: text/plain\r\n"
2412141Smax.romanov@nginx.com         "Connection: close\r\n\r\n",
2413141Smax.romanov@nginx.com         code, nxt_router_text_by_code(code));
2414141Smax.romanov@nginx.com 
2415345Smax.romanov@nginx.com     b->mem.free = nxt_cpymem(b->mem.free, str, nxt_strlen(str));
2416345Smax.romanov@nginx.com 
2417345Smax.romanov@nginx.com     nxt_log_alert(task->log, "error %d: %s", code, str);
2418345Smax.romanov@nginx.com 
2419345Smax.romanov@nginx.com     last = nxt_buf_sync_alloc(mp, NXT_BUF_SYNC_LAST);
2420163Smax.romanov@nginx.com 
2421141Smax.romanov@nginx.com     if (nxt_slow_path(last == NULL)) {
2422345Smax.romanov@nginx.com         nxt_mp_free(mp, b);
2423163Smax.romanov@nginx.com         return NULL;
2424141Smax.romanov@nginx.com     }
2425141Smax.romanov@nginx.com 
2426141Smax.romanov@nginx.com     nxt_buf_chain_add(&b, last);
2427141Smax.romanov@nginx.com 
2428163Smax.romanov@nginx.com     return b;
2429163Smax.romanov@nginx.com }
2430163Smax.romanov@nginx.com 
2431163Smax.romanov@nginx.com 
2432163Smax.romanov@nginx.com 
2433163Smax.romanov@nginx.com static void
2434163Smax.romanov@nginx.com nxt_router_gen_error(nxt_task_t *task, nxt_conn_t *c, int code,
2435345Smax.romanov@nginx.com     const char* str)
2436163Smax.romanov@nginx.com {
2437318Smax.romanov@nginx.com     nxt_mp_t   *mp;
2438163Smax.romanov@nginx.com     nxt_buf_t  *b;
2439163Smax.romanov@nginx.com 
2440318Smax.romanov@nginx.com     /* TODO: fix when called in the middle of response */
2441318Smax.romanov@nginx.com 
2442345Smax.romanov@nginx.com     mp = c->mem_pool;
2443345Smax.romanov@nginx.com 
2444345Smax.romanov@nginx.com     b = nxt_router_get_error_buf(task, mp, code, str);
2445163Smax.romanov@nginx.com 
2446273Smax.romanov@nginx.com     if (c->socket.fd == -1) {
2447345Smax.romanov@nginx.com         nxt_mp_free(mp, b->next);
2448345Smax.romanov@nginx.com         nxt_mp_free(mp, b);
2449273Smax.romanov@nginx.com         return;
2450273Smax.romanov@nginx.com     }
2451273Smax.romanov@nginx.com 
2452141Smax.romanov@nginx.com     if (c->write == NULL) {
2453141Smax.romanov@nginx.com         c->write = b;
2454141Smax.romanov@nginx.com         c->write_state = &nxt_router_conn_write_state;
2455141Smax.romanov@nginx.com 
2456141Smax.romanov@nginx.com         nxt_conn_write(task->thread->engine, c);
2457277Sigor@sysoev.ru 
2458141Smax.romanov@nginx.com     } else {
2459141Smax.romanov@nginx.com         nxt_debug(task, "router data attach out bufs to existing chain");
2460141Smax.romanov@nginx.com 
2461141Smax.romanov@nginx.com         nxt_buf_chain_add(&c->write, b);
2462141Smax.romanov@nginx.com     }
2463141Smax.romanov@nginx.com }
2464141Smax.romanov@nginx.com 
2465141Smax.romanov@nginx.com 
2466141Smax.romanov@nginx.com static void
2467343Smax.romanov@nginx.com nxt_router_app_port_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2468343Smax.romanov@nginx.com     void *data)
2469192Smax.romanov@nginx.com {
2470343Smax.romanov@nginx.com     nxt_app_t   *app;
2471343Smax.romanov@nginx.com     nxt_port_t  *port;
2472343Smax.romanov@nginx.com 
2473343Smax.romanov@nginx.com     app = data;
2474347Smax.romanov@nginx.com     port = msg->u.new_port;
2475343Smax.romanov@nginx.com 
2476343Smax.romanov@nginx.com     nxt_assert(app != NULL);
2477343Smax.romanov@nginx.com     nxt_assert(port != NULL);
2478343Smax.romanov@nginx.com 
2479343Smax.romanov@nginx.com     port->app = app;
2480343Smax.romanov@nginx.com 
2481343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
2482343Smax.romanov@nginx.com 
2483343Smax.romanov@nginx.com     nxt_assert(app->pending_workers != 0);
2484343Smax.romanov@nginx.com 
2485343Smax.romanov@nginx.com     app->pending_workers--;
2486343Smax.romanov@nginx.com     app->workers++;
2487343Smax.romanov@nginx.com 
2488343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
2489343Smax.romanov@nginx.com 
2490343Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p new port ready", &app->name, app);
2491343Smax.romanov@nginx.com 
2492343Smax.romanov@nginx.com     nxt_router_app_port_release(task, port, 0, 0);
2493192Smax.romanov@nginx.com }
2494192Smax.romanov@nginx.com 
2495192Smax.romanov@nginx.com 
2496192Smax.romanov@nginx.com static void
2497343Smax.romanov@nginx.com nxt_router_app_port_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2498343Smax.romanov@nginx.com     void *data)
2499192Smax.romanov@nginx.com {
2500318Smax.romanov@nginx.com     nxt_app_t           *app;
2501318Smax.romanov@nginx.com     nxt_queue_link_t    *lnk;
2502318Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
2503343Smax.romanov@nginx.com 
2504343Smax.romanov@nginx.com     app = data;
2505343Smax.romanov@nginx.com 
2506343Smax.romanov@nginx.com     nxt_assert(app != NULL);
2507343Smax.romanov@nginx.com 
2508343Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p start error", &app->name, app);
2509343Smax.romanov@nginx.com 
2510343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
2511343Smax.romanov@nginx.com 
2512343Smax.romanov@nginx.com     nxt_assert(app->pending_workers != 0);
2513343Smax.romanov@nginx.com 
2514343Smax.romanov@nginx.com     app->pending_workers--;
2515318Smax.romanov@nginx.com 
2516318Smax.romanov@nginx.com     if (!nxt_queue_is_empty(&app->requests)) {
2517318Smax.romanov@nginx.com         lnk = nxt_queue_last(&app->requests);
2518318Smax.romanov@nginx.com         nxt_queue_remove(lnk);
2519343Smax.romanov@nginx.com         lnk->next = NULL;
2520318Smax.romanov@nginx.com 
2521318Smax.romanov@nginx.com         ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link);
2522318Smax.romanov@nginx.com 
2523343Smax.romanov@nginx.com     } else {
2524343Smax.romanov@nginx.com         ra = NULL;
2525343Smax.romanov@nginx.com     }
2526343Smax.romanov@nginx.com 
2527343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
2528343Smax.romanov@nginx.com 
2529343Smax.romanov@nginx.com     if (ra != NULL) {
2530318Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p abort next stream #%uD",
2531318Smax.romanov@nginx.com                   &app->name, app, ra->stream);
2532318Smax.romanov@nginx.com 
2533318Smax.romanov@nginx.com         nxt_router_ra_abort(task, ra, ra->work.data);
2534318Smax.romanov@nginx.com     }
2535192Smax.romanov@nginx.com 
2536343Smax.romanov@nginx.com     nxt_router_app_use(task, app, -1);
2537192Smax.romanov@nginx.com }
2538192Smax.romanov@nginx.com 
2539192Smax.romanov@nginx.com 
2540343Smax.romanov@nginx.com void
2541343Smax.romanov@nginx.com nxt_router_app_use(nxt_task_t *task, nxt_app_t *app, int i)
2542141Smax.romanov@nginx.com {
2543343Smax.romanov@nginx.com     int  c;
2544343Smax.romanov@nginx.com 
2545343Smax.romanov@nginx.com     c = nxt_atomic_fetch_add(&app->use_count, i);
2546343Smax.romanov@nginx.com 
2547343Smax.romanov@nginx.com     if (i < 0 && c == -i) {
2548343Smax.romanov@nginx.com 
2549343Smax.romanov@nginx.com         nxt_assert(app->live == 0);
2550343Smax.romanov@nginx.com         nxt_assert(app->workers == 0);
2551343Smax.romanov@nginx.com         nxt_assert(app->pending_workers == 0);
2552343Smax.romanov@nginx.com         nxt_assert(nxt_queue_is_empty(&app->requests) != 0);
2553343Smax.romanov@nginx.com         nxt_assert(nxt_queue_is_empty(&app->ports) != 0);
2554343Smax.romanov@nginx.com 
2555163Smax.romanov@nginx.com         nxt_thread_mutex_destroy(&app->mutex);
2556163Smax.romanov@nginx.com         nxt_free(app);
2557163Smax.romanov@nginx.com     }
2558343Smax.romanov@nginx.com }
2559343Smax.romanov@nginx.com 
2560343Smax.romanov@nginx.com 
2561343Smax.romanov@nginx.com nxt_inline nxt_port_t *
2562343Smax.romanov@nginx.com nxt_router_app_get_port_unsafe(nxt_app_t *app, int *use_delta)
2563343Smax.romanov@nginx.com {
2564343Smax.romanov@nginx.com     nxt_port_t        *port;
2565343Smax.romanov@nginx.com     nxt_queue_link_t  *lnk;
2566343Smax.romanov@nginx.com 
2567343Smax.romanov@nginx.com     lnk = nxt_queue_first(&app->ports);
2568343Smax.romanov@nginx.com     nxt_queue_remove(lnk);
2569343Smax.romanov@nginx.com 
2570343Smax.romanov@nginx.com     port = nxt_queue_link_data(lnk, nxt_port_t, app_link);
2571343Smax.romanov@nginx.com 
2572343Smax.romanov@nginx.com     port->app_requests++;
2573343Smax.romanov@nginx.com 
2574343Smax.romanov@nginx.com     if (app->live &&
2575343Smax.romanov@nginx.com          (app->max_pending_responses == 0 ||
2576343Smax.romanov@nginx.com             (port->app_requests - port->app_responses) <
2577343Smax.romanov@nginx.com                 app->max_pending_responses) )
2578277Sigor@sysoev.ru     {
2579343Smax.romanov@nginx.com         nxt_queue_insert_tail(&app->ports, lnk);
2580343Smax.romanov@nginx.com 
2581343Smax.romanov@nginx.com     } else {
2582343Smax.romanov@nginx.com         lnk->next = NULL;
2583343Smax.romanov@nginx.com 
2584343Smax.romanov@nginx.com         (*use_delta)--;
2585167Smax.romanov@nginx.com     }
2586167Smax.romanov@nginx.com 
2587343Smax.romanov@nginx.com     return port;
2588163Smax.romanov@nginx.com }
2589163Smax.romanov@nginx.com 
2590163Smax.romanov@nginx.com 
2591141Smax.romanov@nginx.com static nxt_port_t *
2592343Smax.romanov@nginx.com nxt_router_app_get_idle_port(nxt_app_t *app)
2593141Smax.romanov@nginx.com {
2594343Smax.romanov@nginx.com     nxt_port_t  *port;
2595141Smax.romanov@nginx.com 
2596141Smax.romanov@nginx.com     port = NULL;
2597141Smax.romanov@nginx.com 
2598141Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
2599141Smax.romanov@nginx.com 
2600343Smax.romanov@nginx.com     nxt_queue_each(port, &app->ports, nxt_port_t, app_link) {
2601343Smax.romanov@nginx.com 
2602343Smax.romanov@nginx.com         if (port->app_requests > port->app_responses) {
2603343Smax.romanov@nginx.com             port = NULL;
2604343Smax.romanov@nginx.com 
2605343Smax.romanov@nginx.com             continue;
2606343Smax.romanov@nginx.com         }
2607343Smax.romanov@nginx.com 
2608343Smax.romanov@nginx.com         nxt_queue_remove(&port->app_link);
2609343Smax.romanov@nginx.com         port->app_link.next = NULL;
2610343Smax.romanov@nginx.com 
2611343Smax.romanov@nginx.com         break;
2612343Smax.romanov@nginx.com 
2613343Smax.romanov@nginx.com     } nxt_queue_loop;
2614141Smax.romanov@nginx.com 
2615141Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
2616141Smax.romanov@nginx.com 
2617141Smax.romanov@nginx.com     return port;
2618141Smax.romanov@nginx.com }
2619141Smax.romanov@nginx.com 
2620141Smax.romanov@nginx.com 
2621141Smax.romanov@nginx.com static void
2622343Smax.romanov@nginx.com nxt_router_app_process_request(nxt_task_t *task, void *obj, void *data)
2623141Smax.romanov@nginx.com {
2624343Smax.romanov@nginx.com     nxt_app_t           *app;
2625343Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
2626343Smax.romanov@nginx.com 
2627343Smax.romanov@nginx.com     app = obj;
2628343Smax.romanov@nginx.com     ra = data;
2629141Smax.romanov@nginx.com 
2630141Smax.romanov@nginx.com     nxt_assert(app != NULL);
2631343Smax.romanov@nginx.com     nxt_assert(ra != NULL);
2632343Smax.romanov@nginx.com     nxt_assert(ra->app_port != NULL);
2633343Smax.romanov@nginx.com 
2634343Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p process next stream #%uD",
2635343Smax.romanov@nginx.com               &app->name, app, ra->stream);
2636343Smax.romanov@nginx.com 
2637343Smax.romanov@nginx.com     nxt_router_process_http_request_mp(task, ra);
2638343Smax.romanov@nginx.com }
2639343Smax.romanov@nginx.com 
2640343Smax.romanov@nginx.com 
2641343Smax.romanov@nginx.com static void
2642343Smax.romanov@nginx.com nxt_router_app_port_release(nxt_task_t *task, nxt_port_t *port,
2643343Smax.romanov@nginx.com     uint32_t request_failed, uint32_t got_response)
2644343Smax.romanov@nginx.com {
2645343Smax.romanov@nginx.com     int                 use_delta, ra_use_delta;
2646343Smax.romanov@nginx.com     nxt_app_t           *app;
2647343Smax.romanov@nginx.com     nxt_queue_link_t    *lnk;
2648343Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
2649343Smax.romanov@nginx.com 
2650343Smax.romanov@nginx.com     nxt_assert(port != NULL);
2651343Smax.romanov@nginx.com     nxt_assert(port->app != NULL);
2652343Smax.romanov@nginx.com 
2653343Smax.romanov@nginx.com     app = port->app;
2654343Smax.romanov@nginx.com 
2655343Smax.romanov@nginx.com     use_delta = (request_failed == 0 && got_response == 0) ? 0 : -1;
2656343Smax.romanov@nginx.com 
2657343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
2658343Smax.romanov@nginx.com 
2659343Smax.romanov@nginx.com     port->app_requests -= request_failed;
2660343Smax.romanov@nginx.com     port->app_responses += got_response;
2661343Smax.romanov@nginx.com 
2662343Smax.romanov@nginx.com     if (app->live != 0 &&
2663343Smax.romanov@nginx.com         port->pair[1] != -1 &&
2664343Smax.romanov@nginx.com         port->app_link.next == NULL &&
2665343Smax.romanov@nginx.com         (app->max_pending_responses == 0 ||
2666343Smax.romanov@nginx.com             (port->app_requests - port->app_responses) <
2667343Smax.romanov@nginx.com                 app->max_pending_responses) )
2668343Smax.romanov@nginx.com     {
2669343Smax.romanov@nginx.com         nxt_queue_insert_tail(&app->ports, &port->app_link);
2670343Smax.romanov@nginx.com         use_delta++;
2671141Smax.romanov@nginx.com     }
2672141Smax.romanov@nginx.com 
2673343Smax.romanov@nginx.com     if (app->live != 0 &&
2674343Smax.romanov@nginx.com         !nxt_queue_is_empty(&app->ports) &&
2675343Smax.romanov@nginx.com         !nxt_queue_is_empty(&app->requests))
2676343Smax.romanov@nginx.com     {
2677141Smax.romanov@nginx.com         lnk = nxt_queue_first(&app->requests);
2678141Smax.romanov@nginx.com         nxt_queue_remove(lnk);
2679343Smax.romanov@nginx.com         lnk->next = NULL;
2680141Smax.romanov@nginx.com 
2681167Smax.romanov@nginx.com         ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link);
2682167Smax.romanov@nginx.com 
2683343Smax.romanov@nginx.com         ra_use_delta = 1;
2684343Smax.romanov@nginx.com         ra->app_port = nxt_router_app_get_port_unsafe(app, &ra_use_delta);
2685343Smax.romanov@nginx.com 
2686343Smax.romanov@nginx.com     } else {
2687343Smax.romanov@nginx.com         ra = NULL;
2688343Smax.romanov@nginx.com         ra_use_delta = 0;
2689141Smax.romanov@nginx.com     }
2690141Smax.romanov@nginx.com 
2691343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
2692343Smax.romanov@nginx.com 
2693343Smax.romanov@nginx.com     if (ra != NULL) {
2694343Smax.romanov@nginx.com         nxt_work_queue_add(&task->thread->engine->fast_work_queue,
2695343Smax.romanov@nginx.com                            nxt_router_app_process_request,
2696343Smax.romanov@nginx.com                            &task->thread->engine->task, app, ra);
2697343Smax.romanov@nginx.com 
2698343Smax.romanov@nginx.com         goto adjust_use;
2699343Smax.romanov@nginx.com     }
2700343Smax.romanov@nginx.com 
2701343Smax.romanov@nginx.com     /* ? */
2702163Smax.romanov@nginx.com     if (port->pair[1] == -1) {
2703343Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p port %p already closed (pid %PI dead?)",
2704343Smax.romanov@nginx.com                   &app->name, app, port, port->pid);
2705343Smax.romanov@nginx.com 
2706343Smax.romanov@nginx.com         goto adjust_use;
2707163Smax.romanov@nginx.com     }
2708163Smax.romanov@nginx.com 
2709343Smax.romanov@nginx.com     if (app->live == 0) {
2710167Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p is not alive, send QUIT to port",
2711167Smax.romanov@nginx.com                   &app->name, app);
2712163Smax.romanov@nginx.com 
2713163Smax.romanov@nginx.com         nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT,
2714163Smax.romanov@nginx.com                               -1, 0, 0, NULL);
2715163Smax.romanov@nginx.com 
2716343Smax.romanov@nginx.com         goto adjust_use;
2717163Smax.romanov@nginx.com     }
2718163Smax.romanov@nginx.com 
2719167Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p requests queue is empty, keep the port",
2720167Smax.romanov@nginx.com               &app->name, app);
2721141Smax.romanov@nginx.com 
2722343Smax.romanov@nginx.com adjust_use:
2723343Smax.romanov@nginx.com 
2724343Smax.romanov@nginx.com     if (use_delta != 0) {
2725343Smax.romanov@nginx.com         nxt_port_use(task, port, use_delta);
2726343Smax.romanov@nginx.com     }
2727343Smax.romanov@nginx.com 
2728343Smax.romanov@nginx.com     if (ra_use_delta != 0) {
2729343Smax.romanov@nginx.com         nxt_port_use(task, ra->app_port, ra_use_delta);
2730343Smax.romanov@nginx.com     }
2731141Smax.romanov@nginx.com }
2732141Smax.romanov@nginx.com 
2733141Smax.romanov@nginx.com 
2734343Smax.romanov@nginx.com void
2735343Smax.romanov@nginx.com nxt_router_app_port_close(nxt_task_t *task, nxt_port_t *port)
2736141Smax.romanov@nginx.com {
2737163Smax.romanov@nginx.com     nxt_app_t   *app;
2738343Smax.romanov@nginx.com     nxt_bool_t  unchain, start_worker;
2739141Smax.romanov@nginx.com 
2740141Smax.romanov@nginx.com     app = port->app;
2741343Smax.romanov@nginx.com 
2742343Smax.romanov@nginx.com     nxt_assert(app != NULL);
2743141Smax.romanov@nginx.com 
2744141Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
2745141Smax.romanov@nginx.com 
2746343Smax.romanov@nginx.com     unchain = port->app_link.next != NULL;
2747343Smax.romanov@nginx.com 
2748343Smax.romanov@nginx.com     if (unchain) {
2749163Smax.romanov@nginx.com         nxt_queue_remove(&port->app_link);
2750163Smax.romanov@nginx.com         port->app_link.next = NULL;
2751343Smax.romanov@nginx.com     }
2752343Smax.romanov@nginx.com 
2753343Smax.romanov@nginx.com     app->workers--;
2754343Smax.romanov@nginx.com 
2755343Smax.romanov@nginx.com     start_worker = app->live != 0 &&
2756343Smax.romanov@nginx.com                    nxt_queue_is_empty(&app->requests) == 0 &&
2757343Smax.romanov@nginx.com                    app->workers + app->pending_workers < app->max_workers;
2758343Smax.romanov@nginx.com 
2759343Smax.romanov@nginx.com     if (start_worker) {
2760343Smax.romanov@nginx.com         app->pending_workers++;
2761163Smax.romanov@nginx.com     }
2762141Smax.romanov@nginx.com 
2763141Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
2764163Smax.romanov@nginx.com 
2765343Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p port %p close", &app->name, app, port);
2766343Smax.romanov@nginx.com 
2767343Smax.romanov@nginx.com     if (unchain) {
2768343Smax.romanov@nginx.com         nxt_port_use(task, port, -1);
2769163Smax.romanov@nginx.com     }
2770163Smax.romanov@nginx.com 
2771343Smax.romanov@nginx.com     if (start_worker) {
2772343Smax.romanov@nginx.com         nxt_router_start_worker(task, app);
2773343Smax.romanov@nginx.com     }
2774141Smax.romanov@nginx.com }
2775141Smax.romanov@nginx.com 
2776141Smax.romanov@nginx.com 
2777167Smax.romanov@nginx.com static nxt_int_t
2778167Smax.romanov@nginx.com nxt_router_app_port(nxt_task_t *task, nxt_req_app_link_t *ra)
2779141Smax.romanov@nginx.com {
2780343Smax.romanov@nginx.com     int                      use_delta;
2781343Smax.romanov@nginx.com     nxt_int_t                res;
2782141Smax.romanov@nginx.com     nxt_app_t                *app;
2783343Smax.romanov@nginx.com     nxt_bool_t               can_start_worker;
2784141Smax.romanov@nginx.com     nxt_conn_t               *c;
2785167Smax.romanov@nginx.com     nxt_port_t               *port;
2786318Smax.romanov@nginx.com     nxt_event_engine_t       *engine;
2787141Smax.romanov@nginx.com     nxt_socket_conf_joint_t  *joint;
2788141Smax.romanov@nginx.com 
2789141Smax.romanov@nginx.com     port = NULL;
2790343Smax.romanov@nginx.com     use_delta = 1;
2791167Smax.romanov@nginx.com     c = ra->rc->conn;
2792141Smax.romanov@nginx.com 
2793*359Sigor@sysoev.ru     joint = c->joint;
2794141Smax.romanov@nginx.com     app = joint->socket_conf->application;
2795141Smax.romanov@nginx.com 
2796141Smax.romanov@nginx.com     if (app == NULL) {
2797167Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 500,
2798141Smax.romanov@nginx.com                              "Application is NULL in socket_conf");
2799141Smax.romanov@nginx.com         return NXT_ERROR;
2800141Smax.romanov@nginx.com     }
2801141Smax.romanov@nginx.com 
2802343Smax.romanov@nginx.com     ra->rc->app = app;
2803343Smax.romanov@nginx.com 
2804343Smax.romanov@nginx.com     nxt_router_app_use(task, app, 1);
2805343Smax.romanov@nginx.com 
2806318Smax.romanov@nginx.com     engine = task->thread->engine;
2807318Smax.romanov@nginx.com 
2808318Smax.romanov@nginx.com     nxt_timer_disable(engine, &c->read_timer);
2809318Smax.romanov@nginx.com 
2810318Smax.romanov@nginx.com     if (app->timeout != 0) {
2811318Smax.romanov@nginx.com         c->read_timer.handler = nxt_router_app_timeout;
2812318Smax.romanov@nginx.com         nxt_timer_add(engine, &c->read_timer, app->timeout);
2813318Smax.romanov@nginx.com     }
2814318Smax.romanov@nginx.com 
2815351Smax.romanov@nginx.com     can_start_worker = 0;
2816351Smax.romanov@nginx.com 
2817343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
2818343Smax.romanov@nginx.com 
2819343Smax.romanov@nginx.com     if (!nxt_queue_is_empty(&app->ports)) {
2820343Smax.romanov@nginx.com         port = nxt_router_app_get_port_unsafe(app, &use_delta);
2821343Smax.romanov@nginx.com 
2822343Smax.romanov@nginx.com     } else {
2823351Smax.romanov@nginx.com         ra = nxt_router_ra_create(task, ra);
2824351Smax.romanov@nginx.com 
2825351Smax.romanov@nginx.com         if (nxt_fast_path(ra != NULL)) {
2826351Smax.romanov@nginx.com             nxt_queue_insert_tail(&app->requests, &ra->link);
2827351Smax.romanov@nginx.com 
2828351Smax.romanov@nginx.com             can_start_worker = (app->workers + app->pending_workers) <
2829351Smax.romanov@nginx.com                                   app->max_workers;
2830351Smax.romanov@nginx.com             if (can_start_worker) {
2831351Smax.romanov@nginx.com                 app->pending_workers++;
2832351Smax.romanov@nginx.com             }
2833343Smax.romanov@nginx.com         }
2834343Smax.romanov@nginx.com 
2835343Smax.romanov@nginx.com         port = NULL;
2836343Smax.romanov@nginx.com     }
2837343Smax.romanov@nginx.com 
2838343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
2839141Smax.romanov@nginx.com 
2840351Smax.romanov@nginx.com     if (nxt_slow_path(ra == NULL)) {
2841351Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 500, "Failed to allocate "
2842351Smax.romanov@nginx.com                              "req<->app link");
2843351Smax.romanov@nginx.com         return NXT_ERROR;
2844351Smax.romanov@nginx.com     }
2845351Smax.romanov@nginx.com 
2846141Smax.romanov@nginx.com     if (port != NULL) {
2847343Smax.romanov@nginx.com         nxt_debug(task, "already have port for app '%V' %p ", &app->name, app);
2848163Smax.romanov@nginx.com 
2849167Smax.romanov@nginx.com         ra->app_port = port;
2850343Smax.romanov@nginx.com 
2851343Smax.romanov@nginx.com         if (use_delta != 0) {
2852343Smax.romanov@nginx.com             nxt_port_use(task, port, use_delta);
2853343Smax.romanov@nginx.com         }
2854141Smax.romanov@nginx.com         return NXT_OK;
2855141Smax.romanov@nginx.com     }
2856141Smax.romanov@nginx.com 
2857351Smax.romanov@nginx.com     nxt_debug(task, "ra stream #%uD allocated", ra->stream);
2858351Smax.romanov@nginx.com 
2859343Smax.romanov@nginx.com     if (!can_start_worker) {
2860343Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p too many running or pending workers",
2861343Smax.romanov@nginx.com                   &app->name, app);
2862343Smax.romanov@nginx.com 
2863343Smax.romanov@nginx.com         return NXT_AGAIN;
2864343Smax.romanov@nginx.com     }
2865343Smax.romanov@nginx.com 
2866343Smax.romanov@nginx.com     res = nxt_router_start_worker(task, app);
2867343Smax.romanov@nginx.com 
2868343Smax.romanov@nginx.com     if (nxt_slow_path(res != NXT_OK)) {
2869343Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 500, "Failed to start worker");
2870343Smax.romanov@nginx.com 
2871141Smax.romanov@nginx.com         return NXT_ERROR;
2872141Smax.romanov@nginx.com     }
2873141Smax.romanov@nginx.com 
2874141Smax.romanov@nginx.com     return NXT_AGAIN;
287588Smax.romanov@nginx.com }
287688Smax.romanov@nginx.com 
287788Smax.romanov@nginx.com 
287888Smax.romanov@nginx.com static void
287953Sigor@sysoev.ru nxt_router_conn_http_header_parse(nxt_task_t *task, void *obj, void *data)
288053Sigor@sysoev.ru {
2881206Smax.romanov@nginx.com     size_t                    size;
288253Sigor@sysoev.ru     nxt_int_t                 ret;
2883206Smax.romanov@nginx.com     nxt_buf_t                 *buf;
288462Sigor@sysoev.ru     nxt_conn_t                *c;
2885268Sigor@sysoev.ru     nxt_sockaddr_t            *local;
288688Smax.romanov@nginx.com     nxt_app_parse_ctx_t       *ap;
2887206Smax.romanov@nginx.com     nxt_app_request_body_t    *b;
288853Sigor@sysoev.ru     nxt_socket_conf_joint_t   *joint;
288988Smax.romanov@nginx.com     nxt_app_request_header_t  *h;
289053Sigor@sysoev.ru 
289153Sigor@sysoev.ru     c = obj;
289288Smax.romanov@nginx.com     ap = data;
2893206Smax.romanov@nginx.com     buf = c->read;
2894*359Sigor@sysoev.ru     joint = c->joint;
289553Sigor@sysoev.ru 
289653Sigor@sysoev.ru     nxt_debug(task, "router conn http header parse");
289753Sigor@sysoev.ru 
289888Smax.romanov@nginx.com     if (ap == NULL) {
2899319Smax.romanov@nginx.com         ap = nxt_app_http_req_init(task);
290088Smax.romanov@nginx.com         if (nxt_slow_path(ap == NULL)) {
2901319Smax.romanov@nginx.com             nxt_router_gen_error(task, c, 500,
2902319Smax.romanov@nginx.com                                  "Failed to allocate parse context");
290361Sigor@sysoev.ru             return;
290461Sigor@sysoev.ru         }
290588Smax.romanov@nginx.com 
290688Smax.romanov@nginx.com         c->socket.data = ap;
2907113Smax.romanov@nginx.com 
2908113Smax.romanov@nginx.com         ap->r.remote.start = nxt_sockaddr_address(c->remote);
2909113Smax.romanov@nginx.com         ap->r.remote.length = c->remote->address_length;
2910206Smax.romanov@nginx.com 
2911*359Sigor@sysoev.ru         /*
2912*359Sigor@sysoev.ru          * TODO: need an application flag to get local address
2913*359Sigor@sysoev.ru          * required by "SERVER_ADDR" in Pyhton and PHP. Not used in Go.
2914*359Sigor@sysoev.ru          */
2915*359Sigor@sysoev.ru         local = nxt_router_local_addr(task, c);
2916*359Sigor@sysoev.ru 
2917*359Sigor@sysoev.ru         if (nxt_fast_path(local != NULL)) {
2918*359Sigor@sysoev.ru             ap->r.local.start = nxt_sockaddr_address(local);
2919*359Sigor@sysoev.ru             ap->r.local.length = local->address_length;
2920*359Sigor@sysoev.ru         }
2921268Sigor@sysoev.ru 
2922206Smax.romanov@nginx.com         ap->r.header.buf = buf;
292353Sigor@sysoev.ru     }
292453Sigor@sysoev.ru 
292588Smax.romanov@nginx.com     h = &ap->r.header;
2926206Smax.romanov@nginx.com     b = &ap->r.body;
2927206Smax.romanov@nginx.com 
2928206Smax.romanov@nginx.com     ret = nxt_app_http_req_header_parse(task, ap, buf);
2929206Smax.romanov@nginx.com 
2930206Smax.romanov@nginx.com     nxt_debug(task, "http parse request header: %d", ret);
293153Sigor@sysoev.ru 
293253Sigor@sysoev.ru     switch (nxt_expect(NXT_DONE, ret)) {
293353Sigor@sysoev.ru 
293453Sigor@sysoev.ru     case NXT_DONE:
293588Smax.romanov@nginx.com         nxt_debug(task, "router request header parsing complete, "
293688Smax.romanov@nginx.com                   "content length: %O, preread: %uz",
2937206Smax.romanov@nginx.com                   h->parsed_content_length, nxt_buf_mem_used_size(&buf->mem));
2938206Smax.romanov@nginx.com 
2939206Smax.romanov@nginx.com         if (b->done) {
2940206Smax.romanov@nginx.com             nxt_router_process_http_request(task, c, ap);
2941206Smax.romanov@nginx.com 
2942206Smax.romanov@nginx.com             return;
2943206Smax.romanov@nginx.com         }
2944206Smax.romanov@nginx.com 
2945277Sigor@sysoev.ru         if (joint->socket_conf->max_body_size > 0
2946277Sigor@sysoev.ru             && (size_t) h->parsed_content_length
2947277Sigor@sysoev.ru                > joint->socket_conf->max_body_size)
2948277Sigor@sysoev.ru         {
2949206Smax.romanov@nginx.com             nxt_router_gen_error(task, c, 413, "Content-Length too big");
2950206Smax.romanov@nginx.com             return;
2951206Smax.romanov@nginx.com         }
2952206Smax.romanov@nginx.com 
2953206Smax.romanov@nginx.com         if (nxt_buf_mem_free_size(&buf->mem) == 0) {
2954206Smax.romanov@nginx.com             size = nxt_min(joint->socket_conf->body_buffer_size,
2955206Smax.romanov@nginx.com                            (size_t) h->parsed_content_length);
2956206Smax.romanov@nginx.com 
2957206Smax.romanov@nginx.com             buf->next = nxt_buf_mem_alloc(c->mem_pool, size, 0);
2958206Smax.romanov@nginx.com             if (nxt_slow_path(buf->next == NULL)) {
2959206Smax.romanov@nginx.com                 nxt_router_gen_error(task, c, 500, "Failed to allocate "
2960206Smax.romanov@nginx.com                                      "buffer for request body");
2961206Smax.romanov@nginx.com                 return;
2962206Smax.romanov@nginx.com             }
2963206Smax.romanov@nginx.com 
2964206Smax.romanov@nginx.com             c->read = buf->next;
2965206Smax.romanov@nginx.com 
2966206Smax.romanov@nginx.com             b->preread_size += nxt_buf_mem_used_size(&buf->mem);
2967206Smax.romanov@nginx.com         }
2968206Smax.romanov@nginx.com 
2969206Smax.romanov@nginx.com         if (b->buf == NULL) {
2970206Smax.romanov@nginx.com             b->buf = c->read;
2971206Smax.romanov@nginx.com         }
2972206Smax.romanov@nginx.com 
2973206Smax.romanov@nginx.com         c->read_state = &nxt_router_conn_read_body_state;
2974206Smax.romanov@nginx.com         break;
2975206Smax.romanov@nginx.com 
2976206Smax.romanov@nginx.com     case NXT_ERROR:
2977206Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 400, "Request header parse error");
2978206Smax.romanov@nginx.com         return;
2979206Smax.romanov@nginx.com 
2980206Smax.romanov@nginx.com     default:  /* NXT_AGAIN */
2981206Smax.romanov@nginx.com 
2982206Smax.romanov@nginx.com         if (c->read->mem.free == c->read->mem.end) {
2983206Smax.romanov@nginx.com             size = joint->socket_conf->large_header_buffer_size;
2984206Smax.romanov@nginx.com 
2985277Sigor@sysoev.ru             if (size <= (size_t) nxt_buf_mem_used_size(&buf->mem)
2986277Sigor@sysoev.ru                 || ap->r.header.bufs
2987277Sigor@sysoev.ru                    >= joint->socket_conf->large_header_buffers)
2988277Sigor@sysoev.ru             {
2989206Smax.romanov@nginx.com                 nxt_router_gen_error(task, c, 413,
2990206Smax.romanov@nginx.com                                      "Too long request headers");
2991206Smax.romanov@nginx.com                 return;
2992206Smax.romanov@nginx.com             }
2993206Smax.romanov@nginx.com 
2994206Smax.romanov@nginx.com             buf->next = nxt_buf_mem_alloc(c->mem_pool, size, 0);
2995206Smax.romanov@nginx.com             if (nxt_slow_path(buf->next == NULL)) {
2996206Smax.romanov@nginx.com                 nxt_router_gen_error(task, c, 500,
2997206Smax.romanov@nginx.com                                      "Failed to allocate large header "
2998206Smax.romanov@nginx.com                                      "buffer");
2999206Smax.romanov@nginx.com                 return;
3000206Smax.romanov@nginx.com             }
3001206Smax.romanov@nginx.com 
3002206Smax.romanov@nginx.com             ap->r.header.bufs++;
3003206Smax.romanov@nginx.com 
3004206Smax.romanov@nginx.com             size = c->read->mem.free - c->read->mem.pos;
3005206Smax.romanov@nginx.com 
3006206Smax.romanov@nginx.com             c->read = nxt_buf_cpy(buf->next, c->read->mem.pos, size);
3007206Smax.romanov@nginx.com         }
3008206Smax.romanov@nginx.com 
3009206Smax.romanov@nginx.com     }
3010206Smax.romanov@nginx.com 
3011206Smax.romanov@nginx.com     nxt_conn_read(task->thread->engine, c);
3012206Smax.romanov@nginx.com }
3013206Smax.romanov@nginx.com 
3014206Smax.romanov@nginx.com 
3015*359Sigor@sysoev.ru static nxt_sockaddr_t *
3016*359Sigor@sysoev.ru nxt_router_local_addr(nxt_task_t *task, nxt_conn_t *c)
3017*359Sigor@sysoev.ru {
3018*359Sigor@sysoev.ru     int             ret;
3019*359Sigor@sysoev.ru     size_t          size;
3020*359Sigor@sysoev.ru     socklen_t       socklen;
3021*359Sigor@sysoev.ru     nxt_sockaddr_t  *sa;
3022*359Sigor@sysoev.ru 
3023*359Sigor@sysoev.ru     if (c->local != NULL) {
3024*359Sigor@sysoev.ru         return c->local;
3025*359Sigor@sysoev.ru     }
3026*359Sigor@sysoev.ru 
3027*359Sigor@sysoev.ru     /* AF_UNIX should not get in here. */
3028*359Sigor@sysoev.ru 
3029*359Sigor@sysoev.ru     switch (c->remote->u.sockaddr.sa_family) {
3030*359Sigor@sysoev.ru #if (NXT_INET6)
3031*359Sigor@sysoev.ru     case AF_INET6:
3032*359Sigor@sysoev.ru         socklen = sizeof(struct sockaddr_in6);
3033*359Sigor@sysoev.ru         size = offsetof(nxt_sockaddr_t, u) + socklen + NXT_INET6_ADDR_STR_LEN;
3034*359Sigor@sysoev.ru         break;
3035*359Sigor@sysoev.ru #endif
3036*359Sigor@sysoev.ru     case AF_INET:
3037*359Sigor@sysoev.ru     default:
3038*359Sigor@sysoev.ru         socklen = sizeof(struct sockaddr_in6);
3039*359Sigor@sysoev.ru         size = offsetof(nxt_sockaddr_t, u) + socklen + NXT_INET_ADDR_STR_LEN;
3040*359Sigor@sysoev.ru         break;
3041*359Sigor@sysoev.ru     }
3042*359Sigor@sysoev.ru 
3043*359Sigor@sysoev.ru     sa = nxt_mp_get(c->mem_pool, size);
3044*359Sigor@sysoev.ru     if (nxt_slow_path(sa == NULL)) {
3045*359Sigor@sysoev.ru         return NULL;
3046*359Sigor@sysoev.ru     }
3047*359Sigor@sysoev.ru 
3048*359Sigor@sysoev.ru     ret = getsockname(c->socket.fd, &sa->u.sockaddr, &socklen);
3049*359Sigor@sysoev.ru     if (nxt_slow_path(ret != 0)) {
3050*359Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "getsockname(%d) failed", c->socket.fd);
3051*359Sigor@sysoev.ru         return NULL;
3052*359Sigor@sysoev.ru     }
3053*359Sigor@sysoev.ru 
3054*359Sigor@sysoev.ru     c->local = sa;
3055*359Sigor@sysoev.ru 
3056*359Sigor@sysoev.ru     nxt_sockaddr_text(sa);
3057*359Sigor@sysoev.ru 
3058*359Sigor@sysoev.ru     /*
3059*359Sigor@sysoev.ru      * TODO: here we can adjust the end of non-freeable block
3060*359Sigor@sysoev.ru      * in c->mem_pool to the end of actual sockaddr length.
3061*359Sigor@sysoev.ru      */
3062*359Sigor@sysoev.ru 
3063*359Sigor@sysoev.ru     return sa;
3064*359Sigor@sysoev.ru }
3065*359Sigor@sysoev.ru 
3066*359Sigor@sysoev.ru 
3067206Smax.romanov@nginx.com static void
3068206Smax.romanov@nginx.com nxt_router_conn_http_body_read(nxt_task_t *task, void *obj, void *data)
3069206Smax.romanov@nginx.com {
3070206Smax.romanov@nginx.com     size_t                    size;
3071206Smax.romanov@nginx.com     nxt_int_t                 ret;
3072206Smax.romanov@nginx.com     nxt_buf_t                 *buf;
3073206Smax.romanov@nginx.com     nxt_conn_t                *c;
3074206Smax.romanov@nginx.com     nxt_app_parse_ctx_t       *ap;
3075206Smax.romanov@nginx.com     nxt_app_request_body_t    *b;
3076206Smax.romanov@nginx.com     nxt_socket_conf_joint_t   *joint;
3077206Smax.romanov@nginx.com     nxt_app_request_header_t  *h;
3078206Smax.romanov@nginx.com 
3079206Smax.romanov@nginx.com     c = obj;
3080206Smax.romanov@nginx.com     ap = data;
3081206Smax.romanov@nginx.com     buf = c->read;
3082206Smax.romanov@nginx.com 
3083206Smax.romanov@nginx.com     nxt_debug(task, "router conn http body read");
3084206Smax.romanov@nginx.com 
3085206Smax.romanov@nginx.com     nxt_assert(ap != NULL);
3086206Smax.romanov@nginx.com 
3087206Smax.romanov@nginx.com     b = &ap->r.body;
3088206Smax.romanov@nginx.com     h = &ap->r.header;
3089206Smax.romanov@nginx.com 
3090206Smax.romanov@nginx.com     ret = nxt_app_http_req_body_read(task, ap, buf);
3091206Smax.romanov@nginx.com 
3092206Smax.romanov@nginx.com     nxt_debug(task, "http read request body: %d", ret);
3093206Smax.romanov@nginx.com 
3094206Smax.romanov@nginx.com     switch (nxt_expect(NXT_DONE, ret)) {
3095206Smax.romanov@nginx.com 
3096206Smax.romanov@nginx.com     case NXT_DONE:
309788Smax.romanov@nginx.com         nxt_router_process_http_request(task, c, ap);
309888Smax.romanov@nginx.com         return;
309953Sigor@sysoev.ru 
310053Sigor@sysoev.ru     case NXT_ERROR:
3101206Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 500, "Read body error");
310253Sigor@sysoev.ru         return;
310353Sigor@sysoev.ru 
310453Sigor@sysoev.ru     default:  /* NXT_AGAIN */
310553Sigor@sysoev.ru 
3106206Smax.romanov@nginx.com         if (nxt_buf_mem_free_size(&buf->mem) == 0) {
3107*359Sigor@sysoev.ru             joint = c->joint;
3108206Smax.romanov@nginx.com 
3109206Smax.romanov@nginx.com             b->preread_size += nxt_buf_mem_used_size(&buf->mem);
3110206Smax.romanov@nginx.com 
3111206Smax.romanov@nginx.com             size = nxt_min(joint->socket_conf->body_buffer_size,
3112206Smax.romanov@nginx.com                            (size_t) h->parsed_content_length - b->preread_size);
3113206Smax.romanov@nginx.com 
3114206Smax.romanov@nginx.com             buf->next = nxt_buf_mem_alloc(c->mem_pool, size, 0);
3115206Smax.romanov@nginx.com             if (nxt_slow_path(buf->next == NULL)) {
3116206Smax.romanov@nginx.com                 nxt_router_gen_error(task, c, 500, "Failed to allocate "
3117206Smax.romanov@nginx.com                                      "buffer for request body");
3118206Smax.romanov@nginx.com                 return;
311988Smax.romanov@nginx.com             }
3120206Smax.romanov@nginx.com 
3121206Smax.romanov@nginx.com             c->read = buf->next;
312288Smax.romanov@nginx.com         }
312388Smax.romanov@nginx.com 
3124206Smax.romanov@nginx.com         nxt_debug(task, "router request body read again, rest: %uz",
3125206Smax.romanov@nginx.com                   h->parsed_content_length - b->preread_size);
312688Smax.romanov@nginx.com     }
312788Smax.romanov@nginx.com 
312888Smax.romanov@nginx.com     nxt_conn_read(task->thread->engine, c);
312988Smax.romanov@nginx.com }
313088Smax.romanov@nginx.com 
313188Smax.romanov@nginx.com 
313288Smax.romanov@nginx.com static void
313388Smax.romanov@nginx.com nxt_router_process_http_request(nxt_task_t *task, nxt_conn_t *c,
313488Smax.romanov@nginx.com     nxt_app_parse_ctx_t *ap)
313588Smax.romanov@nginx.com {
3136122Smax.romanov@nginx.com     nxt_int_t            res;
3137167Smax.romanov@nginx.com     nxt_port_t           *port;
313888Smax.romanov@nginx.com     nxt_event_engine_t   *engine;
3139351Smax.romanov@nginx.com     nxt_req_app_link_t   ra_local, *ra;
314088Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
314188Smax.romanov@nginx.com 
314288Smax.romanov@nginx.com     engine = task->thread->engine;
314388Smax.romanov@nginx.com 
3144318Smax.romanov@nginx.com     rc = nxt_port_rpc_register_handler_ex(task, engine->port,
3145318Smax.romanov@nginx.com                                           nxt_router_response_ready_handler,
3146318Smax.romanov@nginx.com                                           nxt_router_response_error_handler,
3147318Smax.romanov@nginx.com                                           sizeof(nxt_req_conn_link_t));
3148122Smax.romanov@nginx.com 
314988Smax.romanov@nginx.com     if (nxt_slow_path(rc == NULL)) {
3150141Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 500, "Failed to allocate "
3151346Smax.romanov@nginx.com                              "req<->conn link");
3152141Smax.romanov@nginx.com 
3153141Smax.romanov@nginx.com         return;
315488Smax.romanov@nginx.com     }
315588Smax.romanov@nginx.com 
3156318Smax.romanov@nginx.com     rc->stream = nxt_port_rpc_ex_stream(rc);
3157318Smax.romanov@nginx.com     rc->conn = c;
3158318Smax.romanov@nginx.com 
3159318Smax.romanov@nginx.com     nxt_queue_insert_tail(&c->requests, &rc->link);
3160318Smax.romanov@nginx.com 
3161318Smax.romanov@nginx.com     nxt_debug(task, "stream #%uD linked to conn %p at engine %p",
3162318Smax.romanov@nginx.com               rc->stream, c, engine);
316353Sigor@sysoev.ru 
3164346Smax.romanov@nginx.com     rc->ap = ap;
3165346Smax.romanov@nginx.com     c->socket.data = NULL;
3166346Smax.romanov@nginx.com 
3167351Smax.romanov@nginx.com     ra = &ra_local;
3168351Smax.romanov@nginx.com     nxt_router_ra_init(task, ra, rc);
3169167Smax.romanov@nginx.com 
3170167Smax.romanov@nginx.com     res = nxt_router_app_port(task, ra);
3171141Smax.romanov@nginx.com 
3172141Smax.romanov@nginx.com     if (res != NXT_OK) {
3173141Smax.romanov@nginx.com         return;
3174141Smax.romanov@nginx.com     }
3175141Smax.romanov@nginx.com 
3176167Smax.romanov@nginx.com     port = ra->app_port;
3177141Smax.romanov@nginx.com 
3178141Smax.romanov@nginx.com     if (nxt_slow_path(port == NULL)) {
3179318Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 500, "Application port not found");
3180141Smax.romanov@nginx.com         return;
3181141Smax.romanov@nginx.com     }
3182141Smax.romanov@nginx.com 
3183318Smax.romanov@nginx.com     nxt_port_rpc_ex_set_peer(task, engine->port, rc, port->pid);
3184318Smax.romanov@nginx.com 
3185343Smax.romanov@nginx.com     nxt_router_process_http_request_mp(task, ra);
3186167Smax.romanov@nginx.com }
3187167Smax.romanov@nginx.com 
3188167Smax.romanov@nginx.com 
3189167Smax.romanov@nginx.com static void
3190343Smax.romanov@nginx.com nxt_router_process_http_request_mp(nxt_task_t *task, nxt_req_app_link_t *ra)
3191167Smax.romanov@nginx.com {
3192343Smax.romanov@nginx.com     uint32_t             request_failed;
3193167Smax.romanov@nginx.com     nxt_int_t            res;
3194343Smax.romanov@nginx.com     nxt_port_t           *port, *c_port, *reply_port;
3195167Smax.romanov@nginx.com     nxt_app_wmsg_t       wmsg;
3196167Smax.romanov@nginx.com     nxt_app_parse_ctx_t  *ap;
3197167Smax.romanov@nginx.com 
3198343Smax.romanov@nginx.com     nxt_assert(ra->app_port != NULL);
3199343Smax.romanov@nginx.com 
3200343Smax.romanov@nginx.com     port = ra->app_port;
3201167Smax.romanov@nginx.com     reply_port = ra->reply_port;
3202167Smax.romanov@nginx.com     ap = ra->ap;
3203141Smax.romanov@nginx.com 
3204343Smax.romanov@nginx.com     request_failed = 1;
3205343Smax.romanov@nginx.com 
3206141Smax.romanov@nginx.com     c_port = nxt_process_connected_port_find(port->process, reply_port->pid,
3207141Smax.romanov@nginx.com                                              reply_port->id);
3208141Smax.romanov@nginx.com     if (nxt_slow_path(c_port != reply_port)) {
3209141Smax.romanov@nginx.com         res = nxt_port_send_port(task, port, reply_port, 0);
3210122Smax.romanov@nginx.com 
3211122Smax.romanov@nginx.com         if (nxt_slow_path(res != NXT_OK)) {
3212345Smax.romanov@nginx.com             nxt_router_ra_error(task, ra, 500,
3213345Smax.romanov@nginx.com                                 "Failed to send reply port to application");
3214345Smax.romanov@nginx.com             ra = NULL;
3215343Smax.romanov@nginx.com             goto release_port;
3216122Smax.romanov@nginx.com         }
3217122Smax.romanov@nginx.com 
3218141Smax.romanov@nginx.com         nxt_process_connected_port_add(port->process, reply_port);
321988Smax.romanov@nginx.com     }
322088Smax.romanov@nginx.com 
322188Smax.romanov@nginx.com     wmsg.port = port;
322288Smax.romanov@nginx.com     wmsg.write = NULL;
322388Smax.romanov@nginx.com     wmsg.buf = &wmsg.write;
3224318Smax.romanov@nginx.com     wmsg.stream = ra->stream;
3225167Smax.romanov@nginx.com 
3226216Sigor@sysoev.ru     res = port->app->prepare_msg(task, &ap->r, &wmsg);
3227122Smax.romanov@nginx.com 
3228122Smax.romanov@nginx.com     if (nxt_slow_path(res != NXT_OK)) {
3229345Smax.romanov@nginx.com         nxt_router_ra_error(task, ra, 500,
3230345Smax.romanov@nginx.com                             "Failed to prepare message for application");
3231345Smax.romanov@nginx.com         ra = NULL;
3232343Smax.romanov@nginx.com         goto release_port;
3233122Smax.romanov@nginx.com     }
323488Smax.romanov@nginx.com 
323588Smax.romanov@nginx.com     nxt_debug(task, "about to send %d bytes buffer to worker port %d",
323688Smax.romanov@nginx.com                     nxt_buf_used_size(wmsg.write),
323788Smax.romanov@nginx.com                     wmsg.port->socket.fd);
323888Smax.romanov@nginx.com 
3239343Smax.romanov@nginx.com     request_failed = 0;
3240343Smax.romanov@nginx.com 
3241122Smax.romanov@nginx.com     res = nxt_port_socket_write(task, wmsg.port, NXT_PORT_MSG_DATA,
3242318Smax.romanov@nginx.com                                  -1, ra->stream, reply_port->id, wmsg.write);
3243122Smax.romanov@nginx.com 
3244122Smax.romanov@nginx.com     if (nxt_slow_path(res != NXT_OK)) {
3245345Smax.romanov@nginx.com         nxt_router_ra_error(task, ra, 500,
3246345Smax.romanov@nginx.com                             "Failed to send message to application");
3247345Smax.romanov@nginx.com         ra = NULL;
3248343Smax.romanov@nginx.com         goto release_port;
3249122Smax.romanov@nginx.com     }
3250343Smax.romanov@nginx.com 
3251343Smax.romanov@nginx.com release_port:
3252343Smax.romanov@nginx.com 
3253345Smax.romanov@nginx.com     nxt_router_app_port_release(task, port, request_failed, 0);
3254345Smax.romanov@nginx.com 
3255345Smax.romanov@nginx.com     if (ra != NULL) {
3256345Smax.romanov@nginx.com         if (request_failed != 0) {
3257345Smax.romanov@nginx.com             ra->app_port = 0;
3258345Smax.romanov@nginx.com         }
3259345Smax.romanov@nginx.com 
3260345Smax.romanov@nginx.com         nxt_router_ra_release(task, ra, ra->work.data);
3261343Smax.romanov@nginx.com     }
326253Sigor@sysoev.ru }
326353Sigor@sysoev.ru 
326453Sigor@sysoev.ru 
3265216Sigor@sysoev.ru static nxt_int_t
3266216Sigor@sysoev.ru nxt_python_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
3267216Sigor@sysoev.ru     nxt_app_wmsg_t *wmsg)
3268216Sigor@sysoev.ru {
3269216Sigor@sysoev.ru     nxt_int_t                 rc;
3270216Sigor@sysoev.ru     nxt_buf_t                 *b;
3271216Sigor@sysoev.ru     nxt_http_field_t          *field;
3272216Sigor@sysoev.ru     nxt_app_request_header_t  *h;
3273216Sigor@sysoev.ru 
3274216Sigor@sysoev.ru     static const nxt_str_t prefix = nxt_string("HTTP_");
3275216Sigor@sysoev.ru     static const nxt_str_t eof = nxt_null_string;
3276216Sigor@sysoev.ru 
3277216Sigor@sysoev.ru     h = &r->header;
3278216Sigor@sysoev.ru 
3279216Sigor@sysoev.ru #define RC(S)                                                                 \
3280216Sigor@sysoev.ru     do {                                                                      \
3281216Sigor@sysoev.ru         rc = (S);                                                             \
3282216Sigor@sysoev.ru         if (nxt_slow_path(rc != NXT_OK)) {                                    \
3283216Sigor@sysoev.ru             goto fail;                                                        \
3284216Sigor@sysoev.ru         }                                                                     \
3285216Sigor@sysoev.ru     } while(0)
3286216Sigor@sysoev.ru 
3287216Sigor@sysoev.ru #define NXT_WRITE(N)                                                          \
3288216Sigor@sysoev.ru     RC(nxt_app_msg_write_str(task, wmsg, N))
3289216Sigor@sysoev.ru 
3290216Sigor@sysoev.ru     /* TODO error handle, async mmap buffer assignment */
3291216Sigor@sysoev.ru 
3292216Sigor@sysoev.ru     NXT_WRITE(&h->method);
3293216Sigor@sysoev.ru     NXT_WRITE(&h->target);
3294277Sigor@sysoev.ru 
3295216Sigor@sysoev.ru     if (h->path.start == h->target.start) {
3296216Sigor@sysoev.ru         NXT_WRITE(&eof);
3297277Sigor@sysoev.ru 
3298216Sigor@sysoev.ru     } else {
3299216Sigor@sysoev.ru         NXT_WRITE(&h->path);
3300216Sigor@sysoev.ru     }
3301216Sigor@sysoev.ru 
3302216Sigor@sysoev.ru     if (h->query.start != NULL) {
3303216Sigor@sysoev.ru         RC(nxt_app_msg_write_size(task, wmsg,
3304216Sigor@sysoev.ru                                   h->query.start - h->target.start + 1));
3305216Sigor@sysoev.ru     } else {
3306216Sigor@sysoev.ru         RC(nxt_app_msg_write_size(task, wmsg, 0));
3307216Sigor@sysoev.ru     }
3308216Sigor@sysoev.ru 
3309216Sigor@sysoev.ru     NXT_WRITE(&h->version);
3310216Sigor@sysoev.ru 
3311216Sigor@sysoev.ru     NXT_WRITE(&r->remote);
3312268Sigor@sysoev.ru     NXT_WRITE(&r->local);
3313216Sigor@sysoev.ru 
3314216Sigor@sysoev.ru     NXT_WRITE(&h->host);
3315216Sigor@sysoev.ru     NXT_WRITE(&h->content_type);
3316216Sigor@sysoev.ru     NXT_WRITE(&h->content_length);
3317216Sigor@sysoev.ru 
3318216Sigor@sysoev.ru     nxt_list_each(field, h->fields) {
3319216Sigor@sysoev.ru         RC(nxt_app_msg_write_prefixed_upcase(task, wmsg,
3320216Sigor@sysoev.ru                                              &prefix, &field->name));
3321216Sigor@sysoev.ru         NXT_WRITE(&field->value);
3322216Sigor@sysoev.ru 
3323216Sigor@sysoev.ru     } nxt_list_loop;
3324216Sigor@sysoev.ru 
3325216Sigor@sysoev.ru     /* end-of-headers mark */
3326216Sigor@sysoev.ru     NXT_WRITE(&eof);
3327216Sigor@sysoev.ru 
3328216Sigor@sysoev.ru     RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size));
3329216Sigor@sysoev.ru 
3330216Sigor@sysoev.ru     for(b = r->body.buf; b != NULL; b = b->next) {
3331216Sigor@sysoev.ru         RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos,
3332216Sigor@sysoev.ru                                  nxt_buf_mem_used_size(&b->mem)));
3333216Sigor@sysoev.ru     }
3334216Sigor@sysoev.ru 
3335216Sigor@sysoev.ru #undef NXT_WRITE
3336216Sigor@sysoev.ru #undef RC
3337216Sigor@sysoev.ru 
3338216Sigor@sysoev.ru     return NXT_OK;
3339216Sigor@sysoev.ru 
3340216Sigor@sysoev.ru fail:
3341216Sigor@sysoev.ru 
3342216Sigor@sysoev.ru     return NXT_ERROR;
3343216Sigor@sysoev.ru }
3344216Sigor@sysoev.ru 
3345216Sigor@sysoev.ru 
3346216Sigor@sysoev.ru static nxt_int_t
3347216Sigor@sysoev.ru nxt_php_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
3348216Sigor@sysoev.ru     nxt_app_wmsg_t *wmsg)
3349216Sigor@sysoev.ru {
3350216Sigor@sysoev.ru     nxt_int_t                 rc;
3351216Sigor@sysoev.ru     nxt_buf_t                 *b;
3352305Smax.romanov@nginx.com     nxt_bool_t                method_is_post;
3353216Sigor@sysoev.ru     nxt_http_field_t          *field;
3354216Sigor@sysoev.ru     nxt_app_request_header_t  *h;
3355216Sigor@sysoev.ru 
3356216Sigor@sysoev.ru     static const nxt_str_t prefix = nxt_string("HTTP_");
3357216Sigor@sysoev.ru     static const nxt_str_t eof = nxt_null_string;
3358216Sigor@sysoev.ru 
3359216Sigor@sysoev.ru     h = &r->header;
3360216Sigor@sysoev.ru 
3361216Sigor@sysoev.ru #define RC(S)                                                                 \
3362216Sigor@sysoev.ru     do {                                                                      \
3363216Sigor@sysoev.ru         rc = (S);                                                             \
3364216Sigor@sysoev.ru         if (nxt_slow_path(rc != NXT_OK)) {                                    \
3365216Sigor@sysoev.ru             goto fail;                                                        \
3366216Sigor@sysoev.ru         }                                                                     \
3367216Sigor@sysoev.ru     } while(0)
3368216Sigor@sysoev.ru 
3369216Sigor@sysoev.ru #define NXT_WRITE(N)                                                          \
3370216Sigor@sysoev.ru     RC(nxt_app_msg_write_str(task, wmsg, N))
3371216Sigor@sysoev.ru 
3372216Sigor@sysoev.ru     /* TODO error handle, async mmap buffer assignment */
3373216Sigor@sysoev.ru 
3374216Sigor@sysoev.ru     NXT_WRITE(&h->method);
3375216Sigor@sysoev.ru     NXT_WRITE(&h->target);
3376277Sigor@sysoev.ru 
3377216Sigor@sysoev.ru     if (h->path.start == h->target.start) {
3378216Sigor@sysoev.ru         NXT_WRITE(&eof);
3379277Sigor@sysoev.ru 
3380216Sigor@sysoev.ru     } else {
3381216Sigor@sysoev.ru         NXT_WRITE(&h->path);
3382216Sigor@sysoev.ru     }
3383216Sigor@sysoev.ru 
3384216Sigor@sysoev.ru     if (h->query.start != NULL) {
3385216Sigor@sysoev.ru         RC(nxt_app_msg_write_size(task, wmsg,
3386216Sigor@sysoev.ru                                   h->query.start - h->target.start + 1));
3387216Sigor@sysoev.ru     } else {
3388216Sigor@sysoev.ru         RC(nxt_app_msg_write_size(task, wmsg, 0));
3389216Sigor@sysoev.ru     }
3390216Sigor@sysoev.ru 
3391216Sigor@sysoev.ru     NXT_WRITE(&h->version);
3392216Sigor@sysoev.ru 
3393216Sigor@sysoev.ru     // PHP_SELF
3394216Sigor@sysoev.ru     // SCRIPT_NAME
3395216Sigor@sysoev.ru     // SCRIPT_FILENAME
3396216Sigor@sysoev.ru     // DOCUMENT_ROOT
3397216Sigor@sysoev.ru 
3398216Sigor@sysoev.ru     NXT_WRITE(&r->remote);
3399268Sigor@sysoev.ru     NXT_WRITE(&r->local);
3400216Sigor@sysoev.ru 
3401216Sigor@sysoev.ru     NXT_WRITE(&h->host);
3402216Sigor@sysoev.ru     NXT_WRITE(&h->cookie);
3403216Sigor@sysoev.ru     NXT_WRITE(&h->content_type);
3404216Sigor@sysoev.ru     NXT_WRITE(&h->content_length);
3405216Sigor@sysoev.ru 
3406216Sigor@sysoev.ru     RC(nxt_app_msg_write_size(task, wmsg, h->parsed_content_length));
3407305Smax.romanov@nginx.com     RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size));
3408305Smax.romanov@nginx.com 
3409305Smax.romanov@nginx.com     method_is_post = h->method.length == 4 &&
3410305Smax.romanov@nginx.com                      h->method.start[0] == 'P' &&
3411305Smax.romanov@nginx.com                      h->method.start[1] == 'O' &&
3412305Smax.romanov@nginx.com                      h->method.start[2] == 'S' &&
3413305Smax.romanov@nginx.com                      h->method.start[3] == 'T';
3414305Smax.romanov@nginx.com 
3415305Smax.romanov@nginx.com     if (method_is_post) {
3416305Smax.romanov@nginx.com         for(b = r->body.buf; b != NULL; b = b->next) {
3417305Smax.romanov@nginx.com             RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos,
3418305Smax.romanov@nginx.com                                      nxt_buf_mem_used_size(&b->mem)));
3419305Smax.romanov@nginx.com         }
3420305Smax.romanov@nginx.com     }
3421216Sigor@sysoev.ru 
3422216Sigor@sysoev.ru     nxt_list_each(field, h->fields) {
3423216Sigor@sysoev.ru         RC(nxt_app_msg_write_prefixed_upcase(task, wmsg,
3424216Sigor@sysoev.ru                                              &prefix, &field->name));
3425216Sigor@sysoev.ru         NXT_WRITE(&field->value);
3426216Sigor@sysoev.ru 
3427216Sigor@sysoev.ru     } nxt_list_loop;
3428216Sigor@sysoev.ru 
3429216Sigor@sysoev.ru     /* end-of-headers mark */
3430216Sigor@sysoev.ru     NXT_WRITE(&eof);
3431216Sigor@sysoev.ru 
3432305Smax.romanov@nginx.com     if (!method_is_post) {
3433305Smax.romanov@nginx.com         for(b = r->body.buf; b != NULL; b = b->next) {
3434305Smax.romanov@nginx.com             RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos,
3435305Smax.romanov@nginx.com                                      nxt_buf_mem_used_size(&b->mem)));
3436305Smax.romanov@nginx.com         }
3437216Sigor@sysoev.ru     }
3438216Sigor@sysoev.ru 
3439216Sigor@sysoev.ru #undef NXT_WRITE
3440216Sigor@sysoev.ru #undef RC
3441216Sigor@sysoev.ru 
3442216Sigor@sysoev.ru     return NXT_OK;
3443216Sigor@sysoev.ru 
3444216Sigor@sysoev.ru fail:
3445216Sigor@sysoev.ru 
3446216Sigor@sysoev.ru     return NXT_ERROR;
3447216Sigor@sysoev.ru }
3448216Sigor@sysoev.ru 
3449216Sigor@sysoev.ru 
3450216Sigor@sysoev.ru static nxt_int_t
3451216Sigor@sysoev.ru nxt_go_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, nxt_app_wmsg_t *wmsg)
3452216Sigor@sysoev.ru {
3453216Sigor@sysoev.ru     nxt_int_t                 rc;
3454216Sigor@sysoev.ru     nxt_buf_t                 *b;
3455216Sigor@sysoev.ru     nxt_http_field_t          *field;
3456216Sigor@sysoev.ru     nxt_app_request_header_t  *h;
3457216Sigor@sysoev.ru 
3458216Sigor@sysoev.ru     static const nxt_str_t eof = nxt_null_string;
3459216Sigor@sysoev.ru 
3460216Sigor@sysoev.ru     h = &r->header;
3461216Sigor@sysoev.ru 
3462216Sigor@sysoev.ru #define RC(S)                                                                 \
3463216Sigor@sysoev.ru     do {                                                                      \
3464216Sigor@sysoev.ru         rc = (S);                                                             \
3465216Sigor@sysoev.ru         if (nxt_slow_path(rc != NXT_OK)) {                                    \
3466216Sigor@sysoev.ru             goto fail;                                                        \
3467216Sigor@sysoev.ru         }                                                                     \
3468216Sigor@sysoev.ru     } while(0)
3469216Sigor@sysoev.ru 
3470216Sigor@sysoev.ru #define NXT_WRITE(N)                                                          \
3471216Sigor@sysoev.ru     RC(nxt_app_msg_write_str(task, wmsg, N))
3472216Sigor@sysoev.ru 
3473216Sigor@sysoev.ru     /* TODO error handle, async mmap buffer assignment */
3474216Sigor@sysoev.ru 
3475216Sigor@sysoev.ru     NXT_WRITE(&h->method);
3476216Sigor@sysoev.ru     NXT_WRITE(&h->target);
3477277Sigor@sysoev.ru 
3478216Sigor@sysoev.ru     if (h->path.start == h->target.start) {
3479216Sigor@sysoev.ru         NXT_WRITE(&eof);
3480277Sigor@sysoev.ru 
3481216Sigor@sysoev.ru     } else {
3482216Sigor@sysoev.ru         NXT_WRITE(&h->path);
3483216Sigor@sysoev.ru     }
3484216Sigor@sysoev.ru 
3485216Sigor@sysoev.ru     if (h->query.start != NULL) {
3486216Sigor@sysoev.ru         RC(nxt_app_msg_write_size(task, wmsg,
3487216Sigor@sysoev.ru                                   h->query.start - h->target.start + 1));
3488216Sigor@sysoev.ru     } else {
3489216Sigor@sysoev.ru         RC(nxt_app_msg_write_size(task, wmsg, 0));
3490216Sigor@sysoev.ru     }
3491216Sigor@sysoev.ru 
3492216Sigor@sysoev.ru     NXT_WRITE(&h->version);
3493253Smax.romanov@nginx.com     NXT_WRITE(&r->remote);
3494216Sigor@sysoev.ru 
3495216Sigor@sysoev.ru     NXT_WRITE(&h->host);
3496216Sigor@sysoev.ru     NXT_WRITE(&h->cookie);
3497216Sigor@sysoev.ru     NXT_WRITE(&h->content_type);
3498216Sigor@sysoev.ru     NXT_WRITE(&h->content_length);
3499216Sigor@sysoev.ru 
3500216Sigor@sysoev.ru     RC(nxt_app_msg_write_size(task, wmsg, h->parsed_content_length));
3501216Sigor@sysoev.ru 
3502216Sigor@sysoev.ru     nxt_list_each(field, h->fields) {
3503216Sigor@sysoev.ru         NXT_WRITE(&field->name);
3504216Sigor@sysoev.ru         NXT_WRITE(&field->value);
3505216Sigor@sysoev.ru 
3506216Sigor@sysoev.ru     } nxt_list_loop;
3507216Sigor@sysoev.ru 
3508216Sigor@sysoev.ru     /* end-of-headers mark */
3509216Sigor@sysoev.ru     NXT_WRITE(&eof);
3510216Sigor@sysoev.ru 
3511216Sigor@sysoev.ru     RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size));
3512216Sigor@sysoev.ru 
3513216Sigor@sysoev.ru     for(b = r->body.buf; b != NULL; b = b->next) {
3514216Sigor@sysoev.ru         RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos,
3515216Sigor@sysoev.ru                                  nxt_buf_mem_used_size(&b->mem)));
3516216Sigor@sysoev.ru     }
3517216Sigor@sysoev.ru 
3518216Sigor@sysoev.ru #undef NXT_WRITE
3519216Sigor@sysoev.ru #undef RC
3520216Sigor@sysoev.ru 
3521216Sigor@sysoev.ru     return NXT_OK;
3522216Sigor@sysoev.ru 
3523216Sigor@sysoev.ru fail:
3524216Sigor@sysoev.ru 
3525216Sigor@sysoev.ru     return NXT_ERROR;
3526216Sigor@sysoev.ru }
3527216Sigor@sysoev.ru 
3528216Sigor@sysoev.ru 
352962Sigor@sysoev.ru static const nxt_conn_state_t  nxt_router_conn_close_state
353053Sigor@sysoev.ru     nxt_aligned(64) =
353153Sigor@sysoev.ru {
353253Sigor@sysoev.ru     .ready_handler = nxt_router_conn_free,
353353Sigor@sysoev.ru };
353453Sigor@sysoev.ru 
353553Sigor@sysoev.ru 
353653Sigor@sysoev.ru static void
353788Smax.romanov@nginx.com nxt_router_conn_ready(nxt_task_t *task, void *obj, void *data)
353888Smax.romanov@nginx.com {
353988Smax.romanov@nginx.com     nxt_buf_t         *b;
354088Smax.romanov@nginx.com     nxt_bool_t        last;
354188Smax.romanov@nginx.com     nxt_conn_t        *c;
354288Smax.romanov@nginx.com     nxt_work_queue_t  *wq;
354388Smax.romanov@nginx.com 
354488Smax.romanov@nginx.com     nxt_debug(task, "router conn ready %p", obj);
354588Smax.romanov@nginx.com 
354688Smax.romanov@nginx.com     c = obj;
354788Smax.romanov@nginx.com     b = c->write;
354888Smax.romanov@nginx.com 
354988Smax.romanov@nginx.com     wq = &task->thread->engine->fast_work_queue;
355088Smax.romanov@nginx.com 
355188Smax.romanov@nginx.com     last = 0;
355288Smax.romanov@nginx.com 
355388Smax.romanov@nginx.com     while (b != NULL) {
355488Smax.romanov@nginx.com         if (!nxt_buf_is_sync(b)) {
355588Smax.romanov@nginx.com             if (nxt_buf_used_size(b) > 0) {
355688Smax.romanov@nginx.com                 break;
355788Smax.romanov@nginx.com             }
355888Smax.romanov@nginx.com         }
355988Smax.romanov@nginx.com 
356088Smax.romanov@nginx.com         if (nxt_buf_is_last(b)) {
356188Smax.romanov@nginx.com             last = 1;
356288Smax.romanov@nginx.com         }
356388Smax.romanov@nginx.com 
356488Smax.romanov@nginx.com         nxt_work_queue_add(wq, b->completion_handler, task, b, b->parent);
356588Smax.romanov@nginx.com 
356688Smax.romanov@nginx.com         b = b->next;
356788Smax.romanov@nginx.com     }
356888Smax.romanov@nginx.com 
356988Smax.romanov@nginx.com     c->write = b;
357088Smax.romanov@nginx.com 
357188Smax.romanov@nginx.com     if (b != NULL) {
357288Smax.romanov@nginx.com         nxt_debug(task, "router conn %p has more data to write", obj);
357388Smax.romanov@nginx.com 
357488Smax.romanov@nginx.com         nxt_conn_write(task->thread->engine, c);
3575277Sigor@sysoev.ru 
357688Smax.romanov@nginx.com     } else {
357788Smax.romanov@nginx.com         nxt_debug(task, "router conn %p no more data to write, last = %d", obj,
357888Smax.romanov@nginx.com                   last);
357988Smax.romanov@nginx.com 
358088Smax.romanov@nginx.com         if (last != 0) {
358188Smax.romanov@nginx.com             nxt_debug(task, "enqueue router conn close %p (ready handler)", c);
358288Smax.romanov@nginx.com 
358388Smax.romanov@nginx.com             nxt_work_queue_add(wq, nxt_router_conn_close, task, c,
358488Smax.romanov@nginx.com                                c->socket.data);
358588Smax.romanov@nginx.com         }
358688Smax.romanov@nginx.com     }
358788Smax.romanov@nginx.com }
358888Smax.romanov@nginx.com 
358988Smax.romanov@nginx.com 
359088Smax.romanov@nginx.com static void
359153Sigor@sysoev.ru nxt_router_conn_close(nxt_task_t *task, void *obj, void *data)
359253Sigor@sysoev.ru {
359362Sigor@sysoev.ru     nxt_conn_t  *c;
359453Sigor@sysoev.ru 
359553Sigor@sysoev.ru     c = obj;
359653Sigor@sysoev.ru 
359753Sigor@sysoev.ru     nxt_debug(task, "router conn close");
359853Sigor@sysoev.ru 
359953Sigor@sysoev.ru     c->write_state = &nxt_router_conn_close_state;
360053Sigor@sysoev.ru 
360162Sigor@sysoev.ru     nxt_conn_close(task->thread->engine, c);
360253Sigor@sysoev.ru }
360353Sigor@sysoev.ru 
360453Sigor@sysoev.ru 
360553Sigor@sysoev.ru static void
3606164Smax.romanov@nginx.com nxt_router_conn_mp_cleanup(nxt_task_t *task, void *obj, void *data)
3607164Smax.romanov@nginx.com {
3608164Smax.romanov@nginx.com     nxt_socket_conf_joint_t  *joint;
3609164Smax.romanov@nginx.com 
3610164Smax.romanov@nginx.com     joint = obj;
3611164Smax.romanov@nginx.com 
3612164Smax.romanov@nginx.com     nxt_router_conf_release(task, joint);
3613164Smax.romanov@nginx.com }
3614164Smax.romanov@nginx.com 
3615164Smax.romanov@nginx.com 
3616164Smax.romanov@nginx.com static void
361753Sigor@sysoev.ru nxt_router_conn_free(nxt_task_t *task, void *obj, void *data)
361853Sigor@sysoev.ru {
361962Sigor@sysoev.ru     nxt_conn_t               *c;
3620337Sigor@sysoev.ru     nxt_event_engine_t       *engine;
362188Smax.romanov@nginx.com     nxt_req_conn_link_t      *rc;
3622319Smax.romanov@nginx.com     nxt_app_parse_ctx_t      *ap;
362353Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
362453Sigor@sysoev.ru 
362553Sigor@sysoev.ru     c = obj;
3626319Smax.romanov@nginx.com     ap = data;
362753Sigor@sysoev.ru 
362853Sigor@sysoev.ru     nxt_debug(task, "router conn close done");
362953Sigor@sysoev.ru 
3630319Smax.romanov@nginx.com     if (ap != NULL) {
3631319Smax.romanov@nginx.com         nxt_app_http_req_done(task, ap);
3632319Smax.romanov@nginx.com 
3633319Smax.romanov@nginx.com         c->socket.data = NULL;
3634319Smax.romanov@nginx.com     }
3635319Smax.romanov@nginx.com 
363688Smax.romanov@nginx.com     nxt_queue_each(rc, &c->requests, nxt_req_conn_link_t, link) {
363788Smax.romanov@nginx.com 
3638318Smax.romanov@nginx.com         nxt_debug(task, "conn %p close, stream #%uD", c, rc->stream);
363988Smax.romanov@nginx.com 
3640343Smax.romanov@nginx.com         nxt_router_rc_unlink(task, rc);
3641318Smax.romanov@nginx.com 
3642318Smax.romanov@nginx.com         nxt_port_rpc_cancel(task, task->thread->engine->port, rc->stream);
364388Smax.romanov@nginx.com 
364488Smax.romanov@nginx.com     } nxt_queue_loop;
364588Smax.romanov@nginx.com 
3646122Smax.romanov@nginx.com     nxt_queue_remove(&c->link);
3647122Smax.romanov@nginx.com 
3648337Sigor@sysoev.ru     engine = task->thread->engine;
3649337Sigor@sysoev.ru 
3650337Sigor@sysoev.ru     nxt_sockaddr_cache_free(engine, c);
3651337Sigor@sysoev.ru 
3652*359Sigor@sysoev.ru     joint = c->joint;
3653131Smax.romanov@nginx.com 
3654337Sigor@sysoev.ru     nxt_mp_cleanup(c->mem_pool, nxt_router_conn_mp_cleanup,
3655337Sigor@sysoev.ru                    &engine->task, joint, NULL);
3656164Smax.romanov@nginx.com 
3657164Smax.romanov@nginx.com     nxt_mp_release(c->mem_pool, c);
365853Sigor@sysoev.ru }
365953Sigor@sysoev.ru 
366053Sigor@sysoev.ru 
366153Sigor@sysoev.ru static void
366253Sigor@sysoev.ru nxt_router_conn_error(nxt_task_t *task, void *obj, void *data)
366353Sigor@sysoev.ru {
366462Sigor@sysoev.ru     nxt_conn_t  *c;
366553Sigor@sysoev.ru 
366653Sigor@sysoev.ru     c = obj;
366753Sigor@sysoev.ru 
366853Sigor@sysoev.ru     nxt_debug(task, "router conn error");
366953Sigor@sysoev.ru 
3670273Smax.romanov@nginx.com     if (c->socket.fd != -1) {
3671273Smax.romanov@nginx.com         c->write_state = &nxt_router_conn_close_state;
3672273Smax.romanov@nginx.com 
3673273Smax.romanov@nginx.com         nxt_conn_close(task->thread->engine, c);
3674273Smax.romanov@nginx.com     }
367553Sigor@sysoev.ru }
367653Sigor@sysoev.ru 
367753Sigor@sysoev.ru 
367853Sigor@sysoev.ru static void
367953Sigor@sysoev.ru nxt_router_conn_timeout(nxt_task_t *task, void *obj, void *data)
368053Sigor@sysoev.ru {
368162Sigor@sysoev.ru     nxt_conn_t   *c;
368262Sigor@sysoev.ru     nxt_timer_t  *timer;
368353Sigor@sysoev.ru 
368453Sigor@sysoev.ru     timer = obj;
368553Sigor@sysoev.ru 
368653Sigor@sysoev.ru     nxt_debug(task, "router conn timeout");
368753Sigor@sysoev.ru 
368862Sigor@sysoev.ru     c = nxt_read_timer_conn(timer);
368953Sigor@sysoev.ru 
3690206Smax.romanov@nginx.com     if (c->read_state == &nxt_router_conn_read_header_state) {
3691206Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 408, "Read header timeout");
3692206Smax.romanov@nginx.com 
3693206Smax.romanov@nginx.com     } else {
3694206Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 408, "Read body timeout");
3695206Smax.romanov@nginx.com     }
369653Sigor@sysoev.ru }
369753Sigor@sysoev.ru 
369853Sigor@sysoev.ru 
3699318Smax.romanov@nginx.com static void
3700318Smax.romanov@nginx.com nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data)
3701318Smax.romanov@nginx.com {
3702318Smax.romanov@nginx.com     nxt_conn_t   *c;
3703318Smax.romanov@nginx.com     nxt_timer_t  *timer;
3704318Smax.romanov@nginx.com 
3705318Smax.romanov@nginx.com     timer = obj;
3706318Smax.romanov@nginx.com 
3707318Smax.romanov@nginx.com     nxt_debug(task, "router app timeout");
3708318Smax.romanov@nginx.com 
3709318Smax.romanov@nginx.com     c = nxt_read_timer_conn(timer);
3710318Smax.romanov@nginx.com 
3711318Smax.romanov@nginx.com     nxt_router_gen_error(task, c, 408, "Application timeout");
3712318Smax.romanov@nginx.com }
3713318Smax.romanov@nginx.com 
3714318Smax.romanov@nginx.com 
371553Sigor@sysoev.ru static nxt_msec_t
371662Sigor@sysoev.ru nxt_router_conn_timeout_value(nxt_conn_t *c, uintptr_t data)
371753Sigor@sysoev.ru {
371853Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
371953Sigor@sysoev.ru 
3720*359Sigor@sysoev.ru     joint = c->joint;
372153Sigor@sysoev.ru 
372253Sigor@sysoev.ru     return nxt_value_at(nxt_msec_t, joint->socket_conf, data);
372353Sigor@sysoev.ru }
3724