xref: /unit/src/nxt_router.c (revision 144)
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 
23141Smax.romanov@nginx.com typedef struct nxt_start_worker_s nxt_start_worker_t;
24141Smax.romanov@nginx.com 
25141Smax.romanov@nginx.com struct nxt_start_worker_s {
26141Smax.romanov@nginx.com     uint32_t               stream;
27141Smax.romanov@nginx.com     nxt_app_t              *app;
28141Smax.romanov@nginx.com     nxt_req_conn_link_t    *rc;
29141Smax.romanov@nginx.com     nxt_mp_t               *mem_pool;
30141Smax.romanov@nginx.com     void                   *joint;
31141Smax.romanov@nginx.com 
32141Smax.romanov@nginx.com     nxt_work_t             work;
33141Smax.romanov@nginx.com };
34141Smax.romanov@nginx.com 
35141Smax.romanov@nginx.com 
36139Sigor@sysoev.ru static nxt_router_temp_conf_t *nxt_router_temp_conf(nxt_task_t *task);
37139Sigor@sysoev.ru static nxt_int_t nxt_router_conf_new(nxt_task_t *task,
38139Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, u_char *start, u_char *end);
39139Sigor@sysoev.ru static void nxt_router_conf_success(nxt_task_t *task,
40139Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
41139Sigor@sysoev.ru static void nxt_router_conf_error(nxt_task_t *task,
42139Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
43139Sigor@sysoev.ru static void nxt_router_conf_send(nxt_task_t *task,
44139Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, u_char *start, size_t size);
45139Sigor@sysoev.ru static void nxt_router_conf_buf_completion(nxt_task_t *task, void *obj,
46139Sigor@sysoev.ru     void *data);
4753Sigor@sysoev.ru static void nxt_router_listen_sockets_sort(nxt_router_t *router,
4853Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
4953Sigor@sysoev.ru 
50115Sigor@sysoev.ru static nxt_int_t nxt_router_conf_create(nxt_task_t *task,
51115Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, u_char *start, u_char *end);
52133Sigor@sysoev.ru static nxt_app_t *nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name);
53133Sigor@sysoev.ru static nxt_app_t *nxt_router_listener_application(nxt_router_temp_conf_t *tmcf,
54133Sigor@sysoev.ru     nxt_str_t *name);
5553Sigor@sysoev.ru static nxt_int_t nxt_router_listen_sockets_stub_create(nxt_task_t *task,
5653Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
5765Sigor@sysoev.ru static nxt_socket_conf_t *nxt_router_socket_conf(nxt_task_t *task, nxt_mp_t *mp,
5865Sigor@sysoev.ru     nxt_sockaddr_t *sa);
5953Sigor@sysoev.ru 
6053Sigor@sysoev.ru static nxt_int_t nxt_router_engines_create(nxt_task_t *task,
6153Sigor@sysoev.ru     nxt_router_t *router, nxt_router_temp_conf_t *tmcf,
6253Sigor@sysoev.ru     const nxt_event_interface_t *interface);
63115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf,
64115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
65115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf,
66115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
67115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf,
68115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
69115Sigor@sysoev.ru static void nxt_router_engine_socket_count(nxt_queue_t *sockets);
70115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_create(nxt_mp_t *mp,
71139Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_router_engine_conf_t *recf,
72139Sigor@sysoev.ru     nxt_queue_t *sockets, nxt_array_t *array, nxt_work_handler_t handler);
73139Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf,
74139Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets);
7553Sigor@sysoev.ru 
7653Sigor@sysoev.ru static nxt_int_t nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt,
7753Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
7853Sigor@sysoev.ru static nxt_int_t nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt,
7953Sigor@sysoev.ru     nxt_event_engine_t *engine);
80133Sigor@sysoev.ru static void nxt_router_apps_sort(nxt_router_t *router,
81133Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
8253Sigor@sysoev.ru 
8353Sigor@sysoev.ru static void nxt_router_engines_post(nxt_router_temp_conf_t *tmcf);
84139Sigor@sysoev.ru static void nxt_router_engine_post(nxt_router_temp_conf_t *tmcf,
85139Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
8653Sigor@sysoev.ru 
8753Sigor@sysoev.ru static void nxt_router_thread_start(void *data);
8853Sigor@sysoev.ru static void nxt_router_listen_socket_create(nxt_task_t *task, void *obj,
8953Sigor@sysoev.ru     void *data);
9053Sigor@sysoev.ru static void nxt_router_listen_socket_update(nxt_task_t *task, void *obj,
9153Sigor@sysoev.ru     void *data);
9253Sigor@sysoev.ru static void nxt_router_listen_socket_delete(nxt_task_t *task, void *obj,
9353Sigor@sysoev.ru     void *data);
9453Sigor@sysoev.ru static void nxt_router_listen_socket_close(nxt_task_t *task, void *obj,
9553Sigor@sysoev.ru     void *data);
9653Sigor@sysoev.ru static void nxt_router_listen_socket_release(nxt_task_t *task,
9753Sigor@sysoev.ru     nxt_socket_conf_joint_t *joint);
9853Sigor@sysoev.ru static void nxt_router_thread_exit_handler(nxt_task_t *task, void *obj,
9953Sigor@sysoev.ru     void *data);
10053Sigor@sysoev.ru static void nxt_router_conf_release(nxt_task_t *task,
10153Sigor@sysoev.ru     nxt_socket_conf_joint_t *joint);
10253Sigor@sysoev.ru 
103141Smax.romanov@nginx.com static nxt_port_t * nxt_router_app_get_port(nxt_app_t *app);
104141Smax.romanov@nginx.com static void nxt_router_app_release_port(nxt_task_t *task, void *obj,
105141Smax.romanov@nginx.com     void *data);
106141Smax.romanov@nginx.com 
107141Smax.romanov@nginx.com static void nxt_router_sw_add(nxt_task_t *task, nxt_router_t *router,
108141Smax.romanov@nginx.com     nxt_start_worker_t *sw);
109141Smax.romanov@nginx.com static nxt_start_worker_t *nxt_router_sw_find_remove(nxt_task_t *task,
110141Smax.romanov@nginx.com     nxt_router_t *router, uint32_t id);
111141Smax.romanov@nginx.com 
11253Sigor@sysoev.ru static void nxt_router_conn_init(nxt_task_t *task, void *obj, void *data);
11353Sigor@sysoev.ru static void nxt_router_conn_http_header_parse(nxt_task_t *task, void *obj,
11453Sigor@sysoev.ru     void *data);
11588Smax.romanov@nginx.com static void nxt_router_process_http_request(nxt_task_t *task,
11688Smax.romanov@nginx.com     nxt_conn_t *c, nxt_app_parse_ctx_t *ap);
117141Smax.romanov@nginx.com static void nxt_router_process_http_request_mp(nxt_task_t *task,
118141Smax.romanov@nginx.com     nxt_req_conn_link_t *rc, nxt_mp_t *mp);
11988Smax.romanov@nginx.com static void nxt_router_conn_ready(nxt_task_t *task, void *obj, void *data);
12053Sigor@sysoev.ru static void nxt_router_conn_close(nxt_task_t *task, void *obj, void *data);
12153Sigor@sysoev.ru static void nxt_router_conn_free(nxt_task_t *task, void *obj, void *data);
12253Sigor@sysoev.ru static void nxt_router_conn_error(nxt_task_t *task, void *obj, void *data);
12353Sigor@sysoev.ru static void nxt_router_conn_timeout(nxt_task_t *task, void *obj, void *data);
12462Sigor@sysoev.ru static nxt_msec_t nxt_router_conn_timeout_value(nxt_conn_t *c, uintptr_t data);
12520Sigor@sysoev.ru 
126141Smax.romanov@nginx.com static void nxt_router_gen_error(nxt_task_t *task, nxt_conn_t *c, int code,
127141Smax.romanov@nginx.com     const char* fmt, ...);
128141Smax.romanov@nginx.com 
129119Smax.romanov@nginx.com static nxt_router_t  *nxt_router;
13020Sigor@sysoev.ru 
13120Sigor@sysoev.ru nxt_int_t
132141Smax.romanov@nginx.com nxt_router_start(nxt_task_t *task, void *data)
13320Sigor@sysoev.ru {
134141Smax.romanov@nginx.com     nxt_int_t      ret;
135141Smax.romanov@nginx.com     nxt_router_t   *router;
136141Smax.romanov@nginx.com     nxt_runtime_t  *rt;
137141Smax.romanov@nginx.com 
138141Smax.romanov@nginx.com     rt = task->thread->runtime;
13953Sigor@sysoev.ru 
14088Smax.romanov@nginx.com     ret = nxt_app_http_init(task, rt);
14188Smax.romanov@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
14288Smax.romanov@nginx.com         return ret;
14388Smax.romanov@nginx.com     }
14488Smax.romanov@nginx.com 
14553Sigor@sysoev.ru     router = nxt_zalloc(sizeof(nxt_router_t));
14653Sigor@sysoev.ru     if (nxt_slow_path(router == NULL)) {
14753Sigor@sysoev.ru         return NXT_ERROR;
14853Sigor@sysoev.ru     }
14953Sigor@sysoev.ru 
15053Sigor@sysoev.ru     nxt_queue_init(&router->engines);
15153Sigor@sysoev.ru     nxt_queue_init(&router->sockets);
152133Sigor@sysoev.ru     nxt_queue_init(&router->apps);
15353Sigor@sysoev.ru 
154119Smax.romanov@nginx.com     nxt_router = router;
155119Smax.romanov@nginx.com 
156115Sigor@sysoev.ru     return NXT_OK;
157115Sigor@sysoev.ru }
158115Sigor@sysoev.ru 
159115Sigor@sysoev.ru 
160141Smax.romanov@nginx.com static void
161141Smax.romanov@nginx.com nxt_router_sw_release(nxt_task_t *task, void *obj, void *data)
162141Smax.romanov@nginx.com {
163141Smax.romanov@nginx.com     nxt_start_worker_t       *sw;
164141Smax.romanov@nginx.com     nxt_socket_conf_joint_t  *joint;
165141Smax.romanov@nginx.com 
166141Smax.romanov@nginx.com     sw = obj;
167141Smax.romanov@nginx.com     joint = sw->joint;
168141Smax.romanov@nginx.com 
169141Smax.romanov@nginx.com     nxt_debug(task, "sw #%uxD release", sw->stream);
170141Smax.romanov@nginx.com 
171141Smax.romanov@nginx.com     if (nxt_mp_release(sw->mem_pool, sw) == 0) {
172141Smax.romanov@nginx.com         nxt_router_conf_release(task, joint);
173141Smax.romanov@nginx.com     }
174141Smax.romanov@nginx.com }
175141Smax.romanov@nginx.com 
176141Smax.romanov@nginx.com 
177141Smax.romanov@nginx.com void
178141Smax.romanov@nginx.com nxt_router_new_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
179141Smax.romanov@nginx.com {
180141Smax.romanov@nginx.com     nxt_start_worker_t  *sw;
181141Smax.romanov@nginx.com 
182141Smax.romanov@nginx.com     nxt_port_new_port_handler(task, msg);
183141Smax.romanov@nginx.com 
184141Smax.romanov@nginx.com     if (msg->new_port == NULL || msg->new_port->type != NXT_PROCESS_WORKER) {
185141Smax.romanov@nginx.com         return;
186141Smax.romanov@nginx.com     }
187141Smax.romanov@nginx.com 
188141Smax.romanov@nginx.com     sw = nxt_router_sw_find_remove(task, nxt_router, msg->port_msg.stream);
189141Smax.romanov@nginx.com 
190141Smax.romanov@nginx.com     if (nxt_fast_path(sw != NULL)) {
191141Smax.romanov@nginx.com         msg->new_port->app = sw->app;
192141Smax.romanov@nginx.com 
193141Smax.romanov@nginx.com         nxt_router_app_release_port(task, msg->new_port, sw->app);
194141Smax.romanov@nginx.com 
195141Smax.romanov@nginx.com         sw->work.handler = nxt_router_sw_release;
196141Smax.romanov@nginx.com 
197141Smax.romanov@nginx.com         nxt_debug(task, "post sw #%uxD release to %p", sw->stream,
198141Smax.romanov@nginx.com                   sw->work.data);
199141Smax.romanov@nginx.com 
200141Smax.romanov@nginx.com         nxt_event_engine_post(sw->work.data, &sw->work);
201141Smax.romanov@nginx.com     }
202141Smax.romanov@nginx.com }
203141Smax.romanov@nginx.com 
204141Smax.romanov@nginx.com 
205139Sigor@sysoev.ru void
206139Sigor@sysoev.ru nxt_router_conf_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
207115Sigor@sysoev.ru {
208139Sigor@sysoev.ru     size_t                  dump_size;
209139Sigor@sysoev.ru     nxt_buf_t               *b;
210139Sigor@sysoev.ru     nxt_int_t               ret;
211139Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
212139Sigor@sysoev.ru 
213139Sigor@sysoev.ru     b = msg->buf;
214139Sigor@sysoev.ru 
215139Sigor@sysoev.ru     dump_size = nxt_buf_used_size(b);
216139Sigor@sysoev.ru 
217139Sigor@sysoev.ru     if (dump_size > 300) {
218139Sigor@sysoev.ru         dump_size = 300;
21953Sigor@sysoev.ru     }
22053Sigor@sysoev.ru 
221139Sigor@sysoev.ru     nxt_debug(task, "router conf data (%z): %*s",
222139Sigor@sysoev.ru               msg->size, dump_size, b->mem.pos);
223139Sigor@sysoev.ru 
224139Sigor@sysoev.ru     tmcf = nxt_router_temp_conf(task);
225139Sigor@sysoev.ru     if (nxt_slow_path(tmcf == NULL)) {
226139Sigor@sysoev.ru         return;
22753Sigor@sysoev.ru     }
22853Sigor@sysoev.ru 
229139Sigor@sysoev.ru     tmcf->conf->router = nxt_router;
230139Sigor@sysoev.ru     tmcf->stream = msg->port_msg.stream;
231139Sigor@sysoev.ru     tmcf->port = nxt_runtime_port_find(task->thread->runtime,
232139Sigor@sysoev.ru                                        msg->port_msg.pid, 0);
233139Sigor@sysoev.ru 
234139Sigor@sysoev.ru     ret = nxt_router_conf_new(task, tmcf, b->mem.pos, b->mem.free);
235139Sigor@sysoev.ru 
236139Sigor@sysoev.ru     b->mem.pos = b->mem.free;
237139Sigor@sysoev.ru 
238139Sigor@sysoev.ru     if (ret == NXT_OK) {
239139Sigor@sysoev.ru         return nxt_router_conf_success(task, tmcf);
240139Sigor@sysoev.ru     }
241139Sigor@sysoev.ru 
242139Sigor@sysoev.ru     nxt_log(task, NXT_LOG_CRIT, "failed to apply new conf");
243139Sigor@sysoev.ru 
244139Sigor@sysoev.ru     return nxt_router_conf_error(task, tmcf);
24553Sigor@sysoev.ru }
24653Sigor@sysoev.ru 
24753Sigor@sysoev.ru 
24853Sigor@sysoev.ru static nxt_router_temp_conf_t *
249139Sigor@sysoev.ru nxt_router_temp_conf(nxt_task_t *task)
25053Sigor@sysoev.ru {
25165Sigor@sysoev.ru     nxt_mp_t                *mp, *tmp;
25253Sigor@sysoev.ru     nxt_router_conf_t       *rtcf;
25353Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
25453Sigor@sysoev.ru 
25565Sigor@sysoev.ru     mp = nxt_mp_create(1024, 128, 256, 32);
25653Sigor@sysoev.ru     if (nxt_slow_path(mp == NULL)) {
25753Sigor@sysoev.ru         return NULL;
25853Sigor@sysoev.ru     }
25953Sigor@sysoev.ru 
26065Sigor@sysoev.ru     rtcf = nxt_mp_zget(mp, sizeof(nxt_router_conf_t));
26153Sigor@sysoev.ru     if (nxt_slow_path(rtcf == NULL)) {
26253Sigor@sysoev.ru         goto fail;
26353Sigor@sysoev.ru     }
26453Sigor@sysoev.ru 
26553Sigor@sysoev.ru     rtcf->mem_pool = mp;
26653Sigor@sysoev.ru     rtcf->count = 1;
26753Sigor@sysoev.ru 
26865Sigor@sysoev.ru     tmp = nxt_mp_create(1024, 128, 256, 32);
26953Sigor@sysoev.ru     if (nxt_slow_path(tmp == NULL)) {
27053Sigor@sysoev.ru         goto fail;
27153Sigor@sysoev.ru     }
27253Sigor@sysoev.ru 
27365Sigor@sysoev.ru     tmcf = nxt_mp_zget(tmp, sizeof(nxt_router_temp_conf_t));
27453Sigor@sysoev.ru     if (nxt_slow_path(tmcf == NULL)) {
27553Sigor@sysoev.ru         goto temp_fail;
27653Sigor@sysoev.ru     }
27753Sigor@sysoev.ru 
27853Sigor@sysoev.ru     tmcf->mem_pool = tmp;
27953Sigor@sysoev.ru     tmcf->conf = rtcf;
280139Sigor@sysoev.ru     tmcf->count = 1;
281139Sigor@sysoev.ru     tmcf->engine = task->thread->engine;
28253Sigor@sysoev.ru 
28353Sigor@sysoev.ru     tmcf->engines = nxt_array_create(tmcf->mem_pool, 4,
28453Sigor@sysoev.ru                                      sizeof(nxt_router_engine_conf_t));
28553Sigor@sysoev.ru     if (nxt_slow_path(tmcf->engines == NULL)) {
28653Sigor@sysoev.ru         goto temp_fail;
28753Sigor@sysoev.ru     }
28853Sigor@sysoev.ru 
28953Sigor@sysoev.ru     nxt_queue_init(&tmcf->deleting);
29053Sigor@sysoev.ru     nxt_queue_init(&tmcf->keeping);
29153Sigor@sysoev.ru     nxt_queue_init(&tmcf->updating);
29253Sigor@sysoev.ru     nxt_queue_init(&tmcf->pending);
29353Sigor@sysoev.ru     nxt_queue_init(&tmcf->creating);
294133Sigor@sysoev.ru     nxt_queue_init(&tmcf->apps);
295133Sigor@sysoev.ru     nxt_queue_init(&tmcf->previous);
29653Sigor@sysoev.ru 
29753Sigor@sysoev.ru     return tmcf;
29853Sigor@sysoev.ru 
29953Sigor@sysoev.ru temp_fail:
30053Sigor@sysoev.ru 
30165Sigor@sysoev.ru     nxt_mp_destroy(tmp);
30253Sigor@sysoev.ru 
30353Sigor@sysoev.ru fail:
30453Sigor@sysoev.ru 
30565Sigor@sysoev.ru     nxt_mp_destroy(mp);
30653Sigor@sysoev.ru 
30753Sigor@sysoev.ru     return NULL;
30853Sigor@sysoev.ru }
30953Sigor@sysoev.ru 
31053Sigor@sysoev.ru 
311139Sigor@sysoev.ru static nxt_int_t
312139Sigor@sysoev.ru nxt_router_conf_new(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
313139Sigor@sysoev.ru     u_char *start, u_char *end)
314139Sigor@sysoev.ru {
315139Sigor@sysoev.ru     nxt_int_t                    ret;
316139Sigor@sysoev.ru     nxt_router_t                 *router;
317139Sigor@sysoev.ru     nxt_runtime_t                *rt;
318139Sigor@sysoev.ru     const nxt_event_interface_t  *interface;
319139Sigor@sysoev.ru 
320139Sigor@sysoev.ru     ret = nxt_router_conf_create(task, tmcf, start, end);
321139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
322139Sigor@sysoev.ru         return ret;
323139Sigor@sysoev.ru     }
324139Sigor@sysoev.ru 
325139Sigor@sysoev.ru     router = tmcf->conf->router;
326139Sigor@sysoev.ru 
327139Sigor@sysoev.ru     nxt_router_listen_sockets_sort(router, tmcf);
328139Sigor@sysoev.ru 
329139Sigor@sysoev.ru     ret = nxt_router_listen_sockets_stub_create(task, tmcf);
330139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
331139Sigor@sysoev.ru         return ret;
332139Sigor@sysoev.ru     }
333139Sigor@sysoev.ru 
334139Sigor@sysoev.ru     rt = task->thread->runtime;
335139Sigor@sysoev.ru 
336139Sigor@sysoev.ru     interface = nxt_service_get(rt->services, "engine", NULL);
337139Sigor@sysoev.ru 
338139Sigor@sysoev.ru     ret = nxt_router_engines_create(task, router, tmcf, interface);
339139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
340139Sigor@sysoev.ru         return ret;
341139Sigor@sysoev.ru     }
342139Sigor@sysoev.ru 
343139Sigor@sysoev.ru     ret = nxt_router_threads_create(task, rt, tmcf);
344139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
345139Sigor@sysoev.ru         return ret;
346139Sigor@sysoev.ru     }
347139Sigor@sysoev.ru 
348139Sigor@sysoev.ru     nxt_router_apps_sort(router, tmcf);
349139Sigor@sysoev.ru 
350139Sigor@sysoev.ru     nxt_router_engines_post(tmcf);
351139Sigor@sysoev.ru 
352139Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->updating);
353139Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->creating);
354139Sigor@sysoev.ru 
355139Sigor@sysoev.ru     return NXT_OK;
356139Sigor@sysoev.ru }
357139Sigor@sysoev.ru 
358139Sigor@sysoev.ru 
359139Sigor@sysoev.ru static void
360139Sigor@sysoev.ru nxt_router_conf_wait(nxt_task_t *task, void *obj, void *data)
361139Sigor@sysoev.ru {
362139Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
363139Sigor@sysoev.ru 
364139Sigor@sysoev.ru     tmcf = obj;
365139Sigor@sysoev.ru 
366139Sigor@sysoev.ru     nxt_router_conf_success(task, tmcf);
367139Sigor@sysoev.ru }
368139Sigor@sysoev.ru 
369139Sigor@sysoev.ru 
370139Sigor@sysoev.ru static void
371139Sigor@sysoev.ru nxt_router_conf_success(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
372139Sigor@sysoev.ru {
373139Sigor@sysoev.ru     nxt_debug(task, "temp conf count:%D", tmcf->count);
374139Sigor@sysoev.ru 
375139Sigor@sysoev.ru     if (--tmcf->count == 0) {
376139Sigor@sysoev.ru         nxt_router_conf_send(task, tmcf, (u_char *) "OK", 2);
377139Sigor@sysoev.ru     }
378139Sigor@sysoev.ru }
379139Sigor@sysoev.ru 
380139Sigor@sysoev.ru 
381139Sigor@sysoev.ru static void
382139Sigor@sysoev.ru nxt_router_conf_error(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
383139Sigor@sysoev.ru {
384139Sigor@sysoev.ru     nxt_mp_destroy(tmcf->conf->mem_pool);
385139Sigor@sysoev.ru 
386139Sigor@sysoev.ru     nxt_router_conf_send(task, tmcf, (u_char *) "ERROR", 5);
387139Sigor@sysoev.ru }
388139Sigor@sysoev.ru 
389139Sigor@sysoev.ru 
390139Sigor@sysoev.ru static void
391139Sigor@sysoev.ru nxt_router_conf_send(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
392139Sigor@sysoev.ru     u_char *start, size_t size)
393139Sigor@sysoev.ru {
394139Sigor@sysoev.ru     nxt_buf_t  *b;
395139Sigor@sysoev.ru 
396139Sigor@sysoev.ru     b = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0);
397139Sigor@sysoev.ru     if (nxt_slow_path(b == NULL)) {
398139Sigor@sysoev.ru         return;
399139Sigor@sysoev.ru     }
400139Sigor@sysoev.ru 
401140Svbart@nginx.com     b->mem.free = nxt_cpymem(b->mem.free, start, size);
402140Svbart@nginx.com 
403139Sigor@sysoev.ru     b->parent = tmcf->mem_pool;
404139Sigor@sysoev.ru     b->completion_handler = nxt_router_conf_buf_completion;
405139Sigor@sysoev.ru 
406139Sigor@sysoev.ru     nxt_port_socket_write(task, tmcf->port, NXT_PORT_MSG_DATA, -1,
407139Sigor@sysoev.ru                           tmcf->stream, 0, b);
408139Sigor@sysoev.ru }
409139Sigor@sysoev.ru 
410139Sigor@sysoev.ru 
411139Sigor@sysoev.ru static void
412139Sigor@sysoev.ru nxt_router_conf_buf_completion(nxt_task_t *task, void *obj, void *data)
413139Sigor@sysoev.ru {
414139Sigor@sysoev.ru     nxt_mp_t  *mp;
415139Sigor@sysoev.ru 
416139Sigor@sysoev.ru     /* nxt_router_temp_conf_t mem pool. */
417139Sigor@sysoev.ru     mp = data;
418139Sigor@sysoev.ru 
419139Sigor@sysoev.ru     nxt_mp_destroy(mp);
420139Sigor@sysoev.ru }
421139Sigor@sysoev.ru 
422139Sigor@sysoev.ru 
423115Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_conf[] = {
424115Sigor@sysoev.ru     {
425133Sigor@sysoev.ru         nxt_string("listeners_threads"),
426115Sigor@sysoev.ru         NXT_CONF_MAP_INT32,
427115Sigor@sysoev.ru         offsetof(nxt_router_conf_t, threads),
428115Sigor@sysoev.ru     },
429115Sigor@sysoev.ru };
430115Sigor@sysoev.ru 
431115Sigor@sysoev.ru 
432133Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_app_conf[] = {
433115Sigor@sysoev.ru     {
434133Sigor@sysoev.ru         nxt_string("type"),
435115Sigor@sysoev.ru         NXT_CONF_MAP_STR,
436133Sigor@sysoev.ru         offsetof(nxt_router_app_conf_t, type),
437115Sigor@sysoev.ru     },
438115Sigor@sysoev.ru 
439115Sigor@sysoev.ru     {
440133Sigor@sysoev.ru         nxt_string("workers"),
441115Sigor@sysoev.ru         NXT_CONF_MAP_INT32,
442133Sigor@sysoev.ru         offsetof(nxt_router_app_conf_t, workers),
443133Sigor@sysoev.ru     },
444133Sigor@sysoev.ru };
445133Sigor@sysoev.ru 
446133Sigor@sysoev.ru 
447133Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_listener_conf[] = {
448133Sigor@sysoev.ru     {
449133Sigor@sysoev.ru         nxt_string("application"),
450133Sigor@sysoev.ru         NXT_CONF_MAP_STR,
451133Sigor@sysoev.ru         offsetof(nxt_router_listener_conf_t, application),
452115Sigor@sysoev.ru     },
453115Sigor@sysoev.ru };
454115Sigor@sysoev.ru 
455115Sigor@sysoev.ru 
456115Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_http_conf[] = {
457115Sigor@sysoev.ru     {
458115Sigor@sysoev.ru         nxt_string("header_buffer_size"),
459115Sigor@sysoev.ru         NXT_CONF_MAP_SIZE,
460115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, header_buffer_size),
461115Sigor@sysoev.ru     },
462115Sigor@sysoev.ru 
463115Sigor@sysoev.ru     {
464115Sigor@sysoev.ru         nxt_string("large_header_buffer_size"),
465115Sigor@sysoev.ru         NXT_CONF_MAP_SIZE,
466115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, large_header_buffer_size),
467115Sigor@sysoev.ru     },
468115Sigor@sysoev.ru 
469115Sigor@sysoev.ru     {
470115Sigor@sysoev.ru         nxt_string("header_read_timeout"),
471115Sigor@sysoev.ru         NXT_CONF_MAP_MSEC,
472115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, header_read_timeout),
473115Sigor@sysoev.ru     },
474115Sigor@sysoev.ru };
475115Sigor@sysoev.ru 
476115Sigor@sysoev.ru 
47753Sigor@sysoev.ru static nxt_int_t
478115Sigor@sysoev.ru nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
479115Sigor@sysoev.ru     u_char *start, u_char *end)
48053Sigor@sysoev.ru {
481133Sigor@sysoev.ru     u_char                      *p;
482133Sigor@sysoev.ru     size_t                      size;
483115Sigor@sysoev.ru     nxt_mp_t                    *mp;
484115Sigor@sysoev.ru     uint32_t                    next;
485115Sigor@sysoev.ru     nxt_int_t                   ret;
486115Sigor@sysoev.ru     nxt_str_t                   name;
487133Sigor@sysoev.ru     nxt_app_t                   *app, *prev;
488133Sigor@sysoev.ru     nxt_app_type_t              type;
489115Sigor@sysoev.ru     nxt_sockaddr_t              *sa;
490133Sigor@sysoev.ru     nxt_conf_value_t            *conf, *http;
491133Sigor@sysoev.ru     nxt_conf_value_t            *applications, *application;
492133Sigor@sysoev.ru     nxt_conf_value_t            *listeners, *listener;
493115Sigor@sysoev.ru     nxt_socket_conf_t           *skcf;
494133Sigor@sysoev.ru     nxt_router_app_conf_t       apcf;
495115Sigor@sysoev.ru     nxt_router_listener_conf_t  lscf;
496115Sigor@sysoev.ru 
497115Sigor@sysoev.ru     static nxt_str_t  http_path = nxt_string("/http");
498133Sigor@sysoev.ru     static nxt_str_t  applications_path = nxt_string("/applications");
499115Sigor@sysoev.ru     static nxt_str_t  listeners_path = nxt_string("/listeners");
500115Sigor@sysoev.ru 
501115Sigor@sysoev.ru     conf = nxt_conf_json_parse(tmcf->mem_pool, start, end);
502115Sigor@sysoev.ru     if (conf == NULL) {
503115Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "configuration parsing error");
504115Sigor@sysoev.ru         return NXT_ERROR;
505115Sigor@sysoev.ru     }
506115Sigor@sysoev.ru 
507136Svbart@nginx.com     ret = nxt_conf_map_object(conf, nxt_router_conf,
508136Svbart@nginx.com                               nxt_nitems(nxt_router_conf), tmcf->conf);
509115Sigor@sysoev.ru     if (ret != NXT_OK) {
510133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "root map error");
511115Sigor@sysoev.ru         return NXT_ERROR;
512115Sigor@sysoev.ru     }
513115Sigor@sysoev.ru 
514117Sigor@sysoev.ru     if (tmcf->conf->threads == 0) {
515117Sigor@sysoev.ru         tmcf->conf->threads = nxt_ncpu;
516117Sigor@sysoev.ru     }
517117Sigor@sysoev.ru 
518133Sigor@sysoev.ru     applications = nxt_conf_get_path(conf, &applications_path);
519133Sigor@sysoev.ru     if (applications == NULL) {
520133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "no \"applications\" block");
521115Sigor@sysoev.ru         return NXT_ERROR;
522115Sigor@sysoev.ru     }
523115Sigor@sysoev.ru 
524133Sigor@sysoev.ru     next = 0;
525133Sigor@sysoev.ru 
526133Sigor@sysoev.ru     for ( ;; ) {
527133Sigor@sysoev.ru         application = nxt_conf_next_object_member(applications, &name, &next);
528133Sigor@sysoev.ru         if (application == NULL) {
529133Sigor@sysoev.ru             break;
530133Sigor@sysoev.ru         }
531133Sigor@sysoev.ru 
532133Sigor@sysoev.ru         nxt_debug(task, "application \"%V\"", &name);
533133Sigor@sysoev.ru 
534*144Smax.romanov@nginx.com         size = nxt_conf_json_length(application, NULL);
535*144Smax.romanov@nginx.com 
536*144Smax.romanov@nginx.com         app = nxt_malloc(sizeof(nxt_app_t) + name.length + size);
537133Sigor@sysoev.ru         if (app == NULL) {
538133Sigor@sysoev.ru             goto fail;
539133Sigor@sysoev.ru         }
540133Sigor@sysoev.ru 
541*144Smax.romanov@nginx.com         nxt_memzero(app, sizeof(nxt_app_t));
542*144Smax.romanov@nginx.com 
543*144Smax.romanov@nginx.com         app->name.start = nxt_pointer_to(app, sizeof(nxt_app_t));
544*144Smax.romanov@nginx.com         app->conf.start = nxt_pointer_to(app, sizeof(nxt_app_t) + name.length);
545133Sigor@sysoev.ru 
546133Sigor@sysoev.ru         p = nxt_conf_json_print(app->conf.start, application, NULL);
547133Sigor@sysoev.ru         app->conf.length = p - app->conf.start;
548133Sigor@sysoev.ru 
549*144Smax.romanov@nginx.com         nxt_assert(app->conf.length <= size);
550*144Smax.romanov@nginx.com 
551133Sigor@sysoev.ru         nxt_debug(task, "application conf \"%V\"", &app->conf);
552133Sigor@sysoev.ru 
553133Sigor@sysoev.ru         prev = nxt_router_app_find(&tmcf->conf->router->apps, &name);
554133Sigor@sysoev.ru 
555133Sigor@sysoev.ru         if (prev != NULL && nxt_strstr_eq(&app->conf, &prev->conf)) {
556133Sigor@sysoev.ru             nxt_free(app);
557133Sigor@sysoev.ru 
558133Sigor@sysoev.ru             nxt_queue_remove(&prev->link);
559133Sigor@sysoev.ru             nxt_queue_insert_tail(&tmcf->previous, &prev->link);
560133Sigor@sysoev.ru             continue;
561133Sigor@sysoev.ru         }
562133Sigor@sysoev.ru 
563136Svbart@nginx.com         ret = nxt_conf_map_object(application, nxt_router_app_conf,
564136Svbart@nginx.com                                   nxt_nitems(nxt_router_app_conf), &apcf);
565133Sigor@sysoev.ru         if (ret != NXT_OK) {
566133Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "application map error");
567133Sigor@sysoev.ru             goto app_fail;
568133Sigor@sysoev.ru         }
569115Sigor@sysoev.ru 
570133Sigor@sysoev.ru         nxt_debug(task, "application type: %V", &apcf.type);
571133Sigor@sysoev.ru         nxt_debug(task, "application workers: %D", apcf.workers);
572133Sigor@sysoev.ru 
573141Smax.romanov@nginx.com         type = nxt_app_parse_type(&apcf.type);
574141Smax.romanov@nginx.com 
575141Smax.romanov@nginx.com         if (type == NXT_APP_UNKNOWN) {
576141Smax.romanov@nginx.com             nxt_log(task, NXT_LOG_CRIT, "unknown application type: \"%V\"",
577141Smax.romanov@nginx.com                     &apcf.type);
578141Smax.romanov@nginx.com             goto app_fail;
579141Smax.romanov@nginx.com         }
580141Smax.romanov@nginx.com 
581141Smax.romanov@nginx.com         if (nxt_app_modules[type] == NULL) {
582133Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "unsupported application type: \"%V\"",
583133Sigor@sysoev.ru                     &apcf.type);
584133Sigor@sysoev.ru             goto app_fail;
585133Sigor@sysoev.ru         }
586133Sigor@sysoev.ru 
587133Sigor@sysoev.ru         ret = nxt_thread_mutex_create(&app->mutex);
588133Sigor@sysoev.ru         if (ret != NXT_OK) {
589133Sigor@sysoev.ru             goto app_fail;
590133Sigor@sysoev.ru         }
591133Sigor@sysoev.ru 
592141Smax.romanov@nginx.com         nxt_queue_init(&app->ports);
593141Smax.romanov@nginx.com         nxt_queue_init(&app->requests);
594141Smax.romanov@nginx.com 
595*144Smax.romanov@nginx.com         app->name.length = name.length;
596*144Smax.romanov@nginx.com         nxt_memcpy(app->name.start, name.start, name.length);
597*144Smax.romanov@nginx.com 
598133Sigor@sysoev.ru         app->type = type;
599133Sigor@sysoev.ru         app->max_workers = apcf.workers;
600133Sigor@sysoev.ru         app->live = 1;
601141Smax.romanov@nginx.com         app->module = nxt_app_modules[type];
602133Sigor@sysoev.ru 
603133Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->apps, &app->link);
604133Sigor@sysoev.ru     }
605133Sigor@sysoev.ru 
606133Sigor@sysoev.ru     http = nxt_conf_get_path(conf, &http_path);
607133Sigor@sysoev.ru #if 0
608133Sigor@sysoev.ru     if (http == NULL) {
609133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "no \"http\" block");
610133Sigor@sysoev.ru         return NXT_ERROR;
611133Sigor@sysoev.ru     }
612133Sigor@sysoev.ru #endif
613133Sigor@sysoev.ru 
614133Sigor@sysoev.ru     listeners = nxt_conf_get_path(conf, &listeners_path);
615115Sigor@sysoev.ru     if (listeners == NULL) {
616133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "no \"listeners\" block");
617115Sigor@sysoev.ru         return NXT_ERROR;
618115Sigor@sysoev.ru     }
61953Sigor@sysoev.ru 
620133Sigor@sysoev.ru     next = 0;
62153Sigor@sysoev.ru 
622133Sigor@sysoev.ru     mp = tmcf->conf->mem_pool;
623115Sigor@sysoev.ru 
624115Sigor@sysoev.ru     for ( ;; ) {
625115Sigor@sysoev.ru         listener = nxt_conf_next_object_member(listeners, &name, &next);
626115Sigor@sysoev.ru         if (listener == NULL) {
627115Sigor@sysoev.ru             break;
628115Sigor@sysoev.ru         }
62953Sigor@sysoev.ru 
630115Sigor@sysoev.ru         sa = nxt_sockaddr_parse(mp, &name);
631115Sigor@sysoev.ru         if (sa == NULL) {
632115Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "invalid listener \"%V\"", &name);
633133Sigor@sysoev.ru             goto fail;
634115Sigor@sysoev.ru         }
635115Sigor@sysoev.ru 
636115Sigor@sysoev.ru         sa->type = SOCK_STREAM;
637115Sigor@sysoev.ru 
638115Sigor@sysoev.ru         nxt_debug(task, "router listener: \"%*s\"",
639115Sigor@sysoev.ru                   sa->length, nxt_sockaddr_start(sa));
64053Sigor@sysoev.ru 
641115Sigor@sysoev.ru         skcf = nxt_router_socket_conf(task, mp, sa);
642115Sigor@sysoev.ru         if (skcf == NULL) {
643133Sigor@sysoev.ru             goto fail;
644115Sigor@sysoev.ru         }
64553Sigor@sysoev.ru 
646136Svbart@nginx.com         ret = nxt_conf_map_object(listener, nxt_router_listener_conf,
647136Svbart@nginx.com                                   nxt_nitems(nxt_router_listener_conf), &lscf);
648115Sigor@sysoev.ru         if (ret != NXT_OK) {
649115Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "listener map error");
650133Sigor@sysoev.ru             goto fail;
651115Sigor@sysoev.ru         }
65253Sigor@sysoev.ru 
653133Sigor@sysoev.ru         nxt_debug(task, "application: %V", &lscf.application);
654133Sigor@sysoev.ru 
655133Sigor@sysoev.ru         // STUB, default values if http block is not defined.
656133Sigor@sysoev.ru         skcf->header_buffer_size = 2048;
657133Sigor@sysoev.ru         skcf->large_header_buffer_size = 8192;
658133Sigor@sysoev.ru         skcf->header_read_timeout = 5000;
65953Sigor@sysoev.ru 
660133Sigor@sysoev.ru         if (http != NULL) {
661136Svbart@nginx.com             ret = nxt_conf_map_object(http, nxt_router_http_conf,
662136Svbart@nginx.com                                       nxt_nitems(nxt_router_http_conf), skcf);
663133Sigor@sysoev.ru             if (ret != NXT_OK) {
664133Sigor@sysoev.ru                 nxt_log(task, NXT_LOG_CRIT, "http map error");
665133Sigor@sysoev.ru                 goto fail;
666133Sigor@sysoev.ru             }
667115Sigor@sysoev.ru         }
668115Sigor@sysoev.ru 
669115Sigor@sysoev.ru         skcf->listen.handler = nxt_router_conn_init;
670115Sigor@sysoev.ru         skcf->router_conf = tmcf->conf;
671133Sigor@sysoev.ru         skcf->application = nxt_router_listener_application(tmcf,
672133Sigor@sysoev.ru                                                             &lscf.application);
673115Sigor@sysoev.ru 
674115Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->pending, &skcf->link);
675115Sigor@sysoev.ru     }
67653Sigor@sysoev.ru 
67753Sigor@sysoev.ru     return NXT_OK;
678133Sigor@sysoev.ru 
679133Sigor@sysoev.ru app_fail:
680133Sigor@sysoev.ru 
681133Sigor@sysoev.ru     nxt_free(app);
682133Sigor@sysoev.ru 
683133Sigor@sysoev.ru fail:
684133Sigor@sysoev.ru 
685141Smax.romanov@nginx.com     nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) {
686141Smax.romanov@nginx.com 
687141Smax.romanov@nginx.com         nxt_queue_remove(&app->link);
688133Sigor@sysoev.ru         nxt_thread_mutex_destroy(&app->mutex);
689133Sigor@sysoev.ru         nxt_free(app);
690141Smax.romanov@nginx.com 
691141Smax.romanov@nginx.com     } nxt_queue_loop;
692133Sigor@sysoev.ru 
693133Sigor@sysoev.ru     return NXT_ERROR;
694133Sigor@sysoev.ru }
695133Sigor@sysoev.ru 
696133Sigor@sysoev.ru 
697133Sigor@sysoev.ru static nxt_app_t *
698133Sigor@sysoev.ru nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name)
699133Sigor@sysoev.ru {
700141Smax.romanov@nginx.com     nxt_app_t  *app;
701141Smax.romanov@nginx.com 
702141Smax.romanov@nginx.com     nxt_queue_each(app, queue, nxt_app_t, link) {
703133Sigor@sysoev.ru 
704133Sigor@sysoev.ru         if (nxt_strstr_eq(name, &app->name)) {
705133Sigor@sysoev.ru             return app;
706133Sigor@sysoev.ru         }
707141Smax.romanov@nginx.com 
708141Smax.romanov@nginx.com     } nxt_queue_loop;
709133Sigor@sysoev.ru 
710133Sigor@sysoev.ru     return NULL;
711133Sigor@sysoev.ru }
712133Sigor@sysoev.ru 
713133Sigor@sysoev.ru 
714133Sigor@sysoev.ru static nxt_app_t *
715133Sigor@sysoev.ru nxt_router_listener_application(nxt_router_temp_conf_t *tmcf, nxt_str_t *name)
716133Sigor@sysoev.ru {
717133Sigor@sysoev.ru     nxt_app_t  *app;
718133Sigor@sysoev.ru 
719133Sigor@sysoev.ru     app = nxt_router_app_find(&tmcf->apps, name);
720133Sigor@sysoev.ru 
721133Sigor@sysoev.ru     if (app == NULL) {
722134Sigor@sysoev.ru         app = nxt_router_app_find(&tmcf->previous, name);
723133Sigor@sysoev.ru     }
724133Sigor@sysoev.ru 
725133Sigor@sysoev.ru     return app;
72653Sigor@sysoev.ru }
72753Sigor@sysoev.ru 
72853Sigor@sysoev.ru 
72953Sigor@sysoev.ru static nxt_socket_conf_t *
73065Sigor@sysoev.ru nxt_router_socket_conf(nxt_task_t *task, nxt_mp_t *mp, nxt_sockaddr_t *sa)
73153Sigor@sysoev.ru {
73253Sigor@sysoev.ru     nxt_socket_conf_t  *conf;
73353Sigor@sysoev.ru 
73465Sigor@sysoev.ru     conf = nxt_mp_zget(mp, sizeof(nxt_socket_conf_t));
73553Sigor@sysoev.ru     if (nxt_slow_path(conf == NULL)) {
73653Sigor@sysoev.ru         return NULL;
73753Sigor@sysoev.ru     }
73853Sigor@sysoev.ru 
739115Sigor@sysoev.ru     conf->sockaddr = sa;
740115Sigor@sysoev.ru 
74153Sigor@sysoev.ru     conf->listen.sockaddr = sa;
742103Sigor@sysoev.ru     conf->listen.socklen = sa->socklen;
743103Sigor@sysoev.ru     conf->listen.address_length = sa->length;
74453Sigor@sysoev.ru 
74553Sigor@sysoev.ru     conf->listen.socket = -1;
74653Sigor@sysoev.ru     conf->listen.backlog = NXT_LISTEN_BACKLOG;
74753Sigor@sysoev.ru     conf->listen.flags = NXT_NONBLOCK;
74853Sigor@sysoev.ru     conf->listen.read_after_accept = 1;
74953Sigor@sysoev.ru 
75053Sigor@sysoev.ru     return conf;
75153Sigor@sysoev.ru }
75253Sigor@sysoev.ru 
75353Sigor@sysoev.ru 
75453Sigor@sysoev.ru static void
75553Sigor@sysoev.ru nxt_router_listen_sockets_sort(nxt_router_t *router,
75653Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf)
75753Sigor@sysoev.ru {
75853Sigor@sysoev.ru     nxt_queue_link_t   *nqlk, *oqlk, *next;
75953Sigor@sysoev.ru     nxt_socket_conf_t  *nskcf, *oskcf;
76053Sigor@sysoev.ru 
76153Sigor@sysoev.ru     for (nqlk = nxt_queue_first(&tmcf->pending);
76253Sigor@sysoev.ru          nqlk != nxt_queue_tail(&tmcf->pending);
76353Sigor@sysoev.ru          nqlk = next)
76453Sigor@sysoev.ru     {
76553Sigor@sysoev.ru         next = nxt_queue_next(nqlk);
76653Sigor@sysoev.ru         nskcf = nxt_queue_link_data(nqlk, nxt_socket_conf_t, link);
76753Sigor@sysoev.ru 
76853Sigor@sysoev.ru         for (oqlk = nxt_queue_first(&router->sockets);
76953Sigor@sysoev.ru              oqlk != nxt_queue_tail(&router->sockets);
77053Sigor@sysoev.ru              oqlk = nxt_queue_next(oqlk))
77153Sigor@sysoev.ru         {
77253Sigor@sysoev.ru             oskcf = nxt_queue_link_data(oqlk, nxt_socket_conf_t, link);
77353Sigor@sysoev.ru 
774115Sigor@sysoev.ru             if (nxt_sockaddr_cmp(nskcf->sockaddr, oskcf->sockaddr)) {
775115Sigor@sysoev.ru                 nskcf->socket = oskcf->socket;
776115Sigor@sysoev.ru                 nskcf->listen.socket = oskcf->listen.socket;
777115Sigor@sysoev.ru 
77853Sigor@sysoev.ru                 nxt_queue_remove(oqlk);
77953Sigor@sysoev.ru                 nxt_queue_insert_tail(&tmcf->keeping, oqlk);
78053Sigor@sysoev.ru 
78153Sigor@sysoev.ru                 nxt_queue_remove(nqlk);
78253Sigor@sysoev.ru                 nxt_queue_insert_tail(&tmcf->updating, nqlk);
78353Sigor@sysoev.ru 
78453Sigor@sysoev.ru                 break;
78553Sigor@sysoev.ru             }
78653Sigor@sysoev.ru         }
78753Sigor@sysoev.ru     }
78853Sigor@sysoev.ru 
78953Sigor@sysoev.ru     nxt_queue_add(&tmcf->deleting, &router->sockets);
790115Sigor@sysoev.ru     nxt_queue_init(&router->sockets);
79153Sigor@sysoev.ru }
79253Sigor@sysoev.ru 
79353Sigor@sysoev.ru 
79453Sigor@sysoev.ru static nxt_int_t
79553Sigor@sysoev.ru nxt_router_listen_sockets_stub_create(nxt_task_t *task,
79653Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf)
79753Sigor@sysoev.ru {
798115Sigor@sysoev.ru     nxt_int_t            ret;
799115Sigor@sysoev.ru     nxt_socket_t         s;
800115Sigor@sysoev.ru     nxt_queue_link_t     *qlk, *nqlk;
801115Sigor@sysoev.ru     nxt_socket_conf_t    *skcf;
802115Sigor@sysoev.ru     nxt_router_socket_t  *rtsk;
80353Sigor@sysoev.ru 
80453Sigor@sysoev.ru     for (qlk = nxt_queue_first(&tmcf->pending);
80553Sigor@sysoev.ru          qlk != nxt_queue_tail(&tmcf->pending);
80653Sigor@sysoev.ru          qlk = nqlk)
80753Sigor@sysoev.ru     {
808115Sigor@sysoev.ru         rtsk = nxt_malloc(sizeof(nxt_router_socket_t));
809115Sigor@sysoev.ru         if (nxt_slow_path(rtsk == NULL)) {
81053Sigor@sysoev.ru             return NXT_ERROR;
81153Sigor@sysoev.ru         }
81253Sigor@sysoev.ru 
813115Sigor@sysoev.ru         rtsk->count = 0;
814115Sigor@sysoev.ru 
815115Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
816115Sigor@sysoev.ru         skcf->socket = rtsk;
817115Sigor@sysoev.ru 
818115Sigor@sysoev.ru         s = nxt_listen_socket_create0(task, skcf->sockaddr, NXT_NONBLOCK);
819115Sigor@sysoev.ru         if (nxt_slow_path(s == -1)) {
820115Sigor@sysoev.ru             return NXT_ERROR;
821115Sigor@sysoev.ru         }
822115Sigor@sysoev.ru 
823115Sigor@sysoev.ru         ret = nxt_listen_socket(task, s, NXT_LISTEN_BACKLOG);
824115Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
825115Sigor@sysoev.ru             return NXT_ERROR;
826115Sigor@sysoev.ru         }
827115Sigor@sysoev.ru 
828115Sigor@sysoev.ru         skcf->listen.socket = s;
829115Sigor@sysoev.ru 
830115Sigor@sysoev.ru         rtsk->fd = s;
831115Sigor@sysoev.ru 
83253Sigor@sysoev.ru         nqlk = nxt_queue_next(qlk);
83353Sigor@sysoev.ru         nxt_queue_remove(qlk);
83453Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->creating, qlk);
83553Sigor@sysoev.ru     }
83653Sigor@sysoev.ru 
83753Sigor@sysoev.ru     return NXT_OK;
83853Sigor@sysoev.ru }
83953Sigor@sysoev.ru 
84053Sigor@sysoev.ru 
84153Sigor@sysoev.ru static nxt_int_t
84253Sigor@sysoev.ru nxt_router_engines_create(nxt_task_t *task, nxt_router_t *router,
84353Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, const nxt_event_interface_t *interface)
84453Sigor@sysoev.ru {
84553Sigor@sysoev.ru     nxt_int_t                 ret;
84653Sigor@sysoev.ru     nxt_uint_t                n, threads;
84753Sigor@sysoev.ru     nxt_queue_link_t          *qlk;
84853Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
84953Sigor@sysoev.ru 
85053Sigor@sysoev.ru     threads = tmcf->conf->threads;
85153Sigor@sysoev.ru 
85253Sigor@sysoev.ru     tmcf->engines = nxt_array_create(tmcf->mem_pool, threads,
85353Sigor@sysoev.ru                                      sizeof(nxt_router_engine_conf_t));
85453Sigor@sysoev.ru     if (nxt_slow_path(tmcf->engines == NULL)) {
85553Sigor@sysoev.ru         return NXT_ERROR;
85653Sigor@sysoev.ru     }
85753Sigor@sysoev.ru 
85853Sigor@sysoev.ru     n = 0;
85953Sigor@sysoev.ru 
86053Sigor@sysoev.ru     for (qlk = nxt_queue_first(&router->engines);
86153Sigor@sysoev.ru          qlk != nxt_queue_tail(&router->engines);
86253Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
86353Sigor@sysoev.ru     {
86453Sigor@sysoev.ru         recf = nxt_array_zero_add(tmcf->engines);
86553Sigor@sysoev.ru         if (nxt_slow_path(recf == NULL)) {
86653Sigor@sysoev.ru             return NXT_ERROR;
86753Sigor@sysoev.ru         }
86853Sigor@sysoev.ru 
869115Sigor@sysoev.ru         recf->engine = nxt_queue_link_data(qlk, nxt_event_engine_t, link0);
87053Sigor@sysoev.ru 
87153Sigor@sysoev.ru         if (n < threads) {
872115Sigor@sysoev.ru             ret = nxt_router_engine_conf_update(tmcf, recf);
87353Sigor@sysoev.ru 
87453Sigor@sysoev.ru         } else {
875115Sigor@sysoev.ru             ret = nxt_router_engine_conf_delete(tmcf, recf);
87653Sigor@sysoev.ru         }
87753Sigor@sysoev.ru 
87853Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
87953Sigor@sysoev.ru             return ret;
88053Sigor@sysoev.ru         }
88153Sigor@sysoev.ru 
88253Sigor@sysoev.ru         n++;
88353Sigor@sysoev.ru     }
88453Sigor@sysoev.ru 
88553Sigor@sysoev.ru     tmcf->new_threads = n;
88653Sigor@sysoev.ru 
88753Sigor@sysoev.ru     while (n < threads) {
88853Sigor@sysoev.ru         recf = nxt_array_zero_add(tmcf->engines);
88953Sigor@sysoev.ru         if (nxt_slow_path(recf == NULL)) {
89053Sigor@sysoev.ru             return NXT_ERROR;
89153Sigor@sysoev.ru         }
89253Sigor@sysoev.ru 
89353Sigor@sysoev.ru         recf->engine = nxt_event_engine_create(task, interface, NULL, 0, 0);
89453Sigor@sysoev.ru         if (nxt_slow_path(recf->engine == NULL)) {
89553Sigor@sysoev.ru             return NXT_ERROR;
89653Sigor@sysoev.ru         }
89753Sigor@sysoev.ru 
898115Sigor@sysoev.ru         ret = nxt_router_engine_conf_create(tmcf, recf);
89953Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
90053Sigor@sysoev.ru             return ret;
90153Sigor@sysoev.ru         }
90253Sigor@sysoev.ru 
903115Sigor@sysoev.ru         nxt_queue_insert_tail(&router->engines, &recf->engine->link0);
904115Sigor@sysoev.ru 
90553Sigor@sysoev.ru         n++;
90653Sigor@sysoev.ru     }
90753Sigor@sysoev.ru 
90853Sigor@sysoev.ru     return NXT_OK;
90953Sigor@sysoev.ru }
91053Sigor@sysoev.ru 
91153Sigor@sysoev.ru 
91253Sigor@sysoev.ru static nxt_int_t
913115Sigor@sysoev.ru nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf,
914115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
91553Sigor@sysoev.ru {
916115Sigor@sysoev.ru     nxt_mp_t               *mp;
917115Sigor@sysoev.ru     nxt_int_t              ret;
918115Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
91953Sigor@sysoev.ru 
92053Sigor@sysoev.ru     recf->creating = nxt_array_create(tmcf->mem_pool, 4, sizeof(nxt_work_t));
92153Sigor@sysoev.ru     if (nxt_slow_path(recf->creating == NULL)) {
92253Sigor@sysoev.ru         return NXT_ERROR;
92353Sigor@sysoev.ru     }
92453Sigor@sysoev.ru 
925115Sigor@sysoev.ru     mp = tmcf->conf->mem_pool;
926115Sigor@sysoev.ru 
927139Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(mp, tmcf, recf, &tmcf->creating,
928115Sigor@sysoev.ru                             recf->creating, nxt_router_listen_socket_create);
929115Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
930115Sigor@sysoev.ru         return ret;
931115Sigor@sysoev.ru     }
932115Sigor@sysoev.ru 
933139Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(mp, tmcf, recf, &tmcf->updating,
93453Sigor@sysoev.ru                             recf->creating, nxt_router_listen_socket_create);
93553Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
93653Sigor@sysoev.ru         return ret;
93753Sigor@sysoev.ru     }
93853Sigor@sysoev.ru 
939115Sigor@sysoev.ru     lock = &tmcf->conf->router->lock;
940115Sigor@sysoev.ru 
941115Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
942115Sigor@sysoev.ru 
943115Sigor@sysoev.ru     nxt_router_engine_socket_count(&tmcf->creating);
944115Sigor@sysoev.ru     nxt_router_engine_socket_count(&tmcf->updating);
945115Sigor@sysoev.ru 
946115Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
947115Sigor@sysoev.ru 
948115Sigor@sysoev.ru     return ret;
94953Sigor@sysoev.ru }
95053Sigor@sysoev.ru 
95153Sigor@sysoev.ru 
95253Sigor@sysoev.ru static nxt_int_t
953115Sigor@sysoev.ru nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf,
954115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
95553Sigor@sysoev.ru {
956115Sigor@sysoev.ru     nxt_mp_t               *mp;
957115Sigor@sysoev.ru     nxt_int_t              ret;
958115Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
95953Sigor@sysoev.ru 
96053Sigor@sysoev.ru     recf->creating = nxt_array_create(tmcf->mem_pool, 4, sizeof(nxt_work_t));
96153Sigor@sysoev.ru     if (nxt_slow_path(recf->creating == NULL)) {
96253Sigor@sysoev.ru         return NXT_ERROR;
96353Sigor@sysoev.ru     }
96453Sigor@sysoev.ru 
965115Sigor@sysoev.ru     mp = tmcf->conf->mem_pool;
966115Sigor@sysoev.ru 
967139Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(mp, tmcf, recf, &tmcf->creating,
96853Sigor@sysoev.ru                             recf->creating, nxt_router_listen_socket_create);
96953Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
97053Sigor@sysoev.ru         return ret;
97153Sigor@sysoev.ru     }
97253Sigor@sysoev.ru 
97353Sigor@sysoev.ru     recf->updating = nxt_array_create(tmcf->mem_pool, 4, sizeof(nxt_work_t));
97453Sigor@sysoev.ru     if (nxt_slow_path(recf->updating == NULL)) {
97553Sigor@sysoev.ru         return NXT_ERROR;
97653Sigor@sysoev.ru     }
97753Sigor@sysoev.ru 
978139Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(mp, tmcf, recf, &tmcf->updating,
97953Sigor@sysoev.ru                             recf->updating, nxt_router_listen_socket_update);
98053Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
98153Sigor@sysoev.ru         return ret;
98253Sigor@sysoev.ru     }
98353Sigor@sysoev.ru 
98453Sigor@sysoev.ru     recf->deleting = nxt_array_create(tmcf->mem_pool, 4, sizeof(nxt_work_t));
98553Sigor@sysoev.ru     if (nxt_slow_path(recf->deleting == NULL)) {
98653Sigor@sysoev.ru         return NXT_ERROR;
98753Sigor@sysoev.ru     }
98853Sigor@sysoev.ru 
989139Sigor@sysoev.ru     ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting);
990115Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
991115Sigor@sysoev.ru         return ret;
992115Sigor@sysoev.ru     }
993115Sigor@sysoev.ru 
994115Sigor@sysoev.ru     lock = &tmcf->conf->router->lock;
995115Sigor@sysoev.ru 
996115Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
997115Sigor@sysoev.ru 
998115Sigor@sysoev.ru     nxt_router_engine_socket_count(&tmcf->creating);
999115Sigor@sysoev.ru 
1000115Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
1001115Sigor@sysoev.ru 
1002115Sigor@sysoev.ru     return ret;
100353Sigor@sysoev.ru }
100453Sigor@sysoev.ru 
100553Sigor@sysoev.ru 
100653Sigor@sysoev.ru static nxt_int_t
1007115Sigor@sysoev.ru nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf,
1008115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
100953Sigor@sysoev.ru {
101053Sigor@sysoev.ru     nxt_int_t  ret;
101153Sigor@sysoev.ru 
101253Sigor@sysoev.ru     recf->deleting = nxt_array_create(tmcf->mem_pool, 4, sizeof(nxt_work_t));
101353Sigor@sysoev.ru     if (nxt_slow_path(recf->deleting == NULL)) {
101453Sigor@sysoev.ru         return NXT_ERROR;
101553Sigor@sysoev.ru     }
101653Sigor@sysoev.ru 
1017139Sigor@sysoev.ru     ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->updating);
101853Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
101953Sigor@sysoev.ru         return ret;
102053Sigor@sysoev.ru     }
102153Sigor@sysoev.ru 
1022139Sigor@sysoev.ru     return nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting);
102353Sigor@sysoev.ru }
102453Sigor@sysoev.ru 
102553Sigor@sysoev.ru 
102653Sigor@sysoev.ru static nxt_int_t
1027139Sigor@sysoev.ru nxt_router_engine_joints_create(nxt_mp_t *mp, nxt_router_temp_conf_t *tmcf,
1028139Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets, nxt_array_t *array,
102953Sigor@sysoev.ru     nxt_work_handler_t handler)
103053Sigor@sysoev.ru {
1031139Sigor@sysoev.ru     nxt_work_t               *work, *back;
103253