xref: /unit/src/nxt_router.c (revision 53)
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 
8*53Sigor@sysoev.ru #include <nxt_router.h>
920Sigor@sysoev.ru 
1020Sigor@sysoev.ru 
11*53Sigor@sysoev.ru static nxt_router_temp_conf_t *nxt_router_temp_conf(nxt_task_t *task,
12*53Sigor@sysoev.ru     nxt_router_t *router);
13*53Sigor@sysoev.ru static void nxt_router_listen_sockets_sort(nxt_router_t *router,
14*53Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
15*53Sigor@sysoev.ru 
16*53Sigor@sysoev.ru static nxt_int_t nxt_router_stub_conf(nxt_task_t *task,
17*53Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
18*53Sigor@sysoev.ru static nxt_int_t nxt_router_listen_sockets_stub_create(nxt_task_t *task,
19*53Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
20*53Sigor@sysoev.ru static nxt_socket_conf_t *nxt_router_socket_conf(nxt_task_t *task,
21*53Sigor@sysoev.ru     nxt_mem_pool_t *mp, nxt_sockaddr_t *sa);
22*53Sigor@sysoev.ru static nxt_sockaddr_t *nxt_router_listen_sockaddr_stub(nxt_task_t *task,
23*53Sigor@sysoev.ru     nxt_mem_pool_t *mp, uint32_t port);
24*53Sigor@sysoev.ru 
25*53Sigor@sysoev.ru static nxt_int_t nxt_router_engines_create(nxt_task_t *task,
26*53Sigor@sysoev.ru     nxt_router_t *router, nxt_router_temp_conf_t *tmcf,
27*53Sigor@sysoev.ru     const nxt_event_interface_t *interface);
28*53Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_create(nxt_task_t *task,
29*53Sigor@sysoev.ru     nxt_mem_pool_t *mp, nxt_router_temp_conf_t *tmcf,
30*53Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
31*53Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_update(nxt_task_t *task,
32*53Sigor@sysoev.ru     nxt_mem_pool_t *mp, nxt_router_temp_conf_t *tmcf,
33*53Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
34*53Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_delete(nxt_task_t *task,
35*53Sigor@sysoev.ru     nxt_mem_pool_t *mp, nxt_router_temp_conf_t *tmcf,
36*53Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
37*53Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_create(nxt_task_t *task,
38*53Sigor@sysoev.ru     nxt_mem_pool_t *mp, nxt_router_engine_conf_t *recf, nxt_queue_t *sockets,
39*53Sigor@sysoev.ru     nxt_array_t *array, nxt_work_handler_t handler);
40*53Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_delete(nxt_task_t *task,
41*53Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets, nxt_array_t *array);
42*53Sigor@sysoev.ru 
43*53Sigor@sysoev.ru static nxt_int_t nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt,
44*53Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
45*53Sigor@sysoev.ru static nxt_int_t nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt,
46*53Sigor@sysoev.ru     nxt_event_engine_t *engine);
47*53Sigor@sysoev.ru 
48*53Sigor@sysoev.ru static void nxt_router_engines_post(nxt_router_temp_conf_t *tmcf);
49*53Sigor@sysoev.ru static void nxt_router_engine_post(nxt_router_engine_conf_t *recf);
50*53Sigor@sysoev.ru 
51*53Sigor@sysoev.ru static void nxt_router_thread_start(void *data);
52*53Sigor@sysoev.ru static void nxt_router_listen_socket_create(nxt_task_t *task, void *obj,
53*53Sigor@sysoev.ru     void *data);
54*53Sigor@sysoev.ru static void nxt_router_listen_socket_update(nxt_task_t *task, void *obj,
55*53Sigor@sysoev.ru     void *data);
56*53Sigor@sysoev.ru static void nxt_router_listen_socket_delete(nxt_task_t *task, void *obj,
57*53Sigor@sysoev.ru     void *data);
58*53Sigor@sysoev.ru static void nxt_router_listen_socket_close(nxt_task_t *task, void *obj,
59*53Sigor@sysoev.ru     void *data);
60*53Sigor@sysoev.ru static void nxt_router_listen_socket_release(nxt_task_t *task,
61*53Sigor@sysoev.ru     nxt_socket_conf_joint_t *joint);
62*53Sigor@sysoev.ru static void nxt_router_thread_exit_handler(nxt_task_t *task, void *obj,
63*53Sigor@sysoev.ru     void *data);
64*53Sigor@sysoev.ru static void nxt_router_conf_release(nxt_task_t *task,
65*53Sigor@sysoev.ru     nxt_socket_conf_joint_t *joint);
66*53Sigor@sysoev.ru 
67*53Sigor@sysoev.ru static void nxt_router_conn_init(nxt_task_t *task, void *obj, void *data);
68*53Sigor@sysoev.ru static void nxt_router_conn_http_header_parse(nxt_task_t *task, void *obj,
69*53Sigor@sysoev.ru     void *data);
70*53Sigor@sysoev.ru static void nxt_router_conn_close(nxt_task_t *task, void *obj, void *data);
71*53Sigor@sysoev.ru static void nxt_router_conn_free(nxt_task_t *task, void *obj, void *data);
72*53Sigor@sysoev.ru static void nxt_router_conn_error(nxt_task_t *task, void *obj, void *data);
73*53Sigor@sysoev.ru static void nxt_router_conn_timeout(nxt_task_t *task, void *obj, void *data);
74*53Sigor@sysoev.ru static nxt_msec_t nxt_router_conn_timeout_value(nxt_event_conn_t *c,
75*53Sigor@sysoev.ru     uintptr_t data);
7620Sigor@sysoev.ru 
7720Sigor@sysoev.ru 
7820Sigor@sysoev.ru nxt_int_t
7920Sigor@sysoev.ru nxt_router_start(nxt_task_t *task, nxt_runtime_t *rt)
8020Sigor@sysoev.ru {
81*53Sigor@sysoev.ru     nxt_int_t                    ret;
82*53Sigor@sysoev.ru     nxt_router_t                 *router;
83*53Sigor@sysoev.ru     nxt_router_temp_conf_t       *tmcf;
84*53Sigor@sysoev.ru     const nxt_event_interface_t  *interface;
85*53Sigor@sysoev.ru 
86*53Sigor@sysoev.ru     router = nxt_zalloc(sizeof(nxt_router_t));
87*53Sigor@sysoev.ru     if (nxt_slow_path(router == NULL)) {
88*53Sigor@sysoev.ru         return NXT_ERROR;
89*53Sigor@sysoev.ru     }
90*53Sigor@sysoev.ru 
91*53Sigor@sysoev.ru     nxt_queue_init(&router->engines);
92*53Sigor@sysoev.ru     nxt_queue_init(&router->sockets);
93*53Sigor@sysoev.ru 
94*53Sigor@sysoev.ru     /**/
95*53Sigor@sysoev.ru 
96*53Sigor@sysoev.ru     tmcf = nxt_router_temp_conf(task, router);
97*53Sigor@sysoev.ru     if (nxt_slow_path(tmcf == NULL)) {
9820Sigor@sysoev.ru         return NXT_ERROR;
9920Sigor@sysoev.ru     }
10020Sigor@sysoev.ru 
101*53Sigor@sysoev.ru     ret = nxt_router_stub_conf(task, tmcf);
102*53Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
103*53Sigor@sysoev.ru         return ret;
104*53Sigor@sysoev.ru     }
105*53Sigor@sysoev.ru 
106*53Sigor@sysoev.ru     nxt_router_listen_sockets_sort(router, tmcf);
107*53Sigor@sysoev.ru 
108*53Sigor@sysoev.ru     ret = nxt_router_listen_sockets_stub_create(task, tmcf);
109*53Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
110*53Sigor@sysoev.ru         return ret;
111*53Sigor@sysoev.ru     }
112*53Sigor@sysoev.ru 
113*53Sigor@sysoev.ru     interface = nxt_service_get(rt->services, "engine", NULL);
114*53Sigor@sysoev.ru 
115*53Sigor@sysoev.ru     ret = nxt_router_engines_create(task, router, tmcf, interface);
116*53Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
117*53Sigor@sysoev.ru         return ret;
118*53Sigor@sysoev.ru     }
119*53Sigor@sysoev.ru 
120*53Sigor@sysoev.ru     ret = nxt_router_threads_create(task, rt, tmcf);
121*53Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
122*53Sigor@sysoev.ru         return ret;
123*53Sigor@sysoev.ru     }
124*53Sigor@sysoev.ru 
125*53Sigor@sysoev.ru     nxt_router_engines_post(tmcf);
126*53Sigor@sysoev.ru 
127*53Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->updating);
128*53Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->creating);
129*53Sigor@sysoev.ru 
130*53Sigor@sysoev.ru     return NXT_OK;
131*53Sigor@sysoev.ru }
132*53Sigor@sysoev.ru 
133*53Sigor@sysoev.ru 
134*53Sigor@sysoev.ru static nxt_router_temp_conf_t *
135*53Sigor@sysoev.ru nxt_router_temp_conf(nxt_task_t *task, nxt_router_t *router)
136*53Sigor@sysoev.ru {
137*53Sigor@sysoev.ru     nxt_mem_pool_t          *mp, *tmp;
138*53Sigor@sysoev.ru     nxt_router_conf_t       *rtcf;
139*53Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
140*53Sigor@sysoev.ru 
141*53Sigor@sysoev.ru     mp = nxt_mem_pool_create(1024);
142*53Sigor@sysoev.ru     if (nxt_slow_path(mp == NULL)) {
143*53Sigor@sysoev.ru         return NULL;
144*53Sigor@sysoev.ru     }
145*53Sigor@sysoev.ru 
146*53Sigor@sysoev.ru     rtcf = nxt_mem_zalloc(mp, sizeof(nxt_router_conf_t));
147*53Sigor@sysoev.ru     if (nxt_slow_path(rtcf == NULL)) {
148*53Sigor@sysoev.ru         goto fail;
149*53Sigor@sysoev.ru     }
150*53Sigor@sysoev.ru 
151*53Sigor@sysoev.ru     rtcf->mem_pool = mp;
152*53Sigor@sysoev.ru     rtcf->router = router;
153*53Sigor@sysoev.ru     rtcf->count = 1;
154*53Sigor@sysoev.ru 
155*53Sigor@sysoev.ru     tmp = nxt_mem_pool_create(1024);
156*53Sigor@sysoev.ru     if (nxt_slow_path(tmp == NULL)) {
157*53Sigor@sysoev.ru         goto fail;
158*53Sigor@sysoev.ru     }
159*53Sigor@sysoev.ru 
160*53Sigor@sysoev.ru     tmcf = nxt_mem_zalloc(tmp, sizeof(nxt_router_temp_conf_t));
161*53Sigor@sysoev.ru     if (nxt_slow_path(tmcf == NULL)) {
162*53Sigor@sysoev.ru         goto temp_fail;
163*53Sigor@sysoev.ru     }
164*53Sigor@sysoev.ru 
165*53Sigor@sysoev.ru     tmcf->mem_pool = tmp;
166*53Sigor@sysoev.ru     tmcf->conf = rtcf;
167*53Sigor@sysoev.ru 
168*53Sigor@sysoev.ru     tmcf->engines = nxt_array_create(tmcf->mem_pool, 4,
169*53Sigor@sysoev.ru                                      sizeof(nxt_router_engine_conf_t));
170*53Sigor@sysoev.ru     if (nxt_slow_path(tmcf->engines == NULL)) {
171*53Sigor@sysoev.ru         goto temp_fail;
172*53Sigor@sysoev.ru     }
173*53Sigor@sysoev.ru 
174*53Sigor@sysoev.ru     nxt_queue_init(&tmcf->deleting);
175*53Sigor@sysoev.ru     nxt_queue_init(&tmcf->keeping);
176*53Sigor@sysoev.ru     nxt_queue_init(&tmcf->updating);
177*53Sigor@sysoev.ru     nxt_queue_init(&tmcf->pending);
178*53Sigor@sysoev.ru     nxt_queue_init(&tmcf->creating);
179*53Sigor@sysoev.ru 
180*53Sigor@sysoev.ru     return tmcf;
181*53Sigor@sysoev.ru 
182*53Sigor@sysoev.ru temp_fail:
183*53Sigor@sysoev.ru 
184*53Sigor@sysoev.ru     nxt_mem_pool_destroy(tmp);
185*53Sigor@sysoev.ru 
186*53Sigor@sysoev.ru fail:
187*53Sigor@sysoev.ru 
188*53Sigor@sysoev.ru     nxt_mem_pool_destroy(mp);
189*53Sigor@sysoev.ru 
190*53Sigor@sysoev.ru     return NULL;
191*53Sigor@sysoev.ru }
192*53Sigor@sysoev.ru 
193*53Sigor@sysoev.ru 
194*53Sigor@sysoev.ru static nxt_int_t
195*53Sigor@sysoev.ru nxt_router_stub_conf(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
196*53Sigor@sysoev.ru {
197*53Sigor@sysoev.ru     nxt_sockaddr_t     *sa;
198*53Sigor@sysoev.ru     nxt_mem_pool_t     *mp;
199*53Sigor@sysoev.ru     nxt_socket_conf_t  *skcf;
200*53Sigor@sysoev.ru 
201*53Sigor@sysoev.ru     tmcf->conf->threads = 1;
202*53Sigor@sysoev.ru 
203*53Sigor@sysoev.ru     mp = tmcf->conf->mem_pool;
204*53Sigor@sysoev.ru 
205*53Sigor@sysoev.ru     sa = nxt_router_listen_sockaddr_stub(task, mp, 8000);
206*53Sigor@sysoev.ru     skcf = nxt_router_socket_conf(task, mp, sa);
207*53Sigor@sysoev.ru 
208*53Sigor@sysoev.ru     skcf->listen.handler = nxt_router_conn_init;
209*53Sigor@sysoev.ru     skcf->listen.mem_pool_size = nxt_listen_socket_pool_min_size(&skcf->listen)
210*53Sigor@sysoev.ru                         + sizeof(nxt_event_conn_proxy_t)
211*53Sigor@sysoev.ru                         + sizeof(nxt_event_conn_t)
212*53Sigor@sysoev.ru                         + 4 * sizeof(nxt_buf_t);
213*53Sigor@sysoev.ru 
214*53Sigor@sysoev.ru     skcf->header_buffer_size = 2048;
215*53Sigor@sysoev.ru     skcf->large_header_buffer_size = 8192;
216*53Sigor@sysoev.ru     skcf->header_read_timeout = 5000;
217*53Sigor@sysoev.ru 
218*53Sigor@sysoev.ru     nxt_queue_insert_tail(&tmcf->pending, &skcf->link);
219*53Sigor@sysoev.ru 
220*53Sigor@sysoev.ru     sa = nxt_router_listen_sockaddr_stub(task, mp, 8001);
221*53Sigor@sysoev.ru     skcf = nxt_router_socket_conf(task, mp, sa);
222*53Sigor@sysoev.ru 
223*53Sigor@sysoev.ru     skcf->listen.handler = nxt_stream_connection_init;
224*53Sigor@sysoev.ru     skcf->listen.mem_pool_size = nxt_listen_socket_pool_min_size(&skcf->listen)
225*53Sigor@sysoev.ru                         + sizeof(nxt_event_conn_proxy_t)
226*53Sigor@sysoev.ru                         + sizeof(nxt_event_conn_t)
227*53Sigor@sysoev.ru                         + 4 * sizeof(nxt_buf_t);
228*53Sigor@sysoev.ru 
229*53Sigor@sysoev.ru     skcf->header_read_timeout = 5000;
230*53Sigor@sysoev.ru 
231*53Sigor@sysoev.ru     nxt_queue_insert_tail(&tmcf->pending, &skcf->link);
232*53Sigor@sysoev.ru 
233*53Sigor@sysoev.ru     return NXT_OK;
234*53Sigor@sysoev.ru }
235*53Sigor@sysoev.ru 
236*53Sigor@sysoev.ru 
237*53Sigor@sysoev.ru static nxt_socket_conf_t *
238*53Sigor@sysoev.ru nxt_router_socket_conf(nxt_task_t *task, nxt_mem_pool_t *mp, nxt_sockaddr_t *sa)
239*53Sigor@sysoev.ru {
240*53Sigor@sysoev.ru     nxt_socket_conf_t  *conf;
241*53Sigor@sysoev.ru 
242*53Sigor@sysoev.ru     conf = nxt_mem_zalloc(mp, sizeof(nxt_socket_conf_t));
243*53Sigor@sysoev.ru     if (nxt_slow_path(conf == NULL)) {
244*53Sigor@sysoev.ru         return NULL;
245*53Sigor@sysoev.ru     }
246*53Sigor@sysoev.ru 
247*53Sigor@sysoev.ru     conf->listen.sockaddr = sa;
248*53Sigor@sysoev.ru 
249*53Sigor@sysoev.ru     conf->listen.socket = -1;
250*53Sigor@sysoev.ru     conf->listen.backlog = NXT_LISTEN_BACKLOG;
251*53Sigor@sysoev.ru     conf->listen.flags = NXT_NONBLOCK;
252*53Sigor@sysoev.ru     conf->listen.read_after_accept = 1;
253*53Sigor@sysoev.ru 
254*53Sigor@sysoev.ru     return conf;
255*53Sigor@sysoev.ru }
256*53Sigor@sysoev.ru 
257*53Sigor@sysoev.ru 
258*53Sigor@sysoev.ru static nxt_sockaddr_t *
259*53Sigor@sysoev.ru nxt_router_listen_sockaddr_stub(nxt_task_t *task, nxt_mem_pool_t *mp,
260*53Sigor@sysoev.ru     uint32_t port)
261*53Sigor@sysoev.ru {
262*53Sigor@sysoev.ru     nxt_sockaddr_t      *sa;
263*53Sigor@sysoev.ru     struct sockaddr_in  sin;
264*53Sigor@sysoev.ru 
265*53Sigor@sysoev.ru     nxt_memzero(&sin, sizeof(struct sockaddr_in));
266*53Sigor@sysoev.ru 
267*53Sigor@sysoev.ru     sin.sin_family = AF_INET;
268*53Sigor@sysoev.ru     sin.sin_port = htons(port);
269*53Sigor@sysoev.ru 
270*53Sigor@sysoev.ru     sa = nxt_sockaddr_create(mp, (struct sockaddr *) &sin,
271*53Sigor@sysoev.ru                              sizeof(struct sockaddr_in), NXT_INET_ADDR_STR_LEN);
272*53Sigor@sysoev.ru     if (nxt_slow_path(sa == NULL)) {
273*53Sigor@sysoev.ru         return NULL;
274*53Sigor@sysoev.ru     }
275*53Sigor@sysoev.ru 
276*53Sigor@sysoev.ru     sa->type = SOCK_STREAM;
277*53Sigor@sysoev.ru 
278*53Sigor@sysoev.ru     nxt_sockaddr_text(sa);
279*53Sigor@sysoev.ru 
280*53Sigor@sysoev.ru     return sa;
281*53Sigor@sysoev.ru }
282*53Sigor@sysoev.ru 
283*53Sigor@sysoev.ru 
284*53Sigor@sysoev.ru static void
285*53Sigor@sysoev.ru nxt_router_listen_sockets_sort(nxt_router_t *router,
286*53Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf)
287*53Sigor@sysoev.ru {
288*53Sigor@sysoev.ru     nxt_queue_link_t   *nqlk, *oqlk, *next;
289*53Sigor@sysoev.ru     nxt_socket_conf_t  *nskcf, *oskcf;
290*53Sigor@sysoev.ru 
291*53Sigor@sysoev.ru     for (nqlk = nxt_queue_first(&tmcf->pending);
292*53Sigor@sysoev.ru          nqlk != nxt_queue_tail(&tmcf->pending);
293*53Sigor@sysoev.ru          nqlk = next)
294*53Sigor@sysoev.ru     {
295*53Sigor@sysoev.ru         next = nxt_queue_next(nqlk);
296*53Sigor@sysoev.ru         nskcf = nxt_queue_link_data(nqlk, nxt_socket_conf_t, link);
297*53Sigor@sysoev.ru 
298*53Sigor@sysoev.ru         for (oqlk = nxt_queue_first(&router->sockets);
299*53Sigor@sysoev.ru              oqlk != nxt_queue_tail(&router->sockets);
300*53Sigor@sysoev.ru              oqlk = nxt_queue_next(oqlk))
301*53Sigor@sysoev.ru         {
302*53Sigor@sysoev.ru             oskcf = nxt_queue_link_data(oqlk, nxt_socket_conf_t, link);
303*53Sigor@sysoev.ru 
304*53Sigor@sysoev.ru             if (nxt_sockaddr_cmp(nskcf->listen.sockaddr,
305*53Sigor@sysoev.ru                                  oskcf->listen.sockaddr))
306*53Sigor@sysoev.ru             {
307*53Sigor@sysoev.ru                 nxt_queue_remove(oqlk);
308*53Sigor@sysoev.ru                 nxt_queue_insert_tail(&tmcf->keeping, oqlk);
309*53Sigor@sysoev.ru 
310*53Sigor@sysoev.ru                 nxt_queue_remove(nqlk);
311*53Sigor@sysoev.ru                 nxt_queue_insert_tail(&tmcf->updating, nqlk);
312*53Sigor@sysoev.ru 
313*53Sigor@sysoev.ru                 break;
314*53Sigor@sysoev.ru             }
315*53Sigor@sysoev.ru         }
316*53Sigor@sysoev.ru     }
317*53Sigor@sysoev.ru 
318*53Sigor@sysoev.ru     nxt_queue_add(&tmcf->deleting, &router->sockets);
319*53Sigor@sysoev.ru }
320*53Sigor@sysoev.ru 
321*53Sigor@sysoev.ru 
322*53Sigor@sysoev.ru static nxt_int_t
323*53Sigor@sysoev.ru nxt_router_listen_sockets_stub_create(nxt_task_t *task,
324*53Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf)
325*53Sigor@sysoev.ru {
326*53Sigor@sysoev.ru     nxt_queue_link_t   *qlk, *nqlk;
327*53Sigor@sysoev.ru     nxt_socket_conf_t  *skcf;
328*53Sigor@sysoev.ru 
329*53Sigor@sysoev.ru     for (qlk = nxt_queue_first(&tmcf->pending);
330*53Sigor@sysoev.ru          qlk != nxt_queue_tail(&tmcf->pending);
331*53Sigor@sysoev.ru          qlk = nqlk)
332*53Sigor@sysoev.ru     {
333*53Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
334*53Sigor@sysoev.ru 
335*53Sigor@sysoev.ru         if (nxt_listen_socket_create(task, &skcf->listen, 0) != NXT_OK) {
336*53Sigor@sysoev.ru             return NXT_ERROR;
337*53Sigor@sysoev.ru         }
338*53Sigor@sysoev.ru 
339*53Sigor@sysoev.ru         nqlk = nxt_queue_next(qlk);
340*53Sigor@sysoev.ru         nxt_queue_remove(qlk);
341*53Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->creating, qlk);
342*53Sigor@sysoev.ru     }
343*53Sigor@sysoev.ru 
344*53Sigor@sysoev.ru     return NXT_OK;
345*53Sigor@sysoev.ru }
346*53Sigor@sysoev.ru 
347*53Sigor@sysoev.ru 
348*53Sigor@sysoev.ru static nxt_int_t
349*53Sigor@sysoev.ru nxt_router_engines_create(nxt_task_t *task, nxt_router_t *router,
350*53Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, const nxt_event_interface_t *interface)
351*53Sigor@sysoev.ru {
352*53Sigor@sysoev.ru     nxt_int_t                 ret;
353*53Sigor@sysoev.ru     nxt_uint_t                n, threads;
354*53Sigor@sysoev.ru     nxt_mem_pool_t            *mp;
355*53Sigor@sysoev.ru     nxt_queue_link_t          *qlk;
356*53Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
357*53Sigor@sysoev.ru 
358*53Sigor@sysoev.ru     mp = tmcf->conf->mem_pool;
359*53Sigor@sysoev.ru     threads = tmcf->conf->threads;
360*53Sigor@sysoev.ru 
361*53Sigor@sysoev.ru     tmcf->engines = nxt_array_create(tmcf->mem_pool, threads,
362*53Sigor@sysoev.ru                                      sizeof(nxt_router_engine_conf_t));
363*53Sigor@sysoev.ru     if (nxt_slow_path(tmcf->engines == NULL)) {
364*53Sigor@sysoev.ru         return NXT_ERROR;
365*53Sigor@sysoev.ru     }
366*53Sigor@sysoev.ru 
367*53Sigor@sysoev.ru     n = 0;
368*53Sigor@sysoev.ru 
369*53Sigor@sysoev.ru     for (qlk = nxt_queue_first(&router->engines);
370*53Sigor@sysoev.ru          qlk != nxt_queue_tail(&router->engines);
371*53Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
372*53Sigor@sysoev.ru     {
373*53Sigor@sysoev.ru         recf = nxt_array_zero_add(tmcf->engines);
374*53Sigor@sysoev.ru         if (nxt_slow_path(recf == NULL)) {
375*53Sigor@sysoev.ru             return NXT_ERROR;
376*53Sigor@sysoev.ru         }
377*53Sigor@sysoev.ru 
378*53Sigor@sysoev.ru         recf->engine = nxt_queue_link_data(qlk, nxt_event_engine_t, link);
379*53Sigor@sysoev.ru         // STUB
380*53Sigor@sysoev.ru         recf->task = recf->engine->task;
381*53Sigor@sysoev.ru 
382*53Sigor@sysoev.ru         if (n < threads) {
383*53Sigor@sysoev.ru             ret = nxt_router_engine_conf_update(task, mp, tmcf, recf);
384*53Sigor@sysoev.ru 
385*53Sigor@sysoev.ru         } else {
386*53Sigor@sysoev.ru             ret = nxt_router_engine_conf_delete(task, mp, tmcf, recf);
387*53Sigor@sysoev.ru         }
388*53Sigor@sysoev.ru 
389*53Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
390*53Sigor@sysoev.ru             return ret;
391*53Sigor@sysoev.ru         }
392*53Sigor@sysoev.ru 
393*53Sigor@sysoev.ru         n++;
394*53Sigor@sysoev.ru     }
395*53Sigor@sysoev.ru 
396*53Sigor@sysoev.ru     tmcf->new_threads = n;
397*53Sigor@sysoev.ru 
398*53Sigor@sysoev.ru     while (n < threads) {
399*53Sigor@sysoev.ru         recf = nxt_array_zero_add(tmcf->engines);
400*53Sigor@sysoev.ru         if (nxt_slow_path(recf == NULL)) {
401*53Sigor@sysoev.ru             return NXT_ERROR;
402*53Sigor@sysoev.ru         }
403*53Sigor@sysoev.ru 
404*53Sigor@sysoev.ru         recf->engine = nxt_event_engine_create(task, interface, NULL, 0, 0);
405*53Sigor@sysoev.ru         if (nxt_slow_path(recf->engine == NULL)) {
406*53Sigor@sysoev.ru             return NXT_ERROR;
407*53Sigor@sysoev.ru         }
408*53Sigor@sysoev.ru         // STUB
409*53Sigor@sysoev.ru         recf->task = recf->engine->task;
410*53Sigor@sysoev.ru 
411*53Sigor@sysoev.ru         ret = nxt_router_engine_conf_create(task, mp, tmcf, recf);
412*53Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
413*53Sigor@sysoev.ru             return ret;
414*53Sigor@sysoev.ru         }
415*53Sigor@sysoev.ru 
416*53Sigor@sysoev.ru         n++;
417*53Sigor@sysoev.ru     }
418*53Sigor@sysoev.ru 
419*53Sigor@sysoev.ru     return NXT_OK;
420*53Sigor@sysoev.ru }
421*53Sigor@sysoev.ru 
422*53Sigor@sysoev.ru 
423*53Sigor@sysoev.ru static nxt_int_t
424*53Sigor@sysoev.ru nxt_router_engine_conf_create(nxt_task_t *task, nxt_mem_pool_t *mp,
425*53Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_router_engine_conf_t *recf)
426*53Sigor@sysoev.ru {
427*53Sigor@sysoev.ru     nxt_int_t  ret;
428*53Sigor@sysoev.ru 
429*53Sigor@sysoev.ru     recf->creating = nxt_array_create(tmcf->mem_pool, 4, sizeof(nxt_work_t));
430*53Sigor@sysoev.ru     if (nxt_slow_path(recf->creating == NULL)) {
431*53Sigor@sysoev.ru         return NXT_ERROR;
432*53Sigor@sysoev.ru     }
433*53Sigor@sysoev.ru 
434*53Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(task, mp, recf, &tmcf->creating,
435*53Sigor@sysoev.ru                             recf->creating, nxt_router_listen_socket_create);
436*53Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
437*53Sigor@sysoev.ru         return ret;
438*53Sigor@sysoev.ru     }
439*53Sigor@sysoev.ru 
440*53Sigor@sysoev.ru     return nxt_router_engine_joints_create(task, mp, recf, &tmcf->updating,
441*53Sigor@sysoev.ru                             recf->creating, nxt_router_listen_socket_create);
442*53Sigor@sysoev.ru }
443*53Sigor@sysoev.ru 
444*53Sigor@sysoev.ru 
445*53Sigor@sysoev.ru static nxt_int_t
446*53Sigor@sysoev.ru nxt_router_engine_conf_update(nxt_task_t *task, nxt_mem_pool_t *mp,
447*53Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_router_engine_conf_t *recf)
448*53Sigor@sysoev.ru {
449*53Sigor@sysoev.ru     nxt_int_t  ret;
450*53Sigor@sysoev.ru 
451*53Sigor@sysoev.ru     recf->creating = nxt_array_create(tmcf->mem_pool, 4, sizeof(nxt_work_t));
452*53Sigor@sysoev.ru     if (nxt_slow_path(recf->creating == NULL)) {
453*53Sigor@sysoev.ru         return NXT_ERROR;
454*53Sigor@sysoev.ru     }
455*53Sigor@sysoev.ru 
456*53Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(task, mp, recf, &tmcf->creating,
457*53Sigor@sysoev.ru                             recf->creating, nxt_router_listen_socket_create);
458*53Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
459*53Sigor@sysoev.ru         return ret;
460*53Sigor@sysoev.ru     }
461*53Sigor@sysoev.ru 
462*53Sigor@sysoev.ru     recf->updating = nxt_array_create(tmcf->mem_pool, 4, sizeof(nxt_work_t));
463*53Sigor@sysoev.ru     if (nxt_slow_path(recf->updating == NULL)) {
464*53Sigor@sysoev.ru         return NXT_ERROR;
465*53Sigor@sysoev.ru     }
466*53Sigor@sysoev.ru 
467*53Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(task, mp, recf, &tmcf->updating,
468*53Sigor@sysoev.ru                             recf->updating, nxt_router_listen_socket_update);
469*53Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
470*53Sigor@sysoev.ru         return ret;
471*53Sigor@sysoev.ru     }
472*53Sigor@sysoev.ru 
473*53Sigor@sysoev.ru     recf->deleting = nxt_array_create(tmcf->mem_pool, 4, sizeof(nxt_work_t));
474*53Sigor@sysoev.ru     if (nxt_slow_path(recf->deleting == NULL)) {
475*53Sigor@sysoev.ru         return NXT_ERROR;
476*53Sigor@sysoev.ru     }
477*53Sigor@sysoev.ru 
478*53Sigor@sysoev.ru     return nxt_router_engine_joints_delete(task, recf, &tmcf->deleting,
479*53Sigor@sysoev.ru                                            recf->deleting);
480*53Sigor@sysoev.ru }
481*53Sigor@sysoev.ru 
482*53Sigor@sysoev.ru 
483*53Sigor@sysoev.ru static nxt_int_t
484*53Sigor@sysoev.ru nxt_router_engine_conf_delete(nxt_task_t *task, nxt_mem_pool_t *mp,
485*53Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_router_engine_conf_t *recf)
486*53Sigor@sysoev.ru {
487*53Sigor@sysoev.ru     nxt_int_t  ret;
488*53Sigor@sysoev.ru 
489*53Sigor@sysoev.ru     recf->deleting = nxt_array_create(tmcf->mem_pool, 4, sizeof(nxt_work_t));
490*53Sigor@sysoev.ru     if (nxt_slow_path(recf->deleting == NULL)) {
491*53Sigor@sysoev.ru         return NXT_ERROR;
492*53Sigor@sysoev.ru     }
493*53Sigor@sysoev.ru 
494*53Sigor@sysoev.ru     ret = nxt_router_engine_joints_delete(task, recf, &tmcf->updating,
495*53Sigor@sysoev.ru                                           recf->deleting);
496*53Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
497*53Sigor@sysoev.ru         return ret;
498*53Sigor@sysoev.ru     }
499*53Sigor@sysoev.ru 
500*53Sigor@sysoev.ru     return nxt_router_engine_joints_delete(task, recf, &tmcf->deleting,
501*53Sigor@sysoev.ru                                            recf->deleting);
502*53Sigor@sysoev.ru }
503*53Sigor@sysoev.ru 
504*53Sigor@sysoev.ru 
505*53Sigor@sysoev.ru static nxt_int_t
506*53Sigor@sysoev.ru nxt_router_engine_joints_create(nxt_task_t *task, nxt_mem_pool_t *mp,
507*53Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets, nxt_array_t *array,
508*53Sigor@sysoev.ru     nxt_work_handler_t handler)
509*53Sigor@sysoev.ru {
510*53Sigor@sysoev.ru     nxt_work_t               *work;
511*53Sigor@sysoev.ru     nxt_queue_link_t         *qlk;
512*53Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
513*53Sigor@sysoev.ru 
514*53Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
515*53Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
516*53Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
517*53Sigor@sysoev.ru     {
518*53Sigor@sysoev.ru         work = nxt_array_add(array);
519*53Sigor@sysoev.ru         if (nxt_slow_path(work == NULL)) {
520*53Sigor@sysoev.ru             return NXT_ERROR;
521*53Sigor@sysoev.ru         }
522*53Sigor@sysoev.ru 
523*53Sigor@sysoev.ru         work->next = NULL;
524*53Sigor@sysoev.ru         work->handler = handler;
525*53Sigor@sysoev.ru         work->task = &recf->task;
526*53Sigor@sysoev.ru         work->obj = recf->engine;
527*53Sigor@sysoev.ru 
528*53Sigor@sysoev.ru         joint = nxt_mem_alloc(mp, sizeof(nxt_socket_conf_joint_t));
529*53Sigor@sysoev.ru         if (nxt_slow_path(joint == NULL)) {
530*53Sigor@sysoev.ru             return NXT_ERROR;
531*53Sigor@sysoev.ru         }
532*53Sigor@sysoev.ru 
533*53Sigor@sysoev.ru         work->data = joint;
534*53Sigor@sysoev.ru 
535*53Sigor@sysoev.ru         joint->count = 1;
536*53Sigor@sysoev.ru         joint->socket_conf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
537*53Sigor@sysoev.ru     }
538*53Sigor@sysoev.ru 
53920Sigor@sysoev.ru     return NXT_OK;
54020Sigor@sysoev.ru }
54120Sigor@sysoev.ru 
54220Sigor@sysoev.ru 
54320Sigor@sysoev.ru static nxt_int_t
544*53Sigor@sysoev.ru nxt_router_engine_joints_delete(nxt_task_t *task,
545*53Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets, nxt_array_t *array)
54620Sigor@sysoev.ru {
547*53Sigor@sysoev.ru     nxt_work_t        *work;
548*53Sigor@sysoev.ru     nxt_queue_link_t  *qlk;
54920Sigor@sysoev.ru 
550*53Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
551*53Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
552*53Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
553*53Sigor@sysoev.ru     {
554*53Sigor@sysoev.ru         work = nxt_array_add(array);
555*53Sigor@sysoev.ru         if (nxt_slow_path(work == NULL)) {
556*53Sigor@sysoev.ru             return NXT_ERROR;
557*53Sigor@sysoev.ru         }
55820Sigor@sysoev.ru 
559*53Sigor@sysoev.ru         work->next = NULL;
560*53Sigor@sysoev.ru         work->handler = nxt_router_listen_socket_delete;
561*53Sigor@sysoev.ru         work->task = &recf->task;
562*53Sigor@sysoev.ru         work->obj = recf->engine;
563*53Sigor@sysoev.ru         work->data = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
56420Sigor@sysoev.ru     }
56520Sigor@sysoev.ru 
566*53Sigor@sysoev.ru     return NXT_OK;
567*53Sigor@sysoev.ru }
56820Sigor@sysoev.ru 
56920Sigor@sysoev.ru 
570*53Sigor@sysoev.ru static nxt_int_t
571*53Sigor@sysoev.ru nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt,
572*53Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf)
573*53Sigor@sysoev.ru {
574*53Sigor@sysoev.ru     nxt_int_t                 ret;
575*53Sigor@sysoev.ru     nxt_uint_t                i, threads;
576*53Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
57720Sigor@sysoev.ru 
578*53Sigor@sysoev.ru     recf = tmcf->engines->elts;
579*53Sigor@sysoev.ru     threads = tmcf->conf->threads;
58020Sigor@sysoev.ru 
581*53Sigor@sysoev.ru     for (i = tmcf->new_threads; i < threads; i++) {
582*53Sigor@sysoev.ru         ret = nxt_router_thread_create(task, rt, recf[i].engine);
583*53Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
584*53Sigor@sysoev.ru             return ret;
585*53Sigor@sysoev.ru         }
58620Sigor@sysoev.ru     }
58720Sigor@sysoev.ru 
58820Sigor@sysoev.ru     return NXT_OK;
58920Sigor@sysoev.ru }
590*53Sigor@sysoev.ru 
591*53Sigor@sysoev.ru 
592*53Sigor@sysoev.ru static nxt_int_t
593*53Sigor@sysoev.ru nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt,
594*53Sigor@sysoev.ru     nxt_event_engine_t *engine)
595*53Sigor@sysoev.ru {
596*53Sigor@sysoev.ru     nxt_int_t            ret;
597*53Sigor@sysoev.ru     nxt_thread_link_t    *link;
598*53Sigor@sysoev.ru     nxt_thread_handle_t  handle;
599*53Sigor@sysoev.ru 
600*53Sigor@sysoev.ru     link = nxt_zalloc(sizeof(nxt_thread_link_t));
601*53Sigor@sysoev.ru 
602*53Sigor@sysoev.ru     if (nxt_slow_path(link == NULL)) {
603*53Sigor@sysoev.ru         return NXT_ERROR;
604*53Sigor@sysoev.ru     }
605*53Sigor@sysoev.ru 
606*53Sigor@sysoev.ru     link->start = nxt_router_thread_start;
607*53Sigor@sysoev.ru     link->engine = engine;
608*53Sigor@sysoev.ru     link->work.handler = nxt_router_thread_exit_handler;
609*53Sigor@sysoev.ru     link->work.task = task;
610*53Sigor@sysoev.ru     link->work.data = link;
611*53Sigor@sysoev.ru 
612*53Sigor@sysoev.ru     nxt_queue_insert_tail(&rt->engines, &engine->link);
613*53Sigor@sysoev.ru 
614*53Sigor@sysoev.ru     ret = nxt_thread_create(&handle, link);
615*53Sigor@sysoev.ru 
616*53Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
617*53Sigor@sysoev.ru         nxt_queue_remove(&engine->link);
618*53Sigor@sysoev.ru     }
619*53Sigor@sysoev.ru 
620*53Sigor@sysoev.ru     return ret;
621*53Sigor@sysoev.ru }
622*53Sigor@sysoev.ru 
623*53Sigor@sysoev.ru 
624*53Sigor@sysoev.ru static void
625*53Sigor@sysoev.ru nxt_router_engines_post(nxt_router_temp_conf_t *tmcf)
626*53Sigor@sysoev.ru {
627*53Sigor@sysoev.ru     nxt_uint_t                n;
628*53Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
629*53Sigor@sysoev.ru 
630*53Sigor@sysoev.ru     recf = tmcf->engines->elts;
631*53Sigor@sysoev.ru 
632*53Sigor@sysoev.ru     for (n = tmcf->engines->nelts; n != 0; n--) {
633*53Sigor@sysoev.ru         nxt_router_engine_post(recf);
634*53Sigor@sysoev.ru         recf++;
635*53Sigor@sysoev.ru     }
636*53Sigor@sysoev.ru }
637*53Sigor@sysoev.ru 
638*53Sigor@sysoev.ru 
639*53Sigor@sysoev.ru static void
640*53Sigor@sysoev.ru nxt_router_engine_post(nxt_router_engine_conf_t *recf)
641*53Sigor@sysoev.ru {
642*53Sigor@sysoev.ru     nxt_uint_t  n;
643*53Sigor@sysoev.ru     nxt_work_t  *work;
644*53Sigor@sysoev.ru 
645*53Sigor@sysoev.ru     work = recf->creating->elts;
646*53Sigor@sysoev.ru 
647*53Sigor@sysoev.ru     for (n = recf->creating->nelts; n != 0; n--) {
648*53Sigor@sysoev.ru         nxt_event_engine_post(recf->engine, work);
649*53Sigor@sysoev.ru         work++;
650*53Sigor@sysoev.ru     }
651*53Sigor@sysoev.ru }
652*53Sigor@sysoev.ru 
653*53Sigor@sysoev.ru 
654*53Sigor@sysoev.ru static void
655*53Sigor@sysoev.ru nxt_router_thread_start(void *data)
656*53Sigor@sysoev.ru {
657*53Sigor@sysoev.ru     nxt_thread_t        *thread;
658*53Sigor@sysoev.ru     nxt_thread_link_t   *link;
659*53Sigor@sysoev.ru     nxt_event_engine_t  *engine;
660*53Sigor@sysoev.ru 
661*53Sigor@sysoev.ru     link = data;
662*53Sigor@sysoev.ru     engine = link->engine;
663*53Sigor@sysoev.ru 
664*53Sigor@sysoev.ru     thread = nxt_thread();
665*53Sigor@sysoev.ru 
666*53Sigor@sysoev.ru     /* STUB */
667*53Sigor@sysoev.ru     thread->runtime = engine->task.thread->runtime;
668*53Sigor@sysoev.ru 
669*53Sigor@sysoev.ru     engine->task.thread = thread;
670*53Sigor@sysoev.ru     engine->task.log = thread->log;
671*53Sigor@sysoev.ru     thread->engine = engine;
672*53Sigor@sysoev.ru     thread->fiber = &engine->fibers->fiber;
673*53Sigor@sysoev.ru 
674*53Sigor@sysoev.ru     engine->mem_pool = nxt_mem_cache_pool_create(4096, 1024, 1024, 64);
675*53Sigor@sysoev.ru 
676*53Sigor@sysoev.ru     nxt_event_engine_start(engine);
677*53Sigor@sysoev.ru }
678*53Sigor@sysoev.ru 
679*53Sigor@sysoev.ru 
680*53Sigor@sysoev.ru static void
681*53Sigor@sysoev.ru nxt_router_listen_socket_create(nxt_task_t *task, void *obj, void *data)
682*53Sigor@sysoev.ru {
683*53Sigor@sysoev.ru     nxt_listen_event_t       *listen;
684*53Sigor@sysoev.ru     nxt_event_engine_t       *engine;
685*53Sigor@sysoev.ru     nxt_listen_socket_t      *ls;
686*53Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
687*53Sigor@sysoev.ru 
688*53Sigor@sysoev.ru     engine = obj;
689*53Sigor@sysoev.ru     joint = data;
690*53Sigor@sysoev.ru 
691*53Sigor@sysoev.ru     ls = &joint->socket_conf->listen;
692*53Sigor@sysoev.ru 
693*53Sigor@sysoev.ru     listen = nxt_listen_event(task, ls);
694*53Sigor@sysoev.ru     if (nxt_slow_path(listen == NULL)) {
695*53Sigor@sysoev.ru         nxt_router_listen_socket_release(task, joint);
696*53Sigor@sysoev.ru         return;
697*53Sigor@sysoev.ru     }
698*53Sigor@sysoev.ru 
699*53Sigor@sysoev.ru     listen->socket.data = joint;
700*53Sigor@sysoev.ru }
701*53Sigor@sysoev.ru 
702*53Sigor@sysoev.ru 
703*53Sigor@sysoev.ru nxt_inline nxt_listen_event_t *
704*53Sigor@sysoev.ru nxt_router_listen_event(nxt_queue_t *listen_connections,
705*53Sigor@sysoev.ru     nxt_socket_conf_t *skcf)
706*53Sigor@sysoev.ru {
707*53Sigor@sysoev.ru     nxt_socket_t        socket;
708*53Sigor@sysoev.ru     nxt_queue_link_t    *link;
709*53Sigor@sysoev.ru     nxt_listen_event_t  *listen;
710*53Sigor@sysoev.ru 
711*53Sigor@sysoev.ru     socket = skcf->listen.socket;
712*53Sigor@sysoev.ru 
713*53Sigor@sysoev.ru     for (link = nxt_queue_first(listen_connections);
714*53Sigor@sysoev.ru          link != nxt_queue_tail(listen_connections);
715*53Sigor@sysoev.ru          link = nxt_queue_next(link))
716*53Sigor@sysoev.ru     {
717*53Sigor@sysoev.ru         listen = nxt_queue_link_data(link, nxt_listen_event_t, link);
718*53Sigor@sysoev.ru 
719*53Sigor@sysoev.ru         if (socket == listen->socket.fd) {
720*53Sigor@sysoev.ru             return listen;
721*53Sigor@sysoev.ru         }
722*53Sigor@sysoev.ru     }
723*53Sigor@sysoev.ru 
724*53Sigor@sysoev.ru     return NULL;
725*53Sigor@sysoev.ru }
726*53Sigor@sysoev.ru 
727*53Sigor@sysoev.ru 
728*53Sigor@sysoev.ru static void
729*53Sigor@sysoev.ru nxt_router_listen_socket_update(nxt_task_t *task, void *obj, void *data)
730*53Sigor@sysoev.ru {
731*53Sigor@sysoev.ru     nxt_event_engine_t       *engine;
732*53Sigor@sysoev.ru     nxt_listen_event_t       *listen;
733*53Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint, *old;
734*53Sigor@sysoev.ru 
735*53Sigor@sysoev.ru     engine = obj;
736*53Sigor@sysoev.ru     joint = data;
737*53Sigor@sysoev.ru 
738*53Sigor@sysoev.ru     listen = nxt_router_listen_event(&engine->listen_connections,
739*53Sigor@sysoev.ru                                      joint->socket_conf);
740*53Sigor@sysoev.ru 
741*53Sigor@sysoev.ru     old = listen->socket.data;
742*53Sigor@sysoev.ru     listen->socket.data = joint;
743*53Sigor@sysoev.ru 
744*53Sigor@sysoev.ru     nxt_router_conf_release(task, old);
745*53Sigor@sysoev.ru }
746*53Sigor@sysoev.ru 
747*53Sigor@sysoev.ru 
748*53Sigor@sysoev.ru static void
749*53Sigor@sysoev.ru nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, void *data)
750*53Sigor@sysoev.ru {
751*53Sigor@sysoev.ru     nxt_socket_conf_t   *skcf;
752*53Sigor@sysoev.ru     nxt_listen_event_t  *listen;
753*53Sigor@sysoev.ru     nxt_event_engine_t  *engine;
754*53Sigor@sysoev.ru 
755*53Sigor@sysoev.ru     engine = obj;
756*53Sigor@sysoev.ru     skcf = data;
757*53Sigor@sysoev.ru 
758*53Sigor@sysoev.ru     listen = nxt_router_listen_event(&engine->listen_connections, skcf);
759*53Sigor@sysoev.ru 
760*53Sigor@sysoev.ru     nxt_fd_event_delete(engine, &listen->socket);
761*53Sigor@sysoev.ru 
762*53Sigor@sysoev.ru     listen->timer.handler = nxt_router_listen_socket_close;
763*53Sigor@sysoev.ru     listen->timer.work_queue = &engine->fast_work_queue;
764*53Sigor@sysoev.ru 
765*53Sigor@sysoev.ru     nxt_timer_add(engine, &listen->timer, 0);
766*53Sigor@sysoev.ru }
767*53Sigor@sysoev.ru 
768*53Sigor@sysoev.ru 
769*53Sigor@sysoev.ru static void
770*53Sigor@sysoev.ru nxt_router_listen_socket_close(nxt_task_t *task, void *obj, void *data)
771*53Sigor@sysoev.ru {
772*53Sigor@sysoev.ru     nxt_timer_t              *timer;
773*53Sigor@sysoev.ru     nxt_listen_event_t       *listen;
774*53Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
775*53Sigor@sysoev.ru 
776*53Sigor@sysoev.ru     timer = obj;
777*53Sigor@sysoev.ru     listen = nxt_timer_data(timer, nxt_listen_event_t, timer);
778*53Sigor@sysoev.ru     joint = listen->socket.data;
779*53Sigor@sysoev.ru 
780*53Sigor@sysoev.ru     nxt_queue_remove(&listen->link);
781*53Sigor@sysoev.ru     nxt_free(listen);
782*53Sigor@sysoev.ru 
783*53Sigor@sysoev.ru     nxt_router_listen_socket_release(task, joint);
784*53Sigor@sysoev.ru }
785*53Sigor@sysoev.ru 
786*53Sigor@sysoev.ru 
787*53Sigor@sysoev.ru static void
788*53Sigor@sysoev.ru nxt_router_listen_socket_release(nxt_task_t *task,
789*53Sigor@sysoev.ru     nxt_socket_conf_joint_t *joint)
790*53Sigor@sysoev.ru {
791*53Sigor@sysoev.ru     nxt_socket_t           s;
792*53Sigor@sysoev.ru     nxt_listen_socket_t    *ls;
793*53Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
794*53Sigor@sysoev.ru 
795*53Sigor@sysoev.ru     s = -1;
796*53Sigor@sysoev.ru     ls = &joint->socket_conf->listen;
797*53Sigor@sysoev.ru     lock = &joint->socket_conf->router_conf->router->lock;
798*53Sigor@sysoev.ru 
799*53Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
800*53Sigor@sysoev.ru 
801*53Sigor@sysoev.ru     if (--ls->count == 0) {
802*53Sigor@sysoev.ru         s = ls->socket;
803*53Sigor@sysoev.ru         ls->socket = -1;
804*53Sigor@sysoev.ru     }
805*53Sigor@sysoev.ru 
806*53Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
807*53Sigor@sysoev.ru 
808*53Sigor@sysoev.ru     if (s != -1) {
809*53Sigor@sysoev.ru         nxt_socket_close(task, s);
810*53Sigor@sysoev.ru     }
811*53Sigor@sysoev.ru 
812*53Sigor@sysoev.ru     nxt_router_conf_release(task, joint);
813*53Sigor@sysoev.ru }
814*53Sigor@sysoev.ru 
815*53Sigor@sysoev.ru 
816*53Sigor@sysoev.ru static void
817*53Sigor@sysoev.ru nxt_router_conf_release(nxt_task_t *task, nxt_socket_conf_joint_t *joint)
818*53Sigor@sysoev.ru {
819*53Sigor@sysoev.ru     nxt_socket_conf_t      *skcf;
820*53Sigor@sysoev.ru     nxt_router_conf_t      *rtcf;
821*53Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
822*53Sigor@sysoev.ru 
823*53Sigor@sysoev.ru     nxt_debug(task, "conf joint count: %D", joint->count);
824*53Sigor@sysoev.ru 
825*53Sigor@sysoev.ru     if (--joint->count != 0) {
826*53Sigor@sysoev.ru         return;
827*53Sigor@sysoev.ru     }
828*53Sigor@sysoev.ru 
829*53Sigor@sysoev.ru     nxt_queue_remove(&joint->link);
830*53Sigor@sysoev.ru 
831*53Sigor@sysoev.ru     skcf = joint->socket_conf;
832*53Sigor@sysoev.ru     rtcf = skcf->router_conf;
833*53Sigor@sysoev.ru     lock = &rtcf->router->lock;
834*53Sigor@sysoev.ru 
835*53Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
836*53Sigor@sysoev.ru 
837*53Sigor@sysoev.ru     if (--skcf->count != 0) {
838*53Sigor@sysoev.ru         rtcf = NULL;
839*53Sigor@sysoev.ru 
840*53Sigor@sysoev.ru     } else {
841*53Sigor@sysoev.ru         nxt_queue_remove(&skcf->link);
842*53Sigor@sysoev.ru 
843*53Sigor@sysoev.ru         if (--rtcf->count != 0) {
844*53Sigor@sysoev.ru             rtcf = NULL;
845*53Sigor@sysoev.ru         }
846*53Sigor@sysoev.ru     }
847*53Sigor@sysoev.ru 
848*53Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
849*53Sigor@sysoev.ru 
850*53Sigor@sysoev.ru     if (rtcf != NULL) {
851*53Sigor@sysoev.ru         nxt_mem_pool_destroy(rtcf->mem_pool);
852*53Sigor@sysoev.ru     }
853*53Sigor@sysoev.ru 
854*53Sigor@sysoev.ru     if (nxt_queue_is_empty(&joint->engine->joints)) {
855*53Sigor@sysoev.ru         nxt_thread_exit(task->thread);
856*53Sigor@sysoev.ru     }
857*53Sigor@sysoev.ru }
858*53Sigor@sysoev.ru 
859*53Sigor@sysoev.ru 
860*53Sigor@sysoev.ru static void
861*53Sigor@sysoev.ru nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, void *data)
862*53Sigor@sysoev.ru {
863*53Sigor@sysoev.ru     nxt_thread_link_t    *link;
864*53Sigor@sysoev.ru     nxt_event_engine_t   *engine;
865*53Sigor@sysoev.ru     nxt_thread_handle_t  handle;
866*53Sigor@sysoev.ru 
867*53Sigor@sysoev.ru     handle = obj;
868*53Sigor@sysoev.ru     link = data;
869*53Sigor@sysoev.ru 
870*53Sigor@sysoev.ru     nxt_thread_wait(handle);
871*53Sigor@sysoev.ru 
872*53Sigor@sysoev.ru     engine = link->engine;
873*53Sigor@sysoev.ru 
874*53Sigor@sysoev.ru     nxt_queue_remove(&engine->link);
875*53Sigor@sysoev.ru 
876*53Sigor@sysoev.ru     nxt_mem_cache_pool_destroy(engine->mem_pool);
877*53Sigor@sysoev.ru 
878*53Sigor@sysoev.ru     nxt_event_engine_free(engine);
879*53Sigor@sysoev.ru 
880*53Sigor@sysoev.ru     nxt_free(link);
881*53Sigor@sysoev.ru 
882*53Sigor@sysoev.ru     // TODO: free port
883*53Sigor@sysoev.ru }
884*53Sigor@sysoev.ru 
885*53Sigor@sysoev.ru 
886*53Sigor@sysoev.ru static const nxt_event_conn_state_t  nxt_router_conn_read_state
887*53Sigor@sysoev.ru     nxt_aligned(64) =
888*53Sigor@sysoev.ru {
889*53Sigor@sysoev.ru     .ready_handler = nxt_router_conn_http_header_parse,
890*53Sigor@sysoev.ru     .close_handler = nxt_router_conn_close,
891*53Sigor@sysoev.ru     .error_handler = nxt_router_conn_error,
892*53Sigor@sysoev.ru 
893*53Sigor@sysoev.ru     .timer_handler = nxt_router_conn_timeout,
894*53Sigor@sysoev.ru     .timer_value = nxt_router_conn_timeout_value,
895*53Sigor@sysoev.ru     .timer_data = offsetof(nxt_socket_conf_t, header_read_timeout),
896*53Sigor@sysoev.ru };
897*53Sigor@sysoev.ru 
898*53Sigor@sysoev.ru 
899*53Sigor@sysoev.ru static void
900*53Sigor@sysoev.ru nxt_router_conn_init(nxt_task_t *task, void *obj, void *data)
901*53Sigor@sysoev.ru {
902*53Sigor@sysoev.ru     size_t                   size;
903*53Sigor@sysoev.ru     nxt_event_conn_t         *c;
904*53Sigor@sysoev.ru     nxt_event_engine_t       *engine;
905*53Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
906*53Sigor@sysoev.ru 
907*53Sigor@sysoev.ru     c = obj;
908*53Sigor@sysoev.ru     joint = data;
909*53Sigor@sysoev.ru 
910*53Sigor@sysoev.ru     nxt_debug(task, "router conn init");
911*53Sigor@sysoev.ru 
912*53Sigor@sysoev.ru     joint->count++;
913*53Sigor@sysoev.ru 
914*53Sigor@sysoev.ru     size = joint->socket_conf->header_buffer_size;
915*53Sigor@sysoev.ru     c->read = nxt_buf_mem_alloc(c->mem_pool, size, 0);
916*53Sigor@sysoev.ru 
917*53Sigor@sysoev.ru     c->socket.data = NULL;
918*53Sigor@sysoev.ru 
919*53Sigor@sysoev.ru     engine = task->thread->engine;
920*53Sigor@sysoev.ru     c->read_work_queue = &engine->fast_work_queue;
921*53Sigor@sysoev.ru     c->write_work_queue = &engine->fast_work_queue;
922*53Sigor@sysoev.ru 
923*53Sigor@sysoev.ru     c->read_state = &nxt_router_conn_read_state;
924*53Sigor@sysoev.ru 
925*53Sigor@sysoev.ru     nxt_event_conn_read(engine, c);
926*53Sigor@sysoev.ru }
927*53Sigor@sysoev.ru 
928*53Sigor@sysoev.ru 
929*53Sigor@sysoev.ru static const nxt_event_conn_state_t  nxt_router_conn_write_state
930*53Sigor@sysoev.ru     nxt_aligned(64) =
931*53Sigor@sysoev.ru {
932*53Sigor@sysoev.ru     .ready_handler = nxt_router_conn_close,
933*53Sigor@sysoev.ru     .close_handler = nxt_router_conn_close,
934*53Sigor@sysoev.ru     .error_handler = nxt_router_conn_error,
935*53Sigor@sysoev.ru };
936*53Sigor@sysoev.ru 
937*53Sigor@sysoev.ru 
938*53Sigor@sysoev.ru static void
939*53Sigor@sysoev.ru nxt_router_conn_http_header_parse(nxt_task_t *task, void *obj, void *data)
940*53Sigor@sysoev.ru {
941*53Sigor@sysoev.ru     size_t                    size;
942*53Sigor@sysoev.ru     nxt_int_t                 ret;
943*53Sigor@sysoev.ru     nxt_buf_t                 *b;
944*53Sigor@sysoev.ru     nxt_event_conn_t          *c;
945*53Sigor@sysoev.ru     nxt_socket_conf_joint_t   *joint;
946*53Sigor@sysoev.ru     nxt_http_request_parse_t  *rp;
947*53Sigor@sysoev.ru 
948*53Sigor@sysoev.ru     c = obj;
949*53Sigor@sysoev.ru     rp = data;
950*53Sigor@sysoev.ru 
951*53Sigor@sysoev.ru     nxt_debug(task, "router conn http header parse");
952*53Sigor@sysoev.ru 
953*53Sigor@sysoev.ru     if (rp == NULL) {
954*53Sigor@sysoev.ru         rp = nxt_mem_zalloc(c->mem_pool, sizeof(nxt_http_request_parse_t));
955*53Sigor@sysoev.ru         if (nxt_slow_path(rp == NULL)) {
956*53Sigor@sysoev.ru             nxt_router_conn_close(task, c, data);
957*53Sigor@sysoev.ru             return;
958*53Sigor@sysoev.ru         }
959*53Sigor@sysoev.ru 
960*53Sigor@sysoev.ru         c->socket.data = rp;
961*53Sigor@sysoev.ru     }
962*53Sigor@sysoev.ru 
963*53Sigor@sysoev.ru     ret = nxt_http_parse_request(rp, &c->read->mem);
964*53Sigor@sysoev.ru 
965*53Sigor@sysoev.ru     nxt_debug(task, "http parse request: %d", ret);
966*53Sigor@sysoev.ru 
967*53Sigor@sysoev.ru     switch (nxt_expect(NXT_DONE, ret)) {
968*53Sigor@sysoev.ru 
969*53Sigor@sysoev.ru     case NXT_DONE:
970*53Sigor@sysoev.ru         break;
971*53Sigor@sysoev.ru 
972*53Sigor@sysoev.ru     case NXT_ERROR:
973*53Sigor@sysoev.ru         nxt_router_conn_close(task, c, data);
974*53Sigor@sysoev.ru         return;
975*53Sigor@sysoev.ru 
976*53Sigor@sysoev.ru     default:  /* NXT_AGAIN */
977*53Sigor@sysoev.ru 
978*53Sigor@sysoev.ru         if (c->read->mem.free == c->read->mem.end) {
979*53Sigor@sysoev.ru             joint = c->listen->socket.data;
980*53Sigor@sysoev.ru             size = joint->socket_conf->large_header_buffer_size,
981*53Sigor@sysoev.ru 
982*53Sigor@sysoev.ru             b = nxt_buf_mem_alloc(c->mem_pool, size, 0);
983*53Sigor@sysoev.ru             if (nxt_slow_path(b == NULL)) {
984*53Sigor@sysoev.ru                 nxt_router_conn_close(task, c, data);
985*53Sigor@sysoev.ru                 return;
986*53Sigor@sysoev.ru             }
987*53Sigor@sysoev.ru 
988*53Sigor@sysoev.ru             size = c->read->mem.free - c->read->mem.pos;
989*53Sigor@sysoev.ru             nxt_memcpy(b->mem.pos, c->read->mem.pos, size);
990*53Sigor@sysoev.ru 
991*53Sigor@sysoev.ru             b->mem.free += size;
992*53Sigor@sysoev.ru             c->read = b;
993*53Sigor@sysoev.ru         }
994*53Sigor@sysoev.ru 
995*53Sigor@sysoev.ru         nxt_event_conn_read(task->thread->engine, c);
996*53Sigor@sysoev.ru         return;
997*53Sigor@sysoev.ru     }
998*53Sigor@sysoev.ru 
999*53Sigor@sysoev.ru     c->write = c->read;
1000*53Sigor@sysoev.ru     c->write->mem.pos = c->write->mem.start;
1001*53Sigor@sysoev.ru     c->write_state = &nxt_router_conn_write_state;
1002*53Sigor@sysoev.ru 
1003*53Sigor@sysoev.ru     nxt_event_conn_write(task->thread->engine, c);
1004*53Sigor@sysoev.ru }
1005*53Sigor@sysoev.ru 
1006*53Sigor@sysoev.ru 
1007*53Sigor@sysoev.ru static const nxt_event_conn_state_t  nxt_router_conn_close_state
1008*53Sigor@sysoev.ru     nxt_aligned(64) =
1009*53Sigor@sysoev.ru {
1010*53Sigor@sysoev.ru     .ready_handler = nxt_router_conn_free,
1011*53Sigor@sysoev.ru };
1012*53Sigor@sysoev.ru 
1013*53Sigor@sysoev.ru 
1014*53Sigor@sysoev.ru static void
1015*53Sigor@sysoev.ru nxt_router_conn_close(nxt_task_t *task, void *obj, void *data)
1016*53Sigor@sysoev.ru {
1017*53Sigor@sysoev.ru     nxt_event_conn_t  *c;
1018*53Sigor@sysoev.ru 
1019*53Sigor@sysoev.ru     c = obj;
1020*53Sigor@sysoev.ru 
1021*53Sigor@sysoev.ru     nxt_debug(task, "router conn close");
1022*53Sigor@sysoev.ru 
1023*53Sigor@sysoev.ru     c->write_state = &nxt_router_conn_close_state;
1024*53Sigor@sysoev.ru 
1025*53Sigor@sysoev.ru     nxt_event_conn_close(task->thread->engine, c);
1026*53Sigor@sysoev.ru }
1027*53Sigor@sysoev.ru 
1028*53Sigor@sysoev.ru