xref: /unit/src/nxt_router.c (revision 167)
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 
23*167Smax.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     uint32_t               stream;
28141Smax.romanov@nginx.com     nxt_app_t              *app;
29*167Smax.romanov@nginx.com     nxt_req_app_link_t     *ra;
30141Smax.romanov@nginx.com     nxt_mp_t               *mem_pool;
31141Smax.romanov@nginx.com 
32141Smax.romanov@nginx.com     nxt_work_t             work;
33141Smax.romanov@nginx.com };
34141Smax.romanov@nginx.com 
35141Smax.romanov@nginx.com 
36*167Smax.romanov@nginx.com struct nxt_req_app_link_s {
37*167Smax.romanov@nginx.com     nxt_req_id_t         req_id;
38*167Smax.romanov@nginx.com     nxt_port_t           *app_port;
39*167Smax.romanov@nginx.com     nxt_port_t           *reply_port;
40*167Smax.romanov@nginx.com     nxt_app_parse_ctx_t  *ap;
41*167Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
42*167Smax.romanov@nginx.com 
43*167Smax.romanov@nginx.com     nxt_queue_link_t     link; /* for nxt_app_t.requests */
44*167Smax.romanov@nginx.com 
45*167Smax.romanov@nginx.com     nxt_mp_t             *mem_pool;
46*167Smax.romanov@nginx.com     nxt_work_t           work;
47*167Smax.romanov@nginx.com };
48*167Smax.romanov@nginx.com 
49*167Smax.romanov@nginx.com 
50139Sigor@sysoev.ru static nxt_router_temp_conf_t *nxt_router_temp_conf(nxt_task_t *task);
51139Sigor@sysoev.ru static nxt_int_t nxt_router_conf_new(nxt_task_t *task,
52139Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, u_char *start, u_char *end);
53139Sigor@sysoev.ru static void nxt_router_conf_success(nxt_task_t *task,
54139Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
55139Sigor@sysoev.ru static void nxt_router_conf_error(nxt_task_t *task,
56139Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
57139Sigor@sysoev.ru static void nxt_router_conf_send(nxt_task_t *task,
58139Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, u_char *start, size_t size);
59139Sigor@sysoev.ru static void nxt_router_conf_buf_completion(nxt_task_t *task, void *obj,
60139Sigor@sysoev.ru     void *data);
6153Sigor@sysoev.ru static void nxt_router_listen_sockets_sort(nxt_router_t *router,
6253Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
6353Sigor@sysoev.ru 
64115Sigor@sysoev.ru static nxt_int_t nxt_router_conf_create(nxt_task_t *task,
65115Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, u_char *start, u_char *end);
66133Sigor@sysoev.ru static nxt_app_t *nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name);
67133Sigor@sysoev.ru static nxt_app_t *nxt_router_listener_application(nxt_router_temp_conf_t *tmcf,
68133Sigor@sysoev.ru     nxt_str_t *name);
6953Sigor@sysoev.ru static nxt_int_t nxt_router_listen_sockets_stub_create(nxt_task_t *task,
7053Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
7165Sigor@sysoev.ru static nxt_socket_conf_t *nxt_router_socket_conf(nxt_task_t *task, nxt_mp_t *mp,
7265Sigor@sysoev.ru     nxt_sockaddr_t *sa);
7353Sigor@sysoev.ru 
7453Sigor@sysoev.ru static nxt_int_t nxt_router_engines_create(nxt_task_t *task,
7553Sigor@sysoev.ru     nxt_router_t *router, nxt_router_temp_conf_t *tmcf,
7653Sigor@sysoev.ru     const nxt_event_interface_t *interface);
77115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf,
78115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
79115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf,
80115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
81115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf,
82115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
83115Sigor@sysoev.ru static void nxt_router_engine_socket_count(nxt_queue_t *sockets);
84154Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf,
85154Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets,
86154Sigor@sysoev.ru     nxt_work_handler_t handler);
87139Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf,
88139Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets);
8953Sigor@sysoev.ru 
9053Sigor@sysoev.ru static nxt_int_t nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt,
9153Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
9253Sigor@sysoev.ru static nxt_int_t nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt,
9353Sigor@sysoev.ru     nxt_event_engine_t *engine);
94133Sigor@sysoev.ru static void nxt_router_apps_sort(nxt_router_t *router,
95133Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
9653Sigor@sysoev.ru 
9753Sigor@sysoev.ru static void nxt_router_engines_post(nxt_router_temp_conf_t *tmcf);
98154Sigor@sysoev.ru static void nxt_router_engine_post(nxt_router_engine_conf_t *recf);
9953Sigor@sysoev.ru 
10053Sigor@sysoev.ru static void nxt_router_thread_start(void *data);
10153Sigor@sysoev.ru static void nxt_router_listen_socket_create(nxt_task_t *task, void *obj,
10253Sigor@sysoev.ru     void *data);
10353Sigor@sysoev.ru static void nxt_router_listen_socket_update(nxt_task_t *task, void *obj,
10453Sigor@sysoev.ru     void *data);
10553Sigor@sysoev.ru static void nxt_router_listen_socket_delete(nxt_task_t *task, void *obj,
10653Sigor@sysoev.ru     void *data);
10753Sigor@sysoev.ru static void nxt_router_listen_socket_close(nxt_task_t *task, void *obj,
10853Sigor@sysoev.ru     void *data);
10953Sigor@sysoev.ru static void nxt_router_listen_socket_release(nxt_task_t *task,
11053Sigor@sysoev.ru     nxt_socket_conf_joint_t *joint);
11153Sigor@sysoev.ru static void nxt_router_thread_exit_handler(nxt_task_t *task, void *obj,
11253Sigor@sysoev.ru     void *data);
11353Sigor@sysoev.ru static void nxt_router_conf_release(nxt_task_t *task,
11453Sigor@sysoev.ru     nxt_socket_conf_joint_t *joint);
11553Sigor@sysoev.ru 
116*167Smax.romanov@nginx.com static void nxt_router_send_sw_request(nxt_task_t *task, void *obj,
117*167Smax.romanov@nginx.com     void *data);
118*167Smax.romanov@nginx.com static nxt_bool_t nxt_router_app_free(nxt_task_t *task, nxt_app_t *app);
119*167Smax.romanov@nginx.com static nxt_port_t * nxt_router_app_get_port(nxt_app_t *app, uint32_t req_id);
120141Smax.romanov@nginx.com static void nxt_router_app_release_port(nxt_task_t *task, void *obj,
121141Smax.romanov@nginx.com     void *data);
122141Smax.romanov@nginx.com 
123141Smax.romanov@nginx.com static void nxt_router_sw_add(nxt_task_t *task, nxt_router_t *router,
124141Smax.romanov@nginx.com     nxt_start_worker_t *sw);
125141Smax.romanov@nginx.com static nxt_start_worker_t *nxt_router_sw_find_remove(nxt_task_t *task,
126141Smax.romanov@nginx.com     nxt_router_t *router, uint32_t id);
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);
13188Smax.romanov@nginx.com static void nxt_router_process_http_request(nxt_task_t *task,
13288Smax.romanov@nginx.com     nxt_conn_t *c, nxt_app_parse_ctx_t *ap);
133141Smax.romanov@nginx.com static void nxt_router_process_http_request_mp(nxt_task_t *task,
134*167Smax.romanov@nginx.com     nxt_req_app_link_t *ra, nxt_port_t *port);
13588Smax.romanov@nginx.com static void nxt_router_conn_ready(nxt_task_t *task, void *obj, void *data);
13653Sigor@sysoev.ru static void nxt_router_conn_close(nxt_task_t *task, void *obj, void *data);
13753Sigor@sysoev.ru static void nxt_router_conn_free(nxt_task_t *task, void *obj, void *data);
13853Sigor@sysoev.ru static void nxt_router_conn_error(nxt_task_t *task, void *obj, void *data);
13953Sigor@sysoev.ru static void nxt_router_conn_timeout(nxt_task_t *task, void *obj, void *data);
14062Sigor@sysoev.ru static nxt_msec_t nxt_router_conn_timeout_value(nxt_conn_t *c, uintptr_t data);
14120Sigor@sysoev.ru 
142141Smax.romanov@nginx.com static void nxt_router_gen_error(nxt_task_t *task, nxt_conn_t *c, int code,
143141Smax.romanov@nginx.com     const char* fmt, ...);
144141Smax.romanov@nginx.com 
145119Smax.romanov@nginx.com static nxt_router_t  *nxt_router;
14620Sigor@sysoev.ru 
14720Sigor@sysoev.ru nxt_int_t
148141Smax.romanov@nginx.com nxt_router_start(nxt_task_t *task, void *data)
14920Sigor@sysoev.ru {
150141Smax.romanov@nginx.com     nxt_int_t      ret;
151141Smax.romanov@nginx.com     nxt_router_t   *router;
152141Smax.romanov@nginx.com     nxt_runtime_t  *rt;
153141Smax.romanov@nginx.com 
154141Smax.romanov@nginx.com     rt = task->thread->runtime;
15553Sigor@sysoev.ru 
15688Smax.romanov@nginx.com     ret = nxt_app_http_init(task, rt);
15788Smax.romanov@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
15888Smax.romanov@nginx.com         return ret;
15988Smax.romanov@nginx.com     }
16088Smax.romanov@nginx.com 
16153Sigor@sysoev.ru     router = nxt_zalloc(sizeof(nxt_router_t));
16253Sigor@sysoev.ru     if (nxt_slow_path(router == NULL)) {
16353Sigor@sysoev.ru         return NXT_ERROR;
16453Sigor@sysoev.ru     }
16553Sigor@sysoev.ru 
16653Sigor@sysoev.ru     nxt_queue_init(&router->engines);
16753Sigor@sysoev.ru     nxt_queue_init(&router->sockets);
168133Sigor@sysoev.ru     nxt_queue_init(&router->apps);
16953Sigor@sysoev.ru 
170119Smax.romanov@nginx.com     nxt_router = router;
171119Smax.romanov@nginx.com 
172115Sigor@sysoev.ru     return NXT_OK;
173115Sigor@sysoev.ru }
174115Sigor@sysoev.ru 
175115Sigor@sysoev.ru 
176*167Smax.romanov@nginx.com static nxt_start_worker_t *
177*167Smax.romanov@nginx.com nxt_router_sw_create(nxt_task_t *task, nxt_mp_t *mp, nxt_app_t *app,
178*167Smax.romanov@nginx.com     nxt_req_app_link_t *ra)
179*167Smax.romanov@nginx.com {
180*167Smax.romanov@nginx.com     nxt_port_t          *master_port;
181*167Smax.romanov@nginx.com     nxt_runtime_t       *rt;
182*167Smax.romanov@nginx.com     nxt_start_worker_t  *sw;
183*167Smax.romanov@nginx.com 
184*167Smax.romanov@nginx.com     sw = nxt_mp_retain(mp, sizeof(nxt_start_worker_t));
185*167Smax.romanov@nginx.com 
186*167Smax.romanov@nginx.com     if (nxt_slow_path(sw == NULL)) {
187*167Smax.romanov@nginx.com         return NULL;
188*167Smax.romanov@nginx.com     }
189*167Smax.romanov@nginx.com 
190*167Smax.romanov@nginx.com     nxt_memzero(sw, sizeof(nxt_start_worker_t));
191*167Smax.romanov@nginx.com 
192*167Smax.romanov@nginx.com     sw->stream = nxt_random(&task->thread->random);
193*167Smax.romanov@nginx.com     sw->mem_pool = mp;
194*167Smax.romanov@nginx.com 
195*167Smax.romanov@nginx.com     sw->app = app;
196*167Smax.romanov@nginx.com     sw->ra = ra;
197*167Smax.romanov@nginx.com 
198*167Smax.romanov@nginx.com     nxt_debug(task, "sw #%uxD create, request #%uD, app '%V' %p", sw->stream,
199*167Smax.romanov@nginx.com                     ra->req_id, &app->name, app);
200*167Smax.romanov@nginx.com 
201*167Smax.romanov@nginx.com     rt = task->thread->runtime;
202*167Smax.romanov@nginx.com     master_port = rt->port_by_type[NXT_PROCESS_MASTER];
203*167Smax.romanov@nginx.com 
204*167Smax.romanov@nginx.com     sw->work.handler = nxt_router_send_sw_request;
205*167Smax.romanov@nginx.com     sw->work.task = &master_port->engine->task;
206*167Smax.romanov@nginx.com     sw->work.obj = sw;
207*167Smax.romanov@nginx.com     sw->work.data = task->thread->engine;
208*167Smax.romanov@nginx.com     sw->work.next = NULL;
209*167Smax.romanov@nginx.com 
210*167Smax.romanov@nginx.com     if (task->thread->engine != master_port->engine) {
211*167Smax.romanov@nginx.com         nxt_debug(task, "post send sw %uxD to master engine %p", sw->stream,
212*167Smax.romanov@nginx.com                   master_port->engine);
213*167Smax.romanov@nginx.com 
214*167Smax.romanov@nginx.com         nxt_event_engine_post(master_port->engine, &sw->work);
215*167Smax.romanov@nginx.com 
216*167Smax.romanov@nginx.com     } else {
217*167Smax.romanov@nginx.com         nxt_router_send_sw_request(task, sw, sw->work.data);
218*167Smax.romanov@nginx.com     }
219*167Smax.romanov@nginx.com 
220*167Smax.romanov@nginx.com     return sw;
221*167Smax.romanov@nginx.com }
222*167Smax.romanov@nginx.com 
223*167Smax.romanov@nginx.com 
224141Smax.romanov@nginx.com static void
225141Smax.romanov@nginx.com nxt_router_sw_release(nxt_task_t *task, void *obj, void *data)
226141Smax.romanov@nginx.com {
227*167Smax.romanov@nginx.com     nxt_event_engine_t  *engine;
228164Smax.romanov@nginx.com     nxt_start_worker_t  *sw;
229141Smax.romanov@nginx.com 
230141Smax.romanov@nginx.com     sw = obj;
231*167Smax.romanov@nginx.com     engine = data;
232*167Smax.romanov@nginx.com 
233*167Smax.romanov@nginx.com     if (task->thread->engine != engine) {
234*167Smax.romanov@nginx.com         sw->work.handler = nxt_router_sw_release;
235*167Smax.romanov@nginx.com         sw->work.task = &engine->task;
236*167Smax.romanov@nginx.com         sw->work.next = NULL;
237*167Smax.romanov@nginx.com 
238*167Smax.romanov@nginx.com         nxt_debug(task, "sw #%uxD post release to %p", sw->stream, engine);
239*167Smax.romanov@nginx.com 
240*167Smax.romanov@nginx.com         nxt_event_engine_post(engine, &sw->work);
241*167Smax.romanov@nginx.com 
242*167Smax.romanov@nginx.com         return;
243*167Smax.romanov@nginx.com     }
244141Smax.romanov@nginx.com 
245141Smax.romanov@nginx.com     nxt_debug(task, "sw #%uxD release", sw->stream);
246141Smax.romanov@nginx.com 
247164Smax.romanov@nginx.com     nxt_mp_release(sw->mem_pool, sw);
248141Smax.romanov@nginx.com }
249141Smax.romanov@nginx.com 
250141Smax.romanov@nginx.com 
251*167Smax.romanov@nginx.com static nxt_req_app_link_t *
252*167Smax.romanov@nginx.com nxt_router_ra_create(nxt_task_t *task, nxt_req_conn_link_t *rc)
253*167Smax.romanov@nginx.com {
254*167Smax.romanov@nginx.com     nxt_mp_t            *mp;
255*167Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
256*167Smax.romanov@nginx.com 
257*167Smax.romanov@nginx.com     mp = rc->conn->mem_pool;
258*167Smax.romanov@nginx.com 
259*167Smax.romanov@nginx.com     ra = nxt_mp_retain(mp, sizeof(nxt_req_app_link_t));
260*167Smax.romanov@nginx.com 
261*167Smax.romanov@nginx.com     if (nxt_slow_path(ra == NULL)) {
262*167Smax.romanov@nginx.com         return NULL;
263*167Smax.romanov@nginx.com     }
264*167Smax.romanov@nginx.com 
265*167Smax.romanov@nginx.com     nxt_debug(task, "ra #%uxD create", ra->req_id);
266*167Smax.romanov@nginx.com 
267*167Smax.romanov@nginx.com     nxt_memzero(ra, sizeof(nxt_req_app_link_t));
268*167Smax.romanov@nginx.com 
269*167Smax.romanov@nginx.com     ra->req_id = rc->req_id;
270*167Smax.romanov@nginx.com     ra->app_port = NULL;
271*167Smax.romanov@nginx.com     ra->rc = rc;
272*167Smax.romanov@nginx.com 
273*167Smax.romanov@nginx.com     ra->mem_pool = mp;
274*167Smax.romanov@nginx.com 
275*167Smax.romanov@nginx.com     ra->work.handler = NULL;
276*167Smax.romanov@nginx.com     ra->work.task = &task->thread->engine->task;
277*167Smax.romanov@nginx.com     ra->work.obj = ra;
278*167Smax.romanov@nginx.com     ra->work.data = task->thread->engine;
279*167Smax.romanov@nginx.com 
280*167Smax.romanov@nginx.com     return ra;
281*167Smax.romanov@nginx.com }
282*167Smax.romanov@nginx.com 
283*167Smax.romanov@nginx.com 
284*167Smax.romanov@nginx.com static void
285*167Smax.romanov@nginx.com nxt_router_ra_release(nxt_task_t *task, void *obj, void *data)
286*167Smax.romanov@nginx.com {
287*167Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
288*167Smax.romanov@nginx.com     nxt_event_engine_t  *engine;
289*167Smax.romanov@nginx.com 
290*167Smax.romanov@nginx.com     ra = obj;
291*167Smax.romanov@nginx.com     engine = data;
292*167Smax.romanov@nginx.com 
293*167Smax.romanov@nginx.com     if (task->thread->engine != engine) {
294*167Smax.romanov@nginx.com         ra->work.handler = nxt_router_ra_release;
295*167Smax.romanov@nginx.com         ra->work.task = &engine->task;
296*167Smax.romanov@nginx.com         ra->work.next = NULL;
297*167Smax.romanov@nginx.com 
298*167Smax.romanov@nginx.com         nxt_debug(task, "ra #%uxD post release to %p", ra->req_id, engine);
299*167Smax.romanov@nginx.com 
300*167Smax.romanov@nginx.com         nxt_event_engine_post(engine, &ra->work);
301*167Smax.romanov@nginx.com 
302*167Smax.romanov@nginx.com         return;
303*167Smax.romanov@nginx.com     }
304*167Smax.romanov@nginx.com 
305*167Smax.romanov@nginx.com     nxt_debug(task, "ra #%uxD release", ra->req_id);
306*167Smax.romanov@nginx.com 
307*167Smax.romanov@nginx.com     if (ra->app_port != NULL) {
308*167Smax.romanov@nginx.com 
309*167Smax.romanov@nginx.com         if (ra->rc->conn != NULL) {
310*167Smax.romanov@nginx.com             ra->rc->app_port = ra->app_port;
311*167Smax.romanov@nginx.com 
312*167Smax.romanov@nginx.com         } else {
313*167Smax.romanov@nginx.com             nxt_router_app_release_port(task, ra->app_port, ra->app_port->app);
314*167Smax.romanov@nginx.com         }
315*167Smax.romanov@nginx.com     }
316*167Smax.romanov@nginx.com 
317*167Smax.romanov@nginx.com     nxt_mp_release(ra->mem_pool, ra);
318*167Smax.romanov@nginx.com }
319*167Smax.romanov@nginx.com 
320*167Smax.romanov@nginx.com 
321141Smax.romanov@nginx.com void
322141Smax.romanov@nginx.com nxt_router_new_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
323141Smax.romanov@nginx.com {
324141Smax.romanov@nginx.com     nxt_start_worker_t  *sw;
325141Smax.romanov@nginx.com 
326141Smax.romanov@nginx.com     nxt_port_new_port_handler(task, msg);
327141Smax.romanov@nginx.com 
328141Smax.romanov@nginx.com     if (msg->new_port == NULL || msg->new_port->type != NXT_PROCESS_WORKER) {
329141Smax.romanov@nginx.com         return;
330141Smax.romanov@nginx.com     }
331141Smax.romanov@nginx.com 
332141Smax.romanov@nginx.com     sw = nxt_router_sw_find_remove(task, nxt_router, msg->port_msg.stream);
333141Smax.romanov@nginx.com 
334141Smax.romanov@nginx.com     if (nxt_fast_path(sw != NULL)) {
335141Smax.romanov@nginx.com         msg->new_port->app = sw->app;
336141Smax.romanov@nginx.com 
337163Smax.romanov@nginx.com         nxt_assert(sw->app->pending_workers != 0);
338163Smax.romanov@nginx.com 
339163Smax.romanov@nginx.com         sw->app->pending_workers--;
340*167Smax.romanov@nginx.com         sw->app->workers++;
341*167Smax.romanov@nginx.com 
342*167Smax.romanov@nginx.com         nxt_debug(task, "sw #%uxD got port %p", sw->stream, msg->new_port);
343163Smax.romanov@nginx.com 
344141Smax.romanov@nginx.com         nxt_router_app_release_port(task, msg->new_port, sw->app);
345141Smax.romanov@nginx.com 
346*167Smax.romanov@nginx.com         nxt_router_sw_release(task, sw, sw->work.data);
347141Smax.romanov@nginx.com     }
348141Smax.romanov@nginx.com }
349141Smax.romanov@nginx.com 
350141Smax.romanov@nginx.com 
351139Sigor@sysoev.ru void
352139Sigor@sysoev.ru nxt_router_conf_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
353115Sigor@sysoev.ru {
354139Sigor@sysoev.ru     size_t                  dump_size;
355139Sigor@sysoev.ru     nxt_buf_t               *b;
356139Sigor@sysoev.ru     nxt_int_t               ret;
357139Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
358139Sigor@sysoev.ru 
359139Sigor@sysoev.ru     b = msg->buf;
360139Sigor@sysoev.ru 
361139Sigor@sysoev.ru     dump_size = nxt_buf_used_size(b);
362139Sigor@sysoev.ru 
363139Sigor@sysoev.ru     if (dump_size > 300) {
364139Sigor@sysoev.ru         dump_size = 300;
36553Sigor@sysoev.ru     }
36653Sigor@sysoev.ru 
367139Sigor@sysoev.ru     nxt_debug(task, "router conf data (%z): %*s",
368139Sigor@sysoev.ru               msg->size, dump_size, b->mem.pos);
369139Sigor@sysoev.ru 
370139Sigor@sysoev.ru     tmcf = nxt_router_temp_conf(task);
371139Sigor@sysoev.ru     if (nxt_slow_path(tmcf == NULL)) {
372139Sigor@sysoev.ru         return;
37353Sigor@sysoev.ru     }
37453Sigor@sysoev.ru 
375139Sigor@sysoev.ru     tmcf->conf->router = nxt_router;
376139Sigor@sysoev.ru     tmcf->stream = msg->port_msg.stream;
377139Sigor@sysoev.ru     tmcf->port = nxt_runtime_port_find(task->thread->runtime,
378139Sigor@sysoev.ru                                        msg->port_msg.pid, 0);
379139Sigor@sysoev.ru 
380139Sigor@sysoev.ru     ret = nxt_router_conf_new(task, tmcf, b->mem.pos, b->mem.free);
381139Sigor@sysoev.ru 
382139Sigor@sysoev.ru     b->mem.pos = b->mem.free;
383139Sigor@sysoev.ru 
384139Sigor@sysoev.ru     if (ret == NXT_OK) {
385139Sigor@sysoev.ru         return nxt_router_conf_success(task, tmcf);
386139Sigor@sysoev.ru     }
387139Sigor@sysoev.ru 
388139Sigor@sysoev.ru     nxt_log(task, NXT_LOG_CRIT, "failed to apply new conf");
389139Sigor@sysoev.ru 
390139Sigor@sysoev.ru     return nxt_router_conf_error(task, tmcf);
39153Sigor@sysoev.ru }
39253Sigor@sysoev.ru 
39353Sigor@sysoev.ru 
39453Sigor@sysoev.ru static nxt_router_temp_conf_t *
395139Sigor@sysoev.ru nxt_router_temp_conf(nxt_task_t *task)
39653Sigor@sysoev.ru {
39765Sigor@sysoev.ru     nxt_mp_t                *mp, *tmp;
39853Sigor@sysoev.ru     nxt_router_conf_t       *rtcf;
39953Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
40053Sigor@sysoev.ru 
40165Sigor@sysoev.ru     mp = nxt_mp_create(1024, 128, 256, 32);
40253Sigor@sysoev.ru     if (nxt_slow_path(mp == NULL)) {
40353Sigor@sysoev.ru         return NULL;
40453Sigor@sysoev.ru     }
40553Sigor@sysoev.ru 
40665Sigor@sysoev.ru     rtcf = nxt_mp_zget(mp, sizeof(nxt_router_conf_t));
40753Sigor@sysoev.ru     if (nxt_slow_path(rtcf == NULL)) {
40853Sigor@sysoev.ru         goto fail;
40953Sigor@sysoev.ru     }
41053Sigor@sysoev.ru 
41153Sigor@sysoev.ru     rtcf->mem_pool = mp;
41253Sigor@sysoev.ru 
41365Sigor@sysoev.ru     tmp = nxt_mp_create(1024, 128, 256, 32);
41453Sigor@sysoev.ru     if (nxt_slow_path(tmp == NULL)) {
41553Sigor@sysoev.ru         goto fail;
41653Sigor@sysoev.ru     }
41753Sigor@sysoev.ru 
41865Sigor@sysoev.ru     tmcf = nxt_mp_zget(tmp, sizeof(nxt_router_temp_conf_t));
41953Sigor@sysoev.ru     if (nxt_slow_path(tmcf == NULL)) {
42053Sigor@sysoev.ru         goto temp_fail;
42153Sigor@sysoev.ru     }
42253Sigor@sysoev.ru 
42353Sigor@sysoev.ru     tmcf->mem_pool = tmp;
42453Sigor@sysoev.ru     tmcf->conf = rtcf;
425139Sigor@sysoev.ru     tmcf->count = 1;
426139Sigor@sysoev.ru     tmcf->engine = task->thread->engine;
42753Sigor@sysoev.ru 
42853Sigor@sysoev.ru     tmcf->engines = nxt_array_create(tmcf->mem_pool, 4,
42953Sigor@sysoev.ru                                      sizeof(nxt_router_engine_conf_t));
43053Sigor@sysoev.ru     if (nxt_slow_path(tmcf->engines == NULL)) {
43153Sigor@sysoev.ru         goto temp_fail;
43253Sigor@sysoev.ru     }
43353Sigor@sysoev.ru 
43453Sigor@sysoev.ru     nxt_queue_init(&tmcf->deleting);
43553Sigor@sysoev.ru     nxt_queue_init(&tmcf->keeping);
43653Sigor@sysoev.ru     nxt_queue_init(&tmcf->updating);
43753Sigor@sysoev.ru     nxt_queue_init(&tmcf->pending);
43853Sigor@sysoev.ru     nxt_queue_init(&tmcf->creating);
439133Sigor@sysoev.ru     nxt_queue_init(&tmcf->apps);
440133Sigor@sysoev.ru     nxt_queue_init(&tmcf->previous);
44153Sigor@sysoev.ru 
44253Sigor@sysoev.ru     return tmcf;
44353Sigor@sysoev.ru 
44453Sigor@sysoev.ru temp_fail:
44553Sigor@sysoev.ru 
44665Sigor@sysoev.ru     nxt_mp_destroy(tmp);
44753Sigor@sysoev.ru 
44853Sigor@sysoev.ru fail:
44953Sigor@sysoev.ru 
45065Sigor@sysoev.ru     nxt_mp_destroy(mp);
45153Sigor@sysoev.ru 
45253Sigor@sysoev.ru     return NULL;
45353Sigor@sysoev.ru }
45453Sigor@sysoev.ru 
45553Sigor@sysoev.ru 
456139Sigor@sysoev.ru static nxt_int_t
457139Sigor@sysoev.ru nxt_router_conf_new(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
458139Sigor@sysoev.ru     u_char *start, u_char *end)
459139Sigor@sysoev.ru {
460139Sigor@sysoev.ru     nxt_int_t                    ret;
461139Sigor@sysoev.ru     nxt_router_t                 *router;
462139Sigor@sysoev.ru     nxt_runtime_t                *rt;
463139Sigor@sysoev.ru     const nxt_event_interface_t  *interface;
464139Sigor@sysoev.ru 
465139Sigor@sysoev.ru     ret = nxt_router_conf_create(task, tmcf, start, end);
466139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
467139Sigor@sysoev.ru         return ret;
468139Sigor@sysoev.ru     }
469139Sigor@sysoev.ru 
470139Sigor@sysoev.ru     router = tmcf->conf->router;
471139Sigor@sysoev.ru 
472139Sigor@sysoev.ru     nxt_router_listen_sockets_sort(router, tmcf);
473139Sigor@sysoev.ru 
474139Sigor@sysoev.ru     ret = nxt_router_listen_sockets_stub_create(task, tmcf);
475139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
476139Sigor@sysoev.ru         return ret;
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 
483139Sigor@sysoev.ru     ret = nxt_router_engines_create(task, router, tmcf, interface);
484139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
485139Sigor@sysoev.ru         return ret;
486139Sigor@sysoev.ru     }
487139Sigor@sysoev.ru 
488139Sigor@sysoev.ru     ret = nxt_router_threads_create(task, rt, tmcf);
489139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
490139Sigor@sysoev.ru         return ret;
491139Sigor@sysoev.ru     }
492139Sigor@sysoev.ru 
493139Sigor@sysoev.ru     nxt_router_apps_sort(router, tmcf);
494139Sigor@sysoev.ru 
495139Sigor@sysoev.ru     nxt_router_engines_post(tmcf);
496139Sigor@sysoev.ru 
497139Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->updating);
498139Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->creating);
499139Sigor@sysoev.ru 
500139Sigor@sysoev.ru     return NXT_OK;
501139Sigor@sysoev.ru }
502139Sigor@sysoev.ru 
503139Sigor@sysoev.ru 
504139Sigor@sysoev.ru static void
505139Sigor@sysoev.ru nxt_router_conf_wait(nxt_task_t *task, void *obj, void *data)
506139Sigor@sysoev.ru {
507153Sigor@sysoev.ru     nxt_joint_job_t  *job;
508153Sigor@sysoev.ru 
509153Sigor@sysoev.ru     job = obj;
510153Sigor@sysoev.ru 
511153Sigor@sysoev.ru     nxt_router_conf_success(task, job->tmcf);
512139Sigor@sysoev.ru }
513139Sigor@sysoev.ru 
514139Sigor@sysoev.ru 
515139Sigor@sysoev.ru static void
516139Sigor@sysoev.ru nxt_router_conf_success(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
517139Sigor@sysoev.ru {
518139Sigor@sysoev.ru     nxt_debug(task, "temp conf count:%D", tmcf->count);
519139Sigor@sysoev.ru 
520139Sigor@sysoev.ru     if (--tmcf->count == 0) {
521139Sigor@sysoev.ru         nxt_router_conf_send(task, tmcf, (u_char *) "OK", 2);
522139Sigor@sysoev.ru     }
523139Sigor@sysoev.ru }
524139Sigor@sysoev.ru 
525139Sigor@sysoev.ru 
526139Sigor@sysoev.ru static void
527139Sigor@sysoev.ru nxt_router_conf_error(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
528139Sigor@sysoev.ru {
529148Sigor@sysoev.ru     nxt_socket_t       s;
530149Sigor@sysoev.ru     nxt_router_t       *router;
531148Sigor@sysoev.ru     nxt_queue_link_t   *qlk;
532148Sigor@sysoev.ru     nxt_socket_conf_t  *skcf;
533148Sigor@sysoev.ru 
534148Sigor@sysoev.ru     for (qlk = nxt_queue_first(&tmcf->creating);
535148Sigor@sysoev.ru          qlk != nxt_queue_tail(&tmcf->creating);
536148Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
537148Sigor@sysoev.ru     {
538148Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
539148Sigor@sysoev.ru         s = skcf->listen.socket;
540148Sigor@sysoev.ru 
541148Sigor@sysoev.ru         if (s != -1) {
542148Sigor@sysoev.ru             nxt_socket_close(task, s);
543148Sigor@sysoev.ru         }
544148Sigor@sysoev.ru 
545148Sigor@sysoev.ru         nxt_free(skcf->socket);
546148Sigor@sysoev.ru     }
547148Sigor@sysoev.ru 
548149Sigor@sysoev.ru     router = tmcf->conf->router;
549149Sigor@sysoev.ru 
550149Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->keeping);
551149Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->deleting);
552149Sigor@sysoev.ru 
553148Sigor@sysoev.ru     // TODO: new engines and threads
554148Sigor@sysoev.ru 
555139Sigor@sysoev.ru     nxt_mp_destroy(tmcf->conf->mem_pool);
556139Sigor@sysoev.ru 
557139Sigor@sysoev.ru     nxt_router_conf_send(task, tmcf, (u_char *) "ERROR", 5);
558139Sigor@sysoev.ru }
559139Sigor@sysoev.ru 
560139Sigor@sysoev.ru 
561139Sigor@sysoev.ru static void
562139Sigor@sysoev.ru nxt_router_conf_send(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
563139Sigor@sysoev.ru     u_char *start, size_t size)
564139Sigor@sysoev.ru {
565139Sigor@sysoev.ru     nxt_buf_t  *b;
566139Sigor@sysoev.ru 
567139Sigor@sysoev.ru     b = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0);
568139Sigor@sysoev.ru     if (nxt_slow_path(b == NULL)) {
569139Sigor@sysoev.ru         return;
570139Sigor@sysoev.ru     }
571139Sigor@sysoev.ru 
572140Svbart@nginx.com     b->mem.free = nxt_cpymem(b->mem.free, start, size);
573140Svbart@nginx.com 
574139Sigor@sysoev.ru     b->parent = tmcf->mem_pool;
575139Sigor@sysoev.ru     b->completion_handler = nxt_router_conf_buf_completion;
576139Sigor@sysoev.ru 
577139Sigor@sysoev.ru     nxt_port_socket_write(task, tmcf->port, NXT_PORT_MSG_DATA, -1,
578139Sigor@sysoev.ru                           tmcf->stream, 0, b);
579139Sigor@sysoev.ru }
580139Sigor@sysoev.ru 
581139Sigor@sysoev.ru 
582139Sigor@sysoev.ru static void
583139Sigor@sysoev.ru nxt_router_conf_buf_completion(nxt_task_t *task, void *obj, void *data)
584139Sigor@sysoev.ru {
585139Sigor@sysoev.ru     nxt_mp_t  *mp;
586139Sigor@sysoev.ru 
587139Sigor@sysoev.ru     /* nxt_router_temp_conf_t mem pool. */
588139Sigor@sysoev.ru     mp = data;
589139Sigor@sysoev.ru 
590139Sigor@sysoev.ru     nxt_mp_destroy(mp);
591139Sigor@sysoev.ru }
592139Sigor@sysoev.ru 
593139Sigor@sysoev.ru 
594115Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_conf[] = {
595115Sigor@sysoev.ru     {
596133Sigor@sysoev.ru         nxt_string("listeners_threads"),
597115Sigor@sysoev.ru         NXT_CONF_MAP_INT32,
598115Sigor@sysoev.ru         offsetof(nxt_router_conf_t, threads),
599115Sigor@sysoev.ru     },
600115Sigor@sysoev.ru };
601115Sigor@sysoev.ru 
602115Sigor@sysoev.ru 
603133Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_app_conf[] = {
604115Sigor@sysoev.ru     {
605133Sigor@sysoev.ru         nxt_string("type"),
606115Sigor@sysoev.ru         NXT_CONF_MAP_STR,
607133Sigor@sysoev.ru         offsetof(nxt_router_app_conf_t, type),
608115Sigor@sysoev.ru     },
609115Sigor@sysoev.ru 
610115Sigor@sysoev.ru     {
611133Sigor@sysoev.ru         nxt_string("workers"),
612115Sigor@sysoev.ru         NXT_CONF_MAP_INT32,
613133Sigor@sysoev.ru         offsetof(nxt_router_app_conf_t, workers),
614133Sigor@sysoev.ru     },
615133Sigor@sysoev.ru };
616133Sigor@sysoev.ru 
617133Sigor@sysoev.ru 
618133Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_listener_conf[] = {
619133Sigor@sysoev.ru     {
620133Sigor@sysoev.ru         nxt_string("application"),
621133Sigor@sysoev.ru         NXT_CONF_MAP_STR,
622133Sigor@sysoev.ru         offsetof(nxt_router_listener_conf_t, application),
623115Sigor@sysoev.ru     },
624115Sigor@sysoev.ru };
625115Sigor@sysoev.ru 
626115Sigor@sysoev.ru 
627115Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_http_conf[] = {
628115Sigor@sysoev.ru     {
629115Sigor@sysoev.ru         nxt_string("header_buffer_size"),
630115Sigor@sysoev.ru         NXT_CONF_MAP_SIZE,
631115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, header_buffer_size),
632115Sigor@sysoev.ru     },
633115Sigor@sysoev.ru 
634115Sigor@sysoev.ru     {
635115Sigor@sysoev.ru         nxt_string("large_header_buffer_size"),
636115Sigor@sysoev.ru         NXT_CONF_MAP_SIZE,
637115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, large_header_buffer_size),
638115Sigor@sysoev.ru     },
639115Sigor@sysoev.ru 
640115Sigor@sysoev.ru     {
641115Sigor@sysoev.ru         nxt_string("header_read_timeout"),
642115Sigor@sysoev.ru         NXT_CONF_MAP_MSEC,
643115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, header_read_timeout),
644115Sigor@sysoev.ru     },
645115Sigor@sysoev.ru };
646115Sigor@sysoev.ru 
647115Sigor@sysoev.ru 
64853Sigor@sysoev.ru static nxt_int_t
649115Sigor@sysoev.ru nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
650115Sigor@sysoev.ru     u_char *start, u_char *end)
65153Sigor@sysoev.ru {
652133Sigor@sysoev.ru     u_char                      *p;
653133Sigor@sysoev.ru     size_t                      size;
654115Sigor@sysoev.ru     nxt_mp_t                    *mp;
655115Sigor@sysoev.ru     uint32_t                    next;
656115Sigor@sysoev.ru     nxt_int_t                   ret;
657115Sigor@sysoev.ru     nxt_str_t                   name;
658133Sigor@sysoev.ru     nxt_app_t                   *app, *prev;
659133Sigor@sysoev.ru     nxt_app_type_t              type;
660115Sigor@sysoev.ru     nxt_sockaddr_t              *sa;
661133Sigor@sysoev.ru     nxt_conf_value_t            *conf, *http;
662133Sigor@sysoev.ru     nxt_conf_value_t            *applications, *application;
663133Sigor@sysoev.ru     nxt_conf_value_t            *listeners, *listener;
664115Sigor@sysoev.ru     nxt_socket_conf_t           *skcf;
665133Sigor@sysoev.ru     nxt_router_app_conf_t       apcf;
666115Sigor@sysoev.ru     nxt_router_listener_conf_t  lscf;
667115Sigor@sysoev.ru 
668115Sigor@sysoev.ru     static nxt_str_t  http_path = nxt_string("/http");
669133Sigor@sysoev.ru     static nxt_str_t  applications_path = nxt_string("/applications");
670115Sigor@sysoev.ru     static nxt_str_t  listeners_path = nxt_string("/listeners");
671115Sigor@sysoev.ru 
672115Sigor@sysoev.ru     conf = nxt_conf_json_parse(tmcf->mem_pool, start, end);
673115Sigor@sysoev.ru     if (conf == NULL) {
674115Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "configuration parsing error");
675115Sigor@sysoev.ru         return NXT_ERROR;
676115Sigor@sysoev.ru     }
677115Sigor@sysoev.ru 
678136Svbart@nginx.com     ret = nxt_conf_map_object(conf, nxt_router_conf,
679136Svbart@nginx.com                               nxt_nitems(nxt_router_conf), tmcf->conf);
680115Sigor@sysoev.ru     if (ret != NXT_OK) {
681133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "root map error");
682115Sigor@sysoev.ru         return NXT_ERROR;
683115Sigor@sysoev.ru     }
684115Sigor@sysoev.ru 
685117Sigor@sysoev.ru     if (tmcf->conf->threads == 0) {
686117Sigor@sysoev.ru         tmcf->conf->threads = nxt_ncpu;
687117Sigor@sysoev.ru     }
688117Sigor@sysoev.ru 
689133Sigor@sysoev.ru     applications = nxt_conf_get_path(conf, &applications_path);
690133Sigor@sysoev.ru     if (applications == NULL) {
691133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "no \"applications\" block");
692115Sigor@sysoev.ru         return NXT_ERROR;
693115Sigor@sysoev.ru     }
694115Sigor@sysoev.ru 
695133Sigor@sysoev.ru     next = 0;
696133Sigor@sysoev.ru 
697133Sigor@sysoev.ru     for ( ;; ) {
698133Sigor@sysoev.ru         application = nxt_conf_next_object_member(applications, &name, &next);
699133Sigor@sysoev.ru         if (application == NULL) {
700133Sigor@sysoev.ru             break;
701133Sigor@sysoev.ru         }
702133Sigor@sysoev.ru 
703133Sigor@sysoev.ru         nxt_debug(task, "application \"%V\"", &name);
704133Sigor@sysoev.ru 
705144Smax.romanov@nginx.com         size = nxt_conf_json_length(application, NULL);
706144Smax.romanov@nginx.com 
707144Smax.romanov@nginx.com         app = nxt_malloc(sizeof(nxt_app_t) + name.length + size);
708133Sigor@sysoev.ru         if (app == NULL) {
709133Sigor@sysoev.ru             goto fail;
710133Sigor@sysoev.ru         }
711133Sigor@sysoev.ru 
712144Smax.romanov@nginx.com         nxt_memzero(app, sizeof(nxt_app_t));
713144Smax.romanov@nginx.com 
714144Smax.romanov@nginx.com         app->name.start = nxt_pointer_to(app, sizeof(nxt_app_t));
715144Smax.romanov@nginx.com         app->conf.start = nxt_pointer_to(app, sizeof(nxt_app_t) + name.length);
716133Sigor@sysoev.ru 
717133Sigor@sysoev.ru         p = nxt_conf_json_print(app->conf.start, application, NULL);
718133Sigor@sysoev.ru         app->conf.length = p - app->conf.start;
719133Sigor@sysoev.ru 
720144Smax.romanov@nginx.com         nxt_assert(app->conf.length <= size);
721144Smax.romanov@nginx.com 
722133Sigor@sysoev.ru         nxt_debug(task, "application conf \"%V\"", &app->conf);
723133Sigor@sysoev.ru 
724133Sigor@sysoev.ru         prev = nxt_router_app_find(&tmcf->conf->router->apps, &name);
725133Sigor@sysoev.ru 
726133Sigor@sysoev.ru         if (prev != NULL && nxt_strstr_eq(&app->conf, &prev->conf)) {
727133Sigor@sysoev.ru             nxt_free(app);
728133Sigor@sysoev.ru 
729133Sigor@sysoev.ru             nxt_queue_remove(&prev->link);
730133Sigor@sysoev.ru             nxt_queue_insert_tail(&tmcf->previous, &prev->link);
731133Sigor@sysoev.ru             continue;
732133Sigor@sysoev.ru         }
733133Sigor@sysoev.ru 
734136Svbart@nginx.com         ret = nxt_conf_map_object(application, nxt_router_app_conf,
735136Svbart@nginx.com                                   nxt_nitems(nxt_router_app_conf), &apcf);
736133Sigor@sysoev.ru         if (ret != NXT_OK) {
737133Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "application map error");
738133Sigor@sysoev.ru             goto app_fail;
739133Sigor@sysoev.ru         }
740115Sigor@sysoev.ru 
741133Sigor@sysoev.ru         nxt_debug(task, "application type: %V", &apcf.type);
742133Sigor@sysoev.ru         nxt_debug(task, "application workers: %D", apcf.workers);
743133Sigor@sysoev.ru 
744141Smax.romanov@nginx.com         type = nxt_app_parse_type(&apcf.type);
745141Smax.romanov@nginx.com 
746141Smax.romanov@nginx.com         if (type == NXT_APP_UNKNOWN) {
747141Smax.romanov@nginx.com             nxt_log(task, NXT_LOG_CRIT, "unknown application type: \"%V\"",
748141Smax.romanov@nginx.com                     &apcf.type);
749141Smax.romanov@nginx.com             goto app_fail;
750141Smax.romanov@nginx.com         }
751141Smax.romanov@nginx.com 
752141Smax.romanov@nginx.com         if (nxt_app_modules[type] == NULL) {
753133Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "unsupported application type: \"%V\"",
754133Sigor@sysoev.ru                     &apcf.type);
755133Sigor@sysoev.ru             goto app_fail;
756133Sigor@sysoev.ru         }
757133Sigor@sysoev.ru 
758133Sigor@sysoev.ru         ret = nxt_thread_mutex_create(&app->mutex);
759133Sigor@sysoev.ru         if (ret != NXT_OK) {
760133Sigor@sysoev.ru             goto app_fail;
761133Sigor@sysoev.ru         }
762133Sigor@sysoev.ru 
763141Smax.romanov@nginx.com         nxt_queue_init(&app->ports);
764141Smax.romanov@nginx.com         nxt_queue_init(&app->requests);
765141Smax.romanov@nginx.com 
766144Smax.romanov@nginx.com         app->name.length = name.length;
767144Smax.romanov@nginx.com         nxt_memcpy(app->name.start, name.start, name.length);
768144Smax.romanov@nginx.com 
769133Sigor@sysoev.ru         app->type = type;
770133Sigor@sysoev.ru         app->max_workers = apcf.workers;
771133Sigor@sysoev.ru         app->live = 1;
772141Smax.romanov@nginx.com         app->module = nxt_app_modules[type];
773133Sigor@sysoev.ru 
774133Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->apps, &app->link);
775133Sigor@sysoev.ru     }
776133Sigor@sysoev.ru 
777133Sigor@sysoev.ru     http = nxt_conf_get_path(conf, &http_path);
778133Sigor@sysoev.ru #if 0
779133Sigor@sysoev.ru     if (http == NULL) {
780133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "no \"http\" block");
781133Sigor@sysoev.ru         return NXT_ERROR;
782133Sigor@sysoev.ru     }
783133Sigor@sysoev.ru #endif
784133Sigor@sysoev.ru 
785133Sigor@sysoev.ru     listeners = nxt_conf_get_path(conf, &listeners_path);
786115Sigor@sysoev.ru     if (listeners == NULL) {
787133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "no \"listeners\" block");
788115Sigor@sysoev.ru         return NXT_ERROR;
789115Sigor@sysoev.ru     }
79053Sigor@sysoev.ru 
791133Sigor@sysoev.ru     next = 0;
79253Sigor@sysoev.ru 
793133Sigor@sysoev.ru     mp = tmcf->conf->mem_pool;
794115Sigor@sysoev.ru 
795115Sigor@sysoev.ru     for ( ;; ) {
796115Sigor@sysoev.ru         listener = nxt_conf_next_object_member(listeners, &name, &next);
797115Sigor@sysoev.ru         if (listener == NULL) {
798115Sigor@sysoev.ru             break;
799115Sigor@sysoev.ru         }
80053Sigor@sysoev.ru 
801115Sigor@sysoev.ru         sa = nxt_sockaddr_parse(mp, &name);
802115Sigor@sysoev.ru         if (sa == NULL) {
803115Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "invalid listener \"%V\"", &name);
804133Sigor@sysoev.ru             goto fail;
805115Sigor@sysoev.ru         }
806115Sigor@sysoev.ru 
807115Sigor@sysoev.ru         sa->type = SOCK_STREAM;
808115Sigor@sysoev.ru 
809115Sigor@sysoev.ru         nxt_debug(task, "router listener: \"%*s\"",
810115Sigor@sysoev.ru                   sa->length, nxt_sockaddr_start(sa));
81153Sigor@sysoev.ru 
812115Sigor@sysoev.ru         skcf = nxt_router_socket_conf(task, mp, sa);
813115Sigor@sysoev.ru         if (skcf == NULL) {
814133Sigor@sysoev.ru             goto fail;
815115Sigor@sysoev.ru         }
81653Sigor@sysoev.ru 
817136Svbart@nginx.com         ret = nxt_conf_map_object(listener, nxt_router_listener_conf,
818136Svbart@nginx.com                                   nxt_nitems(nxt_router_listener_conf), &lscf);
819115Sigor@sysoev.ru         if (ret != NXT_OK) {
820115Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "listener map error");
821133Sigor@sysoev.ru             goto fail;
822115Sigor@sysoev.ru         }
82353Sigor@sysoev.ru 
824133Sigor@sysoev.ru         nxt_debug(task, "application: %V", &lscf.application);
825133Sigor@sysoev.ru 
826133Sigor@sysoev.ru         // STUB, default values if http block is not defined.
827133Sigor@sysoev.ru         skcf->header_buffer_size = 2048;
828133Sigor@sysoev.ru         skcf->large_header_buffer_size = 8192;
829133Sigor@sysoev.ru         skcf->header_read_timeout = 5000;
83053Sigor@sysoev.ru 
831133Sigor@sysoev.ru         if (http != NULL) {
832136Svbart@nginx.com             ret = nxt_conf_map_object(http, nxt_router_http_conf,
833136Svbart@nginx.com                                       nxt_nitems(nxt_router_http_conf), skcf);
834133Sigor@sysoev.ru             if (ret != NXT_OK) {
835133Sigor@sysoev.ru                 nxt_log(task, NXT_LOG_CRIT, "http map error");
836133Sigor@sysoev.ru                 goto fail;
837133Sigor@sysoev.ru             }
838115Sigor@sysoev.ru         }
839115Sigor@sysoev.ru 
840115Sigor@sysoev.ru         skcf->listen.handler = nxt_router_conn_init;
841115Sigor@sysoev.ru         skcf->router_conf = tmcf->conf;
842160Sigor@sysoev.ru         skcf->router_conf->count++;
843133Sigor@sysoev.ru         skcf->application = nxt_router_listener_application(tmcf,
844133Sigor@sysoev.ru                                                             &lscf.application);
845115Sigor@sysoev.ru 
846115Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->pending, &skcf->link);
847115Sigor@sysoev.ru     }
84853Sigor@sysoev.ru 
84953Sigor@sysoev.ru     return NXT_OK;
850133Sigor@sysoev.ru 
851133Sigor@sysoev.ru app_fail:
852133Sigor@sysoev.ru 
853133Sigor@sysoev.ru     nxt_free(app);
854133Sigor@sysoev.ru 
855133Sigor@sysoev.ru fail:
856133Sigor@sysoev.ru 
857141Smax.romanov@nginx.com     nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) {
858141Smax.romanov@nginx.com 
859141Smax.romanov@nginx.com         nxt_queue_remove(&app->link);
860133Sigor@sysoev.ru         nxt_thread_mutex_destroy(&app->mutex);
861133Sigor@sysoev.ru         nxt_free(app);
862141Smax.romanov@nginx.com 
863141Smax.romanov@nginx.com     } nxt_queue_loop;
864133Sigor@sysoev.ru 
865133Sigor@sysoev.ru     return NXT_ERROR;
866133Sigor@sysoev.ru }
867133Sigor@sysoev.ru 
868133Sigor@sysoev.ru 
869133Sigor@sysoev.ru static nxt_app_t *
870133Sigor@sysoev.ru nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name)
871133Sigor@sysoev.ru {
872141Smax.romanov@nginx.com     nxt_app_t  *app;
873141Smax.romanov@nginx.com 
874141Smax.romanov@nginx.com     nxt_queue_each(app, queue, nxt_app_t, link) {
875133Sigor@sysoev.ru 
876133Sigor@sysoev.ru         if (nxt_strstr_eq(name, &app->name)) {
877133Sigor@sysoev.ru             return app;
878133Sigor@sysoev.ru         }
879141Smax.romanov@nginx.com 
880141Smax.romanov@nginx.com     } nxt_queue_loop;
881133Sigor@sysoev.ru 
882133Sigor@sysoev.ru     return NULL;
883133Sigor@sysoev.ru }
884133Sigor@sysoev.ru 
885133Sigor@sysoev.ru 
886133Sigor@sysoev.ru static nxt_app_t *
887133Sigor@sysoev.ru nxt_router_listener_application(nxt_router_temp_conf_t *tmcf, nxt_str_t *name)
888133Sigor@sysoev.ru {
889133Sigor@sysoev.ru     nxt_app_t  *app;
890133Sigor@sysoev.ru 
891133Sigor@sysoev.ru     app = nxt_router_app_find(&tmcf->apps, name);
892133Sigor@sysoev.ru 
893133Sigor@sysoev.ru     if (app == NULL) {
894134Sigor@sysoev.ru         app = nxt_router_app_find(&tmcf->previous, name);
895133Sigor@sysoev.ru     }
896133Sigor@sysoev.ru 
897133Sigor@sysoev.ru     return app;
89853Sigor@sysoev.ru }
89953Sigor@sysoev.ru 
90053Sigor@sysoev.ru 
90153Sigor@sysoev.ru static nxt_socket_conf_t *
90265Sigor@sysoev.ru nxt_router_socket_conf(nxt_task_t *task, nxt_mp_t *mp, nxt_sockaddr_t *sa)
90353Sigor@sysoev.ru {
904163Smax.romanov@nginx.com     nxt_socket_conf_t  *skcf;
905163Smax.romanov@nginx.com 
906163Smax.romanov@nginx.com     skcf = nxt_mp_zget(mp, sizeof(nxt_socket_conf_t));
907163Smax.romanov@nginx.com     if (nxt_slow_path(skcf == NULL)) {
90853Sigor@sysoev.ru         return NULL;
90953Sigor@sysoev.ru     }
91053Sigor@sysoev.ru 
911163Smax.romanov@nginx.com     skcf->sockaddr = sa;
912163Smax.romanov@nginx.com 
913163Smax.romanov@nginx.com     skcf->listen.sockaddr = sa;
914163Smax.romanov@nginx.com     skcf->listen.socklen = sa->socklen;
915163Smax.romanov@nginx.com     skcf->listen.address_length = sa->length;
916163Smax.romanov@nginx.com 
917163Smax.romanov@nginx.com     skcf->listen.socket = -1;
918163Smax.romanov@nginx.com     skcf->listen.backlog = NXT_LISTEN_BACKLOG;
919163Smax.romanov@nginx.com     skcf->listen.flags = NXT_NONBLOCK;
920163Smax.romanov@nginx.com     skcf->listen.read_after_accept = 1;
921163Smax.romanov@nginx.com 
922163Smax.romanov@nginx.com     return skcf;
92353Sigor@sysoev.ru }
92453Sigor@sysoev.ru 
92553Sigor@sysoev.ru 
92653Sigor@sysoev.ru static void
92753Sigor@sysoev.ru nxt_router_listen_sockets_sort(nxt_router_t *router,
92853Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf)
92953Sigor@sysoev.ru {
93053Sigor@sysoev.ru     nxt_queue_link_t   *nqlk, *oqlk, *next;
93153Sigor@sysoev.ru     nxt_socket_conf_t  *nskcf, *oskcf;
93253Sigor@sysoev.ru 
93353Sigor@sysoev.ru     for (nqlk = nxt_queue_first(&tmcf->pending);
93453Sigor@sysoev.ru          nqlk != nxt_queue_tail(&tmcf->pending);
93553Sigor@sysoev.ru          nqlk = next)
93653Sigor@sysoev.ru     {
93753Sigor@sysoev.ru         next = nxt_queue_next(nqlk);
93853Sigor@sysoev.ru         nskcf = nxt_queue_link_data(nqlk, nxt_socket_conf_t, link);
93953Sigor@sysoev.ru 
94053Sigor@sysoev.ru         for (oqlk = nxt_queue_first(&router->sockets);
94153Sigor@sysoev.ru              oqlk != nxt_queue_tail(&router->sockets);
94253Sigor@sysoev.ru              oqlk = nxt_queue_next(oqlk))
94353Sigor@sysoev.ru         {
94453Sigor@sysoev.ru             oskcf = nxt_queue_link_data(oqlk, nxt_socket_conf_t, link);
94553Sigor@sysoev.ru 
946115Sigor@sysoev.ru             if (nxt_sockaddr_cmp(nskcf->sockaddr, oskcf->sockaddr)) {
947115Sigor@sysoev.ru                 nskcf->socket = oskcf->socket;
948115Sigor@sysoev.ru                 nskcf->listen.socket = oskcf->listen.socket;
949