xref: /unit/src/nxt_router.c (revision 264)
120Sigor@sysoev.ru 
220Sigor@sysoev.ru /*
320Sigor@sysoev.ru  * Copyright (C) Igor Sysoev
420Sigor@sysoev.ru  * Copyright (C) Valentin V. Bartenev
520Sigor@sysoev.ru  * Copyright (C) NGINX, Inc.
620Sigor@sysoev.ru  */
720Sigor@sysoev.ru 
853Sigor@sysoev.ru #include <nxt_router.h>
9115Sigor@sysoev.ru #include <nxt_conf.h>
1020Sigor@sysoev.ru 
1120Sigor@sysoev.ru 
12115Sigor@sysoev.ru typedef struct {
13133Sigor@sysoev.ru     nxt_str_t  type;
14133Sigor@sysoev.ru     uint32_t   workers;
15133Sigor@sysoev.ru } nxt_router_app_conf_t;
16133Sigor@sysoev.ru 
17133Sigor@sysoev.ru 
18133Sigor@sysoev.ru typedef struct {
19133Sigor@sysoev.ru     nxt_str_t  application;
20115Sigor@sysoev.ru } nxt_router_listener_conf_t;
21115Sigor@sysoev.ru 
22115Sigor@sysoev.ru 
23167Smax.romanov@nginx.com typedef struct nxt_req_app_link_s nxt_req_app_link_t;
24141Smax.romanov@nginx.com typedef struct nxt_start_worker_s nxt_start_worker_t;
25141Smax.romanov@nginx.com 
26141Smax.romanov@nginx.com struct nxt_start_worker_s {
27141Smax.romanov@nginx.com     nxt_app_t              *app;
28167Smax.romanov@nginx.com     nxt_req_app_link_t     *ra;
29141Smax.romanov@nginx.com 
30141Smax.romanov@nginx.com     nxt_work_t             work;
31141Smax.romanov@nginx.com };
32141Smax.romanov@nginx.com 
33141Smax.romanov@nginx.com 
34167Smax.romanov@nginx.com struct nxt_req_app_link_s {
35167Smax.romanov@nginx.com     nxt_req_id_t         req_id;
36167Smax.romanov@nginx.com     nxt_port_t           *app_port;
37167Smax.romanov@nginx.com     nxt_port_t           *reply_port;
38167Smax.romanov@nginx.com     nxt_app_parse_ctx_t  *ap;
39167Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
40167Smax.romanov@nginx.com 
41167Smax.romanov@nginx.com     nxt_queue_link_t     link; /* for nxt_app_t.requests */
42167Smax.romanov@nginx.com 
43167Smax.romanov@nginx.com     nxt_mp_t             *mem_pool;
44167Smax.romanov@nginx.com     nxt_work_t           work;
45167Smax.romanov@nginx.com };
46167Smax.romanov@nginx.com 
47167Smax.romanov@nginx.com 
48198Sigor@sysoev.ru typedef struct {
49198Sigor@sysoev.ru     nxt_socket_conf_t       *socket_conf;
50198Sigor@sysoev.ru     nxt_router_temp_conf_t  *temp_conf;
51198Sigor@sysoev.ru } nxt_socket_rpc_t;
52198Sigor@sysoev.ru 
53198Sigor@sysoev.ru 
54139Sigor@sysoev.ru static nxt_router_temp_conf_t *nxt_router_temp_conf(nxt_task_t *task);
55198Sigor@sysoev.ru static void nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data);
56198Sigor@sysoev.ru static void nxt_router_conf_ready(nxt_task_t *task,
57139Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
58139Sigor@sysoev.ru static void nxt_router_conf_error(nxt_task_t *task,
59139Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
60139Sigor@sysoev.ru static void nxt_router_conf_send(nxt_task_t *task,
61193Smax.romanov@nginx.com     nxt_router_temp_conf_t *tmcf, nxt_port_msg_type_t type);
6253Sigor@sysoev.ru static void nxt_router_listen_sockets_sort(nxt_router_t *router,
6353Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
6453Sigor@sysoev.ru 
65115Sigor@sysoev.ru static nxt_int_t nxt_router_conf_create(nxt_task_t *task,
66115Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, u_char *start, u_char *end);
67133Sigor@sysoev.ru static nxt_app_t *nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name);
68133Sigor@sysoev.ru static nxt_app_t *nxt_router_listener_application(nxt_router_temp_conf_t *tmcf,
69133Sigor@sysoev.ru     nxt_str_t *name);
70198Sigor@sysoev.ru static void nxt_router_listen_socket_rpc_create(nxt_task_t *task,
71198Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf);
72198Sigor@sysoev.ru static void nxt_router_listen_socket_ready(nxt_task_t *task,
73198Sigor@sysoev.ru     nxt_port_recv_msg_t *msg, void *data);
74198Sigor@sysoev.ru static void nxt_router_listen_socket_error(nxt_task_t *task,
75198Sigor@sysoev.ru     nxt_port_recv_msg_t *msg, void *data);
7665Sigor@sysoev.ru static nxt_socket_conf_t *nxt_router_socket_conf(nxt_task_t *task, nxt_mp_t *mp,
7765Sigor@sysoev.ru     nxt_sockaddr_t *sa);
7853Sigor@sysoev.ru 
7953Sigor@sysoev.ru static nxt_int_t nxt_router_engines_create(nxt_task_t *task,
8053Sigor@sysoev.ru     nxt_router_t *router, nxt_router_temp_conf_t *tmcf,
8153Sigor@sysoev.ru     const nxt_event_interface_t *interface);
82115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf,
83115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
84115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf,
85115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
86115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf,
87115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
88115Sigor@sysoev.ru static void nxt_router_engine_socket_count(nxt_queue_t *sockets);
89154Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf,
90154Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets,
91154Sigor@sysoev.ru     nxt_work_handler_t handler);
92139Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf,
93139Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets);
9453Sigor@sysoev.ru 
9553Sigor@sysoev.ru static nxt_int_t nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt,
9653Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
9753Sigor@sysoev.ru static nxt_int_t nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt,
9853Sigor@sysoev.ru     nxt_event_engine_t *engine);
99133Sigor@sysoev.ru static void nxt_router_apps_sort(nxt_router_t *router,
100133Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
10153Sigor@sysoev.ru 
10253Sigor@sysoev.ru static void nxt_router_engines_post(nxt_router_temp_conf_t *tmcf);
103154Sigor@sysoev.ru static void nxt_router_engine_post(nxt_router_engine_conf_t *recf);
10453Sigor@sysoev.ru 
10553Sigor@sysoev.ru static void nxt_router_thread_start(void *data);
10653Sigor@sysoev.ru static void nxt_router_listen_socket_create(nxt_task_t *task, void *obj,
10753Sigor@sysoev.ru     void *data);
10853Sigor@sysoev.ru static void nxt_router_listen_socket_update(nxt_task_t *task, void *obj,
10953Sigor@sysoev.ru     void *data);
11053Sigor@sysoev.ru static void nxt_router_listen_socket_delete(nxt_task_t *task, void *obj,
11153Sigor@sysoev.ru     void *data);
11253Sigor@sysoev.ru static void nxt_router_listen_socket_close(nxt_task_t *task, void *obj,
11353Sigor@sysoev.ru     void *data);
11453Sigor@sysoev.ru static void nxt_router_listen_socket_release(nxt_task_t *task,
11553Sigor@sysoev.ru     nxt_socket_conf_joint_t *joint);
11653Sigor@sysoev.ru static void nxt_router_thread_exit_handler(nxt_task_t *task, void *obj,
11753Sigor@sysoev.ru     void *data);
11853Sigor@sysoev.ru static void nxt_router_conf_release(nxt_task_t *task,
11953Sigor@sysoev.ru     nxt_socket_conf_joint_t *joint);
12053Sigor@sysoev.ru 
121167Smax.romanov@nginx.com static void nxt_router_send_sw_request(nxt_task_t *task, void *obj,
122167Smax.romanov@nginx.com     void *data);
123167Smax.romanov@nginx.com static nxt_bool_t nxt_router_app_free(nxt_task_t *task, nxt_app_t *app);
124167Smax.romanov@nginx.com static nxt_port_t * nxt_router_app_get_port(nxt_app_t *app, uint32_t req_id);
125141Smax.romanov@nginx.com static void nxt_router_app_release_port(nxt_task_t *task, void *obj,
126141Smax.romanov@nginx.com     void *data);
127141Smax.romanov@nginx.com 
12853Sigor@sysoev.ru static void nxt_router_conn_init(nxt_task_t *task, void *obj, void *data);
12953Sigor@sysoev.ru static void nxt_router_conn_http_header_parse(nxt_task_t *task, void *obj,
13053Sigor@sysoev.ru     void *data);
131206Smax.romanov@nginx.com static void nxt_router_conn_http_body_read(nxt_task_t *task, void *obj,
132206Smax.romanov@nginx.com     void *data);
13388Smax.romanov@nginx.com static void nxt_router_process_http_request(nxt_task_t *task,
13488Smax.romanov@nginx.com     nxt_conn_t *c, nxt_app_parse_ctx_t *ap);
135141Smax.romanov@nginx.com static void nxt_router_process_http_request_mp(nxt_task_t *task,
136167Smax.romanov@nginx.com     nxt_req_app_link_t *ra, nxt_port_t *port);
137216Sigor@sysoev.ru static nxt_int_t nxt_python_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
138216Sigor@sysoev.ru     nxt_app_wmsg_t *wmsg);
139216Sigor@sysoev.ru static nxt_int_t nxt_php_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
140216Sigor@sysoev.ru     nxt_app_wmsg_t *wmsg);
141216Sigor@sysoev.ru static nxt_int_t nxt_go_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
142216Sigor@sysoev.ru     nxt_app_wmsg_t *wmsg);
14388Smax.romanov@nginx.com static void nxt_router_conn_ready(nxt_task_t *task, void *obj, void *data);
14453Sigor@sysoev.ru static void nxt_router_conn_close(nxt_task_t *task, void *obj, void *data);
14553Sigor@sysoev.ru static void nxt_router_conn_free(nxt_task_t *task, void *obj, void *data);
14653Sigor@sysoev.ru static void nxt_router_conn_error(nxt_task_t *task, void *obj, void *data);
14753Sigor@sysoev.ru static void nxt_router_conn_timeout(nxt_task_t *task, void *obj, void *data);
14862Sigor@sysoev.ru static nxt_msec_t nxt_router_conn_timeout_value(nxt_conn_t *c, uintptr_t data);
14920Sigor@sysoev.ru 
150141Smax.romanov@nginx.com static void nxt_router_gen_error(nxt_task_t *task, nxt_conn_t *c, int code,
151141Smax.romanov@nginx.com     const char* fmt, ...);
152141Smax.romanov@nginx.com 
153119Smax.romanov@nginx.com static nxt_router_t  *nxt_router;
15420Sigor@sysoev.ru 
155216Sigor@sysoev.ru 
156216Sigor@sysoev.ru static nxt_app_prepare_msg_t  nxt_app_prepare_msg[] = {
157216Sigor@sysoev.ru     nxt_python_prepare_msg,
158216Sigor@sysoev.ru     nxt_php_prepare_msg,
159216Sigor@sysoev.ru     nxt_go_prepare_msg,
160216Sigor@sysoev.ru };
161216Sigor@sysoev.ru 
162216Sigor@sysoev.ru 
16320Sigor@sysoev.ru nxt_int_t
164141Smax.romanov@nginx.com nxt_router_start(nxt_task_t *task, void *data)
16520Sigor@sysoev.ru {
166141Smax.romanov@nginx.com     nxt_int_t      ret;
167141Smax.romanov@nginx.com     nxt_router_t   *router;
168141Smax.romanov@nginx.com     nxt_runtime_t  *rt;
169141Smax.romanov@nginx.com 
170141Smax.romanov@nginx.com     rt = task->thread->runtime;
17153Sigor@sysoev.ru 
17288Smax.romanov@nginx.com     ret = nxt_app_http_init(task, rt);
17388Smax.romanov@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
17488Smax.romanov@nginx.com         return ret;
17588Smax.romanov@nginx.com     }
17688Smax.romanov@nginx.com 
17753Sigor@sysoev.ru     router = nxt_zalloc(sizeof(nxt_router_t));
17853Sigor@sysoev.ru     if (nxt_slow_path(router == NULL)) {
17953Sigor@sysoev.ru         return NXT_ERROR;
18053Sigor@sysoev.ru     }
18153Sigor@sysoev.ru 
18253Sigor@sysoev.ru     nxt_queue_init(&router->engines);
18353Sigor@sysoev.ru     nxt_queue_init(&router->sockets);
184133Sigor@sysoev.ru     nxt_queue_init(&router->apps);
18553Sigor@sysoev.ru 
186119Smax.romanov@nginx.com     nxt_router = router;
187119Smax.romanov@nginx.com 
188115Sigor@sysoev.ru     return NXT_OK;
189115Sigor@sysoev.ru }
190115Sigor@sysoev.ru 
191115Sigor@sysoev.ru 
192167Smax.romanov@nginx.com static nxt_start_worker_t *
193192Smax.romanov@nginx.com nxt_router_sw_create(nxt_task_t *task, nxt_app_t *app, nxt_req_app_link_t *ra)
194167Smax.romanov@nginx.com {
195240Sigor@sysoev.ru     nxt_port_t          *main_port;
196167Smax.romanov@nginx.com     nxt_runtime_t       *rt;
197167Smax.romanov@nginx.com     nxt_start_worker_t  *sw;
198167Smax.romanov@nginx.com 
199192Smax.romanov@nginx.com     sw = nxt_zalloc(sizeof(nxt_start_worker_t));
200167Smax.romanov@nginx.com 
201167Smax.romanov@nginx.com     if (nxt_slow_path(sw == NULL)) {
202167Smax.romanov@nginx.com         return NULL;
203167Smax.romanov@nginx.com     }
204167Smax.romanov@nginx.com 
205167Smax.romanov@nginx.com     sw->app = app;
206167Smax.romanov@nginx.com     sw->ra = ra;
207167Smax.romanov@nginx.com 
208192Smax.romanov@nginx.com     nxt_debug(task, "sw %p create, request #%uxD, app '%V' %p", sw,
209167Smax.romanov@nginx.com                     ra->req_id, &app->name, app);
210167Smax.romanov@nginx.com 
211167Smax.romanov@nginx.com     rt = task->thread->runtime;
212240Sigor@sysoev.ru     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
213167Smax.romanov@nginx.com 
214167Smax.romanov@nginx.com     sw->work.handler = nxt_router_send_sw_request;
215240Sigor@sysoev.ru     sw->work.task = &main_port->engine->task;
216167Smax.romanov@nginx.com     sw->work.obj = sw;
217167Smax.romanov@nginx.com     sw->work.data = task->thread->engine;
218167Smax.romanov@nginx.com     sw->work.next = NULL;
219167Smax.romanov@nginx.com 
220240Sigor@sysoev.ru     if (task->thread->engine != main_port->engine) {
221240Sigor@sysoev.ru         nxt_debug(task, "sw %p post send to main engine %p", sw,
222240Sigor@sysoev.ru                   main_port->engine);
223240Sigor@sysoev.ru 
224240Sigor@sysoev.ru         nxt_event_engine_post(main_port->engine, &sw->work);
225167Smax.romanov@nginx.com 
226167Smax.romanov@nginx.com     } else {
227167Smax.romanov@nginx.com         nxt_router_send_sw_request(task, sw, sw->work.data);
228167Smax.romanov@nginx.com     }
229167Smax.romanov@nginx.com 
230167Smax.romanov@nginx.com     return sw;
231167Smax.romanov@nginx.com }
232167Smax.romanov@nginx.com 
233167Smax.romanov@nginx.com 
234192Smax.romanov@nginx.com nxt_inline void
235192Smax.romanov@nginx.com nxt_router_sw_release(nxt_task_t *task, nxt_start_worker_t *sw)
236141Smax.romanov@nginx.com {
237192Smax.romanov@nginx.com     nxt_debug(task, "sw %p release", sw);
238192Smax.romanov@nginx.com 
239192Smax.romanov@nginx.com     nxt_free(sw);
240141Smax.romanov@nginx.com }
241141Smax.romanov@nginx.com 
242141Smax.romanov@nginx.com 
243167Smax.romanov@nginx.com static nxt_req_app_link_t *
244167Smax.romanov@nginx.com nxt_router_ra_create(nxt_task_t *task, nxt_req_conn_link_t *rc)
245167Smax.romanov@nginx.com {
246167Smax.romanov@nginx.com     nxt_mp_t            *mp;
247167Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
248167Smax.romanov@nginx.com 
249167Smax.romanov@nginx.com     mp = rc->conn->mem_pool;
250167Smax.romanov@nginx.com 
251167Smax.romanov@nginx.com     ra = nxt_mp_retain(mp, sizeof(nxt_req_app_link_t));
252167Smax.romanov@nginx.com 
253167Smax.romanov@nginx.com     if (nxt_slow_path(ra == NULL)) {
254167Smax.romanov@nginx.com         return NULL;
255167Smax.romanov@nginx.com     }
256167Smax.romanov@nginx.com 
257167Smax.romanov@nginx.com     nxt_debug(task, "ra #%uxD create", ra->req_id);
258167Smax.romanov@nginx.com 
259167Smax.romanov@nginx.com     nxt_memzero(ra, sizeof(nxt_req_app_link_t));
260167Smax.romanov@nginx.com 
261167Smax.romanov@nginx.com     ra->req_id = rc->req_id;
262167Smax.romanov@nginx.com     ra->app_port = NULL;
263167Smax.romanov@nginx.com     ra->rc = rc;
264167Smax.romanov@nginx.com 
265167Smax.romanov@nginx.com     ra->mem_pool = mp;
266167Smax.romanov@nginx.com 
267167Smax.romanov@nginx.com     ra->work.handler = NULL;
268167Smax.romanov@nginx.com     ra->work.task = &task->thread->engine->task;
269167Smax.romanov@nginx.com     ra->work.obj = ra;
270167Smax.romanov@nginx.com     ra->work.data = task->thread->engine;
271167Smax.romanov@nginx.com 
272167Smax.romanov@nginx.com     return ra;
273167Smax.romanov@nginx.com }
274167Smax.romanov@nginx.com 
275167Smax.romanov@nginx.com 
276167Smax.romanov@nginx.com static void
277167Smax.romanov@nginx.com nxt_router_ra_release(nxt_task_t *task, void *obj, void *data)
278167Smax.romanov@nginx.com {
279167Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
280167Smax.romanov@nginx.com     nxt_event_engine_t  *engine;
281167Smax.romanov@nginx.com 
282167Smax.romanov@nginx.com     ra = obj;
283167Smax.romanov@nginx.com     engine = data;
284167Smax.romanov@nginx.com 
285167Smax.romanov@nginx.com     if (task->thread->engine != engine) {
286167Smax.romanov@nginx.com         ra->work.handler = nxt_router_ra_release;
287167Smax.romanov@nginx.com         ra->work.task = &engine->task;
288167Smax.romanov@nginx.com         ra->work.next = NULL;
289167Smax.romanov@nginx.com 
290167Smax.romanov@nginx.com         nxt_debug(task, "ra #%uxD post release to %p", ra->req_id, engine);
291167Smax.romanov@nginx.com 
292167Smax.romanov@nginx.com         nxt_event_engine_post(engine, &ra->work);
293167Smax.romanov@nginx.com 
294167Smax.romanov@nginx.com         return;
295167Smax.romanov@nginx.com     }
296167Smax.romanov@nginx.com 
297167Smax.romanov@nginx.com     nxt_debug(task, "ra #%uxD release", ra->req_id);
298167Smax.romanov@nginx.com 
299167Smax.romanov@nginx.com     if (ra->app_port != NULL) {
300167Smax.romanov@nginx.com 
301*264Smax.romanov@nginx.com         nxt_router_app_release_port(task, ra->app_port, ra->app_port->app);
302*264Smax.romanov@nginx.com 
303*264Smax.romanov@nginx.com #if 0
304*264Smax.romanov@nginx.com         /* Uncomment to hold app port until complete response received. */
305167Smax.romanov@nginx.com         if (ra->rc->conn != NULL) {
306167Smax.romanov@nginx.com             ra->rc->app_port = ra->app_port;
307167Smax.romanov@nginx.com 
308167Smax.romanov@nginx.com         } else {
309167Smax.romanov@nginx.com             nxt_router_app_release_port(task, ra->app_port, ra->app_port->app);
310167Smax.romanov@nginx.com         }
311*264Smax.romanov@nginx.com #endif
312167Smax.romanov@nginx.com     }
313167Smax.romanov@nginx.com 
314167Smax.romanov@nginx.com     nxt_mp_release(ra->mem_pool, ra);
315167Smax.romanov@nginx.com }
316167Smax.romanov@nginx.com 
317167Smax.romanov@nginx.com 
318141Smax.romanov@nginx.com void
319141Smax.romanov@nginx.com nxt_router_new_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
320141Smax.romanov@nginx.com {
321141Smax.romanov@nginx.com     nxt_port_new_port_handler(task, msg);
322141Smax.romanov@nginx.com 
323192Smax.romanov@nginx.com     if (msg->port_msg.stream == 0) {
324141Smax.romanov@nginx.com         return;
325141Smax.romanov@nginx.com     }
326141Smax.romanov@nginx.com 
327192Smax.romanov@nginx.com     if (msg->new_port == NULL || msg->new_port->type != NXT_PROCESS_WORKER) {
328192Smax.romanov@nginx.com         msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR;
329141Smax.romanov@nginx.com     }
330192Smax.romanov@nginx.com 
331192Smax.romanov@nginx.com     nxt_port_rpc_handler(task, msg);
332141Smax.romanov@nginx.com }
333141Smax.romanov@nginx.com 
334141Smax.romanov@nginx.com 
335139Sigor@sysoev.ru void
336139Sigor@sysoev.ru nxt_router_conf_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
337115Sigor@sysoev.ru {
338139Sigor@sysoev.ru     size_t                  dump_size;
339198Sigor@sysoev.ru     nxt_int_t               ret;
340139Sigor@sysoev.ru     nxt_buf_t               *b;
341139Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
342139Sigor@sysoev.ru 
343139Sigor@sysoev.ru     b = msg->buf;
344139Sigor@sysoev.ru 
345139Sigor@sysoev.ru     dump_size = nxt_buf_used_size(b);
346139Sigor@sysoev.ru 
347139Sigor@sysoev.ru     if (dump_size > 300) {
348139Sigor@sysoev.ru         dump_size = 300;
34953Sigor@sysoev.ru     }
35053Sigor@sysoev.ru 
351139Sigor@sysoev.ru     nxt_debug(task, "router conf data (%z): %*s",
352139Sigor@sysoev.ru               msg->size, dump_size, b->mem.pos);
353139Sigor@sysoev.ru 
354139Sigor@sysoev.ru     tmcf = nxt_router_temp_conf(task);
355139Sigor@sysoev.ru     if (nxt_slow_path(tmcf == NULL)) {
356139Sigor@sysoev.ru         return;
35753Sigor@sysoev.ru     }
35853Sigor@sysoev.ru 
359139Sigor@sysoev.ru     tmcf->conf->router = nxt_router;
360139Sigor@sysoev.ru     tmcf->stream = msg->port_msg.stream;
361139Sigor@sysoev.ru     tmcf->port = nxt_runtime_port_find(task->thread->runtime,
362198Sigor@sysoev.ru                                        msg->port_msg.pid,
363198Sigor@sysoev.ru                                        msg->port_msg.reply_port);
364198Sigor@sysoev.ru 
365198Sigor@sysoev.ru     ret = nxt_router_conf_create(task, tmcf, b->mem.pos, b->mem.free);
366198Sigor@sysoev.ru 
367198Sigor@sysoev.ru     if (nxt_fast_path(ret == NXT_OK)) {
368198Sigor@sysoev.ru         nxt_router_conf_apply(task, tmcf, NULL);
369198Sigor@sysoev.ru 
370198Sigor@sysoev.ru     } else {
371198Sigor@sysoev.ru         nxt_router_conf_error(task, tmcf);
372139Sigor@sysoev.ru     }
37353Sigor@sysoev.ru }
37453Sigor@sysoev.ru 
37553Sigor@sysoev.ru 
376192Smax.romanov@nginx.com void
377192Smax.romanov@nginx.com nxt_router_remove_pid_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
378192Smax.romanov@nginx.com {
379192Smax.romanov@nginx.com     nxt_port_remove_pid_handler(task, msg);
380192Smax.romanov@nginx.com 
381192Smax.romanov@nginx.com     if (msg->port_msg.stream == 0) {
382192Smax.romanov@nginx.com         return;
383192Smax.romanov@nginx.com     }
384192Smax.romanov@nginx.com 
385192Smax.romanov@nginx.com     msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR;
386192Smax.romanov@nginx.com 
387192Smax.romanov@nginx.com     nxt_port_rpc_handler(task, msg);
388192Smax.romanov@nginx.com }
389192Smax.romanov@nginx.com 
390192Smax.romanov@nginx.com 
39153Sigor@sysoev.ru static nxt_router_temp_conf_t *
392139Sigor@sysoev.ru nxt_router_temp_conf(nxt_task_t *task)
39353Sigor@sysoev.ru {
39465Sigor@sysoev.ru     nxt_mp_t                *mp, *tmp;
39553Sigor@sysoev.ru     nxt_router_conf_t       *rtcf;
39653Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
39753Sigor@sysoev.ru 
39865Sigor@sysoev.ru     mp = nxt_mp_create(1024, 128, 256, 32);
39953Sigor@sysoev.ru     if (nxt_slow_path(mp == NULL)) {
40053Sigor@sysoev.ru         return NULL;
40153Sigor@sysoev.ru     }
40253Sigor@sysoev.ru 
40365Sigor@sysoev.ru     rtcf = nxt_mp_zget(mp, sizeof(nxt_router_conf_t));
40453Sigor@sysoev.ru     if (nxt_slow_path(rtcf == NULL)) {
40553Sigor@sysoev.ru         goto fail;
40653Sigor@sysoev.ru     }
40753Sigor@sysoev.ru 
40853Sigor@sysoev.ru     rtcf->mem_pool = mp;
40953Sigor@sysoev.ru 
41065Sigor@sysoev.ru     tmp = nxt_mp_create(1024, 128, 256, 32);
41153Sigor@sysoev.ru     if (nxt_slow_path(tmp == NULL)) {
41253Sigor@sysoev.ru         goto fail;
41353Sigor@sysoev.ru     }
41453Sigor@sysoev.ru 
41565Sigor@sysoev.ru     tmcf = nxt_mp_zget(tmp, sizeof(nxt_router_temp_conf_t));
41653Sigor@sysoev.ru     if (nxt_slow_path(tmcf == NULL)) {
41753Sigor@sysoev.ru         goto temp_fail;
41853Sigor@sysoev.ru     }
41953Sigor@sysoev.ru 
42053Sigor@sysoev.ru     tmcf->mem_pool = tmp;
42153Sigor@sysoev.ru     tmcf->conf = rtcf;
422139Sigor@sysoev.ru     tmcf->count = 1;
423139Sigor@sysoev.ru     tmcf->engine = task->thread->engine;
42453Sigor@sysoev.ru 
42553Sigor@sysoev.ru     tmcf->engines = nxt_array_create(tmcf->mem_pool, 4,
42653Sigor@sysoev.ru                                      sizeof(nxt_router_engine_conf_t));
42753Sigor@sysoev.ru     if (nxt_slow_path(tmcf->engines == NULL)) {
42853Sigor@sysoev.ru         goto temp_fail;
42953Sigor@sysoev.ru     }
43053Sigor@sysoev.ru 
43153Sigor@sysoev.ru     nxt_queue_init(&tmcf->deleting);
43253Sigor@sysoev.ru     nxt_queue_init(&tmcf->keeping);
43353Sigor@sysoev.ru     nxt_queue_init(&tmcf->updating);
43453Sigor@sysoev.ru     nxt_queue_init(&tmcf->pending);
43553Sigor@sysoev.ru     nxt_queue_init(&tmcf->creating);
436133Sigor@sysoev.ru     nxt_queue_init(&tmcf->apps);
437133Sigor@sysoev.ru     nxt_queue_init(&tmcf->previous);
43853Sigor@sysoev.ru 
43953Sigor@sysoev.ru     return tmcf;
44053Sigor@sysoev.ru 
44153Sigor@sysoev.ru temp_fail:
44253Sigor@sysoev.ru 
44365Sigor@sysoev.ru     nxt_mp_destroy(tmp);
44453Sigor@sysoev.ru 
44553Sigor@sysoev.ru fail:
44653Sigor@sysoev.ru 
44765Sigor@sysoev.ru     nxt_mp_destroy(mp);
44853Sigor@sysoev.ru 
44953Sigor@sysoev.ru     return NULL;
45053Sigor@sysoev.ru }
45153Sigor@sysoev.ru 
45253Sigor@sysoev.ru 
453198Sigor@sysoev.ru static void
454198Sigor@sysoev.ru nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data)
455139Sigor@sysoev.ru {
456139Sigor@sysoev.ru     nxt_int_t                    ret;
457139Sigor@sysoev.ru     nxt_router_t                 *router;
458139Sigor@sysoev.ru     nxt_runtime_t                *rt;
459198Sigor@sysoev.ru     nxt_queue_link_t             *qlk;
460198Sigor@sysoev.ru     nxt_socket_conf_t            *skcf;
461198Sigor@sysoev.ru     nxt_router_temp_conf_t       *tmcf;
462139Sigor@sysoev.ru     const nxt_event_interface_t  *interface;
463139Sigor@sysoev.ru 
464198Sigor@sysoev.ru     tmcf = obj;
465198Sigor@sysoev.ru 
466198Sigor@sysoev.ru     qlk = nxt_queue_first(&tmcf->pending);
467198Sigor@sysoev.ru 
468198Sigor@sysoev.ru     if (qlk != nxt_queue_tail(&tmcf->pending)) {
469198Sigor@sysoev.ru         nxt_queue_remove(qlk);
470198Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->creating, qlk);
471198Sigor@sysoev.ru 
472198Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
473198Sigor@sysoev.ru 
474198Sigor@sysoev.ru         nxt_router_listen_socket_rpc_create(task, tmcf, skcf);
475198Sigor@sysoev.ru 
476198Sigor@sysoev.ru         return;
477139Sigor@sysoev.ru     }
478139Sigor@sysoev.ru 
479139Sigor@sysoev.ru     rt = task->thread->runtime;
480139Sigor@sysoev.ru 
481139Sigor@sysoev.ru     interface = nxt_service_get(rt->services, "engine", NULL);
482139Sigor@sysoev.ru 
483198Sigor@sysoev.ru     router = tmcf->conf->router;
484198Sigor@sysoev.ru 
485139Sigor@sysoev.ru     ret = nxt_router_engines_create(task, router, tmcf, interface);
486139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
487198Sigor@sysoev.ru         goto fail;
488139Sigor@sysoev.ru     }
489139Sigor@sysoev.ru 
490139Sigor@sysoev.ru     ret = nxt_router_threads_create(task, rt, tmcf);
491139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
492198Sigor@sysoev.ru         goto fail;
493139Sigor@sysoev.ru     }
494139Sigor@sysoev.ru 
495139Sigor@sysoev.ru     nxt_router_apps_sort(router, tmcf);
496139Sigor@sysoev.ru 
497139Sigor@sysoev.ru     nxt_router_engines_post(tmcf);
498139Sigor@sysoev.ru 
499139Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->updating);
500139Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->creating);
501139Sigor@sysoev.ru 
502198Sigor@sysoev.ru     nxt_router_conf_ready(task, tmcf);
503198Sigor@sysoev.ru 
504198Sigor@sysoev.ru     return;
505198Sigor@sysoev.ru 
506198Sigor@sysoev.ru fail:
507198Sigor@sysoev.ru 
508198Sigor@sysoev.ru     nxt_router_conf_error(task, tmcf);
509198Sigor@sysoev.ru 
510198Sigor@sysoev.ru     return;
511139Sigor@sysoev.ru }
512139Sigor@sysoev.ru 
513139Sigor@sysoev.ru 
514139Sigor@sysoev.ru static void
515139Sigor@sysoev.ru nxt_router_conf_wait(nxt_task_t *task, void *obj, void *data)
516139Sigor@sysoev.ru {
517153Sigor@sysoev.ru     nxt_joint_job_t  *job;
518153Sigor@sysoev.ru 
519153Sigor@sysoev.ru     job = obj;
520153Sigor@sysoev.ru 
521198Sigor@sysoev.ru     nxt_router_conf_ready(task, job->tmcf);
522139Sigor@sysoev.ru }
523139Sigor@sysoev.ru 
524139Sigor@sysoev.ru 
525139Sigor@sysoev.ru static void
526198Sigor@sysoev.ru nxt_router_conf_ready(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
527139Sigor@sysoev.ru {
528139Sigor@sysoev.ru     nxt_debug(task, "temp conf count:%D", tmcf->count);
529139Sigor@sysoev.ru 
530139Sigor@sysoev.ru     if (--tmcf->count == 0) {
531193Smax.romanov@nginx.com         nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_READY_LAST);
532139Sigor@sysoev.ru     }
533139Sigor@sysoev.ru }
534139Sigor@sysoev.ru 
535139Sigor@sysoev.ru 
536139Sigor@sysoev.ru static void
537139Sigor@sysoev.ru nxt_router_conf_error(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
538139Sigor@sysoev.ru {
539148Sigor@sysoev.ru     nxt_socket_t       s;
540149Sigor@sysoev.ru     nxt_router_t       *router;
541148Sigor@sysoev.ru     nxt_queue_link_t   *qlk;
542148Sigor@sysoev.ru     nxt_socket_conf_t  *skcf;
543148Sigor@sysoev.ru 
544198Sigor@sysoev.ru     nxt_log(task, NXT_LOG_CRIT, "failed to apply new conf");
545198Sigor@sysoev.ru 
546148Sigor@sysoev.ru     for (qlk = nxt_queue_first(&tmcf->creating);
547148Sigor@sysoev.ru          qlk != nxt_queue_tail(&tmcf->creating);
548148Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
549148Sigor@sysoev.ru     {
550148Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
551148Sigor@sysoev.ru         s = skcf->listen.socket;
552148Sigor@sysoev.ru 
553148Sigor@sysoev.ru         if (s != -1) {
554148Sigor@sysoev.ru             nxt_socket_close(task, s);
555148Sigor@sysoev.ru         }
556148Sigor@sysoev.ru 
557148Sigor@sysoev.ru         nxt_free(skcf->socket);
558148Sigor@sysoev.ru     }
559148Sigor@sysoev.ru 
560149Sigor@sysoev.ru     router = tmcf->conf->router;
561149Sigor@sysoev.ru 
562149Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->keeping);
563149Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->deleting);
564149Sigor@sysoev.ru 
565148Sigor@sysoev.ru     // TODO: new engines and threads
566148Sigor@sysoev.ru 
567139Sigor@sysoev.ru     nxt_mp_destroy(tmcf->conf->mem_pool);
568139Sigor@sysoev.ru 
569193Smax.romanov@nginx.com     nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_ERROR);
570139Sigor@sysoev.ru }
571139Sigor@sysoev.ru 
572139Sigor@sysoev.ru 
573139Sigor@sysoev.ru static void
574139Sigor@sysoev.ru nxt_router_conf_send(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
575193Smax.romanov@nginx.com     nxt_port_msg_type_t type)
576139Sigor@sysoev.ru {
577193Smax.romanov@nginx.com     nxt_port_socket_write(task, tmcf->port, type, -1, tmcf->stream, 0, NULL);
578139Sigor@sysoev.ru }
579139Sigor@sysoev.ru 
580139Sigor@sysoev.ru 
581115Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_conf[] = {
582115Sigor@sysoev.ru     {
583133Sigor@sysoev.ru         nxt_string("listeners_threads"),
584115Sigor@sysoev.ru         NXT_CONF_MAP_INT32,
585115Sigor@sysoev.ru         offsetof(nxt_router_conf_t, threads),
586115Sigor@sysoev.ru     },
587115Sigor@sysoev.ru };
588115Sigor@sysoev.ru 
589115Sigor@sysoev.ru 
590133Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_app_conf[] = {
591115Sigor@sysoev.ru     {
592133Sigor@sysoev.ru         nxt_string("type"),
593115Sigor@sysoev.ru         NXT_CONF_MAP_STR,
594133Sigor@sysoev.ru         offsetof(nxt_router_app_conf_t, type),
595115Sigor@sysoev.ru     },
596115Sigor@sysoev.ru 
597115Sigor@sysoev.ru     {
598133Sigor@sysoev.ru         nxt_string("workers"),
599115Sigor@sysoev.ru         NXT_CONF_MAP_INT32,
600133Sigor@sysoev.ru         offsetof(nxt_router_app_conf_t, workers),
601133Sigor@sysoev.ru     },
602133Sigor@sysoev.ru };
603133Sigor@sysoev.ru 
604133Sigor@sysoev.ru 
605133Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_listener_conf[] = {
606133Sigor@sysoev.ru     {
607133Sigor@sysoev.ru         nxt_string("application"),
608133Sigor@sysoev.ru         NXT_CONF_MAP_STR,
609133Sigor@sysoev.ru         offsetof(nxt_router_listener_conf_t, application),
610115Sigor@sysoev.ru     },
611115Sigor@sysoev.ru };
612115Sigor@sysoev.ru 
613115Sigor@sysoev.ru 
614115Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_http_conf[] = {
615115Sigor@sysoev.ru     {
616115Sigor@sysoev.ru         nxt_string("header_buffer_size"),
617115Sigor@sysoev.ru         NXT_CONF_MAP_SIZE,
618115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, header_buffer_size),
619115Sigor@sysoev.ru     },
620115Sigor@sysoev.ru 
621115Sigor@sysoev.ru     {
622115Sigor@sysoev.ru         nxt_string("large_header_buffer_size"),
623115Sigor@sysoev.ru         NXT_CONF_MAP_SIZE,
624115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, large_header_buffer_size),
625115Sigor@sysoev.ru     },
626115Sigor@sysoev.ru 
627115Sigor@sysoev.ru     {
628206Smax.romanov@nginx.com         nxt_string("large_header_buffers"),
629206Smax.romanov@nginx.com         NXT_CONF_MAP_SIZE,
630206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, large_header_buffers),
631206Smax.romanov@nginx.com     },
632206Smax.romanov@nginx.com 
633206Smax.romanov@nginx.com     {
634206Smax.romanov@nginx.com         nxt_string("body_buffer_size"),
635206Smax.romanov@nginx.com         NXT_CONF_MAP_SIZE,
636206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, body_buffer_size),
637206Smax.romanov@nginx.com     },
638206Smax.romanov@nginx.com 
639206Smax.romanov@nginx.com     {
640206Smax.romanov@nginx.com         nxt_string("max_body_size"),
641206Smax.romanov@nginx.com         NXT_CONF_MAP_SIZE,
642206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, max_body_size),
643206Smax.romanov@nginx.com     },
644206Smax.romanov@nginx.com 
645206Smax.romanov@nginx.com     {
646115Sigor@sysoev.ru         nxt_string("header_read_timeout"),
647115Sigor@sysoev.ru         NXT_CONF_MAP_MSEC,
648115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, header_read_timeout),
649115Sigor@sysoev.ru     },
650206Smax.romanov@nginx.com 
651206Smax.romanov@nginx.com     {
652206Smax.romanov@nginx.com         nxt_string("body_read_timeout"),
653206Smax.romanov@nginx.com         NXT_CONF_MAP_MSEC,
654206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, body_read_timeout),
655206Smax.romanov@nginx.com     },
656115Sigor@sysoev.ru };
657115Sigor@sysoev.ru 
658115Sigor@sysoev.ru 
65953Sigor@sysoev.ru static nxt_int_t
660115Sigor@sysoev.ru nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
661115Sigor@sysoev.ru     u_char *start, u_char *end)
66253Sigor@sysoev.ru {
663133Sigor@sysoev.ru     u_char                      *p;
664133Sigor@sysoev.ru     size_t                      size;
665115Sigor@sysoev.ru     nxt_mp_t                    *mp;
666115Sigor@sysoev.ru     uint32_t                    next;
667115Sigor@sysoev.ru     nxt_int_t                   ret;
668115Sigor@sysoev.ru     nxt_str_t                   name;
669133Sigor@sysoev.ru     nxt_app_t                   *app, *prev;
670133Sigor@sysoev.ru     nxt_app_type_t              type;
671115Sigor@sysoev.ru     nxt_sockaddr_t              *sa;
672133Sigor@sysoev.ru     nxt_conf_value_t            *conf, *http;
673133Sigor@sysoev.ru     nxt_conf_value_t            *applications, *application;
674133Sigor@sysoev.ru     nxt_conf_value_t            *listeners, *listener;
675115Sigor@sysoev.ru     nxt_socket_conf_t           *skcf;
676216Sigor@sysoev.ru     nxt_app_lang_module_t       *lang;
677133Sigor@sysoev.ru     nxt_router_app_conf_t       apcf;
678115Sigor@sysoev.ru     nxt_router_listener_conf_t  lscf;
679115Sigor@sysoev.ru 
680115Sigor@sysoev.ru     static nxt_str_t  http_path = nxt_string("/http");
681133Sigor@sysoev.ru     static nxt_str_t  applications_path = nxt_string("/applications");
682115Sigor@sysoev.ru     static nxt_str_t  listeners_path = nxt_string("/listeners");
683115Sigor@sysoev.ru 
684208Svbart@nginx.com     conf = nxt_conf_json_parse(tmcf->mem_pool, start, end, NULL);
685115Sigor@sysoev.ru     if (conf == NULL) {
686115Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "configuration parsing error");
687115Sigor@sysoev.ru         return NXT_ERROR;
688115Sigor@sysoev.ru     }
689115Sigor@sysoev.ru 
690213Svbart@nginx.com     mp = tmcf->conf->mem_pool;
691213Svbart@nginx.com 
692213Svbart@nginx.com     ret = nxt_conf_map_object(mp, conf, nxt_router_conf,
693136Svbart@nginx.com                               nxt_nitems(nxt_router_conf), tmcf->conf);
694115Sigor@sysoev.ru     if (ret != NXT_OK) {
695133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "root map error");
696115Sigor@sysoev.ru         return NXT_ERROR;
697115Sigor@sysoev.ru     }
698115Sigor@sysoev.ru 
699117Sigor@sysoev.ru     if (tmcf->conf->threads == 0) {
700117Sigor@sysoev.ru         tmcf->conf->threads = nxt_ncpu;
701117Sigor@sysoev.ru     }
702117Sigor@sysoev.ru 
703133Sigor@sysoev.ru     applications = nxt_conf_get_path(conf, &applications_path);
704133Sigor@sysoev.ru     if (applications == NULL) {
705133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "no \"applications\" block");
706115Sigor@sysoev.ru         return NXT_ERROR;
707115Sigor@sysoev.ru     }
708115Sigor@sysoev.ru 
709133Sigor@sysoev.ru     next = 0;
710133Sigor@sysoev.ru 
711133Sigor@sysoev.ru     for ( ;; ) {
712133Sigor@sysoev.ru         application = nxt_conf_next_object_member(applications, &name, &next);
713133Sigor@sysoev.ru         if (application == NULL) {
714133Sigor@sysoev.ru             break;
715133Sigor@sysoev.ru         }
716133Sigor@sysoev.ru 
717133Sigor@sysoev.ru         nxt_debug(task, "application \"%V\"", &name);
718133Sigor@sysoev.ru 
719144Smax.romanov@nginx.com         size = nxt_conf_json_length(application, NULL);
720144Smax.romanov@nginx.com 
721144Smax.romanov@nginx.com         app = nxt_malloc(sizeof(nxt_app_t) + name.length + size);
722133Sigor@sysoev.ru         if (app == NULL) {
723133Sigor@sysoev.ru             goto fail;
724133Sigor@sysoev.ru         }
725133Sigor@sysoev.ru 
726144Smax.romanov@nginx.com         nxt_memzero(app, sizeof(nxt_app_t));
727144Smax.romanov@nginx.com 
728144Smax.romanov@nginx.com         app->name.start = nxt_pointer_to(app, sizeof(nxt_app_t));
729144Smax.romanov@nginx.com         app->conf.start = nxt_pointer_to(app, sizeof(nxt_app_t) + name.length);
730133Sigor@sysoev.ru 
731133Sigor@sysoev.ru         p = nxt_conf_json_print(app->conf.start, application, NULL);
732133Sigor@sysoev.ru         app->conf.length = p - app->conf.start;
733133Sigor@sysoev.ru 
734144Smax.romanov@nginx.com         nxt_assert(app->conf.length <= size);
735144Smax.romanov@nginx.com 
736133Sigor@sysoev.ru         nxt_debug(task, "application conf \"%V\"", &app->conf);
737133Sigor@sysoev.ru 
738133Sigor@sysoev.ru         prev = nxt_router_app_find(&tmcf->conf->router->apps, &name);
739133Sigor@sysoev.ru 
740133Sigor@sysoev.ru         if (prev != NULL && nxt_strstr_eq(&app->conf, &prev->conf)) {
741133Sigor@sysoev.ru             nxt_free(app);
742133Sigor@sysoev.ru 
743133Sigor@sysoev.ru             nxt_queue_remove(&prev->link);
744133Sigor@sysoev.ru             nxt_queue_insert_tail(&tmcf->previous, &prev->link);
745133Sigor@sysoev.ru             continue;
746133Sigor@sysoev.ru         }
747133Sigor@sysoev.ru 
748263Smax.romanov@nginx.com         apcf.workers = 1;
749263Smax.romanov@nginx.com 
750213Svbart@nginx.com         ret = nxt_conf_map_object(mp, application, nxt_router_app_conf,
751136Svbart@nginx.com                                   nxt_nitems(nxt_router_app_conf), &apcf);
752133Sigor@sysoev.ru         if (ret != NXT_OK) {
753133Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "application map error");
754133Sigor@sysoev.ru             goto app_fail;
755133Sigor@sysoev.ru         }
756115Sigor@sysoev.ru 
757133Sigor@sysoev.ru         nxt_debug(task, "application type: %V", &apcf.type);
758133Sigor@sysoev.ru         nxt_debug(task, "application workers: %D", apcf.workers);
759133Sigor@sysoev.ru 
760216Sigor@sysoev.ru         lang = nxt_app_lang_module(task->thread->runtime, &apcf.type);
761216Sigor@sysoev.ru 
762216Sigor@sysoev.ru         if (lang == NULL) {
763141Smax.romanov@nginx.com             nxt_log(task, NXT_LOG_CRIT, "unknown application type: \"%V\"",
764141Smax.romanov@nginx.com                     &apcf.type);
765141Smax.romanov@nginx.com             goto app_fail;
766141Smax.romanov@nginx.com         }
767141Smax.romanov@nginx.com 
768216Sigor@sysoev.ru         nxt_debug(task, "application language module: \"%s\"", lang->file);
769216Sigor@sysoev.ru 
770216Sigor@sysoev.ru         type = nxt_app_parse_type(&lang->type);
771216Sigor@sysoev.ru 
772216Sigor@sysoev.ru         if (type == NXT_APP_UNKNOWN) {
773216Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "unknown application type: \"%V\"",
774216Sigor@sysoev.ru                     &lang->type);
775216Sigor@sysoev.ru             goto app_fail;
776216Sigor@sysoev.ru         }
777216Sigor@sysoev.ru 
778216Sigor@sysoev.ru         if (nxt_app_prepare_msg[type] == NULL) {
779133Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "unsupported application type: \"%V\"",
780216Sigor@sysoev.ru                     &lang->type);
781133Sigor@sysoev.ru             goto app_fail;
782133Sigor@sysoev.ru         }
783133Sigor@sysoev.ru 
784133Sigor@sysoev.ru         ret = nxt_thread_mutex_create(&app->mutex);
785133Sigor@sysoev.ru         if (ret != NXT_OK) {
786133Sigor@sysoev.ru             goto app_fail;
787133Sigor@sysoev.ru         }
788133Sigor@sysoev.ru 
789141Smax.romanov@nginx.com         nxt_queue_init(&app->ports);
790141Smax.romanov@nginx.com         nxt_queue_init(&app->requests);
791141Smax.romanov@nginx.com 
792144Smax.romanov@nginx.com         app->name.length = name.length;
793144Smax.romanov@nginx.com         nxt_memcpy(app->name.start, name.start, name.length);
794144Smax.romanov@nginx.com 
795133Sigor@sysoev.ru         app->type = type;
796133Sigor@sysoev.ru         app->max_workers = apcf.workers;
797133Sigor@sysoev.ru         app->live = 1;
798216Sigor@sysoev.ru         app->prepare_msg = nxt_app_prepare_msg[type];
799133Sigor@sysoev.ru 
800133Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->apps, &app->link);
801133Sigor@sysoev.ru     }
802133Sigor@sysoev.ru 
803133Sigor@sysoev.ru     http = nxt_conf_get_path(conf, &http_path);
804133Sigor@sysoev.ru #if 0
805133Sigor@sysoev.ru     if (http == NULL) {
806133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "no \"http\" block");
807133Sigor@sysoev.ru         return NXT_ERROR;
808133Sigor@sysoev.ru     }
809133Sigor@sysoev.ru #endif
810133Sigor@sysoev.ru 
811133Sigor@sysoev.ru     listeners = nxt_conf_get_path(conf, &listeners_path);
812115Sigor@sysoev.ru     if (listeners == NULL) {
813133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "no \"listeners\" block");
814115Sigor@sysoev.ru         return NXT_ERROR;
815115Sigor@sysoev.ru     }
81653Sigor@sysoev.ru 
817133Sigor@sysoev.ru     next = 0;
81853Sigor@sysoev.ru 
819115Sigor@sysoev.ru     for ( ;; ) {
820115Sigor@sysoev.ru         listener = nxt_conf_next_object_member(listeners, &name, &next);
821115Sigor@sysoev.ru         if (listener == NULL) {
822115Sigor@sysoev.ru             break;
823115Sigor@sysoev.ru         }
82453Sigor@sysoev.ru 
825115Sigor@sysoev.ru         sa = nxt_sockaddr_parse(mp, &name);
826115Sigor@sysoev.ru         if (sa == NULL) {
827115Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "invalid listener \"%V\"", &name);
828133Sigor@sysoev.ru             goto fail;
829115Sigor@sysoev.ru         }
830115Sigor@sysoev.ru 
831115Sigor@sysoev.ru         sa->type = SOCK_STREAM;
832115Sigor@sysoev.ru 
833115Sigor@sysoev.ru         nxt_debug(task, "router listener: \"%*s\"",
834115Sigor@sysoev.ru                   sa->length, nxt_sockaddr_start(sa));
83553Sigor@sysoev.ru 
836115Sigor@sysoev.ru         skcf = nxt_router_socket_conf(task, mp, sa);
837115Sigor@sysoev.ru         if (skcf == NULL) {
838133Sigor@sysoev.ru             goto fail;
839115Sigor@sysoev.ru         }
84053Sigor@sysoev.ru 
841213Svbart@nginx.com         ret = nxt_conf_map_object(mp, listener, nxt_router_listener_conf,
842136Svbart@nginx.com                                   nxt_nitems(nxt_router_listener_conf), &lscf);
843115Sigor@sysoev.ru         if (ret != NXT_OK) {
844115Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "listener map error");
845133Sigor@sysoev.ru             goto fail;
846115Sigor@sysoev.ru         }
84753Sigor@sysoev.ru 
848133Sigor@sysoev.ru         nxt_debug(task, "application: %V", &lscf.application);
849133Sigor@sysoev.ru 
850133Sigor@sysoev.ru         // STUB, default values if http block is not defined.
851133Sigor@sysoev.ru         skcf->header_buffer_size = 2048;
852133Sigor@sysoev.ru         skcf->large_header_buffer_size = 8192;
853206Smax.romanov@nginx.com         skcf->large_header_buffers = 4;
854206Smax.romanov@nginx.com         skcf->body_buffer_size = 16 * 1024;
855206Smax.romanov@nginx.com         skcf->max_body_size = 2 * 1024 * 1024;
856133Sigor@sysoev.ru         skcf->header_read_timeout = 5000;
857206Smax.romanov@nginx.com         skcf->body_read_timeout = 5000;
85853Sigor@sysoev.ru 
859133Sigor@sysoev.ru         if (http != NULL) {
860213Svbart@nginx.com             ret = nxt_conf_map_object(mp, http, nxt_router_http_conf,
861136Svbart@nginx.com                                       nxt_nitems(nxt_router_http_conf), skcf);
862133Sigor@sysoev.ru             if (ret != NXT_OK) {
863133Sigor@sysoev.ru                 nxt_log(task, NXT_LOG_CRIT, "http map error");
864133Sigor@sysoev.ru                 goto fail;
865133Sigor@sysoev.ru             }
866115Sigor@sysoev.ru         }
867115Sigor@sysoev.ru 
868115Sigor@sysoev.ru         skcf->listen.handler = nxt_router_conn_init;
869115Sigor@sysoev.ru         skcf->router_conf = tmcf->conf;
870160Sigor@sysoev.ru         skcf->router_conf->count++;
871133Sigor@sysoev.ru         skcf->application = nxt_router_listener_application(tmcf,
872133Sigor@sysoev.ru                                                             &lscf.application);
873115Sigor@sysoev.ru 
874115Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->pending, &skcf->link);
875115Sigor@sysoev.ru     }
87653Sigor@sysoev.ru 
877198Sigor@sysoev.ru     nxt_router_listen_sockets_sort(tmcf->conf->router, tmcf);
878198Sigor@sysoev.ru 
87953Sigor@sysoev.ru     return NXT_OK;
880133Sigor@sysoev.ru 
881133Sigor@sysoev.ru app_fail:
882133Sigor@sysoev.ru 
883133Sigor@sysoev.ru     nxt_free(app);
884133Sigor@sysoev.ru 
885133Sigor@sysoev.ru fail:
886133Sigor@sysoev.ru 
887141Smax.romanov@nginx.com     nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) {
888141Smax.romanov@nginx.com 
889141Smax.romanov@nginx.com         nxt_queue_remove(&app->link);
890133Sigor@sysoev.ru         nxt_thread_mutex_destroy(&app->mutex);
891133Sigor@sysoev.ru         nxt_free(app);
892141Smax.romanov@nginx.com 
893141Smax.romanov@nginx.com     } nxt_queue_loop;
894133Sigor@sysoev.ru 
895133Sigor@sysoev.ru     return NXT_ERROR;
896133Sigor@sysoev.ru }
897133Sigor@sysoev.ru 
898133Sigor@sysoev.ru 
899133Sigor@sysoev.ru static nxt_app_t *
900133Sigor@sysoev.ru nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name)
901133Sigor@sysoev.ru {
902141Smax.romanov@nginx.com     nxt_app_t  *app;
903141Smax.romanov@nginx.com 
904141Smax.romanov@nginx.com     nxt_queue_each(app, queue, nxt_app_t, link) {
905133Sigor@sysoev.ru 
906133Sigor@sysoev.ru         if (nxt_strstr_eq(name, &app->name)) {
907133Sigor@sysoev.ru             return app;
908133Sigor@sysoev.ru         }
909141Smax.romanov@nginx.com 
910141Smax.romanov@nginx.com     } nxt_queue_loop;
911133Sigor@sysoev.ru 
912133Sigor@sysoev.ru     return NULL;
913133Sigor@sysoev.ru }
914133Sigor@sysoev.ru 
915133Sigor@sysoev.ru 
916133Sigor@sysoev.ru static nxt_app_t *
917133Sigor@sysoev.ru nxt_router_listener_application(nxt_router_temp_conf_t *tmcf, nxt_str_t *name)
918133Sigor@sysoev.ru {
919133Sigor@sysoev.ru     nxt_app_t  *app;
920133Sigor@sysoev.ru 
921133Sigor@sysoev.ru     app = nxt_router_app_find(&tmcf->apps, name);
922133Sigor@sysoev.ru 
923133Sigor@sysoev.ru     if (app == NULL) {
924134Sigor@sysoev.ru         app = nxt_router_app_find(&tmcf->previous, name);
925133Sigor@sysoev.ru     }
926133Sigor@sysoev.ru 
927133Sigor@sysoev.ru     return app;
92853Sigor@sysoev.ru }
92953Sigor@sysoev.ru 
93053Sigor@sysoev.ru 
93153Sigor@sysoev.ru static nxt_socket_conf_t *
93265Sigor@sysoev.ru nxt_router_socket_conf(nxt_task_t *task, nxt_mp_t *mp, nxt_sockaddr_t *sa)
93353Sigor@sysoev.ru {
934163Smax.romanov@nginx.com     nxt_socket_conf_t  *skcf;
935163Smax.romanov@nginx.com 
936163Smax.romanov@nginx.com     skcf = nxt_mp_zget(mp, sizeof(nxt_socket_conf_t));
937163Smax.romanov@nginx.com     if (nxt_slow_path(skcf == NULL)) {
93853Sigor@sysoev.ru         return NULL;
93953Sigor@sysoev.ru     }
94053Sigor@sysoev.ru 
941163Smax.romanov@nginx.com     skcf->sockaddr = sa;
942163Smax.romanov@nginx.com 
943163Smax.romanov@nginx.com     skcf->listen.sockaddr = sa;
944163Smax.romanov@nginx.com     skcf->listen.socklen = sa->socklen;
945163Smax.romanov@nginx.com     skcf->listen.address_length = sa->length;
946163Smax.romanov@nginx.com 
947163Smax.romanov@nginx.com     skcf->listen.socket = -1;
948163Smax.romanov@nginx.com     skcf->listen.backlog = NXT_LISTEN_BACKLOG;
949163Smax.romanov@nginx.com     skcf->listen.flags = NXT_NONBLOCK;
950163Smax.romanov@nginx.com     skcf->listen.read_after_accept = 1;
951163Smax.romanov@nginx.com 
952163Smax.romanov@nginx.com     return skcf;
95353Sigor@sysoev.ru }
95453Sigor@sysoev.ru 
95553Sigor@sysoev.ru 
95653Sigor@sysoev.ru static void
95753Sigor@sysoev.ru nxt_router_listen_sockets_sort(nxt_router_t *router,
95853Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf)
95953Sigor@sysoev.ru {
96053Sigor@sysoev.ru     nxt_queue_link_t   *nqlk, *oqlk, *next;
96153Sigor@sysoev.ru     nxt_socket_conf_t  *nskcf, *oskcf;
96253Sigor@sysoev.ru 
96353Sigor@sysoev.ru     for (nqlk = nxt_queue_first(&tmcf->pending);
96453Sigor@sysoev.ru          nqlk != nxt_queue_tail(&tmcf->pending);
96553Sigor@sysoev.ru          nqlk = next)
96653Sigor@sysoev.ru     {
96753Sigor@sysoev.ru         next = nxt_queue_next(nqlk);
96853Sigor@sysoev.ru         nskcf = nxt_queue_link_data(nqlk, nxt_socket_conf_t, link);
96953Sigor@sysoev.ru 
97053Sigor@sysoev.ru         for (oqlk = nxt_queue_first(&router->sockets);
97153Sigor@sysoev.ru              oqlk != nxt_queue_tail(&router->sockets);
97253Sigor@sysoev.ru              oqlk = nxt_queue_next(oqlk))
97353Sigor@sysoev.ru         {
97453Sigor@sysoev.ru             oskcf = nxt_queue_link_data(oqlk, nxt_socket_conf_t, link);
97553Sigor@sysoev.ru 
976115Sigor@sysoev.ru             if (nxt_sockaddr_cmp(nskcf->sockaddr, oskcf->sockaddr)) {
977115Sigor@sysoev.ru                 nskcf->socket = oskcf->socket;
978115Sigor@sysoev.ru                 nskcf->listen.socket = oskcf->listen.socket;
979115Sigor@sysoev.ru 
98053Sigor@sysoev.ru                 nxt_queue_remove(oqlk);
98153Sigor@sysoev.ru                 nxt_queue_insert_tail(&tmcf->keeping, oqlk);
98253Sigor@sysoev.ru 
98353Sigor@sysoev.ru                 nxt_queue_remove(nqlk);
98453Sigor@sysoev.ru                 nxt_queue_insert_tail(&tmcf->updating, nqlk);
98553Sigor@sysoev.ru 
98653Sigor@sysoev.ru                 break;
98753Sigor@sysoev.ru             }
98853Sigor@sysoev.ru         }
98953Sigor@sysoev.ru     }
99053Sigor@sysoev.ru 
99153Sigor@sysoev.ru     nxt_queue_add(&tmcf->deleting, &router->sockets);
992115Sigor@sysoev.ru     nxt_queue_init(&router->sockets);
99353Sigor@sysoev.ru }
99453Sigor@sysoev.ru 
99553Sigor@sysoev.ru 
996198Sigor@sysoev.ru static void
997198Sigor@sysoev.ru nxt_router_listen_socket_rpc_create(nxt_task_t *task,
998198Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf)
999198Sigor@sysoev.ru {
1000198Sigor@sysoev.ru     uint32_t          stream;
1001198Sigor@sysoev.ru     nxt_buf_t         *b;
1002198Sigor@sysoev.ru     nxt_port_t        *main_port, *router_port;
1003198Sigor@sysoev.ru     nxt_runtime_t     *rt;
1004198Sigor@sysoev.ru     nxt_socket_rpc_t  *rpc;
1005198Sigor@sysoev.ru 
1006198Sigor@sysoev.ru     rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_socket_rpc_t));
1007198Sigor@sysoev.ru     if (rpc == NULL) {
1008198Sigor@sysoev.ru         goto fail;
1009198Sigor@sysoev.ru     }
1010198Sigor@sysoev.ru 
1011198Sigor@sysoev.ru     rpc->socket_conf = skcf;
1012198Sigor@sysoev.ru     rpc->temp_conf = tmcf;
1013198Sigor@sysoev.ru 
1014198Sigor@sysoev.ru     b = nxt_buf_mem_alloc(tmcf->mem_pool, skcf->sockaddr->sockaddr_size, 0);
1015198Sigor@sysoev.ru     if (b == NULL) {
1016198Sigor@sysoev.ru         goto fail;
1017198Sigor@sysoev.ru     }
1018198Sigor@sysoev.ru 
1019198Sigor@sysoev.ru     b->mem.free = nxt_cpymem(b->mem.free, skcf->sockaddr,
1020198Sigor@sysoev.ru                              skcf->sockaddr->sockaddr_size);
1021198Sigor@sysoev.ru 
1022198Sigor@sysoev.ru     rt = task->thread->runtime;
1023240Sigor@sysoev.ru     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
1024198Sigor@sysoev.ru     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
1025198Sigor@sysoev.ru 
1026198Sigor@sysoev.ru     stream = nxt_port_rpc_register_handler(task, router_port,
1027198Sigor@sysoev.ru                                            nxt_router_listen_socket_ready,
1028198Sigor@sysoev.ru                                            nxt_router_listen_socket_error,
1029198Sigor@sysoev.ru                                            main_port->pid, rpc);
1030198Sigor@sysoev.ru     if (stream == 0) {
1031198Sigor@sysoev.ru         goto fail;
1032198Sigor@sysoev.ru     }
1033198Sigor@sysoev.ru 
1034198Sigor@sysoev.ru     nxt_port_socket_write(task, main_port, NXT_PORT_MSG_SOCKET, -1,
1035198Sigor@sysoev.ru                           stream, router_port->id, b);
1036198Sigor@sysoev.ru 
1037198Sigor@sysoev.ru     return;
1038198Sigor@sysoev.ru 
1039198Sigor@sysoev.ru fail:
1040198Sigor@sysoev.ru 
1041198Sigor@sysoev.ru     nxt_router_conf_error(task, tmcf);
1042198Sigor@sysoev.ru }
1043198Sigor@sysoev.ru 
1044198Sigor@sysoev.ru 
1045198Sigor@sysoev.ru static void
1046198Sigor@sysoev.ru nxt_router_listen_socket_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
1047198Sigor@sysoev.ru     void *data)
104853Sigor@sysoev.ru {
1049115Sigor@sysoev.ru     nxt_int_t            ret;
1050115Sigor@sysoev.ru     nxt_socket_t         s;
1051198Sigor@sysoev.ru     nxt_socket_rpc_t     *rpc;
1052115Sigor@sysoev.ru     nxt_router_socket_t  *rtsk;
105353Sigor@sysoev.ru 
1054198Sigor@sysoev.ru     rpc = data;
1055198Sigor@sysoev.ru 
1056198Sigor@sysoev.ru     s = msg->fd;
1057198Sigor@sysoev.ru 
1058198Sigor@sysoev.ru     ret = nxt_socket_nonblocking(task, s);
1059198Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1060198Sigor@sysoev.ru         goto fail;
106153Sigor@sysoev.ru     }
106253Sigor@sysoev.ru 
1063229Sigor@sysoev.ru     nxt_socket_defer_accept(task, s, rpc->socket_conf->sockaddr);
1064198Sigor@sysoev.ru 
1065198Sigor@sysoev.ru     ret = nxt_listen_socket(task, s, NXT_LISTEN_BACKLOG);
1066198Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1067198Sigor@sysoev.ru         goto fail;
1068198Sigor@sysoev.ru     }
1069198Sigor@sysoev.ru 
1070198Sigor@sysoev.ru     rtsk = nxt_malloc(sizeof(nxt_router_socket_t));
1071198Sigor@sysoev.ru     if (nxt_slow_path(rtsk == NULL)) {
1072198Sigor@sysoev.ru         goto fail;
1073198Sigor@sysoev.ru     }
1074198Sigor@sysoev.ru 
1075198Sigor@sysoev.ru     rtsk->count = 0;
1076198Sigor@sysoev.ru     rtsk->fd = s;
1077198Sigor@sysoev.ru 
1078198Sigor@sysoev.ru     rpc->socket_conf->listen.socket = s;
1079198Sigor@sysoev.ru     rpc->socket_conf->socket = rtsk;
1080198Sigor@sysoev.ru 
1081198Sigor@sysoev.ru     nxt_work_queue_add(&task->thread->engine->fast_work_queue,
1082198Sigor@sysoev.ru                        nxt_router_conf_apply, task, rpc->temp_conf, NULL);
1083198Sigor@sysoev.ru 
1084198Sigor@sysoev.ru     return;
1085148Sigor@sysoev.ru 
1086148Sigor@sysoev.ru fail:
1087148Sigor@sysoev.ru 
1088148Sigor@sysoev.ru     nxt_socket_close(task, s);
1089148Sigor@sysoev.ru 
1090198Sigor@sysoev.ru     nxt_router_conf_error(task, rpc->temp_conf);
1091198Sigor@sysoev.ru }
1092198Sigor@sysoev.ru 
1093198Sigor@sysoev.ru 
1094198Sigor@sysoev.ru static void
1095198Sigor@sysoev.ru nxt_router_listen_socket_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
1096198Sigor@sysoev.ru     void *data)
1097198Sigor@sysoev.ru {
1098198Sigor@sysoev.ru     u_char                  *p;
1099198Sigor@sysoev.ru     size_t                  size;
1100198Sigor@sysoev.ru     uint8_t                 error;
1101198Sigor@sysoev.ru     nxt_buf_t               *in, *out;
1102198Sigor@sysoev.ru     nxt_sockaddr_t          *sa;
1103198Sigor@sysoev.ru     nxt_socket_rpc_t        *rpc;
1104198Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
1105198Sigor@sysoev.ru 
1106198Sigor@sysoev.ru     static nxt_str_t  socket_errors[] = {
1107198Sigor@sysoev.ru         nxt_string("ListenerSystem"),
1108198Sigor@sysoev.ru         nxt_string("ListenerNoIPv6"),
1109198Sigor@sysoev.ru         nxt_string("ListenerPort"),
1110198Sigor@sysoev.ru         nxt_string("ListenerInUse"),
1111198Sigor@sysoev.ru         nxt_string("ListenerNoAddress"),
1112198Sigor@sysoev.ru         nxt_string("ListenerNoAccess"),
1113198Sigor@sysoev.ru         nxt_string("ListenerPath"),
1114198Sigor@sysoev.ru     };
1115198Sigor@sysoev.ru 
1116198Sigor@sysoev.ru     rpc = data;
1117198Sigor@sysoev.ru     sa = rpc->socket_conf->sockaddr;
1118198Sigor@sysoev.ru 
1119198Sigor@sysoev.ru     in = msg->buf;
1120198Sigor@sysoev.ru     p = in->mem.pos;
1121198Sigor@sysoev.ru 
1122198Sigor@sysoev.ru     error = *p++;
1123198Sigor@sysoev.ru 
1124198Sigor@sysoev.ru     size = sizeof("listen socket error: ") - 1
1125198Sigor@sysoev.ru            + sizeof("{listener: \"\", code:\"\", message: \"\"}") - 1
1126198Sigor@sysoev.ru            + sa->length + socket_errors[error].length + (in->mem.free - p);
1127198Sigor@sysoev.ru 
1128198Sigor@sysoev.ru     tmcf = rpc->temp_conf;
1129198Sigor@sysoev.ru 
1130198Sigor@sysoev.ru     out = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0);
1131198Sigor@sysoev.ru     if (nxt_slow_path(out == NULL)) {
1132198Sigor@sysoev.ru         return;
1133198Sigor@sysoev.ru     }
1134198Sigor@sysoev.ru 
1135198Sigor@sysoev.ru     out->mem.free = nxt_sprintf(out->mem.free, out->mem.end,
1136198Sigor@sysoev.ru                         "listen socket error: "
1137198Sigor@sysoev.ru                         "{listener: \"%*s\", code:\"%V\", message: \"%*s\"}",
1138198Sigor@sysoev.ru                         sa->length, nxt_sockaddr_start(sa),
1139198Sigor@sysoev.ru                         &socket_errors[error], in->mem.free - p, p);
1140198Sigor@sysoev.ru 
1141198Sigor@sysoev.ru     nxt_debug(task, "%*s", out->mem.free - out->mem.pos, out->mem.pos);
1142198Sigor@sysoev.ru 
1143198Sigor@sysoev.ru     nxt_router_conf_error(task, tmcf);
114453Sigor@sysoev.ru }
114553Sigor@sysoev.ru 
114653Sigor@sysoev.ru 
114753Sigor@sysoev.ru static nxt_int_t
114853Sigor@sysoev.ru nxt_router_engines_create(nxt_task_t *task, nxt_router_t *router,
114953Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, const nxt_event_interface_t *interface)
115053Sigor@sysoev.ru {
115153Sigor@sysoev.ru     nxt_int_t                 ret;
115253Sigor@sysoev.ru     nxt_uint_t                n, threads;
115353Sigor@sysoev.ru     nxt_queue_link_t          *qlk;
115453Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
115553Sigor@sysoev.ru 
115653Sigor@sysoev.ru     threads = tmcf->conf->threads;
115753Sigor@sysoev.ru 
115853Sigor@sysoev.ru     tmcf->engines = nxt_array_create(tmcf->mem_pool, threads,
115953Sigor@sysoev.ru                                      sizeof(nxt_router_engine_conf_t));
116053Sigor@sysoev.ru     if (nxt_slow_path(tmcf->engines == NULL)) {
116153Sigor@sysoev.ru         return NXT_ERROR;
116253Sigor@sysoev.ru     }
116353Sigor@sysoev.ru 
116453Sigor@sysoev.ru     n = 0;
116553Sigor@sysoev.ru 
116653Sigor@sysoev.ru     for (qlk = nxt_queue_first(&router->engines);
116753Sigor@sysoev.ru          qlk != nxt_queue_tail(&router->engines);
116853Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
116953Sigor@sysoev.ru     {
117053Sigor@sysoev.ru         recf = nxt_array_zero_add(tmcf->engines);
117153Sigor@sysoev.ru         if (nxt_slow_path(recf == NULL)) {
117253Sigor@sysoev.ru             return NXT_ERROR;
117353Sigor@sysoev.ru         }
117453Sigor@sysoev.ru 
1175115Sigor@sysoev.ru         recf->engine = nxt_queue_link_data(qlk, nxt_event_engine_t, link0);
117653Sigor@sysoev.ru 
117753Sigor@sysoev.ru         if (n < threads) {
1178115Sigor@sysoev.ru             ret = nxt_router_engine_conf_update(tmcf, recf);
117953Sigor@sysoev.ru 
118053Sigor@sysoev.ru         } else {
1181115Sigor@sysoev.ru             ret = nxt_router_engine_conf_delete(tmcf, recf);
118253Sigor@sysoev.ru         }
118353Sigor@sysoev.ru 
118453Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
118553Sigor@sysoev.ru             return ret;
118653Sigor@sysoev.ru         }
118753Sigor@sysoev.ru 
118853Sigor@sysoev.ru         n++;
118953Sigor@sysoev.ru     }
119053Sigor@sysoev.ru 
119153Sigor@sysoev.ru     tmcf->new_threads = n;
119253Sigor@sysoev.ru 
119353Sigor@sysoev.ru     while (n < threads) {
119453Sigor@sysoev.ru         recf = nxt_array_zero_add(tmcf->engines);
119553Sigor@sysoev.ru         if (nxt_slow_path(recf == NULL)) {
119653Sigor@sysoev.ru             return NXT_ERROR;
119753Sigor@sysoev.ru         }
119853Sigor@sysoev.ru 
119953Sigor@sysoev.ru         recf->engine = nxt_event_engine_create(task, interface, NULL, 0, 0);
120053Sigor@sysoev.ru         if (nxt_slow_path(recf->engine == NULL)) {
120153Sigor@sysoev.ru             return NXT_ERROR;
120253Sigor@sysoev.ru         }
120353Sigor@sysoev.ru 
1204115Sigor@sysoev.ru         ret = nxt_router_engine_conf_create(tmcf, recf);
120553Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
120653Sigor@sysoev.ru             return ret;
120753Sigor@sysoev.ru         }
120853Sigor@sysoev.ru 
1209115Sigor@sysoev.ru         nxt_queue_insert_tail(&router->engines, &recf->engine->link0);
1210115Sigor@sysoev.ru 
121153Sigor@sysoev.ru         n++;
121253Sigor@sysoev.ru     }
121353Sigor@sysoev.ru 
121453Sigor@sysoev.ru     return NXT_OK;
121553Sigor@sysoev.ru }
121653Sigor@sysoev.ru 
121753Sigor@sysoev.ru 
121853Sigor@sysoev.ru static nxt_int_t
1219115Sigor@sysoev.ru nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf,
1220115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
122153Sigor@sysoev.ru {
1222115Sigor@sysoev.ru     nxt_int_t              ret;
1223115Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
122453Sigor@sysoev.ru 
1225154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating,
1226154Sigor@sysoev.ru                                           nxt_router_listen_socket_create);
1227115Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1228115Sigor@sysoev.ru         return ret;
1229115Sigor@sysoev.ru     }
1230115Sigor@sysoev.ru 
1231154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating,
1232154Sigor@sysoev.ru                                           nxt_router_listen_socket_create);
123353Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
123453Sigor@sysoev.ru         return ret;
123553Sigor@sysoev.ru     }
123653Sigor@sysoev.ru 
1237115Sigor@sysoev.ru     lock = &tmcf->conf->router->lock;
1238115Sigor@sysoev.ru 
1239115Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
1240115Sigor@sysoev.ru 
1241115Sigor@sysoev.ru     nxt_router_engine_socket_count(&tmcf->creating);
1242115Sigor@sysoev.ru     nxt_router_engine_socket_count(&tmcf->updating);
1243115Sigor@sysoev.ru 
1244115Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
1245115Sigor@sysoev.ru 
1246115Sigor@sysoev.ru     return ret;
124753Sigor@sysoev.ru }
124853Sigor@sysoev.ru 
124953Sigor@sysoev.ru 
125053Sigor@sysoev.ru static nxt_int_t
1251115Sigor@sysoev.ru nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf,
1252115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
125353Sigor@sysoev.ru {
1254115Sigor@sysoev.ru     nxt_int_t              ret;
1255115Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
125653Sigor@sysoev.ru 
1257154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating,
1258154Sigor@sysoev.ru                                           nxt_router_listen_socket_create);
125953Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
126053Sigor@sysoev.ru         return ret;
126153Sigor@sysoev.ru     }
126253Sigor@sysoev.ru 
1263154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating,
1264154Sigor@sysoev.ru                                           nxt_router_listen_socket_update);
126553Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
126653Sigor@sysoev.ru         return ret;
126753Sigor@sysoev.ru     }
126853Sigor@sysoev.ru 
1269139Sigor@sysoev.ru     ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting);
1270115Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1271115Sigor@sysoev.ru         return ret;
1272115Sigor@sysoev.ru     }
1273115Sigor@sysoev.ru 
1274115Sigor@sysoev.ru     lock = &tmcf->conf->router->lock;
1275115Sigor@sysoev.ru 
1276115Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
1277115Sigor@sysoev.ru 
1278115Sigor@sysoev.ru     nxt_router_engine_socket_count(&tmcf->creating);
1279115Sigor@sysoev.ru 
1280115Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
1281115Sigor@sysoev.ru 
1282115Sigor@sysoev.ru     return ret;
128353Sigor@sysoev.ru }
128453Sigor@sysoev.ru 
128553Sigor@sysoev.ru 
128653Sigor@sysoev.ru static nxt_int_t
1287115Sigor@sysoev.ru nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf,
1288115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
128953Sigor@sysoev.ru {
129053Sigor@sysoev.ru     nxt_int_t  ret;
129153Sigor@sysoev.ru 
1292139Sigor@sysoev.ru     ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->updating);
129353Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
129453Sigor@sysoev.ru         return ret;
129553Sigor@sysoev.ru     }
129653Sigor@sysoev.ru 
1297139Sigor@sysoev.ru     return nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting);
129853Sigor@sysoev.ru }
129953Sigor@sysoev.ru 
130053Sigor@sysoev.ru 
130153Sigor@sysoev.ru static nxt_int_t
1302154Sigor@sysoev.ru nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf,
1303154Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets,
130453Sigor@sysoev.ru     nxt_work_handler_t handler)
130553Sigor@sysoev.ru {
1306153Sigor@sysoev.ru     nxt_joint_job_t          *job;
130753Sigor@sysoev.ru     nxt_queue_link_t         *qlk;
1308155Sigor@sysoev.ru     nxt_socket_conf_t        *skcf;
130953Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
131053Sigor@sysoev.ru 
131153Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
131253Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
131353Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
131453Sigor@sysoev.ru     {
1315154Sigor@sysoev.ru         job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t));
1316153Sigor@sysoev.ru         if (nxt_slow_path(job == NULL)) {
1317139Sigor@sysoev.ru             return NXT_ERROR;
1318139Sigor@sysoev.ru         }
1319139Sigor@sysoev.ru 
1320154Sigor@sysoev.ru         job->work.next = recf->jobs;
1321154Sigor@sysoev.ru         recf->jobs = &job->work;
1322154Sigor@sysoev.ru 
1323153Sigor@sysoev.ru         job->task = tmcf->engine->task;
1324153Sigor@sysoev.ru         job->work.handler = handler;
1325153Sigor@sysoev.ru         job->work.task = &job->task;
1326153Sigor@sysoev.ru         job->work.obj = job;
1327153Sigor@sysoev.ru         job->tmcf = tmcf;
132853Sigor@sysoev.ru 
1329154Sigor@sysoev.ru         tmcf->count++;
1330154Sigor@sysoev.ru 
1331154Sigor@sysoev.ru         joint = nxt_mp_alloc(tmcf->conf->mem_pool,
1332154Sigor@sysoev.ru                              sizeof(nxt_socket_conf_joint_t));
133353Sigor@sysoev.ru         if (nxt_slow_path(joint == NULL)) {
133453Sigor@sysoev.ru             return NXT_ERROR;
133553Sigor@sysoev.ru         }
133653Sigor@sysoev.ru 
1337153Sigor@sysoev.ru         job->work.data = joint;
133853Sigor@sysoev.ru 
133953Sigor@sysoev.ru         joint->count = 1;
1340155Sigor@sysoev.ru 
1341155Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
1342155Sigor@sysoev.ru         skcf->count++;
1343155Sigor@sysoev.ru         joint->socket_conf = skcf;
1344155Sigor@sysoev.ru 
134588Smax.romanov@nginx.com         joint->engine = recf->engine;
134653Sigor@sysoev.ru     }
134753Sigor@sysoev.ru 
134820Sigor@sysoev.ru     return NXT_OK;
134920Sigor@sysoev.ru }
135020Sigor@sysoev.ru 
135120Sigor@sysoev.ru 
1352115Sigor@sysoev.ru static void
1353115Sigor@sysoev.ru nxt_router_engine_socket_count(nxt_queue_t *sockets)
1354115Sigor@sysoev.ru {
1355115Sigor@sysoev.ru     nxt_queue_link_t   *qlk;
1356115Sigor@sysoev.ru     nxt_socket_conf_t  *skcf;
1357115Sigor@sysoev.ru 
1358115Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
1359115Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
1360115Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
1361115Sigor@sysoev.ru     {
1362115Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
1363115Sigor@sysoev.ru         skcf->socket->count++;
1364115Sigor@sysoev.ru     }
1365115Sigor@sysoev.ru }
1366115Sigor@sysoev.ru 
1367115Sigor@sysoev.ru 
136820Sigor@sysoev.ru static nxt_int_t
1369139Sigor@sysoev.ru nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf,
1370139Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets)
137120Sigor@sysoev.ru {
1372153Sigor@sysoev.ru     nxt_joint_job_t   *job;
137353Sigor@sysoev.ru     nxt_queue_link_t  *qlk;
137420Sigor@sysoev.ru 
137553Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
137653Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
137753Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
137853Sigor@sysoev.ru     {
1379154Sigor@sysoev.ru         job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t));
1380153Sigor@sysoev.ru         if (nxt_slow_path(job == NULL)) {
1381139Sigor@sysoev.ru             return NXT_ERROR;
1382139Sigor@sysoev.ru         }
1383139Sigor@sysoev.ru 
1384154Sigor@sysoev.ru         job->work.next = recf->jobs;
1385154Sigor@sysoev.ru         recf->jobs = &job->work;
1386154Sigor@sysoev.ru 
1387153Sigor@sysoev.ru         job->task = tmcf->engine->task;
1388153Sigor@sysoev.ru         job->work.handler = nxt_router_listen_socket_delete;
1389153Sigor@sysoev.ru         job->work.task = &job->task;
1390153Sigor@sysoev.ru         job->work.obj = job;
1391153Sigor@sysoev.ru         job->work.data = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
1392153Sigor@sysoev.ru         job->tmcf = tmcf;
1393154Sigor@sysoev.ru 
1394154Sigor@sysoev.ru         tmcf->count++;
139520Sigor@sysoev.ru     }
139620Sigor@sysoev.ru 
139753Sigor@sysoev.ru     return NXT_OK;
139853Sigor@sysoev.ru }
139920Sigor@sysoev.ru 
140020Sigor@sysoev.ru 
140153Sigor@sysoev.ru static nxt_int_t
140253Sigor@sysoev.ru nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt,
140353Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf)
140453Sigor@sysoev.ru {
140553Sigor@sysoev.ru     nxt_int_t                 ret;
140653Sigor@sysoev.ru     nxt_uint_t                i, threads;
140753Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
140820Sigor@sysoev.ru 
140953Sigor@sysoev.ru     recf = tmcf->engines->elts;
141053Sigor@sysoev.ru     threads = tmcf->conf->threads;
141120Sigor@sysoev.ru 
141253Sigor@sysoev.ru     for (i = tmcf->new_threads; i < threads; i++) {
141353Sigor@sysoev.ru         ret = nxt_router_thread_create(task, rt, recf[i].engine);
141453Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
141553Sigor@sysoev.ru             return ret;
141653Sigor@sysoev.ru         }
141720Sigor@sysoev.ru     }
141820Sigor@sysoev.ru 
141920Sigor@sysoev.ru     return NXT_OK;
142020Sigor@sysoev.ru }
142153Sigor@sysoev.ru 
142253Sigor@sysoev.ru 
142353Sigor@sysoev.ru static nxt_int_t
142453Sigor@sysoev.ru nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt,
142553Sigor@sysoev.ru     nxt_event_engine_t *engine)
142653Sigor@sysoev.ru {
142753Sigor@sysoev.ru     nxt_int_t            ret;
142853Sigor@sysoev.ru     nxt_thread_link_t    *link;
142953Sigor@sysoev.ru     nxt_thread_handle_t  handle;
143053Sigor@sysoev.ru 
143153Sigor@sysoev.ru     link = nxt_zalloc(sizeof(nxt_thread_link_t));
143253Sigor@sysoev.ru 
143353Sigor@sysoev.ru     if (nxt_slow_path(link == NULL)) {
143453Sigor@sysoev.ru         return NXT_ERROR;
143553Sigor@sysoev.ru     }
143653Sigor@sysoev.ru 
143753Sigor@sysoev.ru     link->start = nxt_router_thread_start;
143853Sigor@sysoev.ru     link->engine = engine;
143953Sigor@sysoev.ru     link->work.handler = nxt_router_thread_exit_handler;
144053Sigor@sysoev.ru     link->work.task = task;
144153Sigor@sysoev.ru     link->work.data = link;
144253Sigor@sysoev.ru 
144353Sigor@sysoev.ru     nxt_queue_insert_tail(&rt->engines, &engine->link);
144453Sigor@sysoev.ru 
144553Sigor@sysoev.ru     ret = nxt_thread_create(&handle, link);
144653Sigor@sysoev.ru 
144753Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
144853Sigor@sysoev.ru         nxt_queue_remove(&engine->link);
144953Sigor@sysoev.ru     }
145053Sigor@sysoev.ru 
145153Sigor@sysoev.ru     return ret;
145253Sigor@sysoev.ru }
145353Sigor@sysoev.ru 
145453Sigor@sysoev.ru 
145553Sigor@sysoev.ru static void
1456133Sigor@sysoev.ru nxt_router_apps_sort(nxt_router_t *router, nxt_router_temp_conf_t *tmcf)
1457133Sigor@sysoev.ru {
1458167Smax.romanov@nginx.com     nxt_app_t    *app;
1459167Smax.romanov@nginx.com     nxt_port_t   *port;
1460141Smax.romanov@nginx.com 
1461141Smax.romanov@nginx.com     nxt_queue_each(app, &router->apps, nxt_app_t, link) {
1462133Sigor@sysoev.ru 
1463133Sigor@sysoev.ru         nxt_queue_remove(&app->link);
1464133Sigor@sysoev.ru 
1465167Smax.romanov@nginx.com         nxt_thread_log_debug("about to remove app '%V' %p", &app->name, app);
1466167Smax.romanov@nginx.com 
1467163Smax.romanov@nginx.com         app->live = 0;
1468163Smax.romanov@nginx.com 
1469167Smax.romanov@nginx.com         if (nxt_router_app_free(NULL, app) != 0) {
1470163Smax.romanov@nginx.com             continue;
1471163Smax.romanov@nginx.com         }
1472163Smax.romanov@nginx.com 
1473167Smax.romanov@nginx.com         if (!nxt_queue_is_empty(&app->requests)) {
1474167Smax.romanov@nginx.com 
1475167Smax.romanov@nginx.com             nxt_thread_log_debug("app '%V' %p pending requests found",
1476167Smax.romanov@nginx.com                                  &app->name, app);
1477167Smax.romanov@nginx.com             continue;
1478163Smax.romanov@nginx.com         }
1479163Smax.romanov@nginx.com 
1480167Smax.romanov@nginx.com         do {
1481167Smax.romanov@nginx.com             port = nxt_router_app_get_port(app, 0);
1482167Smax.romanov@nginx.com             if (port == NULL) {
1483167Smax.romanov@nginx.com                 break;
1484167Smax.romanov@nginx.com             }
1485167Smax.romanov@nginx.com 
1486167Smax.romanov@nginx.com             nxt_thread_log_debug("port %p send quit", port);
1487167Smax.romanov@nginx.com 
1488167Smax.romanov@nginx.com             nxt_port_socket_write(&port->engine->task, port,
1489167Smax.romanov@nginx.com                                   NXT_PORT_MSG_QUIT, -1, 0, 0, NULL);
1490167Smax.romanov@nginx.com         } while (1);
1491167Smax.romanov@nginx.com 
1492141Smax.romanov@nginx.com     } nxt_queue_loop;
1493133Sigor@sysoev.ru 
1494133Sigor@sysoev.ru     nxt_queue_add(&router->apps, &tmcf->previous);
1495133Sigor@sysoev.ru     nxt_queue_add(&router->apps, &tmcf->apps);
1496133Sigor@sysoev.ru }
1497133Sigor@sysoev.ru 
1498133Sigor@sysoev.ru 
1499133Sigor@sysoev.ru static void
150053Sigor@sysoev.ru nxt_router_engines_post(nxt_router_temp_conf_t *tmcf)
150153Sigor@sysoev.ru {
150253Sigor@sysoev.ru     nxt_uint_t                n;
150353Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
150453Sigor@sysoev.ru 
150553Sigor@sysoev.ru     recf = tmcf->engines->elts;
150653Sigor@sysoev.ru 
150753Sigor@sysoev.ru     for (n = tmcf->engines->nelts; n != 0; n--) {
1508154Sigor@sysoev.ru         nxt_router_engine_post(recf);
150953Sigor@sysoev.ru         recf++;
151053Sigor@sysoev.ru     }
151153Sigor@sysoev.ru }
151253Sigor@sysoev.ru 
151353Sigor@sysoev.ru 
151453Sigor@sysoev.ru static void
1515154Sigor@sysoev.ru nxt_router_engine_post(nxt_router_engine_conf_t *recf)
151653Sigor@sysoev.ru {
1517154Sigor@sysoev.ru     nxt_work_t  *work, *next;
1518154Sigor@sysoev.ru 
1519154Sigor@sysoev.ru     for (work = recf->jobs; work != NULL; work = next) {
1520154Sigor@sysoev.ru         next = work->next;
1521154Sigor@sysoev.ru         work->next = NULL;
1522154Sigor@sysoev.ru 
1523154Sigor@sysoev.ru         nxt_event_engine_post(recf->engine, work);
152453Sigor@sysoev.ru     }
152553Sigor@sysoev.ru }
152653Sigor@sysoev.ru 
152753Sigor@sysoev.ru 
152853Sigor@sysoev.ru static void
1529119Smax.romanov@nginx.com nxt_router_app_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg);
153088Smax.romanov@nginx.com 
1531119Smax.romanov@nginx.com static nxt_port_handler_t  nxt_router_app_port_handlers[] = {
1532192Smax.romanov@nginx.com     NULL, /* NXT_PORT_MSG_QUIT         */
1533192Smax.romanov@nginx.com     NULL, /* NXT_PORT_MSG_NEW_PORT     */
1534192Smax.romanov@nginx.com     NULL, /* NXT_PORT_MSG_CHANGE_FILE  */
1535192Smax.romanov@nginx.com     /* TODO: remove mmap_handler from app ports */
1536192Smax.romanov@nginx.com     nxt_port_mmap_handler, /* NXT_PORT_MSG_MMAP         */
1537119Smax.romanov@nginx.com     nxt_router_app_data_handler,
1538192Smax.romanov@nginx.com     NULL, /* NXT_PORT_MSG_REMOVE_PID   */
1539192Smax.romanov@nginx.com     NULL, /* NXT_PORT_MSG_READY        */
1540192Smax.romanov@nginx.com     NULL, /* NXT_PORT_MSG_START_WORKER */
1541190Smax.romanov@nginx.com     nxt_port_rpc_handler,
1542190Smax.romanov@nginx.com     nxt_port_rpc_handler,
154388Smax.romanov@nginx.com };
154488Smax.romanov@nginx.com 
154588Smax.romanov@nginx.com 
154688Smax.romanov@nginx.com static void
154753Sigor@sysoev.ru nxt_router_thread_start(void *data)
154853Sigor@sysoev.ru {
1549141Smax.romanov@nginx.com     nxt_int_t           ret;
1550141Smax.romanov@nginx.com     nxt_port_t          *port;
155188Smax.romanov@nginx.com     nxt_task_t          *task;
155253Sigor@sysoev.ru     nxt_thread_t        *thread;
155353Sigor@sysoev.ru     nxt_thread_link_t   *link;
155453Sigor@sysoev.ru     nxt_event_engine_t  *engine;
155553Sigor@sysoev.ru 
155653Sigor@sysoev.ru     link = data;
155753Sigor@sysoev.ru     engine = link->engine;
155888Smax.romanov@nginx.com     task = &engine->task;
155953Sigor@sysoev.ru 
156053Sigor@sysoev.ru     thread = nxt_thread();
156153Sigor@sysoev.ru 
1562165Smax.romanov@nginx.com     nxt_event_engine_thread_adopt(engine);
1563165Smax.romanov@nginx.com 
156453Sigor@sysoev.ru     /* STUB */
156553Sigor@sysoev.ru     thread->runtime = engine->task.thread->runtime;
156653Sigor@sysoev.ru 
156753Sigor@sysoev.ru     engine->task.thread = thread;
156853Sigor@sysoev.ru     engine->task.log = thread->log;
156953Sigor@sysoev.ru     thread->engine = engine;
157063Sigor@sysoev.ru     thread->task = &engine->task;
157153Sigor@sysoev.ru     thread->fiber = &engine->fibers->fiber;
157253Sigor@sysoev.ru 
157363Sigor@sysoev.ru     engine->mem_pool = nxt_mp_create(4096, 128, 1024, 64);
157453Sigor@sysoev.ru 
1575197Smax.romanov@nginx.com     port = nxt_port_new(task, nxt_port_get_next_id(), nxt_pid,
1576197Smax.romanov@nginx.com                         NXT_PROCESS_ROUTER);
1577141Smax.romanov@nginx.com     if (nxt_slow_path(port == NULL)) {
1578141Smax.romanov@nginx.com         return;
1579141Smax.romanov@nginx.com     }
1580141Smax.romanov@nginx.com 
1581141Smax.romanov@nginx.com     ret = nxt_port_socket_init(task, port, 0);
1582141Smax.romanov@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
1583163Smax.romanov@nginx.com         nxt_mp_release(port->mem_pool, port);
1584141Smax.romanov@nginx.com         return;
1585141Smax.romanov@nginx.com     }
1586141Smax.romanov@nginx.com 
1587141Smax.romanov@nginx.com     engine->port = port;
1588141Smax.romanov@nginx.com 
1589141Smax.romanov@nginx.com     nxt_port_enable(task, port, nxt_router_app_port_handlers);
1590141Smax.romanov@nginx.com 
159153Sigor@sysoev.ru     nxt_event_engine_start(engine);
159253Sigor@sysoev.ru }
159353Sigor@sysoev.ru 
159453Sigor@sysoev.ru 
159553Sigor@sysoev.ru static void
159653Sigor@sysoev.ru nxt_router_listen_socket_create(nxt_task_t *task, void *obj, void *data)
159753Sigor@sysoev.ru {
1598153Sigor@sysoev.ru     nxt_joint_job_t          *job;
159953Sigor@sysoev.ru     nxt_listen_event_t       *listen;
160053Sigor@sysoev.ru     nxt_listen_socket_t      *ls;
160153Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
160253Sigor@sysoev.ru 
1603153Sigor@sysoev.ru     job = obj;
160453Sigor@sysoev.ru     joint = data;
160553Sigor@sysoev.ru 
160653Sigor@sysoev.ru     ls = &joint->socket_conf->listen;
160753Sigor@sysoev.ru 
1608159Sigor@sysoev.ru     nxt_queue_insert_tail(&task->thread->engine->joints, &joint->link);
1609159Sigor@sysoev.ru 
161053Sigor@sysoev.ru     listen = nxt_listen_event(task, ls);
161153Sigor@sysoev.ru     if (nxt_slow_path(listen == NULL)) {
161253Sigor@sysoev.ru         nxt_router_listen_socket_release(task, joint);
161353Sigor@sysoev.ru         return;
161453Sigor@sysoev.ru     }
161553Sigor@sysoev.ru 
161653Sigor@sysoev.ru     listen->socket.data = joint;
1617139Sigor@sysoev.ru 
1618153Sigor@sysoev.ru     job->work.next = NULL;
1619153Sigor@sysoev.ru     job->work.handler = nxt_router_conf_wait;
1620153Sigor@sysoev.ru 
1621153Sigor@sysoev.ru     nxt_event_engine_post(job->tmcf->engine, &job->work);
162253Sigor@sysoev.ru }
162353Sigor@sysoev.ru 
162453Sigor@sysoev.ru 
162553Sigor@sysoev.ru nxt_inline nxt_listen_event_t *
162653Sigor@sysoev.ru nxt_router_listen_event(nxt_queue_t *listen_connections,
162753Sigor@sysoev.ru     nxt_socket_conf_t *skcf)
162853Sigor@sysoev.ru {
1629115Sigor@sysoev.ru     nxt_socket_t        fd;
1630115Sigor@sysoev.ru     nxt_queue_link_t    *qlk;
163153Sigor@sysoev.ru     nxt_listen_event_t  *listen;
163253Sigor@sysoev.ru 
1633115Sigor@sysoev.ru     fd = skcf->socket->fd;
163453Sigor@sysoev.ru 
1635115Sigor@sysoev.ru     for (qlk = nxt_queue_first(listen_connections);
1636115Sigor@sysoev.ru          qlk != nxt_queue_tail(listen_connections);
1637115Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
163853Sigor@sysoev.ru     {
1639115Sigor@sysoev.ru         listen = nxt_queue_link_data(qlk, nxt_listen_event_t, link);
164053Sigor@sysoev.ru 
1641115Sigor@sysoev.ru         if (fd == listen->socket.fd) {
164253Sigor@sysoev.ru             return listen;
164353Sigor@sysoev.ru         }
164453Sigor@sysoev.ru     }
164553Sigor@sysoev.ru 
164653Sigor@sysoev.ru     return NULL;
164753Sigor@sysoev.ru }
164853Sigor@sysoev.ru 
164953Sigor@sysoev.ru 
165053Sigor@sysoev.ru static void
165153Sigor@sysoev.ru nxt_router_listen_socket_update(nxt_task_t *task, void *obj, void *data)
165253Sigor@sysoev.ru {
1653153Sigor@sysoev.ru     nxt_joint_job_t          *job;
165453Sigor@sysoev.ru     nxt_event_engine_t       *engine;
165553Sigor@sysoev.ru     nxt_listen_event_t       *listen;
165653Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint, *old;
165753Sigor@sysoev.ru 
1658153Sigor@sysoev.ru     job = obj;
165953Sigor@sysoev.ru     joint = data;
166053Sigor@sysoev.ru 
1661139Sigor@sysoev.ru     engine = task->thread->engine;
1662139Sigor@sysoev.ru 
1663159Sigor@sysoev.ru     nxt_queue_insert_tail(&engine->joints, &joint->link);
1664159Sigor@sysoev.ru 
166553Sigor@sysoev.ru     listen = nxt_router_listen_event(&engine->listen_connections,
166653Sigor@sysoev.ru                                      joint->socket_conf);
166753Sigor@sysoev.ru 
166853Sigor@sysoev.ru     old = listen->socket.data;
166953Sigor@sysoev.ru     listen->socket.data = joint;
1670177Sigor@sysoev.ru     listen->listen = &joint->socket_conf->listen;
167153Sigor@sysoev.ru 
1672153Sigor@sysoev.ru     job->work.next = NULL;
1673153Sigor@sysoev.ru     job->work.handler = nxt_router_conf_wait;
1674153Sigor@sysoev.ru 
1675153Sigor@sysoev.ru     nxt_event_engine_post(job->tmcf->engine, &job->work);
1676139Sigor@sysoev.ru 
1677181Smax.romanov@nginx.com     /*
1678181Smax.romanov@nginx.com      * The task is allocated from configuration temporary
1679181Smax.romanov@nginx.com      * memory pool so it can be freed after engine post operation.
1680181Smax.romanov@nginx.com      */
1681181Smax.romanov@nginx.com 
1682181Smax.romanov@nginx.com     nxt_router_conf_release(&engine->task, old);
168353Sigor@sysoev.ru }
168453Sigor@sysoev.ru 
168553Sigor@sysoev.ru 
168653Sigor@sysoev.ru static void
168753Sigor@sysoev.ru nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, void *data)
168853Sigor@sysoev.ru {
1689153Sigor@sysoev.ru     nxt_joint_job_t     *job;
1690153Sigor@sysoev.ru     nxt_socket_conf_t   *skcf;
1691153Sigor@sysoev.ru     nxt_listen_event_t  *listen;
1692153Sigor@sysoev.ru     nxt_event_engine_t  *engine;
1693153Sigor@sysoev.ru 
1694153Sigor@sysoev.ru     job = obj;
169553Sigor@sysoev.ru     skcf = data;
169653Sigor@sysoev.ru 
1697139Sigor@sysoev.ru     engine = task->thread->engine;
1698139Sigor@sysoev.ru 
169953Sigor@sysoev.ru     listen = nxt_router_listen_event(&engine->listen_connections, skcf);
170053Sigor@sysoev.ru 
170153Sigor@sysoev.ru     nxt_fd_event_delete(engine, &listen->socket);
170253Sigor@sysoev.ru 
1703163Smax.romanov@nginx.com     nxt_debug(task, "engine %p: listen socket delete: %d", engine,
1704163Smax.romanov@nginx.com               listen->socket.fd);
1705163Smax.romanov@nginx.com 
170653Sigor@sysoev.ru     listen->timer.handler = nxt_router_listen_socket_close;
170753Sigor@sysoev.ru     listen->timer.work_queue = &engine->fast_work_queue;
170853Sigor@sysoev.ru 
170953Sigor@sysoev.ru     nxt_timer_add(engine, &listen->timer, 0);
1710139Sigor@sysoev.ru 
1711153Sigor@sysoev.ru     job->work.next = NULL;
1712153Sigor@sysoev.ru     job->work.handler = nxt_router_conf_wait;
1713153Sigor@sysoev.ru 
1714153Sigor@sysoev.ru     nxt_event_engine_post(job->tmcf->engine, &job->work);
171553Sigor@sysoev.ru }
171653Sigor@sysoev.ru 
171753Sigor@sysoev.ru 
171853Sigor@sysoev.ru static void
171953Sigor@sysoev.ru nxt_router_listen_socket_close(nxt_task_t *task, void *obj, void *data)
172053Sigor@sysoev.ru {
172153Sigor@sysoev.ru     nxt_timer_t              *timer;
172253Sigor@sysoev.ru     nxt_listen_event_t       *listen;
172353Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
172453Sigor@sysoev.ru 
172553Sigor@sysoev.ru     timer = obj;
172653Sigor@sysoev.ru     listen = nxt_timer_data(timer, nxt_listen_event_t, timer);
172753Sigor@sysoev.ru     joint = listen->socket.data;
172853Sigor@sysoev.ru 
1729163Smax.romanov@nginx.com     nxt_debug(task, "engine %p: listen socket close: %d", task->thread->engine,
1730163Smax.romanov@nginx.com               listen->socket.fd);
1731163Smax.romanov@nginx.com 
173253Sigor@sysoev.ru     nxt_queue_remove(&listen->link);
1733123Smax.romanov@nginx.com 
1734123Smax.romanov@nginx.com     /* 'task' refers to listen->task and we cannot use after nxt_free() */
1735123Smax.romanov@nginx.com     task = &task->thread->engine->task;
1736123Smax.romanov@nginx.com 
173753Sigor@sysoev.ru     nxt_free(listen);
173853Sigor@sysoev.ru 
173953Sigor@sysoev.ru     nxt_router_listen_socket_release(task, joint);
174053Sigor@sysoev.ru }
174153Sigor@sysoev.ru 
174253Sigor@sysoev.ru 
174353Sigor@sysoev.ru static void
174453Sigor@sysoev.ru nxt_router_listen_socket_release(nxt_task_t *task,
174553Sigor@sysoev.ru     nxt_socket_conf_joint_t *joint)
174653Sigor@sysoev.ru {
1747118Sigor@sysoev.ru     nxt_socket_conf_t      *skcf;
1748115Sigor@sysoev.ru     nxt_router_socket_t    *rtsk;
174953Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
175053Sigor@sysoev.ru 
1751118Sigor@sysoev.ru     skcf = joint->socket_conf;
1752118Sigor@sysoev.ru     rtsk = skcf->socket;
1753118Sigor@sysoev.ru     lock = &skcf->router_conf->router->lock;
175453Sigor@sysoev.ru 
175553Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
175653Sigor@sysoev.ru 
1757163Smax.romanov@nginx.com     nxt_debug(task, "engine %p: listen socket release: rtsk->count %D",
1758163Smax.romanov@nginx.com               task->thread->engine, rtsk->count);
1759163Smax.romanov@nginx.com 
1760115Sigor@sysoev.ru     if (--rtsk->count != 0) {
1761115Sigor@sysoev.ru         rtsk = NULL;
176253Sigor@sysoev.ru     }
176353Sigor@sysoev.ru 
176453Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
176553Sigor@sysoev.ru 
1766115Sigor@sysoev.ru     if (rtsk != NULL) {
1767115Sigor@sysoev.ru         nxt_socket_close(task, rtsk->fd);
1768115Sigor@sysoev.ru         nxt_free(rtsk);
1769118Sigor@sysoev.ru         skcf->socket = NULL;
177053Sigor@sysoev.ru     }
177153Sigor@sysoev.ru 
177253Sigor@sysoev.ru     nxt_router_conf_release(task, joint);
177353Sigor@sysoev.ru }
177453Sigor@sysoev.ru 
177553Sigor@sysoev.ru 
177653Sigor@sysoev.ru static void
177753Sigor@sysoev.ru nxt_router_conf_release(nxt_task_t *task, nxt_socket_conf_joint_t *joint)
177853Sigor@sysoev.ru {
1779156Sigor@sysoev.ru     nxt_bool_t             exit;
178053Sigor@sysoev.ru     nxt_socket_conf_t      *skcf;
178153Sigor@sysoev.ru     nxt_router_conf_t      *rtcf;
178253Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
178353Sigor@sysoev.ru 
1784163Smax.romanov@nginx.com     nxt_debug(task, "conf joint %p count: %D", joint, joint->count);
178553Sigor@sysoev.ru 
178653Sigor@sysoev.ru     if (--joint->count != 0) {
178753Sigor@sysoev.ru         return;
178853Sigor@sysoev.ru     }
178953Sigor@sysoev.ru 
179053Sigor@sysoev.ru     nxt_queue_remove(&joint->link);
179153Sigor@sysoev.ru 
179253Sigor@sysoev.ru     skcf = joint->socket_conf;
179353Sigor@sysoev.ru     rtcf = skcf->router_conf;
179453Sigor@sysoev.ru     lock = &rtcf->router->lock;
179553Sigor@sysoev.ru 
179653Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
179753Sigor@sysoev.ru 
1798163Smax.romanov@nginx.com     nxt_debug(task, "conf skcf %p: %D, rtcf %p: %D", skcf, skcf->count,
1799163Smax.romanov@nginx.com               rtcf, rtcf->count);
1800163Smax.romanov@nginx.com 
180153Sigor@sysoev.ru     if (--skcf->count != 0) {
180253Sigor@sysoev.ru         rtcf = NULL;
180353Sigor@sysoev.ru 
180453Sigor@sysoev.ru     } else {
180553Sigor@sysoev.ru         nxt_queue_remove(&skcf->link);
180653Sigor@sysoev.ru 
180753Sigor@sysoev.ru         if (--rtcf->count != 0) {
180853Sigor@sysoev.ru             rtcf = NULL;
180953Sigor@sysoev.ru         }
181053Sigor@sysoev.ru     }
181153Sigor@sysoev.ru 
181253Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
181353Sigor@sysoev.ru 
1814141Smax.romanov@nginx.com     /* TODO remove engine->port */
1815141Smax.romanov@nginx.com     /* TODO excude from connected ports */
1816141Smax.romanov@nginx.com 
1817156Sigor@sysoev.ru     /* The joint content can be used before memory pool destruction. */
1818156Sigor@sysoev.ru     exit = nxt_queue_is_empty(&joint->engine->joints);
1819156Sigor@sysoev.ru 
182053Sigor@sysoev.ru     if (rtcf != NULL) {
1821115Sigor@sysoev.ru         nxt_debug(task, "old router conf is destroyed");
1822131Smax.romanov@nginx.com 
1823131Smax.romanov@nginx.com         nxt_mp_thread_adopt(rtcf->mem_pool);
1824131Smax.romanov@nginx.com 
182565Sigor@sysoev.ru         nxt_mp_destroy(rtcf->mem_pool);
182653Sigor@sysoev.ru     }
182753Sigor@sysoev.ru 
1828156Sigor@sysoev.ru     if (exit) {
182953Sigor@sysoev.ru         nxt_thread_exit(task->thread);
183053Sigor@sysoev.ru     }
183153Sigor@sysoev.ru }
183253Sigor@sysoev.ru 
183353Sigor@sysoev.ru 
183453Sigor@sysoev.ru static void
183553Sigor@sysoev.ru nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, void *data)
183653Sigor@sysoev.ru {
1837141Smax.romanov@nginx.com     nxt_port_t           *port;
183853Sigor@sysoev.ru     nxt_thread_link_t    *link;
183953Sigor@sysoev.ru     nxt_event_engine_t   *engine;
184053Sigor@sysoev.ru     nxt_thread_handle_t  handle;
184153Sigor@sysoev.ru 
184258Svbart@nginx.com     handle = (nxt_thread_handle_t) obj;
184353Sigor@sysoev.ru     link = data;
184453Sigor@sysoev.ru 
184553Sigor@sysoev.ru     nxt_thread_wait(handle);
184653Sigor@sysoev.ru 
184753Sigor@sysoev.ru     engine = link->engine;
184853Sigor@sysoev.ru 
184953Sigor@sysoev.ru     nxt_queue_remove(&engine->link);
185053Sigor@sysoev.ru 
1851141Smax.romanov@nginx.com     port = engine->port;
1852141Smax.romanov@nginx.com 
1853141Smax.romanov@nginx.com     // TODO notify all apps
1854141Smax.romanov@nginx.com 
1855163Smax.romanov@nginx.com     nxt_mp_thread_adopt(port->mem_pool);
1856163Smax.romanov@nginx.com     nxt_port_release(port);
1857163Smax.romanov@nginx.com 
1858163Smax.romanov@nginx.com     nxt_mp_thread_adopt(engine->mem_pool);
185963Sigor@sysoev.ru     nxt_mp_destroy(engine->mem_pool);
186053Sigor@sysoev.ru 
186153Sigor@sysoev.ru     nxt_event_engine_free(engine);
186253Sigor@sysoev.ru 
186353Sigor@sysoev.ru     nxt_free(link);
186453Sigor@sysoev.ru }
186553Sigor@sysoev.ru 
186653Sigor@sysoev.ru 
1867206Smax.romanov@nginx.com static const nxt_conn_state_t  nxt_router_conn_read_header_state
186853Sigor@sysoev.ru     nxt_aligned(64) =
186953Sigor@sysoev.ru {
187053Sigor@sysoev.ru     .ready_handler = nxt_router_conn_http_header_parse,
187153Sigor@sysoev.ru     .close_handler = nxt_router_conn_close,
187253Sigor@sysoev.ru     .error_handler = nxt_router_conn_error,
187353Sigor@sysoev.ru 
187453Sigor@sysoev.ru     .timer_handler = nxt_router_conn_timeout,
187553Sigor@sysoev.ru     .timer_value = nxt_router_conn_timeout_value,
187653Sigor@sysoev.ru     .timer_data = offsetof(nxt_socket_conf_t, header_read_timeout),
187753Sigor@sysoev.ru };
187853Sigor@sysoev.ru 
187953Sigor@sysoev.ru 
1880206Smax.romanov@nginx.com static const nxt_conn_state_t  nxt_router_conn_read_body_state
1881206Smax.romanov@nginx.com     nxt_aligned(64) =
1882206Smax.romanov@nginx.com {
1883206Smax.romanov@nginx.com     .ready_handler = nxt_router_conn_http_body_read,
1884206Smax.romanov@nginx.com     .close_handler = nxt_router_conn_close,
1885206Smax.romanov@nginx.com     .error_handler = nxt_router_conn_error,
1886206Smax.romanov@nginx.com 
1887206Smax.romanov@nginx.com     .timer_handler = nxt_router_conn_timeout,
1888206Smax.romanov@nginx.com     .timer_value = nxt_router_conn_timeout_value,
1889206Smax.romanov@nginx.com     .timer_data = offsetof(nxt_socket_conf_t, body_read_timeout),
1890206Smax.romanov@nginx.com     .timer_autoreset = 1,
1891206Smax.romanov@nginx.com };
1892206Smax.romanov@nginx.com 
1893206Smax.romanov@nginx.com 
189453Sigor@sysoev.ru static void
189553Sigor@sysoev.ru nxt_router_conn_init(nxt_task_t *task, void *obj, void *data)
189653Sigor@sysoev.ru {
189753Sigor@sysoev.ru     size_t                   size;
189862Sigor@sysoev.ru     nxt_conn_t               *c;
189953Sigor@sysoev.ru     nxt_event_engine_t       *engine;
190053Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
190153Sigor@sysoev.ru 
190253Sigor@sysoev.ru     c = obj;
190353Sigor@sysoev.ru     joint = data;
190453Sigor@sysoev.ru 
190553Sigor@sysoev.ru     nxt_debug(task, "router conn init");
190653Sigor@sysoev.ru 
190753Sigor@sysoev.ru     joint->count++;
190853Sigor@sysoev.ru 
190953Sigor@sysoev.ru     size = joint->socket_conf->header_buffer_size;
191053Sigor@sysoev.ru     c->read = nxt_buf_mem_alloc(c->mem_pool, size, 0);
191153Sigor@sysoev.ru 
191253Sigor@sysoev.ru     c->socket.data = NULL;
191353Sigor@sysoev.ru 
191453Sigor@sysoev.ru     engine = task->thread->engine;
191553Sigor@sysoev.ru     c->read_work_queue = &engine->fast_work_queue;
191653Sigor@sysoev.ru     c->write_work_queue = &engine->fast_work_queue;
191753Sigor@sysoev.ru 
1918206Smax.romanov@nginx.com     c->read_state = &nxt_router_conn_read_header_state;
191953Sigor@sysoev.ru 
192062Sigor@sysoev.ru     nxt_conn_read(engine, c);
192153Sigor@sysoev.ru }
192253Sigor@sysoev.ru 
192353Sigor@sysoev.ru 
192462Sigor@sysoev.ru static const nxt_conn_state_t  nxt_router_conn_write_state
192553Sigor@sysoev.ru     nxt_aligned(64) =
192653Sigor@sysoev.ru {
192788Smax.romanov@nginx.com     .ready_handler = nxt_router_conn_ready,
192853Sigor@sysoev.ru     .close_handler = nxt_router_conn_close,
192953Sigor@sysoev.ru     .error_handler = nxt_router_conn_error,
193053Sigor@sysoev.ru };
193153Sigor@sysoev.ru 
193253Sigor@sysoev.ru 
193353Sigor@sysoev.ru static void
1934119Smax.romanov@nginx.com nxt_router_app_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
193588Smax.romanov@nginx.com {
193688Smax.romanov@nginx.com     size_t               dump_size;
1937194Smax.romanov@nginx.com     nxt_buf_t            *b, *last;
193888Smax.romanov@nginx.com     nxt_conn_t           *c;
193988Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
194088Smax.romanov@nginx.com     nxt_event_engine_t   *engine;
194188Smax.romanov@nginx.com 
194288Smax.romanov@nginx.com     b = msg->buf;
194388Smax.romanov@nginx.com     engine = task->thread->engine;
194488Smax.romanov@nginx.com 
194588Smax.romanov@nginx.com     rc = nxt_event_engine_request_find(engine, msg->port_msg.stream);
194688Smax.romanov@nginx.com     if (nxt_slow_path(rc == NULL)) {
194788Smax.romanov@nginx.com         nxt_debug(task, "request id %08uxD not found", msg->port_msg.stream);
194888Smax.romanov@nginx.com 
194988Smax.romanov@nginx.com         return;
195088Smax.romanov@nginx.com     }
195188Smax.romanov@nginx.com 
195288Smax.romanov@nginx.com     c = rc->conn;
195388Smax.romanov@nginx.com 
195488Smax.romanov@nginx.com     dump_size = nxt_buf_used_size(b);
195588Smax.romanov@nginx.com 
195688Smax.romanov@nginx.com     if (dump_size > 300) {
195788Smax.romanov@nginx.com         dump_size = 300;
195888Smax.romanov@nginx.com     }
195988Smax.romanov@nginx.com 
1960119Smax.romanov@nginx.com     nxt_debug(task, "%srouter app data (%z): %*s",
196188Smax.romanov@nginx.com               msg->port_msg.last ? "last " : "", msg->size, dump_size,
196288Smax.romanov@nginx.com               b->mem.pos);
196388Smax.romanov@nginx.com 
196488Smax.romanov@nginx.com     if (msg->size == 0) {
196588Smax.romanov@nginx.com         b = NULL;
196688Smax.romanov@nginx.com     }
196788Smax.romanov@nginx.com 
196888Smax.romanov@nginx.com     if (msg->port_msg.last != 0) {
196988Smax.romanov@nginx.com         nxt_debug(task, "router data create last buf");
197088Smax.romanov@nginx.com 
197188Smax.romanov@nginx.com         last = nxt_buf_sync_alloc(c->mem_pool, NXT_BUF_SYNC_LAST);
197288Smax.romanov@nginx.com         if (nxt_slow_path(last == NULL)) {
197388Smax.romanov@nginx.com             /* TODO pogorevaTb */
197488Smax.romanov@nginx.com         }
197588Smax.romanov@nginx.com 
197688Smax.romanov@nginx.com         nxt_buf_chain_add(&b, last);
1977167Smax.romanov@nginx.com 
1978167Smax.romanov@nginx.com         if (rc->app_port != NULL) {
1979167Smax.romanov@nginx.com             nxt_router_app_release_port(task, rc->app_port, rc->app_port->app);
1980167Smax.romanov@nginx.com 
1981167Smax.romanov@nginx.com             rc->app_port = NULL;
1982167Smax.romanov@nginx.com         }
1983206Smax.romanov@nginx.com 
1984206Smax.romanov@nginx.com         rc->conn = NULL;
198588Smax.romanov@nginx.com     }
198688Smax.romanov@nginx.com 
198788Smax.romanov@nginx.com     if (b == NULL) {
198888Smax.romanov@nginx.com         return;
198988Smax.romanov@nginx.com     }
199088Smax.romanov@nginx.com 
1991206Smax.romanov@nginx.com     if (msg->buf == b) {
1992206Smax.romanov@nginx.com         /* Disable instant buffer completion/re-using by port. */
1993206Smax.romanov@nginx.com         msg->buf = NULL;
1994206Smax.romanov@nginx.com     }
1995194Smax.romanov@nginx.com 
199688Smax.romanov@nginx.com     if (c->write == NULL) {
199788Smax.romanov@nginx.com         c->write = b;
199888Smax.romanov@nginx.com         c->write_state = &nxt_router_conn_write_state;
199988Smax.romanov@nginx.com 
200088Smax.romanov@nginx.com         nxt_conn_write(task->thread->engine, c);
200188Smax.romanov@nginx.com     } else {
200288Smax.romanov@nginx.com         nxt_debug(task, "router data attach out bufs to existing chain");
200388Smax.romanov@nginx.com 
200488Smax.romanov@nginx.com         nxt_buf_chain_add(&c->write, b);
200588Smax.romanov@nginx.com     }
200688Smax.romanov@nginx.com }
200788Smax.romanov@nginx.com 
2008141Smax.romanov@nginx.com nxt_inline const char *
2009141Smax.romanov@nginx.com nxt_router_text_by_code(int code)
2010141Smax.romanov@nginx.com {
2011141Smax.romanov@nginx.com     switch (code) {
2012141Smax.romanov@nginx.com     case 400: return "Bad request";
2013141Smax.romanov@nginx.com     case 404: return "Not found";
2014141Smax.romanov@nginx.com     case 403: return "Forbidden";
2015206Smax.romanov@nginx.com     case 408: return "Request Timeout";
2016206Smax.romanov@nginx.com     case 411: return "Length Required";
2017206Smax.romanov@nginx.com     case 413: return "Request Entity Too Large";
2018141Smax.romanov@nginx.com     case 500:
2019141Smax.romanov@nginx.com     default:  return "Internal server error";
2020141Smax.romanov@nginx.com     }
2021141Smax.romanov@nginx.com }
2022141Smax.romanov@nginx.com 
2023163Smax.romanov@nginx.com 
2024163Smax.romanov@nginx.com static nxt_buf_t *
2025163Smax.romanov@nginx.com nxt_router_get_error_buf(nxt_task_t *task, nxt_mp_t *mp, int code,
2026163Smax.romanov@nginx.com     const char* fmt, va_list args)
202788Smax.romanov@nginx.com {
2028163Smax.romanov@nginx.com     nxt_buf_t   *b, *last;
2029163Smax.romanov@nginx.com     const char  *msg;
2030163Smax.romanov@nginx.com 
2031163Smax.romanov@nginx.com     b = nxt_buf_mem_ts_alloc(task, mp, 16384);
2032141Smax.romanov@nginx.com     if (nxt_slow_path(b == NULL)) {
2033163Smax.romanov@nginx.com         return NULL;
2034141Smax.romanov@nginx.com     }
2035141Smax.romanov@nginx.com 
2036141Smax.romanov@nginx.com     b->mem.free = nxt_sprintf(b->mem.free, b->mem.end,
2037141Smax.romanov@nginx.com         "HTTP/1.0 %d %s\r\n"
2038141Smax.romanov@nginx.com         "Content-Type: text/plain\r\n"
2039141Smax.romanov@nginx.com         "Connection: close\r\n\r\n",
2040141Smax.romanov@nginx.com         code, nxt_router_text_by_code(code));
2041141Smax.romanov@nginx.com 
2042141Smax.romanov@nginx.com     msg = (const char *) b->mem.free;
2043141Smax.romanov@nginx.com 
2044141Smax.romanov@nginx.com     b->mem.free = nxt_vsprintf(b->mem.free, b->mem.end, fmt, args);
2045206Smax.romanov@nginx.com     b->mem.free[0] = '\0';
2046141Smax.romanov@nginx.com 
2047141Smax.romanov@nginx.com     nxt_log_alert(task->log, "error %d: %s", code, msg);
2048141Smax.romanov@nginx.com 
2049163Smax.romanov@nginx.com     last = nxt_buf_mem_ts_alloc(task, mp, 0);
2050163Smax.romanov@nginx.com 
2051141Smax.romanov@nginx.com     if (nxt_slow_path(last == NULL)) {
2052163Smax.romanov@nginx.com         nxt_mp_release(mp, b);
2053163Smax.romanov@nginx.com         return NULL;
2054141Smax.romanov@nginx.com     }
2055141Smax.romanov@nginx.com 
2056163Smax.romanov@nginx.com     nxt_buf_set_sync(last);
2057163Smax.romanov@nginx.com     nxt_buf_set_last(last);
2058163Smax.romanov@nginx.com 
2059141Smax.romanov@nginx.com     nxt_buf_chain_add(&b, last);
2060141Smax.romanov@nginx.com 
2061163Smax.romanov@nginx.com     return b;
2062163Smax.romanov@nginx.com }
2063163Smax.romanov@nginx.com 
2064163Smax.romanov@nginx.com 
2065163Smax.romanov@nginx.com 
2066163Smax.romanov@nginx.com static void
2067163Smax.romanov@nginx.com nxt_router_gen_error(nxt_task_t *task, nxt_conn_t *c, int code,
2068163Smax.romanov@nginx.com     const char* fmt, ...)
2069163Smax.romanov@nginx.com {
2070163Smax.romanov@nginx.com     va_list    args;
2071163Smax.romanov@nginx.com     nxt_buf_t  *b;
2072163Smax.romanov@nginx.com 
2073163Smax.romanov@nginx.com     va_start(args, fmt);
2074163Smax.romanov@nginx.com     b = nxt_router_get_error_buf(task, c->mem_pool, code, fmt, args);
2075163Smax.romanov@nginx.com     va_end(args);
2076163Smax.romanov@nginx.com 
2077206Smax.romanov@nginx.com     if (c->socket.data != NULL) {
2078206Smax.romanov@nginx.com         nxt_mp_free(c->mem_pool, c->socket.data);
2079206Smax.romanov@nginx.com         c->socket.data = NULL;
2080206Smax.romanov@nginx.com     }
2081206Smax.romanov@nginx.com 
2082141Smax.romanov@nginx.com     if (c->write == NULL) {
2083141Smax.romanov@nginx.com         c->write = b;
2084141Smax.romanov@nginx.com         c->write_state = &nxt_router_conn_write_state;
2085141Smax.romanov@nginx.com 
2086141Smax.romanov@nginx.com         nxt_conn_write(task->thread->engine, c);
2087141Smax.romanov@nginx.com     } else {
2088141Smax.romanov@nginx.com         nxt_debug(task, "router data attach out bufs to existing chain");
2089141Smax.romanov@nginx.com 
2090141Smax.romanov@nginx.com         nxt_buf_chain_add(&c->write, b);
2091141Smax.romanov@nginx.com     }
2092141Smax.romanov@nginx.com }
2093141Smax.romanov@nginx.com 
2094141Smax.romanov@nginx.com 
2095141Smax.romanov@nginx.com static void
2096192Smax.romanov@nginx.com nxt_router_sw_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, void *data)
2097192Smax.romanov@nginx.com {
2098192Smax.romanov@nginx.com     nxt_start_worker_t  *sw;
2099192Smax.romanov@nginx.com 
2100192Smax.romanov@nginx.com     sw = data;
2101192Smax.romanov@nginx.com 
2102192Smax.romanov@nginx.com     nxt_assert(sw != NULL);
2103192Smax.romanov@nginx.com     nxt_assert(sw->app->pending_workers != 0);
2104192Smax.romanov@nginx.com 
2105192Smax.romanov@nginx.com     msg->new_port->app = sw->app;
2106192Smax.romanov@nginx.com 
2107192Smax.romanov@nginx.com     sw->app->pending_workers--;
2108192Smax.romanov@nginx.com     sw->app->workers++;
2109192Smax.romanov@nginx.com 
2110192Smax.romanov@nginx.com     nxt_debug(task, "sw %p got port %p", sw, msg->new_port);
2111192Smax.romanov@nginx.com 
2112192Smax.romanov@nginx.com     nxt_router_app_release_port(task, msg->new_port, sw->app);
2113192Smax.romanov@nginx.com 
2114192Smax.romanov@nginx.com     nxt_router_sw_release(task, sw);
2115192Smax.romanov@nginx.com }
2116192Smax.romanov@nginx.com 
2117192Smax.romanov@nginx.com 
2118192Smax.romanov@nginx.com static void
2119192Smax.romanov@nginx.com nxt_router_sw_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, void *data)
2120192Smax.romanov@nginx.com {
2121192Smax.romanov@nginx.com     nxt_start_worker_t  *sw;
2122192Smax.romanov@nginx.com 
2123192Smax.romanov@nginx.com     sw = data;
2124192Smax.romanov@nginx.com 
2125192Smax.romanov@nginx.com     nxt_assert(sw != NULL);
2126192Smax.romanov@nginx.com     nxt_assert(sw->app->pending_workers != 0);
2127192Smax.romanov@nginx.com 
2128192Smax.romanov@nginx.com     sw->app->pending_workers--;
2129192Smax.romanov@nginx.com 
2130192Smax.romanov@nginx.com     nxt_debug(task, "sw %p error, failed to start app '%V'", sw, &sw->app->name);
2131192Smax.romanov@nginx.com 
2132192Smax.romanov@nginx.com     nxt_router_sw_release(task, sw);
2133192Smax.romanov@nginx.com }
2134192Smax.romanov@nginx.com 
2135192Smax.romanov@nginx.com 
2136192Smax.romanov@nginx.com static void
2137141Smax.romanov@nginx.com nxt_router_send_sw_request(nxt_task_t *task, void *obj, void *data)
2138141Smax.romanov@nginx.com {
2139174Sigor@sysoev.ru     size_t              size;
2140192Smax.romanov@nginx.com     uint32_t            stream;
2141141Smax.romanov@nginx.com     nxt_buf_t           *b;
2142141Smax.romanov@nginx.com     nxt_app_t           *app;
2143240Sigor@sysoev.ru     nxt_port_t          *main_port, *router_port;
2144141Smax.romanov@nginx.com     nxt_runtime_t       *rt;
2145141Smax.romanov@nginx.com     nxt_start_worker_t  *sw;
2146141Smax.romanov@nginx.com 
2147141Smax.romanov@nginx.com     sw = obj;
2148141Smax.romanov@nginx.com     app = sw->app;
2149141Smax.romanov@nginx.com 
2150167Smax.romanov@nginx.com     nxt_queue_insert_tail(&app->requests, &sw->ra->link);
2151167Smax.romanov@nginx.com 
2152163Smax.romanov@nginx.com     if (app->workers + app->pending_workers >= app->max_workers) {
2153244Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p %uD/%uD running/pending workers, "
2154244Smax.romanov@nginx.com                   "max_workers (%uD) reached", &app->name, app,
2155244Smax.romanov@nginx.com                    app->workers, app->pending_workers, app->max_workers);
2156192Smax.romanov@nginx.com 
2157192Smax.romanov@nginx.com         nxt_router_sw_release(task, sw);
2158163Smax.romanov@nginx.com 
2159163Smax.romanov@nginx.com         return;
2160163Smax.romanov@nginx.com     }
2161163Smax.romanov@nginx.com 
2162163Smax.romanov@nginx.com     app->pending_workers++;
2163163Smax.romanov@nginx.com 
2164192Smax.romanov@nginx.com     nxt_debug(task, "sw %p send", sw);
216588Smax.romanov@nginx.com 
2166119Smax.romanov@nginx.com     rt = task->thread->runtime;
2167240Sigor@sysoev.ru     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
2168192Smax.romanov@nginx.com     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
2169141Smax.romanov@nginx.com 
2170174Sigor@sysoev.ru     size = app->name.length + 1 + app->conf.length;
2171174Sigor@sysoev.ru 
2172240Sigor@sysoev.ru     b = nxt_buf_mem_alloc(main_port->mem_pool, size, 0);
2173174Sigor@sysoev.ru 
2174174Sigor@sysoev.ru     nxt_buf_cpystr(b, &app->name);
2175174Sigor@sysoev.ru     *b->mem.free++ = '\0';
2176141Smax.romanov@nginx.com     nxt_buf_cpystr(b, &app->conf);
2177141Smax.romanov@nginx.com 
2178192Smax.romanov@nginx.com     stream = nxt_port_rpc_register_handler(task, router_port,
2179192Smax.romanov@nginx.com                                            nxt_router_sw_ready,
2180192Smax.romanov@nginx.com                                            nxt_router_sw_error,
2181240Sigor@sysoev.ru                                            main_port->pid, sw);
2182240Sigor@sysoev.ru 
2183240Sigor@sysoev.ru     nxt_port_socket_write(task, main_port, NXT_PORT_MSG_START_WORKER, -1,
2184192Smax.romanov@nginx.com                           stream, router_port->id, b);
2185141Smax.romanov@nginx.com }
2186141Smax.romanov@nginx.com 
2187141Smax.romanov@nginx.com 
2188163Smax.romanov@nginx.com static nxt_bool_t
2189167Smax.romanov@nginx.com nxt_router_app_free(nxt_task_t *task, nxt_app_t *app)
2190163Smax.romanov@nginx.com {
2191192Smax.romanov@nginx.com     nxt_queue_link_t    *lnk;
2192192Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
2193167Smax.romanov@nginx.com 
2194167Smax.romanov@nginx.com     nxt_thread_log_debug("app '%V' %p state: %d/%uD/%uD/%d", &app->name, app,
2195167Smax.romanov@nginx.com                          app->live, app->workers, app->pending_workers,
2196167Smax.romanov@nginx.com                          nxt_queue_is_empty(&app->requests));
2197167Smax.romanov@nginx.com 
2198163Smax.romanov@nginx.com     if (app->live == 0 && app->workers == 0 &&
2199163Smax.romanov@nginx.com         app->pending_workers == 0 &&
2200163Smax.romanov@nginx.com         nxt_queue_is_empty(&app->requests)) {
2201163Smax.romanov@nginx.com 
2202163Smax.romanov@nginx.com         nxt_thread_mutex_destroy(&app->mutex);
2203163Smax.romanov@nginx.com         nxt_free(app);
2204163Smax.romanov@nginx.com 
2205163Smax.romanov@nginx.com         return 1;
2206163Smax.romanov@nginx.com     }
2207163Smax.romanov@nginx.com 
2208167Smax.romanov@nginx.com     if (app->live == 1 && nxt_queue_is_empty(&app->requests) == 0 &&
2209167Smax.romanov@nginx.com        (app->workers + app->pending_workers < app->max_workers)) {
2210167Smax.romanov@nginx.com 
2211167Smax.romanov@nginx.com         lnk = nxt_queue_first(&app->requests);
2212167Smax.romanov@nginx.com         nxt_queue_remove(lnk);
2213167Smax.romanov@nginx.com 
2214167Smax.romanov@nginx.com         ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link);
2215167Smax.romanov@nginx.com 
2216192Smax.romanov@nginx.com         nxt_router_sw_create(task, app, ra);
2217167Smax.romanov@nginx.com     }
2218167Smax.romanov@nginx.com 
2219163Smax.romanov@nginx.com     return 0;
2220163Smax.romanov@nginx.com }
2221163Smax.romanov@nginx.com 
2222163Smax.romanov@nginx.com 
2223141Smax.romanov@nginx.com static nxt_port_t *
2224167Smax.romanov@nginx.com nxt_router_app_get_port(nxt_app_t *app, uint32_t req_id)
2225141Smax.romanov@nginx.com {
2226141Smax.romanov@nginx.com     nxt_port_t        *port;
2227141Smax.romanov@nginx.com     nxt_queue_link_t  *lnk;
2228141Smax.romanov@nginx.com 
2229141Smax.romanov@nginx.com     port = NULL;
2230141Smax.romanov@nginx.com 
2231141Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
2232141Smax.romanov@nginx.com 
2233141Smax.romanov@nginx.com     if (!nxt_queue_is_empty(&app->ports)) {
2234141Smax.romanov@nginx.com         lnk = nxt_queue_first(&app->ports);
2235141Smax.romanov@nginx.com         nxt_queue_remove(lnk);
2236141Smax.romanov@nginx.com 
2237141Smax.romanov@nginx.com         lnk->next = NULL;
2238141Smax.romanov@nginx.com 
2239141Smax.romanov@nginx.com         port = nxt_queue_link_data(lnk, nxt_port_t, app_link);
2240167Smax.romanov@nginx.com 
2241167Smax.romanov@nginx.com         port->app_req_id = req_id;
2242141Smax.romanov@nginx.com     }
2243141Smax.romanov@nginx.com 
2244141Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
2245141Smax.romanov@nginx.com 
2246141Smax.romanov@nginx.com     return port;
2247141Smax.romanov@nginx.com }
2248141Smax.romanov@nginx.com 
2249141Smax.romanov@nginx.com 
2250141Smax.romanov@nginx.com static void
2251141Smax.romanov@nginx.com nxt_router_app_release_port(nxt_task_t *task, void *obj, void *data)
2252141Smax.romanov@nginx.com {
2253141Smax.romanov@nginx.com     nxt_app_t            *app;
2254141Smax.romanov@nginx.com     nxt_port_t           *port;
2255141Smax.romanov@nginx.com     nxt_work_t           *work;
2256141Smax.romanov@nginx.com     nxt_queue_link_t     *lnk;
2257167Smax.romanov@nginx.com     nxt_req_app_link_t   *ra;
2258141Smax.romanov@nginx.com 
2259141Smax.romanov@nginx.com     port = obj;
2260141Smax.romanov@nginx.com     app = data;
2261141Smax.romanov@nginx.com 
2262141Smax.romanov@nginx.com     nxt_assert(app != NULL);
2263141Smax.romanov@nginx.com     nxt_assert(app == port->app);
2264141Smax.romanov@nginx.com     nxt_assert(port->app_link.next == NULL);
2265141Smax.romanov@nginx.com 
2266141Smax.romanov@nginx.com 
2267141Smax.romanov@nginx.com     if (task->thread->engine != port->engine) {
2268163Smax.romanov@nginx.com         work = &port->work;
2269141Smax.romanov@nginx.com 
2270141Smax.romanov@nginx.com         nxt_debug(task, "post release port to engine %p", port->engine);
2271141Smax.romanov@nginx.com 
2272141Smax.romanov@nginx.com         work->next = NULL;
2273141Smax.romanov@nginx.com         work->handler = nxt_router_app_release_port;
2274166Smax.romanov@nginx.com         work->task = &port->engine->task;
2275141Smax.romanov@nginx.com         work->obj = port;
2276141Smax.romanov@nginx.com         work->data = app;
2277141Smax.romanov@nginx.com 
2278141Smax.romanov@nginx.com         nxt_event_engine_post(port->engine, work);
2279141Smax.romanov@nginx.com 
2280141Smax.romanov@nginx.com         return;
2281141Smax.romanov@nginx.com     }
2282141Smax.romanov@nginx.com 
2283141Smax.romanov@nginx.com     if (!nxt_queue_is_empty(&app->requests)) {
2284141Smax.romanov@nginx.com         lnk = nxt_queue_first(&app->requests);
2285141Smax.romanov@nginx.com         nxt_queue_remove(lnk);
2286141Smax.romanov@nginx.com 
2287167Smax.romanov@nginx.com         ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link);
2288167Smax.romanov@nginx.com 
2289167Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p process next request #%uxD",
2290167Smax.romanov@nginx.com                   &app->name, app, ra->req_id);
2291167Smax.romanov@nginx.com 
2292167Smax.romanov@nginx.com         ra->app_port = port;
2293182Smax.romanov@nginx.com         port->app_req_id = ra->req_id;
2294167Smax.romanov@nginx.com 
2295167Smax.romanov@nginx.com         nxt_router_process_http_request_mp(task, ra, port);
2296167Smax.romanov@nginx.com 
2297167Smax.romanov@nginx.com         nxt_router_ra_release(task, ra, ra->work.data);
2298141Smax.romanov@nginx.com 
2299141Smax.romanov@nginx.com         return;
2300141Smax.romanov@nginx.com     }
2301141Smax.romanov@nginx.com 
2302167Smax.romanov@nginx.com     port->app_req_id = 0;
2303167Smax.romanov@nginx.com 
2304163Smax.romanov@nginx.com     if (port->pair[1] == -1) {
2305167Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p port already closed (pid %PI dead?)",
2306167Smax.romanov@nginx.com                   &app->name, app, port->pid);
2307163Smax.romanov@nginx.com 
2308163Smax.romanov@nginx.com         app->workers--;
2309167Smax.romanov@nginx.com         nxt_router_app_free(task, app);
2310163Smax.romanov@nginx.com 
2311163Smax.romanov@nginx.com         port->app = NULL;
2312163Smax.romanov@nginx.com 
2313163Smax.romanov@nginx.com         nxt_port_release(port);
2314163Smax.romanov@nginx.com 
2315163Smax.romanov@nginx.com         return;
2316163Smax.romanov@nginx.com     }
2317163Smax.romanov@nginx.com 
2318163Smax.romanov@nginx.com     if (!app->live) {
2319167Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p is not alive, send QUIT to port",
2320167Smax.romanov@nginx.com                   &app->name, app);
2321163Smax.romanov@nginx.com 
2322163Smax.romanov@nginx.com         nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT,
2323163Smax.romanov@nginx.com                               -1, 0, 0, NULL);
2324163Smax.romanov@nginx.com 
2325163Smax.romanov@nginx.com         return;
2326163Smax.romanov@nginx.com     }
2327163Smax.romanov@nginx.com 
2328167Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p requests queue is empty, keep the port",
2329167Smax.romanov@nginx.com               &app->name, app);
2330141Smax.romanov@nginx.com 
2331141Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
2332141Smax.romanov@nginx.com 
2333141Smax.romanov@nginx.com     nxt_queue_insert_head(&app->ports, &port->app_link);
2334141Smax.romanov@nginx.com 
2335141Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
2336141Smax.romanov@nginx.com }
2337141Smax.romanov@nginx.com 
2338141Smax.romanov@nginx.com 
2339163Smax.romanov@nginx.com nxt_bool_t
2340141Smax.romanov@nginx.com nxt_router_app_remove_port(nxt_port_t *port)
2341141Smax.romanov@nginx.com {
2342163Smax.romanov@nginx.com     nxt_app_t   *app;
2343163Smax.romanov@nginx.com     nxt_bool_t  busy;
2344141Smax.romanov@nginx.com 
2345141Smax.romanov@nginx.com     app = port->app;
2346167Smax.romanov@nginx.com     busy = port->app_req_id != 0;
2347163Smax.romanov@nginx.com 
2348163Smax.romanov@nginx.com     if (app == NULL) {
2349167Smax.romanov@nginx.com         nxt_thread_log_debug("port %p app remove, no app", port);
2350167Smax.romanov@nginx.com 
2351163Smax.romanov@nginx.com         nxt_assert(port->app_link.next == NULL);
2352163Smax.romanov@nginx.com 
2353163Smax.romanov@nginx.com         return 1;
2354141Smax.romanov@nginx.com     }
2355141Smax.romanov@nginx.com 
2356141Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
2357141Smax.romanov@nginx.com 
2358163Smax.romanov@nginx.com     if (port->app_link.next != NULL) {
2359163Smax.romanov@nginx.com 
2360163Smax.romanov@nginx.com         nxt_queue_remove(&port->app_link);
2361163Smax.romanov@nginx.com         port->app_link.next = NULL;
2362163Smax.romanov@nginx.com 
2363163Smax.romanov@nginx.com     }
2364141Smax.romanov@nginx.com 
2365141Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
2366163Smax.romanov@nginx.com 
2367163Smax.romanov@nginx.com     if (busy == 0) {
2368167Smax.romanov@nginx.com         nxt_thread_log_debug("port %p app remove, free, app '%V' %p", port,
2369167Smax.romanov@nginx.com                              &app->name, app);
2370163Smax.romanov@nginx.com 
2371163Smax.romanov@nginx.com         app->workers--;
2372167Smax.romanov@nginx.com         nxt_router_app_free(&port->engine->task, app);
2373163Smax.romanov@nginx.com 
2374163Smax.romanov@nginx.com         return 1;
2375163Smax.romanov@nginx.com     }
2376163Smax.romanov@nginx.com 
2377167Smax.romanov@nginx.com     nxt_thread_log_debug("port %p app remove, busy, app '%V' %p, req #%uxD",
2378167Smax.romanov@nginx.com                          port, &app->name, app, port->app_req_id);
2379167Smax.romanov@nginx.com 
2380163Smax.romanov@nginx.com     return 0;
2381141Smax.romanov@nginx.com }
2382141Smax.romanov@nginx.com 
2383141Smax.romanov@nginx.com 
2384167Smax.romanov@nginx.com static nxt_int_t
2385167Smax.romanov@nginx.com nxt_router_app_port(nxt_task_t *task, nxt_req_app_link_t *ra)
2386141Smax.romanov@nginx.com {
2387141Smax.romanov@nginx.com     nxt_app_t                *app;
2388141Smax.romanov@nginx.com     nxt_conn_t               *c;
2389167Smax.romanov@nginx.com     nxt_port_t               *port;
2390141Smax.romanov@nginx.com     nxt_start_worker_t       *sw;
2391141Smax.romanov@nginx.com     nxt_socket_conf_joint_t  *joint;
2392141Smax.romanov@nginx.com 
2393141Smax.romanov@nginx.com     port = NULL;
2394167Smax.romanov@nginx.com     c = ra->rc->conn;
2395141Smax.romanov@nginx.com 
2396141Smax.romanov@nginx.com     joint = c->listen->socket.data;
2397141Smax.romanov@nginx.com     app = joint->socket_conf->application;
2398141Smax.romanov@nginx.com 
2399141Smax.romanov@nginx.com     if (app == NULL) {
2400167Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 500,
2401141Smax.romanov@nginx.com                              "Application is NULL in socket_conf");
2402141Smax.romanov@nginx.com         return NXT_ERROR;
2403141Smax.romanov@nginx.com     }
2404141Smax.romanov@nginx.com 
2405141Smax.romanov@nginx.com 
2406167Smax.romanov@nginx.com     port = nxt_router_app_get_port(app, ra->req_id);
2407141Smax.romanov@nginx.com 
2408141Smax.romanov@nginx.com     if (port != NULL) {
2409163Smax.romanov@nginx.com         nxt_debug(task, "already have port for app '%V'", &app->name);
2410163Smax.romanov@nginx.com 
2411167Smax.romanov@nginx.com         ra->app_port = port;
2412141Smax.romanov@nginx.com         return NXT_OK;
2413141Smax.romanov@nginx.com     }
2414141Smax.romanov@nginx.com 
2415192Smax.romanov@nginx.com     sw = nxt_router_sw_create(task, app, ra);
2416141Smax.romanov@nginx.com 
2417141Smax.romanov@nginx.com     if (nxt_slow_path(sw == NULL)) {
2418167Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 500,
2419141Smax.romanov@nginx.com                              "Failed to allocate start worker struct");
2420141Smax.romanov@nginx.com         return NXT_ERROR;
2421141Smax.romanov@nginx.com     }
2422141Smax.romanov@nginx.com 
2423141Smax.romanov@nginx.com     return NXT_AGAIN;
242488Smax.romanov@nginx.com }
242588Smax.romanov@nginx.com 
242688Smax.romanov@nginx.com 
242788Smax.romanov@nginx.com static void
242853Sigor@sysoev.ru nxt_router_conn_http_header_parse(nxt_task_t *task, void *obj, void *data)
242953Sigor@sysoev.ru {
2430206Smax.romanov@nginx.com     size_t                    size;
243153Sigor@sysoev.ru     nxt_int_t                 ret;
2432206Smax.romanov@nginx.com     nxt_buf_t                 *buf;
243362Sigor@sysoev.ru     nxt_conn_t                *c;
243488Smax.romanov@nginx.com     nxt_app_parse_ctx_t       *ap;
2435206Smax.romanov@nginx.com     nxt_app_request_body_t    *b;
243653Sigor@sysoev.ru     nxt_socket_conf_joint_t   *joint;
243788Smax.romanov@nginx.com     nxt_app_request_header_t  *h;
243853Sigor@sysoev.ru 
243953Sigor@sysoev.ru     c = obj;
244088Smax.romanov@nginx.com     ap = data;
2441206Smax.romanov@nginx.com     buf = c->read;
2442206Smax.romanov@nginx.com     joint = c->listen->socket.data;
244353Sigor@sysoev.ru 
244453Sigor@sysoev.ru     nxt_debug(task, "router conn http header parse");
244553Sigor@sysoev.ru 
244688Smax.romanov@nginx.com     if (ap == NULL) {
2447206Smax.romanov@nginx.com         ap = nxt_mp_zalloc(c->mem_pool, sizeof(nxt_app_parse_ctx_t));
244888Smax.romanov@nginx.com         if (nxt_slow_path(ap == NULL)) {
244953Sigor@sysoev.ru             nxt_router_conn_close(task, c, data);
245053Sigor@sysoev.ru             return;
245153Sigor@sysoev.ru         }
245253Sigor@sysoev.ru 
245388Smax.romanov@nginx.com         ret = nxt_app_http_req_init(task, ap);
245461Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
245561Sigor@sysoev.ru             nxt_router_conn_close(task, c, data);
245661Sigor@sysoev.ru             return;
245761Sigor@sysoev.ru         }
245888Smax.romanov@nginx.com 
245988Smax.romanov@nginx.com         c->socket.data = ap;
2460113Smax.romanov@nginx.com 
2461113Smax.romanov@nginx.com         ap->r.remote.start = nxt_sockaddr_address(c->remote);
2462113Smax.romanov@nginx.com         ap->r.remote.length = c->remote->address_length;
2463206Smax.romanov@nginx.com 
2464206Smax.romanov@nginx.com         ap->r.header.buf = buf;
246553Sigor@sysoev.ru     }
246653Sigor@sysoev.ru 
246788Smax.romanov@nginx.com     h = &ap->r.header;
2468206Smax.romanov@nginx.com     b = &ap->r.body;
2469206Smax.romanov@nginx.com 
2470206Smax.romanov@nginx.com     ret = nxt_app_http_req_header_parse(task, ap, buf);
2471206Smax.romanov@nginx.com 
2472206Smax.romanov@nginx.com     nxt_debug(task, "http parse request header: %d", ret);
247353Sigor@sysoev.ru 
247453Sigor@sysoev.ru     switch (nxt_expect(NXT_DONE, ret)) {
247553Sigor@sysoev.ru 
247653Sigor@sysoev.ru     case NXT_DONE:
247788Smax.romanov@nginx.com         nxt_debug(task, "router request header parsing complete, "
247888Smax.romanov@nginx.com                   "content length: %O, preread: %uz",
2479206Smax.romanov@nginx.com                   h->parsed_content_length, nxt_buf_mem_used_size(&buf->mem));
2480206Smax.romanov@nginx.com 
2481206Smax.romanov@nginx.com         if (b->done) {
2482206Smax.romanov@nginx.com             nxt_router_process_http_request(task, c, ap);
2483206Smax.romanov@nginx.com 
2484206Smax.romanov@nginx.com             return;
2485206Smax.romanov@nginx.com         }
2486206Smax.romanov@nginx.com 
2487206Smax.romanov@nginx.com         if (joint->socket_conf->max_body_size > 0 &&
2488206Smax.romanov@nginx.com             (size_t) h->parsed_content_length >
2489206Smax.romanov@nginx.com             joint->socket_conf->max_body_size) {
2490206Smax.romanov@nginx.com 
2491206Smax.romanov@nginx.com             nxt_router_gen_error(task, c, 413, "Content-Length too big");
2492206Smax.romanov@nginx.com             return;
2493206Smax.romanov@nginx.com         }
2494206Smax.romanov@nginx.com 
2495206Smax.romanov@nginx.com         if (nxt_buf_mem_free_size(&buf->mem) == 0) {
2496206Smax.romanov@nginx.com             size = nxt_min(joint->socket_conf->body_buffer_size,
2497206Smax.romanov@nginx.com                            (size_t) h->parsed_content_length);
2498206Smax.romanov@nginx.com 
2499206Smax.romanov@nginx.com             buf->next = nxt_buf_mem_alloc(c->mem_pool, size, 0);
2500206Smax.romanov@nginx.com             if (nxt_slow_path(buf->next == NULL)) {
2501206Smax.romanov@nginx.com                 nxt_router_gen_error(task, c, 500, "Failed to allocate "
2502206Smax.romanov@nginx.com                                      "buffer for request body");
2503206Smax.romanov@nginx.com                 return;
2504206Smax.romanov@nginx.com             }
2505206Smax.romanov@nginx.com 
2506206Smax.romanov@nginx.com             c->read = buf->next;
2507206Smax.romanov@nginx.com 
2508206Smax.romanov@nginx.com             b->preread_size += nxt_buf_mem_used_size(&buf->mem);
2509206Smax.romanov@nginx.com         }
2510206Smax.romanov@nginx.com 
2511206Smax.romanov@nginx.com         if (b->buf == NULL) {
2512206Smax.romanov@nginx.com             b->buf = c->read;
2513206Smax.romanov@nginx.com         }
2514206Smax.romanov@nginx.com 
2515206Smax.romanov@nginx.com         c->read_state = &nxt_router_conn_read_body_state;
2516206Smax.romanov@nginx.com         break;
2517206Smax.romanov@nginx.com 
2518206Smax.romanov@nginx.com     case NXT_ERROR:
2519206Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 400, "Request header parse error");
2520206Smax.romanov@nginx.com         return;
2521206Smax.romanov@nginx.com 
2522206Smax.romanov@nginx.com     default:  /* NXT_AGAIN */
2523206Smax.romanov@nginx.com 
2524206Smax.romanov@nginx.com         if (c->read->mem.free == c->read->mem.end) {
2525206Smax.romanov@nginx.com             size = joint->socket_conf->large_header_buffer_size;
2526206Smax.romanov@nginx.com 
2527206Smax.romanov@nginx.com             if (size <= (size_t) nxt_buf_mem_used_size(&buf->mem) ||
2528206Smax.romanov@nginx.com                 ap->r.header.bufs >= joint->socket_conf->large_header_buffers) {
2529206Smax.romanov@nginx.com                 nxt_router_gen_error(task, c, 413,
2530206Smax.romanov@nginx.com                                      "Too long request headers");
2531206Smax.romanov@nginx.com                 return;
2532206Smax.romanov@nginx.com             }
2533206Smax.romanov@nginx.com 
2534206Smax.romanov@nginx.com             buf->next = nxt_buf_mem_alloc(c->mem_pool, size, 0);
2535206Smax.romanov@nginx.com             if (nxt_slow_path(buf->next == NULL)) {
2536206Smax.romanov@nginx.com                 nxt_router_gen_error(task, c, 500,
2537206Smax.romanov@nginx.com                                      "Failed to allocate large header "
2538206Smax.romanov@nginx.com                                      "buffer");
2539206Smax.romanov@nginx.com                 return;
2540206Smax.romanov@nginx.com             }
2541206Smax.romanov@nginx.com 
2542206Smax.romanov@nginx.com             ap->r.header.bufs++;
2543206Smax.romanov@nginx.com 
2544206Smax.romanov@nginx.com             size = c->read->mem.free - c->read->mem.pos;
2545206Smax.romanov@nginx.com 
2546206Smax.romanov@nginx.com             c->read = nxt_buf_cpy(buf->next, c->read->mem.pos, size);
2547206Smax.romanov@nginx.com         }
2548206Smax.romanov@nginx.com 
2549206Smax.romanov@nginx.com     }
2550206Smax.romanov@nginx.com 
2551206Smax.romanov@nginx.com     nxt_conn_read(task->thread->engine, c);
2552206Smax.romanov@nginx.com }
2553206Smax.romanov@nginx.com 
2554206Smax.romanov@nginx.com 
2555206Smax.romanov@nginx.com static void
2556206Smax.romanov@nginx.com nxt_router_conn_http_body_read(nxt_task_t *task, void *obj, void *data)
2557206Smax.romanov@nginx.com {
2558206Smax.romanov@nginx.com     size_t                    size;
2559206Smax.romanov@nginx.com     nxt_int_t                 ret;
2560206Smax.romanov@nginx.com     nxt_buf_t                 *buf;
2561206Smax.romanov@nginx.com     nxt_conn_t                *c;
2562206Smax.romanov@nginx.com     nxt_app_parse_ctx_t       *ap;
2563206Smax.romanov@nginx.com     nxt_app_request_body_t    *b;
2564206Smax.romanov@nginx.com     nxt_socket_conf_joint_t   *joint;
2565206Smax.romanov@nginx.com     nxt_app_request_header_t  *h;
2566206Smax.romanov@nginx.com 
2567206Smax.romanov@nginx.com     c = obj;
2568206Smax.romanov@nginx.com     ap = data;
2569206Smax.romanov@nginx.com     buf = c->read;
2570206Smax.romanov@nginx.com 
2571206Smax.romanov@nginx.com     nxt_debug(task, "router conn http body read");
2572206Smax.romanov@nginx.com 
2573206Smax.romanov@nginx.com     nxt_assert(ap != NULL);
2574206Smax.romanov@nginx.com 
2575206Smax.romanov@nginx.com     b = &ap->r.body;
2576206Smax.romanov@nginx.com     h = &ap->r.header;
2577206Smax.romanov@nginx.com 
2578206Smax.romanov@nginx.com     ret = nxt_app_http_req_body_read(task, ap, buf);
2579206Smax.romanov@nginx.com 
2580206Smax.romanov@nginx.com     nxt_debug(task, "http read request body: %d", ret);
2581206Smax.romanov@nginx.com 
2582206Smax.romanov@nginx.com     switch (nxt_expect(NXT_DONE, ret)) {
2583206Smax.romanov@nginx.com 
2584206Smax.romanov@nginx.com     case NXT_DONE:
258588Smax.romanov@nginx.com         nxt_router_process_http_request(task, c, ap);
258688Smax.romanov@nginx.com         return;
258753Sigor@sysoev.ru 
258853Sigor@sysoev.ru     case NXT_ERROR:
2589206Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 500, "Read body error");
259053Sigor@sysoev.ru         return;
259153Sigor@sysoev.ru 
259253Sigor@sysoev.ru     default:  /* NXT_AGAIN */
259353Sigor@sysoev.ru 
2594206Smax.romanov@nginx.com         if (nxt_buf_mem_free_size(&buf->mem) == 0) {
2595206Smax.romanov@nginx.com             joint = c->listen->socket.data;
2596206Smax.romanov@nginx.com 
2597206Smax.romanov@nginx.com             b->preread_size += nxt_buf_mem_used_size(&buf->mem);
2598206Smax.romanov@nginx.com 
2599206Smax.romanov@nginx.com             size = nxt_min(joint->socket_conf->body_buffer_size,
2600206Smax.romanov@nginx.com                            (size_t) h->parsed_content_length - b->preread_size);
2601206Smax.romanov@nginx.com 
2602206Smax.romanov@nginx.com             buf->next = nxt_buf_mem_alloc(c->mem_pool, size, 0);
2603206Smax.romanov@nginx.com             if (nxt_slow_path(buf->next == NULL)) {
2604206Smax.romanov@nginx.com                 nxt_router_gen_error(task, c, 500, "Failed to allocate "
2605206Smax.romanov@nginx.com                                      "buffer for request body");
2606206Smax.romanov@nginx.com                 return;
260788Smax.romanov@nginx.com             }
2608206Smax.romanov@nginx.com 
2609206Smax.romanov@nginx.com             c->read = buf->next;
261088Smax.romanov@nginx.com         }
261188Smax.romanov@nginx.com 
2612206Smax.romanov@nginx.com         nxt_debug(task, "router request body read again, rest: %uz",
2613206Smax.romanov@nginx.com                   h->parsed_content_length - b->preread_size);
261488Smax.romanov@nginx.com     }
261588Smax.romanov@nginx.com 
261688Smax.romanov@nginx.com     nxt_conn_read(task->thread->engine, c);
261788Smax.romanov@nginx.com }
261888Smax.romanov@nginx.com 
261988Smax.romanov@nginx.com 
262088Smax.romanov@nginx.com static void
262188Smax.romanov@nginx.com nxt_router_process_http_request(nxt_task_t *task, nxt_conn_t *c,
262288Smax.romanov@nginx.com     nxt_app_parse_ctx_t *ap)
262388Smax.romanov@nginx.com {
2624167Smax.romanov@nginx.com     nxt_mp_t             *port_mp;
2625122Smax.romanov@nginx.com     nxt_int_t            res;
2626167Smax.romanov@nginx.com     nxt_port_t           *port;
262788Smax.romanov@nginx.com     nxt_req_id_t         req_id;
262888Smax.romanov@nginx.com     nxt_event_engine_t   *engine;
2629167Smax.romanov@nginx.com     nxt_req_app_link_t   *ra;
263088Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
263188Smax.romanov@nginx.com 
263288Smax.romanov@nginx.com     engine = task->thread->engine;
263388Smax.romanov@nginx.com 
263488Smax.romanov@nginx.com     do {
2635138Sigor@sysoev.ru         req_id = nxt_random(&task->thread->random);
263688Smax.romanov@nginx.com     } while (nxt_event_engine_request_find(engine, req_id) != NULL);
263788Smax.romanov@nginx.com 
263888Smax.romanov@nginx.com     rc = nxt_conn_request_add(c, req_id);
2639122Smax.romanov@nginx.com 
264088Smax.romanov@nginx.com     if (nxt_slow_path(rc == NULL)) {
2641141Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 500, "Failed to allocate "
2642141Smax.romanov@nginx.com                              "req->conn link");
2643141Smax.romanov@nginx.com 
2644141Smax.romanov@nginx.com         return;
264588Smax.romanov@nginx.com     }
264688Smax.romanov@nginx.com 
264788Smax.romanov@nginx.com     nxt_event_engine_request_add(engine, rc);
264888Smax.romanov@nginx.com 
264988Smax.romanov@nginx.com     nxt_debug(task, "req_id %uxD linked to conn %p at engine %p",
265088Smax.romanov@nginx.com               req_id, c, engine);
265153Sigor@sysoev.ru 
2652167Smax.romanov@nginx.com 
2653167Smax.romanov@nginx.com     ra = nxt_router_ra_create(task, rc);
2654167Smax.romanov@nginx.com 
2655167Smax.romanov@nginx.com     ra->ap = ap;
2656167Smax.romanov@nginx.com     ra->reply_port = engine->port;
2657167Smax.romanov@nginx.com 
2658167Smax.romanov@nginx.com     res = nxt_router_app_port(task, ra);
2659141Smax.romanov@nginx.com 
2660141Smax.romanov@nginx.com     if (res != NXT_OK) {
2661141Smax.romanov@nginx.com         return;
2662141Smax.romanov@nginx.com     }
2663141Smax.romanov@nginx.com 
2664167Smax.romanov@nginx.com     port = ra->app_port;
2665141Smax.romanov@nginx.com 
2666141Smax.romanov@nginx.com     if (nxt_slow_path(port == NULL)) {
2667141Smax.romanov@nginx.com         nxt_router_gen_error(task, rc->conn, 500, "Application port not found");
2668141Smax.romanov@nginx.com         return;
2669141Smax.romanov@nginx.com     }
2670141Smax.romanov@nginx.com 
2671122Smax.romanov@nginx.com     port_mp = port->mem_pool;
2672167Smax.romanov@nginx.com     port->mem_pool = c->mem_pool;
2673167Smax.romanov@nginx.com 
2674167Smax.romanov@nginx.com     nxt_router_process_http_request_mp(task, ra, port);
2675167Smax.romanov@nginx.com 
2676167Smax.romanov@nginx.com     port->mem_pool = port_mp;
2677167Smax.romanov@nginx.com 
2678167Smax.romanov@nginx.com 
2679167Smax.romanov@nginx.com     nxt_router_ra_release(task, ra, ra->work.data);
2680167Smax.romanov@nginx.com }
2681167Smax.romanov@nginx.com 
2682167Smax.romanov@nginx.com 
2683167Smax.romanov@nginx.com static void
2684167Smax.romanov@nginx.com nxt_router_process_http_request_mp(nxt_task_t *task, nxt_req_app_link_t *ra,
2685167Smax.romanov@nginx.com     nxt_port_t *port)
2686167Smax.romanov@nginx.com {
2687167Smax.romanov@nginx.com     nxt_int_t            res;
2688167Smax.romanov@nginx.com     nxt_port_t           *c_port, *reply_port;
2689167Smax.romanov@nginx.com     nxt_conn_t           *c;
2690167Smax.romanov@nginx.com     nxt_app_wmsg_t       wmsg;
2691167Smax.romanov@nginx.com     nxt_app_parse_ctx_t  *ap;
2692167Smax.romanov@nginx.com 
2693167Smax.romanov@nginx.com     reply_port = ra->reply_port;
2694167Smax.romanov@nginx.com     ap = ra->ap;
2695167Smax.romanov@nginx.com     c = ra->rc->conn;
2696141Smax.romanov@nginx.com 
2697141Smax.romanov@nginx.com     c_port = nxt_process_connected_port_find(port->process, reply_port->pid,
2698141Smax.romanov@nginx.com                                              reply_port->id);
2699141Smax.romanov@nginx.com     if (nxt_slow_path(c_port != reply_port)) {
2700141Smax.romanov@nginx.com         res = nxt_port_send_port(task, port, reply_port, 0);
2701122Smax.romanov@nginx.com 
2702122Smax.romanov@nginx.com         if (nxt_slow_path(res != NXT_OK)) {
2703167Smax.romanov@nginx.com             nxt_router_gen_error(task, c, 500,
2704141Smax.romanov@nginx.com                                  "Failed to send reply port to application");
2705167Smax.romanov@nginx.com             return;
2706122Smax.romanov@nginx.com         }
2707122Smax.romanov@nginx.com 
2708141Smax.romanov@nginx.com         nxt_process_connected_port_add(port->process, reply_port);
270988Smax.romanov@nginx.com     }
271088Smax.romanov@nginx.com 
271188Smax.romanov@nginx.com     wmsg.port = port;
271288Smax.romanov@nginx.com     wmsg.write = NULL;
271388Smax.romanov@nginx.com     wmsg.buf = &wmsg.write;
2714167Smax.romanov@nginx.com     wmsg.stream = ra->req_id;
2715167Smax.romanov@nginx.com 
2716216Sigor@sysoev.ru     res = port->app->prepare_msg(task, &ap->r, &wmsg);
2717122Smax.romanov@nginx.com 
2718122Smax.romanov@nginx.com     if (nxt_slow_path(res != NXT_OK)) {
2719167Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 500,
2720141Smax.romanov@nginx.com                              "Failed to prepare message for application");
2721167Smax.romanov@nginx.com         return;
2722122Smax.romanov@nginx.com     }
272388Smax.romanov@nginx.com 
272488Smax.romanov@nginx.com     nxt_debug(task, "about to send %d bytes buffer to worker port %d",
272588Smax.romanov@nginx.com                     nxt_buf_used_size(wmsg.write),
272688Smax.romanov@nginx.com                     wmsg.port->socket.fd);
272788Smax.romanov@nginx.com 
2728122Smax.romanov@nginx.com     res = nxt_port_socket_write(task, wmsg.port, NXT_PORT_MSG_DATA,
2729167Smax.romanov@nginx.com                                  -1, ra->req_id, reply_port->id, wmsg.write);
2730122Smax.romanov@nginx.com 
2731122Smax.romanov@nginx.com     if (nxt_slow_path(res != NXT_OK)) {
2732167Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 500,
2733141Smax.romanov@nginx.com                              "Failed to send message to application");
2734167Smax.romanov@nginx.com         return;
2735122Smax.romanov@nginx.com     }
273653Sigor@sysoev.ru }
273753Sigor@sysoev.ru 
273853Sigor@sysoev.ru 
2739216Sigor@sysoev.ru static nxt_int_t
2740216Sigor@sysoev.ru nxt_python_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
2741216Sigor@sysoev.ru     nxt_app_wmsg_t *wmsg)
2742216Sigor@sysoev.ru {
2743216Sigor@sysoev.ru     nxt_int_t                 rc;
2744216Sigor@sysoev.ru     nxt_buf_t                 *b;
2745216Sigor@sysoev.ru     nxt_http_field_t          *field;
2746216Sigor@sysoev.ru     nxt_app_request_header_t  *h;
2747216Sigor@sysoev.ru 
2748216Sigor@sysoev.ru     static const nxt_str_t prefix = nxt_string("HTTP_");
2749216Sigor@sysoev.ru     static const nxt_str_t eof = nxt_null_string;
2750216Sigor@sysoev.ru 
2751216Sigor@sysoev.ru     h = &r->header;
2752216Sigor@sysoev.ru 
2753216Sigor@sysoev.ru #define RC(S)                                                                 \
2754216Sigor@sysoev.ru     do {                                                                      \
2755216Sigor@sysoev.ru         rc = (S);                                                             \
2756216Sigor@sysoev.ru         if (nxt_slow_path(rc != NXT_OK)) {                                    \
2757216Sigor@sysoev.ru             goto fail;                                                        \
2758216Sigor@sysoev.ru         }                                                                     \
2759216Sigor@sysoev.ru     } while(0)
2760216Sigor@sysoev.ru 
2761216Sigor@sysoev.ru #define NXT_WRITE(N)                                                          \
2762216Sigor@sysoev.ru     RC(nxt_app_msg_write_str(task, wmsg, N))
2763216Sigor@sysoev.ru 
2764216Sigor@sysoev.ru     /* TODO error handle, async mmap buffer assignment */
2765216Sigor@sysoev.ru 
2766216Sigor@sysoev.ru     NXT_WRITE(&h->method);
2767216Sigor@sysoev.ru     NXT_WRITE(&h->target);
2768216Sigor@sysoev.ru     if (h->path.start == h->target.start) {
2769216Sigor@sysoev.ru         NXT_WRITE(&eof);
2770216Sigor@sysoev.ru     } else {
2771216Sigor@sysoev.ru         NXT_WRITE(&h->path);
2772216Sigor@sysoev.ru     }
2773216Sigor@sysoev.ru 
2774216Sigor@sysoev.ru     if (h->query.start != NULL) {
2775216Sigor@sysoev.ru         RC(nxt_app_msg_write_size(task, wmsg,
2776216Sigor@sysoev.ru                                   h->query.start - h->target.start + 1));
2777216Sigor@sysoev.ru     } else {
2778216Sigor@sysoev.ru         RC(nxt_app_msg_write_size(task, wmsg, 0));
2779216Sigor@sysoev.ru     }
2780216Sigor@sysoev.ru 
2781216Sigor@sysoev.ru     NXT_WRITE(&h->version);
2782216Sigor@sysoev.ru 
2783216Sigor@sysoev.ru     NXT_WRITE(&r->remote);
2784216Sigor@sysoev.ru 
2785216Sigor@sysoev.ru     NXT_WRITE(&h->host);
2786216Sigor@sysoev.ru     NXT_WRITE(&h->content_type);
2787216Sigor@sysoev.ru     NXT_WRITE(&h->content_length);
2788216Sigor@sysoev.ru 
2789216Sigor@sysoev.ru     nxt_list_each(field, h->fields) {
2790216Sigor@sysoev.ru         RC(nxt_app_msg_write_prefixed_upcase(task, wmsg,
2791216Sigor@sysoev.ru                                              &prefix, &field->name));
2792216Sigor@sysoev.ru         NXT_WRITE(&field->value);
2793216Sigor@sysoev.ru 
2794216Sigor@sysoev.ru     } nxt_list_loop;
2795216Sigor@sysoev.ru 
2796216Sigor@sysoev.ru     /* end-of-headers mark */
2797216Sigor@sysoev.ru     NXT_WRITE(&eof);
2798216Sigor@sysoev.ru 
2799216Sigor@sysoev.ru     RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size));
2800216Sigor@sysoev.ru 
2801216Sigor@sysoev.ru     for(b = r->body.buf; b != NULL; b = b->next) {
2802216Sigor@sysoev.ru         RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos,
2803216Sigor@sysoev.ru                                  nxt_buf_mem_used_size(&b->mem)));
2804216Sigor@sysoev.ru     }
2805216Sigor@sysoev.ru 
2806216Sigor@sysoev.ru #undef NXT_WRITE
2807216Sigor@sysoev.ru #undef RC
2808216Sigor@sysoev.ru 
2809216Sigor@sysoev.ru     return NXT_OK;
2810216Sigor@sysoev.ru 
2811216Sigor@sysoev.ru fail:
2812216Sigor@sysoev.ru 
2813216Sigor@sysoev.ru     return NXT_ERROR;
2814216Sigor@sysoev.ru }
2815216Sigor@sysoev.ru 
2816216Sigor@sysoev.ru 
2817216Sigor@sysoev.ru static nxt_int_t
2818216Sigor@sysoev.ru nxt_php_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
2819216Sigor@sysoev.ru     nxt_app_wmsg_t *wmsg)
2820216Sigor@sysoev.ru {
2821216Sigor@sysoev.ru     nxt_int_t                 rc;
2822216Sigor@sysoev.ru     nxt_buf_t                 *b;
2823216Sigor@sysoev.ru     nxt_http_field_t          *field;
2824216Sigor@sysoev.ru     nxt_app_request_header_t  *h;
2825216Sigor@sysoev.ru 
2826216Sigor@sysoev.ru     static const nxt_str_t prefix = nxt_string("HTTP_");
2827216Sigor@sysoev.ru     static const nxt_str_t eof = nxt_null_string;
2828216Sigor@sysoev.ru 
2829216Sigor@sysoev.ru     h = &r->header;
2830216Sigor@sysoev.ru 
2831216Sigor@sysoev.ru #define RC(S)                                                                 \
2832216Sigor@sysoev.ru     do {                                                                      \
2833216Sigor@sysoev.ru         rc = (S);                                                             \
2834216Sigor@sysoev.ru         if (nxt_slow_path(rc != NXT_OK)) {                                    \
2835216Sigor@sysoev.ru             goto fail;                                                        \
2836216Sigor@sysoev.ru         }                                                                     \
2837216Sigor@sysoev.ru     } while(0)
2838216Sigor@sysoev.ru 
2839216Sigor@sysoev.ru #define NXT_WRITE(N)                                                          \
2840216Sigor@sysoev.ru     RC(nxt_app_msg_write_str(task, wmsg, N))
2841216Sigor@sysoev.ru 
2842216Sigor@sysoev.ru     /* TODO error handle, async mmap buffer assignment */
2843216Sigor@sysoev.ru 
2844216Sigor@sysoev.ru     NXT_WRITE(&h->method);
2845216Sigor@sysoev.ru     NXT_WRITE(&h->target);
2846216Sigor@sysoev.ru     if (h->path.start == h->target.start) {
2847216Sigor@sysoev.ru         NXT_WRITE(&eof);
2848216Sigor@sysoev.ru     } else {
2849216Sigor@sysoev.ru         NXT_WRITE(&h->path);
2850216Sigor@sysoev.ru     }
2851216Sigor@sysoev.ru 
2852216Sigor@sysoev.ru     if (h->query.start != NULL) {
2853216Sigor@sysoev.ru         RC(nxt_app_msg_write_size(task, wmsg,
2854216Sigor@sysoev.ru                                   h->query.start - h->target.start + 1));
2855216Sigor@sysoev.ru     } else {
2856216Sigor@sysoev.ru         RC(nxt_app_msg_write_size(task, wmsg, 0));
2857216Sigor@sysoev.ru     }
2858216Sigor@sysoev.ru 
2859216Sigor@sysoev.ru     NXT_WRITE(&h->version);
2860216Sigor@sysoev.ru 
2861216Sigor@sysoev.ru     // PHP_SELF
2862216Sigor@sysoev.ru     // SCRIPT_NAME
2863216Sigor@sysoev.ru     // SCRIPT_FILENAME
2864216Sigor@sysoev.ru     // DOCUMENT_ROOT
2865216Sigor@sysoev.ru 
2866216Sigor@sysoev.ru     NXT_WRITE(&r->remote);
2867216Sigor@sysoev.ru 
2868216Sigor@sysoev.ru     NXT_WRITE(&h->host);
2869216Sigor@sysoev.ru     NXT_WRITE(&h->cookie);
2870216Sigor@sysoev.ru     NXT_WRITE(&h->content_type);
2871216Sigor@sysoev.ru     NXT_WRITE(&h->content_length);
2872216Sigor@sysoev.ru 
2873216Sigor@sysoev.ru     RC(nxt_app_msg_write_size(task, wmsg, h->parsed_content_length));
2874216Sigor@sysoev.ru 
2875216Sigor@sysoev.ru     nxt_list_each(field, h->fields) {
2876216Sigor@sysoev.ru         RC(nxt_app_msg_write_prefixed_upcase(task, wmsg,
2877216Sigor@sysoev.ru                                              &prefix, &field->name));
2878216Sigor@sysoev.ru         NXT_WRITE(&field->value);
2879216Sigor@sysoev.ru 
2880216Sigor@sysoev.ru     } nxt_list_loop;
2881216Sigor@sysoev.ru 
2882216Sigor@sysoev.ru     /* end-of-headers mark */
2883216Sigor@sysoev.ru     NXT_WRITE(&eof);
2884216Sigor@sysoev.ru 
2885216Sigor@sysoev.ru     RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size));
2886216Sigor@sysoev.ru 
2887216Sigor@sysoev.ru     for(b = r->body.buf; b != NULL; b = b->next) {
2888216Sigor@sysoev.ru         RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos,
2889216Sigor@sysoev.ru                                  nxt_buf_mem_used_size(&b->mem)));
2890216Sigor@sysoev.ru     }
2891216Sigor@sysoev.ru 
2892216Sigor@sysoev.ru #undef NXT_WRITE
2893216Sigor@sysoev.ru #undef RC
2894216Sigor@sysoev.ru 
2895216Sigor@sysoev.ru     return NXT_OK;
2896216Sigor@sysoev.ru 
2897216Sigor@sysoev.ru fail:
2898216Sigor@sysoev.ru 
2899216Sigor@sysoev.ru     return NXT_ERROR;
2900216Sigor@sysoev.ru }
2901216Sigor@sysoev.ru 
2902216Sigor@sysoev.ru 
2903216Sigor@sysoev.ru static nxt_int_t
2904216Sigor@sysoev.ru nxt_go_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, nxt_app_wmsg_t *wmsg)
2905216Sigor@sysoev.ru {
2906216Sigor@sysoev.ru     nxt_int_t                 rc;
2907216Sigor@sysoev.ru     nxt_buf_t                 *b;
2908216Sigor@sysoev.ru     nxt_http_field_t          *field;
2909216Sigor@sysoev.ru     nxt_app_request_header_t  *h;
2910216Sigor@sysoev.ru 
2911216Sigor@sysoev.ru     static const nxt_str_t eof = nxt_null_string;
2912216Sigor@sysoev.ru 
2913216Sigor@sysoev.ru     h = &r->header;
2914216Sigor@sysoev.ru 
2915216Sigor@sysoev.ru #define RC(S)                                                                 \
2916216Sigor@sysoev.ru     do {                                                                      \
2917216Sigor@sysoev.ru         rc = (S);                                                             \
2918216Sigor@sysoev.ru         if (nxt_slow_path(rc != NXT_OK)) {                                    \
2919216Sigor@sysoev.ru             goto fail;                                                        \
2920216Sigor@sysoev.ru         }                                                                     \
2921216Sigor@sysoev.ru     } while(0)
2922216Sigor@sysoev.ru 
2923216Sigor@sysoev.ru #define NXT_WRITE(N)                                                          \
2924216Sigor@sysoev.ru     RC(nxt_app_msg_write_str(task, wmsg, N))
2925216Sigor@sysoev.ru 
2926216Sigor@sysoev.ru     /* TODO error handle, async mmap buffer assignment */
2927216Sigor@sysoev.ru 
2928216Sigor@sysoev.ru     NXT_WRITE(&h->method);
2929216Sigor@sysoev.ru     NXT_WRITE(&h->target);
2930216Sigor@sysoev.ru     if (h->path.start == h->target.start) {
2931216Sigor@sysoev.ru         NXT_WRITE(&eof);
2932216Sigor@sysoev.ru     } else {
2933216Sigor@sysoev.ru         NXT_WRITE(&h->path);
2934216Sigor@sysoev.ru     }
2935216Sigor@sysoev.ru 
2936216Sigor@sysoev.ru     if (h->query.start != NULL) {
2937216Sigor@sysoev.ru         RC(nxt_app_msg_write_size(task, wmsg,
2938216Sigor@sysoev.ru                                   h->query.start - h->target.start + 1));
2939216Sigor@sysoev.ru     } else {
2940216Sigor@sysoev.ru         RC(nxt_app_msg_write_size(task, wmsg, 0));
2941216Sigor@sysoev.ru     }
2942216Sigor@sysoev.ru 
2943216Sigor@sysoev.ru     NXT_WRITE(&h->version);
2944253Smax.romanov@nginx.com     NXT_WRITE(&r->remote);
2945216Sigor@sysoev.ru 
2946216Sigor@sysoev.ru     NXT_WRITE(&h->host);
2947216Sigor@sysoev.ru     NXT_WRITE(&h->cookie);
2948216Sigor@sysoev.ru     NXT_WRITE(&h->content_type);
2949216Sigor@sysoev.ru     NXT_WRITE(&h->content_length);
2950216Sigor@sysoev.ru 
2951216Sigor@sysoev.ru     RC(nxt_app_msg_write_size(task, wmsg, h->parsed_content_length));
2952216Sigor@sysoev.ru 
2953216Sigor@sysoev.ru     nxt_list_each(field, h->fields) {
2954216Sigor@sysoev.ru         NXT_WRITE(&field->name);
2955216Sigor@sysoev.ru         NXT_WRITE(&field->value);
2956216Sigor@sysoev.ru 
2957216Sigor@sysoev.ru     } nxt_list_loop;
2958216Sigor@sysoev.ru 
2959216Sigor@sysoev.ru     /* end-of-headers mark */
2960216Sigor@sysoev.ru     NXT_WRITE(&eof);
2961216Sigor@sysoev.ru 
2962216Sigor@sysoev.ru     RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size));
2963216Sigor@sysoev.ru 
2964216Sigor@sysoev.ru     for(b = r->body.buf; b != NULL; b = b->next) {
2965216Sigor@sysoev.ru         RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos,
2966216Sigor@sysoev.ru                                  nxt_buf_mem_used_size(&b->mem)));
2967216Sigor@sysoev.ru     }
2968216Sigor@sysoev.ru 
2969216Sigor@sysoev.ru #undef NXT_WRITE
2970216Sigor@sysoev.ru #undef RC
2971216Sigor@sysoev.ru 
2972216Sigor@sysoev.ru     return NXT_OK;
2973216Sigor@sysoev.ru 
2974216Sigor@sysoev.ru fail:
2975216Sigor@sysoev.ru 
2976216Sigor@sysoev.ru     return NXT_ERROR;
2977216Sigor@sysoev.ru }
2978216Sigor@sysoev.ru 
2979216Sigor@sysoev.ru 
298062Sigor@sysoev.ru static const nxt_conn_state_t  nxt_router_conn_close_state
298153Sigor@sysoev.ru     nxt_aligned(64) =
298253Sigor@sysoev.ru {
298353Sigor@sysoev.ru     .ready_handler = nxt_router_conn_free,
298453Sigor@sysoev.ru };
298553Sigor@sysoev.ru 
298653Sigor@sysoev.ru 
298753Sigor@sysoev.ru static void
298888Smax.romanov@nginx.com nxt_router_conn_ready(nxt_task_t *task, void *obj, void *data)
298988Smax.romanov@nginx.com {
299088Smax.romanov@nginx.com     nxt_buf_t         *b;
299188Smax.romanov@nginx.com     nxt_bool_t        last;
299288Smax.romanov@nginx.com     nxt_conn_t        *c;
299388Smax.romanov@nginx.com     nxt_work_queue_t  *wq;
299488Smax.romanov@nginx.com 
299588Smax.romanov@nginx.com     nxt_debug(task, "router conn ready %p", obj);
299688Smax.romanov@nginx.com 
299788Smax.romanov@nginx.com     c = obj;
299888Smax.romanov@nginx.com     b = c->write;
299988Smax.romanov@nginx.com 
300088Smax.romanov@nginx.com     wq = &task->thread->engine->fast_work_queue;
300188Smax.romanov@nginx.com 
300288Smax.romanov@nginx.com     last = 0;
300388Smax.romanov@nginx.com 
300488Smax.romanov@nginx.com     while (b != NULL) {
300588Smax.romanov@nginx.com         if (!nxt_buf_is_sync(b)) {
300688Smax.romanov@nginx.com             if (nxt_buf_used_size(b) > 0) {
300788Smax.romanov@nginx.com                 break;
300888Smax.romanov@nginx.com             }
300988Smax.romanov@nginx.com         }
301088Smax.romanov@nginx.com 
301188Smax.romanov@nginx.com         if (nxt_buf_is_last(b)) {
301288Smax.romanov@nginx.com             last = 1;
301388Smax.romanov@nginx.com         }
301488Smax.romanov@nginx.com 
301588Smax.romanov@nginx.com         nxt_work_queue_add(wq, b->completion_handler, task, b, b->parent);
301688Smax.romanov@nginx.com 
301788Smax.romanov@nginx.com         b = b->next;
301888Smax.romanov@nginx.com     }
301988Smax.romanov@nginx.com 
302088Smax.romanov@nginx.com     c->write = b;
302188Smax.romanov@nginx.com 
302288Smax.romanov@nginx.com     if (b != NULL) {
302388Smax.romanov@nginx.com         nxt_debug(task, "router conn %p has more data to write", obj);
302488Smax.romanov@nginx.com 
302588Smax.romanov@nginx.com         nxt_conn_write(task->thread->engine, c);
302688Smax.romanov@nginx.com     } else {
302788Smax.romanov@nginx.com         nxt_debug(task, "router conn %p no more data to write, last = %d", obj,
302888Smax.romanov@nginx.com                   last);
302988Smax.romanov@nginx.com 
303088Smax.romanov@nginx.com         if (last != 0) {
303188Smax.romanov@nginx.com             nxt_debug(task, "enqueue router conn close %p (ready handler)", c);
303288Smax.romanov@nginx.com 
303388Smax.romanov@nginx.com             nxt_work_queue_add(wq, nxt_router_conn_close, task, c,
303488Smax.romanov@nginx.com                                c->socket.data);
303588Smax.romanov@nginx.com         }
303688Smax.romanov@nginx.com     }
303788Smax.romanov@nginx.com }
303888Smax.romanov@nginx.com 
303988Smax.romanov@nginx.com 
304088Smax.romanov@nginx.com static void
304153Sigor@sysoev.ru nxt_router_conn_close(nxt_task_t *task, void *obj, void *data)
304253Sigor@sysoev.ru {
304362Sigor@sysoev.ru     nxt_conn_t  *c;
304453Sigor@sysoev.ru 
304553Sigor@sysoev.ru     c = obj;
304653Sigor@sysoev.ru 
304753Sigor@sysoev.ru     nxt_debug(task, "router conn close");
304853Sigor@sysoev.ru 
304953Sigor@sysoev.ru     c->write_state = &nxt_router_conn_close_state;
305053Sigor@sysoev.ru 
305162Sigor@sysoev.ru     nxt_conn_close(task->thread->engine, c);
305253Sigor@sysoev.ru }
305353Sigor@sysoev.ru 
305453Sigor@sysoev.ru 
305553Sigor@sysoev.ru static void
3056164Smax.romanov@nginx.com nxt_router_conn_mp_cleanup(nxt_task_t *task, void *obj, void *data)
3057164Smax.romanov@nginx.com {
3058164Smax.romanov@nginx.com     nxt_socket_conf_joint_t  *joint;
3059164Smax.romanov@nginx.com 
3060164Smax.romanov@nginx.com     joint = obj;
3061164Smax.romanov@nginx.com 
3062164Smax.romanov@nginx.com     nxt_router_conf_release(task, joint);
3063164Smax.romanov@nginx.com }
3064164Smax.romanov@nginx.com 
3065164Smax.romanov@nginx.com 
3066164Smax.romanov@nginx.com static void
306753Sigor@sysoev.ru nxt_router_conn_free(nxt_task_t *task, void *obj, void *data)
306853Sigor@sysoev.ru {
306962Sigor@sysoev.ru     nxt_conn_t               *c;
307088Smax.romanov@nginx.com     nxt_req_conn_link_t      *rc;
307153Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
307253Sigor@sysoev.ru 
307353Sigor@sysoev.ru     c = obj;
307453Sigor@sysoev.ru 
307553Sigor@sysoev.ru     nxt_debug(task, "router conn close done");
307653Sigor@sysoev.ru 
307788Smax.romanov@nginx.com     nxt_queue_each(rc, &c->requests, nxt_req_conn_link_t, link) {
307888Smax.romanov@nginx.com 
307988Smax.romanov@nginx.com         nxt_debug(task, "conn %p close, req %uxD", c, rc->req_id);
308088Smax.romanov@nginx.com 
3081141Smax.romanov@nginx.com         if (rc->app_port != NULL) {
3082141Smax.romanov@nginx.com             nxt_router_app_release_port(task, rc->app_port, rc->app_port->app);
3083141Smax.romanov@nginx.com 
3084141Smax.romanov@nginx.com             rc->app_port = NULL;
3085141Smax.romanov@nginx.com         }
3086141Smax.romanov@nginx.com 
3087167Smax.romanov@nginx.com         rc->conn = NULL;
3088167Smax.romanov@nginx.com 
308988Smax.romanov@nginx.com         nxt_event_engine_request_remove(task->thread->engine, rc);
309088Smax.romanov@nginx.com 
309188Smax.romanov@nginx.com     } nxt_queue_loop;
309288Smax.romanov@nginx.com 
3093122Smax.romanov@nginx.com     nxt_queue_remove(&c->link);
3094122Smax.romanov@nginx.com 
3095131Smax.romanov@nginx.com     joint = c->listen->socket.data;
3096131Smax.romanov@nginx.com 
3097131Smax.romanov@nginx.com     task = &task->thread->engine->task;
3098131Smax.romanov@nginx.com 
3099164Smax.romanov@nginx.com     nxt_mp_cleanup(c->mem_pool, nxt_router_conn_mp_cleanup, task, joint, NULL);
3100164Smax.romanov@nginx.com 
3101164Smax.romanov@nginx.com     nxt_mp_release(c->mem_pool, c);
310253Sigor@sysoev.ru }
310353Sigor@sysoev.ru 
310453Sigor@sysoev.ru 
310553Sigor@sysoev.ru static void
310653Sigor@sysoev.ru nxt_router_conn_error(nxt_task_t *task, void *obj, void *data)
310753Sigor@sysoev.ru {
310862Sigor@sysoev.ru     nxt_conn_t  *c;
310953Sigor@sysoev.ru 
311053Sigor@sysoev.ru     c = obj;
311153Sigor@sysoev.ru 
311253Sigor@sysoev.ru     nxt_debug(task, "router conn error");
311353Sigor@sysoev.ru 
311453Sigor@sysoev.ru     c->write_state = &nxt_router_conn_close_state;
311553Sigor@sysoev.ru 
311662Sigor@sysoev.ru     nxt_conn_close(task->thread->engine, c);
311753Sigor@sysoev.ru }
311853Sigor@sysoev.ru 
311953Sigor@sysoev.ru 
312053Sigor@sysoev.ru static void
312153Sigor@sysoev.ru nxt_router_conn_timeout(nxt_task_t *task, void *obj, void *data)
312253Sigor@sysoev.ru {
312362Sigor@sysoev.ru     nxt_conn_t   *c;
312462Sigor@sysoev.ru     nxt_timer_t  *timer;
312553Sigor@sysoev.ru 
312653Sigor@sysoev.ru     timer = obj;
312753Sigor@sysoev.ru 
312853Sigor@sysoev.ru     nxt_debug(task, "router conn timeout");
312953Sigor@sysoev.ru 
313062Sigor@sysoev.ru     c = nxt_read_timer_conn(timer);
313153Sigor@sysoev.ru 
3132206Smax.romanov@nginx.com     if (c->read_state == &nxt_router_conn_read_header_state) {
3133206Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 408, "Read header timeout");
3134206Smax.romanov@nginx.com 
3135206Smax.romanov@nginx.com     } else {
3136206Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 408, "Read body timeout");
3137206Smax.romanov@nginx.com     }
313853Sigor@sysoev.ru }
313953Sigor@sysoev.ru 
314053Sigor@sysoev.ru 
314153Sigor@sysoev.ru static nxt_msec_t
314262Sigor@sysoev.ru nxt_router_conn_timeout_value(nxt_conn_t *c, uintptr_t data)
314353Sigor@sysoev.ru {
314453Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
314553Sigor@sysoev.ru 
314653Sigor@sysoev.ru     joint = c->listen->socket.data;
314753Sigor@sysoev.ru 
314853Sigor@sysoev.ru     return nxt_value_at(nxt_msec_t, joint->socket_conf, data);
314953Sigor@sysoev.ru }
3150