xref: /unit/src/nxt_router.c (revision 193)
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 
48139Sigor@sysoev.ru static nxt_router_temp_conf_t *nxt_router_temp_conf(nxt_task_t *task);
49139Sigor@sysoev.ru static nxt_int_t nxt_router_conf_new(nxt_task_t *task,
50139Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, u_char *start, u_char *end);
51139Sigor@sysoev.ru static void nxt_router_conf_success(nxt_task_t *task,
52139Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
53139Sigor@sysoev.ru static void nxt_router_conf_error(nxt_task_t *task,
54139Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
55139Sigor@sysoev.ru static void nxt_router_conf_send(nxt_task_t *task,
56*193Smax.romanov@nginx.com     nxt_router_temp_conf_t *tmcf, nxt_port_msg_type_t type);
5753Sigor@sysoev.ru static void nxt_router_listen_sockets_sort(nxt_router_t *router,
5853Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
5953Sigor@sysoev.ru 
60115Sigor@sysoev.ru static nxt_int_t nxt_router_conf_create(nxt_task_t *task,
61115Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, u_char *start, u_char *end);
62133Sigor@sysoev.ru static nxt_app_t *nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name);
63133Sigor@sysoev.ru static nxt_app_t *nxt_router_listener_application(nxt_router_temp_conf_t *tmcf,
64133Sigor@sysoev.ru     nxt_str_t *name);
6553Sigor@sysoev.ru static nxt_int_t nxt_router_listen_sockets_stub_create(nxt_task_t *task,
6653Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
6765Sigor@sysoev.ru static nxt_socket_conf_t *nxt_router_socket_conf(nxt_task_t *task, nxt_mp_t *mp,
6865Sigor@sysoev.ru     nxt_sockaddr_t *sa);
6953Sigor@sysoev.ru 
7053Sigor@sysoev.ru static nxt_int_t nxt_router_engines_create(nxt_task_t *task,
7153Sigor@sysoev.ru     nxt_router_t *router, nxt_router_temp_conf_t *tmcf,
7253Sigor@sysoev.ru     const nxt_event_interface_t *interface);
73115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf,
74115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
75115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf,
76115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
77115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf,
78115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
79115Sigor@sysoev.ru static void nxt_router_engine_socket_count(nxt_queue_t *sockets);
80154Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf,
81154Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets,
82154Sigor@sysoev.ru     nxt_work_handler_t handler);
83139Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf,
84139Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets);
8553Sigor@sysoev.ru 
8653Sigor@sysoev.ru static nxt_int_t nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt,
8753Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
8853Sigor@sysoev.ru static nxt_int_t nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt,
8953Sigor@sysoev.ru     nxt_event_engine_t *engine);
90133Sigor@sysoev.ru static void nxt_router_apps_sort(nxt_router_t *router,
91133Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
9253Sigor@sysoev.ru 
9353Sigor@sysoev.ru static void nxt_router_engines_post(nxt_router_temp_conf_t *tmcf);
94154Sigor@sysoev.ru static void nxt_router_engine_post(nxt_router_engine_conf_t *recf);
9553Sigor@sysoev.ru 
9653Sigor@sysoev.ru static void nxt_router_thread_start(void *data);
9753Sigor@sysoev.ru static void nxt_router_listen_socket_create(nxt_task_t *task, void *obj,
9853Sigor@sysoev.ru     void *data);
9953Sigor@sysoev.ru static void nxt_router_listen_socket_update(nxt_task_t *task, void *obj,
10053Sigor@sysoev.ru     void *data);
10153Sigor@sysoev.ru static void nxt_router_listen_socket_delete(nxt_task_t *task, void *obj,
10253Sigor@sysoev.ru     void *data);
10353Sigor@sysoev.ru static void nxt_router_listen_socket_close(nxt_task_t *task, void *obj,
10453Sigor@sysoev.ru     void *data);
10553Sigor@sysoev.ru static void nxt_router_listen_socket_release(nxt_task_t *task,
10653Sigor@sysoev.ru     nxt_socket_conf_joint_t *joint);
10753Sigor@sysoev.ru static void nxt_router_thread_exit_handler(nxt_task_t *task, void *obj,
10853Sigor@sysoev.ru     void *data);
10953Sigor@sysoev.ru static void nxt_router_conf_release(nxt_task_t *task,
11053Sigor@sysoev.ru     nxt_socket_conf_joint_t *joint);
11153Sigor@sysoev.ru 
112167Smax.romanov@nginx.com static void nxt_router_send_sw_request(nxt_task_t *task, void *obj,
113167Smax.romanov@nginx.com     void *data);
114167Smax.romanov@nginx.com static nxt_bool_t nxt_router_app_free(nxt_task_t *task, nxt_app_t *app);
115167Smax.romanov@nginx.com static nxt_port_t * nxt_router_app_get_port(nxt_app_t *app, uint32_t req_id);
116141Smax.romanov@nginx.com static void nxt_router_app_release_port(nxt_task_t *task, void *obj,
117141Smax.romanov@nginx.com     void *data);
118141Smax.romanov@nginx.com 
11953Sigor@sysoev.ru static void nxt_router_conn_init(nxt_task_t *task, void *obj, void *data);
12053Sigor@sysoev.ru static void nxt_router_conn_http_header_parse(nxt_task_t *task, void *obj,
12153Sigor@sysoev.ru     void *data);
12288Smax.romanov@nginx.com static void nxt_router_process_http_request(nxt_task_t *task,
12388Smax.romanov@nginx.com     nxt_conn_t *c, nxt_app_parse_ctx_t *ap);
124141Smax.romanov@nginx.com static void nxt_router_process_http_request_mp(nxt_task_t *task,
125167Smax.romanov@nginx.com     nxt_req_app_link_t *ra, nxt_port_t *port);
12688Smax.romanov@nginx.com static void nxt_router_conn_ready(nxt_task_t *task, void *obj, void *data);
12753Sigor@sysoev.ru static void nxt_router_conn_close(nxt_task_t *task, void *obj, void *data);
12853Sigor@sysoev.ru static void nxt_router_conn_free(nxt_task_t *task, void *obj, void *data);
12953Sigor@sysoev.ru static void nxt_router_conn_error(nxt_task_t *task, void *obj, void *data);
13053Sigor@sysoev.ru static void nxt_router_conn_timeout(nxt_task_t *task, void *obj, void *data);
13162Sigor@sysoev.ru static nxt_msec_t nxt_router_conn_timeout_value(nxt_conn_t *c, uintptr_t data);
13220Sigor@sysoev.ru 
133141Smax.romanov@nginx.com static void nxt_router_gen_error(nxt_task_t *task, nxt_conn_t *c, int code,
134141Smax.romanov@nginx.com     const char* fmt, ...);
135141Smax.romanov@nginx.com 
136119Smax.romanov@nginx.com static nxt_router_t  *nxt_router;
13720Sigor@sysoev.ru 
13820Sigor@sysoev.ru nxt_int_t
139141Smax.romanov@nginx.com nxt_router_start(nxt_task_t *task, void *data)
14020Sigor@sysoev.ru {
141141Smax.romanov@nginx.com     nxt_int_t      ret;
142141Smax.romanov@nginx.com     nxt_router_t   *router;
143141Smax.romanov@nginx.com     nxt_runtime_t  *rt;
144141Smax.romanov@nginx.com 
145141Smax.romanov@nginx.com     rt = task->thread->runtime;
14653Sigor@sysoev.ru 
14788Smax.romanov@nginx.com     ret = nxt_app_http_init(task, rt);
14888Smax.romanov@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
14988Smax.romanov@nginx.com         return ret;
15088Smax.romanov@nginx.com     }
15188Smax.romanov@nginx.com 
15253Sigor@sysoev.ru     router = nxt_zalloc(sizeof(nxt_router_t));
15353Sigor@sysoev.ru     if (nxt_slow_path(router == NULL)) {
15453Sigor@sysoev.ru         return NXT_ERROR;
15553Sigor@sysoev.ru     }
15653Sigor@sysoev.ru 
15753Sigor@sysoev.ru     nxt_queue_init(&router->engines);
15853Sigor@sysoev.ru     nxt_queue_init(&router->sockets);
159133Sigor@sysoev.ru     nxt_queue_init(&router->apps);
16053Sigor@sysoev.ru 
161119Smax.romanov@nginx.com     nxt_router = router;
162119Smax.romanov@nginx.com 
163115Sigor@sysoev.ru     return NXT_OK;
164115Sigor@sysoev.ru }
165115Sigor@sysoev.ru 
166115Sigor@sysoev.ru 
167167Smax.romanov@nginx.com static nxt_start_worker_t *
168192Smax.romanov@nginx.com nxt_router_sw_create(nxt_task_t *task, nxt_app_t *app, nxt_req_app_link_t *ra)
169167Smax.romanov@nginx.com {
170167Smax.romanov@nginx.com     nxt_port_t          *master_port;
171167Smax.romanov@nginx.com     nxt_runtime_t       *rt;
172167Smax.romanov@nginx.com     nxt_start_worker_t  *sw;
173167Smax.romanov@nginx.com 
174192Smax.romanov@nginx.com     sw = nxt_zalloc(sizeof(nxt_start_worker_t));
175167Smax.romanov@nginx.com 
176167Smax.romanov@nginx.com     if (nxt_slow_path(sw == NULL)) {
177167Smax.romanov@nginx.com         return NULL;
178167Smax.romanov@nginx.com     }
179167Smax.romanov@nginx.com 
180167Smax.romanov@nginx.com     sw->app = app;
181167Smax.romanov@nginx.com     sw->ra = ra;
182167Smax.romanov@nginx.com 
183192Smax.romanov@nginx.com     nxt_debug(task, "sw %p create, request #%uxD, app '%V' %p", sw,
184167Smax.romanov@nginx.com                     ra->req_id, &app->name, app);
185167Smax.romanov@nginx.com 
186167Smax.romanov@nginx.com     rt = task->thread->runtime;
187167Smax.romanov@nginx.com     master_port = rt->port_by_type[NXT_PROCESS_MASTER];
188167Smax.romanov@nginx.com 
189167Smax.romanov@nginx.com     sw->work.handler = nxt_router_send_sw_request;
190167Smax.romanov@nginx.com     sw->work.task = &master_port->engine->task;
191167Smax.romanov@nginx.com     sw->work.obj = sw;
192167Smax.romanov@nginx.com     sw->work.data = task->thread->engine;
193167Smax.romanov@nginx.com     sw->work.next = NULL;
194167Smax.romanov@nginx.com 
195167Smax.romanov@nginx.com     if (task->thread->engine != master_port->engine) {
196192Smax.romanov@nginx.com         nxt_debug(task, "sw %p post send to master engine %p", sw,
197167Smax.romanov@nginx.com                   master_port->engine);
198167Smax.romanov@nginx.com 
199167Smax.romanov@nginx.com         nxt_event_engine_post(master_port->engine, &sw->work);
200167Smax.romanov@nginx.com 
201167Smax.romanov@nginx.com     } else {
202167Smax.romanov@nginx.com         nxt_router_send_sw_request(task, sw, sw->work.data);
203167Smax.romanov@nginx.com     }
204167Smax.romanov@nginx.com 
205167Smax.romanov@nginx.com     return sw;
206167Smax.romanov@nginx.com }
207167Smax.romanov@nginx.com 
208167Smax.romanov@nginx.com 
209192Smax.romanov@nginx.com nxt_inline void
210192Smax.romanov@nginx.com nxt_router_sw_release(nxt_task_t *task, nxt_start_worker_t *sw)
211141Smax.romanov@nginx.com {
212192Smax.romanov@nginx.com     nxt_debug(task, "sw %p release", sw);
213192Smax.romanov@nginx.com 
214192Smax.romanov@nginx.com     nxt_free(sw);
215141Smax.romanov@nginx.com }
216141Smax.romanov@nginx.com 
217141Smax.romanov@nginx.com 
218167Smax.romanov@nginx.com static nxt_req_app_link_t *
219167Smax.romanov@nginx.com nxt_router_ra_create(nxt_task_t *task, nxt_req_conn_link_t *rc)
220167Smax.romanov@nginx.com {
221167Smax.romanov@nginx.com     nxt_mp_t            *mp;
222167Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
223167Smax.romanov@nginx.com 
224167Smax.romanov@nginx.com     mp = rc->conn->mem_pool;
225167Smax.romanov@nginx.com 
226167Smax.romanov@nginx.com     ra = nxt_mp_retain(mp, sizeof(nxt_req_app_link_t));
227167Smax.romanov@nginx.com 
228167Smax.romanov@nginx.com     if (nxt_slow_path(ra == NULL)) {
229167Smax.romanov@nginx.com         return NULL;
230167Smax.romanov@nginx.com     }
231167Smax.romanov@nginx.com 
232167Smax.romanov@nginx.com     nxt_debug(task, "ra #%uxD create", ra->req_id);
233167Smax.romanov@nginx.com 
234167Smax.romanov@nginx.com     nxt_memzero(ra, sizeof(nxt_req_app_link_t));
235167Smax.romanov@nginx.com 
236167Smax.romanov@nginx.com     ra->req_id = rc->req_id;
237167Smax.romanov@nginx.com     ra->app_port = NULL;
238167Smax.romanov@nginx.com     ra->rc = rc;
239167Smax.romanov@nginx.com 
240167Smax.romanov@nginx.com     ra->mem_pool = mp;
241167Smax.romanov@nginx.com 
242167Smax.romanov@nginx.com     ra->work.handler = NULL;
243167Smax.romanov@nginx.com     ra->work.task = &task->thread->engine->task;
244167Smax.romanov@nginx.com     ra->work.obj = ra;
245167Smax.romanov@nginx.com     ra->work.data = task->thread->engine;
246167Smax.romanov@nginx.com 
247167Smax.romanov@nginx.com     return ra;
248167Smax.romanov@nginx.com }
249167Smax.romanov@nginx.com 
250167Smax.romanov@nginx.com 
251167Smax.romanov@nginx.com static void
252167Smax.romanov@nginx.com nxt_router_ra_release(nxt_task_t *task, void *obj, void *data)
253167Smax.romanov@nginx.com {
254167Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
255167Smax.romanov@nginx.com     nxt_event_engine_t  *engine;
256167Smax.romanov@nginx.com 
257167Smax.romanov@nginx.com     ra = obj;
258167Smax.romanov@nginx.com     engine = data;
259167Smax.romanov@nginx.com 
260167Smax.romanov@nginx.com     if (task->thread->engine != engine) {
261167Smax.romanov@nginx.com         ra->work.handler = nxt_router_ra_release;
262167Smax.romanov@nginx.com         ra->work.task = &engine->task;
263167Smax.romanov@nginx.com         ra->work.next = NULL;
264167Smax.romanov@nginx.com 
265167Smax.romanov@nginx.com         nxt_debug(task, "ra #%uxD post release to %p", ra->req_id, engine);
266167Smax.romanov@nginx.com 
267167Smax.romanov@nginx.com         nxt_event_engine_post(engine, &ra->work);
268167Smax.romanov@nginx.com 
269167Smax.romanov@nginx.com         return;
270167Smax.romanov@nginx.com     }
271167Smax.romanov@nginx.com 
272167Smax.romanov@nginx.com     nxt_debug(task, "ra #%uxD release", ra->req_id);
273167Smax.romanov@nginx.com 
274167Smax.romanov@nginx.com     if (ra->app_port != NULL) {
275167Smax.romanov@nginx.com 
276167Smax.romanov@nginx.com         if (ra->rc->conn != NULL) {
277167Smax.romanov@nginx.com             ra->rc->app_port = ra->app_port;
278167Smax.romanov@nginx.com 
279167Smax.romanov@nginx.com         } else {
280167Smax.romanov@nginx.com             nxt_router_app_release_port(task, ra->app_port, ra->app_port->app);
281167Smax.romanov@nginx.com         }
282167Smax.romanov@nginx.com     }
283167Smax.romanov@nginx.com 
284167Smax.romanov@nginx.com     nxt_mp_release(ra->mem_pool, ra);
285167Smax.romanov@nginx.com }
286167Smax.romanov@nginx.com 
287167Smax.romanov@nginx.com 
288141Smax.romanov@nginx.com void
289141Smax.romanov@nginx.com nxt_router_new_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
290141Smax.romanov@nginx.com {
291141Smax.romanov@nginx.com     nxt_port_new_port_handler(task, msg);
292141Smax.romanov@nginx.com 
293192Smax.romanov@nginx.com     if (msg->port_msg.stream == 0) {
294141Smax.romanov@nginx.com         return;
295141Smax.romanov@nginx.com     }
296141Smax.romanov@nginx.com 
297192Smax.romanov@nginx.com     if (msg->new_port == NULL || msg->new_port->type != NXT_PROCESS_WORKER) {
298192Smax.romanov@nginx.com         msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR;
299141Smax.romanov@nginx.com     }
300192Smax.romanov@nginx.com 
301192Smax.romanov@nginx.com     nxt_port_rpc_handler(task, msg);
302141Smax.romanov@nginx.com }
303141Smax.romanov@nginx.com 
304141Smax.romanov@nginx.com 
305139Sigor@sysoev.ru void
306139Sigor@sysoev.ru nxt_router_conf_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
307115Sigor@sysoev.ru {
308139Sigor@sysoev.ru     size_t                  dump_size;
309139Sigor@sysoev.ru     nxt_buf_t               *b;
310139Sigor@sysoev.ru     nxt_int_t               ret;
311139Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
312139Sigor@sysoev.ru 
313139Sigor@sysoev.ru     b = msg->buf;
314139Sigor@sysoev.ru 
315139Sigor@sysoev.ru     dump_size = nxt_buf_used_size(b);
316139Sigor@sysoev.ru 
317139Sigor@sysoev.ru     if (dump_size > 300) {
318139Sigor@sysoev.ru         dump_size = 300;
31953Sigor@sysoev.ru     }
32053Sigor@sysoev.ru 
321139Sigor@sysoev.ru     nxt_debug(task, "router conf data (%z): %*s",
322139Sigor@sysoev.ru               msg->size, dump_size, b->mem.pos);
323139Sigor@sysoev.ru 
324139Sigor@sysoev.ru     tmcf = nxt_router_temp_conf(task);
325139Sigor@sysoev.ru     if (nxt_slow_path(tmcf == NULL)) {
326139Sigor@sysoev.ru         return;
32753Sigor@sysoev.ru     }
32853Sigor@sysoev.ru 
329139Sigor@sysoev.ru     tmcf->conf->router = nxt_router;
330139Sigor@sysoev.ru     tmcf->stream = msg->port_msg.stream;
331139Sigor@sysoev.ru     tmcf->port = nxt_runtime_port_find(task->thread->runtime,
332139Sigor@sysoev.ru                                        msg->port_msg.pid, 0);
333139Sigor@sysoev.ru 
334139Sigor@sysoev.ru     ret = nxt_router_conf_new(task, tmcf, b->mem.pos, b->mem.free);
335139Sigor@sysoev.ru 
336139Sigor@sysoev.ru     b->mem.pos = b->mem.free;
337139Sigor@sysoev.ru 
338139Sigor@sysoev.ru     if (ret == NXT_OK) {
339180Smax.romanov@nginx.com         nxt_router_conf_success(task, tmcf);
340180Smax.romanov@nginx.com         return;
341139Sigor@sysoev.ru     }
342139Sigor@sysoev.ru 
343139Sigor@sysoev.ru     nxt_log(task, NXT_LOG_CRIT, "failed to apply new conf");
344139Sigor@sysoev.ru 
345180Smax.romanov@nginx.com     nxt_router_conf_error(task, tmcf);
34653Sigor@sysoev.ru }
34753Sigor@sysoev.ru 
34853Sigor@sysoev.ru 
349192Smax.romanov@nginx.com void
350192Smax.romanov@nginx.com nxt_router_remove_pid_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
351192Smax.romanov@nginx.com {
352192Smax.romanov@nginx.com     nxt_port_remove_pid_handler(task, msg);
353192Smax.romanov@nginx.com 
354192Smax.romanov@nginx.com     if (msg->port_msg.stream == 0) {
355192Smax.romanov@nginx.com         return;
356192Smax.romanov@nginx.com     }
357192Smax.romanov@nginx.com 
358192Smax.romanov@nginx.com     msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR;
359192Smax.romanov@nginx.com 
360192Smax.romanov@nginx.com     nxt_port_rpc_handler(task, msg);
361192Smax.romanov@nginx.com }
362192Smax.romanov@nginx.com 
363192Smax.romanov@nginx.com 
36453Sigor@sysoev.ru static nxt_router_temp_conf_t *
365139Sigor@sysoev.ru nxt_router_temp_conf(nxt_task_t *task)
36653Sigor@sysoev.ru {
36765Sigor@sysoev.ru     nxt_mp_t                *mp, *tmp;
36853Sigor@sysoev.ru     nxt_router_conf_t       *rtcf;
36953Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
37053Sigor@sysoev.ru 
37165Sigor@sysoev.ru     mp = nxt_mp_create(1024, 128, 256, 32);
37253Sigor@sysoev.ru     if (nxt_slow_path(mp == NULL)) {
37353Sigor@sysoev.ru         return NULL;
37453Sigor@sysoev.ru     }
37553Sigor@sysoev.ru 
37665Sigor@sysoev.ru     rtcf = nxt_mp_zget(mp, sizeof(nxt_router_conf_t));
37753Sigor@sysoev.ru     if (nxt_slow_path(rtcf == NULL)) {
37853Sigor@sysoev.ru         goto fail;
37953Sigor@sysoev.ru     }
38053Sigor@sysoev.ru 
38153Sigor@sysoev.ru     rtcf->mem_pool = mp;
38253Sigor@sysoev.ru 
38365Sigor@sysoev.ru     tmp = nxt_mp_create(1024, 128, 256, 32);
38453Sigor@sysoev.ru     if (nxt_slow_path(tmp == NULL)) {
38553Sigor@sysoev.ru         goto fail;
38653Sigor@sysoev.ru     }
38753Sigor@sysoev.ru 
38865Sigor@sysoev.ru     tmcf = nxt_mp_zget(tmp, sizeof(nxt_router_temp_conf_t));
38953Sigor@sysoev.ru     if (nxt_slow_path(tmcf == NULL)) {
39053Sigor@sysoev.ru         goto temp_fail;
39153Sigor@sysoev.ru     }
39253Sigor@sysoev.ru 
39353Sigor@sysoev.ru     tmcf->mem_pool = tmp;
39453Sigor@sysoev.ru     tmcf->conf = rtcf;
395139Sigor@sysoev.ru     tmcf->count = 1;
396139Sigor@sysoev.ru     tmcf->engine = task->thread->engine;
39753Sigor@sysoev.ru 
39853Sigor@sysoev.ru     tmcf->engines = nxt_array_create(tmcf->mem_pool, 4,
39953Sigor@sysoev.ru                                      sizeof(nxt_router_engine_conf_t));
40053Sigor@sysoev.ru     if (nxt_slow_path(tmcf->engines == NULL)) {
40153Sigor@sysoev.ru         goto temp_fail;
40253Sigor@sysoev.ru     }
40353Sigor@sysoev.ru 
40453Sigor@sysoev.ru     nxt_queue_init(&tmcf->deleting);
40553Sigor@sysoev.ru     nxt_queue_init(&tmcf->keeping);
40653Sigor@sysoev.ru     nxt_queue_init(&tmcf->updating);
40753Sigor@sysoev.ru     nxt_queue_init(&tmcf->pending);
40853Sigor@sysoev.ru     nxt_queue_init(&tmcf->creating);
409133Sigor@sysoev.ru     nxt_queue_init(&tmcf->apps);
410133Sigor@sysoev.ru     nxt_queue_init(&tmcf->previous);
41153Sigor@sysoev.ru 
41253Sigor@sysoev.ru     return tmcf;
41353Sigor@sysoev.ru 
41453Sigor@sysoev.ru temp_fail:
41553Sigor@sysoev.ru 
41665Sigor@sysoev.ru     nxt_mp_destroy(tmp);
41753Sigor@sysoev.ru 
41853Sigor@sysoev.ru fail:
41953Sigor@sysoev.ru 
42065Sigor@sysoev.ru     nxt_mp_destroy(mp);
42153Sigor@sysoev.ru 
42253Sigor@sysoev.ru     return NULL;
42353Sigor@sysoev.ru }
42453Sigor@sysoev.ru 
42553Sigor@sysoev.ru 
426139Sigor@sysoev.ru static nxt_int_t
427139Sigor@sysoev.ru nxt_router_conf_new(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
428139Sigor@sysoev.ru     u_char *start, u_char *end)
429139Sigor@sysoev.ru {
430139Sigor@sysoev.ru     nxt_int_t                    ret;
431139Sigor@sysoev.ru     nxt_router_t                 *router;
432139Sigor@sysoev.ru     nxt_runtime_t                *rt;
433139Sigor@sysoev.ru     const nxt_event_interface_t  *interface;
434139Sigor@sysoev.ru 
435139Sigor@sysoev.ru     ret = nxt_router_conf_create(task, tmcf, start, end);
436139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
437139Sigor@sysoev.ru         return ret;
438139Sigor@sysoev.ru     }
439139Sigor@sysoev.ru 
440139Sigor@sysoev.ru     router = tmcf->conf->router;
441139Sigor@sysoev.ru 
442139Sigor@sysoev.ru     nxt_router_listen_sockets_sort(router, tmcf);
443139Sigor@sysoev.ru 
444139Sigor@sysoev.ru     ret = nxt_router_listen_sockets_stub_create(task, tmcf);
445139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
446139Sigor@sysoev.ru         return ret;
447139Sigor@sysoev.ru     }
448139Sigor@sysoev.ru 
449139Sigor@sysoev.ru     rt = task->thread->runtime;
450139Sigor@sysoev.ru 
451139Sigor@sysoev.ru     interface = nxt_service_get(rt->services, "engine", NULL);
452139Sigor@sysoev.ru 
453139Sigor@sysoev.ru     ret = nxt_router_engines_create(task, router, tmcf, interface);
454139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
455139Sigor@sysoev.ru         return ret;
456139Sigor@sysoev.ru     }
457139Sigor@sysoev.ru 
458139Sigor@sysoev.ru     ret = nxt_router_threads_create(task, rt, tmcf);
459139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
460139Sigor@sysoev.ru         return ret;
461139Sigor@sysoev.ru     }
462139Sigor@sysoev.ru 
463139Sigor@sysoev.ru     nxt_router_apps_sort(router, tmcf);
464139Sigor@sysoev.ru 
465139Sigor@sysoev.ru     nxt_router_engines_post(tmcf);
466139Sigor@sysoev.ru 
467139Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->updating);
468139Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->creating);
469139Sigor@sysoev.ru 
470139Sigor@sysoev.ru     return NXT_OK;
471139Sigor@sysoev.ru }
472139Sigor@sysoev.ru 
473139Sigor@sysoev.ru 
474139Sigor@sysoev.ru static void
475139Sigor@sysoev.ru nxt_router_conf_wait(nxt_task_t *task, void *obj, void *data)
476139Sigor@sysoev.ru {
477153Sigor@sysoev.ru     nxt_joint_job_t  *job;
478153Sigor@sysoev.ru 
479153Sigor@sysoev.ru     job = obj;
480153Sigor@sysoev.ru 
481153Sigor@sysoev.ru     nxt_router_conf_success(task, job->tmcf);
482139Sigor@sysoev.ru }
483139Sigor@sysoev.ru 
484139Sigor@sysoev.ru 
485139Sigor@sysoev.ru static void
486139Sigor@sysoev.ru nxt_router_conf_success(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
487139Sigor@sysoev.ru {
488139Sigor@sysoev.ru     nxt_debug(task, "temp conf count:%D", tmcf->count);
489139Sigor@sysoev.ru 
490139Sigor@sysoev.ru     if (--tmcf->count == 0) {
491*193Smax.romanov@nginx.com         nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_READY_LAST);
492139Sigor@sysoev.ru     }
493139Sigor@sysoev.ru }
494139Sigor@sysoev.ru 
495139Sigor@sysoev.ru 
496139Sigor@sysoev.ru static void
497139Sigor@sysoev.ru nxt_router_conf_error(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
498139Sigor@sysoev.ru {
499148Sigor@sysoev.ru     nxt_socket_t       s;
500149Sigor@sysoev.ru     nxt_router_t       *router;
501148Sigor@sysoev.ru     nxt_queue_link_t   *qlk;
502148Sigor@sysoev.ru     nxt_socket_conf_t  *skcf;
503148Sigor@sysoev.ru 
504148Sigor@sysoev.ru     for (qlk = nxt_queue_first(&tmcf->creating);
505148Sigor@sysoev.ru          qlk != nxt_queue_tail(&tmcf->creating);
506148Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
507148Sigor@sysoev.ru     {
508148Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
509148Sigor@sysoev.ru         s = skcf->listen.socket;
510148Sigor@sysoev.ru 
511148Sigor@sysoev.ru         if (s != -1) {
512148Sigor@sysoev.ru             nxt_socket_close(task, s);
513148Sigor@sysoev.ru         }
514148Sigor@sysoev.ru 
515148Sigor@sysoev.ru         nxt_free(skcf->socket);
516148Sigor@sysoev.ru     }
517148Sigor@sysoev.ru 
518149Sigor@sysoev.ru     router = tmcf->conf->router;
519149Sigor@sysoev.ru 
520149Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->keeping);
521149Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->deleting);
522149Sigor@sysoev.ru 
523148Sigor@sysoev.ru     // TODO: new engines and threads
524148Sigor@sysoev.ru 
525139Sigor@sysoev.ru     nxt_mp_destroy(tmcf->conf->mem_pool);
526139Sigor@sysoev.ru 
527*193Smax.romanov@nginx.com     nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_ERROR);
528139Sigor@sysoev.ru }
529139Sigor@sysoev.ru 
530139Sigor@sysoev.ru 
531139Sigor@sysoev.ru static void
532139Sigor@sysoev.ru nxt_router_conf_send(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
533*193Smax.romanov@nginx.com     nxt_port_msg_type_t type)
534139Sigor@sysoev.ru {
535*193Smax.romanov@nginx.com     nxt_port_socket_write(task, tmcf->port, type, -1, tmcf->stream, 0, NULL);
536139Sigor@sysoev.ru }
537139Sigor@sysoev.ru 
538139Sigor@sysoev.ru 
539115Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_conf[] = {
540115Sigor@sysoev.ru     {
541133Sigor@sysoev.ru         nxt_string("listeners_threads"),
542115Sigor@sysoev.ru         NXT_CONF_MAP_INT32,
543115Sigor@sysoev.ru         offsetof(nxt_router_conf_t, threads),
544115Sigor@sysoev.ru     },
545115Sigor@sysoev.ru };
546115Sigor@sysoev.ru 
547115Sigor@sysoev.ru 
548133Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_app_conf[] = {
549115Sigor@sysoev.ru     {
550133Sigor@sysoev.ru         nxt_string("type"),
551115Sigor@sysoev.ru         NXT_CONF_MAP_STR,
552133Sigor@sysoev.ru         offsetof(nxt_router_app_conf_t, type),
553115Sigor@sysoev.ru     },
554115Sigor@sysoev.ru 
555115Sigor@sysoev.ru     {
556133Sigor@sysoev.ru         nxt_string("workers"),
557115Sigor@sysoev.ru         NXT_CONF_MAP_INT32,
558133Sigor@sysoev.ru         offsetof(nxt_router_app_conf_t, workers),
559133Sigor@sysoev.ru     },
560133Sigor@sysoev.ru };
561133Sigor@sysoev.ru 
562133Sigor@sysoev.ru 
563133Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_listener_conf[] = {
564133Sigor@sysoev.ru     {
565133Sigor@sysoev.ru         nxt_string("application"),
566133Sigor@sysoev.ru         NXT_CONF_MAP_STR,
567133Sigor@sysoev.ru         offsetof(nxt_router_listener_conf_t, application),
568115Sigor@sysoev.ru     },
569115Sigor@sysoev.ru };
570115Sigor@sysoev.ru 
571115Sigor@sysoev.ru 
572115Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_http_conf[] = {
573115Sigor@sysoev.ru     {
574115Sigor@sysoev.ru         nxt_string("header_buffer_size"),
575115Sigor@sysoev.ru         NXT_CONF_MAP_SIZE,
576115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, header_buffer_size),
577115Sigor@sysoev.ru     },
578115Sigor@sysoev.ru 
579115Sigor@sysoev.ru     {
580115Sigor@sysoev.ru         nxt_string("large_header_buffer_size"),
581115Sigor@sysoev.ru         NXT_CONF_MAP_SIZE,
582115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, large_header_buffer_size),
583115Sigor@sysoev.ru     },
584115Sigor@sysoev.ru 
585115Sigor@sysoev.ru     {
586115Sigor@sysoev.ru         nxt_string("header_read_timeout"),
587115Sigor@sysoev.ru         NXT_CONF_MAP_MSEC,
588115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, header_read_timeout),
589115Sigor@sysoev.ru     },
590115Sigor@sysoev.ru };
591115Sigor@sysoev.ru 
592115Sigor@sysoev.ru 
59353Sigor@sysoev.ru static nxt_int_t
594115Sigor@sysoev.ru nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
595115Sigor@sysoev.ru     u_char *start, u_char *end)
59653Sigor@sysoev.ru {
597133Sigor@sysoev.ru     u_char                      *p;
598133Sigor@sysoev.ru     size_t                      size;
599115Sigor@sysoev.ru     nxt_mp_t                    *mp;
600115Sigor@sysoev.ru     uint32_t                    next;
601115Sigor@sysoev.ru     nxt_int_t                   ret;
602115Sigor@sysoev.ru     nxt_str_t                   name;
603133Sigor@sysoev.ru     nxt_app_t                   *app, *prev;
604133Sigor@sysoev.ru     nxt_app_type_t              type;
605115Sigor@sysoev.ru     nxt_sockaddr_t              *sa;
606133Sigor@sysoev.ru     nxt_conf_value_t            *conf, *http;
607133Sigor@sysoev.ru     nxt_conf_value_t            *applications, *application;
608133Sigor@sysoev.ru     nxt_conf_value_t            *listeners, *listener;
609115Sigor@sysoev.ru     nxt_socket_conf_t           *skcf;
610133Sigor@sysoev.ru     nxt_router_app_conf_t       apcf;
611115Sigor@sysoev.ru     nxt_router_listener_conf_t  lscf;
612115Sigor@sysoev.ru 
613115Sigor@sysoev.ru     static nxt_str_t  http_path = nxt_string("/http");
614133Sigor@sysoev.ru     static nxt_str_t  applications_path = nxt_string("/applications");
615115Sigor@sysoev.ru     static nxt_str_t  listeners_path = nxt_string("/listeners");
616115Sigor@sysoev.ru 
617115Sigor@sysoev.ru     conf = nxt_conf_json_parse(tmcf->mem_pool, start, end);
618115Sigor@sysoev.ru     if (conf == NULL) {
619115Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "configuration parsing error");
620115Sigor@sysoev.ru         return NXT_ERROR;
621115Sigor@sysoev.ru     }
622115Sigor@sysoev.ru 
623136Svbart@nginx.com     ret = nxt_conf_map_object(conf, nxt_router_conf,
624136Svbart@nginx.com                               nxt_nitems(nxt_router_conf), tmcf->conf);
625115Sigor@sysoev.ru     if (ret != NXT_OK) {
626133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "root map error");
627115Sigor@sysoev.ru         return NXT_ERROR;
628115Sigor@sysoev.ru     }
629115Sigor@sysoev.ru 
630117Sigor@sysoev.ru     if (tmcf->conf->threads == 0) {
631117Sigor@sysoev.ru         tmcf->conf->threads = nxt_ncpu;
632117Sigor@sysoev.ru     }
633117Sigor@sysoev.ru 
634133Sigor@sysoev.ru     applications = nxt_conf_get_path(conf, &applications_path);
635133Sigor@sysoev.ru     if (applications == NULL) {
636133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "no \"applications\" block");
637115Sigor@sysoev.ru         return NXT_ERROR;
638115Sigor@sysoev.ru     }
639115Sigor@sysoev.ru 
640133Sigor@sysoev.ru     next = 0;
641133Sigor@sysoev.ru 
642133Sigor@sysoev.ru     for ( ;; ) {
643133Sigor@sysoev.ru         application = nxt_conf_next_object_member(applications, &name, &next);
644133Sigor@sysoev.ru         if (application == NULL) {
645133Sigor@sysoev.ru             break;
646133Sigor@sysoev.ru         }
647133Sigor@sysoev.ru 
648133Sigor@sysoev.ru         nxt_debug(task, "application \"%V\"", &name);
649133Sigor@sysoev.ru 
650144Smax.romanov@nginx.com         size = nxt_conf_json_length(application, NULL);
651144Smax.romanov@nginx.com 
652144Smax.romanov@nginx.com         app = nxt_malloc(sizeof(nxt_app_t) + name.length + size);
653133Sigor@sysoev.ru         if (app == NULL) {
654133Sigor@sysoev.ru             goto fail;
655133Sigor@sysoev.ru         }
656133Sigor@sysoev.ru 
657144Smax.romanov@nginx.com         nxt_memzero(app, sizeof(nxt_app_t));
658144Smax.romanov@nginx.com 
659144Smax.romanov@nginx.com         app->name.start = nxt_pointer_to(app, sizeof(nxt_app_t));
660144Smax.romanov@nginx.com         app->conf.start = nxt_pointer_to(app, sizeof(nxt_app_t) + name.length);
661133Sigor@sysoev.ru 
662133Sigor@sysoev.ru         p = nxt_conf_json_print(app->conf.start, application, NULL);
663133Sigor@sysoev.ru         app->conf.length = p - app->conf.start;
664133Sigor@sysoev.ru 
665144Smax.romanov@nginx.com         nxt_assert(app->conf.length <= size);
666144Smax.romanov@nginx.com 
667133Sigor@sysoev.ru         nxt_debug(task, "application conf \"%V\"", &app->conf);
668133Sigor@sysoev.ru 
669133Sigor@sysoev.ru         prev = nxt_router_app_find(&tmcf->conf->router->apps, &name);
670133Sigor@sysoev.ru 
671133Sigor@sysoev.ru         if (prev != NULL && nxt_strstr_eq(&app->conf, &prev->conf)) {
672133Sigor@sysoev.ru             nxt_free(app);
673133Sigor@sysoev.ru 
674133Sigor@sysoev.ru             nxt_queue_remove(&prev->link);
675133Sigor@sysoev.ru             nxt_queue_insert_tail(&tmcf->previous, &prev->link);
676133Sigor@sysoev.ru             continue;
677133Sigor@sysoev.ru         }
678133Sigor@sysoev.ru 
679136Svbart@nginx.com         ret = nxt_conf_map_object(application, nxt_router_app_conf,
680136Svbart@nginx.com                                   nxt_nitems(nxt_router_app_conf), &apcf);
681133Sigor@sysoev.ru         if (ret != NXT_OK) {
682133Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "application map error");
683133Sigor@sysoev.ru             goto app_fail;
684133Sigor@sysoev.ru         }
685115Sigor@sysoev.ru 
686133Sigor@sysoev.ru         nxt_debug(task, "application type: %V", &apcf.type);
687133Sigor@sysoev.ru         nxt_debug(task, "application workers: %D", apcf.workers);
688133Sigor@sysoev.ru 
689141Smax.romanov@nginx.com         type = nxt_app_parse_type(&apcf.type);
690141Smax.romanov@nginx.com 
691141Smax.romanov@nginx.com         if (type == NXT_APP_UNKNOWN) {
692141Smax.romanov@nginx.com             nxt_log(task, NXT_LOG_CRIT, "unknown application type: \"%V\"",
693141Smax.romanov@nginx.com                     &apcf.type);
694141Smax.romanov@nginx.com             goto app_fail;
695141Smax.romanov@nginx.com         }
696141Smax.romanov@nginx.com 
697141Smax.romanov@nginx.com         if (nxt_app_modules[type] == NULL) {
698133Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "unsupported application type: \"%V\"",
699133Sigor@sysoev.ru                     &apcf.type);
700133Sigor@sysoev.ru             goto app_fail;
701133Sigor@sysoev.ru         }
702133Sigor@sysoev.ru 
703133Sigor@sysoev.ru         ret = nxt_thread_mutex_create(&app->mutex);
704133Sigor@sysoev.ru         if (ret != NXT_OK) {
705133Sigor@sysoev.ru             goto app_fail;
706133Sigor@sysoev.ru         }
707133Sigor@sysoev.ru 
708141Smax.romanov@nginx.com         nxt_queue_init(&app->ports);
709141Smax.romanov@nginx.com         nxt_queue_init(&app->requests);
710141Smax.romanov@nginx.com 
711144Smax.romanov@nginx.com         app->name.length = name.length;
712144Smax.romanov@nginx.com         nxt_memcpy(app->name.start, name.start, name.length);
713144Smax.romanov@nginx.com 
714133Sigor@sysoev.ru         app->type = type;
715133Sigor@sysoev.ru         app->max_workers = apcf.workers;
716133Sigor@sysoev.ru         app->live = 1;
717141Smax.romanov@nginx.com         app->module = nxt_app_modules[type];
718133Sigor@sysoev.ru 
719133Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->apps, &app->link);
720133Sigor@sysoev.ru     }
721133Sigor@sysoev.ru 
722133Sigor@sysoev.ru     http = nxt_conf_get_path(conf, &http_path);
723133Sigor@sysoev.ru #if 0
724133Sigor@sysoev.ru     if (http == NULL) {
725133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "no \"http\" block");
726133Sigor@sysoev.ru         return NXT_ERROR;
727133Sigor@sysoev.ru     }
728133Sigor@sysoev.ru #endif
729133Sigor@sysoev.ru 
730133Sigor@sysoev.ru     listeners = nxt_conf_get_path(conf, &listeners_path);
731115Sigor@sysoev.ru     if (listeners == NULL) {
732133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "no \"listeners\" block");
733115Sigor@sysoev.ru         return NXT_ERROR;
734115Sigor@sysoev.ru     }
73553Sigor@sysoev.ru 
736133Sigor@sysoev.ru     next = 0;
73753Sigor@sysoev.ru 
738133Sigor@sysoev.ru     mp = tmcf->conf->mem_pool;
739115Sigor@sysoev.ru 
740115Sigor@sysoev.ru     for ( ;; ) {
741115Sigor@sysoev.ru         listener = nxt_conf_next_object_member(listeners, &name, &next);
742115Sigor@sysoev.ru         if (listener == NULL) {
743115Sigor@sysoev.ru             break;
744115Sigor@sysoev.ru         }
74553Sigor@sysoev.ru 
746115Sigor@sysoev.ru         sa = nxt_sockaddr_parse(mp, &name);
747115Sigor@sysoev.ru         if (sa == NULL) {
748115Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "invalid listener \"%V\"", &name);
749133Sigor@sysoev.ru             goto fail;
750115Sigor@sysoev.ru         }
751115Sigor@sysoev.ru 
752115Sigor@sysoev.ru         sa->type = SOCK_STREAM;
753115Sigor@sysoev.ru 
754115Sigor@sysoev.ru         nxt_debug(task, "router listener: \"%*s\"",
755115Sigor@sysoev.ru                   sa->length, nxt_sockaddr_start(sa));
75653Sigor@sysoev.ru 
757115Sigor@sysoev.ru         skcf = nxt_router_socket_conf(task, mp, sa);
758115Sigor@sysoev.ru         if (skcf == NULL) {
759133Sigor@sysoev.ru             goto fail;
760115Sigor@sysoev.ru         }
76153Sigor@sysoev.ru 
762136Svbart@nginx.com         ret = nxt_conf_map_object(listener, nxt_router_listener_conf,
763136Svbart@nginx.com                                   nxt_nitems(nxt_router_listener_conf), &lscf);
764115Sigor@sysoev.ru         if (ret != NXT_OK) {
765115Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "listener map error");
766133Sigor@sysoev.ru             goto fail;
767115Sigor@sysoev.ru         }
76853Sigor@sysoev.ru 
769133Sigor@sysoev.ru         nxt_debug(task, "application: %V", &lscf.application);
770133Sigor@sysoev.ru 
771133Sigor@sysoev.ru         // STUB, default values if http block is not defined.
772133Sigor@sysoev.ru         skcf->header_buffer_size = 2048;
773133Sigor@sysoev.ru         skcf->large_header_buffer_size = 8192;
774133Sigor@sysoev.ru         skcf->header_read_timeout = 5000;
77553Sigor@sysoev.ru 
776133Sigor@sysoev.ru         if (http != NULL) {
777136Svbart@nginx.com             ret = nxt_conf_map_object(http, nxt_router_http_conf,
778136Svbart@nginx.com                                       nxt_nitems(nxt_router_http_conf), skcf);
779133Sigor@sysoev.ru             if (ret != NXT_OK) {
780133Sigor@sysoev.ru                 nxt_log(task, NXT_LOG_CRIT, "http map error");
781133Sigor@sysoev.ru                 goto fail;
782133Sigor@sysoev.ru             }
783115Sigor@sysoev.ru         }
784115Sigor@sysoev.ru 
785115Sigor@sysoev.ru         skcf->listen.handler = nxt_router_conn_init;
786115Sigor@sysoev.ru         skcf->router_conf = tmcf->conf;
787160Sigor@sysoev.ru         skcf->router_conf->count++;
788133Sigor@sysoev.ru         skcf->application = nxt_router_listener_application(tmcf,
789133Sigor@sysoev.ru                                                             &lscf.application);
790115Sigor@sysoev.ru 
791115Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->pending, &skcf->link);
792115Sigor@sysoev.ru     }
79353Sigor@sysoev.ru 
79453Sigor@sysoev.ru     return NXT_OK;
795133Sigor@sysoev.ru 
796133Sigor@sysoev.ru app_fail:
797133Sigor@sysoev.ru 
798133Sigor@sysoev.ru     nxt_free(app);
799133Sigor@sysoev.ru 
800133Sigor@sysoev.ru fail:
801133Sigor@sysoev.ru 
802141Smax.romanov@nginx.com     nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) {
803141Smax.romanov@nginx.com 
804141Smax.romanov@nginx.com         nxt_queue_remove(&app->link);
805133Sigor@sysoev.ru         nxt_thread_mutex_destroy(&app->mutex);
806133Sigor@sysoev.ru         nxt_free(app);
807141Smax.romanov@nginx.com 
808141Smax.romanov@nginx.com     } nxt_queue_loop;
809133Sigor@sysoev.ru 
810133Sigor@sysoev.ru     return NXT_ERROR;
811133Sigor@sysoev.ru }
812133Sigor@sysoev.ru 
813133Sigor@sysoev.ru 
814133Sigor@sysoev.ru static nxt_app_t *
815133Sigor@sysoev.ru nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name)
816133Sigor@sysoev.ru {
817141Smax.romanov@nginx.com     nxt_app_t  *app;
818141Smax.romanov@nginx.com 
819141Smax.romanov@nginx.com     nxt_queue_each(app, queue, nxt_app_t, link) {
820133Sigor@sysoev.ru 
821133Sigor@sysoev.ru         if (nxt_strstr_eq(name, &app->name)) {
822133Sigor@sysoev.ru             return app;
823133Sigor@sysoev.ru         }
824141Smax.romanov@nginx.com 
825141Smax.romanov@nginx.com     } nxt_queue_loop;
826133Sigor@sysoev.ru 
827133Sigor@sysoev.ru     return NULL;
828133Sigor@sysoev.ru }
829133Sigor@sysoev.ru 
830133Sigor@sysoev.ru 
831133Sigor@sysoev.ru static nxt_app_t *
832133Sigor@sysoev.ru nxt_router_listener_application(nxt_router_temp_conf_t *tmcf, nxt_str_t *name)
833133Sigor@sysoev.ru {
834133Sigor@sysoev.ru     nxt_app_t  *app;
835133Sigor@sysoev.ru 
836133Sigor@sysoev.ru     app = nxt_router_app_find(&tmcf->apps, name);
837133Sigor@sysoev.ru 
838133Sigor@sysoev.ru     if (app == NULL) {
839134Sigor@sysoev.ru         app = nxt_router_app_find(&tmcf->previous, name);
840133Sigor@sysoev.ru     }
841133Sigor@sysoev.ru 
842133Sigor@sysoev.ru     return app;
84353Sigor@sysoev.ru }
84453Sigor@sysoev.ru 
84553Sigor@sysoev.ru 
84653Sigor@sysoev.ru static nxt_socket_conf_t *
84765Sigor@sysoev.ru nxt_router_socket_conf(nxt_task_t *task, nxt_mp_t *mp, nxt_sockaddr_t *sa)
84853Sigor@sysoev.ru {
849163Smax.romanov@nginx.com     nxt_socket_conf_t  *skcf;
850163Smax.romanov@nginx.com 
851163Smax.romanov@nginx.com     skcf = nxt_mp_zget(mp, sizeof(nxt_socket_conf_t));
852163Smax.romanov@nginx.com     if (nxt_slow_path(skcf == NULL)) {
85353Sigor@sysoev.ru         return NULL;
85453Sigor@sysoev.ru     }
85553Sigor@sysoev.ru 
856163Smax.romanov@nginx.com     skcf->sockaddr = sa;
857163Smax.romanov@nginx.com 
858163Smax.romanov@nginx.com     skcf->listen.sockaddr = sa;
859163Smax.romanov@nginx.com     skcf->listen.socklen = sa->socklen;
860163Smax.romanov@nginx.com     skcf->listen.address_length = sa->length;
861163Smax.romanov@nginx.com 
862163Smax.romanov@nginx.com     skcf->listen.socket = -1;
863163Smax.romanov@nginx.com     skcf->listen.backlog = NXT_LISTEN_BACKLOG;
864163Smax.romanov@nginx.com     skcf->listen.flags = NXT_NONBLOCK;
865163Smax.romanov@nginx.com     skcf->listen.read_after_accept = 1;
866163Smax.romanov@nginx.com 
867163Smax.romanov@nginx.com     return skcf;
86853Sigor@sysoev.ru }
86953Sigor@sysoev.ru 
87053Sigor@sysoev.ru 
87153Sigor@sysoev.ru static void
87253Sigor@sysoev.ru nxt_router_listen_sockets_sort(nxt_router_t *router,
87353Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf)
87453Sigor@sysoev.ru {
87553Sigor@sysoev.ru     nxt_queue_link_t   *nqlk, *oqlk, *next;
87653Sigor@sysoev.ru     nxt_socket_conf_t  *nskcf, *oskcf;
87753Sigor@sysoev.ru 
87853Sigor@sysoev.ru     for (nqlk = nxt_queue_first(&tmcf->pending);
87953Sigor@sysoev.ru          nqlk != nxt_queue_tail(&tmcf->pending);
88053Sigor@sysoev.ru          nqlk = next)
88153Sigor@sysoev.ru     {
88253Sigor@sysoev.ru         next = nxt_queue_next(nqlk);
88353Sigor@sysoev.ru         nskcf = nxt_queue_link_data(nqlk, nxt_socket_conf_t, link);
88453Sigor@sysoev.ru 
88553Sigor@sysoev.ru         for (oqlk = nxt_queue_first(&router->sockets);
88653Sigor@sysoev.ru              oqlk != nxt_queue_tail(&router->sockets);
88753Sigor@sysoev.ru              oqlk = nxt_queue_next(oqlk))
88853Sigor@sysoev.ru         {
88953Sigor@sysoev.ru             oskcf = nxt_queue_link_data(oqlk, nxt_socket_conf_t, link);
89053Sigor@sysoev.ru 
891115Sigor@sysoev.ru             if (nxt_sockaddr_cmp(nskcf->sockaddr, oskcf->sockaddr)) {
892115Sigor@sysoev.ru                 nskcf->socket = oskcf->socket;
893115Sigor@sysoev.ru                 nskcf->listen.socket = oskcf->listen.socket;
894115Sigor@sysoev.ru 
89553Sigor@sysoev.ru                 nxt_queue_remove(oqlk);
89653Sigor@sysoev.ru                 nxt_queue_insert_tail(&tmcf->keeping, oqlk);
89753Sigor@sysoev.ru 
89853Sigor@sysoev.ru                 nxt_queue_remove(nqlk);
89953Sigor@sysoev.ru                 nxt_queue_insert_tail(&tmcf->updating, nqlk);
90053Sigor@sysoev.ru 
90153Sigor@sysoev.ru                 break;
90253Sigor@sysoev.ru             }
90353Sigor@sysoev.ru         }
90453Sigor@sysoev.ru     }
90553Sigor@sysoev.ru 
90653Sigor@sysoev.ru     nxt_queue_add(&tmcf->deleting, &router->sockets);
907115Sigor@sysoev.ru     nxt_queue_init(&router->sockets);
90853Sigor@sysoev.ru }
90953Sigor@sysoev.ru 
91053Sigor@sysoev.ru 
91153Sigor@sysoev.ru static nxt_int_t
91253Sigor@sysoev.ru nxt_router_listen_sockets_stub_create(nxt_task_t *task,
91353Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf)
91453Sigor@sysoev.ru {
915115Sigor@sysoev.ru     nxt_int_t            ret;
916115Sigor@sysoev.ru     nxt_socket_t         s;
917115Sigor@sysoev.ru     nxt_queue_link_t     *qlk, *nqlk;
918115Sigor@sysoev.ru     nxt_socket_conf_t    *skcf;
919115Sigor@sysoev.ru     nxt_router_socket_t  *rtsk;
92053Sigor@sysoev.ru 
92153Sigor@sysoev.ru     for (qlk = nxt_queue_first(&tmcf->pending);
92253Sigor@sysoev.ru          qlk != nxt_queue_tail(&tmcf->pending);
92353Sigor@sysoev.ru          qlk = nqlk)
92453Sigor@sysoev.ru     {
925115Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
926115Sigor@sysoev.ru 
927115Sigor@sysoev.ru         s = nxt_listen_socket_create0(task, skcf->sockaddr, NXT_NONBLOCK);
928115Sigor@sysoev.ru         if (nxt_slow_path(s == -1)) {
929115Sigor@sysoev.ru             return NXT_ERROR;
930115Sigor@sysoev.ru         }
931115Sigor@sysoev.ru 
932115Sigor@sysoev.ru         ret = nxt_listen_socket(task, s, NXT_LISTEN_BACKLOG);
933115Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
934148Sigor@sysoev.ru             goto fail;
935115Sigor@sysoev.ru         }
936115Sigor@sysoev.ru 
937115Sigor@sysoev.ru         skcf->listen.socket = s;
938115Sigor@sysoev.ru 
939148Sigor@sysoev.ru         rtsk = nxt_malloc(sizeof(nxt_router_socket_t));
940148Sigor@sysoev.ru         if (nxt_slow_path(rtsk == NULL)) {
941148Sigor@sysoev.ru             goto fail;
942148Sigor@sysoev.ru         }
943148Sigor@sysoev.ru 
944148Sigor@sysoev.ru         rtsk->count = 0;
945148Sigor@sysoev.ru         rtsk->fd = skcf->listen.socket;
946148Sigor@sysoev.ru         skcf->socket = rtsk;
947115Sigor@sysoev.ru 
94853Sigor@sysoev.ru         nqlk = nxt_queue_next(qlk);
94953Sigor@sysoev.ru         nxt_queue_remove(qlk);
95053Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->creating, qlk);
95153Sigor@sysoev.ru     }
95253Sigor@sysoev.ru 
95353Sigor@sysoev.ru     return NXT_OK;
954148Sigor@sysoev.ru 
955148Sigor@sysoev.ru fail:
956148Sigor@sysoev.ru 
957148Sigor@sysoev.ru     nxt_socket_close(task, s);
958148Sigor@sysoev.ru 
959148Sigor@sysoev.ru     return NXT_ERROR;
96053Sigor@sysoev.ru }
96153Sigor@sysoev.ru 
96253Sigor@sysoev.ru 
96353Sigor@sysoev.ru static nxt_int_t
96453Sigor@sysoev.ru nxt_router_engines_create(nxt_task_t *task, nxt_router_t *router,
96553Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, const nxt_event_interface_t *interface)
96653Sigor@sysoev.ru {
96753Sigor@sysoev.ru     nxt_int_t                 ret;
96853Sigor@sysoev.ru     nxt_uint_t                n, threads;
96953Sigor@sysoev.ru     nxt_queue_link_t          *qlk;
97053Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
97153Sigor@sysoev.ru 
97253Sigor@sysoev.ru     threads = tmcf->conf->threads;
97353Sigor@sysoev.ru 
97453Sigor@sysoev.ru     tmcf->engines = nxt_array_create(tmcf->mem_pool, threads,
97553Sigor@sysoev.ru                                      sizeof(nxt_router_engine_conf_t));
97653Sigor@sysoev.ru     if (nxt_slow_path(tmcf->engines == NULL)) {
97753Sigor@sysoev.ru         return NXT_ERROR;
97853Sigor@sysoev.ru     }
97953Sigor@sysoev.ru 
98053Sigor@sysoev.ru     n = 0;
98153Sigor@sysoev.ru 
98253Sigor@sysoev.ru     for (qlk = nxt_queue_first(&router->engines);
98353Sigor@sysoev.ru          qlk != nxt_queue_tail(&router->engines);
98453