xref: /unit/src/nxt_unit.c (revision 2749:31f4163987b2)
1743Smax.romanov@nginx.com 
2743Smax.romanov@nginx.com /*
3743Smax.romanov@nginx.com  * Copyright (C) NGINX, Inc.
4743Smax.romanov@nginx.com  */
5743Smax.romanov@nginx.com 
6743Smax.romanov@nginx.com #include "nxt_main.h"
7743Smax.romanov@nginx.com #include "nxt_port_memory_int.h"
81996St.nateldemoura@f5.com #include "nxt_socket_msg.h"
91555Smax.romanov@nginx.com #include "nxt_port_queue.h"
101555Smax.romanov@nginx.com #include "nxt_app_queue.h"
11743Smax.romanov@nginx.com 
12743Smax.romanov@nginx.com #include "nxt_unit.h"
13743Smax.romanov@nginx.com #include "nxt_unit_request.h"
14743Smax.romanov@nginx.com #include "nxt_unit_response.h"
151131Smax.romanov@nginx.com #include "nxt_unit_websocket.h"
161131Smax.romanov@nginx.com 
171131Smax.romanov@nginx.com #include "nxt_websocket.h"
18743Smax.romanov@nginx.com 
19743Smax.romanov@nginx.com #if (NXT_HAVE_MEMFD_CREATE)
20743Smax.romanov@nginx.com #include <linux/memfd.h>
21743Smax.romanov@nginx.com #endif
22743Smax.romanov@nginx.com 
231317Smax.romanov@nginx.com #define NXT_UNIT_MAX_PLAIN_SIZE  1024
241317Smax.romanov@nginx.com #define NXT_UNIT_LOCAL_BUF_SIZE  \
251317Smax.romanov@nginx.com     (NXT_UNIT_MAX_PLAIN_SIZE + sizeof(nxt_port_msg_t))
261317Smax.romanov@nginx.com 
271980Smax.romanov@nginx.com enum {
281980Smax.romanov@nginx.com     NXT_QUIT_NORMAL   = 0,
291980Smax.romanov@nginx.com     NXT_QUIT_GRACEFUL = 1,
301980Smax.romanov@nginx.com };
311980Smax.romanov@nginx.com 
321131Smax.romanov@nginx.com typedef struct nxt_unit_impl_s                  nxt_unit_impl_t;
331131Smax.romanov@nginx.com typedef struct nxt_unit_mmap_s                  nxt_unit_mmap_t;
341131Smax.romanov@nginx.com typedef struct nxt_unit_mmaps_s                 nxt_unit_mmaps_t;
351131Smax.romanov@nginx.com typedef struct nxt_unit_process_s               nxt_unit_process_t;
361131Smax.romanov@nginx.com typedef struct nxt_unit_mmap_buf_s              nxt_unit_mmap_buf_t;
371131Smax.romanov@nginx.com typedef struct nxt_unit_recv_msg_s              nxt_unit_recv_msg_t;
381321Smax.romanov@nginx.com typedef struct nxt_unit_read_buf_s              nxt_unit_read_buf_t;
391131Smax.romanov@nginx.com typedef struct nxt_unit_ctx_impl_s              nxt_unit_ctx_impl_t;
401131Smax.romanov@nginx.com typedef struct nxt_unit_port_impl_s             nxt_unit_port_impl_t;
411131Smax.romanov@nginx.com typedef struct nxt_unit_request_info_impl_s     nxt_unit_request_info_impl_t;
421131Smax.romanov@nginx.com typedef struct nxt_unit_websocket_frame_impl_s  nxt_unit_websocket_frame_impl_t;
43743Smax.romanov@nginx.com 
44743Smax.romanov@nginx.com static nxt_unit_impl_t *nxt_unit_create(nxt_unit_init_t *init);
451175Smax.romanov@nginx.com static int nxt_unit_ctx_init(nxt_unit_impl_t *lib,
46743Smax.romanov@nginx.com     nxt_unit_ctx_impl_t *ctx_impl, void *data);
471547Smax.romanov@nginx.com nxt_inline void nxt_unit_ctx_use(nxt_unit_ctx_t *ctx);
481547Smax.romanov@nginx.com nxt_inline void nxt_unit_ctx_release(nxt_unit_ctx_t *ctx);
491543Smax.romanov@nginx.com nxt_inline void nxt_unit_lib_use(nxt_unit_impl_t *lib);
501543Smax.romanov@nginx.com nxt_inline void nxt_unit_lib_release(nxt_unit_impl_t *lib);
511131Smax.romanov@nginx.com nxt_inline void nxt_unit_mmap_buf_insert(nxt_unit_mmap_buf_t **head,
521131Smax.romanov@nginx.com     nxt_unit_mmap_buf_t *mmap_buf);
531131Smax.romanov@nginx.com nxt_inline void nxt_unit_mmap_buf_insert_tail(nxt_unit_mmap_buf_t **prev,
541131Smax.romanov@nginx.com     nxt_unit_mmap_buf_t *mmap_buf);
551319Smax.romanov@nginx.com nxt_inline void nxt_unit_mmap_buf_unlink(nxt_unit_mmap_buf_t *mmap_buf);
56743Smax.romanov@nginx.com static int nxt_unit_read_env(nxt_unit_port_t *ready_port,
571543Smax.romanov@nginx.com     nxt_unit_port_t *router_port, nxt_unit_port_t *read_port,
582014Smax.romanov@nginx.com     int *shared_port_fd, int *shared_queue_fd,
591980Smax.romanov@nginx.com     int *log_fd, uint32_t *stream, uint32_t *shm_limit,
601980Smax.romanov@nginx.com     uint32_t *request_limit);
611555Smax.romanov@nginx.com static int nxt_unit_ready(nxt_unit_ctx_t *ctx, int ready_fd, uint32_t stream,
621555Smax.romanov@nginx.com     int queue_fd);
631713Smax.romanov@nginx.com static int nxt_unit_process_msg(nxt_unit_ctx_t *ctx, nxt_unit_read_buf_t *rbuf,
641713Smax.romanov@nginx.com     nxt_unit_request_info_t **preq);
651131Smax.romanov@nginx.com static int nxt_unit_process_new_port(nxt_unit_ctx_t *ctx,
661131Smax.romanov@nginx.com     nxt_unit_recv_msg_t *recv_msg);
671666Smax.romanov@nginx.com static int nxt_unit_ctx_ready(nxt_unit_ctx_t *ctx);
681131Smax.romanov@nginx.com static int nxt_unit_process_req_headers(nxt_unit_ctx_t *ctx,
691713Smax.romanov@nginx.com     nxt_unit_recv_msg_t *recv_msg, nxt_unit_request_info_t **preq);
701555Smax.romanov@nginx.com static int nxt_unit_process_req_body(nxt_unit_ctx_t *ctx,
711555Smax.romanov@nginx.com     nxt_unit_recv_msg_t *recv_msg);
721545Smax.romanov@nginx.com static int nxt_unit_request_check_response_port(nxt_unit_request_info_t *req,
731545Smax.romanov@nginx.com     nxt_unit_port_id_t *port_id);
741547Smax.romanov@nginx.com static int nxt_unit_send_req_headers_ack(nxt_unit_request_info_t *req);
751131Smax.romanov@nginx.com static int nxt_unit_process_websocket(nxt_unit_ctx_t *ctx,
761131Smax.romanov@nginx.com     nxt_unit_recv_msg_t *recv_msg);
771321Smax.romanov@nginx.com static int nxt_unit_process_shm_ack(nxt_unit_ctx_t *ctx);
78743Smax.romanov@nginx.com static nxt_unit_request_info_impl_t *nxt_unit_request_info_get(
79743Smax.romanov@nginx.com     nxt_unit_ctx_t *ctx);
80743Smax.romanov@nginx.com static void nxt_unit_request_info_release(nxt_unit_request_info_t *req);
81743Smax.romanov@nginx.com static void nxt_unit_request_info_free(nxt_unit_request_info_impl_t *req);
821131Smax.romanov@nginx.com static nxt_unit_websocket_frame_impl_t *nxt_unit_websocket_frame_get(
831131Smax.romanov@nginx.com     nxt_unit_ctx_t *ctx);
841131Smax.romanov@nginx.com static void nxt_unit_websocket_frame_release(nxt_unit_websocket_frame_t *ws);
851623Smax.romanov@nginx.com static void nxt_unit_websocket_frame_free(nxt_unit_ctx_t *ctx,
861623Smax.romanov@nginx.com     nxt_unit_websocket_frame_impl_t *ws);
87743Smax.romanov@nginx.com static nxt_unit_mmap_buf_t *nxt_unit_mmap_buf_get(nxt_unit_ctx_t *ctx);
88743Smax.romanov@nginx.com static void nxt_unit_mmap_buf_release(nxt_unit_mmap_buf_t *mmap_buf);
891544Smax.romanov@nginx.com static int nxt_unit_mmap_buf_send(nxt_unit_request_info_t *req,
90743Smax.romanov@nginx.com     nxt_unit_mmap_buf_t *mmap_buf, int last);
911131Smax.romanov@nginx.com static void nxt_unit_mmap_buf_free(nxt_unit_mmap_buf_t *mmap_buf);
921317Smax.romanov@nginx.com static void nxt_unit_free_outgoing_buf(nxt_unit_mmap_buf_t *mmap_buf);
931321Smax.romanov@nginx.com static nxt_unit_read_buf_t *nxt_unit_read_buf_get(nxt_unit_ctx_t *ctx);
941321Smax.romanov@nginx.com static nxt_unit_read_buf_t *nxt_unit_read_buf_get_impl(
951321Smax.romanov@nginx.com     nxt_unit_ctx_impl_t *ctx_impl);
961321Smax.romanov@nginx.com static void nxt_unit_read_buf_release(nxt_unit_ctx_t *ctx,
971321Smax.romanov@nginx.com     nxt_unit_read_buf_t *rbuf);
981403Smax.romanov@nginx.com static nxt_unit_mmap_buf_t *nxt_unit_request_preread(
991403Smax.romanov@nginx.com     nxt_unit_request_info_t *req, size_t size);
1001131Smax.romanov@nginx.com static ssize_t nxt_unit_buf_read(nxt_unit_buf_t **b, uint64_t *len, void *dst,
1011131Smax.romanov@nginx.com     size_t size);
102743Smax.romanov@nginx.com static nxt_port_mmap_header_t *nxt_unit_mmap_get(nxt_unit_ctx_t *ctx,
1031544Smax.romanov@nginx.com     nxt_unit_port_t *port, nxt_chunk_id_t *c, int *n, int min_n);
1041544Smax.romanov@nginx.com static int nxt_unit_send_oosm(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port);
1051321Smax.romanov@nginx.com static int nxt_unit_wait_shm_ack(nxt_unit_ctx_t *ctx);
106743Smax.romanov@nginx.com static nxt_unit_mmap_t *nxt_unit_mmap_at(nxt_unit_mmaps_t *mmaps, uint32_t i);
107743Smax.romanov@nginx.com static nxt_port_mmap_header_t *nxt_unit_new_mmap(nxt_unit_ctx_t *ctx,
1081544Smax.romanov@nginx.com     nxt_unit_port_t *port, int n);
1091555Smax.romanov@nginx.com static int nxt_unit_shm_open(nxt_unit_ctx_t *ctx, size_t size);
1101544Smax.romanov@nginx.com static int nxt_unit_send_mmap(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port,
111743Smax.romanov@nginx.com     int fd);
112743Smax.romanov@nginx.com static int nxt_unit_get_outgoing_buf(nxt_unit_ctx_t *ctx,
1131544Smax.romanov@nginx.com     nxt_unit_port_t *port, uint32_t size,
1141321Smax.romanov@nginx.com     uint32_t min_size, nxt_unit_mmap_buf_t *mmap_buf, char *local_buf);
115743Smax.romanov@nginx.com static int nxt_unit_incoming_mmap(nxt_unit_ctx_t *ctx, pid_t pid, int fd);
116743Smax.romanov@nginx.com 
1171667Smax.romanov@nginx.com static void nxt_unit_awake_ctx(nxt_unit_ctx_t *ctx,
1181667Smax.romanov@nginx.com     nxt_unit_ctx_impl_t *ctx_impl);
1192217Sa.colomar@f5.com static int nxt_unit_mmaps_init(nxt_unit_mmaps_t *mmaps);
1201543Smax.romanov@nginx.com nxt_inline void nxt_unit_process_use(nxt_unit_process_t *process);
1211543Smax.romanov@nginx.com nxt_inline void nxt_unit_process_release(nxt_unit_process_t *process);
122743Smax.romanov@nginx.com static void nxt_unit_mmaps_destroy(nxt_unit_mmaps_t *mmaps);
1231546Smax.romanov@nginx.com static int nxt_unit_check_rbuf_mmap(nxt_unit_ctx_t *ctx,
1241546Smax.romanov@nginx.com     nxt_unit_mmaps_t *mmaps, pid_t pid, uint32_t id,
1251546Smax.romanov@nginx.com     nxt_port_mmap_header_t **hdr, nxt_unit_read_buf_t *rbuf);
126743Smax.romanov@nginx.com static int nxt_unit_mmap_read(nxt_unit_ctx_t *ctx,
1271546Smax.romanov@nginx.com     nxt_unit_recv_msg_t *recv_msg, nxt_unit_read_buf_t *rbuf);
1281546Smax.romanov@nginx.com static int nxt_unit_get_mmap(nxt_unit_ctx_t *ctx, pid_t pid, uint32_t id);
1291321Smax.romanov@nginx.com static void nxt_unit_mmap_release(nxt_unit_ctx_t *ctx,
1301321Smax.romanov@nginx.com     nxt_port_mmap_header_t *hdr, void *start, uint32_t size);
1311321Smax.romanov@nginx.com static int nxt_unit_send_shm_ack(nxt_unit_ctx_t *ctx, pid_t pid);
132743Smax.romanov@nginx.com 
1331623Smax.romanov@nginx.com static nxt_unit_process_t *nxt_unit_process_get(nxt_unit_ctx_t *ctx, pid_t pid);
1341543Smax.romanov@nginx.com static nxt_unit_process_t *nxt_unit_process_find(nxt_unit_impl_t *lib,
135743Smax.romanov@nginx.com     pid_t pid, int remove);
136743Smax.romanov@nginx.com static nxt_unit_process_t *nxt_unit_process_pop_first(nxt_unit_impl_t *lib);
1371547Smax.romanov@nginx.com static int nxt_unit_run_once_impl(nxt_unit_ctx_t *ctx);
1381547Smax.romanov@nginx.com static int nxt_unit_read_buf(nxt_unit_ctx_t *ctx, nxt_unit_read_buf_t *rbuf);
1391980Smax.romanov@nginx.com static int nxt_unit_chk_ready(nxt_unit_ctx_t *ctx);
1401547Smax.romanov@nginx.com static int nxt_unit_process_pending_rbuf(nxt_unit_ctx_t *ctx);
1411547Smax.romanov@nginx.com static void nxt_unit_process_ready_req(nxt_unit_ctx_t *ctx);
1421555Smax.romanov@nginx.com nxt_inline int nxt_unit_is_read_queue(nxt_unit_read_buf_t *rbuf);
1431555Smax.romanov@nginx.com nxt_inline int nxt_unit_is_read_socket(nxt_unit_read_buf_t *rbuf);
1441555Smax.romanov@nginx.com nxt_inline int nxt_unit_is_shm_ack(nxt_unit_read_buf_t *rbuf);
1451555Smax.romanov@nginx.com nxt_inline int nxt_unit_is_quit(nxt_unit_read_buf_t *rbuf);
1461547Smax.romanov@nginx.com static int nxt_unit_process_port_msg_impl(nxt_unit_ctx_t *ctx,
1471547Smax.romanov@nginx.com     nxt_unit_port_t *port);
1481543Smax.romanov@nginx.com static void nxt_unit_ctx_free(nxt_unit_ctx_impl_t *ctx_impl);
1491544Smax.romanov@nginx.com static nxt_unit_port_t *nxt_unit_create_port(nxt_unit_ctx_t *ctx);
1501544Smax.romanov@nginx.com 
1511544Smax.romanov@nginx.com static int nxt_unit_send_port(nxt_unit_ctx_t *ctx, nxt_unit_port_t *dst,
1521555Smax.romanov@nginx.com     nxt_unit_port_t *port, int queue_fd);
1531544Smax.romanov@nginx.com 
1541544Smax.romanov@nginx.com nxt_inline void nxt_unit_port_use(nxt_unit_port_t *port);
1551544Smax.romanov@nginx.com nxt_inline void nxt_unit_port_release(nxt_unit_port_t *port);
1561544Smax.romanov@nginx.com static nxt_unit_port_t *nxt_unit_add_port(nxt_unit_ctx_t *ctx,
1571555Smax.romanov@nginx.com     nxt_unit_port_t *port, void *queue);
1581711Smax.romanov@nginx.com static void nxt_unit_process_awaiting_req(nxt_unit_ctx_t *ctx,
1591711Smax.romanov@nginx.com     nxt_queue_t *awaiting_req);
1601980Smax.romanov@nginx.com static void nxt_unit_remove_port(nxt_unit_impl_t *lib, nxt_unit_ctx_t *ctx,
1611543Smax.romanov@nginx.com     nxt_unit_port_id_t *port_id);
1621544Smax.romanov@nginx.com static nxt_unit_port_t *nxt_unit_remove_port_unsafe(nxt_unit_impl_t *lib,
1631544Smax.romanov@nginx.com     nxt_unit_port_id_t *port_id);
1641543Smax.romanov@nginx.com static void nxt_unit_remove_pid(nxt_unit_impl_t *lib, pid_t pid);
1651543Smax.romanov@nginx.com static void nxt_unit_remove_process(nxt_unit_impl_t *lib,
166743Smax.romanov@nginx.com     nxt_unit_process_t *process);
1671980Smax.romanov@nginx.com static void nxt_unit_quit(nxt_unit_ctx_t *ctx, uint8_t quit_param);
1681545Smax.romanov@nginx.com static int nxt_unit_get_port(nxt_unit_ctx_t *ctx, nxt_unit_port_id_t *port_id);
1691543Smax.romanov@nginx.com static ssize_t nxt_unit_port_send(nxt_unit_ctx_t *ctx,
1701544Smax.romanov@nginx.com     nxt_unit_port_t *port, const void *buf, size_t buf_size,
1711996St.nateldemoura@f5.com     const nxt_send_oob_t *oob);
1721543Smax.romanov@nginx.com static ssize_t nxt_unit_sendmsg(nxt_unit_ctx_t *ctx, int fd,
1731996St.nateldemoura@f5.com     const void *buf, size_t buf_size, const nxt_send_oob_t *oob);
1741555Smax.romanov@nginx.com static int nxt_unit_ctx_port_recv(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port,
1751555Smax.romanov@nginx.com     nxt_unit_read_buf_t *rbuf);
1761555Smax.romanov@nginx.com nxt_inline void nxt_unit_rbuf_cpy(nxt_unit_read_buf_t *dst,
1771555Smax.romanov@nginx.com     nxt_unit_read_buf_t *src);
1781555Smax.romanov@nginx.com static int nxt_unit_shared_port_recv(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port,
1791555Smax.romanov@nginx.com     nxt_unit_read_buf_t *rbuf);
1801547Smax.romanov@nginx.com static int nxt_unit_port_recv(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port,
1811547Smax.romanov@nginx.com     nxt_unit_read_buf_t *rbuf);
1821555Smax.romanov@nginx.com static int nxt_unit_port_queue_recv(nxt_unit_port_t *port,
1831555Smax.romanov@nginx.com     nxt_unit_read_buf_t *rbuf);
1841980Smax.romanov@nginx.com static int nxt_unit_app_queue_recv(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port,
1851555Smax.romanov@nginx.com     nxt_unit_read_buf_t *rbuf);
1861556Smax.romanov@nginx.com nxt_inline int nxt_unit_close(int fd);
1871557Smax.romanov@nginx.com static int nxt_unit_fd_blocking(int fd);
188743Smax.romanov@nginx.com 
189743Smax.romanov@nginx.com static int nxt_unit_port_hash_add(nxt_lvlhsh_t *port_hash,
190743Smax.romanov@nginx.com     nxt_unit_port_t *port);
1911544Smax.romanov@nginx.com static nxt_unit_port_t *nxt_unit_port_hash_find(nxt_lvlhsh_t *port_hash,
192743Smax.romanov@nginx.com     nxt_unit_port_id_t *port_id, int remove);
193743Smax.romanov@nginx.com 
1941555Smax.romanov@nginx.com static int nxt_unit_request_hash_add(nxt_unit_ctx_t *ctx,
1951555Smax.romanov@nginx.com     nxt_unit_request_info_t *req);
1961555Smax.romanov@nginx.com static nxt_unit_request_info_t *nxt_unit_request_hash_find(
1971555Smax.romanov@nginx.com     nxt_unit_ctx_t *ctx, uint32_t stream, int remove);
1981131Smax.romanov@nginx.com 
1992256Sa.clayton@nginx.com static char * nxt_unit_snprint_prefix(char *p, char *end, pid_t pid,
2002139Sandrew@digital-domain.net     int level);
2011616Smax.romanov@nginx.com static void *nxt_unit_lvlhsh_alloc(void *data, size_t size);
2021616Smax.romanov@nginx.com static void nxt_unit_lvlhsh_free(void *data, void *p);
2031593Smax.romanov@nginx.com static int nxt_unit_memcasecmp(const void *p1, const void *p2, size_t length);
204743Smax.romanov@nginx.com 
205743Smax.romanov@nginx.com 
206743Smax.romanov@nginx.com struct nxt_unit_mmap_buf_s {
207743Smax.romanov@nginx.com     nxt_unit_buf_t           buf;
208743Smax.romanov@nginx.com 
2091131Smax.romanov@nginx.com     nxt_unit_mmap_buf_t      *next;
2101131Smax.romanov@nginx.com     nxt_unit_mmap_buf_t      **prev;
2111131Smax.romanov@nginx.com 
212743Smax.romanov@nginx.com     nxt_port_mmap_header_t   *hdr;
213743Smax.romanov@nginx.com     nxt_unit_request_info_t  *req;
214743Smax.romanov@nginx.com     nxt_unit_ctx_impl_t      *ctx_impl;
2151317Smax.romanov@nginx.com     char                     *free_ptr;
2161317Smax.romanov@nginx.com     char                     *plain_ptr;
217743Smax.romanov@nginx.com };
218743Smax.romanov@nginx.com 
219743Smax.romanov@nginx.com 
220743Smax.romanov@nginx.com struct nxt_unit_recv_msg_s {
2211131Smax.romanov@nginx.com     uint32_t                 stream;
2221131Smax.romanov@nginx.com     nxt_pid_t                pid;
2231131Smax.romanov@nginx.com     nxt_port_id_t            reply_port;
2241131Smax.romanov@nginx.com 
2251131Smax.romanov@nginx.com     uint8_t                  last;      /* 1 bit */
2261131Smax.romanov@nginx.com     uint8_t                  mmap;      /* 1 bit */
227743Smax.romanov@nginx.com 
228743Smax.romanov@nginx.com     void                     *start;
229743Smax.romanov@nginx.com     uint32_t                 size;
230743Smax.romanov@nginx.com 
2311558Smax.romanov@nginx.com     int                      fd[2];
2321131Smax.romanov@nginx.com 
2331131Smax.romanov@nginx.com     nxt_unit_mmap_buf_t      *incoming_buf;
234743Smax.romanov@nginx.com };
235743Smax.romanov@nginx.com 
236743Smax.romanov@nginx.com 
237743Smax.romanov@nginx.com typedef enum {
238743Smax.romanov@nginx.com     NXT_UNIT_RS_START           = 0,
239743Smax.romanov@nginx.com     NXT_UNIT_RS_RESPONSE_INIT,
240743Smax.romanov@nginx.com     NXT_UNIT_RS_RESPONSE_HAS_CONTENT,
241743Smax.romanov@nginx.com     NXT_UNIT_RS_RESPONSE_SENT,
2421131Smax.romanov@nginx.com     NXT_UNIT_RS_RELEASED,
243743Smax.romanov@nginx.com } nxt_unit_req_state_t;
244743Smax.romanov@nginx.com 
245743Smax.romanov@nginx.com 
246743Smax.romanov@nginx.com struct nxt_unit_request_info_impl_s {
247743Smax.romanov@nginx.com     nxt_unit_request_info_t  req;
248743Smax.romanov@nginx.com 
2491131Smax.romanov@nginx.com     uint32_t                 stream;
2501131Smax.romanov@nginx.com 
2511131Smax.romanov@nginx.com     nxt_unit_mmap_buf_t      *outgoing_buf;
2521131Smax.romanov@nginx.com     nxt_unit_mmap_buf_t      *incoming_buf;
253743Smax.romanov@nginx.com 
254743Smax.romanov@nginx.com     nxt_unit_req_state_t     state;
2551131Smax.romanov@nginx.com     uint8_t                  websocket;
2561555Smax.romanov@nginx.com     uint8_t                  in_hash;
257743Smax.romanov@nginx.com 
2581545Smax.romanov@nginx.com     /*  for nxt_unit_ctx_impl_t.free_req or active_req */
259743Smax.romanov@nginx.com     nxt_queue_link_t         link;
2601545Smax.romanov@nginx.com     /*  for nxt_unit_port_impl_t.awaiting_req */
2611545Smax.romanov@nginx.com     nxt_queue_link_t         port_wait_link;
262743Smax.romanov@nginx.com 
263743Smax.romanov@nginx.com     char                     extra_data[];
264743Smax.romanov@nginx.com };
265743Smax.romanov@nginx.com 
266743Smax.romanov@nginx.com 
2671131Smax.romanov@nginx.com struct nxt_unit_websocket_frame_impl_s {
2681131Smax.romanov@nginx.com     nxt_unit_websocket_frame_t  ws;
2691131Smax.romanov@nginx.com 
2701131Smax.romanov@nginx.com     nxt_unit_mmap_buf_t         *buf;
2711131Smax.romanov@nginx.com 
2721131Smax.romanov@nginx.com     nxt_queue_link_t            link;
2731131Smax.romanov@nginx.com 
2741131Smax.romanov@nginx.com     nxt_unit_ctx_impl_t         *ctx_impl;
2751131Smax.romanov@nginx.com };
2761131Smax.romanov@nginx.com 
2771131Smax.romanov@nginx.com 
2781321Smax.romanov@nginx.com struct nxt_unit_read_buf_s {
2791546Smax.romanov@nginx.com     nxt_queue_link_t              link;
2801546Smax.romanov@nginx.com     nxt_unit_ctx_impl_t           *ctx_impl;
2811321Smax.romanov@nginx.com     ssize_t                       size;
2821996St.nateldemoura@f5.com     nxt_recv_oob_t                oob;
2831321Smax.romanov@nginx.com     char                          buf[16384];
2841321Smax.romanov@nginx.com };
2851321Smax.romanov@nginx.com 
2861321Smax.romanov@nginx.com 
287743Smax.romanov@nginx.com struct nxt_unit_ctx_impl_s {
288743Smax.romanov@nginx.com     nxt_unit_ctx_t                ctx;
289743Smax.romanov@nginx.com 
2901543Smax.romanov@nginx.com     nxt_atomic_t                  use_count;
2911545Smax.romanov@nginx.com     nxt_atomic_t                  wait_items;
2921543Smax.romanov@nginx.com 
2931175Smax.romanov@nginx.com     pthread_mutex_t               mutex;
2941175Smax.romanov@nginx.com 
2951544Smax.romanov@nginx.com     nxt_unit_port_t               *read_port;
296743Smax.romanov@nginx.com 
297743Smax.romanov@nginx.com     nxt_queue_link_t              link;
298743Smax.romanov@nginx.com 
2991131Smax.romanov@nginx.com     nxt_unit_mmap_buf_t           *free_buf;
300743Smax.romanov@nginx.com 
301743Smax.romanov@nginx.com     /*  of nxt_unit_request_info_impl_t */
302743Smax.romanov@nginx.com     nxt_queue_t                   free_req;
303743Smax.romanov@nginx.com 
3041131Smax.romanov@nginx.com     /*  of nxt_unit_websocket_frame_impl_t */
3051131Smax.romanov@nginx.com     nxt_queue_t                   free_ws;
3061131Smax.romanov@nginx.com 
307743Smax.romanov@nginx.com     /*  of nxt_unit_request_info_impl_t */
308743Smax.romanov@nginx.com     nxt_queue_t                   active_req;
309743Smax.romanov@nginx.com 
3101131Smax.romanov@nginx.com     /*  of nxt_unit_request_info_impl_t */
3111131Smax.romanov@nginx.com     nxt_lvlhsh_t                  requests;
3121131Smax.romanov@nginx.com 
3131545Smax.romanov@nginx.com     /*  of nxt_unit_request_info_impl_t */
3141545Smax.romanov@nginx.com     nxt_queue_t                   ready_req;
3151545Smax.romanov@nginx.com 
3161546Smax.romanov@nginx.com     /*  of nxt_unit_read_buf_t */
3171546Smax.romanov@nginx.com     nxt_queue_t                   pending_rbuf;
3181546Smax.romanov@nginx.com 
3191546Smax.romanov@nginx.com     /*  of nxt_unit_read_buf_t */
3201546Smax.romanov@nginx.com     nxt_queue_t                   free_rbuf;
3211321Smax.romanov@nginx.com 
3221980Smax.romanov@nginx.com     uint8_t                       online;       /* 1 bit */
3231980Smax.romanov@nginx.com     uint8_t                       ready;        /* 1 bit */
3241980Smax.romanov@nginx.com     uint8_t                       quit_param;
3251663Smax.romanov@nginx.com 
326743Smax.romanov@nginx.com     nxt_unit_mmap_buf_t           ctx_buf[2];
3271321Smax.romanov@nginx.com     nxt_unit_read_buf_t           ctx_read_buf;
328743Smax.romanov@nginx.com 
329743Smax.romanov@nginx.com     nxt_unit_request_info_impl_t  req;
330743Smax.romanov@nginx.com };
331743Smax.romanov@nginx.com 
332743Smax.romanov@nginx.com 
3331548Smax.romanov@nginx.com struct nxt_unit_mmap_s {
3341548Smax.romanov@nginx.com     nxt_port_mmap_header_t   *hdr;
3351659Smax.romanov@nginx.com     pthread_t                src_thread;
3361548Smax.romanov@nginx.com 
3371548Smax.romanov@nginx.com     /*  of nxt_unit_read_buf_t */
3381548Smax.romanov@nginx.com     nxt_queue_t              awaiting_rbuf;
3391548Smax.romanov@nginx.com };
3401548Smax.romanov@nginx.com 
3411548Smax.romanov@nginx.com 
3421548Smax.romanov@nginx.com struct nxt_unit_mmaps_s {
3431548Smax.romanov@nginx.com     pthread_mutex_t          mutex;
3441548Smax.romanov@nginx.com     uint32_t                 size;
3451548Smax.romanov@nginx.com     uint32_t                 cap;
3461548Smax.romanov@nginx.com     nxt_atomic_t             allocated_chunks;
3471548Smax.romanov@nginx.com     nxt_unit_mmap_t          *elts;
3481548Smax.romanov@nginx.com };
3491548Smax.romanov@nginx.com 
3501548Smax.romanov@nginx.com 
351743Smax.romanov@nginx.com struct nxt_unit_impl_s {
352743Smax.romanov@nginx.com     nxt_unit_t               unit;
353743Smax.romanov@nginx.com     nxt_unit_callbacks_t     callbacks;
354743Smax.romanov@nginx.com 
3551543Smax.romanov@nginx.com     nxt_atomic_t             use_count;
3561980Smax.romanov@nginx.com     nxt_atomic_t             request_count;
3571543Smax.romanov@nginx.com 
358743Smax.romanov@nginx.com     uint32_t                 request_data_size;
3591320Smax.romanov@nginx.com     uint32_t                 shm_mmap_limit;
3601980Smax.romanov@nginx.com     uint32_t                 request_limit;
361743Smax.romanov@nginx.com 
362743Smax.romanov@nginx.com     pthread_mutex_t          mutex;
363743Smax.romanov@nginx.com 
364743Smax.romanov@nginx.com     nxt_lvlhsh_t             processes;        /* of nxt_unit_process_t */
365743Smax.romanov@nginx.com     nxt_lvlhsh_t             ports;            /* of nxt_unit_port_impl_t */
366743Smax.romanov@nginx.com 
3671544Smax.romanov@nginx.com     nxt_unit_port_t          *router_port;
3681547Smax.romanov@nginx.com     nxt_unit_port_t          *shared_port;
369743Smax.romanov@nginx.com 
370743Smax.romanov@nginx.com     nxt_queue_t              contexts;         /* of nxt_unit_ctx_impl_t */
371743Smax.romanov@nginx.com 
3721548Smax.romanov@nginx.com     nxt_unit_mmaps_t         incoming;
3731548Smax.romanov@nginx.com     nxt_unit_mmaps_t         outgoing;
3741548Smax.romanov@nginx.com 
375743Smax.romanov@nginx.com     pid_t                    pid;
376743Smax.romanov@nginx.com     int                      log_fd;
377743Smax.romanov@nginx.com 
378743Smax.romanov@nginx.com     nxt_unit_ctx_impl_t      main_ctx;
379743Smax.romanov@nginx.com };
380743Smax.romanov@nginx.com 
381743Smax.romanov@nginx.com 
382743Smax.romanov@nginx.com struct nxt_unit_port_impl_s {
383743Smax.romanov@nginx.com     nxt_unit_port_t          port;
384743Smax.romanov@nginx.com 
3851544Smax.romanov@nginx.com     nxt_atomic_t             use_count;
3861544Smax.romanov@nginx.com 
3871546Smax.romanov@nginx.com     /*  for nxt_unit_process_t.ports */
388743Smax.romanov@nginx.com     nxt_queue_link_t         link;
389743Smax.romanov@nginx.com     nxt_unit_process_t       *process;
3901545Smax.romanov@nginx.com 
3911545Smax.romanov@nginx.com     /*  of nxt_unit_request_info_impl_t */
3921545Smax.romanov@nginx.com     nxt_queue_t              awaiting_req;
3931545Smax.romanov@nginx.com 
3941545Smax.romanov@nginx.com     int                      ready;
3951555Smax.romanov@nginx.com 
3961555Smax.romanov@nginx.com     void                     *queue;
3971555Smax.romanov@nginx.com 
3981555Smax.romanov@nginx.com     int                      from_socket;
3991555Smax.romanov@nginx.com     nxt_unit_read_buf_t      *socket_rbuf;
400743Smax.romanov@nginx.com };
401743Smax.romanov@nginx.com 
402743Smax.romanov@nginx.com 
403743Smax.romanov@nginx.com struct nxt_unit_process_s {
404743Smax.romanov@nginx.com     pid_t                    pid;
405743Smax.romanov@nginx.com 
4061546Smax.romanov@nginx.com     nxt_queue_t              ports;            /* of nxt_unit_port_impl_t */
407743Smax.romanov@nginx.com 
408743Smax.romanov@nginx.com     nxt_unit_impl_t          *lib;
409743Smax.romanov@nginx.com 
410743Smax.romanov@nginx.com     nxt_atomic_t             use_count;
411743Smax.romanov@nginx.com 
412743Smax.romanov@nginx.com     uint32_t                 next_port_id;
413743Smax.romanov@nginx.com };
414743Smax.romanov@nginx.com 
415743Smax.romanov@nginx.com 
416743Smax.romanov@nginx.com /* Explicitly using 32 bit types to avoid possible alignment. */
417743Smax.romanov@nginx.com typedef struct {
418743Smax.romanov@nginx.com     int32_t   pid;
419743Smax.romanov@nginx.com     uint32_t  id;
420743Smax.romanov@nginx.com } nxt_unit_port_hash_id_t;
421743Smax.romanov@nginx.com 
422743Smax.romanov@nginx.com 
4231998St.nateldemoura@f5.com static pid_t  nxt_unit_pid;
4241998St.nateldemoura@f5.com 
4251998St.nateldemoura@f5.com 
426743Smax.romanov@nginx.com nxt_unit_ctx_t *
nxt_unit_init(nxt_unit_init_t * init)427743Smax.romanov@nginx.com nxt_unit_init(nxt_unit_init_t *init)
428743Smax.romanov@nginx.com {
4292014Smax.romanov@nginx.com     int              rc, queue_fd, shared_queue_fd;
4301555Smax.romanov@nginx.com     void             *mem;
4311980Smax.romanov@nginx.com     uint32_t         ready_stream, shm_limit, request_limit;
432743Smax.romanov@nginx.com     nxt_unit_ctx_t   *ctx;
433743Smax.romanov@nginx.com     nxt_unit_impl_t  *lib;
4342014Smax.romanov@nginx.com     nxt_unit_port_t  ready_port, router_port, read_port, shared_port;
435743Smax.romanov@nginx.com 
4361998St.nateldemoura@f5.com     nxt_unit_pid = getpid();
4371998St.nateldemoura@f5.com 
438743Smax.romanov@nginx.com     lib = nxt_unit_create(init);
439743Smax.romanov@nginx.com     if (nxt_slow_path(lib == NULL)) {
440743Smax.romanov@nginx.com         return NULL;
441743Smax.romanov@nginx.com     }
442743Smax.romanov@nginx.com 
4431555Smax.romanov@nginx.com     queue_fd = -1;
4441557Smax.romanov@nginx.com     mem = MAP_FAILED;
4452014Smax.romanov@nginx.com     shared_port.out_fd = -1;
4462024Smax.romanov@nginx.com     shared_port.data = NULL;
4471555Smax.romanov@nginx.com 
448743Smax.romanov@nginx.com     if (init->ready_port.id.pid != 0
449743Smax.romanov@nginx.com         && init->ready_stream != 0
450743Smax.romanov@nginx.com         && init->read_port.id.pid != 0)
451743Smax.romanov@nginx.com     {
452743Smax.romanov@nginx.com         ready_port = init->ready_port;
453743Smax.romanov@nginx.com         ready_stream = init->ready_stream;
4541543Smax.romanov@nginx.com         router_port = init->router_port;
455743Smax.romanov@nginx.com         read_port = init->read_port;
456743Smax.romanov@nginx.com         lib->log_fd = init->log_fd;
457743Smax.romanov@nginx.com 
458743Smax.romanov@nginx.com         nxt_unit_port_id_init(&ready_port.id, ready_port.id.pid,
459743Smax.romanov@nginx.com                               ready_port.id.id);
4601543Smax.romanov@nginx.com         nxt_unit_port_id_init(&router_port.id, router_port.id.pid,
4611543Smax.romanov@nginx.com                               router_port.id.id);
462743Smax.romanov@nginx.com         nxt_unit_port_id_init(&read_port.id, read_port.id.pid,
463743Smax.romanov@nginx.com                               read_port.id.id);
4641320Smax.romanov@nginx.com 
4652014Smax.romanov@nginx.com         shared_port.in_fd = init->shared_port_fd;
4662014Smax.romanov@nginx.com         shared_queue_fd = init->shared_queue_fd;
4672014Smax.romanov@nginx.com 
468743Smax.romanov@nginx.com     } else {
4691543Smax.romanov@nginx.com         rc = nxt_unit_read_env(&ready_port, &router_port, &read_port,
4702014Smax.romanov@nginx.com                                &shared_port.in_fd, &shared_queue_fd,
4711980Smax.romanov@nginx.com                                &lib->log_fd, &ready_stream, &shm_limit,
4721980Smax.romanov@nginx.com                                &request_limit);
473743Smax.romanov@nginx.com         if (nxt_slow_path(rc != NXT_UNIT_OK)) {
474743Smax.romanov@nginx.com             goto fail;
475743Smax.romanov@nginx.com         }
4761320Smax.romanov@nginx.com 
4771320Smax.romanov@nginx.com         lib->shm_mmap_limit = (shm_limit + PORT_MMAP_DATA_SIZE - 1)
4781320Smax.romanov@nginx.com                                 / PORT_MMAP_DATA_SIZE;
4791980Smax.romanov@nginx.com         lib->request_limit = request_limit;
4801320Smax.romanov@nginx.com     }
4811320Smax.romanov@nginx.com 
4821320Smax.romanov@nginx.com     if (nxt_slow_path(lib->shm_mmap_limit < 1)) {
4831320Smax.romanov@nginx.com         lib->shm_mmap_limit = 1;
484743Smax.romanov@nginx.com     }
485743Smax.romanov@nginx.com 
4861182St.nateldemoura@f5.com     lib->pid = read_port.id.pid;
4871998St.nateldemoura@f5.com     nxt_unit_pid = lib->pid;
4881544Smax.romanov@nginx.com 
489743Smax.romanov@nginx.com     ctx = &lib->main_ctx.ctx;
490743Smax.romanov@nginx.com 
4911557Smax.romanov@nginx.com     rc = nxt_unit_fd_blocking(router_port.out_fd);
4921557Smax.romanov@nginx.com     if (nxt_slow_path(rc != NXT_UNIT_OK)) {
4931557Smax.romanov@nginx.com         goto fail;
4941557Smax.romanov@nginx.com     }
4951557Smax.romanov@nginx.com 
4961555Smax.romanov@nginx.com     lib->router_port = nxt_unit_add_port(ctx, &router_port, NULL);
4971544Smax.romanov@nginx.com     if (nxt_slow_path(lib->router_port == NULL)) {
4981543Smax.romanov@nginx.com         nxt_unit_alert(NULL, "failed to add router_port");
499743Smax.romanov@nginx.com 
500743Smax.romanov@nginx.com         goto fail;
501743Smax.romanov@nginx.com     }
502743Smax.romanov@nginx.com 
5031555Smax.romanov@nginx.com     queue_fd = nxt_unit_shm_open(ctx, sizeof(nxt_port_queue_t));
5041555Smax.romanov@nginx.com     if (nxt_slow_path(queue_fd == -1)) {
5051555Smax.romanov@nginx.com         goto fail;
5061555Smax.romanov@nginx.com     }
5071555Smax.romanov@nginx.com 
5081555Smax.romanov@nginx.com     mem = mmap(NULL, sizeof(nxt_port_queue_t),
5091555Smax.romanov@nginx.com                PROT_READ | PROT_WRITE, MAP_SHARED, queue_fd, 0);
5101555Smax.romanov@nginx.com     if (nxt_slow_path(mem == MAP_FAILED)) {
5111555Smax.romanov@nginx.com         nxt_unit_alert(ctx, "mmap(%d) failed: %s (%d)", queue_fd,
5121555Smax.romanov@nginx.com                        strerror(errno), errno);
513743Smax.romanov@nginx.com 
514743Smax.romanov@nginx.com         goto fail;
515743Smax.romanov@nginx.com     }
516743Smax.romanov@nginx.com 
5171555Smax.romanov@nginx.com     nxt_port_queue_init(mem);
5181555Smax.romanov@nginx.com 
5191557Smax.romanov@nginx.com     rc = nxt_unit_fd_blocking(read_port.in_fd);
5201557Smax.romanov@nginx.com     if (nxt_slow_path(rc != NXT_UNIT_OK)) {
5211557Smax.romanov@nginx.com         goto fail;
5221557Smax.romanov@nginx.com     }
5231557Smax.romanov@nginx.com 
5241555Smax.romanov@nginx.com     lib->main_ctx.read_port = nxt_unit_add_port(ctx, &read_port, mem);
5251555Smax.romanov@nginx.com     if (nxt_slow_path(lib->main_ctx.read_port == NULL)) {
5261555Smax.romanov@nginx.com         nxt_unit_alert(NULL, "failed to add read_port");
5271555Smax.romanov@nginx.com 
5281557Smax.romanov@nginx.com         goto fail;
5291557Smax.romanov@nginx.com     }
5301557Smax.romanov@nginx.com 
5311557Smax.romanov@nginx.com     rc = nxt_unit_fd_blocking(ready_port.out_fd);
5321557Smax.romanov@nginx.com     if (nxt_slow_path(rc != NXT_UNIT_OK)) {
5331555Smax.romanov@nginx.com         goto fail;
5341555Smax.romanov@nginx.com     }
5351555Smax.romanov@nginx.com 
5362014Smax.romanov@nginx.com     nxt_unit_port_id_init(&shared_port.id, read_port.id.pid,
5372014Smax.romanov@nginx.com                           NXT_UNIT_SHARED_PORT_ID);
5382014Smax.romanov@nginx.com 
5392014Smax.romanov@nginx.com     mem = mmap(NULL, sizeof(nxt_app_queue_t), PROT_READ | PROT_WRITE,
5402014Smax.romanov@nginx.com                MAP_SHARED, shared_queue_fd, 0);
5412014Smax.romanov@nginx.com     if (nxt_slow_path(mem == MAP_FAILED)) {
5422014Smax.romanov@nginx.com         nxt_unit_alert(ctx, "mmap(%d) failed: %s (%d)", shared_queue_fd,
5432014Smax.romanov@nginx.com                        strerror(errno), errno);
5442014Smax.romanov@nginx.com 
5452014Smax.romanov@nginx.com         goto fail;
5462014Smax.romanov@nginx.com     }
5472014Smax.romanov@nginx.com 
5482014Smax.romanov@nginx.com     nxt_unit_close(shared_queue_fd);
5492014Smax.romanov@nginx.com 
5502014Smax.romanov@nginx.com     lib->shared_port = nxt_unit_add_port(ctx, &shared_port, mem);
5512014Smax.romanov@nginx.com     if (nxt_slow_path(lib->shared_port == NULL)) {
5522014Smax.romanov@nginx.com         nxt_unit_alert(NULL, "failed to add shared_port");
5532014Smax.romanov@nginx.com 
5542014Smax.romanov@nginx.com         goto fail;
5552014Smax.romanov@nginx.com     }
5562014Smax.romanov@nginx.com 
5571555Smax.romanov@nginx.com     rc = nxt_unit_ready(ctx, ready_port.out_fd, ready_stream, queue_fd);
558743Smax.romanov@nginx.com     if (nxt_slow_path(rc != NXT_UNIT_OK)) {
559743Smax.romanov@nginx.com         nxt_unit_alert(NULL, "failed to send READY message");
560743Smax.romanov@nginx.com 
561743Smax.romanov@nginx.com         goto fail;
562743Smax.romanov@nginx.com     }
563743Smax.romanov@nginx.com 
5641556Smax.romanov@nginx.com     nxt_unit_close(ready_port.out_fd);
5651556Smax.romanov@nginx.com     nxt_unit_close(queue_fd);
5661543Smax.romanov@nginx.com 
567743Smax.romanov@nginx.com     return ctx;
568743Smax.romanov@nginx.com 
569743Smax.romanov@nginx.com fail:
570743Smax.romanov@nginx.com 
5711557Smax.romanov@nginx.com     if (mem != MAP_FAILED) {
5721557Smax.romanov@nginx.com         munmap(mem, sizeof(nxt_port_queue_t));
5731557Smax.romanov@nginx.com     }
5741557Smax.romanov@nginx.com 
5751555Smax.romanov@nginx.com     if (queue_fd != -1) {
5761556Smax.romanov@nginx.com         nxt_unit_close(queue_fd);
5771555Smax.romanov@nginx.com     }
5781555Smax.romanov@nginx.com 
5791547Smax.romanov@nginx.com     nxt_unit_ctx_release(&lib->main_ctx.ctx);
580743Smax.romanov@nginx.com 
581743Smax.romanov@nginx.com     return NULL;
582743Smax.romanov@nginx.com }
583743Smax.romanov@nginx.com 
584743Smax.romanov@nginx.com 
585743Smax.romanov@nginx.com static nxt_unit_impl_t *
nxt_unit_create(nxt_unit_init_t * init)586743Smax.romanov@nginx.com nxt_unit_create(nxt_unit_init_t *init)
587743Smax.romanov@nginx.com {
5882194Sa.colomar@f5.com     int              rc;
5892194Sa.colomar@f5.com     nxt_unit_impl_t  *lib;
5902194Sa.colomar@f5.com 
5912194Sa.colomar@f5.com     if (nxt_slow_path(init->callbacks.request_handler == NULL)) {
5922194Sa.colomar@f5.com         nxt_unit_alert(NULL, "request_handler is NULL");
5932194Sa.colomar@f5.com 
5942194Sa.colomar@f5.com         return NULL;
5952194Sa.colomar@f5.com     }
596743Smax.romanov@nginx.com 
5971623Smax.romanov@nginx.com     lib = nxt_unit_malloc(NULL,
5981623Smax.romanov@nginx.com                           sizeof(nxt_unit_impl_t) + init->request_data_size);
599743Smax.romanov@nginx.com     if (nxt_slow_path(lib == NULL)) {
600743Smax.romanov@nginx.com         nxt_unit_alert(NULL, "failed to allocate unit struct");
601743Smax.romanov@nginx.com 
602743Smax.romanov@nginx.com         return NULL;
603743Smax.romanov@nginx.com     }
604743Smax.romanov@nginx.com 
605743Smax.romanov@nginx.com     rc = pthread_mutex_init(&lib->mutex, NULL);
606743Smax.romanov@nginx.com     if (nxt_slow_path(rc != 0)) {
607743Smax.romanov@nginx.com         nxt_unit_alert(NULL, "failed to initialize mutex (%d)", rc);
608743Smax.romanov@nginx.com 
6092217Sa.colomar@f5.com         goto out_unit_free;
610743Smax.romanov@nginx.com     }
611743Smax.romanov@nginx.com 
612743Smax.romanov@nginx.com     lib->unit.data = init->data;
613743Smax.romanov@nginx.com     lib->callbacks = init->callbacks;
614743Smax.romanov@nginx.com 
615743Smax.romanov@nginx.com     lib->request_data_size = init->request_data_size;
6161320Smax.romanov@nginx.com     lib->shm_mmap_limit = (init->shm_limit + PORT_MMAP_DATA_SIZE - 1)
6171320Smax.romanov@nginx.com                             / PORT_MMAP_DATA_SIZE;
6181980Smax.romanov@nginx.com     lib->request_limit = init->request_limit;
619743Smax.romanov@nginx.com 
620743Smax.romanov@nginx.com     lib->processes.slot = NULL;
621743Smax.romanov@nginx.com     lib->ports.slot = NULL;
622743Smax.romanov@nginx.com 
623743Smax.romanov@nginx.com     lib->log_fd = STDERR_FILENO;
624743Smax.romanov@nginx.com 
625743Smax.romanov@nginx.com     nxt_queue_init(&lib->contexts);
626743Smax.romanov@nginx.com 
6271543Smax.romanov@nginx.com     lib->use_count = 0;
6281980Smax.romanov@nginx.com     lib->request_count = 0;
6291544Smax.romanov@nginx.com     lib->router_port = NULL;
6301547Smax.romanov@nginx.com     lib->shared_port = NULL;
6311543Smax.romanov@nginx.com 
6321175Smax.romanov@nginx.com     rc = nxt_unit_ctx_init(lib, &lib->main_ctx, init->ctx_data);
6331175Smax.romanov@nginx.com     if (nxt_slow_path(rc != NXT_UNIT_OK)) {
6342217Sa.colomar@f5.com         goto out_mutex_destroy;
6352217Sa.colomar@f5.com     }
6362217Sa.colomar@f5.com 
6372217Sa.colomar@f5.com     rc = nxt_unit_mmaps_init(&lib->incoming);
6382217Sa.colomar@f5.com     if (nxt_slow_path(rc != 0)) {
6392217Sa.colomar@f5.com         nxt_unit_alert(NULL, "failed to initialize mutex (%d)", rc);
6402217Sa.colomar@f5.com 
6412217Sa.colomar@f5.com         goto out_ctx_free;
6422217Sa.colomar@f5.com     }
6432217Sa.colomar@f5.com 
6442217Sa.colomar@f5.com     rc = nxt_unit_mmaps_init(&lib->outgoing);
6452217Sa.colomar@f5.com     if (nxt_slow_path(rc != 0)) {
6462217Sa.colomar@f5.com         nxt_unit_alert(NULL, "failed to initialize mutex (%d)", rc);
6472217Sa.colomar@f5.com 
6482217Sa.colomar@f5.com         goto out_mmaps_destroy;
6492217Sa.colomar@f5.com     }
6501548Smax.romanov@nginx.com 
651743Smax.romanov@nginx.com     return lib;
652743Smax.romanov@nginx.com 
6532217Sa.colomar@f5.com out_mmaps_destroy:
6542217Sa.colomar@f5.com     nxt_unit_mmaps_destroy(&lib->incoming);
6552217Sa.colomar@f5.com 
6562217Sa.colomar@f5.com out_ctx_free:
6572217Sa.colomar@f5.com     nxt_unit_ctx_free(&lib->main_ctx);
6582217Sa.colomar@f5.com 
6592217Sa.colomar@f5.com out_mutex_destroy:
6602217Sa.colomar@f5.com     pthread_mutex_destroy(&lib->mutex);
6612217Sa.colomar@f5.com 
6622217Sa.colomar@f5.com out_unit_free:
6631623Smax.romanov@nginx.com     nxt_unit_free(NULL, lib);
664743Smax.romanov@nginx.com 
665743Smax.romanov@nginx.com     return NULL;
666743Smax.romanov@nginx.com }
667743Smax.romanov@nginx.com 
668743Smax.romanov@nginx.com 
6691175Smax.romanov@nginx.com static int
nxt_unit_ctx_init(nxt_unit_impl_t * lib,nxt_unit_ctx_impl_t * ctx_impl,void * data)670743Smax.romanov@nginx.com nxt_unit_ctx_init(nxt_unit_impl_t *lib, nxt_unit_ctx_impl_t *ctx_impl,
671743Smax.romanov@nginx.com     void *data)
672743Smax.romanov@nginx.com {
6731175Smax.romanov@nginx.com     int  rc;
6741175Smax.romanov@nginx.com 
675743Smax.romanov@nginx.com     ctx_impl->ctx.data = data;
676743Smax.romanov@nginx.com     ctx_impl->ctx.unit = &lib->unit;
677743Smax.romanov@nginx.com 
6781175Smax.romanov@nginx.com     rc = pthread_mutex_init(&ctx_impl->mutex, NULL);
6791175Smax.romanov@nginx.com     if (nxt_slow_path(rc != 0)) {
6801175Smax.romanov@nginx.com         nxt_unit_alert(NULL, "failed to initialize mutex (%d)", rc);
6811175Smax.romanov@nginx.com 
6821175Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
6831175Smax.romanov@nginx.com     }
6841175Smax.romanov@nginx.com 
6851543Smax.romanov@nginx.com     nxt_unit_lib_use(lib);
6861543Smax.romanov@nginx.com 
6871663Smax.romanov@nginx.com     pthread_mutex_lock(&lib->mutex);
6881663Smax.romanov@nginx.com 
6891543Smax.romanov@nginx.com     nxt_queue_insert_tail(&lib->contexts, &ctx_impl->link);
6901543Smax.romanov@nginx.com 
6911663Smax.romanov@nginx.com     pthread_mutex_unlock(&lib->mutex);
6921663Smax.romanov@nginx.com 
6931543Smax.romanov@nginx.com     ctx_impl->use_count = 1;
6941545Smax.romanov@nginx.com     ctx_impl->wait_items = 0;
6951663Smax.romanov@nginx.com     ctx_impl->online = 1;
6961666Smax.romanov@nginx.com     ctx_impl->ready = 0;
6971980Smax.romanov@nginx.com     ctx_impl->quit_param = NXT_QUIT_GRACEFUL;
6981543Smax.romanov@nginx.com 
699743Smax.romanov@nginx.com     nxt_queue_init(&ctx_impl->free_req);
7001131Smax.romanov@nginx.com     nxt_queue_init(&ctx_impl->free_ws);
701743Smax.romanov@nginx.com     nxt_queue_init(&ctx_impl->active_req);
7021545Smax.romanov@nginx.com     nxt_queue_init(&ctx_impl->ready_req);
7031546Smax.romanov@nginx.com     nxt_queue_init(&ctx_impl->pending_rbuf);
7041546Smax.romanov@nginx.com     nxt_queue_init(&ctx_impl->free_rbuf);
705743Smax.romanov@nginx.com 
7061131Smax.romanov@nginx.com     ctx_impl->free_buf = NULL;
7071131Smax.romanov@nginx.com     nxt_unit_mmap_buf_insert(&ctx_impl->free_buf, &ctx_impl->ctx_buf[1]);
7081131Smax.romanov@nginx.com     nxt_unit_mmap_buf_insert(&ctx_impl->free_buf, &ctx_impl->ctx_buf[0]);
7091131Smax.romanov@nginx.com 
710743Smax.romanov@nginx.com     nxt_queue_insert_tail(&ctx_impl->free_req, &ctx_impl->req.link);
7111546Smax.romanov@nginx.com     nxt_queue_insert_tail(&ctx_impl->free_rbuf, &ctx_impl->ctx_read_buf.link);
7121546Smax.romanov@nginx.com 
7131546Smax.romanov@nginx.com     ctx_impl->ctx_read_buf.ctx_impl = ctx_impl;
7141321Smax.romanov@nginx.com 
715743Smax.romanov@nginx.com     ctx_impl->req.req.ctx = &ctx_impl->ctx;
716743Smax.romanov@nginx.com     ctx_impl->req.req.unit = &lib->unit;
717743Smax.romanov@nginx.com 
7181544Smax.romanov@nginx.com     ctx_impl->read_port = NULL;
7191131Smax.romanov@nginx.com     ctx_impl->requests.slot = 0;
7201175Smax.romanov@nginx.com 
7211175Smax.romanov@nginx.com     return NXT_UNIT_OK;
7221131Smax.romanov@nginx.com }
7231131Smax.romanov@nginx.com 
7241131Smax.romanov@nginx.com 
7251131Smax.romanov@nginx.com nxt_inline void
nxt_unit_ctx_use(nxt_unit_ctx_t * ctx)7261547Smax.romanov@nginx.com nxt_unit_ctx_use(nxt_unit_ctx_t *ctx)
7271543Smax.romanov@nginx.com {
7281547Smax.romanov@nginx.com     nxt_unit_ctx_impl_t  *ctx_impl;
7291547Smax.romanov@nginx.com 
7301547Smax.romanov@nginx.com     ctx_impl = nxt_container_of(ctx, nxt_unit_ctx_impl_t, ctx);
7311547Smax.romanov@nginx.com 
7321543Smax.romanov@nginx.com     nxt_atomic_fetch_add(&ctx_impl->use_count, 1);
7331543Smax.romanov@nginx.com }
7341543Smax.romanov@nginx.com 
7351543Smax.romanov@nginx.com 
7361543Smax.romanov@nginx.com nxt_inline void
nxt_unit_ctx_release(nxt_unit_ctx_t * ctx)7371547Smax.romanov@nginx.com nxt_unit_ctx_release(nxt_unit_ctx_t *ctx)
7381543Smax.romanov@nginx.com {
7391547Smax.romanov@nginx.com     long                 c;
7401547Smax.romanov@nginx.com     nxt_unit_ctx_impl_t  *ctx_impl;
7411547Smax.romanov@nginx.com 
7421547Smax.romanov@nginx.com     ctx_impl = nxt_container_of(ctx, nxt_unit_ctx_impl_t, ctx);
7431543Smax.romanov@nginx.com 
7441543Smax.romanov@nginx.com     c = nxt_atomic_fetch_add(&ctx_impl->use_count, -1);
7451543Smax.romanov@nginx.com 
7461543Smax.romanov@nginx.com     if (c == 1) {
7471543Smax.romanov@nginx.com         nxt_unit_ctx_free(ctx_impl);
7481543Smax.romanov@nginx.com     }
7491543Smax.romanov@nginx.com }
7501543Smax.romanov@nginx.com 
7511543Smax.romanov@nginx.com 
7521543Smax.romanov@nginx.com nxt_inline void
nxt_unit_lib_use(nxt_unit_impl_t * lib)7531543Smax.romanov@nginx.com nxt_unit_lib_use(nxt_unit_impl_t *lib)
7541543Smax.romanov@nginx.com {
7551543Smax.romanov@nginx.com     nxt_atomic_fetch_add(&lib->use_count, 1);
7561543Smax.romanov@nginx.com }
7571543Smax.romanov@nginx.com 
7581543Smax.romanov@nginx.com 
7591543Smax.romanov@nginx.com nxt_inline void
nxt_unit_lib_release(nxt_unit_impl_t * lib)7601543Smax.romanov@nginx.com nxt_unit_lib_release(nxt_unit_impl_t *lib)
7611543Smax.romanov@nginx.com {
7621543Smax.romanov@nginx.com     long                c;
7631543Smax.romanov@nginx.com     nxt_unit_process_t  *process;
7641543Smax.romanov@nginx.com 
7651543Smax.romanov@nginx.com     c = nxt_atomic_fetch_add(&lib->use_count, -1);
7661543Smax.romanov@nginx.com 
7671543Smax.romanov@nginx.com     if (c == 1) {
7681543Smax.romanov@nginx.com         for ( ;; ) {
7691543Smax.romanov@nginx.com             pthread_mutex_lock(&lib->mutex);
7701543Smax.romanov@nginx.com 
7711543Smax.romanov@nginx.com             process = nxt_unit_process_pop_first(lib);
7721543Smax.romanov@nginx.com             if (process == NULL) {
7731543Smax.romanov@nginx.com                 pthread_mutex_unlock(&lib->mutex);
7741543Smax.romanov@nginx.com 
7751543Smax.romanov@nginx.com                 break;
7761543Smax.romanov@nginx.com             }
7771543Smax.romanov@nginx.com 
7781543Smax.romanov@nginx.com             nxt_unit_remove_process(lib, process);
7791543Smax.romanov@nginx.com         }
7801543Smax.romanov@nginx.com 
7811543Smax.romanov@nginx.com         pthread_mutex_destroy(&lib->mutex);
7821543Smax.romanov@nginx.com 
7831544Smax.romanov@nginx.com         if (nxt_fast_path(lib->router_port != NULL)) {
7841544Smax.romanov@nginx.com             nxt_unit_port_release(lib->router_port);
7851544Smax.romanov@nginx.com         }
7861544Smax.romanov@nginx.com 
7871547Smax.romanov@nginx.com         if (nxt_fast_path(lib->shared_port != NULL)) {
7881547Smax.romanov@nginx.com             nxt_unit_port_release(lib->shared_port);
7891547Smax.romanov@nginx.com         }
7901547Smax.romanov@nginx.com 
7911548Smax.romanov@nginx.com         nxt_unit_mmaps_destroy(&lib->incoming);
7921548Smax.romanov@nginx.com         nxt_unit_mmaps_destroy(&lib->outgoing);
7931548Smax.romanov@nginx.com 
7941623Smax.romanov@nginx.com         nxt_unit_free(NULL, lib);
7951543Smax.romanov@nginx.com     }
7961543Smax.romanov@nginx.com }
7971543Smax.romanov@nginx.com 
7981543Smax.romanov@nginx.com 
7991543Smax.romanov@nginx.com nxt_inline void
nxt_unit_mmap_buf_insert(nxt_unit_mmap_buf_t ** head,nxt_unit_mmap_buf_t * mmap_buf)8001131Smax.romanov@nginx.com nxt_unit_mmap_buf_insert(nxt_unit_mmap_buf_t **head,
8011131Smax.romanov@nginx.com     nxt_unit_mmap_buf_t *mmap_buf)
8021131Smax.romanov@nginx.com {
8031131Smax.romanov@nginx.com     mmap_buf->next = *head;
8041131Smax.romanov@nginx.com 
8051131Smax.romanov@nginx.com     if (mmap_buf->next != NULL) {
8061131Smax.romanov@nginx.com         mmap_buf->next->prev = &mmap_buf->next;
8071131Smax.romanov@nginx.com     }
8081131Smax.romanov@nginx.com 
8091131Smax.romanov@nginx.com     *head = mmap_buf;
8101131Smax.romanov@nginx.com     mmap_buf->prev = head;
8111131Smax.romanov@nginx.com }
8121131Smax.romanov@nginx.com 
8131131Smax.romanov@nginx.com 
8141131Smax.romanov@nginx.com nxt_inline void
nxt_unit_mmap_buf_insert_tail(nxt_unit_mmap_buf_t ** prev,nxt_unit_mmap_buf_t * mmap_buf)8151131Smax.romanov@nginx.com nxt_unit_mmap_buf_insert_tail(nxt_unit_mmap_buf_t **prev,
8161131Smax.romanov@nginx.com     nxt_unit_mmap_buf_t *mmap_buf)
8171131Smax.romanov@nginx.com {
8181131Smax.romanov@nginx.com     while (*prev != NULL) {
8191131Smax.romanov@nginx.com         prev = &(*prev)->next;
8201131Smax.romanov@nginx.com     }
8211131Smax.romanov@nginx.com 
8221131Smax.romanov@nginx.com     nxt_unit_mmap_buf_insert(prev, mmap_buf);
8231131Smax.romanov@nginx.com }
8241131Smax.romanov@nginx.com 
8251131Smax.romanov@nginx.com 
8261131Smax.romanov@nginx.com nxt_inline void
nxt_unit_mmap_buf_unlink(nxt_unit_mmap_buf_t * mmap_buf)8271319Smax.romanov@nginx.com nxt_unit_mmap_buf_unlink(nxt_unit_mmap_buf_t *mmap_buf)
8281131Smax.romanov@nginx.com {
8291131Smax.romanov@nginx.com     nxt_unit_mmap_buf_t  **prev;
8301131Smax.romanov@nginx.com 
8311131Smax.romanov@nginx.com     prev = mmap_buf->prev;
8321131Smax.romanov@nginx.com 
8331131Smax.romanov@nginx.com     if (mmap_buf->next != NULL) {
8341131Smax.romanov@nginx.com         mmap_buf->next->prev = prev;
8351131Smax.romanov@nginx.com     }
8361131Smax.romanov@nginx.com 
8371131Smax.romanov@nginx.com     if (prev != NULL) {
8381131Smax.romanov@nginx.com         *prev = mmap_buf->next;
8391131Smax.romanov@nginx.com     }
840743Smax.romanov@nginx.com }
841743Smax.romanov@nginx.com 
842743Smax.romanov@nginx.com 
843743Smax.romanov@nginx.com static int
nxt_unit_read_env(nxt_unit_port_t * ready_port,nxt_unit_port_t * router_port,nxt_unit_port_t * read_port,int * shared_port_fd,int * shared_queue_fd,int * log_fd,uint32_t * stream,uint32_t * shm_limit,uint32_t * request_limit)8441543Smax.romanov@nginx.com nxt_unit_read_env(nxt_unit_port_t *ready_port, nxt_unit_port_t *router_port,
8452014Smax.romanov@nginx.com     nxt_unit_port_t *read_port, int *shared_port_fd, int *shared_queue_fd,
8462014Smax.romanov@nginx.com     int *log_fd, uint32_t *stream,
8471980Smax.romanov@nginx.com     uint32_t *shm_limit, uint32_t *request_limit)
848743Smax.romanov@nginx.com {
849743Smax.romanov@nginx.com     int       rc;
8501668Smax.romanov@nginx.com     int       ready_fd, router_fd, read_in_fd, read_out_fd;
8511728Svbart@nginx.com     char      *unit_init, *version_end, *vars;
8521728Svbart@nginx.com     size_t    version_length;
8531543Smax.romanov@nginx.com     int64_t   ready_pid, router_pid, read_pid;
8541543Smax.romanov@nginx.com     uint32_t  ready_stream, router_id, ready_id, read_id;
855743Smax.romanov@nginx.com 
856743Smax.romanov@nginx.com     unit_init = getenv(NXT_UNIT_INIT_ENV);
857743Smax.romanov@nginx.com     if (nxt_slow_path(unit_init == NULL)) {
858743Smax.romanov@nginx.com         nxt_unit_alert(NULL, "%s is not in the current environment",
859743Smax.romanov@nginx.com                        NXT_UNIT_INIT_ENV);
860743Smax.romanov@nginx.com 
861743Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
862743Smax.romanov@nginx.com     }
863743Smax.romanov@nginx.com 
864743Smax.romanov@nginx.com     version_end = strchr(unit_init, ';');
8651728Svbart@nginx.com     if (nxt_slow_path(version_end == NULL)) {
8661728Svbart@nginx.com         nxt_unit_alert(NULL, "Unit version not found in %s=\"%s\"",
8671728Svbart@nginx.com                        NXT_UNIT_INIT_ENV, unit_init);
868743Smax.romanov@nginx.com 
869743Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
870743Smax.romanov@nginx.com     }
871743Smax.romanov@nginx.com 
8721728Svbart@nginx.com     version_length = version_end - unit_init;
8731728Svbart@nginx.com 
8741728Svbart@nginx.com     rc = version_length != nxt_length(NXT_VERSION)
8751728Svbart@nginx.com          || memcmp(unit_init, NXT_VERSION, nxt_length(NXT_VERSION));
8761728Svbart@nginx.com 
8771728Svbart@nginx.com     if (nxt_slow_path(rc != 0)) {
8781728Svbart@nginx.com         nxt_unit_alert(NULL, "versions mismatch: the Unit daemon has version "
8791728Svbart@nginx.com                        "%.*s, while the app was compiled with libunit %s",
8801728Svbart@nginx.com                        (int) version_length, unit_init, NXT_VERSION);
8811728Svbart@nginx.com 
8821728Svbart@nginx.com         return NXT_UNIT_ERROR;
8831728Svbart@nginx.com     }
8841728Svbart@nginx.com 
8851728Svbart@nginx.com     vars = version_end + 1;
8861728Svbart@nginx.com 
8871728Svbart@nginx.com     rc = sscanf(vars,
888743Smax.romanov@nginx.com                 "%"PRIu32";"
889743Smax.romanov@nginx.com                 "%"PRId64",%"PRIu32",%d;"
890743Smax.romanov@nginx.com                 "%"PRId64",%"PRIu32",%d;"
8911668Smax.romanov@nginx.com                 "%"PRId64",%"PRIu32",%d,%d;"
8922014Smax.romanov@nginx.com                 "%d,%d;"
8931980Smax.romanov@nginx.com                 "%d,%"PRIu32",%"PRIu32,
894743Smax.romanov@nginx.com                 &ready_stream,
895743Smax.romanov@nginx.com                 &ready_pid, &ready_id, &ready_fd,
8961543Smax.romanov@nginx.com                 &router_pid, &router_id, &router_fd,
8971668Smax.romanov@nginx.com                 &read_pid, &read_id, &read_in_fd, &read_out_fd,
8982014Smax.romanov@nginx.com                 shared_port_fd, shared_queue_fd,
8991980Smax.romanov@nginx.com                 log_fd, shm_limit, request_limit);
9001320Smax.romanov@nginx.com 
9011728Svbart@nginx.com     if (nxt_slow_path(rc == EOF)) {
9021728Svbart@nginx.com         nxt_unit_alert(NULL, "sscanf(%s) failed: %s (%d) for %s env",
9031728Svbart@nginx.com                        vars, strerror(errno), errno, NXT_UNIT_INIT_ENV);
904743Smax.romanov@nginx.com 
905743Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
906743Smax.romanov@nginx.com     }
907743Smax.romanov@nginx.com 
9082014Smax.romanov@nginx.com     if (nxt_slow_path(rc != 16)) {
9091728Svbart@nginx.com         nxt_unit_alert(NULL, "invalid number of variables in %s env: "
9102014Smax.romanov@nginx.com                        "found %d of %d in %s", NXT_UNIT_INIT_ENV, rc, 16, vars);
9111728Svbart@nginx.com 
9121728Svbart@nginx.com         return NXT_UNIT_ERROR;
9131728Svbart@nginx.com     }
9141728Svbart@nginx.com 
9151728Svbart@nginx.com     nxt_unit_debug(NULL, "%s='%s'", NXT_UNIT_INIT_ENV, unit_init);
9161728Svbart@nginx.com 
917743Smax.romanov@nginx.com     nxt_unit_port_id_init(&ready_port->id, (pid_t) ready_pid, ready_id);
918743Smax.romanov@nginx.com 
919743Smax.romanov@nginx.com     ready_port->in_fd = -1;
920743Smax.romanov@nginx.com     ready_port->out_fd = ready_fd;
921743Smax.romanov@nginx.com     ready_port->data = NULL;
922743Smax.romanov@nginx.com 
9231543Smax.romanov@nginx.com     nxt_unit_port_id_init(&router_port->id, (pid_t) router_pid, router_id);
9241543Smax.romanov@nginx.com 
9251543Smax.romanov@nginx.com     router_port->in_fd = -1;
9261543Smax.romanov@nginx.com     router_port->out_fd = router_fd;
9271543Smax.romanov@nginx.com     router_port->data = NULL;
9281543Smax.romanov@nginx.com 
929743Smax.romanov@nginx.com     nxt_unit_port_id_init(&read_port->id, (pid_t) read_pid, read_id);
930743Smax.romanov@nginx.com 
9311668Smax.romanov@nginx.com     read_port->in_fd = read_in_fd;
9321668Smax.romanov@nginx.com     read_port->out_fd = read_out_fd;
933743Smax.romanov@nginx.com     read_port->data = NULL;
934743Smax.romanov@nginx.com 
935743Smax.romanov@nginx.com     *stream = ready_stream;
936743Smax.romanov@nginx.com 
937743Smax.romanov@nginx.com     return NXT_UNIT_OK;
938743Smax.romanov@nginx.com }
939743Smax.romanov@nginx.com 
940743Smax.romanov@nginx.com 
941743Smax.romanov@nginx.com static int
nxt_unit_ready(nxt_unit_ctx_t * ctx,int ready_fd,uint32_t stream,int queue_fd)9421555Smax.romanov@nginx.com nxt_unit_ready(nxt_unit_ctx_t *ctx, int ready_fd, uint32_t stream, int queue_fd)
943743Smax.romanov@nginx.com {
944743Smax.romanov@nginx.com     ssize_t          res;
9451996St.nateldemoura@f5.com     nxt_send_oob_t   oob;
946743Smax.romanov@nginx.com     nxt_port_msg_t   msg;
947743Smax.romanov@nginx.com     nxt_unit_impl_t  *lib;
9481996St.nateldemoura@f5.com     int              fds[2] = {queue_fd, -1};
9491555Smax.romanov@nginx.com 
950743Smax.romanov@nginx.com     lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit);
951743Smax.romanov@nginx.com 
952743Smax.romanov@nginx.com     msg.stream = stream;
953743Smax.romanov@nginx.com     msg.pid = lib->pid;
954743Smax.romanov@nginx.com     msg.reply_port = 0;
955743Smax.romanov@nginx.com     msg.type = _NXT_PORT_MSG_PROCESS_READY;
956743Smax.romanov@nginx.com     msg.last = 1;
957743Smax.romanov@nginx.com     msg.mmap = 0;
958743Smax.romanov@nginx.com     msg.nf = 0;
959743Smax.romanov@nginx.com     msg.mf = 0;
960743Smax.romanov@nginx.com 
9611996St.nateldemoura@f5.com     nxt_socket_msg_oob_init(&oob, fds);
9621996St.nateldemoura@f5.com 
9631996St.nateldemoura@f5.com     res = nxt_unit_sendmsg(ctx, ready_fd, &msg, sizeof(msg), &oob);
964743Smax.romanov@nginx.com     if (res != sizeof(msg)) {
965743Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
966743Smax.romanov@nginx.com     }
967743Smax.romanov@nginx.com 
968743Smax.romanov@nginx.com     return NXT_UNIT_OK;
969743Smax.romanov@nginx.com }
970743Smax.romanov@nginx.com 
971743Smax.romanov@nginx.com 
9721546Smax.romanov@nginx.com static int
nxt_unit_process_msg(nxt_unit_ctx_t * ctx,nxt_unit_read_buf_t * rbuf,nxt_unit_request_info_t ** preq)9731713Smax.romanov@nginx.com nxt_unit_process_msg(nxt_unit_ctx_t *ctx, nxt_unit_read_buf_t *rbuf,
9741713Smax.romanov@nginx.com     nxt_unit_request_info_t **preq)
975743Smax.romanov@nginx.com {
9761543Smax.romanov@nginx.com     int                  rc;
9771543Smax.romanov@nginx.com     pid_t                pid;
9781980Smax.romanov@nginx.com     uint8_t              quit_param;
9791543Smax.romanov@nginx.com     nxt_port_msg_t       *port_msg;
9801543Smax.romanov@nginx.com     nxt_unit_impl_t      *lib;
9811543Smax.romanov@nginx.com     nxt_unit_recv_msg_t  recv_msg;
982743Smax.romanov@nginx.com 
983743Smax.romanov@nginx.com     lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit);
984743Smax.romanov@nginx.com 
9852013Svbart@nginx.com     recv_msg.incoming_buf = NULL;
9861558Smax.romanov@nginx.com     recv_msg.fd[0] = -1;
9871558Smax.romanov@nginx.com     recv_msg.fd[1] = -1;
9881996St.nateldemoura@f5.com 
9891996St.nateldemoura@f5.com     rc = nxt_socket_msg_oob_get_fds(&rbuf->oob, recv_msg.fd);
9901996St.nateldemoura@f5.com     if (nxt_slow_path(rc != NXT_OK)) {
9911996St.nateldemoura@f5.com         nxt_unit_alert(ctx, "failed to receive file descriptor over cmsg");
9921996St.nateldemoura@f5.com         rc = NXT_UNIT_ERROR;
9931996St.nateldemoura@f5.com         goto done;
994743Smax.romanov@nginx.com     }
995743Smax.romanov@nginx.com 
9961546Smax.romanov@nginx.com     if (nxt_slow_path(rbuf->size < (ssize_t) sizeof(nxt_port_msg_t))) {
9971547Smax.romanov@nginx.com         if (nxt_slow_path(rbuf->size == 0)) {
9981547Smax.romanov@nginx.com             nxt_unit_debug(ctx, "read port closed");
9991547Smax.romanov@nginx.com 
10001980Smax.romanov@nginx.com             nxt_unit_quit(ctx, NXT_QUIT_GRACEFUL);
10011547Smax.romanov@nginx.com             rc = NXT_UNIT_OK;
10021559Smax.romanov@nginx.com             goto done;
10031547Smax.romanov@nginx.com         }
10041547Smax.romanov@nginx.com 
10051546Smax.romanov@nginx.com         nxt_unit_alert(ctx, "message too small (%d bytes)", (int) rbuf->size);
10061559Smax.romanov@nginx.com 
10071559Smax.romanov@nginx.com         rc = NXT_UNIT_ERROR;
10081559Smax.romanov@nginx.com         goto done;
1009743Smax.romanov@nginx.com     }
1010743Smax.romanov@nginx.com 
10112013Svbart@nginx.com     port_msg = (nxt_port_msg_t *) rbuf->buf;
10122013Svbart@nginx.com 
10131558Smax.romanov@nginx.com     nxt_unit_debug(ctx, "#%"PRIu32": process message %d fd[0] %d fd[1] %d",
10141555Smax.romanov@nginx.com                    port_msg->stream, (int) port_msg->type,
10151558Smax.romanov@nginx.com                    recv_msg.fd[0], recv_msg.fd[1]);
10161555Smax.romanov@nginx.com 
10171131Smax.romanov@nginx.com     recv_msg.stream = port_msg->stream;
10181131Smax.romanov@nginx.com     recv_msg.pid = port_msg->pid;
10191131Smax.romanov@nginx.com     recv_msg.reply_port = port_msg->reply_port;
10201131Smax.romanov@nginx.com     recv_msg.last = port_msg->last;
10211131Smax.romanov@nginx.com     recv_msg.mmap = port_msg->mmap;
10221131Smax.romanov@nginx.com 
1023743Smax.romanov@nginx.com     recv_msg.start = port_msg + 1;
10241546Smax.romanov@nginx.com     recv_msg.size = rbuf->size - sizeof(nxt_port_msg_t);
1025743Smax.romanov@nginx.com 
1026743Smax.romanov@nginx.com     if (nxt_slow_path(port_msg->type >= NXT_PORT_MSG_MAX)) {
10271559Smax.romanov@nginx.com         nxt_unit_alert(ctx, "#%"PRIu32": unknown message type (%d)",
10281559Smax.romanov@nginx.com                        port_msg->stream, (int) port_msg->type);
10291559Smax.romanov@nginx.com         rc = NXT_UNIT_ERROR;
10301559Smax.romanov@nginx.com         goto done;
1031743Smax.romanov@nginx.com     }
1032743Smax.romanov@nginx.com 
1033743Smax.romanov@nginx.com     /* Fragmentation is unsupported. */
1034743Smax.romanov@nginx.com     if (nxt_slow_path(port_msg->nf != 0 || port_msg->mf != 0)) {
10351559Smax.romanov@nginx.com         nxt_unit_alert(ctx, "#%"PRIu32": fragmented message type (%d)",
10361559Smax.romanov@nginx.com                        port_msg->stream, (int) port_msg->type);
10371559Smax.romanov@nginx.com         rc = NXT_UNIT_ERROR;
10381559Smax.romanov@nginx.com         goto done;
1039743Smax.romanov@nginx.com     }
1040743Smax.romanov@nginx.com 
1041743Smax.romanov@nginx.com     if (port_msg->mmap) {
10421546Smax.romanov@nginx.com         rc = nxt_unit_mmap_read(ctx, &recv_msg, rbuf);
10431546Smax.romanov@nginx.com 
10441546Smax.romanov@nginx.com         if (nxt_slow_path(rc != NXT_UNIT_OK)) {
10451546Smax.romanov@nginx.com             if (rc == NXT_UNIT_AGAIN) {
10461558Smax.romanov@nginx.com                 recv_msg.fd[0] = -1;
10471558Smax.romanov@nginx.com                 recv_msg.fd[1] = -1;
10481546Smax.romanov@nginx.com             }
10491546Smax.romanov@nginx.com 
10501559Smax.romanov@nginx.com             goto done;
1051743Smax.romanov@nginx.com         }
1052743Smax.romanov@nginx.com     }
1053743Smax.romanov@nginx.com 
1054743Smax.romanov@nginx.com     switch (port_msg->type) {
1055743Smax.romanov@nginx.com 
10561667Smax.romanov@nginx.com     case _NXT_PORT_MSG_RPC_READY:
10571667Smax.romanov@nginx.com         rc = NXT_UNIT_OK;
10581667Smax.romanov@nginx.com         break;
10591667Smax.romanov@nginx.com 
1060743Smax.romanov@nginx.com     case _NXT_PORT_MSG_QUIT:
10611980Smax.romanov@nginx.com         if (recv_msg.size == sizeof(quit_param)) {
10621980Smax.romanov@nginx.com             memcpy(&quit_param, recv_msg.start, sizeof(quit_param));
10631980Smax.romanov@nginx.com 
10641980Smax.romanov@nginx.com         } else {
10651980Smax.romanov@nginx.com             quit_param = NXT_QUIT_NORMAL;
10661980Smax.romanov@nginx.com         }
10671980Smax.romanov@nginx.com 
10681980Smax.romanov@nginx.com         nxt_unit_debug(ctx, "#%"PRIu32": %squit", port_msg->stream,
10691980Smax.romanov@nginx.com                        (quit_param == NXT_QUIT_GRACEFUL ? "graceful " : ""));
10701980Smax.romanov@nginx.com 
10711980Smax.romanov@nginx.com         nxt_unit_quit(ctx, quit_param);
10721980Smax.romanov@nginx.com 
1073743Smax.romanov@nginx.com         rc = NXT_UNIT_OK;
1074743Smax.romanov@nginx.com         break;
1075743Smax.romanov@nginx.com 
1076743Smax.romanov@nginx.com     case _NXT_PORT_MSG_NEW_PORT:
10771131Smax.romanov@nginx.com         rc = nxt_unit_process_new_port(ctx, &recv_msg);
1078743Smax.romanov@nginx.com         break;
1079743Smax.romanov@nginx.com 
10801666Smax.romanov@nginx.com     case _NXT_PORT_MSG_PORT_ACK:
10811666Smax.romanov@nginx.com         rc = nxt_unit_ctx_ready(ctx);
10821666Smax.romanov@nginx.com         break;
10831666Smax.romanov@nginx.com 
1084743Smax.romanov@nginx.com     case _NXT_PORT_MSG_CHANGE_FILE:
1085743Smax.romanov@nginx.com         nxt_unit_debug(ctx, "#%"PRIu32": change_file: fd %d",
10861558Smax.romanov@nginx.com                        port_msg->stream, recv_msg.fd[0]);
10871558Smax.romanov@nginx.com 
10881558Smax.romanov@nginx.com         if (dup2(recv_msg.fd[0], lib->log_fd) == -1) {
10891437Smax.romanov@nginx.com             nxt_unit_alert(ctx, "#%"PRIu32": dup2(%d, %d) failed: %s (%d)",
10901558Smax.romanov@nginx.com                            port_msg->stream, recv_msg.fd[0], lib->log_fd,
10911437Smax.romanov@nginx.com                            strerror(errno), errno);
10921437Smax.romanov@nginx.com 
10931559Smax.romanov@nginx.com             rc = NXT_UNIT_ERROR;
10941559Smax.romanov@nginx.com             goto done;
10951437Smax.romanov@nginx.com         }
10961437Smax.romanov@nginx.com 
10971437Smax.romanov@nginx.com         rc = NXT_UNIT_OK;
1098743Smax.romanov@nginx.com         break;
1099743Smax.romanov@nginx.com 
1100743Smax.romanov@nginx.com     case _NXT_PORT_MSG_MMAP:
11011558Smax.romanov@nginx.com         if (nxt_slow_path(recv_msg.fd[0] < 0)) {
1102747Smax.romanov@nginx.com             nxt_unit_alert(ctx, "#%"PRIu32": invalid fd %d for mmap",
11031558Smax.romanov@nginx.com                            port_msg->stream, recv_msg.fd[0]);
1104743Smax.romanov@nginx.com 
11051559Smax.romanov@nginx.com             rc = NXT_UNIT_ERROR;
11061559Smax.romanov@nginx.com             goto done;
1107743Smax.romanov@nginx.com         }
1108743Smax.romanov@nginx.com 
11091558Smax.romanov@nginx.com         rc = nxt_unit_incoming_mmap(ctx, port_msg->pid, recv_msg.fd[0]);
11101131Smax.romanov@nginx.com         break;
11111131Smax.romanov@nginx.com 
11121131Smax.romanov@nginx.com     case _NXT_PORT_MSG_REQ_HEADERS:
11131713Smax.romanov@nginx.com         rc = nxt_unit_process_req_headers(ctx, &recv_msg, preq);
11141131Smax.romanov@nginx.com         break;
11151131Smax.romanov@nginx.com 
11161555Smax.romanov@nginx.com     case _NXT_PORT_MSG_REQ_BODY:
11171555Smax.romanov@nginx.com         rc = nxt_unit_process_req_body(ctx, &recv_msg);
11181555Smax.romanov@nginx.com         break;
11191555Smax.romanov@nginx.com 
11201131Smax.romanov@nginx.com     case _NXT_PORT_MSG_WEBSOCKET:
11211131Smax.romanov@nginx.com         rc = nxt_unit_process_websocket(ctx, &recv_msg);
1122743Smax.romanov@nginx.com         break;
1123743Smax.romanov@nginx.com 
1124743Smax.romanov@nginx.com     case _NXT_PORT_MSG_REMOVE_PID:
1125743Smax.romanov@nginx.com         if (nxt_slow_path(recv_msg.size != sizeof(pid))) {
11261559Smax.romanov@nginx.com             nxt_unit_alert(ctx, "#%"PRIu32": remove_pid: invalid message size "
11271559Smax.romanov@nginx.com                            "(%d != %d)", port_msg->stream, (int) recv_msg.size,
11281559Smax.romanov@nginx.com                            (int) sizeof(pid));
11291559Smax.romanov@nginx.com 
11301559Smax.romanov@nginx.com             rc = NXT_UNIT_ERROR;
11311559Smax.romanov@nginx.com             goto done;
1132743Smax.romanov@nginx.com         }
1133743Smax.romanov@nginx.com 
1134743Smax.romanov@nginx.com         memcpy(&pid, recv_msg.start, sizeof(pid));
1135743Smax.romanov@nginx.com 
1136743Smax.romanov@nginx.com         nxt_unit_debug(ctx, "#%"PRIu32": remove_pid: %d",
1137743Smax.romanov@nginx.com                        port_msg->stream, (int) pid);
1138743Smax.romanov@nginx.com 
11391543Smax.romanov@nginx.com         nxt_unit_remove_pid(lib, pid);
1140743Smax.romanov@nginx.com 
1141743Smax.romanov@nginx.com         rc = NXT_UNIT_OK;
1142743Smax.romanov@nginx.com         break;
1143743Smax.romanov@nginx.com 
11441321Smax.romanov@nginx.com     case _NXT_PORT_MSG_SHM_ACK:
11451321Smax.romanov@nginx.com         rc = nxt_unit_process_shm_ack(ctx);
11461321Smax.romanov@nginx.com         break;
11471321Smax.romanov@nginx.com 
1148743Smax.romanov@nginx.com     default:
11491667Smax.romanov@nginx.com         nxt_unit_alert(ctx, "#%"PRIu32": ignore message type: %d",
1150743Smax.romanov@nginx.com                        port_msg->stream, (int) port_msg->type);
1151743Smax.romanov@nginx.com 
11521559Smax.romanov@nginx.com         rc = NXT_UNIT_ERROR;
11531559Smax.romanov@nginx.com         goto done;
11541559Smax.romanov@nginx.com     }
11551559Smax.romanov@nginx.com 
11561559Smax.romanov@nginx.com done:
1157743Smax.romanov@nginx.com 
11581558Smax.romanov@nginx.com     if (recv_msg.fd[0] != -1) {
11591558Smax.romanov@nginx.com         nxt_unit_close(recv_msg.fd[0]);
11601558Smax.romanov@nginx.com     }
11611558Smax.romanov@nginx.com 
11621558Smax.romanov@nginx.com     if (recv_msg.fd[1] != -1) {
11631558Smax.romanov@nginx.com         nxt_unit_close(recv_msg.fd[1]);
11641553Smax.romanov@nginx.com     }
11651553Smax.romanov@nginx.com 
11661131Smax.romanov@nginx.com     while (recv_msg.incoming_buf != NULL) {
11671131Smax.romanov@nginx.com         nxt_unit_mmap_buf_free(recv_msg.incoming_buf);
1168743Smax.romanov@nginx.com     }
1169743Smax.romanov@nginx.com 
11701547Smax.romanov@nginx.com     if (nxt_fast_path(rc != NXT_UNIT_AGAIN)) {
11711547Smax.romanov@nginx.com #if (NXT_DEBUG)
11721547Smax.romanov@nginx.com         memset(rbuf->buf, 0xAC, rbuf->size);
11731547Smax.romanov@nginx.com #endif
11741547Smax.romanov@nginx.com         nxt_unit_read_buf_release(ctx, rbuf);
11751547Smax.romanov@nginx.com     }
11761547Smax.romanov@nginx.com 
1177743Smax.romanov@nginx.com     return rc;
1178743Smax.romanov@nginx.com }
1179743Smax.romanov@nginx.com 
1180743Smax.romanov@nginx.com 
11811131Smax.romanov@nginx.com static int
nxt_unit_process_new_port(nxt_unit_ctx_t * ctx,nxt_unit_recv_msg_t * recv_msg)11821131Smax.romanov@nginx.com nxt_unit_process_new_port(nxt_unit_ctx_t *ctx, nxt_unit_recv_msg_t *recv_msg)
11831131Smax.romanov@nginx.com {
11841555Smax.romanov@nginx.com     void                     *mem;
11851544Smax.romanov@nginx.com     nxt_unit_port_t          new_port, *port;
11861131Smax.romanov@nginx.com     nxt_port_msg_new_port_t  *new_port_msg;
11871131Smax.romanov@nginx.com 
11881131Smax.romanov@nginx.com     if (nxt_slow_path(recv_msg->size != sizeof(nxt_port_msg_new_port_t))) {
11891131Smax.romanov@nginx.com         nxt_unit_warn(ctx, "#%"PRIu32": new_port: "
11901131Smax.romanov@nginx.com                       "invalid message size (%d)",
11911131Smax.romanov@nginx.com                       recv_msg->stream, (int) recv_msg->size);
11921131Smax.romanov@nginx.com 
11931131Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
11941131Smax.romanov@nginx.com     }
11951131Smax.romanov@nginx.com 
11961558Smax.romanov@nginx.com     if (nxt_slow_path(recv_msg->fd[0] < 0)) {
11971131Smax.romanov@nginx.com         nxt_unit_alert(ctx, "#%"PRIu32": invalid fd %d for new port",
11981558Smax.romanov@nginx.com                        recv_msg->stream, recv_msg->fd[0]);
11991131Smax.romanov@nginx.com 
12001131Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
12011131Smax.romanov@nginx.com     }
12021131Smax.romanov@nginx.com 
12031131Smax.romanov@nginx.com     new_port_msg = recv_msg->start;
12041131Smax.romanov@nginx.com 
12051558Smax.romanov@nginx.com     nxt_unit_debug(ctx, "#%"PRIu32": new_port: port{%d,%d} fd[0] %d fd[1] %d",
12061131Smax.romanov@nginx.com                    recv_msg->stream, (int) new_port_msg->pid,
12071558Smax.romanov@nginx.com                    (int) new_port_msg->id, recv_msg->fd[0], recv_msg->fd[1]);
12081131Smax.romanov@nginx.com 
12092014Smax.romanov@nginx.com     if (nxt_slow_path(nxt_unit_fd_blocking(recv_msg->fd[0]) != NXT_UNIT_OK)) {
12102014Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
12112014Smax.romanov@nginx.com     }
12122014Smax.romanov@nginx.com 
12132014Smax.romanov@nginx.com     nxt_unit_port_id_init(&new_port.id, new_port_msg->pid, new_port_msg->id);
12142014Smax.romanov@nginx.com 
12152014Smax.romanov@nginx.com     new_port.in_fd = -1;
12162014Smax.romanov@nginx.com     new_port.out_fd = recv_msg->fd[0];
12172014Smax.romanov@nginx.com 
12182014Smax.romanov@nginx.com     mem = mmap(NULL, sizeof(nxt_port_queue_t), PROT_READ | PROT_WRITE,
12192014Smax.romanov@nginx.com                MAP_SHARED, recv_msg->fd[1], 0);
12201555Smax.romanov@nginx.com 
12211555Smax.romanov@nginx.com     if (nxt_slow_path(mem == MAP_FAILED)) {
12221558Smax.romanov@nginx.com         nxt_unit_alert(ctx, "mmap(%d) failed: %s (%d)", recv_msg->fd[1],
12231555Smax.romanov@nginx.com                        strerror(errno), errno);
12241555Smax.romanov@nginx.com 
12251555Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
12261555Smax.romanov@nginx.com     }
12271547Smax.romanov@nginx.com 
12281131Smax.romanov@nginx.com     new_port.data = NULL;
12291131Smax.romanov@nginx.com 
12301558Smax.romanov@nginx.com     recv_msg->fd[0] = -1;
12311131Smax.romanov@nginx.com 
12321555Smax.romanov@nginx.com     port = nxt_unit_add_port(ctx, &new_port, mem);
12331544Smax.romanov@nginx.com     if (nxt_slow_path(port == NULL)) {
12341544Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
12351544Smax.romanov@nginx.com     }
12361544Smax.romanov@nginx.com 
12371666Smax.romanov@nginx.com     nxt_unit_port_release(port);
12381666Smax.romanov@nginx.com 
12391666Smax.romanov@nginx.com     return NXT_UNIT_OK;
12401666Smax.romanov@nginx.com }
12411666Smax.romanov@nginx.com 
12421666Smax.romanov@nginx.com 
12431666Smax.romanov@nginx.com static int
nxt_unit_ctx_ready(nxt_unit_ctx_t * ctx)12441666Smax.romanov@nginx.com nxt_unit_ctx_ready(nxt_unit_ctx_t *ctx)
12451666Smax.romanov@nginx.com {
12461666Smax.romanov@nginx.com     nxt_unit_impl_t      *lib;
12471666Smax.romanov@nginx.com     nxt_unit_ctx_impl_t  *ctx_impl;
12481666Smax.romanov@nginx.com 
12491666Smax.romanov@nginx.com     ctx_impl = nxt_container_of(ctx, nxt_unit_ctx_impl_t, ctx);
12501666Smax.romanov@nginx.com 
12511980Smax.romanov@nginx.com     if (nxt_slow_path(ctx_impl->ready)) {
12521980Smax.romanov@nginx.com         return NXT_UNIT_OK;
12531980Smax.romanov@nginx.com     }
12541980Smax.romanov@nginx.com 
12551666Smax.romanov@nginx.com     ctx_impl->ready = 1;
12561666Smax.romanov@nginx.com 
12571980Smax.romanov@nginx.com     lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit);
12581980Smax.romanov@nginx.com 
12591980Smax.romanov@nginx.com     /* Call ready_handler() only for main context. */
12601980Smax.romanov@nginx.com     if (&lib->main_ctx == ctx_impl && lib->callbacks.ready_handler != NULL) {
12611666Smax.romanov@nginx.com         return lib->callbacks.ready_handler(ctx);
12621547Smax.romanov@nginx.com     }
12631544Smax.romanov@nginx.com 
12641980Smax.romanov@nginx.com     if (&lib->main_ctx != ctx_impl) {
12651980Smax.romanov@nginx.com         /* Check if the main context is already stopped or quit. */
12661980Smax.romanov@nginx.com         if (nxt_slow_path(!lib->main_ctx.ready)) {
12671980Smax.romanov@nginx.com             ctx_impl->ready = 0;
12681980Smax.romanov@nginx.com 
12691980Smax.romanov@nginx.com             nxt_unit_quit(ctx, lib->main_ctx.quit_param);
12701980Smax.romanov@nginx.com 
12711980Smax.romanov@nginx.com             return NXT_UNIT_OK;
12721980Smax.romanov@nginx.com         }
12731980Smax.romanov@nginx.com 
12741980Smax.romanov@nginx.com         if (lib->callbacks.add_port != NULL) {
12751980Smax.romanov@nginx.com             lib->callbacks.add_port(ctx, lib->shared_port);
12761980Smax.romanov@nginx.com         }
12771980Smax.romanov@nginx.com     }
12781980Smax.romanov@nginx.com 
12791544Smax.romanov@nginx.com     return NXT_UNIT_OK;
12801131Smax.romanov@nginx.com }
12811131Smax.romanov@nginx.com 
12821131Smax.romanov@nginx.com 
12831131Smax.romanov@nginx.com static int
nxt_unit_process_req_headers(nxt_unit_ctx_t * ctx,nxt_unit_recv_msg_t * recv_msg,nxt_unit_request_info_t ** preq)12841713Smax.romanov@nginx.com nxt_unit_process_req_headers(nxt_unit_ctx_t *ctx, nxt_unit_recv_msg_t *recv_msg,
12851713Smax.romanov@nginx.com     nxt_unit_request_info_t **preq)
12861131Smax.romanov@nginx.com {
12871545Smax.romanov@nginx.com     int                           res;
12881131Smax.romanov@nginx.com     nxt_unit_impl_t               *lib;
12891544Smax.romanov@nginx.com     nxt_unit_port_id_t            port_id;
12901131Smax.romanov@nginx.com     nxt_unit_request_t            *r;
12911131Smax.romanov@nginx.com     nxt_unit_mmap_buf_t           *b;
12921131Smax.romanov@nginx.com     nxt_unit_request_info_t       *req;
12931131Smax.romanov@nginx.com     nxt_unit_request_info_impl_t  *req_impl;
12941131Smax.romanov@nginx.com 
12951131Smax.romanov@nginx.com     if (nxt_slow_path(recv_msg->mmap == 0)) {
12961131Smax.romanov@nginx.com         nxt_unit_warn(ctx, "#%"PRIu32": data is not in shared memory",
12971131Smax.romanov@nginx.com                       recv_msg->stream);
12981131Smax.romanov@nginx.com 
12991131Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
13001131Smax.romanov@nginx.com     }
13011131Smax.romanov@nginx.com 
13021131Smax.romanov@nginx.com     if (nxt_slow_path(recv_msg->size < sizeof(nxt_unit_request_t))) {
13031131Smax.romanov@nginx.com         nxt_unit_warn(ctx, "#%"PRIu32": data too short: %d while at least "
13041131Smax.romanov@nginx.com                       "%d expected", recv_msg->stream, (int) recv_msg->size,
13051131Smax.romanov@nginx.com                       (int) sizeof(nxt_unit_request_t));
13061131Smax.romanov@nginx.com 
13071131Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
13081131Smax.romanov@nginx.com     }
13091131Smax.romanov@nginx.com 
13101131Smax.romanov@nginx.com     req_impl = nxt_unit_request_info_get(ctx);
13111131Smax.romanov@nginx.com     if (nxt_slow_path(req_impl == NULL)) {
13121131Smax.romanov@nginx.com         nxt_unit_warn(ctx, "#%"PRIu32": request info allocation failed",
13131131Smax.romanov@nginx.com                       recv_msg->stream);
13141131Smax.romanov@nginx.com 
13151131Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
13161131Smax.romanov@nginx.com     }
13171131Smax.romanov@nginx.com 
13181131Smax.romanov@nginx.com     req = &req_impl->req;
13191131Smax.romanov@nginx.com 
13201131Smax.romanov@nginx.com     req->request = recv_msg->start;
13211131Smax.romanov@nginx.com 
13221131Smax.romanov@nginx.com     b = recv_msg->incoming_buf;
13231131Smax.romanov@nginx.com 
13241131Smax.romanov@nginx.com     req->request_buf = &b->buf;
13251131Smax.romanov@nginx.com     req->response = NULL;
13261131Smax.romanov@nginx.com     req->response_buf = NULL;
13271131Smax.romanov@nginx.com 
13281131Smax.romanov@nginx.com     r = req->request;
13291131Smax.romanov@nginx.com 
13301131Smax.romanov@nginx.com     req->content_length = r->content_length;
13311131Smax.romanov@nginx.com 
13321131Smax.romanov@nginx.com     req->content_buf = req->request_buf;
13331131Smax.romanov@nginx.com     req->content_buf->free = nxt_unit_sptr_get(&r->preread_content);
13341131Smax.romanov@nginx.com 
13351131Smax.romanov@nginx.com     req_impl->stream = recv_msg->stream;
13361131Smax.romanov@nginx.com 
13371131Smax.romanov@nginx.com     req_impl->outgoing_buf = NULL;
13381131Smax.romanov@nginx.com 
13391131Smax.romanov@nginx.com     for (b = recv_msg->incoming_buf; b != NULL; b = b->next) {
13401131Smax.romanov@nginx.com         b->req = req;
13411131Smax.romanov@nginx.com     }
13421131Smax.romanov@nginx.com 
13431131Smax.romanov@nginx.com     /* "Move" incoming buffer list to req_impl. */
13441131Smax.romanov@nginx.com     req_impl->incoming_buf = recv_msg->incoming_buf;
13451131Smax.romanov@nginx.com     req_impl->incoming_buf->prev = &req_impl->incoming_buf;
13461131Smax.romanov@nginx.com     recv_msg->incoming_buf = NULL;
13471131Smax.romanov@nginx.com 
13481558Smax.romanov@nginx.com     req->content_fd = recv_msg->fd[0];
13491558Smax.romanov@nginx.com     recv_msg->fd[0] = -1;
13501403Smax.romanov@nginx.com 
13511131Smax.romanov@nginx.com     req->response_max_fields = 0;
13521131Smax.romanov@nginx.com     req_impl->state = NXT_UNIT_RS_START;
13531131Smax.romanov@nginx.com     req_impl->websocket = 0;
13541555Smax.romanov@nginx.com     req_impl->in_hash = 0;
13551131Smax.romanov@nginx.com 
13561131Smax.romanov@nginx.com     nxt_unit_debug(ctx, "#%"PRIu32": %.*s %.*s (%d)", recv_msg->stream,
13571436Smax.romanov@nginx.com                    (int) r->method_length,
13581436Smax.romanov@nginx.com                    (char *) nxt_unit_sptr_get(&r->method),
13591436Smax.romanov@nginx.com                    (int) r->target_length,
13601436Smax.romanov@nginx.com                    (char *) nxt_unit_sptr_get(&r->target),
13611131Smax.romanov@nginx.com                    (int) r->content_length);
13621131Smax.romanov@nginx.com 
13631545Smax.romanov@nginx.com     nxt_unit_port_id_init(&port_id, recv_msg->pid, recv_msg->reply_port);
13641545Smax.romanov@nginx.com 
13651545Smax.romanov@nginx.com     res = nxt_unit_request_check_response_port(req, &port_id);
13661546Smax.romanov@nginx.com     if (nxt_slow_path(res == NXT_UNIT_ERROR)) {
13671546Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
13681546Smax.romanov@nginx.com     }
13691545Smax.romanov@nginx.com 
13701545Smax.romanov@nginx.com     if (nxt_fast_path(res == NXT_UNIT_OK)) {
13711547Smax.romanov@nginx.com         res = nxt_unit_send_req_headers_ack(req);
13721555Smax.romanov@nginx.com         if (nxt_slow_path(res == NXT_UNIT_ERROR)) {
13731555Smax.romanov@nginx.com             nxt_unit_request_done(req, NXT_UNIT_ERROR);
13741555Smax.romanov@nginx.com 
13751555Smax.romanov@nginx.com             return NXT_UNIT_ERROR;
13761547Smax.romanov@nginx.com         }
13771547Smax.romanov@nginx.com 
13781545Smax.romanov@nginx.com         lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit);
13791545Smax.romanov@nginx.com 
13801555Smax.romanov@nginx.com         if (req->content_length
13811555Smax.romanov@nginx.com             > (uint64_t) (req->content_buf->end - req->content_buf->free))
13821555Smax.romanov@nginx.com         {
13831555Smax.romanov@nginx.com             res = nxt_unit_request_hash_add(ctx, req);
13841555Smax.romanov@nginx.com             if (nxt_slow_path(res != NXT_UNIT_OK)) {
13851555Smax.romanov@nginx.com                 nxt_unit_req_warn(req, "failed to add request to hash");
13861555Smax.romanov@nginx.com 
13871555Smax.romanov@nginx.com                 nxt_unit_request_done(req, NXT_UNIT_ERROR);
13881555Smax.romanov@nginx.com 
13891555Smax.romanov@nginx.com                 return NXT_UNIT_ERROR;
13901555Smax.romanov@nginx.com             }
13911555Smax.romanov@nginx.com 
13921555Smax.romanov@nginx.com             /*
13931555Smax.romanov@nginx.com              * If application have separate data handler, we may start
13941555Smax.romanov@nginx.com              * request processing and process data when it is arrived.
13951555Smax.romanov@nginx.com              */
13961555Smax.romanov@nginx.com             if (lib->callbacks.data_handler == NULL) {
13971555Smax.romanov@nginx.com                 return NXT_UNIT_OK;
13981555Smax.romanov@nginx.com             }
13991555Smax.romanov@nginx.com         }
14001555Smax.romanov@nginx.com 
14011713Smax.romanov@nginx.com         if (preq == NULL) {
14021713Smax.romanov@nginx.com             lib->callbacks.request_handler(req);
14031713Smax.romanov@nginx.com 
14041713Smax.romanov@nginx.com         } else {
14051713Smax.romanov@nginx.com             *preq = req;
14061713Smax.romanov@nginx.com         }
14071555Smax.romanov@nginx.com     }
14081555Smax.romanov@nginx.com 
14091555Smax.romanov@nginx.com     return NXT_UNIT_OK;
14101555Smax.romanov@nginx.com }
14111555Smax.romanov@nginx.com 
14121555Smax.romanov@nginx.com 
14131555Smax.romanov@nginx.com static int
nxt_unit_process_req_body(nxt_unit_ctx_t * ctx,nxt_unit_recv_msg_t * recv_msg)14141555Smax.romanov@nginx.com nxt_unit_process_req_body(nxt_unit_ctx_t *ctx, nxt_unit_recv_msg_t *recv_msg)
14151555Smax.romanov@nginx.com {
14161555Smax.romanov@nginx.com     uint64_t                 l;
14171555Smax.romanov@nginx.com     nxt_unit_impl_t          *lib;
14181555Smax.romanov@nginx.com     nxt_unit_mmap_buf_t      *b;
14191555Smax.romanov@nginx.com     nxt_unit_request_info_t  *req;
14201555Smax.romanov@nginx.com 
14211555Smax.romanov@nginx.com     req = nxt_unit_request_hash_find(ctx, recv_msg->stream, recv_msg->last);
14221555Smax.romanov@nginx.com     if (req == NULL) {
14231555Smax.romanov@nginx.com         return NXT_UNIT_OK;
14241555Smax.romanov@nginx.com     }
14251555Smax.romanov@nginx.com 
14261555Smax.romanov@nginx.com     l = req->content_buf->end - req->content_buf->free;
14271555Smax.romanov@nginx.com 
14281555Smax.romanov@nginx.com     for (b = recv_msg->incoming_buf; b != NULL; b = b->next) {
14291555Smax.romanov@nginx.com         b->req = req;
14301555Smax.romanov@nginx.com         l += b->buf.end - b->buf.free;
14311555Smax.romanov@nginx.com     }
14321555Smax.romanov@nginx.com 
14331555Smax.romanov@nginx.com     if (recv_msg->incoming_buf != NULL) {
14341555Smax.romanov@nginx.com         b = nxt_container_of(req->content_buf, nxt_unit_mmap_buf_t, buf);
14351555Smax.romanov@nginx.com 
14361698Smax.romanov@nginx.com         while (b->next != NULL) {
14371698Smax.romanov@nginx.com             b = b->next;
14381698Smax.romanov@nginx.com         }
14391698Smax.romanov@nginx.com 
14401555Smax.romanov@nginx.com         /* "Move" incoming buffer list to req_impl. */
14411698Smax.romanov@nginx.com         b->next = recv_msg->incoming_buf;
14421698Smax.romanov@nginx.com         b->next->prev = &b->next;
14431698Smax.romanov@nginx.com 
14441555Smax.romanov@nginx.com         recv_msg->incoming_buf = NULL;
14451555Smax.romanov@nginx.com     }
14461555Smax.romanov@nginx.com 
14471558Smax.romanov@nginx.com     req->content_fd = recv_msg->fd[0];
14481558Smax.romanov@nginx.com     recv_msg->fd[0] = -1;
14491555Smax.romanov@nginx.com 
14501555Smax.romanov@nginx.com     lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit);
14511555Smax.romanov@nginx.com 
14521555Smax.romanov@nginx.com     if (lib->callbacks.data_handler != NULL) {
14531555Smax.romanov@nginx.com         lib->callbacks.data_handler(req);
14541555Smax.romanov@nginx.com 
14551555Smax.romanov@nginx.com         return NXT_UNIT_OK;
14561555Smax.romanov@nginx.com     }
14571555Smax.romanov@nginx.com 
14581555Smax.romanov@nginx.com     if (req->content_fd != -1 || l == req->content_length) {
14591545Smax.romanov@nginx.com         lib->callbacks.request_handler(req);
14601545Smax.romanov@nginx.com     }
14611131Smax.romanov@nginx.com 
14621131Smax.romanov@nginx.com     return NXT_UNIT_OK;
14631131Smax.romanov@nginx.com }
14641131Smax.romanov@nginx.com 
14651131Smax.romanov@nginx.com 
14661131Smax.romanov@nginx.com static int
nxt_unit_request_check_response_port(nxt_unit_request_info_t * req,nxt_unit_port_id_t * port_id)14671545Smax.romanov@nginx.com nxt_unit_request_check_response_port(nxt_unit_request_info_t *req,
14681545Smax.romanov@nginx.com     nxt_unit_port_id_t *port_id)
14691545Smax.romanov@nginx.com {
14701545Smax.romanov@nginx.com     int                           res;
14711545Smax.romanov@nginx.com     nxt_unit_ctx_t                *ctx;
14721545Smax.romanov@nginx.com     nxt_unit_impl_t               *lib;
14731545Smax.romanov@nginx.com     nxt_unit_port_t               *port;
14741548Smax.romanov@nginx.com     nxt_unit_process_t            *process;
14751545Smax.romanov@nginx.com     nxt_unit_ctx_impl_t           *ctx_impl;
14761545Smax.romanov@nginx.com     nxt_unit_port_impl_t          *port_impl;
14771545Smax.romanov@nginx.com     nxt_unit_request_info_impl_t  *req_impl;
14781545Smax.romanov@nginx.com 
14791545Smax.romanov@nginx.com     ctx = req->ctx;
14801545Smax.romanov@nginx.com     lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit);
14811545Smax.romanov@nginx.com     ctx_impl = nxt_container_of(ctx, nxt_unit_ctx_impl_t, ctx);
14821545Smax.romanov@nginx.com 
14831545Smax.romanov@nginx.com     pthread_mutex_lock(&lib->mutex);
14841545Smax.romanov@nginx.com 
14851545Smax.romanov@nginx.com     port = nxt_unit_port_hash_find(&lib->ports, port_id, 0);
14861545Smax.romanov@nginx.com     port_impl = nxt_container_of(port, nxt_unit_port_impl_t, port);
14871545Smax.romanov@nginx.com 
14882748Szelenkov@nginx.com     if (nxt_fast_path(port != NULL)) {
14891545Smax.romanov@nginx.com         req->response_port = port;
14901545Smax.romanov@nginx.com 
14911545Smax.romanov@nginx.com         if (nxt_fast_path(port_impl->ready)) {
14921545Smax.romanov@nginx.com             pthread_mutex_unlock(&lib->mutex);
14931545Smax.romanov@nginx.com 
14941545Smax.romanov@nginx.com             nxt_unit_debug(ctx, "check_response_port: found port{%d,%d}",
14951545Smax.romanov@nginx.com                            (int) port->id.pid, (int) port->id.id);
14961545Smax.romanov@nginx.com 
14971545Smax.romanov@nginx.com             return NXT_UNIT_OK;
14981545Smax.romanov@nginx.com         }
14991545Smax.romanov@nginx.com 
15001545Smax.romanov@nginx.com         nxt_unit_debug(ctx, "check_response_port: "
15011545Smax.romanov@nginx.com                        "port{%d,%d} already requested",
15021545Smax.romanov@nginx.com                        (int) port->id.pid, (int) port->id.id);
15031545Smax.romanov@nginx.com 
15041545Smax.romanov@nginx.com         req_impl = nxt_container_of(req, nxt_unit_request_info_impl_t, req);
15051545Smax.romanov@nginx.com 
15061545Smax.romanov@nginx.com         nxt_queue_insert_tail(&port_impl->awaiting_req,
15071545Smax.romanov@nginx.com                               &req_impl->port_wait_link);
15081545Smax.romanov@nginx.com 
15091545Smax.romanov@nginx.com         pthread_mutex_unlock(&lib->mutex);
15101545Smax.romanov@nginx.com 
15111545Smax.romanov@nginx.com         nxt_atomic_fetch_add(&ctx_impl->wait_items, 1);
15121545Smax.romanov@nginx.com 
15131545Smax.romanov@nginx.com         return NXT_UNIT_AGAIN;
15141545Smax.romanov@nginx.com     }
15151545Smax.romanov@nginx.com 
15161623Smax.romanov@nginx.com     port_impl = nxt_unit_malloc(ctx, sizeof(nxt_unit_port_impl_t));
15171545Smax.romanov@nginx.com     if (nxt_slow_path(port_impl == NULL)) {
15181545Smax.romanov@nginx.com         nxt_unit_alert(ctx, "check_response_port: malloc(%d) failed",
15191545Smax.romanov@nginx.com                        (int) sizeof(nxt_unit_port_impl_t));
15201545Smax.romanov@nginx.com 
15211545Smax.romanov@nginx.com         pthread_mutex_unlock(&lib->mutex);
15221545Smax.romanov@nginx.com 
15231545Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
15241545Smax.romanov@nginx.com     }
15251545Smax.romanov@nginx.com 
15261545Smax.romanov@nginx.com     port = &port_impl->port;
15271545Smax.romanov@nginx.com 
15281545Smax.romanov@nginx.com     port->id = *port_id;
15291545Smax.romanov@nginx.com     port->in_fd = -1;
15301545Smax.romanov@nginx.com     port->out_fd = -1;
15311545Smax.romanov@nginx.com     port->data = NULL;
15321545Smax.romanov@nginx.com 
15331545Smax.romanov@nginx.com     res = nxt_unit_port_hash_add(&lib->ports, port);
15341545Smax.romanov@nginx.com     if (nxt_slow_path(res != NXT_UNIT_OK)) {
15351545Smax.romanov@nginx.com         nxt_unit_alert(ctx, "check_response_port: %d,%d hash_add failed",
15361545Smax.romanov@nginx.com                        port->id.pid, port->id.id);
15371545Smax.romanov@nginx.com 
15381545Smax.romanov@nginx.com         pthread_mutex_unlock(&lib->mutex);
15391545Smax.romanov@nginx.com 
15401623Smax.romanov@nginx.com         nxt_unit_free(ctx, port);
15411545Smax.romanov@nginx.com 
15421545Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
15431545Smax.romanov@nginx.com     }
15441545Smax.romanov@nginx.com 
15451548Smax.romanov@nginx.com     process = nxt_unit_process_find(lib, port_id->pid, 0);
15461548Smax.romanov@nginx.com     if (nxt_slow_path(process == NULL)) {
15471548Smax.romanov@nginx.com         nxt_unit_alert(ctx, "check_response_port: process %d not found",
15481548Smax.romanov@nginx.com                        port->id.pid);
15491548Smax.romanov@nginx.com 
15501548Smax.romanov@nginx.com         nxt_unit_port_hash_find(&lib->ports, port_id, 1);
15511548Smax.romanov@nginx.com 
15521548Smax.romanov@nginx.com         pthread_mutex_unlock(&lib->mutex);
15531548Smax.romanov@nginx.com 
15541623Smax.romanov@nginx.com         nxt_unit_free(ctx, port);
15551548Smax.romanov@nginx.com 
15561548Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
15571548Smax.romanov@nginx.com     }
15581548Smax.romanov@nginx.com 
15591548Smax.romanov@nginx.com     nxt_queue_insert_tail(&process->ports, &port_impl->link);
15601548Smax.romanov@nginx.com 
15611548Smax.romanov@nginx.com     port_impl->process = process;
15621555Smax.romanov@nginx.com     port_impl->queue = NULL;
15631555Smax.romanov@nginx.com     port_impl->from_socket = 0;
15641555Smax.romanov@nginx.com     port_impl->socket_rbuf = NULL;
15651545Smax.romanov@nginx.com 
15661545Smax.romanov@nginx.com     nxt_queue_init(&port_impl->awaiting_req);
15671545Smax.romanov@nginx.com 
15681548Smax.romanov@nginx.com     req_impl = nxt_container_of(req, nxt_unit_request_info_impl_t, req);
15691548Smax.romanov@nginx.com 
15701545Smax.romanov@nginx.com     nxt_queue_insert_tail(&port_impl->awaiting_req, &req_impl->port_wait_link);
15711545Smax.romanov@nginx.com 
15721545Smax.romanov@nginx.com     port_impl->use_count = 2;
15731545Smax.romanov@nginx.com     port_impl->ready = 0;
15741545Smax.romanov@nginx.com 
15751545Smax.romanov@nginx.com     req->response_port = port;
15761545Smax.romanov@nginx.com 
15771545Smax.romanov@nginx.com     pthread_mutex_unlock(&lib->mutex);
15781545Smax.romanov@nginx.com 
15791545Smax.romanov@nginx.com     res = nxt_unit_get_port(ctx, port_id);
15801545Smax.romanov@nginx.com     if (nxt_slow_path(res == NXT_UNIT_ERROR)) {
15811545Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
15821545Smax.romanov@nginx.com     }
15831545Smax.romanov@nginx.com 
15841545Smax.romanov@nginx.com     nxt_atomic_fetch_add(&ctx_impl->wait_items, 1);
15851545Smax.romanov@nginx.com 
15861545Smax.romanov@nginx.com     return NXT_UNIT_AGAIN;
15871545Smax.romanov@nginx.com }
15881545Smax.romanov@nginx.com 
15891545Smax.romanov@nginx.com 
15901545Smax.romanov@nginx.com static int
nxt_unit_send_req_headers_ack(nxt_unit_request_info_t * req)15911547Smax.romanov@nginx.com nxt_unit_send_req_headers_ack(nxt_unit_request_info_t *req)
15921547Smax.romanov@nginx.com {
15931547Smax.romanov@nginx.com     ssize_t                       res;
15941547Smax.romanov@nginx.com     nxt_port_msg_t                msg;
15951547Smax.romanov@nginx.com     nxt_unit_impl_t               *lib;
15961547Smax.romanov@nginx.com     nxt_unit_ctx_impl_t           *ctx_impl;
15971547Smax.romanov@nginx.com     nxt_unit_request_info_impl_t  *req_impl;
15981547Smax.romanov@nginx.com 
15991547Smax.romanov@nginx.com     lib = nxt_container_of(req->ctx->unit, nxt_unit_impl_t, unit);
16001547Smax.romanov@nginx.com     ctx_impl = nxt_container_of(req->ctx, nxt_unit_ctx_impl_t, ctx);
16011547Smax.romanov@nginx.com     req_impl = nxt_container_of(req, nxt_unit_request_info_impl_t, req);
16021547Smax.romanov@nginx.com 
16031547Smax.romanov@nginx.com     memset(&msg, 0, sizeof(nxt_port_msg_t));
16041547Smax.romanov@nginx.com 
16051547Smax.romanov@nginx.com     msg.stream = req_impl->stream;
16061547Smax.romanov@nginx.com     msg.pid = lib->pid;
16071547Smax.romanov@nginx.com     msg.reply_port = ctx_impl->read_port->id.id;
16081547Smax.romanov@nginx.com     msg.type = _NXT_PORT_MSG_REQ_HEADERS_ACK;
16091547Smax.romanov@nginx.com 
16101547Smax.romanov@nginx.com     res = nxt_unit_port_send(req->ctx, req->response_port,
16111996St.nateldemoura@f5.com                              &msg, sizeof(msg), NULL);
16121547Smax.romanov@nginx.com     if (nxt_slow_path(res != sizeof(msg))) {
16131547Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
16141547Smax.romanov@nginx.com     }
16151547Smax.romanov@nginx.com 
16161547Smax.romanov@nginx.com     return NXT_UNIT_OK;
16171547Smax.romanov@nginx.com }
16181547Smax.romanov@nginx.com 
16191547Smax.romanov@nginx.com 
16201547Smax.romanov@nginx.com static int
nxt_unit_process_websocket(nxt_unit_ctx_t * ctx,nxt_unit_recv_msg_t * recv_msg)16211131Smax.romanov@nginx.com nxt_unit_process_websocket(nxt_unit_ctx_t *ctx, nxt_unit_recv_msg_t *recv_msg)
16221131Smax.romanov@nginx.com {
16231131Smax.romanov@nginx.com     size_t                           hsize;
16241131Smax.romanov@nginx.com     nxt_unit_impl_t                  *lib;
16251131Smax.romanov@nginx.com     nxt_unit_mmap_buf_t              *b;
16261131Smax.romanov@nginx.com     nxt_unit_callbacks_t             *cb;
16271131Smax.romanov@nginx.com     nxt_unit_request_info_t          *req;
16281131Smax.romanov@nginx.com     nxt_unit_request_info_impl_t     *req_impl;
16291131Smax.romanov@nginx.com     nxt_unit_websocket_frame_impl_t  *ws_impl;
16301131Smax.romanov@nginx.com 
16311555Smax.romanov@nginx.com     req = nxt_unit_request_hash_find(ctx, recv_msg->stream, recv_msg->last);
16321555Smax.romanov@nginx.com     if (nxt_slow_path(req == NULL)) {
16331131Smax.romanov@nginx.com         return NXT_UNIT_OK;
16341131Smax.romanov@nginx.com     }
16351131Smax.romanov@nginx.com 
16361555Smax.romanov@nginx.com     req_impl = nxt_container_of(req, nxt_unit_request_info_impl_t, req);
16371131Smax.romanov@nginx.com 
16381131Smax.romanov@nginx.com     lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit);
16391131Smax.romanov@nginx.com     cb = &lib->callbacks;
16401131Smax.romanov@nginx.com 
16411131Smax.romanov@nginx.com     if (cb->websocket_handler && recv_msg->size >= 2) {
16421131Smax.romanov@nginx.com         ws_impl = nxt_unit_websocket_frame_get(ctx);
16431131Smax.romanov@nginx.com         if (nxt_slow_path(ws_impl == NULL)) {
16441131Smax.romanov@nginx.com             nxt_unit_warn(ctx, "#%"PRIu32": websocket frame allocation failed",
16451131Smax.romanov@nginx.com                           req_impl->stream);
16461131Smax.romanov@nginx.com 
16471131Smax.romanov@nginx.com             return NXT_UNIT_ERROR;
16481131Smax.romanov@nginx.com         }
16491131Smax.romanov@nginx.com 
16501131Smax.romanov@nginx.com         ws_impl->ws.req = req;
16511131Smax.romanov@nginx.com 
16521131Smax.romanov@nginx.com         ws_impl->buf = NULL;
16531131Smax.romanov@nginx.com 
16541131Smax.romanov@nginx.com         if (recv_msg->mmap) {
16551131Smax.romanov@nginx.com             for (b = recv_msg->incoming_buf; b != NULL; b = b->next) {
16561131Smax.romanov@nginx.com                 b->req = req;
16571131Smax.romanov@nginx.com             }
16581131Smax.romanov@nginx.com 
16591131Smax.romanov@nginx.com             /* "Move" incoming buffer list to ws_impl. */
16601131Smax.romanov@nginx.com             ws_impl->buf = recv_msg->incoming_buf;
16611131Smax.romanov@nginx.com             ws_impl->buf->prev = &ws_impl->buf;
16621131Smax.romanov@nginx.com             recv_msg->incoming_buf = NULL;
16631131Smax.romanov@nginx.com 
16641131Smax.romanov@nginx.com             b = ws_impl->buf;
16651131Smax.romanov@nginx.com 
16661131Smax.romanov@nginx.com         } else {
16671131Smax.romanov@nginx.com             b = nxt_unit_mmap_buf_get(ctx);
16681131Smax.romanov@nginx.com             if (nxt_slow_path(b == NULL)) {
16691176Smax.romanov@nginx.com                 nxt_unit_alert(ctx, "#%"PRIu32": failed to allocate buf",
16701176Smax.romanov@nginx.com                                req_impl->stream);
16711176Smax.romanov@nginx.com 
16721181Smax.romanov@nginx.com                 nxt_unit_websocket_frame_release(&ws_impl->ws);
16731181Smax.romanov@nginx.com 
16741131Smax.romanov@nginx.com                 return NXT_UNIT_ERROR;
16751131Smax.romanov@nginx.com             }
16761131Smax.romanov@nginx.com 
16771131Smax.romanov@nginx.com             b->req = req;
16781131Smax.romanov@nginx.com             b->buf.start = recv_msg->start;
16791131Smax.romanov@nginx.com             b->buf.free = b->buf.start;
16801131Smax.romanov@nginx.com             b->buf.end = b->buf.start + recv_msg->size;
16811131Smax.romanov@nginx.com 
16821131Smax.romanov@nginx.com             nxt_unit_mmap_buf_insert(&ws_impl->buf, b);
16831131Smax.romanov@nginx.com         }
16841131Smax.romanov@nginx.com 
16851131Smax.romanov@nginx.com         ws_impl->ws.header = (void *) b->buf.start;
16861131Smax.romanov@nginx.com         ws_impl->ws.payload_len = nxt_websocket_frame_payload_len(
16871131Smax.romanov@nginx.com             ws_impl->ws.header);
16881131Smax.romanov@nginx.com 
16891131Smax.romanov@nginx.com         hsize = nxt_websocket_frame_header_size(ws_impl->ws.header);
16901131Smax.romanov@nginx.com 
16911131Smax.romanov@nginx.com         if (ws_impl->ws.header->mask) {
16921131Smax.romanov@nginx.com             ws_impl->ws.mask = (uint8_t *) b->buf.start + hsize - 4;
16931131Smax.romanov@nginx.com 
16941131Smax.romanov@nginx.com         } else {
16951131Smax.romanov@nginx.com             ws_impl->ws.mask = NULL;
16961131Smax.romanov@nginx.com         }
16971131Smax.romanov@nginx.com 
16981131Smax.romanov@nginx.com         b->buf.free += hsize;
16991131Smax.romanov@nginx.com 
17001131Smax.romanov@nginx.com         ws_impl->ws.content_buf = &b->buf;
17011131Smax.romanov@nginx.com         ws_impl->ws.content_length = ws_impl->ws.payload_len;
17021131Smax.romanov@nginx.com 
17031131Smax.romanov@nginx.com         nxt_unit_req_debug(req, "websocket_handler: opcode=%d, "
17041131Smax.romanov@nginx.com                            "payload_len=%"PRIu64,
17051131Smax.romanov@nginx.com                             ws_impl->ws.header->opcode,
17061131Smax.romanov@nginx.com                             ws_impl->ws.payload_len);
17071131Smax.romanov@nginx.com 
17081131Smax.romanov@nginx.com         cb->websocket_handler(&ws_impl->ws);
17091131Smax.romanov@nginx.com     }
17101131Smax.romanov@nginx.com 
17111131Smax.romanov@nginx.com     if (recv_msg->last) {
17121131Smax.romanov@nginx.com         if (cb->close_handler) {
17131131Smax.romanov@nginx.com             nxt_unit_req_debug(req, "close_handler");
17141131Smax.romanov@nginx.com 
17151131Smax.romanov@nginx.com             cb->close_handler(req);
17161131Smax.romanov@nginx.com 
17171131Smax.romanov@nginx.com         } else {
17181131Smax.romanov@nginx.com             nxt_unit_request_done(req, NXT_UNIT_ERROR);
17191131Smax.romanov@nginx.com         }
17201131Smax.romanov@nginx.com     }
17211131Smax.romanov@nginx.com 
17221131Smax.romanov@nginx.com     return NXT_UNIT_OK;
17231131Smax.romanov@nginx.com }
17241131Smax.romanov@nginx.com 
17251131Smax.romanov@nginx.com 
17261321Smax.romanov@nginx.com static int
nxt_unit_process_shm_ack(nxt_unit_ctx_t * ctx)17271321Smax.romanov@nginx.com nxt_unit_process_shm_ack(nxt_unit_ctx_t *ctx)
17281321Smax.romanov@nginx.com {
17291321Smax.romanov@nginx.com     nxt_unit_impl_t       *lib;
17301321Smax.romanov@nginx.com     nxt_unit_callbacks_t  *cb;
17311321Smax.romanov@nginx.com 
17321321Smax.romanov@nginx.com     lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit);
17331321Smax.romanov@nginx.com     cb = &lib->callbacks;
17341321Smax.romanov@nginx.com 
17351321Smax.romanov@nginx.com     if (cb->shm_ack_handler != NULL) {
17361321Smax.romanov@nginx.com         cb->shm_ack_handler(ctx);
17371321Smax.romanov@nginx.com     }
17381321Smax.romanov@nginx.com 
17391321Smax.romanov@nginx.com     return NXT_UNIT_OK;
17401321Smax.romanov@nginx.com }
17411321Smax.romanov@nginx.com 
17421321Smax.romanov@nginx.com 
1743743Smax.romanov@nginx.com static nxt_unit_request_info_impl_t *
nxt_unit_request_info_get(nxt_unit_ctx_t * ctx)1744743Smax.romanov@nginx.com nxt_unit_request_info_get(nxt_unit_ctx_t *ctx)
1745743Smax.romanov@nginx.com {
1746743Smax.romanov@nginx.com     nxt_unit_impl_t               *lib;
1747743Smax.romanov@nginx.com     nxt_queue_link_t              *lnk;
1748743Smax.romanov@nginx.com     nxt_unit_ctx_impl_t           *ctx_impl;
1749743Smax.romanov@nginx.com     nxt_unit_request_info_impl_t  *req_impl;
1750743Smax.romanov@nginx.com 
1751743Smax.romanov@nginx.com     ctx_impl = nxt_container_of(ctx, nxt_unit_ctx_impl_t, ctx);
1752743Smax.romanov@nginx.com 
1753743Smax.romanov@nginx.com     lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit);
1754743Smax.romanov@nginx.com 
17551175Smax.romanov@nginx.com     pthread_mutex_lock(&ctx_impl->mutex);
17561175Smax.romanov@nginx.com 
1757743Smax.romanov@nginx.com     if (nxt_queue_is_empty(&ctx_impl->free_req)) {
17581175Smax.romanov@nginx.com         pthread_mutex_unlock(&ctx_impl->mutex);
17591175Smax.romanov@nginx.com 
17601623Smax.romanov@nginx.com         req_impl = nxt_unit_malloc(ctx, sizeof(nxt_unit_request_info_impl_t)
17611623Smax.romanov@nginx.com                                         + lib->request_data_size);
1762743Smax.romanov@nginx.com         if (nxt_slow_path(req_impl == NULL)) {
1763743Smax.romanov@nginx.com             return NULL;
1764743Smax.romanov@nginx.com         }
1765743Smax.romanov@nginx.com 
1766743Smax.romanov@nginx.com         req_impl->req.unit = ctx->unit;
1767743Smax.romanov@nginx.com         req_impl->req.ctx = ctx;
1768743Smax.romanov@nginx.com 
17691175Smax.romanov@nginx.com         pthread_mutex_lock(&ctx_impl->mutex);
17701175Smax.romanov@nginx.com 
1771743Smax.romanov@nginx.com     } else {
1772743Smax.romanov@nginx.com         lnk = nxt_queue_first(&ctx_impl->free_req);
1773743Smax.romanov@nginx.com         nxt_queue_remove(lnk);
1774743Smax.romanov@nginx.com 
1775743Smax.romanov@nginx.com         req_impl = nxt_container_of(lnk, nxt_unit_request_info_impl_t, link);
1776743Smax.romanov@nginx.com     }
1777743Smax.romanov@nginx.com 
1778743Smax.romanov@nginx.com     nxt_queue_insert_tail(&ctx_impl->active_req, &req_impl->link);
1779743Smax.romanov@nginx.com 
17801175Smax.romanov@nginx.com     pthread_mutex_unlock(&ctx_impl->mutex);
17811175Smax.romanov@nginx.com 
1782743Smax.romanov@nginx.com     req_impl->req.data = lib->request_data_size ? req_impl->extra_data : NULL;
1783743Smax.romanov@nginx.com 
1784743Smax.romanov@nginx.com     return req_impl;
1785743Smax.romanov@nginx.com }
1786743Smax.romanov@nginx.com 
1787743Smax.romanov@nginx.com 
1788743Smax.romanov@nginx.com static void
nxt_unit_request_info_release(nxt_unit_request_info_t * req)1789743Smax.romanov@nginx.com nxt_unit_request_info_release(nxt_unit_request_info_t *req)
1790743Smax.romanov@nginx.com {
17911980Smax.romanov@nginx.com     nxt_unit_ctx_t                *ctx;
1792743Smax.romanov@nginx.com     nxt_unit_ctx_impl_t           *ctx_impl;
1793743Smax.romanov@nginx.com     nxt_unit_request_info_impl_t  *req_impl;
1794743Smax.romanov@nginx.com 
17951980Smax.romanov@nginx.com     ctx = req->ctx;
17961980Smax.romanov@nginx.com     ctx_impl = nxt_container_of(ctx, nxt_unit_ctx_impl_t, ctx);
1797743Smax.romanov@nginx.com     req_impl = nxt_container_of(req, nxt_unit_request_info_impl_t, req);
1798743Smax.romanov@nginx.com 
1799743Smax.romanov@nginx.com     req->response = NULL;
1800743Smax.romanov@nginx.com     req->response_buf = NULL;
1801743Smax.romanov@nginx.com 
18021555Smax.romanov@nginx.com     if (req_impl->in_hash) {
18031555Smax.romanov@nginx.com         nxt_unit_request_hash_find(req->ctx, req_impl->stream, 1);
18041555Smax.romanov@nginx.com     }
18051555Smax.romanov@nginx.com 
18061131Smax.romanov@nginx.com     while (req_impl->outgoing_buf != NULL) {
18071131Smax.romanov@nginx.com         nxt_unit_mmap_buf_free(req_impl->outgoing_buf);
18081131Smax.romanov@nginx.com     }
18091131Smax.romanov@nginx.com 
18101131Smax.romanov@nginx.com     while (req_impl->incoming_buf != NULL) {
18111131Smax.romanov@nginx.com         nxt_unit_mmap_buf_free(req_impl->incoming_buf);
18121131Smax.romanov@nginx.com     }
1813743Smax.romanov@nginx.com 
18141403Smax.romanov@nginx.com     if (req->content_fd != -1) {
18151556Smax.romanov@nginx.com         nxt_unit_close(req->content_fd);
18161403Smax.romanov@nginx.com 
18171403Smax.romanov@nginx.com         req->content_fd = -1;
18181403Smax.romanov@nginx.com     }
18191403Smax.romanov@nginx.com 
18201544Smax.romanov@nginx.com     if (req->response_port != NULL) {
18211544Smax.romanov@nginx.com         nxt_unit_port_release(req->response_port);
18221544Smax.romanov@nginx.com 
18231544Smax.romanov@nginx.com         req->response_port = NULL;
18241544Smax.romanov@nginx.com     }
18251544Smax.romanov@nginx.com 
18261712Smax.romanov@nginx.com     req_impl->state = NXT_UNIT_RS_RELEASED;
18271712Smax.romanov@nginx.com 
18281175Smax.romanov@nginx.com     pthread_mutex_lock(&ctx_impl->mutex);
18291175Smax.romanov@nginx.com 
1830743Smax.romanov@nginx.com     nxt_queue_remove(&req_impl->link);
1831743Smax.romanov@nginx.com 
1832743Smax.romanov@nginx.com     nxt_queue_insert_tail(&ctx_impl->free_req, &req_impl->link);
18331131Smax.romanov@nginx.com 
18341175Smax.romanov@nginx.com     pthread_mutex_unlock(&ctx_impl->mutex);
18351980Smax.romanov@nginx.com 
18361980Smax.romanov@nginx.com     if (nxt_slow_path(!nxt_unit_chk_ready(ctx))) {
18371980Smax.romanov@nginx.com         nxt_unit_quit(ctx, NXT_QUIT_GRACEFUL);
18381980Smax.romanov@nginx.com     }
1839743Smax.romanov@nginx.com }
1840743Smax.romanov@nginx.com 
1841743Smax.romanov@nginx.com 
1842743Smax.romanov@nginx.com static void
nxt_unit_request_info_free(nxt_unit_request_info_impl_t * req_impl)1843743Smax.romanov@nginx.com nxt_unit_request_info_free(nxt_unit_request_info_impl_t *req_impl)
1844743Smax.romanov@nginx.com {
1845743Smax.romanov@nginx.com     nxt_unit_ctx_impl_t  *ctx_impl;
1846743Smax.romanov@nginx.com 
1847743Smax.romanov@nginx.com     ctx_impl = nxt_container_of(req_impl->req.ctx, nxt_unit_ctx_impl_t, ctx);
1848743Smax.romanov@nginx.com 
1849743Smax.romanov@nginx.com     nxt_queue_remove(&req_impl->link);
1850743Smax.romanov@nginx.com 
1851743Smax.romanov@nginx.com     if (req_impl != &ctx_impl->req) {
18521623Smax.romanov@nginx.com         nxt_unit_free(&ctx_impl->ctx, req_impl);
1853743Smax.romanov@nginx.com     }
1854743Smax.romanov@nginx.com }
1855743Smax.romanov@nginx.com 
1856743Smax.romanov@nginx.com 
18571131Smax.romanov@nginx.com static nxt_unit_websocket_frame_impl_t *
nxt_unit_websocket_frame_get(nxt_unit_ctx_t * ctx)18581131Smax.romanov@nginx.com nxt_unit_websocket_frame_get(nxt_unit_ctx_t *ctx)
18591131Smax.romanov@nginx.com {
18601131Smax.romanov@nginx.com     nxt_queue_link_t                 *lnk;
18611131Smax.romanov@nginx.com     nxt_unit_ctx_impl_t              *ctx_impl;
18621131Smax.romanov@nginx.com     nxt_unit_websocket_frame_impl_t  *ws_impl;
18631131Smax.romanov@nginx.com 
18641131Smax.romanov@nginx.com     ctx_impl = nxt_container_of(ctx, nxt_unit_ctx_impl_t, ctx);
18651131Smax.romanov@nginx.com 
18661175Smax.romanov@nginx.com     pthread_mutex_lock(&ctx_impl->mutex);
18671175Smax.romanov@nginx.com 
18681131Smax.romanov@nginx.com     if (nxt_queue_is_empty(&ctx_impl->free_ws)) {
18691175Smax.romanov@nginx.com         pthread_mutex_unlock(&ctx_impl->mutex);
18701175Smax.romanov@nginx.com 
18711623Smax.romanov@nginx.com         ws_impl = nxt_unit_malloc(ctx, sizeof(nxt_unit_websocket_frame_impl_t));
18721131Smax.romanov@nginx.com         if (nxt_slow_path(ws_impl == NULL)) {
18731131Smax.romanov@nginx.com             return NULL;
18741131Smax.romanov@nginx.com         }
18751131Smax.romanov@nginx.com 
18761131Smax.romanov@nginx.com     } else {
18771131Smax.romanov@nginx.com         lnk = nxt_queue_first(&ctx_impl->free_ws);
18781131Smax.romanov@nginx.com         nxt_queue_remove(lnk);
18791131Smax.romanov@nginx.com 
18801175Smax.romanov@nginx.com         pthread_mutex_unlock(&ctx_impl->mutex);
18811175Smax.romanov@nginx.com 
18821131Smax.romanov@nginx.com         ws_impl = nxt_container_of(lnk, nxt_unit_websocket_frame_impl_t, link);
18831131Smax.romanov@nginx.com     }
18841131Smax.romanov@nginx.com 
18851131Smax.romanov@nginx.com     ws_impl->ctx_impl = ctx_impl;
18861131Smax.romanov@nginx.com 
18871131Smax.romanov@nginx.com     return ws_impl;
18881131Smax.romanov@nginx.com }
18891131Smax.romanov@nginx.com 
18901131Smax.romanov@nginx.com 
18911131Smax.romanov@nginx.com static void
nxt_unit_websocket_frame_release(nxt_unit_websocket_frame_t * ws)18921131Smax.romanov@nginx.com nxt_unit_websocket_frame_release(nxt_unit_websocket_frame_t *ws)
18931131Smax.romanov@nginx.com {
18941131Smax.romanov@nginx.com     nxt_unit_websocket_frame_impl_t  *ws_impl;
18951131Smax.romanov@nginx.com 
18961131Smax.romanov@nginx.com     ws_impl = nxt_container_of(ws, nxt_unit_websocket_frame_impl_t, ws);
18971131Smax.romanov@nginx.com 
18981131Smax.romanov@nginx.com     while (ws_impl->buf != NULL) {
18991131Smax.romanov@nginx.com         nxt_unit_mmap_buf_free(ws_impl->buf);
19001131Smax.romanov@nginx.com     }
19011131Smax.romanov@nginx.com 
19021131Smax.romanov@nginx.com     ws->req = NULL;
19031131Smax.romanov@nginx.com 
19041175Smax.romanov@nginx.com     pthread_mutex_lock(&ws_impl->ctx_impl->mutex);
19051175Smax.romanov@nginx.com 
19061131Smax.romanov@nginx.com     nxt_queue_insert_tail(&ws_impl->ctx_impl->free_ws, &ws_impl->link);
19071175Smax.romanov@nginx.com 
19081175Smax.romanov@nginx.com     pthread_mutex_unlock(&ws_impl->ctx_impl->mutex);
19091131Smax.romanov@nginx.com }
19101131Smax.romanov@nginx.com 
19111131Smax.romanov@nginx.com 
19121131Smax.romanov@nginx.com static void
nxt_unit_websocket_frame_free(nxt_unit_ctx_t * ctx,nxt_unit_websocket_frame_impl_t * ws_impl)19131623Smax.romanov@nginx.com nxt_unit_websocket_frame_free(nxt_unit_ctx_t *ctx,
19141623Smax.romanov@nginx.com     nxt_unit_websocket_frame_impl_t *ws_impl)
19151131Smax.romanov@nginx.com {
19161131Smax.romanov@nginx.com     nxt_queue_remove(&ws_impl->link);
19171131Smax.romanov@nginx.com 
19181623Smax.romanov@nginx.com     nxt_unit_free(ctx, ws_impl);
19191131Smax.romanov@nginx.com }
19201131Smax.romanov@nginx.com 
19211131Smax.romanov@nginx.com 
1922743Smax.romanov@nginx.com uint16_t
nxt_unit_field_hash(const char * name,size_t name_length)1923743Smax.romanov@nginx.com nxt_unit_field_hash(const char *name, size_t name_length)
1924743Smax.romanov@nginx.com {
1925743Smax.romanov@nginx.com     u_char      ch;
1926743Smax.romanov@nginx.com     uint32_t    hash;
1927743Smax.romanov@nginx.com     const char  *p, *end;
1928743Smax.romanov@nginx.com 
1929743Smax.romanov@nginx.com     hash = 159406; /* Magic value copied from nxt_http_parse.c */
1930743Smax.romanov@nginx.com     end = name + name_length;
1931743Smax.romanov@nginx.com 
1932743Smax.romanov@nginx.com     for (p = name; p < end; p++) {
1933743Smax.romanov@nginx.com         ch = *p;
1934743Smax.romanov@nginx.com         hash = (hash << 4) + hash + nxt_lowcase(ch);
1935743Smax.romanov@nginx.com     }
1936743Smax.romanov@nginx.com 
1937743Smax.romanov@nginx.com     hash = (hash >> 16) ^ hash;
1938743Smax.romanov@nginx.com 
1939743Smax.romanov@nginx.com     return hash;
1940743Smax.romanov@nginx.com }
1941743Smax.romanov@nginx.com 
1942743Smax.romanov@nginx.com 
1943743Smax.romanov@nginx.com void
nxt_unit_request_group_dup_fields(nxt_unit_request_info_t * req)1944743Smax.romanov@nginx.com nxt_unit_request_group_dup_fields(nxt_unit_request_info_t *req)
1945743Smax.romanov@nginx.com {
19461593Smax.romanov@nginx.com     char                *name;
1947743Smax.romanov@nginx.com     uint32_t            i, j;
1948743Smax.romanov@nginx.com     nxt_unit_field_t    *fields, f;
1949743Smax.romanov@nginx.com     nxt_unit_request_t  *r;
1950743Smax.romanov@nginx.com 
19511593Smax.romanov@nginx.com     static nxt_str_t  content_length = nxt_string("content-length");
19521593Smax.romanov@nginx.com     static nxt_str_t  content_type = nxt_string("content-type");
19531593Smax.romanov@nginx.com     static nxt_str_t  cookie = nxt_string("cookie");
19541593Smax.romanov@nginx.com 
1955743Smax.romanov@nginx.com     nxt_unit_req_debug(req, "group_dup_fields");
1956743Smax.romanov@nginx.com 
1957743Smax.romanov@nginx.com     r = req->request;
1958743Smax.romanov@nginx.com     fields = r->fields;
1959743Smax.romanov@nginx.com 
1960743Smax.romanov@nginx.com     for (i = 0; i < r->fields_count; i++) {
19611593Smax.romanov@nginx.com         name = nxt_unit_sptr_get(&fields[i].name);
1962743Smax.romanov@nginx.com 
1963743Smax.romanov@nginx.com         switch (fields[i].hash) {
1964743Smax.romanov@nginx.com         case NXT_UNIT_HASH_CONTENT_LENGTH:
19651593Smax.romanov@nginx.com             if (fields[i].name_length == content_length.length
19661593Smax.romanov@nginx.com                 && nxt_unit_memcasecmp(name, content_length.start,
19671593Smax.romanov@nginx.com                                        content_length.length) == 0)
19681593Smax.romanov@nginx.com             {
19691593Smax.romanov@nginx.com                 r->content_length_field = i;
19701593Smax.romanov@nginx.com             }
19711593Smax.romanov@nginx.com 
1972743Smax.romanov@nginx.com             break;
1973743Smax.romanov@nginx.com 
1974743Smax.romanov@nginx.com         case NXT_UNIT_HASH_CONTENT_TYPE:
19751593Smax.romanov@nginx.com             if (fields[i].name_length == content_type.length
19761593Smax.romanov@nginx.com                 && nxt_unit_memcasecmp(name, content_type.start,
19771593Smax.romanov@nginx.com                                        content_type.length) == 0)
19781593Smax.romanov@nginx.com             {
19791593Smax.romanov@nginx.com                 r->content_type_field = i;
19801593Smax.romanov@nginx.com             }
19811593Smax.romanov@nginx.com 
1982743Smax.romanov@nginx.com             break;
1983743Smax.romanov@nginx.com 
1984743Smax.romanov@nginx.com         case NXT_UNIT_HASH_COOKIE:
19851593Smax.romanov@nginx.com             if (fields[i].name_length == cookie.length
19861593Smax.romanov@nginx.com                 && nxt_unit_memcasecmp(name, cookie.start,
19871593Smax.romanov@nginx.com                                        cookie.length) == 0)
19881593Smax.romanov@nginx.com             {
19891593Smax.romanov@nginx.com                 r->cookie_field = i;
19901593Smax.romanov@nginx.com             }
19911593Smax.romanov@nginx.com 
1992743Smax.romanov@nginx.com             break;
19931593Smax.romanov@nginx.com         }
1994743Smax.romanov@nginx.com 
1995743Smax.romanov@nginx.com         for (j = i + 1; j < r->fields_count; j++) {
19961593Smax.romanov@nginx.com             if (fields[i].hash != fields[j].hash
19971593Smax.romanov@nginx.com                 || fields[i].name_length != fields[j].name_length
19981593Smax.romanov@nginx.com                 || nxt_unit_memcasecmp(name,
19991593Smax.romanov@nginx.com                                        nxt_unit_sptr_get(&fields[j].name),
20001593Smax.romanov@nginx.com                                        fields[j].name_length) != 0)
20011593Smax.romanov@nginx.com             {
2002743Smax.romanov@nginx.com                 continue;
2003743Smax.romanov@nginx.com             }
2004743Smax.romanov@nginx.com 
2005743Smax.romanov@nginx.com             f = fields[j];
2006743Smax.romanov@nginx.com             f.value.offset += (j - (i + 1)) * sizeof(f);
2007743Smax.romanov@nginx.com 
2008743Smax.romanov@nginx.com             while (j > i + 1) {
2009743Smax.romanov@nginx.com                 fields[j] = fields[j - 1];
2010743Smax.romanov@nginx.com                 fields[j].name.offset -= sizeof(f);
2011743Smax.romanov@nginx.com                 fields[j].value.offset -= sizeof(f);
2012743Smax.romanov@nginx.com                 j--;
2013743Smax.romanov@nginx.com             }
2014743Smax.romanov@nginx.com 
2015743Smax.romanov@nginx.com             fields[j] = f;
2016743Smax.romanov@nginx.com 
20171593Smax.romanov@nginx.com             /* Assign the same name pointer for further grouping simplicity. */
20181593Smax.romanov@nginx.com             nxt_unit_sptr_set(&fields[j].name, name);
20191593Smax.romanov@nginx.com 
2020743Smax.romanov@nginx.com             i++;
2021743Smax.romanov@nginx.com         }
2022743Smax.romanov@nginx.com     }
2023743Smax.romanov@nginx.com }
2024743Smax.romanov@nginx.com 
2025743Smax.romanov@nginx.com 
2026743Smax.romanov@nginx.com int
nxt_unit_response_init(nxt_unit_request_info_t * req,uint16_t status,uint32_t max_fields_count,uint32_t max_fields_size)2027743Smax.romanov@nginx.com nxt_unit_response_init(nxt_unit_request_info_t *req,
2028743Smax.romanov@nginx.com     uint16_t status, uint32_t max_fields_count, uint32_t max_fields_size)
2029743Smax.romanov@nginx.com {
2030743Smax.romanov@nginx.com     uint32_t                      buf_size;
2031743Smax.romanov@nginx.com     nxt_unit_buf_t                *buf;
2032743Smax.romanov@nginx.com     nxt_unit_request_info_impl_t  *req_impl;
2033743Smax.romanov@nginx.com 
2034743Smax.romanov@nginx.com     req_impl = nxt_container_of(req, nxt_unit_request_info_impl_t, req);
2035743Smax.romanov@nginx.com 
2036743Smax.romanov@nginx.com     if (nxt_slow_path(req_impl->state >= NXT_UNIT_RS_RESPONSE_SENT)) {
2037743Smax.romanov@nginx.com         nxt_unit_req_warn(req, "init: response already sent");
2038743Smax.romanov@nginx.com 
2039743Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
2040743Smax.romanov@nginx.com     }
2041743Smax.romanov@nginx.com 
2042743Smax.romanov@nginx.com     nxt_unit_req_debug(req, "init: %d, max fields %d/%d", (int) status,
2043743Smax.romanov@nginx.com                        (int) max_fields_count, (int) max_fields_size);
2044743Smax.romanov@nginx.com 
2045743Smax.romanov@nginx.com     if (nxt_slow_path(req_impl->state >= NXT_UNIT_RS_RESPONSE_INIT)) {
2046743Smax.romanov@nginx.com         nxt_unit_req_debug(req, "duplicate response init");
2047743Smax.romanov@nginx.com     }
2048743Smax.romanov@nginx.com 
20491257Smax.romanov@nginx.com     /*
20501257Smax.romanov@nginx.com      * Each field name and value 0-terminated by libunit,
20511257Smax.romanov@nginx.com      * this is the reason of '+ 2' below.
20521257Smax.romanov@nginx.com      */
2053743Smax.romanov@nginx.com     buf_size = sizeof(nxt_unit_response_t)
20541257Smax.romanov@nginx.com                + max_fields_count * (sizeof(nxt_unit_field_t) + 2)
2055743Smax.romanov@nginx.com                + max_fields_size;
2056743Smax.romanov@nginx.com 
2057743Smax.romanov@nginx.com     if (nxt_slow_path(req->response_buf != NULL)) {
2058743Smax.romanov@nginx.com         buf = req->response_buf;
2059743Smax.romanov@nginx.com 
2060743Smax.romanov@nginx.com         if (nxt_fast_path(buf_size <= (uint32_t) (buf->end - buf->start))) {
2061743Smax.romanov@nginx.com             goto init_response;
2062743Smax.romanov@nginx.com         }
2063743Smax.romanov@nginx.com 
2064743Smax.romanov@nginx.com         nxt_unit_buf_free(buf);
2065743Smax.romanov@nginx.com 
2066743Smax.romanov@nginx.com         req->response_buf = NULL;
2067743Smax.romanov@nginx.com         req->response = NULL;
2068743Smax.romanov@nginx.com         req->response_max_fields = 0;
2069743Smax.romanov@nginx.com 
2070743Smax.romanov@nginx.com         req_impl->state = NXT_UNIT_RS_START;
2071743Smax.romanov@nginx.com     }
2072743Smax.romanov@nginx.com 
2073743Smax.romanov@nginx.com     buf = nxt_unit_response_buf_alloc(req, buf_size);
2074743Smax.romanov@nginx.com     if (nxt_slow_path(buf == NULL)) {
2075743Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
2076743Smax.romanov@nginx.com     }
2077743Smax.romanov@nginx.com 
2078743Smax.romanov@nginx.com init_response:
2079743Smax.romanov@nginx.com 
2080743Smax.romanov@nginx.com     memset(buf->start, 0, sizeof(nxt_unit_response_t));
2081743Smax.romanov@nginx.com 
2082743Smax.romanov@nginx.com     req->response_buf = buf;
2083743Smax.romanov@nginx.com 
2084743Smax.romanov@nginx.com     req->response = (nxt_unit_response_t *) buf->start;
2085743Smax.romanov@nginx.com     req->response->status = status;
2086743Smax.romanov@nginx.com 
2087743Smax.romanov@nginx.com     buf->free = buf->start + sizeof(nxt_unit_response_t)
2088743Smax.romanov@nginx.com                 + max_fields_count * sizeof(nxt_unit_field_t);
2089743Smax.romanov@nginx.com 
2090743Smax.romanov@nginx.com     req->response_max_fields = max_fields_count;
2091743Smax.romanov@nginx.com     req_impl->state = NXT_UNIT_RS_RESPONSE_INIT;
2092743Smax.romanov@nginx.com 
2093743Smax.romanov@nginx.com     return NXT_UNIT_OK;
2094743Smax.romanov@nginx.com }
2095743Smax.romanov@nginx.com 
2096743Smax.romanov@nginx.com 
2097743Smax.romanov@nginx.com int
nxt_unit_response_realloc(nxt_unit_request_info_t * req,uint32_t max_fields_count,uint32_t max_fields_size)2098743Smax.romanov@nginx.com nxt_unit_response_realloc(nxt_unit_request_info_t *req,
2099743Smax.romanov@nginx.com     uint32_t max_fields_count, uint32_t max_fields_size)
2100743Smax.romanov@nginx.com {
2101743Smax.romanov@nginx.com     char                          *p;
2102743Smax.romanov@nginx.com     uint32_t                      i, buf_size;
2103743Smax.romanov@nginx.com     nxt_unit_buf_t                *buf;
2104743Smax.romanov@nginx.com     nxt_unit_field_t              *f, *src;
2105743Smax.romanov@nginx.com     nxt_unit_response_t           *resp;
2106743Smax.romanov@nginx.com     nxt_unit_request_info_impl_t  *req_impl;
2107743Smax.romanov@nginx.com 
2108743Smax.romanov@nginx.com     req_impl = nxt_container_of(req, nxt_unit_request_info_impl_t, req);
2109743Smax.romanov@nginx.com 
2110743Smax.romanov@nginx.com     if (nxt_slow_path(req_impl->state < NXT_UNIT_RS_RESPONSE_INIT)) {
2111743Smax.romanov@nginx.com         nxt_unit_req_warn(req, "realloc: response not init");
2112743Smax.romanov@nginx.com 
2113743Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
2114743Smax.romanov@nginx.com     }
2115743Smax.romanov@nginx.com 
2116743Smax.romanov@nginx.com     if (nxt_slow_path(req_impl->state >= NXT_UNIT_RS_RESPONSE_SENT)) {
2117743Smax.romanov@nginx.com         nxt_unit_req_warn(req, "realloc: response already sent");
2118743Smax.romanov@nginx.com 
2119743Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
2120743Smax.romanov@nginx.com     }
2121743Smax.romanov@nginx.com 
2122743Smax.romanov@nginx.com     if (nxt_slow_path(max_fields_count < req->response->fields_count)) {
2123743Smax.romanov@nginx.com         nxt_unit_req_warn(req, "realloc: new max_fields_count is too small");
2124743Smax.romanov@nginx.com 
2125743Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
2126743Smax.romanov@nginx.com     }
2127743Smax.romanov@nginx.com 
21281257Smax.romanov@nginx.com     /*
21291257Smax.romanov@nginx.com      * Each field name and value 0-terminated by libunit,
21301257Smax.romanov@nginx.com      * this is the reason of '+ 2' below.
21311257Smax.romanov@nginx.com      */
2132743Smax.romanov@nginx.com     buf_size = sizeof(nxt_unit_response_t)
21331257Smax.romanov@nginx.com                + max_fields_count * (sizeof(nxt_unit_field_t) + 2)
2134743Smax.romanov@nginx.com                + max_fields_size;
2135743Smax.romanov@nginx.com 
2136976Smax.romanov@nginx.com     nxt_unit_req_debug(req, "realloc %"PRIu32"", buf_size);
2137976Smax.romanov@nginx.com 
2138743Smax.romanov@nginx.com     buf = nxt_unit_response_buf_alloc(req, buf_size);
2139743Smax.romanov@nginx.com     if (nxt_slow_path(buf == NULL)) {
2140976Smax.romanov@nginx.com         nxt_unit_req_warn(req, "realloc: new buf allocation failed");
2141743Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
2142743Smax.romanov@nginx.com     }
2143743Smax.romanov@nginx.com 
2144743Smax.romanov@nginx.com     resp = (nxt_unit_response_t *) buf->start;
2145743Smax.romanov@nginx.com 
2146743Smax.romanov@nginx.com     memset(resp, 0, sizeof(nxt_unit_response_t));
2147743Smax.romanov@nginx.com 
2148743Smax.romanov@nginx.com     resp->status = req->response->status;
2149743Smax.romanov@nginx.com     resp->content_length = req->response->content_length;
2150743Smax.romanov@nginx.com 
21512561Sz.hong@f5.com     p = buf->start + sizeof(nxt_unit_response_t)
21522561Sz.hong@f5.com         + max_fields_count * sizeof(nxt_unit_field_t);
2153743Smax.romanov@nginx.com     f = resp->fields;
2154743Smax.romanov@nginx.com 
2155743Smax.romanov@nginx.com     for (i = 0; i < req->response->fields_count; i++) {
2156976Smax.romanov@nginx.com         src = req->response->fields + i;
2157743Smax.romanov@nginx.com 
2158743Smax.romanov@nginx.com         if (nxt_slow_path(src->skip != 0)) {
2159743Smax.romanov@nginx.com             continue;
2160743Smax.romanov@nginx.com         }
2161743Smax.romanov@nginx.com 
2162976Smax.romanov@nginx.com         if (nxt_slow_path(src->name_length + src->value_length + 2
2163743Smax.romanov@nginx.com                           > (uint32_t) (buf->end - p)))
2164743Smax.romanov@nginx.com         {
2165976Smax.romanov@nginx.com             nxt_unit_req_warn(req, "realloc: not enough space for field"
2166976Smax.romanov@nginx.com                   " #%"PRIu32" (%p), (%"PRIu32" + %"PRIu32") required",
2167976Smax.romanov@nginx.com                   i, src, src->name_length, src->value_length);
2168976Smax.romanov@nginx.com 
2169743Smax.romanov@nginx.com             goto fail;
2170743Smax.romanov@nginx.com         }
2171743Smax.romanov@nginx.com 
2172743Smax.romanov@nginx.com         nxt_unit_sptr_set(&f->name, p);
2173743Smax.romanov@nginx.com         p = nxt_cpymem(p, nxt_unit_sptr_get(&src->name), src->name_length);
2174976Smax.romanov@nginx.com         *p++ = '\0';
2175743Smax.romanov@nginx.com 
2176743Smax.romanov@nginx.com         nxt_unit_sptr_set(&f->value, p);
2177743Smax.romanov@nginx.com         p = nxt_cpymem(p, nxt_unit_sptr_get(&src->value), src->value_length);
2178976Smax.romanov@nginx.com         *p++ = '\0';
2179743Smax.romanov@nginx.com 
2180743Smax.romanov@nginx.com         f->hash = src->hash;
2181743Smax.romanov@nginx.com         f->skip = 0;
2182743Smax.romanov@nginx.com         f->name_length = src->name_length;
2183743Smax.romanov@nginx.com         f->value_length = src->value_length;
2184743Smax.romanov@nginx.com 
2185743Smax.romanov@nginx.com         resp->fields_count++;
2186743Smax.romanov@nginx.com         f++;
2187743Smax.romanov@nginx.com     }
2188743Smax.romanov@nginx.com 
2189743Smax.romanov@nginx.com     if (req->response->piggyback_content_length > 0) {
2190743Smax.romanov@nginx.com         if (nxt_slow_path(req->response->piggyback_content_length
2191743Smax.romanov@nginx.com                           > (uint32_t) (buf->end - p)))
2192743Smax.romanov@nginx.com         {
2193976Smax.romanov@nginx.com             nxt_unit_req_warn(req, "realloc: not enought space for content"
2194976Smax.romanov@nginx.com                   " #%"PRIu32", %"PRIu32" required",
2195976Smax.romanov@nginx.com                   i, req->response->piggyback_content_length);
2196976Smax.romanov@nginx.com 
2197743Smax.romanov@nginx.com             goto fail;
2198743Smax.romanov@nginx.com         }
2199743Smax.romanov@nginx.com 
22001235Sigor@sysoev.ru         resp->piggyback_content_length =
22011235Sigor@sysoev.ru                                        req->response->piggyback_content_length;
2202743Smax.romanov@nginx.com 
2203743Smax.romanov@nginx.com         nxt_unit_sptr_set(&resp->piggyback_content, p);
2204743Smax.romanov@nginx.com         p = nxt_cpymem(p, nxt_unit_sptr_get(&req->response->piggyback_content),
2205743Smax.romanov@nginx.com                        req->response->piggyback_content_length);
2206743Smax.romanov@nginx.com     }
2207743Smax.romanov@nginx.com 
2208743Smax.romanov@nginx.com     buf->free = p;
2209743Smax.romanov@nginx.com 
2210743Smax.romanov@nginx.com     nxt_unit_buf_free(req->response_buf);
2211743Smax.romanov@nginx.com 
2212743Smax.romanov@nginx.com     req->response = resp;
2213743Smax.romanov@nginx.com     req->response_buf = buf;
2214743Smax.romanov@nginx.com     req->response_max_fields = max_fields_count;
2215743Smax.romanov@nginx.com 
2216743Smax.romanov@nginx.com     return NXT_UNIT_OK;
2217743Smax.romanov@nginx.com 
2218743Smax.romanov@nginx.com fail:
2219743Smax.romanov@nginx.com 
2220743Smax.romanov@nginx.com     nxt_unit_buf_free(buf);
2221743Smax.romanov@nginx.com 
2222743Smax.romanov@nginx.com     return NXT_UNIT_ERROR;
2223743Smax.romanov@nginx.com }
2224743Smax.romanov@nginx.com 
2225743Smax.romanov@nginx.com 
2226743Smax.romanov@nginx.com int
nxt_unit_response_is_init(nxt_unit_request_info_t * req)2227743Smax.romanov@nginx.com nxt_unit_response_is_init(nxt_unit_request_info_t *req)
2228743Smax.romanov@nginx.com {
2229743Smax.romanov@nginx.com     nxt_unit_request_info_impl_t  *req_impl;
2230743Smax.romanov@nginx.com 
2231743Smax.romanov@nginx.com     req_impl = nxt_container_of(req, nxt_unit_request_info_impl_t, req);
2232743Smax.romanov@nginx.com 
2233743Smax.romanov@nginx.com     return req_impl->state >= NXT_UNIT_RS_RESPONSE_INIT;
2234743Smax.romanov@nginx.com }
2235743Smax.romanov@nginx.com 
2236743Smax.romanov@nginx.com 
2237743Smax.romanov@nginx.com int
nxt_unit_response_add_field(nxt_unit_request_info_t * req,const char * name,uint8_t name_length,const char * value,uint32_t value_length)2238743Smax.romanov@nginx.com nxt_unit_response_add_field(nxt_unit_request_info_t *req,
2239743Smax.romanov@nginx.com     const char *name, uint8_t name_length,
2240743Smax.romanov@nginx.com     const char *value, uint32_t value_length)
2241743Smax.romanov@nginx.com {
2242743Smax.romanov@nginx.com     nxt_unit_buf_t                *buf;
2243743Smax.romanov@nginx.com     nxt_unit_field_t              *f;
2244743Smax.romanov@nginx.com     nxt_unit_response_t           *resp;
2245743Smax.romanov@nginx.com     nxt_unit_request_info_impl_t  *req_impl;
2246743Smax.romanov@nginx.com 
2247743Smax.romanov@nginx.com     req_impl = nxt_container_of(req, nxt_unit_request_info_impl_t, req);
2248743Smax.romanov@nginx.com 
2249743Smax.romanov@nginx.com     if (nxt_slow_path(req_impl->state != NXT_UNIT_RS_RESPONSE_INIT)) {
2250743Smax.romanov@nginx.com         nxt_unit_req_warn(req, "add_field: response not initialized or "
2251743Smax.romanov@nginx.com                           "already sent");
2252743Smax.romanov@nginx.com 
2253743Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
2254743Smax.romanov@nginx.com     }
2255743Smax.romanov@nginx.com 
2256743Smax.romanov@nginx.com     resp = req->response;
2257743Smax.romanov@nginx.com 
2258743Smax.romanov@nginx.com     if (nxt_slow_path(resp->fields_count >= req->response_max_fields)) {
22591713Smax.romanov@nginx.com         nxt_unit_req_warn(req, "add_field: too many response fields (%d)",
22601713Smax.romanov@nginx.com                           (int) resp->fields_count);
2261743Smax.romanov@nginx.com 
2262743Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
2263743Smax.romanov@nginx.com     }
2264743Smax.romanov@nginx.com 
2265743Smax.romanov@nginx.com     buf = req->response_buf;
2266743Smax.romanov@nginx.com 
2267976Smax.romanov@nginx.com     if (nxt_slow_path(name_length + value_length + 2
2268743Smax.romanov@nginx.com                       > (uint32_t) (buf->end - buf->free)))
2269743Smax.romanov@nginx.com     {
2270743Smax.romanov@nginx.com         nxt_unit_req_warn(req, "add_field: response buffer overflow");
2271743Smax.romanov@nginx.com 
2272743Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
2273743Smax.romanov@nginx.com     }
2274743Smax.romanov@nginx.com 
2275743Smax.romanov@nginx.com     nxt_unit_req_debug(req, "add_field #%"PRIu32": %.*s: %.*s",
2276743Smax.romanov@nginx.com                        resp->fields_count,
2277743Smax.romanov@nginx.com                        (int) name_length, name,
2278743Smax.romanov@nginx.com                        (int) value_length, value);
2279743Smax.romanov@nginx.com 
2280743Smax.romanov@nginx.com     f = resp->fields + resp->fields_count;
2281743Smax.romanov@nginx.com 
2282743Smax.romanov@nginx.com     nxt_unit_sptr_set(&f->name, buf->free);
2283743Smax.romanov@nginx.com     buf->free = nxt_cpymem(buf->free, name, name_length);
2284976Smax.romanov@nginx.com     *buf->free++ = '\0';
2285743Smax.romanov@nginx.com 
2286743Smax.romanov@nginx.com     nxt_unit_sptr_set(&f->value, buf->free);
2287743Smax.romanov@nginx.com     buf->free = nxt_cpymem(buf->free, value, value_length);
2288976Smax.romanov@nginx.com     *buf->free++ = '\0';
2289743Smax.romanov@nginx.com 
2290743Smax.romanov@nginx.com     f->hash = nxt_unit_field_hash(name, name_length);
2291743Smax.romanov@nginx.com     f->skip = 0;
2292743Smax.romanov@nginx.com     f->name_length = name_length;
2293743Smax.romanov@nginx.com     f->value_length = value_length;
2294743Smax.romanov@nginx.com 
2295743Smax.romanov@nginx.com     resp->fields_count++;
2296743Smax.romanov@nginx.com 
2297743Smax.romanov@nginx.com     return NXT_UNIT_OK;
2298743Smax.romanov@nginx.com }
2299743Smax.romanov@nginx.com 
2300743Smax.romanov@nginx.com 
2301743Smax.romanov@nginx.com int
nxt_unit_response_add_content(nxt_unit_request_info_t * req,const void * src,uint32_t size)2302743Smax.romanov@nginx.com nxt_unit_response_add_content(nxt_unit_request_info_t *req,
2303743Smax.romanov@nginx.com     const void* src, uint32_t size)
2304743Smax.romanov@nginx.com {
2305743Smax.romanov@nginx.com     nxt_unit_buf_t                *buf;
2306743Smax.romanov@nginx.com     nxt_unit_response_t           *resp;
2307743Smax.romanov@nginx.com     nxt_unit_request_info_impl_t  *req_impl;
2308743Smax.romanov@nginx.com 
2309743Smax.romanov@nginx.com     req_impl = nxt_container_of(req, nxt_unit_request_info_impl_t, req);
2310743Smax.romanov@nginx.com 
2311743Smax.romanov@nginx.com     if (nxt_slow_path(req_impl->state < NXT_UNIT_RS_RESPONSE_INIT)) {
2312743Smax.romanov@nginx.com         nxt_unit_req_warn(req, "add_content: response not initialized yet");
2313743Smax.romanov@nginx.com 
2314743Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
2315743Smax.romanov@nginx.com     }
2316743Smax.romanov@nginx.com 
2317743Smax.romanov@nginx.com     if (nxt_slow_path(req_impl->state >= NXT_UNIT_RS_RESPONSE_SENT)) {
2318743Smax.romanov@nginx.com         nxt_unit_req_warn(req, "add_content: response already sent");
2319743Smax.romanov@nginx.com 
2320743Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
2321743Smax.romanov@nginx.com     }
2322743Smax.romanov@nginx.com 
2323743Smax.romanov@nginx.com     buf = req->response_buf;
2324743Smax.romanov@nginx.com 
2325743Smax.romanov@nginx.com     if (nxt_slow_path(size > (uint32_t) (buf->end - buf->free))) {
2326743Smax.romanov@nginx.com         nxt_unit_req_warn(req, "add_content: buffer overflow");
2327743Smax.romanov@nginx.com 
2328743Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
2329743Smax.romanov@nginx.com     }
2330743Smax.romanov@nginx.com 
2331743Smax.romanov@nginx.com     resp = req->response;
2332743Smax.romanov@nginx.com 
2333743Smax.romanov@nginx.com     if (resp->piggyback_content_length == 0) {
2334743Smax.romanov@nginx.com         nxt_unit_sptr_set(&resp->piggyback_content, buf->free);
2335743Smax.romanov@nginx.com         req_impl->state = NXT_UNIT_RS_RESPONSE_HAS_CONTENT;
2336743Smax.romanov@nginx.com     }
2337743Smax.romanov@nginx.com 
2338743Smax.romanov@nginx.com     resp->piggyback_content_length += size;
2339743Smax.romanov@nginx.com 
2340743Smax.romanov@nginx.com     buf->free = nxt_cpymem(buf->free, src, size);
2341743Smax.romanov@nginx.com 
2342743Smax.romanov@nginx.com     return NXT_UNIT_OK;
2343743Smax.romanov@nginx.com }
2344743Smax.romanov@nginx.com 
2345743Smax.romanov@nginx.com 
2346743Smax.romanov@nginx.com int
nxt_unit_response_send(nxt_unit_request_info_t * req)2347743Smax.romanov@nginx.com nxt_unit_response_send(nxt_unit_request_info_t *req)
2348743Smax.romanov@nginx.com {
2349743Smax.romanov@nginx.com     int                           rc;
2350743Smax.romanov@nginx.com     nxt_unit_mmap_buf_t           *mmap_buf;
2351743Smax.romanov@nginx.com     nxt_unit_request_info_impl_t  *req_impl;
2352743Smax.romanov@nginx.com 
2353743Smax.romanov@nginx.com     req_impl = nxt_container_of(req, nxt_unit_request_info_impl_t, req);
2354743Smax.romanov@nginx.com 
2355743Smax.romanov@nginx.com     if (nxt_slow_path(req_impl->state < NXT_UNIT_RS_RESPONSE_INIT)) {
2356743Smax.romanov@nginx.com         nxt_unit_req_warn(req, "send: response is not initialized yet");
2357743Smax.romanov@nginx.com 
2358743Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
2359743Smax.romanov@nginx.com     }
2360743Smax.romanov@nginx.com 
2361743Smax.romanov@nginx.com     if (nxt_slow_path(req_impl->state >= NXT_UNIT_RS_RESPONSE_SENT)) {
2362743Smax.romanov@nginx.com         nxt_unit_req_warn(req, "send: response already sent");
2363743Smax.romanov@nginx.com 
2364743Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
2365743Smax.romanov@nginx.com     }
2366743Smax.romanov@nginx.com 
23671131Smax.romanov@nginx.com     if (req->request->websocket_handshake && req->response->status == 101) {
23681131Smax.romanov@nginx.com         nxt_unit_response_upgrade(req);
23691131Smax.romanov@nginx.com     }
23701131Smax.romanov@nginx.com 
2371743Smax.romanov@nginx.com     nxt_unit_req_debug(req, "send: %"PRIu32" fields, %d bytes",
2372743Smax.romanov@nginx.com                        req->response->fields_count,
2373743Smax.romanov@nginx.com                        (int) (req->response_buf->free
2374743Smax.romanov@nginx.com                               - req->response_buf->start));
2375743Smax.romanov@nginx.com 
2376743Smax.romanov@nginx.com     mmap_buf = nxt_container_of(req->response_buf, nxt_unit_mmap_buf_t, buf);
2377743Smax.romanov@nginx.com 
23781544Smax.romanov@nginx.com     rc = nxt_unit_mmap_buf_send(req, mmap_buf, 0);
2379743Smax.romanov@nginx.com     if (nxt_fast_path(rc == NXT_UNIT_OK)) {
2380743Smax.romanov@nginx.com         req->response = NULL;
2381743Smax.romanov@nginx.com         req->response_buf = NULL;
2382743Smax.romanov@nginx.com         req_impl->state = NXT_UNIT_RS_RESPONSE_SENT;
2383743Smax.romanov@nginx.com 
23841317Smax.romanov@nginx.com         nxt_unit_mmap_buf_free(mmap_buf);
2385743Smax.romanov@nginx.com     }
2386743Smax.romanov@nginx.com 
2387743Smax.romanov@nginx.com     return rc;
2388743Smax.romanov@nginx.com }
2389743Smax.romanov@nginx.com 
2390743Smax.romanov@nginx.com 
2391743Smax.romanov@nginx.com int
nxt_unit_response_is_sent(nxt_unit_request_info_t * req)2392743Smax.romanov@nginx.com nxt_unit_response_is_sent(nxt_unit_request_info_t *req)
2393743Smax.romanov@nginx.com {
2394743Smax.romanov@nginx.com     nxt_unit_request_info_impl_t  *req_impl;
2395743Smax.romanov@nginx.com 
2396743Smax.romanov@nginx.com     req_impl = nxt_container_of(req, nxt_unit_request_info_impl_t, req);
2397743Smax.romanov@nginx.com 
2398743Smax.romanov@nginx.com     return req_impl->state >= NXT_UNIT_RS_RESPONSE_SENT;
2399743Smax.romanov@nginx.com }
2400743Smax.romanov@nginx.com 
2401743Smax.romanov@nginx.com 
2402743Smax.romanov@nginx.com nxt_unit_buf_t *
nxt_unit_response_buf_alloc(nxt_unit_request_info_t * req,uint32_t size)2403743Smax.romanov@nginx.com nxt_unit_response_buf_alloc(nxt_unit_request_info_t *req, uint32_t size)
2404743Smax.romanov@nginx.com {
2405743Smax.romanov@nginx.com     int                           rc;
2406743Smax.romanov@nginx.com     nxt_unit_mmap_buf_t           *mmap_buf;
2407743Smax.romanov@nginx.com     nxt_unit_request_info_impl_t  *req_impl;
2408743Smax.romanov@nginx.com 
2409743Smax.romanov@nginx.com     if (nxt_slow_path(size > PORT_MMAP_DATA_SIZE)) {
2410743Smax.romanov@nginx.com         nxt_unit_req_warn(req, "response_buf_alloc: "
2411743Smax.romanov@nginx.com                           "requested buffer (%"PRIu32") too big", size);
2412743Smax.romanov@nginx.com 
2413743Smax.romanov@nginx.com         return NULL;
2414743Smax.romanov@nginx.com     }
2415743Smax.romanov@nginx.com 
2416743Smax.romanov@nginx.com     nxt_unit_req_debug(req, "response_buf_alloc: %"PRIu32, size);
2417743Smax.romanov@nginx.com 
2418743Smax.romanov@nginx.com     req_impl = nxt_container_of(req, nxt_unit_request_info_impl_t, req);
2419743Smax.romanov@nginx.com 
2420743Smax.romanov@nginx.com     mmap_buf = nxt_unit_mmap_buf_get(req->ctx);
2421743Smax.romanov@nginx.com     if (nxt_slow_path(mmap_buf == NULL)) {
24221176Smax.romanov@nginx.com         nxt_unit_req_alert(req, "response_buf_alloc: failed to allocate buf");
24231176Smax.romanov@nginx.com 
2424743Smax.romanov@nginx.com         return NULL;
2425743Smax.romanov@nginx.com     }
2426743Smax.romanov@nginx.com 
2427743Smax.romanov@nginx.com     mmap_buf->req = req;
2428743Smax.romanov@nginx.com 
24291131Smax.romanov@nginx.com     nxt_unit_mmap_buf_insert_tail(&req_impl->outgoing_buf, mmap_buf);
24301131Smax.romanov@nginx.com 
24311544Smax.romanov@nginx.com     rc = nxt_unit_get_outgoing_buf(req->ctx, req->response_port,
24321544Smax.romanov@nginx.com                                    size, size, mmap_buf,
24331321Smax.romanov@nginx.com                                    NULL);
2434743Smax.romanov@nginx.com     if (nxt_slow_path(rc != NXT_UNIT_OK)) {
2435743Smax.romanov@nginx.com         nxt_unit_mmap_buf_release(mmap_buf);
2436743Smax.romanov@nginx.com 
24371713Smax.romanov@nginx.com         nxt_unit_req_alert(req, "response_buf_alloc: failed to get out buf");
24381713Smax.romanov@nginx.com 
2439743Smax.romanov@nginx.com         return NULL;
2440743Smax.romanov@nginx.com     }
2441743Smax.romanov@nginx.com 
2442743Smax.romanov@nginx.com     return &mmap_buf->buf;
2443743Smax.romanov@nginx.com }
2444743Smax.romanov@nginx.com 
2445743Smax.romanov@nginx.com 
2446743Smax.romanov@nginx.com static nxt_unit_mmap_buf_t *
nxt_unit_mmap_buf_get(nxt_unit_ctx_t * ctx)2447743Smax.romanov@nginx.com nxt_unit_mmap_buf_get(nxt_unit_ctx_t *ctx)
2448743Smax.romanov@nginx.com {
2449743Smax.romanov@nginx.com     nxt_unit_mmap_buf_t  *mmap_buf;
2450743Smax.romanov@nginx.com     nxt_unit_ctx_impl_t  *ctx_impl;
2451743Smax.romanov@nginx.com 
2452743Smax.romanov@nginx.com     ctx_impl = nxt_container_of(ctx, nxt_unit_ctx_impl_t, ctx);
2453743Smax.romanov@nginx.com 
24541175Smax.romanov@nginx.com     pthread_mutex_lock(&ctx_impl->mutex);
24551175Smax.romanov@nginx.com 
24561131Smax.romanov@nginx.com     if (ctx_impl->free_buf == NULL) {
24571175Smax.romanov@nginx.com         pthread_mutex_unlock(&ctx_impl->mutex);
24581175Smax.romanov@nginx.com 
24591623Smax.romanov@nginx.com         mmap_buf = nxt_unit_malloc(ctx, sizeof(nxt_unit_mmap_buf_t));
2460743Smax.romanov@nginx.com         if (nxt_slow_path(mmap_buf == NULL)) {
24611175Smax.romanov@nginx.com             return NULL;
2462743Smax.romanov@nginx.com         }
2463743Smax.romanov@nginx.com 
2464743Smax.romanov@nginx.com     } else {
24651131Smax.romanov@nginx.com         mmap_buf = ctx_impl->free_buf;
24661131Smax.romanov@nginx.com 
24671319Smax.romanov@nginx.com         nxt_unit_mmap_buf_unlink(mmap_buf);
24681175Smax.romanov@nginx.com 
24691175Smax.romanov@nginx.com         pthread_mutex_unlock(&ctx_impl->mutex);
2470743Smax.romanov@nginx.com     }
2471743Smax.romanov@nginx.com 
2472743Smax.romanov@nginx.com     mmap_buf->ctx_impl = ctx_impl;
2473743Smax.romanov@nginx.com 
24741317Smax.romanov@nginx.com     mmap_buf->hdr = NULL;
24751317Smax.romanov@nginx.com     mmap_buf->free_ptr = NULL;
24761317Smax.romanov@nginx.com 
2477743Smax.romanov@nginx.com     return mmap_buf;
2478743Smax.romanov@nginx.com }
2479743Smax.romanov@nginx.com 
2480743Smax.romanov@nginx.com 
2481743Smax.romanov@nginx.com static void
nxt_unit_mmap_buf_release(nxt_unit_mmap_buf_t * mmap_buf)2482743Smax.romanov@nginx.com nxt_unit_mmap_buf_release(nxt_unit_mmap_buf_t *mmap_buf)
2483743Smax.romanov@nginx.com {
24841319Smax.romanov@nginx.com     nxt_unit_mmap_buf_unlink(mmap_buf);
24851131Smax.romanov@nginx.com 
24861175Smax.romanov@nginx.com     pthread_mutex_lock(&mmap_buf->ctx_impl->mutex);
24871175Smax.romanov@nginx.com 
24881131Smax.romanov@nginx.com     nxt_unit_mmap_buf_insert(&mmap_buf->ctx_impl->free_buf, mmap_buf);
24891175Smax.romanov@nginx.com 
24901175Smax.romanov@nginx.com     pthread_mutex_unlock(&mmap_buf->ctx_impl->mutex);
24911131Smax.romanov@nginx.com }
24921131Smax.romanov@nginx.com 
24931131Smax.romanov@nginx.com 
24941131Smax.romanov@nginx.com int
nxt_unit_request_is_websocket_handshake(nxt_unit_request_info_t * req)24951131Smax.romanov@nginx.com nxt_unit_request_is_websocket_handshake(nxt_unit_request_info_t *req)
24961131Smax.romanov@nginx.com {
24971131Smax.romanov@nginx.com     return req->request->websocket_handshake;
24981131Smax.romanov@nginx.com }
24991131Smax.romanov@nginx.com 
25001131Smax.romanov@nginx.com 
25011131Smax.romanov@nginx.com int
nxt_unit_response_upgrade(nxt_unit_request_info_t * req)25021131Smax.romanov@nginx.com nxt_unit_response_upgrade(nxt_unit_request_info_t *req)
25031131Smax.romanov@nginx.com {
25041131Smax.romanov@nginx.com     int                           rc;
25051131Smax.romanov@nginx.com     nxt_unit_request_info_impl_t  *req_impl;
25061131Smax.romanov@nginx.com 
25071131Smax.romanov@nginx.com     req_impl = nxt_container_of(req, nxt_unit_request_info_impl_t, req);
25081131Smax.romanov@nginx.com 
25091131Smax.romanov@nginx.com     if (nxt_slow_path(req_impl->websocket != 0)) {
25101131Smax.romanov@nginx.com         nxt_unit_req_debug(req, "upgrade: already upgraded");
25111131Smax.romanov@nginx.com 
25121131Smax.romanov@nginx.com         return NXT_UNIT_OK;
25131131Smax.romanov@nginx.com     }
25141131Smax.romanov@nginx.com 
25151131Smax.romanov@nginx.com     if (nxt_slow_path(req_impl->state < NXT_UNIT_RS_RESPONSE_INIT)) {
25161131Smax.romanov@nginx.com         nxt_unit_req_warn(req, "upgrade: response is not initialized yet");
25171131Smax.romanov@nginx.com 
25181131Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
25191131Smax.romanov@nginx.com     }
25201131Smax.romanov@nginx.com 
25211131Smax.romanov@nginx.com     if (nxt_slow_path(req_impl->state >= NXT_UNIT_RS_RESPONSE_SENT)) {
25221131Smax.romanov@nginx.com         nxt_unit_req_warn(req, "upgrade: response already sent");
25231131Smax.romanov@nginx.com 
25241131Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
25251131Smax.romanov@nginx.com     }
25261131Smax.romanov@nginx.com 
25271555Smax.romanov@nginx.com     rc = nxt_unit_request_hash_add(req->ctx, req);
25281131Smax.romanov@nginx.com     if (nxt_slow_path(rc != NXT_UNIT_OK)) {
25291131Smax.romanov@nginx.com         nxt_unit_req_warn(req, "upgrade: failed to add request to hash");
25301131Smax.romanov@nginx.com 
25311131Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
25321131Smax.romanov@nginx.com     }
25331131Smax.romanov@nginx.com 
25341131Smax.romanov@nginx.com     req_impl->websocket = 1;
25351131Smax.romanov@nginx.com 
25361131Smax.romanov@nginx.com     req->response->status = 101;
25371131Smax.romanov@nginx.com 
25381131Smax.romanov@nginx.com     return NXT_UNIT_OK;
25391131Smax.romanov@nginx.com }
25401131Smax.romanov@nginx.com 
25411131Smax.romanov@nginx.com 
25421131Smax.romanov@nginx.com int
nxt_unit_response_is_websocket(nxt_unit_request_info_t * req)25431131Smax.romanov@nginx.com nxt_unit_response_is_websocket(nxt_unit_request_info_t *req)
25441131Smax.romanov@nginx.com {
25451131Smax.romanov@nginx.com     nxt_unit_request_info_impl_t  *req_impl;
25461131Smax.romanov@nginx.com 
25471131Smax.romanov@nginx.com     req_impl = nxt_container_of(req, nxt_unit_request_info_impl_t, req);
25481131Smax.romanov@nginx.com 
25491131Smax.romanov@nginx.com     return req_impl->websocket;
25501131Smax.romanov@nginx.com }
25511131Smax.romanov@nginx.com 
25521131Smax.romanov@nginx.com 
25531131Smax.romanov@nginx.com nxt_unit_request_info_t *
nxt_unit_get_request_info_from_data(void * data)25541131Smax.romanov@nginx.com nxt_unit_get_request_info_from_data(void *data)
25551131Smax.romanov@nginx.com {
25561131Smax.romanov@nginx.com     nxt_unit_request_info_impl_t  *req_impl;
25571131Smax.romanov@nginx.com 
25581131Smax.romanov@nginx.com     req_impl = nxt_container_of(data, nxt_unit_request_info_impl_t, extra_data);
25591131Smax.romanov@nginx.com 
25601131Smax.romanov@nginx.com     return &req_impl->req;
2561743Smax.romanov@nginx.com }
2562743Smax.romanov@nginx.com 
2563743Smax.romanov@nginx.com 
2564743Smax.romanov@nginx.com int
nxt_unit_buf_send(nxt_unit_buf_t * buf)2565743Smax.romanov@nginx.com nxt_unit_buf_send(nxt_unit_buf_t *buf)
2566743Smax.romanov@nginx.com {
2567743Smax.romanov@nginx.com     int                           rc;
2568743Smax.romanov@nginx.com     nxt_unit_mmap_buf_t           *mmap_buf;
2569743Smax.romanov@nginx.com     nxt_unit_request_info_t       *req;
2570743Smax.romanov@nginx.com     nxt_unit_request_info_impl_t  *req_impl;
2571743Smax.romanov@nginx.com 
2572743Smax.romanov@nginx.com     mmap_buf = nxt_container_of(buf, nxt_unit_mmap_buf_t, buf);
2573743Smax.romanov@nginx.com 
2574743Smax.romanov@nginx.com     req = mmap_buf->req;
2575743Smax.romanov@nginx.com     req_impl = nxt_container_of(req, nxt_unit_request_info_impl_t, req);
2576743Smax.romanov@nginx.com 
2577743Smax.romanov@nginx.com     nxt_unit_req_debug(req, "buf_send: %d bytes",
2578743Smax.romanov@nginx.com                        (int) (buf->free - buf->start));
2579743Smax.romanov@nginx.com 
2580743Smax.romanov@nginx.com     if (nxt_slow_path(req_impl->state < NXT_UNIT_RS_RESPONSE_INIT)) {
2581743Smax.romanov@nginx.com         nxt_unit_req_warn(req, "buf_send: response not initialized yet");
2582743Smax.romanov@nginx.com 
2583743Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
2584743Smax.romanov@nginx.com     }
2585743Smax.romanov@nginx.com 
2586743Smax.romanov@nginx.com     if (nxt_slow_path(req_impl->state < NXT_UNIT_RS_RESPONSE_SENT)) {
2587743Smax.romanov@nginx.com         nxt_unit_req_warn(req, "buf_send: headers not sent yet");
2588743Smax.romanov@nginx.com 
2589743Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
2590743Smax.romanov@nginx.com     }
2591743Smax.romanov@nginx.com 
2592743Smax.romanov@nginx.com     if (nxt_fast_path(buf->free > buf->start)) {
25931544Smax.romanov@nginx.com         rc = nxt_unit_mmap_buf_send(req, mmap_buf, 0);
2594743Smax.romanov@nginx.com         if (nxt_slow_path(rc != NXT_UNIT_OK)) {
2595743Smax.romanov@nginx.com             return rc;
2596743Smax.romanov@nginx.com         }
2597743Smax.romanov@nginx.com     }
2598743Smax.romanov@nginx.com 
25991317Smax.romanov@nginx.com     nxt_unit_mmap_buf_free(mmap_buf);
2600743Smax.romanov@nginx.com 
2601743Smax.romanov@nginx.com     return NXT_UNIT_OK;
2602743Smax.romanov@nginx.com }
2603743Smax.romanov@nginx.com 
2604743Smax.romanov@nginx.com 
2605743Smax.romanov@nginx.com static void
nxt_unit_buf_send_done(nxt_unit_buf_t * buf)2606743Smax.romanov@nginx.com nxt_unit_buf_send_done(nxt_unit_buf_t *buf)
2607743Smax.romanov@nginx.com {
26081544Smax.romanov@nginx.com     int                      rc;
26091544Smax.romanov@nginx.com     nxt_unit_mmap_buf_t      *mmap_buf;
26101544Smax.romanov@nginx.com     nxt_unit_request_info_t  *req;
2611743Smax.romanov@nginx.com 
2612743Smax.romanov@nginx.com     mmap_buf = nxt_container_of(buf, nxt_unit_mmap_buf_t, buf);
2613743Smax.romanov@nginx.com 
2614743Smax.romanov@nginx.com     req = mmap_buf->req;
26151544Smax.romanov@nginx.com 
26161544Smax.romanov@nginx.com     rc = nxt_unit_mmap_buf_send(req, mmap_buf, 1);
2617743Smax.romanov@nginx.com     if (nxt_slow_path(rc == NXT_UNIT_OK)) {
26181317Smax.romanov@nginx.com         nxt_unit_mmap_buf_free(mmap_buf);
2619743Smax.romanov@nginx.com 
2620743Smax.romanov@nginx.com         nxt_unit_request_info_release(req);
2621743Smax.romanov@nginx.com 
2622743Smax.romanov@nginx.com     } else {
2623743Smax.romanov@nginx.com         nxt_unit_request_done(req, rc);
2624743Smax.romanov@nginx.com     }
2625743Smax.romanov@nginx.com }
2626743Smax.romanov@nginx.com 
2627743Smax.romanov@nginx.com 
2628743Smax.romanov@nginx.com static int
nxt_unit_mmap_buf_send(nxt_unit_request_info_t * req,nxt_unit_mmap_buf_t * mmap_buf,int last)26291544Smax.romanov@nginx.com nxt_unit_mmap_buf_send(nxt_unit_request_info_t *req,
2630743Smax.romanov@nginx.com     nxt_unit_mmap_buf_t *mmap_buf, int last)
2631743Smax.romanov@nginx.com {
2632743Smax.romanov@nginx.com     struct {
2633743Smax.romanov@nginx.com         nxt_port_msg_t       msg;
2634743Smax.romanov@nginx.com         nxt_port_mmap_msg_t  mmap_msg;
2635743Smax.romanov@nginx.com     } m;
2636743Smax.romanov@nginx.com 
26371544Smax.romanov@nginx.com     int                           rc;
26381544Smax.romanov@nginx.com     u_char                        *last_used, *first_free;
26391544Smax.romanov@nginx.com     ssize_t                       res;
26401544Smax.romanov@nginx.com     nxt_chunk_id_t                first_free_chunk;
26411544Smax.romanov@nginx.com     nxt_unit_buf_t                *buf;
26421544Smax.romanov@nginx.com     nxt_unit_impl_t               *lib;
26431544Smax.romanov@nginx.com     nxt_port_mmap_header_t        *hdr;
26441544Smax.romanov@nginx.com     nxt_unit_request_info_impl_t  *req_impl;
26451544Smax.romanov@nginx.com 
26461544Smax.romanov@nginx.com     lib = nxt_container_of(req->ctx->unit, nxt_unit_impl_t, unit);
26471544Smax.romanov@nginx.com     req_impl = nxt_container_of(req, nxt_unit_request_info_impl_t, req);
2648743Smax.romanov@nginx.com 
2649743Smax.romanov@nginx.com     buf = &mmap_buf->buf;
26501131Smax.romanov@nginx.com     hdr = mmap_buf->hdr;
2651743Smax.romanov@nginx.com 
2652743Smax.romanov@nginx.com     m.mmap_msg.size = buf->free - buf->start;
2653743Smax.romanov@nginx.com 
26541544Smax.romanov@nginx.com     m.msg.stream = req_impl->stream;
2655743Smax.romanov@nginx.com     m.msg.pid = lib->pid;
2656743Smax.romanov@nginx.com     m.msg.reply_port = 0;
2657743Smax.romanov@nginx.com     m.msg.type = _NXT_PORT_MSG_DATA;
2658743Smax.romanov@nginx.com     m.msg.last = last != 0;
26591131Smax.romanov@nginx.com     m.msg.mmap = hdr != NULL && m.mmap_msg.size > 0;
2660743Smax.romanov@nginx.com     m.msg.nf = 0;
2661743Smax.romanov@nginx.com     m.msg.mf = 0;
2662743Smax.romanov@nginx.com 
26631321Smax.romanov@nginx.com     rc = NXT_UNIT_ERROR;
26641321Smax.romanov@nginx.com 
26651317Smax.romanov@nginx.com     if (m.msg.mmap) {
26661131Smax.romanov@nginx.com         m.mmap_msg.mmap_id = hdr->id;
26671235Sigor@sysoev.ru         m.mmap_msg.chunk_id = nxt_port_mmap_chunk_id(hdr,
26681235Sigor@sysoev.ru                                                      (u_char *) buf->start);
26691317Smax.romanov@nginx.com 
26701544Smax.romanov@nginx.com         nxt_unit_debug(req->ctx, "#%"PRIu32": send mmap: (%d,%d,%d)",
26711544Smax.romanov@nginx.com                        req_impl->stream,
26721317Smax.romanov@nginx.com                        (int) m.mmap_msg.mmap_id,
26731317Smax.romanov@nginx.com                        (int) m.mmap_msg.chunk_id,
26741317Smax.romanov@nginx.com                        (int) m.mmap_msg.size);
26751317Smax.romanov@nginx.com 
26761544Smax.romanov@nginx.com         res = nxt_unit_port_send(req->ctx, req->response_port, &m, sizeof(m),
26771996St.nateldemoura@f5.com                                  NULL);
26781317Smax.romanov@nginx.com         if (nxt_slow_path(res != sizeof(m))) {
26791321Smax.romanov@nginx.com             goto free_buf;
26801317Smax.romanov@nginx.com         }
26811317Smax.romanov@nginx.com 
26821321Smax.romanov@nginx.com         last_used = (u_char *) buf->free - 1;
26831321Smax.romanov@nginx.com         first_free_chunk = nxt_port_mmap_chunk_id(hdr, last_used) + 1;
26841321Smax.romanov@nginx.com 
26851317Smax.romanov@nginx.com         if (buf->end - buf->free >= PORT_MMAP_CHUNK_SIZE) {
26861317Smax.romanov@nginx.com             first_free = nxt_port_mmap_chunk_start(hdr, first_free_chunk);
26871317Smax.romanov@nginx.com 
26881317Smax.romanov@nginx.com             buf->start = (char *) first_free;
26891317Smax.romanov@nginx.com             buf->free = buf->start;
26901317Smax.romanov@nginx.com 
26911317Smax.romanov@nginx.com             if (buf->end < buf->start) {
26921317Smax.romanov@nginx.com                 buf->end = buf->start;
26931317Smax.romanov@nginx.com             }
26941317Smax.romanov@nginx.com 
26951317Smax.romanov@nginx.com         } else {
26961317Smax.romanov@nginx.com             buf->start = NULL;
26971317Smax.romanov@nginx.com             buf->free = NULL;
26981317Smax.romanov@nginx.com             buf->end = NULL;
26991317Smax.romanov@nginx.com 
27001317Smax.romanov@nginx.com             mmap_buf->hdr = NULL;
27011317Smax.romanov@nginx.com         }
27021317Smax.romanov@nginx.com 
27031548Smax.romanov@nginx.com         nxt_atomic_fetch_add(&lib->outgoing.allocated_chunks,
27041321Smax.romanov@nginx.com                             (int) m.mmap_msg.chunk_id - (int) first_free_chunk);
27051321Smax.romanov@nginx.com 
27061548Smax.romanov@nginx.com         nxt_unit_debug(req->ctx, "allocated_chunks %d",
27071548Smax.romanov@nginx.com                        (int) lib->outgoing.allocated_chunks);
27081321Smax.romanov@nginx.com 
27091317Smax.romanov@nginx.com     } else {
27101317Smax.romanov@nginx.com         if (nxt_slow_path(mmap_buf->plain_ptr == NULL
27111317Smax.romanov@nginx.com                           || mmap_buf->plain_ptr > buf->start - sizeof(m.msg)))
27121317Smax.romanov@nginx.com         {
27131544Smax.romanov@nginx.com             nxt_unit_alert(req->ctx,
27141544Smax.romanov@nginx.com                            "#%"PRIu32": failed to send plain memory buffer"
27151544Smax.romanov@nginx.com                            ": no space reserved for message header",
27161544Smax.romanov@nginx.com                            req_impl->stream);
27171317Smax.romanov@nginx.com 
27181321Smax.romanov@nginx.com             goto free_buf;
27191317Smax.romanov@nginx.com         }
27201317Smax.romanov@nginx.com 
27211317Smax.romanov@nginx.com         memcpy(buf->start - sizeof(m.msg), &m.msg, sizeof(m.msg));
27221317Smax.romanov@nginx.com 
27231544Smax.romanov@nginx.com         nxt_unit_debug(req->ctx, "#%"PRIu32": send plain: %d",
27241544Smax.romanov@nginx.com                        req_impl->stream,
27251317Smax.romanov@nginx.com                        (int) (sizeof(m.msg) + m.mmap_msg.size));
27261317Smax.romanov@nginx.com 
27271544Smax.romanov@nginx.com         res = nxt_unit_port_send(req->ctx, req->response_port,
27281543Smax.romanov@nginx.com                                  buf->start - sizeof(m.msg),
27291996St.nateldemoura@f5.com                                  m.mmap_msg.size + sizeof(m.msg), NULL);
27301996St.nateldemoura@f5.com 
27311317Smax.romanov@nginx.com         if (nxt_slow_path(res != (ssize_t) (m.mmap_msg.size + sizeof(m.msg)))) {
27321321Smax.romanov@nginx.com             goto free_buf;
27331317Smax.romanov@nginx.com         }
2734743Smax.romanov@nginx.com     }
2735743Smax.romanov@nginx.com 
27361321Smax.romanov@nginx.com     rc = NXT_UNIT_OK;
27371321Smax.romanov@nginx.com 
27381321Smax.romanov@nginx.com free_buf:
27391321Smax.romanov@nginx.com 
27401321Smax.romanov@nginx.com     nxt_unit_free_outgoing_buf(mmap_buf);
27411321Smax.romanov@nginx.com 
27421321Smax.romanov@nginx.com     return rc;
2743743Smax.romanov@nginx.com }
2744743Smax.romanov@nginx.com 
2745743Smax.romanov@nginx.com 
2746743Smax.romanov@nginx.com void
nxt_unit_buf_free(nxt_unit_buf_t * buf)2747743Smax.romanov@nginx.com nxt_unit_buf_free(nxt_unit_buf_t *buf)
2748743Smax.romanov@nginx.com {
27491131Smax.romanov@nginx.com     nxt_unit_mmap_buf_free(nxt_container_of(buf, nxt_unit_mmap_buf_t, buf));
27501131Smax.romanov@nginx.com }
27511131Smax.romanov@nginx.com 
27521131Smax.romanov@nginx.com 
27531131Smax.romanov@nginx.com static void
nxt_unit_mmap_buf_free(nxt_unit_mmap_buf_t * mmap_buf)27541131Smax.romanov@nginx.com nxt_unit_mmap_buf_free(nxt_unit_mmap_buf_t *mmap_buf)
27551131Smax.romanov@nginx.com {
27561317Smax.romanov@nginx.com     nxt_unit_free_outgoing_buf(mmap_buf);
27571317Smax.romanov@nginx.com 
27581317Smax.romanov@nginx.com     nxt_unit_mmap_buf_release(mmap_buf);
27591317Smax.romanov@nginx.com }
27601317Smax.romanov@nginx.com 
27611317Smax.romanov@nginx.com 
27621317Smax.romanov@nginx.com static void
nxt_unit_free_outgoing_buf(nxt_unit_mmap_buf_t * mmap_buf)27631317Smax.romanov@nginx.com nxt_unit_free_outgoing_buf(nxt_unit_mmap_buf_t *mmap_buf)
27641317Smax.romanov@nginx.com {
27651317Smax.romanov@nginx.com     if (mmap_buf->hdr != NULL) {
27661321Smax.romanov@nginx.com         nxt_unit_mmap_release(&mmap_buf->ctx_impl->ctx,
27671321Smax.romanov@nginx.com                               mmap_buf->hdr, mmap_buf->buf.start,
27681131Smax.romanov@nginx.com                               mmap_buf->buf.end - mmap_buf->buf.start);
27691317Smax.romanov@nginx.com 
27701321Smax.romanov@nginx.com         mmap_buf->hdr = NULL;
27711321Smax.romanov@nginx.com 
27721321Smax.romanov@nginx.com         return;
27731321Smax.romanov@nginx.com     }
27741321Smax.romanov@nginx.com 
27751321Smax.romanov@nginx.com     if (mmap_buf->free_ptr != NULL) {
27761623Smax.romanov@nginx.com         nxt_unit_free(&mmap_buf->ctx_impl->ctx, mmap_buf->free_ptr);
27771321Smax.romanov@nginx.com 
27781321Smax.romanov@nginx.com         mmap_buf->free_ptr = NULL;
27791321Smax.romanov@nginx.com     }
27801321Smax.romanov@nginx.com }
27811321Smax.romanov@nginx.com 
27821321Smax.romanov@nginx.com 
27831321Smax.romanov@nginx.com static nxt_unit_read_buf_t *
nxt_unit_read_buf_get(nxt_unit_ctx_t * ctx)27841321Smax.romanov@nginx.com nxt_unit_read_buf_get(nxt_unit_ctx_t *ctx)
27851321Smax.romanov@nginx.com {
27861321Smax.romanov@nginx.com     nxt_unit_ctx_impl_t  *ctx_impl;
27871546Smax.romanov@nginx.com     nxt_unit_read_buf_t  *rbuf;
27881321Smax.romanov@nginx.com 
27891321Smax.romanov@nginx.com     ctx_impl = nxt_container_of(ctx, nxt_unit_ctx_impl_t, ctx);
27901321Smax.romanov@nginx.com 
27911321Smax.romanov@nginx.com     pthread_mutex_lock(&ctx_impl->mutex);
27921321Smax.romanov@nginx.com 
27931546Smax.romanov@nginx.com     rbuf = nxt_unit_read_buf_get_impl(ctx_impl);
27941546Smax.romanov@nginx.com 
27951546Smax.romanov@nginx.com     pthread_mutex_unlock(&ctx_impl->mutex);
27961546Smax.romanov@nginx.com 
27971996St.nateldemoura@f5.com     rbuf->oob.size = 0;
27981555Smax.romanov@nginx.com 
27991546Smax.romanov@nginx.com     return rbuf;
28001321Smax.romanov@nginx.com }
28011321Smax.romanov@nginx.com 
28021321Smax.romanov@nginx.com 
28031321Smax.romanov@nginx.com static nxt_unit_read_buf_t *
nxt_unit_read_buf_get_impl(nxt_unit_ctx_impl_t * ctx_impl)28041321Smax.romanov@nginx.com nxt_unit_read_buf_get_impl(nxt_unit_ctx_impl_t *ctx_impl)
28051321Smax.romanov@nginx.com {
28061546Smax.romanov@nginx.com     nxt_queue_link_t     *link;
28071321Smax.romanov@nginx.com     nxt_unit_read_buf_t  *rbuf;
28081321Smax.romanov@nginx.com 
28091546Smax.romanov@nginx.com     if (!nxt_queue_is_empty(&ctx_impl->free_rbuf)) {
28101546Smax.romanov@nginx.com         link = nxt_queue_first(&ctx_impl->free_rbuf);
28111546Smax.romanov@nginx.com         nxt_queue_remove(link);
28121546Smax.romanov@nginx.com 
28131546Smax.romanov@nginx.com         rbuf = nxt_container_of(link, nxt_unit_read_buf_t, link);
28141321Smax.romanov@nginx.com 
28151321Smax.romanov@nginx.com         return rbuf;
28161321Smax.romanov@nginx.com     }
28171321Smax.romanov@nginx.com 
28181623Smax.romanov@nginx.com     rbuf = nxt_unit_malloc(&ctx_impl->ctx, sizeof(nxt_unit_read_buf_t));
28191321Smax.romanov@nginx.com 
28201546Smax.romanov@nginx.com     if (nxt_fast_path(rbuf != NULL)) {
28211546Smax.romanov@nginx.com         rbuf->ctx_impl = ctx_impl;
28221546Smax.romanov@nginx.com     }
28231546Smax.romanov@nginx.com 
28241321Smax.romanov@nginx.com     return rbuf;
28251321Smax.romanov@nginx.com }
28261321Smax.romanov@nginx.com 
28271321Smax.romanov@nginx.com 
28281321Smax.romanov@nginx.com static void
nxt_unit_read_buf_release(nxt_unit_ctx_t * ctx,nxt_unit_read_buf_t * rbuf)28291321Smax.romanov@nginx.com nxt_unit_read_buf_release(nxt_unit_ctx_t *ctx,
28301321Smax.romanov@nginx.com     nxt_unit_read_buf_t *rbuf)
28311321Smax.romanov@nginx.com {
28321321Smax.romanov@nginx.com     nxt_unit_ctx_impl_t  *ctx_impl;
28331321Smax.romanov@nginx.com 
28341321Smax.romanov@nginx.com     ctx_impl = nxt_container_of(ctx, nxt_unit_ctx_impl_t, ctx);
28351321Smax.romanov@nginx.com 
28361321Smax.romanov@nginx.com     pthread_mutex_lock(&ctx_impl->mutex);
28371321Smax.romanov@nginx.com 
28381546Smax.romanov@nginx.com     nxt_queue_insert_head(&ctx_impl->free_rbuf, &rbuf->link);
28391321Smax.romanov@nginx.com 
28401321Smax.romanov@nginx.com     pthread_mutex_unlock(&ctx_impl->mutex);
2841743Smax.romanov@nginx.com }
2842743Smax.romanov@nginx.com 
2843743Smax.romanov@nginx.com 
2844743Smax.romanov@nginx.com nxt_unit_buf_t *
nxt_unit_buf_next(nxt_unit_buf_t * buf)2845743Smax.romanov@nginx.com nxt_unit_buf_next(nxt_unit_buf_t *buf)
2846743Smax.romanov@nginx.com {
28471131Smax.romanov@nginx.com     nxt_unit_mmap_buf_t  *mmap_buf;
2848743Smax.romanov@nginx.com 
2849743Smax.romanov@nginx.com     mmap_buf = nxt_container_of(buf, nxt_unit_mmap_buf_t, buf);
28501131Smax.romanov@nginx.com 
28511131Smax.romanov@nginx.com     if (mmap_buf->next == NULL) {
2852743Smax.romanov@nginx.com         return NULL;
2853743Smax.romanov@nginx.com     }
2854743Smax.romanov@nginx.com 
28551131Smax.romanov@nginx.com     return &mmap_buf->next->buf;
2856743Smax.romanov@nginx.com }
2857743Smax.romanov@nginx.com 
2858743Smax.romanov@nginx.com 
2859743Smax.romanov@nginx.com uint32_t
nxt_unit_buf_max(void)2860743Smax.romanov@nginx.com nxt_unit_buf_max(void)
2861743Smax.romanov@nginx.com {
2862743Smax.romanov@nginx.com     return PORT_MMAP_DATA_SIZE;
2863743Smax.romanov@nginx.com }
2864743Smax.romanov@nginx.com 
2865743Smax.romanov@nginx.com 
2866743Smax.romanov@nginx.com uint32_t
nxt_unit_buf_min(void)2867743Smax.romanov@nginx.com nxt_unit_buf_min(void)
2868743Smax.romanov@nginx.com {
2869743Smax.romanov@nginx.com     return PORT_MMAP_CHUNK_SIZE;
2870743Smax.romanov@nginx.com }
2871743Smax.romanov@nginx.com 
2872743Smax.romanov@nginx.com 
2873743Smax.romanov@nginx.com int
nxt_unit_response_write(nxt_unit_request_info_t * req,const void * start,size_t size)2874743Smax.romanov@nginx.com nxt_unit_response_write(nxt_unit_request_info_t *req, const void *start,
2875743Smax.romanov@nginx.com     size_t size)
2876743Smax.romanov@nginx.com {
28771321Smax.romanov@nginx.com     ssize_t  res;
28781321Smax.romanov@nginx.com 
28791321Smax.romanov@nginx.com     res = nxt_unit_response_write_nb(req, start, size, size);
28801321Smax.romanov@nginx.com 
28811321Smax.romanov@nginx.com     return res < 0 ? -res : NXT_UNIT_OK;
28821321Smax.romanov@nginx.com }
28831321Smax.romanov@nginx.com 
28841321Smax.romanov@nginx.com 
28851321Smax.romanov@nginx.com ssize_t
nxt_unit_response_write_nb(nxt_unit_request_info_t * req,const void * start,size_t size,size_t min_size)28861321Smax.romanov@nginx.com nxt_unit_response_write_nb(nxt_unit_request_info_t *req, const void *start,
28871321Smax.romanov@nginx.com     size_t size, size_t min_size)
28881321Smax.romanov@nginx.com {
2889743Smax.romanov@nginx.com     int                           rc;
28901321Smax.romanov@nginx.com     ssize_t                       sent;
28911321Smax.romanov@nginx.com     uint32_t                      part_size, min_part_size, buf_size;
2892743Smax.romanov@nginx.com     const char                    *part_start;
2893743Smax.romanov@nginx.com     nxt_unit_mmap_buf_t           mmap_buf;
2894743Smax.romanov@nginx.com     nxt_unit_request_info_impl_t  *req_impl;
28951317Smax.romanov@nginx.com     char                          local_buf[NXT_UNIT_LOCAL_BUF_SIZE];
2896743Smax.romanov@nginx.com 
28971555Smax.romanov@nginx.com     nxt_unit_req_debug(req, "write: %d", (int) size);
28981555Smax.romanov@nginx.com 
2899743Smax.romanov@nginx.com     req_impl = nxt_container_of(req, nxt_unit_request_info_impl_t, req);
2900743Smax.romanov@nginx.com 
2901743Smax.romanov@nginx.com     part_start = start;
29021321Smax.romanov@nginx.com     sent = 0;
2903743Smax.romanov@nginx.com 
29041317Smax.romanov@nginx.com     if (nxt_slow_path(req_impl->state < NXT_UNIT_RS_RESPONSE_INIT)) {
29051544Smax.romanov@nginx.com         nxt_unit_req_alert(req, "write: response not initialized yet");
29061317Smax.romanov@nginx.com 
29071321Smax.romanov@nginx.com         return -NXT_UNIT_ERROR;
29081317Smax.romanov@nginx.com     }
29091317Smax.romanov@nginx.com 
2910743Smax.romanov@nginx.com     /* Check if response is not send yet. */
29111321Smax.romanov@nginx.com     if (nxt_slow_path(req->response_buf != NULL)) {
2912743Smax.romanov@nginx.com         part_size = req->response_buf->end - req->response_buf->free;
2913743Smax.romanov@nginx.com         part_size = nxt_min(size, part_size);
2914743Smax.romanov@nginx.com 
2915743Smax.romanov@nginx.com         rc = nxt_unit_response_add_content(req, part_start, part_size);
2916743Smax.romanov@nginx.com         if (nxt_slow_path(rc != NXT_UNIT_OK)) {
29171321Smax.romanov@nginx.com             return -rc;
2918743Smax.romanov@nginx.com         }
2919743Smax.romanov@nginx.com 
2920743Smax.romanov@nginx.com         rc = nxt_unit_response_send(req);
2921743Smax.romanov@nginx.com         if (nxt_slow_path(rc != NXT_UNIT_OK)) {
29221321Smax.romanov@nginx.com             return -rc;
2923743Smax.romanov@nginx.com         }
2924743Smax.romanov@nginx.com 
2925743Smax.romanov@nginx.com         size -= part_size;
2926743Smax.romanov@nginx.com         part_start += part_size;
29271321Smax.romanov@nginx.com         sent += part_size;
29281321Smax.romanov@nginx.com 
29291321Smax.romanov@nginx.com         min_size -= nxt_min(min_size, part_size);
2930743Smax.romanov@nginx.com     }
2931743Smax.romanov@nginx.com 
2932743Smax.romanov@nginx.com     while (size > 0) {
2933743Smax.romanov@nginx.com         part_size = nxt_min(size, PORT_MMAP_DATA_SIZE);
29341321Smax.romanov@nginx.com         min_part_size = nxt_min(min_size, part_size);
29351321Smax.romanov@nginx.com         min_part_size = nxt_min(min_part_size, PORT_MMAP_CHUNK_SIZE);
2936743Smax.romanov@nginx.com 
29371544Smax.romanov@nginx.com         rc = nxt_unit_get_outgoing_buf(req->ctx, req->response_port, part_size,
29381321Smax.romanov@nginx.com                                        min_part_size, &mmap_buf, local_buf);
2939743Smax.romanov@nginx.com         if (nxt_slow_path(rc != NXT_UNIT_OK)) {
29401321Smax.romanov@nginx.com             return -rc;
2941743Smax.romanov@nginx.com         }
2942743Smax.romanov@nginx.com 
29431321Smax.romanov@nginx.com         buf_size = mmap_buf.buf.end - mmap_buf.buf.free;
29441321Smax.romanov@nginx.com         if (nxt_slow_path(buf_size == 0)) {
29451321Smax.romanov@nginx.com             return sent;
29461321Smax.romanov@nginx.com         }
29471321Smax.romanov@nginx.com         part_size = nxt_min(buf_size, part_size);
29481321Smax.romanov@nginx.com 
2949743Smax.romanov@nginx.com         mmap_buf.buf.free = nxt_cpymem(mmap_buf.buf.free,
2950743Smax.romanov@nginx.com                                        part_start, part_size);
2951743Smax.romanov@nginx.com 
29521544Smax.romanov@nginx.com         rc = nxt_unit_mmap_buf_send(req, &mmap_buf, 0);
2953743Smax.romanov@nginx.com         if (nxt_slow_path(rc != NXT_UNIT_OK)) {
29541321Smax.romanov@nginx.com             return -rc;
2955743Smax.romanov@nginx.com         }
2956743Smax.romanov@nginx.com 
2957743Smax.romanov@nginx.com         size -= part_size;
2958743Smax.romanov@nginx.com         part_start += part_size;
29591321Smax.romanov@nginx.com         sent += part_size;
29601321Smax.romanov@nginx.com 
29611321Smax.romanov@nginx.com         min_size -= nxt_min(min_size, part_size);
29621321Smax.romanov@nginx.com     }
29631321Smax.romanov@nginx.com 
29641321Smax.romanov@nginx.com     return sent;
2965743Smax.romanov@nginx.com }
2966743Smax.romanov@nginx.com 
2967743Smax.romanov@nginx.com 
2968743Smax.romanov@nginx.com int
nxt_unit_response_write_cb(nxt_unit_request_info_t * req,nxt_unit_read_info_t * read_info)2969743Smax.romanov@nginx.com nxt_unit_response_write_cb(nxt_unit_request_info_t *req,
2970743Smax.romanov@nginx.com     nxt_unit_read_info_t *read_info)
2971743Smax.romanov@nginx.com {
29721317Smax.romanov@nginx.com     int                           rc;
29731317Smax.romanov@nginx.com     ssize_t                       n;
29741321Smax.romanov@nginx.com     uint32_t                      buf_size;
29751317Smax.romanov@nginx.com     nxt_unit_buf_t                *buf;
29761317Smax.romanov@nginx.com     nxt_unit_mmap_buf_t           mmap_buf;
29771317Smax.romanov@nginx.com     nxt_unit_request_info_impl_t  *req_impl;
29781317Smax.romanov@nginx.com     char                          local_buf[NXT_UNIT_LOCAL_BUF_SIZE];
29791317Smax.romanov@nginx.com 
29801317Smax.romanov@nginx.com     req_impl = nxt_container_of(req, nxt_unit_request_info_impl_t, req);
2981743Smax.romanov@nginx.com 
29821544Smax.romanov@nginx.com     if (nxt_slow_path(req_impl->state < NXT_UNIT_RS_RESPONSE_INIT)) {
29831544Smax.romanov@nginx.com         nxt_unit_req_alert(req, "write: response not initialized yet");
29841544Smax.romanov@nginx.com 
29851544Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
29861544Smax.romanov@nginx.com     }
29871544Smax.romanov@nginx.com 
2988743Smax.romanov@nginx.com     /* Check if response is not send yet. */
29891544Smax.romanov@nginx.com     if (nxt_slow_path(req->response_buf != NULL)) {
2990743Smax.romanov@nginx.com 
2991743Smax.romanov@nginx.com         /* Enable content in headers buf. */
2992743Smax.romanov@nginx.com         rc = nxt_unit_response_add_content(req, "", 0);
2993743Smax.romanov@nginx.com         if (nxt_slow_path(rc != NXT_UNIT_OK)) {
2994743Smax.romanov@nginx.com             nxt_unit_req_error(req, "Failed to add piggyback content");
2995743Smax.romanov@nginx.com 
2996743Smax.romanov@nginx.com             return rc;
2997743Smax.romanov@nginx.com         }
2998743Smax.romanov@nginx.com 
2999743Smax.romanov@nginx.com         buf = req->response_buf;
3000743Smax.romanov@nginx.com 
3001743Smax.romanov@nginx.com         while (buf->end - buf->free > 0) {
3002743Smax.romanov@nginx.com             n = read_info->read(read_info, buf->free, buf->end - buf->free);
3003743Smax.romanov@nginx.com             if (nxt_slow_path(n < 0)) {
3004743Smax.romanov@nginx.com                 nxt_unit_req_error(req, "Read error");
3005743Smax.romanov@nginx.com 
3006743Smax.romanov@nginx.com                 return NXT_UNIT_ERROR;
3007743Smax.romanov@nginx.com             }
3008743Smax.romanov@nginx.com 
3009743Smax.romanov@nginx.com             /* Manually increase sizes. */
3010743Smax.romanov@nginx.com             buf->free += n;
3011743Smax.romanov@nginx.com             req->response->piggyback_content_length += n;
3012743Smax.romanov@nginx.com 
3013743Smax.romanov@nginx.com             if (read_info->eof) {
3014743Smax.romanov@nginx.com                 break;
3015743Smax.romanov@nginx.com             }
3016743Smax.romanov@nginx.com         }
3017743Smax.romanov@nginx.com 
3018743Smax.romanov@nginx.com         rc = nxt_unit_response_send(req);
3019743Smax.romanov@nginx.com         if (nxt_slow_path(rc != NXT_UNIT_OK)) {
3020743Smax.romanov@nginx.com             nxt_unit_req_error(req, "Failed to send headers with content");
3021743Smax.romanov@nginx.com 
3022743Smax.romanov@nginx.com             return rc;
3023743Smax.romanov@nginx.com         }
3024743Smax.romanov@nginx.com 
3025743Smax.romanov@nginx.com         if (read_info->eof) {
3026743Smax.romanov@nginx.com             return NXT_UNIT_OK;
3027743Smax.romanov@nginx.com         }
3028743Smax.romanov@nginx.com     }
3029743Smax.romanov@nginx.com 
3030743Smax.romanov@nginx.com     while (!read_info->eof) {
3031976Smax.romanov@nginx.com         nxt_unit_req_debug(req, "write_cb, alloc %"PRIu32"",
3032976Smax.romanov@nginx.com                            read_info->buf_size);
3033976Smax.romanov@nginx.com 
30341321Smax.romanov@nginx.com         buf_size = nxt_min(read_info->buf_size, PORT_MMAP_DATA_SIZE);
30351321Smax.romanov@nginx.com 
30361544Smax.romanov@nginx.com         rc = nxt_unit_get_outgoing_buf(req->ctx, req->response_port,
30371321Smax.romanov@nginx.com                                        buf_size, buf_size,
30381317Smax.romanov@nginx.com                                        &mmap_buf, local_buf);
30391317Smax.romanov@nginx.com         if (nxt_slow_path(rc != NXT_UNIT_OK)) {
30401317Smax.romanov@nginx.com             return rc;
3041743Smax.romanov@nginx.com         }
3042743Smax.romanov@nginx.com 
30431317Smax.romanov@nginx.com         buf = &mmap_buf.buf;
30441317Smax.romanov@nginx.com 
3045743Smax.romanov@nginx.com         while (!read_info->eof && buf->end > buf->free) {
3046743Smax.romanov@nginx.com             n = read_info->read(read_info, buf->free, buf->end - buf->free);
3047743Smax.romanov@nginx.com             if (nxt_slow_path(n < 0)) {
3048743Smax.romanov@nginx.com                 nxt_unit_req_error(req, "Read error");
3049743Smax.romanov@nginx.com 
30501317Smax.romanov@nginx.com                 nxt_unit_free_outgoing_buf(&mmap_buf);
3051743Smax.romanov@nginx.com 
3052743Smax.romanov@nginx.com                 return NXT_UNIT_ERROR;
3053743Smax.romanov@nginx.com             }
3054743Smax.romanov@nginx.com 
3055743Smax.romanov@nginx.com             buf->free += n;
3056743Smax.romanov@nginx.com         }
3057743Smax.romanov@nginx.com 
30581544Smax.romanov@nginx.com         rc = nxt_unit_mmap_buf_send(req, &mmap_buf, 0);
3059743Smax.romanov@nginx.com         if (nxt_slow_path(rc != NXT_UNIT_OK)) {
3060743Smax.romanov@nginx.com             nxt_unit_req_error(req, "Failed to send content");
3061743Smax.romanov@nginx.com 
3062743Smax.romanov@nginx.com             return rc;
3063743Smax.romanov@nginx.com         }
3064743Smax.romanov@nginx.com     }
3065743Smax.romanov@nginx.com 
3066743Smax.romanov@nginx.com     return NXT_UNIT_OK;
3067743Smax.romanov@nginx.com }
3068743Smax.romanov@nginx.com 
3069743Smax.romanov@nginx.com 
3070743Smax.romanov@nginx.com ssize_t
nxt_unit_request_read(nxt_unit_request_info_t * req,void * dst,size_t size)3071743Smax.romanov@nginx.com nxt_unit_request_read(nxt_unit_request_info_t *req, void *dst, size_t size)
3072743Smax.romanov@nginx.com {
30731403Smax.romanov@nginx.com     ssize_t  buf_res, res;
30741403Smax.romanov@nginx.com 
30751403Smax.romanov@nginx.com     buf_res = nxt_unit_buf_read(&req->content_buf, &req->content_length,
30761403Smax.romanov@nginx.com                                 dst, size);
30771403Smax.romanov@nginx.com 
30781403Smax.romanov@nginx.com     if (buf_res < (ssize_t) size && req->content_fd != -1) {
30791403Smax.romanov@nginx.com         res = read(req->content_fd, dst, size);
30801555Smax.romanov@nginx.com         if (nxt_slow_path(res < 0)) {
30811403Smax.romanov@nginx.com             nxt_unit_req_alert(req, "failed to read content: %s (%d)",
30821403Smax.romanov@nginx.com                                strerror(errno), errno);
30831403Smax.romanov@nginx.com 
30841403Smax.romanov@nginx.com             return res;
30851403Smax.romanov@nginx.com         }
30861403Smax.romanov@nginx.com 
30871403Smax.romanov@nginx.com         if (res < (ssize_t) size) {
30881556Smax.romanov@nginx.com             nxt_unit_close(req->content_fd);
30891403Smax.romanov@nginx.com 
30901403Smax.romanov@nginx.com             req->content_fd = -1;
30911403Smax.romanov@nginx.com         }
30921403Smax.romanov@nginx.com 
30931403Smax.romanov@nginx.com         req->content_length -= res;
30941403Smax.romanov@nginx.com 
30951403Smax.romanov@nginx.com         dst = nxt_pointer_to(dst, res);
30961403Smax.romanov@nginx.com 
30971403Smax.romanov@nginx.com     } else {
30981403Smax.romanov@nginx.com         res = 0;
30991403Smax.romanov@nginx.com     }
31001403Smax.romanov@nginx.com 
31011403Smax.romanov@nginx.com     return buf_res + res;
31021131Smax.romanov@nginx.com }
31031131Smax.romanov@nginx.com 
31041131Smax.romanov@nginx.com 
31051398Smax.romanov@nginx.com ssize_t
nxt_unit_request_readline_size(nxt_unit_request_info_t * req,size_t max_size)31061398Smax.romanov@nginx.com nxt_unit_request_readline_size(nxt_unit_request_info_t *req, size_t max_size)
31071398Smax.romanov@nginx.com {
31081403Smax.romanov@nginx.com     char                 *p;
31091403Smax.romanov@nginx.com     size_t               l_size, b_size;
31101403Smax.romanov@nginx.com     nxt_unit_buf_t       *b;
31111403Smax.romanov@nginx.com     nxt_unit_mmap_buf_t  *mmap_buf, *preread_buf;
31121398Smax.romanov@nginx.com 
31131398Smax.romanov@nginx.com     if (req->content_length == 0) {
31141398Smax.romanov@nginx.com         return 0;
31151398Smax.romanov@nginx.com     }
31161398Smax.romanov@nginx.com 
31171398Smax.romanov@nginx.com     l_size = 0;
31181398Smax.romanov@nginx.com 
31191398Smax.romanov@nginx.com     b = req->content_buf;
31201398Smax.romanov@nginx.com 
31211398Smax.romanov@nginx.com     while (b != NULL) {
31221398Smax.romanov@nginx.com         b_size = b->end - b->free;
31231398Smax.romanov@nginx.com         p = memchr(b->free, '\n', b_size);
31241398Smax.romanov@nginx.com 
31251398Smax.romanov@nginx.com         if (p != NULL) {
31261398Smax.romanov@nginx.com             p++;
31271398Smax.romanov@nginx.com             l_size += p - b->free;
31281398Smax.romanov@nginx.com             break;
31291398Smax.romanov@nginx.com         }
31301398Smax.romanov@nginx.com 
31311398Smax.romanov@nginx.com         l_size += b_size;
31321398Smax.romanov@nginx.com 
31331398Smax.romanov@nginx.com         if (max_size <= l_size) {
31341398Smax.romanov@nginx.com             break;
31351398Smax.romanov@nginx.com         }
31361398Smax.romanov@nginx.com 
31371403Smax.romanov@nginx.com         mmap_buf = nxt_container_of(b, nxt_unit_mmap_buf_t, buf);
31381403Smax.romanov@nginx.com         if (mmap_buf->next == NULL
31391403Smax.romanov@nginx.com             && req->content_fd != -1
31401403Smax.romanov@nginx.com             && l_size < req->content_length)
31411403Smax.romanov@nginx.com         {
31421403Smax.romanov@nginx.com             preread_buf = nxt_unit_request_preread(req, 16384);
31431403Smax.romanov@nginx.com             if (nxt_slow_path(preread_buf == NULL)) {
31441403Smax.romanov@nginx.com                 return -1;
31451403Smax.romanov@nginx.com             }
31461403Smax.romanov@nginx.com 
31471403Smax.romanov@nginx.com             nxt_unit_mmap_buf_insert(&mmap_buf->next, preread_buf);
31481403Smax.romanov@nginx.com         }
31491403Smax.romanov@nginx.com 
31501398Smax.romanov@nginx.com         b = nxt_unit_buf_next(b);
31511398Smax.romanov@nginx.com     }
31521398Smax.romanov@nginx.com 
31531398Smax.romanov@nginx.com     return nxt_min(max_size, l_size);
31541398Smax.romanov@nginx.com }
31551398Smax.romanov@nginx.com 
31561398Smax.romanov@nginx.com 
31571403Smax.romanov@nginx.com static nxt_unit_mmap_buf_t *
nxt_unit_request_preread(nxt_unit_request_info_t * req,size_t size)31581403Smax.romanov@nginx.com nxt_unit_request_preread(nxt_unit_request_info_t *req, size_t size)
31591403Smax.romanov@nginx.com {
31601403Smax.romanov@nginx.com     ssize_t              res;
31611403Smax.romanov@nginx.com     nxt_unit_mmap_buf_t  *mmap_buf;
31621403Smax.romanov@nginx.com 
31631403Smax.romanov@nginx.com     if (req->content_fd == -1) {
31641403Smax.romanov@nginx.com         nxt_unit_req_alert(req, "preread: content_fd == -1");
31651403Smax.romanov@nginx.com         return NULL;
31661403Smax.romanov@nginx.com     }
31671403Smax.romanov@nginx.com 
31681403Smax.romanov@nginx.com     mmap_buf = nxt_unit_mmap_buf_get(req->ctx);
31691403Smax.romanov@nginx.com     if (nxt_slow_path(mmap_buf == NULL)) {
31701403Smax.romanov@nginx.com         nxt_unit_req_alert(req, "preread: failed to allocate buf");
31711403Smax.romanov@nginx.com         return NULL;
31721403Smax.romanov@nginx.com     }
31731403Smax.romanov@nginx.com 
31741623Smax.romanov@nginx.com     mmap_buf->free_ptr = nxt_unit_malloc(req->ctx, size);
31751403Smax.romanov@nginx.com     if (nxt_slow_path(mmap_buf->free_ptr == NULL)) {
31761403Smax.romanov@nginx.com         nxt_unit_req_alert(req, "preread: failed to allocate buf memory");
31771403Smax.romanov@nginx.com         nxt_unit_mmap_buf_release(mmap_buf);
31781403Smax.romanov@nginx.com         return NULL;
31791403Smax.romanov@nginx.com     }
31801403Smax.romanov@nginx.com 
31811403Smax.romanov@nginx.com     mmap_buf->plain_ptr = mmap_buf->free_ptr;
31821403Smax.romanov@nginx.com 
31831403Smax.romanov@nginx.com     mmap_buf->hdr = NULL;
31841403Smax.romanov@nginx.com     mmap_buf->buf.start = mmap_buf->free_ptr;
31851403Smax.romanov@nginx.com     mmap_buf->buf.free = mmap_buf->buf.start;
31861403Smax.romanov@nginx.com     mmap_buf->buf.end = mmap_buf->buf.start + size;
31871403Smax.romanov@nginx.com 
31881403Smax.romanov@nginx.com     res = read(req->content_fd, mmap_buf->free_ptr, size);
31891403Smax.romanov@nginx.com     if (res < 0) {
31901403Smax.romanov@nginx.com         nxt_unit_req_alert(req, "failed to read content: %s (%d)",
31911403Smax.romanov@nginx.com                            strerror(errno), errno);
31921403Smax.romanov@nginx.com 
31931403Smax.romanov@nginx.com         nxt_unit_mmap_buf_free(mmap_buf);
31941403Smax.romanov@nginx.com 
31951403Smax.romanov@nginx.com         return NULL;
31961403Smax.romanov@nginx.com     }
31971403Smax.romanov@nginx.com 
31981403Smax.romanov@nginx.com     if (res < (ssize_t) size) {
31991556Smax.romanov@nginx.com         nxt_unit_close(req->content_fd);
32001403Smax.romanov@nginx.com 
32011403Smax.romanov@nginx.com         req->content_fd = -1;
32021403Smax.romanov@nginx.com     }
32031403Smax.romanov@nginx.com 
32041403Smax.romanov@nginx.com     nxt_unit_req_debug(req, "preread: read %d", (int) res);
32051403Smax.romanov@nginx.com 
32061403Smax.romanov@nginx.com     mmap_buf->buf.end = mmap_buf->buf.free + res;
32071403Smax.romanov@nginx.com 
32081403Smax.romanov@nginx.com     return mmap_buf;
32091403Smax.romanov@nginx.com }
32101403Smax.romanov@nginx.com 
32111403Smax.romanov@nginx.com 
32121131Smax.romanov@nginx.com static ssize_t
nxt_unit_buf_read(nxt_unit_buf_t ** b,uint64_t * len,void * dst,size_t size)32131131Smax.romanov@nginx.com nxt_unit_buf_read(nxt_unit_buf_t **b, uint64_t *len, void *dst, size_t size)
32141131Smax.romanov@nginx.com {
3215743Smax.romanov@nginx.com     u_char          *p;
3216743Smax.romanov@nginx.com     size_t          rest, copy, read;
32171403Smax.romanov@nginx.com     nxt_unit_buf_t  *buf, *last_buf;
3218743Smax.romanov@nginx.com 
3219743Smax.romanov@nginx.com     p = dst;
3220743Smax.romanov@nginx.com     rest = size;
3221743Smax.romanov@nginx.com 
32221131Smax.romanov@nginx.com     buf = *b;
32231403Smax.romanov@nginx.com     last_buf = buf;
3224743Smax.romanov@nginx.com 
3225743Smax.romanov@nginx.com     while (buf != NULL) {
32261403Smax.romanov@nginx.com         last_buf = buf;
32271403Smax.romanov@nginx.com 
3228743Smax.romanov@nginx.com         copy = buf->end - buf->free;
3229743Smax.romanov@nginx.com         copy = nxt_min(rest, copy);
3230743Smax.romanov@nginx.com 
3231743Smax.romanov@nginx.com         p = nxt_cpymem(p, buf->free, copy);
3232743Smax.romanov@nginx.com 
3233743Smax.romanov@nginx.com         buf->free += copy;
3234743Smax.romanov@nginx.com         rest -= copy;
3235743Smax.romanov@nginx.com 
3236743Smax.romanov@nginx.com         if (rest == 0) {
3237743Smax.romanov@nginx.com             if (buf->end == buf->free) {
3238743Smax.romanov@nginx.com                 buf = nxt_unit_buf_next(buf);
3239743Smax.romanov@nginx.com             }
3240743Smax.romanov@nginx.com 
3241743Smax.romanov@nginx.com             break;
3242743Smax.romanov@nginx.com         }
3243743Smax.romanov@nginx.com 
3244743Smax.romanov@nginx.com         buf = nxt_unit_buf_next(buf);
3245743Smax.romanov@nginx.com     }
3246743Smax.romanov@nginx.com 
32471403Smax.romanov@nginx.com     *b = last_buf;
3248743Smax.romanov@nginx.com 
3249743Smax.romanov@nginx.com     read = size - rest;
3250743Smax.romanov@nginx.com 
32511131Smax.romanov@nginx.com     *len -= read;
3252743Smax.romanov@nginx.com 
3253743Smax.romanov@nginx.com     return read;
3254743Smax.romanov@nginx.com }
3255743Smax.romanov@nginx.com 
3256743Smax.romanov@nginx.com 
3257743Smax.romanov@nginx.com void
nxt_unit_request_done(nxt_unit_request_info_t * req,int rc)3258743Smax.romanov@nginx.com nxt_unit_request_done(nxt_unit_request_info_t *req, int rc)
3259743Smax.romanov@nginx.com {
3260743Smax.romanov@nginx.com     uint32_t                      size;
3261743Smax.romanov@nginx.com     nxt_port_msg_t                msg;
3262743Smax.romanov@nginx.com     nxt_unit_impl_t               *lib;
3263743Smax.romanov@nginx.com     nxt_unit_request_info_impl_t  *req_impl;
3264743Smax.romanov@nginx.com 
3265743Smax.romanov@nginx.com     req_impl = nxt_container_of(req, nxt_unit_request_info_impl_t, req);
3266743Smax.romanov@nginx.com 
3267743Smax.romanov@nginx.com     nxt_unit_req_debug(req, "done: %d", rc);
3268743Smax.romanov@nginx.com 
3269743Smax.romanov@nginx.com     if (nxt_slow_path(rc != NXT_UNIT_OK)) {
3270743Smax.romanov@nginx.com         goto skip_response_send;
3271743Smax.romanov@nginx.com     }
3272743Smax.romanov@nginx.com 
3273743Smax.romanov@nginx.com     if (nxt_slow_path(req_impl->state < NXT_UNIT_RS_RESPONSE_INIT)) {
3274743Smax.romanov@nginx.com 
3275743Smax.romanov@nginx.com         size = nxt_length("Content-Type") + nxt_length("text/plain");
3276743Smax.romanov@nginx.com 
3277743Smax.romanov@nginx.com         rc = nxt_unit_response_init(req, 200, 1, size);
3278743Smax.romanov@nginx.com         if (nxt_slow_path(rc != NXT_UNIT_OK)) {
3279743Smax.romanov@nginx.com             goto skip_response_send;
3280743Smax.romanov@nginx.com         }
3281743Smax.romanov@nginx.com 
3282743Smax.romanov@nginx.com         rc = nxt_unit_response_add_field(req, "Content-Type",
3283743Smax.romanov@nginx.com                                    nxt_length("Content-Type"),
3284743Smax.romanov@nginx.com                                    "text/plain", nxt_length("text/plain"));
3285743Smax.romanov@nginx.com         if (nxt_slow_path(rc != NXT_UNIT_OK)) {
3286743Smax.romanov@nginx.com             goto skip_response_send;
3287743Smax.romanov@nginx.com         }
3288743Smax.romanov@nginx.com     }
3289743Smax.romanov@nginx.com 
3290743Smax.romanov@nginx.com     if (nxt_slow_path(req_impl->state < NXT_UNIT_RS_RESPONSE_SENT)) {
3291743Smax.romanov@nginx.com 
3292743Smax.romanov@nginx.com         req_impl->state = NXT_UNIT_RS_RESPONSE_SENT;
3293743Smax.romanov@nginx.com 
3294743Smax.romanov@nginx.com         nxt_unit_buf_send_done(req->response_buf);
3295743Smax.romanov@nginx.com 
3296743Smax.romanov@nginx.com         return;
3297743Smax.romanov@nginx.com     }
3298743Smax.romanov@nginx.com 
3299743Smax.romanov@nginx.com skip_response_send:
3300743Smax.romanov@nginx.com 
3301743Smax.romanov@nginx.com     lib = nxt_container_of(req->unit, nxt_unit_impl_t, unit);
3302743Smax.romanov@nginx.com 
33031131Smax.romanov@nginx.com     msg.stream = req_impl->stream;
3304743Smax.romanov@nginx.com     msg.pid = lib->pid;
3305743Smax.romanov@nginx.com     msg.reply_port = 0;
3306743Smax.romanov@nginx.com     msg.type = (rc == NXT_UNIT_OK) ? _NXT_PORT_MSG_DATA
3307743Smax.romanov@nginx.com                                    : _NXT_PORT_MSG_RPC_ERROR;
3308743Smax.romanov@nginx.com     msg.last = 1;
3309743Smax.romanov@nginx.com     msg.mmap = 0;
3310743Smax.romanov@nginx.com     msg.nf = 0;
3311743Smax.romanov@nginx.com     msg.mf = 0;
3312743Smax.romanov@nginx.com 
33131544Smax.romanov@nginx.com     (void) nxt_unit_port_send(req->ctx, req->response_port,
33141996St.nateldemoura@f5.com                               &msg, sizeof(msg), NULL);
3315743Smax.romanov@nginx.com 
3316743Smax.romanov@nginx.com     nxt_unit_request_info_release(req);
3317743Smax.romanov@nginx.com }
3318743Smax.romanov@nginx.com 
3319743Smax.romanov@nginx.com 
33201131Smax.romanov@nginx.com int
nxt_unit_websocket_send(nxt_unit_request_info_t * req,uint8_t opcode,uint8_t last,const void * start,size_t size)33211131Smax.romanov@nginx.com nxt_unit_websocket_send(nxt_unit_request_info_t *req, uint8_t opcode,
33221131Smax.romanov@nginx.com     uint8_t last, const void *start, size_t size)
33231131Smax.romanov@nginx.com {
33241131Smax.romanov@nginx.com     const struct iovec  iov = { (void *) start, size };
33251131Smax.romanov@nginx.com 
33261131Smax.romanov@nginx.com     return nxt_unit_websocket_sendv(req, opcode, last, &iov, 1);
33271131Smax.romanov@nginx.com }
33281131Smax.romanov@nginx.com 
33291131Smax.romanov@nginx.com 
33301131Smax.romanov@nginx.com int
nxt_unit_websocket_sendv(nxt_unit_request_info_t * req,uint8_t opcode,uint8_t last,const struct iovec * iov,int iovcnt)33311131Smax.romanov@nginx.com nxt_unit_websocket_sendv(nxt_unit_request_info_t *req, uint8_t opcode,
33321131Smax.romanov@nginx.com     uint8_t last, const struct iovec *iov, int iovcnt)
33331131Smax.romanov@nginx.com {
33341544Smax.romanov@nginx.com     int                     i, rc;
33351544Smax.romanov@nginx.com     size_t                  l, copy;
33361544Smax.romanov@nginx.com     uint32_t                payload_len, buf_size, alloc_size;
33371544Smax.romanov@nginx.com     const uint8_t           *b;
33381544Smax.romanov@nginx.com     nxt_unit_buf_t          *buf;
33391544Smax.romanov@nginx.com     nxt_unit_mmap_buf_t     mmap_buf;
33401544Smax.romanov@nginx.com     nxt_websocket_header_t  *wh;
33411544Smax.romanov@nginx.com     char                    local_buf[NXT_UNIT_LOCAL_BUF_SIZE];
33421131Smax.romanov@nginx.com 
33431131Smax.romanov@nginx.com     payload_len = 0;
33441131Smax.romanov@nginx.com 
33451131Smax.romanov@nginx.com     for (i = 0; i < iovcnt; i++) {
33461131Smax.romanov@nginx.com         payload_len += iov[i].iov_len;
33471131Smax.romanov@nginx.com     }
33481131Smax.romanov@nginx.com 
33491131Smax.romanov@nginx.com     buf_size = 10 + payload_len;
33501321Smax.romanov@nginx.com     alloc_size = nxt_min(buf_size, PORT_MMAP_DATA_SIZE);
33511131Smax.romanov@nginx.com 
33521544Smax.romanov@nginx.com     rc = nxt_unit_get_outgoing_buf(req->ctx, req->response_port,
33531321Smax.romanov@nginx.com                                    alloc_size, alloc_size,
33541317Smax.romanov@nginx.com                                    &mmap_buf, local_buf);
33551317Smax.romanov@nginx.com     if (nxt_slow_path(rc != NXT_UNIT_OK)) {
33561317Smax.romanov@nginx.com         return rc;
33571131Smax.romanov@nginx.com     }
33581131Smax.romanov@nginx.com 
33591317Smax.romanov@nginx.com     buf = &mmap_buf.buf;
33601317Smax.romanov@nginx.com 
33611131Smax.romanov@nginx.com     buf->start[0] = 0;
33621131Smax.romanov@nginx.com     buf->start[1] = 0;
33631131Smax.romanov@nginx.com 
33641317Smax.romanov@nginx.com     buf_size -= buf->end - buf->start;
33651317Smax.romanov@nginx.com 
33661131Smax.romanov@nginx.com     wh = (void *) buf->free;
33671131Smax.romanov@nginx.com 
33681131Smax.romanov@nginx.com     buf->free = nxt_websocket_frame_init(wh, payload_len);
33691131Smax.romanov@nginx.com     wh->fin = last;
33701131Smax.romanov@nginx.com     wh->opcode = opcode;
33711131Smax.romanov@nginx.com 
33721131Smax.romanov@nginx.com     for (i = 0; i < iovcnt; i++) {
33731131Smax.romanov@nginx.com         b = iov[i].iov_base;
33741131Smax.romanov@nginx.com         l = iov[i].iov_len;
33751131Smax.romanov@nginx.com 
33761131Smax.romanov@nginx.com         while (l > 0) {
33771131Smax.romanov@nginx.com             copy = buf->end - buf->free;
33781131Smax.romanov@nginx.com             copy = nxt_min(l, copy);
33791131Smax.romanov@nginx.com 
33801131Smax.romanov@nginx.com             buf->free = nxt_cpymem(buf->free, b, copy);
33811131Smax.romanov@nginx.com             b += copy;
33821131Smax.romanov@nginx.com             l -= copy;
33831131Smax.romanov@nginx.com 
33841131Smax.romanov@nginx.com             if (l > 0) {
33851317Smax.romanov@nginx.com                 if (nxt_fast_path(buf->free > buf->start)) {
33861544Smax.romanov@nginx.com                     rc = nxt_unit_mmap_buf_send(req, &mmap_buf, 0);
33871317Smax.romanov@nginx.com 
33881317Smax.romanov@nginx.com                     if (nxt_slow_path(rc != NXT_UNIT_OK)) {
33891317Smax.romanov@nginx.com                         return rc;
33901317Smax.romanov@nginx.com                     }
33911131Smax.romanov@nginx.com                 }
33921131Smax.romanov@nginx.com 
33931321Smax.romanov@nginx.com                 alloc_size = nxt_min(buf_size, PORT_MMAP_DATA_SIZE);
33941321Smax.romanov@nginx.com 
33951544Smax.romanov@nginx.com                 rc = nxt_unit_get_outgoing_buf(req->ctx, req->response_port,
33961321Smax.romanov@nginx.com                                                alloc_size, alloc_size,
33971317Smax.romanov@nginx.com                                                &mmap_buf, local_buf);
33981317Smax.romanov@nginx.com                 if (nxt_slow_path(rc != NXT_UNIT_OK)) {
33991317Smax.romanov@nginx.com                     return rc;
34001131Smax.romanov@nginx.com                 }
34011317Smax.romanov@nginx.com 
34021317Smax.romanov@nginx.com                 buf_size -= buf->end - buf->start;
34031131Smax.romanov@nginx.com             }
34041131Smax.romanov@nginx.com         }
34051131Smax.romanov@nginx.com     }
34061131Smax.romanov@nginx.com 
34071131Smax.romanov@nginx.com     if (buf->free > buf->start) {
34081544Smax.romanov@nginx.com         rc = nxt_unit_mmap_buf_send(req, &mmap_buf, 0);
34091131Smax.romanov@nginx.com     }
34101131Smax.romanov@nginx.com 
34111131Smax.romanov@nginx.com     return rc;
34121131Smax.romanov@nginx.com }
34131131Smax.romanov@nginx.com 
34141131Smax.romanov@nginx.com 
34151131Smax.romanov@nginx.com ssize_t
nxt_unit_websocket_read(nxt_unit_websocket_frame_t * ws,void * dst,size_t size)34161131Smax.romanov@nginx.com nxt_unit_websocket_read(nxt_unit_websocket_frame_t *ws, void *dst,
34171131Smax.romanov@nginx.com     size_t size)
34181131Smax.romanov@nginx.com {
34191131Smax.romanov@nginx.com     ssize_t   res;
34201131Smax.romanov@nginx.com     uint8_t   *b;
34211131Smax.romanov@nginx.com     uint64_t  i, d;
34221131Smax.romanov@nginx.com 
34231131Smax.romanov@nginx.com     res = nxt_unit_buf_read(&ws->content_buf, &ws->content_length,
34241131Smax.romanov@nginx.com                             dst, size);
34251131Smax.romanov@nginx.com 
34261131Smax.romanov@nginx.com     if (ws->mask == NULL) {
34271131Smax.romanov@nginx.com         return res;
34281131Smax.romanov@nginx.com     }
34291131Smax.romanov@nginx.com 
34301131Smax.romanov@nginx.com     b = dst;
34311131Smax.romanov@nginx.com     d = (ws->payload_len - ws->content_length - res) % 4;
34321131Smax.romanov@nginx.com 
34331131Smax.romanov@nginx.com     for (i = 0; i < (uint64_t) res; i++) {
34341131Smax.romanov@nginx.com         b[i] ^= ws->mask[ (i + d) % 4 ];
34351131Smax.romanov@nginx.com     }
34361131Smax.romanov@nginx.com 
34371131Smax.romanov@nginx.com     return res;
34381131Smax.romanov@nginx.com }
34391131Smax.romanov@nginx.com 
34401131Smax.romanov@nginx.com 
34411131Smax.romanov@nginx.com int
nxt_unit_websocket_retain(nxt_unit_websocket_frame_t * ws)34421131Smax.romanov@nginx.com nxt_unit_websocket_retain(nxt_unit_websocket_frame_t *ws)
34431131Smax.romanov@nginx.com {
34441131Smax.romanov@nginx.com     char                             *b;
34451590Smax.romanov@nginx.com     size_t                           size, hsize;
34461131Smax.romanov@nginx.com     nxt_unit_websocket_frame_impl_t  *ws_impl;
34471131Smax.romanov@nginx.com 
34481131Smax.romanov@nginx.com     ws_impl = nxt_container_of(ws, nxt_unit_websocket_frame_impl_t, ws);
34491131Smax.romanov@nginx.com 
34501317Smax.romanov@nginx.com     if (ws_impl->buf->free_ptr != NULL || ws_impl->buf->hdr != NULL) {
34511131Smax.romanov@nginx.com         return NXT_UNIT_OK;
34521131Smax.romanov@nginx.com     }
34531131Smax.romanov@nginx.com 
34541131Smax.romanov@nginx.com     size = ws_impl->buf->buf.end - ws_impl->buf->buf.start;
34551131Smax.romanov@nginx.com 
34561623Smax.romanov@nginx.com     b = nxt_unit_malloc(ws->req->ctx, size);
34571131Smax.romanov@nginx.com     if (nxt_slow_path(b == NULL)) {
34581131Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
34591131Smax.romanov@nginx.com     }
34601131Smax.romanov@nginx.com 
34611131Smax.romanov@nginx.com     memcpy(b, ws_impl->buf->buf.start, size);
34621131Smax.romanov@nginx.com 
34631590Smax.romanov@nginx.com     hsize = nxt_websocket_frame_header_size(b);
34641590Smax.romanov@nginx.com 
34651131Smax.romanov@nginx.com     ws_impl->buf->buf.start = b;
34661590Smax.romanov@nginx.com     ws_impl->buf->buf.free = b + hsize;
34671131Smax.romanov@nginx.com     ws_impl->buf->buf.end = b + size;
34681131Smax.romanov@nginx.com 
34691317Smax.romanov@nginx.com     ws_impl->buf->free_ptr = b;
34701131Smax.romanov@nginx.com 
34711590Smax.romanov@nginx.com     ws_impl->ws.header = (nxt_websocket_header_t *) b;
34721590Smax.romanov@nginx.com 
34731590Smax.romanov@nginx.com     if (ws_impl->ws.header->mask) {
34741590Smax.romanov@nginx.com         ws_impl->ws.mask = (uint8_t *) b + hsize - 4;
34751590Smax.romanov@nginx.com 
34761590Smax.romanov@nginx.com     } else {
34771590Smax.romanov@nginx.com         ws_impl->ws.mask = NULL;
34781590Smax.romanov@nginx.com     }
34791590Smax.romanov@nginx.com 
34801131Smax.romanov@nginx.com     return NXT_UNIT_OK;
34811131Smax.romanov@nginx.com }
34821131Smax.romanov@nginx.com 
34831131Smax.romanov@nginx.com 
34841131Smax.romanov@nginx.com void
nxt_unit_websocket_done(nxt_unit_websocket_frame_t * ws)34851131Smax.romanov@nginx.com nxt_unit_websocket_done(nxt_unit_websocket_frame_t *ws)
34861131Smax.romanov@nginx.com {
34871131Smax.romanov@nginx.com     nxt_unit_websocket_frame_release(ws);
34881131Smax.romanov@nginx.com }
34891131Smax.romanov@nginx.com 
34901131Smax.romanov@nginx.com 
3491743Smax.romanov@nginx.com static nxt_port_mmap_header_t *
nxt_unit_mmap_get(nxt_unit_ctx_t * ctx,nxt_unit_port_t * port,nxt_chunk_id_t * c,int * n,int min_n)34921544Smax.romanov@nginx.com nxt_unit_mmap_get(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port,
34931544Smax.romanov@nginx.com     nxt_chunk_id_t *c, int *n, int min_n)
3494743Smax.romanov@nginx.com {
3495743Smax.romanov@nginx.com     int                     res, nchunks, i;
34961321Smax.romanov@nginx.com     uint32_t                outgoing_size;
3497743Smax.romanov@nginx.com     nxt_unit_mmap_t         *mm, *mm_end;
34981321Smax.romanov@nginx.com     nxt_unit_impl_t         *lib;
3499743Smax.romanov@nginx.com     nxt_port_mmap_header_t  *hdr;
3500743Smax.romanov@nginx.com 
35011321Smax.romanov@nginx.com     lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit);
35021321Smax.romanov@nginx.com 
35031548Smax.romanov@nginx.com     pthread_mutex_lock(&lib->outgoing.mutex);
3504743Smax.romanov@nginx.com 
3505*2749Szelenkov@nginx.com retry:
3506*2749Szelenkov@nginx.com 
3507*2749Szelenkov@nginx.com     outgoing_size = lib->outgoing.size;
3508*2749Szelenkov@nginx.com 
35091321Smax.romanov@nginx.com     mm_end = lib->outgoing.elts + outgoing_size;
35101321Smax.romanov@nginx.com 
35111548Smax.romanov@nginx.com     for (mm = lib->outgoing.elts; mm < mm_end; mm++) {
35121548Smax.romanov@nginx.com         hdr = mm->hdr;
35131548Smax.romanov@nginx.com 
35141548Smax.romanov@nginx.com         if (hdr->sent_over != 0xFFFFu
35151548Smax.romanov@nginx.com             && (hdr->sent_over != port->id.id
3516743Smax.romanov@nginx.com                 || mm->src_thread != pthread_self()))
3517743Smax.romanov@nginx.com         {
35181659Smax.romanov@nginx.com             continue;
35191659Smax.romanov@nginx.com         }
35201659Smax.romanov@nginx.com 
35211659Smax.romanov@nginx.com         *c = 0;
3522743Smax.romanov@nginx.com 
3523743Smax.romanov@nginx.com         while (nxt_port_mmap_get_free_chunk(hdr->free_map, c)) {
3524743Smax.romanov@nginx.com             nchunks = 1;
3525743Smax.romanov@nginx.com 
3526743Smax.romanov@nginx.com             while (nchunks < *n) {
3527743Smax.romanov@nginx.com                 res = nxt_port_mmap_chk_set_chunk_busy(hdr->free_map,
3528743Smax.romanov@nginx.com                                                        *c + nchunks);
3529743Smax.romanov@nginx.com 
35301321Smax.romanov@nginx.com                 if (res == 0) {
3531743Smax.romanov@nginx.com                     if (nchunks >= min_n) {
3532743Smax.romanov@nginx.com                         *n = nchunks;
3533743Smax.romanov@nginx.com 
3534743Smax.romanov@nginx.com                         goto unlock;
35351321Smax.romanov@nginx.com                     }
35361321Smax.romanov@nginx.com 
35371321Smax.romanov@nginx.com                     for (i = 0; i < nchunks; i++) {
35381321Smax.romanov@nginx.com                         nxt_port_mmap_set_chunk_free(hdr->free_map, *c + i);
35391321Smax.romanov@nginx.com                     }
35401321Smax.romanov@nginx.com 
3541743Smax.romanov@nginx.com                     *c += nchunks + 1;
3542743Smax.romanov@nginx.com                     nchunks = 0;
3543743Smax.romanov@nginx.com                     break;
3544743Smax.romanov@nginx.com                 }
3545743Smax.romanov@nginx.com 
3546743Smax.romanov@nginx.com                 nchunks++;
3547743Smax.romanov@nginx.com             }
3548743Smax.romanov@nginx.com 
3549743Smax.romanov@nginx.com             if (nchunks >= min_n) {
3550743Smax.romanov@nginx.com                 *n = nchunks;
3551743Smax.romanov@nginx.com 
3552743Smax.romanov@nginx.com                 goto unlock;
35531321Smax.romanov@nginx.com             }
35541321Smax.romanov@nginx.com         }
35551321Smax.romanov@nginx.com 
3556743Smax.romanov@nginx.com         hdr->oosm = 1;
3557743Smax.romanov@nginx.com     }
3558743Smax.romanov@nginx.com 
35591321Smax.romanov@nginx.com     if (outgoing_size >= lib->shm_mmap_limit) {
35601321Smax.romanov@nginx.com         /* Cannot allocate more shared memory. */
35611321Smax.romanov@nginx.com         pthread_mutex_unlock(&lib->outgoing.mutex);
35621321Smax.romanov@nginx.com 
35631321Smax.romanov@nginx.com         if (min_n == 0) {
35641321Smax.romanov@nginx.com             *n = 0;
35651548Smax.romanov@nginx.com         }
35661321Smax.romanov@nginx.com 
35671321Smax.romanov@nginx.com         if (nxt_slow_path(lib->outgoing.allocated_chunks + min_n
35681321Smax.romanov@nginx.com                           >= lib->shm_mmap_limit * PORT_MMAP_CHUNK_COUNT))
35691321Smax.romanov@nginx.com         {
35701321Smax.romanov@nginx.com             /* Memory allocated by application, but not send to router. */
35711548Smax.romanov@nginx.com             return NULL;
35721321Smax.romanov@nginx.com         }
35731321Smax.romanov@nginx.com 
35741321Smax.romanov@nginx.com         /* Notify router about OOSM condition. */
35751321Smax.romanov@nginx.com 
35761321Smax.romanov@nginx.com         res = nxt_unit_send_oosm(ctx, port);
35771321Smax.romanov@nginx.com         if (nxt_slow_path(res != NXT_UNIT_OK)) {
35781321Smax.romanov@nginx.com             return NULL;
35791321Smax.romanov@nginx.com         }
35801544Smax.romanov@nginx.com 
35811321Smax.romanov@nginx.com         /* Return if caller can handle OOSM condition. Non-blocking mode. */
35821321Smax.romanov@nginx.com 
35831321Smax.romanov@nginx.com         if (min_n == 0) {
35841321Smax.romanov@nginx.com             return NULL;
35851321Smax.romanov@nginx.com         }
35861321Smax.romanov@nginx.com 
35871321Smax.romanov@nginx.com         nxt_unit_debug(ctx, "oosm: waiting for ACK");
35881321Smax.romanov@nginx.com 
35891321Smax.romanov@nginx.com         res = nxt_unit_wait_shm_ack(ctx);
35901321Smax.romanov@nginx.com         if (nxt_slow_path(res != NXT_UNIT_OK)) {
35911321Smax.romanov@nginx.com             return NULL;
35921321Smax.romanov@nginx.com         }
35931321Smax.romanov@nginx.com 
35941321Smax.romanov@nginx.com         nxt_unit_debug(ctx, "oosm: retry");
35951321Smax.romanov@nginx.com 
35961321Smax.romanov@nginx.com         pthread_mutex_lock(&lib->outgoing.mutex);
35971321Smax.romanov@nginx.com 
35981321Smax.romanov@nginx.com         goto retry;
35991321Smax.romanov@nginx.com     }
36001548Smax.romanov@nginx.com 
36011321Smax.romanov@nginx.com     *c = 0;
36021321Smax.romanov@nginx.com     hdr = nxt_unit_new_mmap(ctx, port, *n);
3603743Smax.romanov@nginx.com 
3604743Smax.romanov@nginx.com unlock:
3605*2749Szelenkov@nginx.com 
3606*2749Szelenkov@nginx.com     nxt_atomic_fetch_add(&lib->outgoing.allocated_chunks, *n);
3607743Smax.romanov@nginx.com 
36081544Smax.romanov@nginx.com     nxt_unit_debug(ctx, "allocated_chunks %d",
3609743Smax.romanov@nginx.com                    (int) lib->outgoing.allocated_chunks);
3610743Smax.romanov@nginx.com 
3611743Smax.romanov@nginx.com     pthread_mutex_unlock(&lib->outgoing.mutex);
36121548Smax.romanov@nginx.com 
36131548Smax.romanov@nginx.com     return hdr;
36141548Smax.romanov@nginx.com }
36151548Smax.romanov@nginx.com 
36161548Smax.romanov@nginx.com 
36171548Smax.romanov@nginx.com static int
nxt_unit_send_oosm(nxt_unit_ctx_t * ctx,nxt_unit_port_t * port)3618743Smax.romanov@nginx.com nxt_unit_send_oosm(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port)
3619743Smax.romanov@nginx.com {
3620743Smax.romanov@nginx.com     ssize_t          res;
3621743Smax.romanov@nginx.com     nxt_port_msg_t   msg;
3622743Smax.romanov@nginx.com     nxt_unit_impl_t  *lib;
36231321Smax.romanov@nginx.com 
36241544Smax.romanov@nginx.com     lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit);
36251321Smax.romanov@nginx.com 
36261321Smax.romanov@nginx.com     msg.stream = 0;
36271321Smax.romanov@nginx.com     msg.pid = lib->pid;
36281321Smax.romanov@nginx.com     msg.reply_port = 0;
36291321Smax.romanov@nginx.com     msg.type = _NXT_PORT_MSG_OOSM;
36301321Smax.romanov@nginx.com     msg.last = 0;
36311321Smax.romanov@nginx.com     msg.mmap = 0;
36321321Smax.romanov@nginx.com     msg.nf = 0;
36331321Smax.romanov@nginx.com     msg.mf = 0;
36341321Smax.romanov@nginx.com 
36351321Smax.romanov@nginx.com     res = nxt_unit_port_send(ctx, lib->router_port, &msg, sizeof(msg), NULL);
36361321Smax.romanov@nginx.com     if (nxt_slow_path(res != sizeof(msg))) {
36371321Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
36381321Smax.romanov@nginx.com     }
36391321Smax.romanov@nginx.com 
36401321Smax.romanov@nginx.com     return NXT_UNIT_OK;
36411996St.nateldemoura@f5.com }
36421321Smax.romanov@nginx.com 
36431321Smax.romanov@nginx.com 
36441321Smax.romanov@nginx.com static int
nxt_unit_wait_shm_ack(nxt_unit_ctx_t * ctx)36451321Smax.romanov@nginx.com nxt_unit_wait_shm_ack(nxt_unit_ctx_t *ctx)
36461321Smax.romanov@nginx.com {
36471321Smax.romanov@nginx.com     int                  res;
36481321Smax.romanov@nginx.com     nxt_unit_ctx_impl_t  *ctx_impl;
36491321Smax.romanov@nginx.com     nxt_unit_read_buf_t  *rbuf;
36501321Smax.romanov@nginx.com 
36511321Smax.romanov@nginx.com     ctx_impl = nxt_container_of(ctx, nxt_unit_ctx_impl_t, ctx);
36521321Smax.romanov@nginx.com 
36531555Smax.romanov@nginx.com     while (1) {
36541321Smax.romanov@nginx.com         rbuf = nxt_unit_read_buf_get(ctx);
36551321Smax.romanov@nginx.com         if (nxt_slow_path(rbuf == NULL)) {
36561321Smax.romanov@nginx.com             return NXT_UNIT_ERROR;
36571321Smax.romanov@nginx.com         }
36581321Smax.romanov@nginx.com 
36591321Smax.romanov@nginx.com         do {
36601321Smax.romanov@nginx.com             res = nxt_unit_ctx_port_recv(ctx, ctx_impl->read_port, rbuf);
36611321Smax.romanov@nginx.com         } while (res == NXT_UNIT_AGAIN);
36621321Smax.romanov@nginx.com 
36631321Smax.romanov@nginx.com         if (res == NXT_UNIT_ERROR) {
36641321Smax.romanov@nginx.com             nxt_unit_read_buf_release(ctx, rbuf);
36651756Smax.romanov@nginx.com 
36661756Smax.romanov@nginx.com             return NXT_UNIT_ERROR;
36671756Smax.romanov@nginx.com         }
36681756Smax.romanov@nginx.com 
36691555Smax.romanov@nginx.com         if (nxt_unit_is_shm_ack(rbuf)) {
36701321Smax.romanov@nginx.com             nxt_unit_read_buf_release(ctx, rbuf);
36711321Smax.romanov@nginx.com             break;
36721321Smax.romanov@nginx.com         }
36731321Smax.romanov@nginx.com 
36741321Smax.romanov@nginx.com         pthread_mutex_lock(&ctx_impl->mutex);
36751555Smax.romanov@nginx.com 
36761321Smax.romanov@nginx.com         nxt_queue_insert_tail(&ctx_impl->pending_rbuf, &rbuf->link);
36771321Smax.romanov@nginx.com 
36781321Smax.romanov@nginx.com         pthread_mutex_unlock(&ctx_impl->mutex);
36791321Smax.romanov@nginx.com 
36801321Smax.romanov@nginx.com         if (nxt_unit_is_quit(rbuf)) {
36811321Smax.romanov@nginx.com             nxt_unit_debug(ctx, "oosm: quit received");
36821546Smax.romanov@nginx.com 
36831321Smax.romanov@nginx.com             return NXT_UNIT_ERROR;
36841321Smax.romanov@nginx.com         }
36851321Smax.romanov@nginx.com     }
36861555Smax.romanov@nginx.com 
36871321Smax.romanov@nginx.com     return NXT_UNIT_OK;
36881321Smax.romanov@nginx.com }
36891321Smax.romanov@nginx.com 
36901321Smax.romanov@nginx.com 
36911321Smax.romanov@nginx.com static nxt_unit_mmap_t *
nxt_unit_mmap_at(nxt_unit_mmaps_t * mmaps,uint32_t i)36921321Smax.romanov@nginx.com nxt_unit_mmap_at(nxt_unit_mmaps_t *mmaps, uint32_t i)
36931321Smax.romanov@nginx.com {
36941321Smax.romanov@nginx.com     uint32_t         cap, n;
36951321Smax.romanov@nginx.com     nxt_unit_mmap_t  *e;
36961321Smax.romanov@nginx.com 
3697743Smax.romanov@nginx.com     if (nxt_fast_path(mmaps->size > i)) {
3698743Smax.romanov@nginx.com         return mmaps->elts + i;
3699743Smax.romanov@nginx.com     }
37001546Smax.romanov@nginx.com 
37011546Smax.romanov@nginx.com     cap = mmaps->cap;
37021546Smax.romanov@nginx.com 
37031546Smax.romanov@nginx.com     if (cap == 0) {
37041546Smax.romanov@nginx.com         cap = i + 1;
37051546Smax.romanov@nginx.com     }
3706743Smax.romanov@nginx.com 
3707743Smax.romanov@nginx.com     while (i + 1 > cap) {
3708743Smax.romanov@nginx.com 
3709743Smax.romanov@nginx.com         if (cap < 16) {
3710743Smax.romanov@nginx.com             cap = cap * 2;
3711743Smax.romanov@nginx.com 
3712743Smax.romanov@nginx.com         } else {
3713743Smax.romanov@nginx.com             cap = cap + cap / 2;
3714743Smax.romanov@nginx.com         }
3715743Smax.romanov@nginx.com     }
37161008Szelenkov@nginx.com 
3717743Smax.romanov@nginx.com     if (cap != mmaps->cap) {
3718743Smax.romanov@nginx.com 
37191008Szelenkov@nginx.com         e = realloc(mmaps->elts, cap * sizeof(nxt_unit_mmap_t));
3720743Smax.romanov@nginx.com         if (nxt_slow_path(e == NULL)) {
3721743Smax.romanov@nginx.com             return NULL;
3722743Smax.romanov@nginx.com         }
3723743Smax.romanov@nginx.com 
3724743Smax.romanov@nginx.com         mmaps->elts = e;
37251546Smax.romanov@nginx.com 
37261546Smax.romanov@nginx.com         for (n = mmaps->cap; n < cap; n++) {
3727743Smax.romanov@nginx.com             e = mmaps->elts + n;
3728743Smax.romanov@nginx.com 
3729743Smax.romanov@nginx.com             e->hdr = NULL;
37301546Smax.romanov@nginx.com             nxt_queue_init(&e->awaiting_rbuf);
37311546Smax.romanov@nginx.com         }
37321546Smax.romanov@nginx.com 
37331546Smax.romanov@nginx.com         mmaps->cap = cap;
37341546Smax.romanov@nginx.com     }
37351546Smax.romanov@nginx.com 
37361546Smax.romanov@nginx.com     if (i + 1 > mmaps->size) {
37371546Smax.romanov@nginx.com         mmaps->size = i + 1;
3738743Smax.romanov@nginx.com     }
3739743Smax.romanov@nginx.com 
3740743Smax.romanov@nginx.com     return mmaps->elts + i;
3741743Smax.romanov@nginx.com }
3742743Smax.romanov@nginx.com 
3743743Smax.romanov@nginx.com 
3744743Smax.romanov@nginx.com static nxt_port_mmap_header_t *
nxt_unit_new_mmap(nxt_unit_ctx_t * ctx,nxt_unit_port_t * port,int n)3745743Smax.romanov@nginx.com nxt_unit_new_mmap(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port, int n)
3746743Smax.romanov@nginx.com {
3747743Smax.romanov@nginx.com     int                     i, fd, rc;
3748743Smax.romanov@nginx.com     void                    *mem;
3749743Smax.romanov@nginx.com     nxt_unit_mmap_t         *mm;
3750743Smax.romanov@nginx.com     nxt_unit_impl_t         *lib;
37511544Smax.romanov@nginx.com     nxt_port_mmap_header_t  *hdr;
3752743Smax.romanov@nginx.com 
3753743Smax.romanov@nginx.com     lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit);
3754743Smax.romanov@nginx.com 
3755743Smax.romanov@nginx.com     mm = nxt_unit_mmap_at(&lib->outgoing, lib->outgoing.size);
3756743Smax.romanov@nginx.com     if (nxt_slow_path(mm == NULL)) {
3757743Smax.romanov@nginx.com         nxt_unit_alert(ctx, "failed to add mmap to outgoing array");
3758743Smax.romanov@nginx.com 
37591544Smax.romanov@nginx.com         return NULL;
3760743Smax.romanov@nginx.com     }
37611548Smax.romanov@nginx.com 
3762743Smax.romanov@nginx.com     fd = nxt_unit_shm_open(ctx, PORT_MMAP_SIZE);
37631544Smax.romanov@nginx.com     if (nxt_slow_path(fd == -1)) {
3764743Smax.romanov@nginx.com         goto remove_fail;
3765743Smax.romanov@nginx.com     }
3766743Smax.romanov@nginx.com 
3767743Smax.romanov@nginx.com     mem = mmap(NULL, PORT_MMAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
37681555Smax.romanov@nginx.com     if (nxt_slow_path(mem == MAP_FAILED)) {
3769743Smax.romanov@nginx.com         nxt_unit_alert(ctx, "mmap(%d) failed: %s (%d)", fd,
3770743Smax.romanov@nginx.com                        strerror(errno), errno);
3771743Smax.romanov@nginx.com 
3772743Smax.romanov@nginx.com         nxt_unit_close(fd);
3773743Smax.romanov@nginx.com 
3774743Smax.romanov@nginx.com         goto remove_fail;
3775743Smax.romanov@nginx.com     }
3776743Smax.romanov@nginx.com 
3777743Smax.romanov@nginx.com     mm->hdr = mem;
37781556Smax.romanov@nginx.com     hdr = mem;
37791555Smax.romanov@nginx.com 
3780743Smax.romanov@nginx.com     memset(hdr->free_map, 0xFFU, sizeof(hdr->free_map));
3781743Smax.romanov@nginx.com     memset(hdr->free_tracking_map, 0xFFU, sizeof(hdr->free_tracking_map));
3782743Smax.romanov@nginx.com 
3783743Smax.romanov@nginx.com     hdr->id = lib->outgoing.size - 1;
3784743Smax.romanov@nginx.com     hdr->src_pid = lib->pid;
3785743Smax.romanov@nginx.com     hdr->dst_pid = port->id.pid;
3786743Smax.romanov@nginx.com     hdr->sent_over = port->id.id;
3787743Smax.romanov@nginx.com     mm->src_thread = pthread_self();
3788743Smax.romanov@nginx.com 
37891548Smax.romanov@nginx.com     /* Mark first n chunk(s) as busy */
3790743Smax.romanov@nginx.com     for (i = 0; i < n; i++) {
37911548Smax.romanov@nginx.com         nxt_port_mmap_set_chunk_busy(hdr->free_map, i);
37921544Smax.romanov@nginx.com     }
37931659Smax.romanov@nginx.com 
3794743Smax.romanov@nginx.com     /* Mark as busy chunk followed the last available chunk. */
3795743Smax.romanov@nginx.com     nxt_port_mmap_set_chunk_busy(hdr->free_map, PORT_MMAP_CHUNK_COUNT);
3796743Smax.romanov@nginx.com     nxt_port_mmap_set_chunk_busy(hdr->free_tracking_map, PORT_MMAP_CHUNK_COUNT);
3797743Smax.romanov@nginx.com 
3798743Smax.romanov@nginx.com     pthread_mutex_unlock(&lib->outgoing.mutex);
3799743Smax.romanov@nginx.com 
3800743Smax.romanov@nginx.com     rc = nxt_unit_send_mmap(ctx, port, fd);
3801743Smax.romanov@nginx.com     if (nxt_slow_path(rc != NXT_UNIT_OK)) {
3802743Smax.romanov@nginx.com         munmap(mem, PORT_MMAP_SIZE);
3803743Smax.romanov@nginx.com         hdr = NULL;
38041548Smax.romanov@nginx.com 
3805743Smax.romanov@nginx.com     } else {
38061544Smax.romanov@nginx.com         nxt_unit_debug(ctx, "new mmap #%"PRIu32" created for %d -> %d",
3807743Smax.romanov@nginx.com                        hdr->id, (int) lib->pid, (int) port->id.pid);
3808743Smax.romanov@nginx.com     }
3809743Smax.romanov@nginx.com 
3810743Smax.romanov@nginx.com     nxt_unit_close(fd);
3811743Smax.romanov@nginx.com 
3812743Smax.romanov@nginx.com     pthread_mutex_lock(&lib->outgoing.mutex);
38131548Smax.romanov@nginx.com 
3814743Smax.romanov@nginx.com     if (nxt_fast_path(hdr != NULL)) {
3815743Smax.romanov@nginx.com         return hdr;
38161556Smax.romanov@nginx.com     }
3817743Smax.romanov@nginx.com 
38181548Smax.romanov@nginx.com remove_fail:
3819743Smax.romanov@nginx.com 
3820743Smax.romanov@nginx.com     lib->outgoing.size--;
3821743Smax.romanov@nginx.com 
3822743Smax.romanov@nginx.com     return NULL;
3823743Smax.romanov@nginx.com }
3824743Smax.romanov@nginx.com 
3825743Smax.romanov@nginx.com 
38261548Smax.romanov@nginx.com static int
nxt_unit_shm_open(nxt_unit_ctx_t * ctx,size_t size)3827743Smax.romanov@nginx.com nxt_unit_shm_open(nxt_unit_ctx_t *ctx, size_t size)
3828743Smax.romanov@nginx.com {
3829743Smax.romanov@nginx.com     int              fd;
3830743Smax.romanov@nginx.com 
3831743Smax.romanov@nginx.com #if (NXT_HAVE_MEMFD_CREATE || NXT_HAVE_SHM_OPEN)
3832743Smax.romanov@nginx.com     char             name[64];
38331555Smax.romanov@nginx.com     nxt_unit_impl_t  *lib;
38341555Smax.romanov@nginx.com 
38351555Smax.romanov@nginx.com     lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit);
38362142Sandrew@digital-domain.net     snprintf(name, sizeof(name), NXT_SHM_PREFIX "unit.%d.%p",
38372142Sandrew@digital-domain.net              lib->pid, (void *) (uintptr_t) pthread_self());
38382142Sandrew@digital-domain.net #endif
38391555Smax.romanov@nginx.com 
38401555Smax.romanov@nginx.com #if (NXT_HAVE_MEMFD_CREATE)
38411555Smax.romanov@nginx.com 
38421555Smax.romanov@nginx.com     fd = syscall(SYS_memfd_create, name, MFD_CLOEXEC);
38431810Smax.romanov@nginx.com     if (nxt_slow_path(fd == -1)) {
38441555Smax.romanov@nginx.com         nxt_unit_alert(ctx, "memfd_create(%s) failed: %s (%d)", name,
38451555Smax.romanov@nginx.com                        strerror(errno), errno);
38461555Smax.romanov@nginx.com 
38471555Smax.romanov@nginx.com         return -1;
38481555Smax.romanov@nginx.com     }
38491555Smax.romanov@nginx.com 
38501555Smax.romanov@nginx.com     nxt_unit_debug(ctx, "memfd_create(%s): %d", name, fd);
38511555Smax.romanov@nginx.com 
38521555Smax.romanov@nginx.com #elif (NXT_HAVE_SHM_OPEN_ANON)
38531555Smax.romanov@nginx.com 
38541555Smax.romanov@nginx.com     fd = shm_open(SHM_ANON, O_RDWR, S_IRUSR | S_IWUSR);
38551555Smax.romanov@nginx.com     if (nxt_slow_path(fd == -1)) {
38561555Smax.romanov@nginx.com         nxt_unit_alert(ctx, "shm_open(SHM_ANON) failed: %s (%d)",
38571555Smax.romanov@nginx.com                        strerror(errno), errno);
38581555Smax.romanov@nginx.com 
38591555Smax.romanov@nginx.com         return -1;
38601555Smax.romanov@nginx.com     }
38611555Smax.romanov@nginx.com 
38621555Smax.romanov@nginx.com #elif (NXT_HAVE_SHM_OPEN)
38631555Smax.romanov@nginx.com 
38641555Smax.romanov@nginx.com     /* Just in case. */
38651555Smax.romanov@nginx.com     shm_unlink(name);
38661555Smax.romanov@nginx.com 
38671555Smax.romanov@nginx.com     fd = shm_open(name, O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR);
38681555Smax.romanov@nginx.com     if (nxt_slow_path(fd == -1)) {
38691555Smax.romanov@nginx.com         nxt_unit_alert(ctx, "shm_open(%s) failed: %s (%d)", name,
38701555Smax.romanov@nginx.com                        strerror(errno), errno);
38711555Smax.romanov@nginx.com 
38721555Smax.romanov@nginx.com         return -1;
38731555Smax.romanov@nginx.com     }
38741555Smax.romanov@nginx.com 
38751555Smax.romanov@nginx.com     if (nxt_slow_path(shm_unlink(name) == -1)) {
38761555Smax.romanov@nginx.com         nxt_unit_alert(ctx, "shm_unlink(%s) failed: %s (%d)", name,
38771555Smax.romanov@nginx.com                        strerror(errno), errno);
38781555Smax.romanov@nginx.com     }
38791555Smax.romanov@nginx.com 
38801555Smax.romanov@nginx.com #else
38811555Smax.romanov@nginx.com 
38821555Smax.romanov@nginx.com #error No working shared memory implementation.
38831555Smax.romanov@nginx.com 
38841555Smax.romanov@nginx.com #endif
38851555Smax.romanov@nginx.com 
38861555Smax.romanov@nginx.com     if (nxt_slow_path(ftruncate(fd, size) == -1)) {
38871555Smax.romanov@nginx.com         nxt_unit_alert(ctx, "ftruncate(%d) failed: %s (%d)", fd,
38881555Smax.romanov@nginx.com                        strerror(errno), errno);
38891555Smax.romanov@nginx.com 
38901555Smax.romanov@nginx.com         nxt_unit_close(fd);
38911555Smax.romanov@nginx.com 
38921555Smax.romanov@nginx.com         return -1;
38931555Smax.romanov@nginx.com     }
38941555Smax.romanov@nginx.com 
38951555Smax.romanov@nginx.com     return fd;
38961556Smax.romanov@nginx.com }
38971555Smax.romanov@nginx.com 
38981555Smax.romanov@nginx.com 
38991555Smax.romanov@nginx.com static int
nxt_unit_send_mmap(nxt_unit_ctx_t * ctx,nxt_unit_port_t * port,int fd)39001555Smax.romanov@nginx.com nxt_unit_send_mmap(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port, int fd)
39011555Smax.romanov@nginx.com {
39021555Smax.romanov@nginx.com     ssize_t          res;
39031555Smax.romanov@nginx.com     nxt_send_oob_t   oob;
39041555Smax.romanov@nginx.com     nxt_port_msg_t   msg;
39051555Smax.romanov@nginx.com     nxt_unit_impl_t  *lib;
39061544Smax.romanov@nginx.com     int              fds[2] = {fd, -1};
3907743Smax.romanov@nginx.com 
3908743Smax.romanov@nginx.com     lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit);
39091996St.nateldemoura@f5.com 
3910743Smax.romanov@nginx.com     msg.stream = 0;
3911743Smax.romanov@nginx.com     msg.pid = lib->pid;
39121996St.nateldemoura@f5.com     msg.reply_port = 0;
3913743Smax.romanov@nginx.com     msg.type = _NXT_PORT_MSG_MMAP;
3914743Smax.romanov@nginx.com     msg.last = 0;
3915743Smax.romanov@nginx.com     msg.mmap = 0;
3916743Smax.romanov@nginx.com     msg.nf = 0;
3917743Smax.romanov@nginx.com     msg.mf = 0;
3918743Smax.romanov@nginx.com 
3919743Smax.romanov@nginx.com     nxt_socket_msg_oob_init(&oob, fds);
3920743Smax.romanov@nginx.com 
3921743Smax.romanov@nginx.com     res = nxt_unit_port_send(ctx, port, &msg, sizeof(msg), &oob);
3922743Smax.romanov@nginx.com     if (nxt_slow_path(res != sizeof(msg))) {
3923743Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
3924743Smax.romanov@nginx.com     }
39251996St.nateldemoura@f5.com 
39261996St.nateldemoura@f5.com     return NXT_UNIT_OK;
39271996St.nateldemoura@f5.com }
3928743Smax.romanov@nginx.com 
3929743Smax.romanov@nginx.com 
3930743Smax.romanov@nginx.com static int
nxt_unit_get_outgoing_buf(nxt_unit_ctx_t * ctx,nxt_unit_port_t * port,uint32_t size,uint32_t min_size,nxt_unit_mmap_buf_t * mmap_buf,char * local_buf)3931743Smax.romanov@nginx.com nxt_unit_get_outgoing_buf(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port,
3932743Smax.romanov@nginx.com     uint32_t size, uint32_t min_size,
3933743Smax.romanov@nginx.com     nxt_unit_mmap_buf_t *mmap_buf, char *local_buf)
3934743Smax.romanov@nginx.com {
3935743Smax.romanov@nginx.com     int                     nchunks, min_nchunks;
3936743Smax.romanov@nginx.com     nxt_chunk_id_t          c;
39371544Smax.romanov@nginx.com     nxt_port_mmap_header_t  *hdr;
39381544Smax.romanov@nginx.com 
39391317Smax.romanov@nginx.com     if (size <= NXT_UNIT_MAX_PLAIN_SIZE) {
3940743Smax.romanov@nginx.com         if (local_buf != NULL) {
39411321Smax.romanov@nginx.com             mmap_buf->free_ptr = NULL;
3942743Smax.romanov@nginx.com             mmap_buf->plain_ptr = local_buf;
3943743Smax.romanov@nginx.com 
3944743Smax.romanov@nginx.com         } else {
39451317Smax.romanov@nginx.com             mmap_buf->free_ptr = nxt_unit_malloc(ctx,
39461317Smax.romanov@nginx.com                                                  size + sizeof(nxt_port_msg_t));
39471317Smax.romanov@nginx.com             if (nxt_slow_path(mmap_buf->free_ptr == NULL)) {
39481317Smax.romanov@nginx.com                 return NXT_UNIT_ERROR;
39491317Smax.romanov@nginx.com             }
39501317Smax.romanov@nginx.com 
39511623Smax.romanov@nginx.com             mmap_buf->plain_ptr = mmap_buf->free_ptr;
39521623Smax.romanov@nginx.com         }
39531317Smax.romanov@nginx.com 
39541317Smax.romanov@nginx.com         mmap_buf->hdr = NULL;
39551317Smax.romanov@nginx.com         mmap_buf->buf.start = mmap_buf->plain_ptr + sizeof(nxt_port_msg_t);
39561317Smax.romanov@nginx.com         mmap_buf->buf.free = mmap_buf->buf.start;
39571317Smax.romanov@nginx.com         mmap_buf->buf.end = mmap_buf->buf.start + size;
39581317Smax.romanov@nginx.com 
39591317Smax.romanov@nginx.com         nxt_unit_debug(ctx, "outgoing plain buffer allocation: (%p, %d)",
39601317Smax.romanov@nginx.com                        mmap_buf->buf.start, (int) size);
39611317Smax.romanov@nginx.com 
39621317Smax.romanov@nginx.com         return NXT_UNIT_OK;
39631317Smax.romanov@nginx.com     }
39641317Smax.romanov@nginx.com 
39651317Smax.romanov@nginx.com     nchunks = (size + PORT_MMAP_CHUNK_SIZE - 1) / PORT_MMAP_CHUNK_SIZE;
39661317Smax.romanov@nginx.com     min_nchunks = (min_size + PORT_MMAP_CHUNK_SIZE - 1) / PORT_MMAP_CHUNK_SIZE;
39671317Smax.romanov@nginx.com 
39681317Smax.romanov@nginx.com     hdr = nxt_unit_mmap_get(ctx, port, &c, &nchunks, min_nchunks);
39691317Smax.romanov@nginx.com     if (nxt_slow_path(hdr == NULL)) {
39701317Smax.romanov@nginx.com         if (nxt_fast_path(min_nchunks == 0 && nchunks == 0)) {
3971743Smax.romanov@nginx.com             mmap_buf->hdr = NULL;
39721321Smax.romanov@nginx.com             mmap_buf->buf.start = NULL;
39731321Smax.romanov@nginx.com             mmap_buf->buf.free = NULL;
39741544Smax.romanov@nginx.com             mmap_buf->buf.end = NULL;
3975743Smax.romanov@nginx.com             mmap_buf->free_ptr = NULL;
39761321Smax.romanov@nginx.com 
39771321Smax.romanov@nginx.com             return NXT_UNIT_OK;
39781321Smax.romanov@nginx.com         }
39791321Smax.romanov@nginx.com 
39801321Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
39811321Smax.romanov@nginx.com     }
39821321Smax.romanov@nginx.com 
39831321Smax.romanov@nginx.com     mmap_buf->hdr = hdr;
39841321Smax.romanov@nginx.com     mmap_buf->buf.start = (char *) nxt_port_mmap_chunk_start(hdr, c);
39851321Smax.romanov@nginx.com     mmap_buf->buf.free = mmap_buf->buf.start;
3986743Smax.romanov@nginx.com     mmap_buf->buf.end = mmap_buf->buf.start + nchunks * PORT_MMAP_CHUNK_SIZE;
3987743Smax.romanov@nginx.com     mmap_buf->free_ptr = NULL;
3988743Smax.romanov@nginx.com     mmap_buf->ctx_impl = nxt_container_of(ctx, nxt_unit_ctx_impl_t, ctx);
3989743Smax.romanov@nginx.com 
3990743Smax.romanov@nginx.com     nxt_unit_debug(ctx, "outgoing mmap allocation: (%d,%d,%d)",
3991743Smax.romanov@nginx.com                   (int) hdr->id, (int) c,
3992743Smax.romanov@nginx.com                   (int) (nchunks * PORT_MMAP_CHUNK_SIZE));
39931317Smax.romanov@nginx.com 
39941351Smax.romanov@nginx.com     return NXT_UNIT_OK;
3995743Smax.romanov@nginx.com }
3996743Smax.romanov@nginx.com 
3997743Smax.romanov@nginx.com 
3998743Smax.romanov@nginx.com static int
nxt_unit_incoming_mmap(nxt_unit_ctx_t * ctx,pid_t pid,int fd)3999743Smax.romanov@nginx.com nxt_unit_incoming_mmap(nxt_unit_ctx_t *ctx, pid_t pid, int fd)
4000743Smax.romanov@nginx.com {
4001743Smax.romanov@nginx.com     int                     rc;
4002743Smax.romanov@nginx.com     void                    *mem;
4003743Smax.romanov@nginx.com     nxt_queue_t             awaiting_rbuf;
4004743Smax.romanov@nginx.com     struct stat             mmap_stat;
4005743Smax.romanov@nginx.com     nxt_unit_mmap_t         *mm;
4006743Smax.romanov@nginx.com     nxt_unit_impl_t         *lib;
40071546Smax.romanov@nginx.com     nxt_unit_ctx_impl_t     *ctx_impl;
40081546Smax.romanov@nginx.com     nxt_unit_read_buf_t     *rbuf;
40091546Smax.romanov@nginx.com     nxt_port_mmap_header_t  *hdr;
40101546Smax.romanov@nginx.com 
40111546Smax.romanov@nginx.com     lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit);
40121546Smax.romanov@nginx.com 
40131546Smax.romanov@nginx.com     nxt_unit_debug(ctx, "incoming_mmap: fd %d from process %d", fd, (int) pid);
40141546Smax.romanov@nginx.com 
40151546Smax.romanov@nginx.com     if (fstat(fd, &mmap_stat) == -1) {
4016743Smax.romanov@nginx.com         nxt_unit_alert(ctx, "incoming_mmap: fstat(%d) failed: %s (%d)", fd,
4017743Smax.romanov@nginx.com                        strerror(errno), errno);
4018743Smax.romanov@nginx.com 
4019743Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
4020743Smax.romanov@nginx.com     }
40211548Smax.romanov@nginx.com 
40221548Smax.romanov@nginx.com     mem = mmap(NULL, mmap_stat.st_size, PROT_READ | PROT_WRITE,
40231548Smax.romanov@nginx.com                MAP_SHARED, fd, 0);
4024743Smax.romanov@nginx.com     if (nxt_slow_path(mem == MAP_FAILED)) {
4025743Smax.romanov@nginx.com         nxt_unit_alert(ctx, "incoming_mmap: mmap() failed: %s (%d)",
4026743Smax.romanov@nginx.com                        strerror(errno), errno);
4027743Smax.romanov@nginx.com 
4028743Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
4029743Smax.romanov@nginx.com     }
4030743Smax.romanov@nginx.com 
40311548Smax.romanov@nginx.com     hdr = mem;
40321548Smax.romanov@nginx.com 
40331548Smax.romanov@nginx.com     if (nxt_slow_path(hdr->src_pid != pid)) {
40341548Smax.romanov@nginx.com 
4035743Smax.romanov@nginx.com         nxt_unit_alert(ctx, "incoming_mmap: unexpected pid in mmap header "
4036743Smax.romanov@nginx.com                        "detected: %d != %d or %d != %d", (int) hdr->src_pid,
4037743Smax.romanov@nginx.com                        (int) pid, (int) hdr->dst_pid, (int) lib->pid);
4038743Smax.romanov@nginx.com 
40391546Smax.romanov@nginx.com         munmap(mem, PORT_MMAP_SIZE);
4040743Smax.romanov@nginx.com 
40411548Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
40421548Smax.romanov@nginx.com     }
40431548Smax.romanov@nginx.com 
4044743Smax.romanov@nginx.com     nxt_queue_init(&awaiting_rbuf);
4045743Smax.romanov@nginx.com 
4046743Smax.romanov@nginx.com     pthread_mutex_lock(&lib->incoming.mutex);
40471548Smax.romanov@nginx.com 
4048743Smax.romanov@nginx.com     mm = nxt_unit_mmap_at(&lib->incoming, hdr->id);
4049743Smax.romanov@nginx.com     if (nxt_slow_path(mm == NULL)) {
40501546Smax.romanov@nginx.com         nxt_unit_alert(ctx, "incoming_mmap: failed to add to incoming array");
40511546Smax.romanov@nginx.com 
40521548Smax.romanov@nginx.com         munmap(mem, PORT_MMAP_SIZE);
40531548Smax.romanov@nginx.com 
40541548Smax.romanov@nginx.com         rc = NXT_UNIT_ERROR;
4055743Smax.romanov@nginx.com 
40561548Smax.romanov@nginx.com     } else {
4057743Smax.romanov@nginx.com         mm->hdr = hdr;
4058743Smax.romanov@nginx.com 
4059743Smax.romanov@nginx.com         hdr->sent_over = 0xFFFFu;
40601548Smax.romanov@nginx.com 
40611548Smax.romanov@nginx.com         nxt_queue_add(&awaiting_rbuf, &mm->awaiting_rbuf);
4062743Smax.romanov@nginx.com         nxt_queue_init(&mm->awaiting_rbuf);
4063743Smax.romanov@nginx.com 
4064743Smax.romanov@nginx.com         rc = NXT_UNIT_OK;
4065743Smax.romanov@nginx.com     }
4066743Smax.romanov@nginx.com 
40671546Smax.romanov@nginx.com     pthread_mutex_unlock(&lib->incoming.mutex);
40681546Smax.romanov@nginx.com 
40691546Smax.romanov@nginx.com     nxt_queue_each(rbuf, &awaiting_rbuf, nxt_unit_read_buf_t, link) {
4070743Smax.romanov@nginx.com 
4071743Smax.romanov@nginx.com         ctx_impl = rbuf->ctx_impl;
4072743Smax.romanov@nginx.com 
40731548Smax.romanov@nginx.com         pthread_mutex_lock(&ctx_impl->mutex);
4074743Smax.romanov@nginx.com 
40751546Smax.romanov@nginx.com         nxt_queue_insert_head(&ctx_impl->pending_rbuf, &rbuf->link);
40761546Smax.romanov@nginx.com 
40771546Smax.romanov@nginx.com         pthread_mutex_unlock(&ctx_impl->mutex);
40781546Smax.romanov@nginx.com 
40791546Smax.romanov@nginx.com         nxt_atomic_fetch_add(&ctx_impl->wait_items, -1);
40801546Smax.romanov@nginx.com 
40811546Smax.romanov@nginx.com         nxt_unit_awake_ctx(ctx, ctx_impl);
40821546Smax.romanov@nginx.com 
40831546Smax.romanov@nginx.com     } nxt_queue_loop;
40841546Smax.romanov@nginx.com 
40851546Smax.romanov@nginx.com     return rc;
40861546Smax.romanov@nginx.com }
40871667Smax.romanov@nginx.com 
40881667Smax.romanov@nginx.com 
40891546Smax.romanov@nginx.com static void
nxt_unit_awake_ctx(nxt_unit_ctx_t * ctx,nxt_unit_ctx_impl_t * ctx_impl)40901546Smax.romanov@nginx.com nxt_unit_awake_ctx(nxt_unit_ctx_t *ctx, nxt_unit_ctx_impl_t *ctx_impl)
4091743Smax.romanov@nginx.com {
4092743Smax.romanov@nginx.com     nxt_port_msg_t  msg;
4093743Smax.romanov@nginx.com 
4094743Smax.romanov@nginx.com     if (nxt_fast_path(ctx == &ctx_impl->ctx)) {
4095743Smax.romanov@nginx.com         return;
40961667Smax.romanov@nginx.com     }
40971667Smax.romanov@nginx.com 
40981667Smax.romanov@nginx.com     if (nxt_slow_path(ctx_impl->read_port == NULL
40991667Smax.romanov@nginx.com                       || ctx_impl->read_port->out_fd == -1))
41001667Smax.romanov@nginx.com     {
41011667Smax.romanov@nginx.com         nxt_unit_alert(ctx, "target context read_port is NULL or not writable");
41021667Smax.romanov@nginx.com 
41031667Smax.romanov@nginx.com         return;
41041667Smax.romanov@nginx.com     }
41051667Smax.romanov@nginx.com 
41061667Smax.romanov@nginx.com     memset(&msg, 0, sizeof(nxt_port_msg_t));
41071667Smax.romanov@nginx.com 
41081667Smax.romanov@nginx.com     msg.type = _NXT_PORT_MSG_RPC_READY;
41091667Smax.romanov@nginx.com 
41101667Smax.romanov@nginx.com     (void) nxt_unit_port_send(ctx, ctx_impl->read_port,
41111667Smax.romanov@nginx.com                               &msg, sizeof(msg), NULL);
41121667Smax.romanov@nginx.com }
41131667Smax.romanov@nginx.com 
41141667Smax.romanov@nginx.com 
41151667Smax.romanov@nginx.com static int
nxt_unit_mmaps_init(nxt_unit_mmaps_t * mmaps)41161667Smax.romanov@nginx.com nxt_unit_mmaps_init(nxt_unit_mmaps_t *mmaps)
41171996St.nateldemoura@f5.com {
41181667Smax.romanov@nginx.com     mmaps->size = 0;
41191667Smax.romanov@nginx.com     mmaps->cap = 0;
41201667Smax.romanov@nginx.com     mmaps->elts = NULL;
41212217Sa.colomar@f5.com     mmaps->allocated_chunks = 0;
4122743Smax.romanov@nginx.com 
4123743Smax.romanov@nginx.com     return pthread_mutex_init(&mmaps->mutex, NULL);
4124743Smax.romanov@nginx.com }
4125743Smax.romanov@nginx.com 
4126743Smax.romanov@nginx.com 
41271321Smax.romanov@nginx.com nxt_inline void
nxt_unit_process_use(nxt_unit_process_t * process)41282217Sa.colomar@f5.com nxt_unit_process_use(nxt_unit_process_t *process)
41292217Sa.colomar@f5.com {
4130743Smax.romanov@nginx.com     nxt_atomic_fetch_add(&process->use_count, 1);
4131743Smax.romanov@nginx.com }
4132743Smax.romanov@nginx.com 
41331543Smax.romanov@nginx.com 
41341543Smax.romanov@nginx.com nxt_inline void
nxt_unit_process_release(nxt_unit_process_t * process)41351543Smax.romanov@nginx.com nxt_unit_process_release(nxt_unit_process_t *process)
41361543Smax.romanov@nginx.com {
41371543Smax.romanov@nginx.com     long c;
41381543Smax.romanov@nginx.com 
41391543Smax.romanov@nginx.com     c = nxt_atomic_fetch_add(&process->use_count, -1);
41401543Smax.romanov@nginx.com 
41411543Smax.romanov@nginx.com     if (c == 1) {
4142743Smax.romanov@nginx.com         nxt_unit_debug(NULL, "destroy process #%d", (int) process->pid);
4143743Smax.romanov@nginx.com 
4144743Smax.romanov@nginx.com         nxt_unit_free(NULL, process);
41451543Smax.romanov@nginx.com     }
41461543Smax.romanov@nginx.com }
41471543Smax.romanov@nginx.com 
41481543Smax.romanov@nginx.com 
4149743Smax.romanov@nginx.com static void
nxt_unit_mmaps_destroy(nxt_unit_mmaps_t * mmaps)41501623Smax.romanov@nginx.com nxt_unit_mmaps_destroy(nxt_unit_mmaps_t *mmaps)
4151743Smax.romanov@nginx.com {
4152743Smax.romanov@nginx.com     nxt_unit_mmap_t  *mm, *end;
4153743Smax.romanov@nginx.com 
4154743Smax.romanov@nginx.com     if (mmaps->elts != NULL) {
4155743Smax.romanov@nginx.com         end = mmaps->elts + mmaps->size;
4156743Smax.romanov@nginx.com 
4157743Smax.romanov@nginx.com         for (mm = mmaps->elts; mm < end; mm++) {
4158743Smax.romanov@nginx.com             munmap(mm->hdr, PORT_MMAP_SIZE);
4159743Smax.romanov@nginx.com         }
4160743Smax.romanov@nginx.com 
4161743Smax.romanov@nginx.com         nxt_unit_free(NULL, mmaps->elts);
4162743Smax.romanov@nginx.com     }
4163743Smax.romanov@nginx.com 
4164743Smax.romanov@nginx.com     pthread_mutex_destroy(&mmaps->mutex);
4165743Smax.romanov@nginx.com }
4166743Smax.romanov@nginx.com 
41671623Smax.romanov@nginx.com 
4168743Smax.romanov@nginx.com static int
nxt_unit_check_rbuf_mmap(nxt_unit_ctx_t * ctx,nxt_unit_mmaps_t * mmaps,pid_t pid,uint32_t id,nxt_port_mmap_header_t ** hdr,nxt_unit_read_buf_t * rbuf)4169743Smax.romanov@nginx.com nxt_unit_check_rbuf_mmap(nxt_unit_ctx_t *ctx, nxt_unit_mmaps_t *mmaps,
4170743Smax.romanov@nginx.com     pid_t pid, uint32_t id, nxt_port_mmap_header_t **hdr,
4171743Smax.romanov@nginx.com     nxt_unit_read_buf_t *rbuf)
4172743Smax.romanov@nginx.com {
4173743Smax.romanov@nginx.com     int                  res, need_rbuf;
41741546Smax.romanov@nginx.com     nxt_unit_mmap_t      *mm;
41751546Smax.romanov@nginx.com     nxt_unit_ctx_impl_t  *ctx_impl;
41761546Smax.romanov@nginx.com 
41771546Smax.romanov@nginx.com     mm = nxt_unit_mmap_at(mmaps, id);
4178743Smax.romanov@nginx.com     if (nxt_slow_path(mm == NULL)) {
41791546Smax.romanov@nginx.com         nxt_unit_alert(ctx, "failed to allocate mmap");
41801546Smax.romanov@nginx.com 
41811546Smax.romanov@nginx.com         pthread_mutex_unlock(&mmaps->mutex);
41821546Smax.romanov@nginx.com 
41831546Smax.romanov@nginx.com         *hdr = NULL;
41841546Smax.romanov@nginx.com 
41851546Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
41861546Smax.romanov@nginx.com     }
41871546Smax.romanov@nginx.com 
41881546Smax.romanov@nginx.com     *hdr = mm->hdr;
41891546Smax.romanov@nginx.com 
41901546Smax.romanov@nginx.com     if (nxt_fast_path(*hdr != NULL)) {
41911546Smax.romanov@nginx.com         return NXT_UNIT_OK;
41921546Smax.romanov@nginx.com     }
41931546Smax.romanov@nginx.com 
41941546Smax.romanov@nginx.com     need_rbuf = nxt_queue_is_empty(&mm->awaiting_rbuf);
41951546Smax.romanov@nginx.com 
41961546Smax.romanov@nginx.com     nxt_queue_insert_tail(&mm->awaiting_rbuf, &rbuf->link);
41971546Smax.romanov@nginx.com 
41981546Smax.romanov@nginx.com     pthread_mutex_unlock(&mmaps->mutex);
41991546Smax.romanov@nginx.com 
42001546Smax.romanov@nginx.com     ctx_impl = nxt_container_of(ctx, nxt_unit_ctx_impl_t, ctx);
42011546Smax.romanov@nginx.com 
42021546Smax.romanov@nginx.com     nxt_atomic_fetch_add(&ctx_impl->wait_items, 1);
42031546Smax.romanov@nginx.com 
42041546Smax.romanov@nginx.com     if (need_rbuf) {
42051546Smax.romanov@nginx.com         res = nxt_unit_get_mmap(ctx, pid, id);
42061546Smax.romanov@nginx.com         if (nxt_slow_path(res == NXT_UNIT_ERROR)) {
42071546Smax.romanov@nginx.com             return NXT_UNIT_ERROR;
42081546Smax.romanov@nginx.com         }
42091546Smax.romanov@nginx.com     }
42101546Smax.romanov@nginx.com 
42111546Smax.romanov@nginx.com     return NXT_UNIT_AGAIN;
42121546Smax.romanov@nginx.com }
42131546Smax.romanov@nginx.com 
42141546Smax.romanov@nginx.com 
42151546Smax.romanov@nginx.com static int
nxt_unit_mmap_read(nxt_unit_ctx_t * ctx,nxt_unit_recv_msg_t * recv_msg,nxt_unit_read_buf_t * rbuf)42161546Smax.romanov@nginx.com nxt_unit_mmap_read(nxt_unit_ctx_t *ctx, nxt_unit_recv_msg_t *recv_msg,
42171546Smax.romanov@nginx.com     nxt_unit_read_buf_t *rbuf)
42181546Smax.romanov@nginx.com {
42191546Smax.romanov@nginx.com     int                     res;
42201546Smax.romanov@nginx.com     void                    *start;
42211546Smax.romanov@nginx.com     uint32_t                size;
42221546Smax.romanov@nginx.com     nxt_unit_impl_t         *lib;
42231546Smax.romanov@nginx.com     nxt_unit_mmaps_t        *mmaps;
42241546Smax.romanov@nginx.com     nxt_unit_mmap_buf_t     *b, **incoming_tail;
42251546Smax.romanov@nginx.com     nxt_port_mmap_msg_t     *mmap_msg, *end;
4226743Smax.romanov@nginx.com     nxt_port_mmap_header_t  *hdr;
4227743Smax.romanov@nginx.com 
42281548Smax.romanov@nginx.com     if (nxt_slow_path(recv_msg->size < sizeof(nxt_port_mmap_msg_t))) {
42291546Smax.romanov@nginx.com         nxt_unit_warn(ctx, "#%"PRIu32": mmap_read: too small message (%d)",
42301131Smax.romanov@nginx.com                       recv_msg->stream, (int) recv_msg->size);
4231743Smax.romanov@nginx.com 
4232743Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
4233743Smax.romanov@nginx.com     }
4234743Smax.romanov@nginx.com 
4235743Smax.romanov@nginx.com     mmap_msg = recv_msg->start;
42361131Smax.romanov@nginx.com     end = nxt_pointer_to(recv_msg->start, recv_msg->size);
4237743Smax.romanov@nginx.com 
4238743Smax.romanov@nginx.com     incoming_tail = &recv_msg->incoming_buf;
4239743Smax.romanov@nginx.com 
4240743Smax.romanov@nginx.com     /* Allocating buffer structures. */
4241743Smax.romanov@nginx.com     for (; mmap_msg < end; mmap_msg++) {
4242743Smax.romanov@nginx.com         b = nxt_unit_mmap_buf_get(ctx);
4243743Smax.romanov@nginx.com         if (nxt_slow_path(b == NULL)) {
42441131Smax.romanov@nginx.com             nxt_unit_warn(ctx, "#%"PRIu32": mmap_read: failed to allocate buf",
42451131Smax.romanov@nginx.com                           recv_msg->stream);
42461546Smax.romanov@nginx.com 
42471317Smax.romanov@nginx.com             while (recv_msg->incoming_buf != NULL) {
42481317Smax.romanov@nginx.com                 nxt_unit_mmap_buf_release(recv_msg->incoming_buf);
42491317Smax.romanov@nginx.com             }
42501317Smax.romanov@nginx.com 
42511317Smax.romanov@nginx.com             return NXT_UNIT_ERROR;
42521317Smax.romanov@nginx.com         }
42531546Smax.romanov@nginx.com 
42541546Smax.romanov@nginx.com         nxt_unit_mmap_buf_insert(incoming_tail, b);
42551546Smax.romanov@nginx.com         incoming_tail = &b->next;
42561546Smax.romanov@nginx.com     }
42571317Smax.romanov@nginx.com 
42581317Smax.romanov@nginx.com     b = recv_msg->incoming_buf;
42591317Smax.romanov@nginx.com     mmap_msg = recv_msg->start;
42601317Smax.romanov@nginx.com 
42611317Smax.romanov@nginx.com     lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit);
42621317Smax.romanov@nginx.com 
42631317Smax.romanov@nginx.com     mmaps = &lib->incoming;
42641317Smax.romanov@nginx.com 
42651317Smax.romanov@nginx.com     pthread_mutex_lock(&mmaps->mutex);
42661317Smax.romanov@nginx.com 
42671548Smax.romanov@nginx.com     for (; mmap_msg < end; mmap_msg++) {
42681548Smax.romanov@nginx.com         res = nxt_unit_check_rbuf_mmap(ctx, mmaps,
42691548Smax.romanov@nginx.com                                        recv_msg->pid, mmap_msg->mmap_id,
42701546Smax.romanov@nginx.com                                        &hdr, rbuf);
42711546Smax.romanov@nginx.com 
4272743Smax.romanov@nginx.com         if (nxt_slow_path(res != NXT_UNIT_OK)) {
4273743Smax.romanov@nginx.com             while (recv_msg->incoming_buf != NULL) {
42741546Smax.romanov@nginx.com                 nxt_unit_mmap_buf_release(recv_msg->incoming_buf);
42751546Smax.romanov@nginx.com             }
42761546Smax.romanov@nginx.com 
42771546Smax.romanov@nginx.com             return res;
42781546Smax.romanov@nginx.com         }
42791546Smax.romanov@nginx.com 
42801546Smax.romanov@nginx.com         start = nxt_port_mmap_chunk_start(hdr, mmap_msg->chunk_id);
42811546Smax.romanov@nginx.com         size = mmap_msg->size;
42821546Smax.romanov@nginx.com 
42831546Smax.romanov@nginx.com         if (recv_msg->start == mmap_msg) {
4284743Smax.romanov@nginx.com             recv_msg->start = start;
4285743Smax.romanov@nginx.com             recv_msg->size = size;
4286743Smax.romanov@nginx.com         }
4287743Smax.romanov@nginx.com 
4288743Smax.romanov@nginx.com         b->buf.start = start;
4289743Smax.romanov@nginx.com         b->buf.free = start;
4290743Smax.romanov@nginx.com         b->buf.end = b->buf.start + size;
4291743Smax.romanov@nginx.com         b->hdr = hdr;
4292743Smax.romanov@nginx.com 
4293743Smax.romanov@nginx.com         b = b->next;
4294743Smax.romanov@nginx.com 
4295743Smax.romanov@nginx.com         nxt_unit_debug(ctx, "#%"PRIu32": mmap_read: [%p,%d] %d->%d,(%d,%d,%d)",
4296743Smax.romanov@nginx.com                        recv_msg->stream,
4297743Smax.romanov@nginx.com                        start, (int) size,
4298743Smax.romanov@nginx.com                        (int) hdr->src_pid, (int) hdr->dst_pid,
42991317Smax.romanov@nginx.com                        (int) hdr->id, (int) mmap_msg->chunk_id,
43001317Smax.romanov@nginx.com                        (int) mmap_msg->size);
4301976Smax.romanov@nginx.com     }
43021131Smax.romanov@nginx.com 
4303743Smax.romanov@nginx.com     pthread_mutex_unlock(&mmaps->mutex);
4304743Smax.romanov@nginx.com 
4305743Smax.romanov@nginx.com     return NXT_UNIT_OK;
4306976Smax.romanov@nginx.com }
4307743Smax.romanov@nginx.com 
4308743Smax.romanov@nginx.com 
43091546Smax.romanov@nginx.com static int
nxt_unit_get_mmap(nxt_unit_ctx_t * ctx,pid_t pid,uint32_t id)43101546Smax.romanov@nginx.com nxt_unit_get_mmap(nxt_unit_ctx_t *ctx, pid_t pid, uint32_t id)
43111546Smax.romanov@nginx.com {
43121546Smax.romanov@nginx.com     ssize_t              res;
43131546Smax.romanov@nginx.com     nxt_unit_impl_t      *lib;
43141546Smax.romanov@nginx.com     nxt_unit_ctx_impl_t  *ctx_impl;
43151546Smax.romanov@nginx.com 
43161546Smax.romanov@nginx.com     struct {
43171546Smax.romanov@nginx.com         nxt_port_msg_t           msg;
43181546Smax.romanov@nginx.com         nxt_port_msg_get_mmap_t  get_mmap;
43191546Smax.romanov@nginx.com     } m;
43201546Smax.romanov@nginx.com 
43211546Smax.romanov@nginx.com     lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit);
43221546Smax.romanov@nginx.com     ctx_impl = nxt_container_of(ctx, nxt_unit_ctx_impl_t, ctx);
43231546Smax.romanov@nginx.com 
43241546Smax.romanov@nginx.com     memset(&m.msg, 0, sizeof(nxt_port_msg_t));
43251546Smax.romanov@nginx.com 
43261546Smax.romanov@nginx.com     m.msg.pid = lib->pid;
43271546Smax.romanov@nginx.com     m.msg.reply_port = ctx_impl->read_port->id.id;
43281546Smax.romanov@nginx.com     m.msg.type = _NXT_PORT_MSG_GET_MMAP;
43291546Smax.romanov@nginx.com 
43301546Smax.romanov@nginx.com     m.get_mmap.id = id;
43311546Smax.romanov@nginx.com 
43321546Smax.romanov@nginx.com     nxt_unit_debug(ctx, "get_mmap: %d %d", (int) pid, (int) id);
43331546Smax.romanov@nginx.com 
43341546Smax.romanov@nginx.com     res = nxt_unit_port_send(ctx, lib->router_port, &m, sizeof(m), NULL);
43351546Smax.romanov@nginx.com     if (nxt_slow_path(res != sizeof(m))) {
43361546Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
43371546Smax.romanov@nginx.com     }
43381546Smax.romanov@nginx.com 
43391546Smax.romanov@nginx.com     return NXT_UNIT_OK;
43401996St.nateldemoura@f5.com }
43411546Smax.romanov@nginx.com 
43421546Smax.romanov@nginx.com 
43431546Smax.romanov@nginx.com static void
nxt_unit_mmap_release(nxt_unit_ctx_t * ctx,nxt_port_mmap_header_t * hdr,void * start,uint32_t size)4344743Smax.romanov@nginx.com nxt_unit_mmap_release(nxt_unit_ctx_t *ctx, nxt_port_mmap_header_t *hdr,
4345743Smax.romanov@nginx.com     void *start, uint32_t size)
4346743Smax.romanov@nginx.com {
4347743Smax.romanov@nginx.com     int              freed_chunks;
4348743Smax.romanov@nginx.com     u_char           *p, *end;
43491321Smax.romanov@nginx.com     nxt_chunk_id_t   c;
43501548Smax.romanov@nginx.com     nxt_unit_impl_t  *lib;
43511321Smax.romanov@nginx.com 
4352743Smax.romanov@nginx.com     memset(start, 0xA5, size);
43531321Smax.romanov@nginx.com 
43541321Smax.romanov@nginx.com     p = start;
43551321Smax.romanov@nginx.com     end = p + size;
43561321Smax.romanov@nginx.com     c = nxt_port_mmap_chunk_id(hdr, p);
4357743Smax.romanov@nginx.com     freed_chunks = 0;
4358743Smax.romanov@nginx.com 
4359743Smax.romanov@nginx.com     while (p < end) {
4360743Smax.romanov@nginx.com         nxt_port_mmap_set_chunk_free(hdr->free_map, c);
4361743Smax.romanov@nginx.com 
4362743Smax.romanov@nginx.com         p += PORT_MMAP_CHUNK_SIZE;
43631321Smax.romanov@nginx.com         c++;
4364743Smax.romanov@nginx.com         freed_chunks++;
4365743Smax.romanov@nginx.com     }
4366743Smax.romanov@nginx.com 
4367743Smax.romanov@nginx.com     lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit);
4368743Smax.romanov@nginx.com 
4369743Smax.romanov@nginx.com     if (hdr->src_pid == lib->pid && freed_chunks != 0) {
43701321Smax.romanov@nginx.com         nxt_atomic_fetch_add(&lib->outgoing.allocated_chunks, -freed_chunks);
43711321Smax.romanov@nginx.com 
43721321Smax.romanov@nginx.com         nxt_unit_debug(ctx, "allocated_chunks %d",
43731321Smax.romanov@nginx.com                        (int) lib->outgoing.allocated_chunks);
43741321Smax.romanov@nginx.com     }
43751321Smax.romanov@nginx.com 
43761548Smax.romanov@nginx.com     if (hdr->dst_pid == lib->pid
43771548Smax.romanov@nginx.com         && freed_chunks != 0
43781548Smax.romanov@nginx.com         && nxt_atomic_cmp_set(&hdr->oosm, 1, 0))
43791548Smax.romanov@nginx.com     {
43801321Smax.romanov@nginx.com         nxt_unit_send_shm_ack(ctx, hdr->src_pid);
43811321Smax.romanov@nginx.com     }
43821321Smax.romanov@nginx.com }
43831321Smax.romanov@nginx.com 
43841321Smax.romanov@nginx.com 
43851321Smax.romanov@nginx.com static int
nxt_unit_send_shm_ack(nxt_unit_ctx_t * ctx,pid_t pid)43861321Smax.romanov@nginx.com nxt_unit_send_shm_ack(nxt_unit_ctx_t *ctx, pid_t pid)
43871321Smax.romanov@nginx.com {
43881321Smax.romanov@nginx.com     ssize_t          res;
43891321Smax.romanov@nginx.com     nxt_port_msg_t   msg;
43901321Smax.romanov@nginx.com     nxt_unit_impl_t  *lib;
43911321Smax.romanov@nginx.com 
43921321Smax.romanov@nginx.com     lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit);
43931321Smax.romanov@nginx.com 
43941544Smax.romanov@nginx.com     msg.stream = 0;
43951544Smax.romanov@nginx.com     msg.pid = lib->pid;
43961544Smax.romanov@nginx.com     msg.reply_port = 0;
43971321Smax.romanov@nginx.com     msg.type = _NXT_PORT_MSG_SHM_ACK;
43981321Smax.romanov@nginx.com     msg.last = 0;
43991321Smax.romanov@nginx.com     msg.mmap = 0;
44001321Smax.romanov@nginx.com     msg.nf = 0;
44011321Smax.romanov@nginx.com     msg.mf = 0;
44021321Smax.romanov@nginx.com 
44031321Smax.romanov@nginx.com     res = nxt_unit_port_send(ctx, lib->router_port, &msg, sizeof(msg), NULL);
44041321Smax.romanov@nginx.com     if (nxt_slow_path(res != sizeof(msg))) {
44051321Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
44061321Smax.romanov@nginx.com     }
44071321Smax.romanov@nginx.com 
44081321Smax.romanov@nginx.com     return NXT_UNIT_OK;
44091996St.nateldemoura@f5.com }
44101321Smax.romanov@nginx.com 
44111321Smax.romanov@nginx.com 
4412743Smax.romanov@nginx.com static nxt_int_t
nxt_unit_lvlhsh_pid_test(nxt_lvlhsh_query_t * lhq,void * data)4413743Smax.romanov@nginx.com nxt_unit_lvlhsh_pid_test(nxt_lvlhsh_query_t *lhq, void *data)
4414743Smax.romanov@nginx.com {
4415743Smax.romanov@nginx.com     nxt_process_t  *process;
4416743Smax.romanov@nginx.com 
4417743Smax.romanov@nginx.com     process = data;
4418743Smax.romanov@nginx.com 
4419743Smax.romanov@nginx.com     if (lhq->key.length == sizeof(pid_t)
4420743Smax.romanov@nginx.com         && *(pid_t *) lhq->key.start == process->pid)
4421743Smax.romanov@nginx.com     {
4422743Smax.romanov@nginx.com         return NXT_OK;
4423743Smax.romanov@nginx.com     }
4424743Smax.romanov@nginx.com 
4425743Smax.romanov@nginx.com     return NXT_DECLINED;
4426743Smax.romanov@nginx.com }
4427743Smax.romanov@nginx.com 
4428743Smax.romanov@nginx.com 
4429743Smax.romanov@nginx.com static const nxt_lvlhsh_proto_t  lvlhsh_processes_proto  nxt_aligned(64) = {
4430743Smax.romanov@nginx.com     NXT_LVLHSH_DEFAULT,
4431743Smax.romanov@nginx.com     nxt_unit_lvlhsh_pid_test,
4432743Smax.romanov@nginx.com     nxt_unit_lvlhsh_alloc,
4433743Smax.romanov@nginx.com     nxt_unit_lvlhsh_free,
4434743Smax.romanov@nginx.com };
4435743Smax.romanov@nginx.com 
4436743Smax.romanov@nginx.com 
4437743Smax.romanov@nginx.com static inline void
nxt_unit_process_lhq_pid(nxt_lvlhsh_query_t * lhq,pid_t * pid)44381616Smax.romanov@nginx.com nxt_unit_process_lhq_pid(nxt_lvlhsh_query_t *lhq, pid_t *pid)
44391616Smax.romanov@nginx.com {
4440743Smax.romanov@nginx.com     lhq->key_hash = nxt_murmur_hash2(pid, sizeof(*pid));
4441743Smax.romanov@nginx.com     lhq->key.length = sizeof(*pid);
4442743Smax.romanov@nginx.com     lhq->key.start = (u_char *) pid;
4443743Smax.romanov@nginx.com     lhq->proto = &lvlhsh_processes_proto;
4444743Smax.romanov@nginx.com }
4445743Smax.romanov@nginx.com 
4446743Smax.romanov@nginx.com 
4447743Smax.romanov@nginx.com static nxt_unit_process_t *
nxt_unit_process_get(nxt_unit_ctx_t * ctx,pid_t pid)4448743Smax.romanov@nginx.com nxt_unit_process_get(nxt_unit_ctx_t *ctx, pid_t pid)
4449743Smax.romanov@nginx.com {
4450743Smax.romanov@nginx.com     nxt_unit_impl_t     *lib;
4451743Smax.romanov@nginx.com     nxt_unit_process_t  *process;
4452743Smax.romanov@nginx.com     nxt_lvlhsh_query_t  lhq;
4453743Smax.romanov@nginx.com 
44541623Smax.romanov@nginx.com     lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit);
4455743Smax.romanov@nginx.com 
44561623Smax.romanov@nginx.com     nxt_unit_process_lhq_pid(&lhq, &pid);
4457743Smax.romanov@nginx.com 
4458743Smax.romanov@nginx.com     if (nxt_lvlhsh_find(&lib->processes, &lhq) == NXT_OK) {
4459743Smax.romanov@nginx.com         process = lhq.value;
44601623Smax.romanov@nginx.com         nxt_unit_process_use(process);
44611623Smax.romanov@nginx.com 
4462743Smax.romanov@nginx.com         return process;
4463743Smax.romanov@nginx.com     }
4464743Smax.romanov@nginx.com 
4465743Smax.romanov@nginx.com     process = nxt_unit_malloc(ctx, sizeof(nxt_unit_process_t));
44661543Smax.romanov@nginx.com     if (nxt_slow_path(process == NULL)) {
4467743Smax.romanov@nginx.com         nxt_unit_alert(ctx, "failed to allocate process for #%d", (int) pid);
4468743Smax.romanov@nginx.com 
4469743Smax.romanov@nginx.com         return NULL;
4470743Smax.romanov@nginx.com     }
44711623Smax.romanov@nginx.com 
4472743Smax.romanov@nginx.com     process->pid = pid;
44731623Smax.romanov@nginx.com     process->use_count = 2;
4474743Smax.romanov@nginx.com     process->next_port_id = 0;
4475743Smax.romanov@nginx.com     process->lib = lib;
4476743Smax.romanov@nginx.com 
4477743Smax.romanov@nginx.com     nxt_queue_init(&process->ports);
4478743Smax.romanov@nginx.com 
44791555Smax.romanov@nginx.com     lhq.replace = 0;
4480743Smax.romanov@nginx.com     lhq.value = process;
4481743Smax.romanov@nginx.com 
4482743Smax.romanov@nginx.com     switch (nxt_lvlhsh_insert(&lib->processes, &lhq)) {
4483743Smax.romanov@nginx.com 
4484743Smax.romanov@nginx.com     case NXT_OK:
4485743Smax.romanov@nginx.com         break;
4486743Smax.romanov@nginx.com 
4487743Smax.romanov@nginx.com     default:
4488743Smax.romanov@nginx.com         nxt_unit_alert(ctx, "process %d insert failed", (int) pid);
4489743Smax.romanov@nginx.com 
4490743Smax.romanov@nginx.com         nxt_unit_free(ctx, process);
4491743Smax.romanov@nginx.com         process = NULL;
4492743Smax.romanov@nginx.com         break;
4493743Smax.romanov@nginx.com     }
44941623Smax.romanov@nginx.com 
44951623Smax.romanov@nginx.com     return process;
44961623Smax.romanov@nginx.com }
4497743Smax.romanov@nginx.com 
4498743Smax.romanov@nginx.com 
4499743Smax.romanov@nginx.com static nxt_unit_process_t *
nxt_unit_process_find(nxt_unit_impl_t * lib,pid_t pid,int remove)4500743Smax.romanov@nginx.com nxt_unit_process_find(nxt_unit_impl_t *lib, pid_t pid, int remove)
4501743Smax.romanov@nginx.com {
4502743Smax.romanov@nginx.com     int                 rc;
4503743Smax.romanov@nginx.com     nxt_lvlhsh_query_t  lhq;
4504743Smax.romanov@nginx.com 
4505743Smax.romanov@nginx.com     nxt_unit_process_lhq_pid(&lhq, &pid);
45061543Smax.romanov@nginx.com 
4507743Smax.romanov@nginx.com     if (remove) {
4508743Smax.romanov@nginx.com         rc = nxt_lvlhsh_delete(&lib->processes, &lhq);
4509743Smax.romanov@nginx.com 
4510743Smax.romanov@nginx.com     } else {
4511743Smax.romanov@nginx.com         rc = nxt_lvlhsh_find(&lib->processes, &lhq);
4512743Smax.romanov@nginx.com     }
4513743Smax.romanov@nginx.com 
4514743Smax.romanov@nginx.com     if (rc == NXT_OK) {
4515743Smax.romanov@nginx.com         if (!remove) {
4516743Smax.romanov@nginx.com             nxt_unit_process_use(lhq.value);
4517743Smax.romanov@nginx.com         }
4518743Smax.romanov@nginx.com 
4519743Smax.romanov@nginx.com         return lhq.value;
4520743Smax.romanov@nginx.com     }
4521743Smax.romanov@nginx.com 
45221544Smax.romanov@nginx.com     return NULL;
4523743Smax.romanov@nginx.com }
4524743Smax.romanov@nginx.com 
45251544Smax.romanov@nginx.com 
4526743Smax.romanov@nginx.com static nxt_unit_process_t *
nxt_unit_process_pop_first(nxt_unit_impl_t * lib)4527743Smax.romanov@nginx.com nxt_unit_process_pop_first(nxt_unit_impl_t *lib)
4528743Smax.romanov@nginx.com {
4529743Smax.romanov@nginx.com     return nxt_lvlhsh_retrieve(&lib->processes, &lvlhsh_processes_proto, NULL);
4530743Smax.romanov@nginx.com }
4531743Smax.romanov@nginx.com 
4532743Smax.romanov@nginx.com 
4533743Smax.romanov@nginx.com int
nxt_unit_run(nxt_unit_ctx_t * ctx)4534743Smax.romanov@nginx.com nxt_unit_run(nxt_unit_ctx_t *ctx)
4535743Smax.romanov@nginx.com {
4536743Smax.romanov@nginx.com     int                  rc;
4537743Smax.romanov@nginx.com     nxt_unit_ctx_impl_t  *ctx_impl;
4538743Smax.romanov@nginx.com 
4539743Smax.romanov@nginx.com     nxt_unit_ctx_use(ctx);
4540743Smax.romanov@nginx.com 
4541743Smax.romanov@nginx.com     ctx_impl = nxt_container_of(ctx, nxt_unit_ctx_impl_t, ctx);
45421663Smax.romanov@nginx.com 
45431663Smax.romanov@nginx.com     rc = NXT_UNIT_OK;
45441547Smax.romanov@nginx.com 
45451547Smax.romanov@nginx.com     while (nxt_fast_path(ctx_impl->online)) {
4546743Smax.romanov@nginx.com         rc = nxt_unit_run_once_impl(ctx);
45471663Smax.romanov@nginx.com 
45481663Smax.romanov@nginx.com         if (nxt_slow_path(rc == NXT_UNIT_ERROR)) {
4549743Smax.romanov@nginx.com             nxt_unit_quit(ctx, NXT_QUIT_NORMAL);
4550743Smax.romanov@nginx.com             break;
45511663Smax.romanov@nginx.com         }
45521547Smax.romanov@nginx.com     }
45531547Smax.romanov@nginx.com 
45541547Smax.romanov@nginx.com     nxt_unit_ctx_release(ctx);
45551980Smax.romanov@nginx.com 
45561438Smax.romanov@nginx.com     return rc;
45571438Smax.romanov@nginx.com }
4558743Smax.romanov@nginx.com 
4559743Smax.romanov@nginx.com 
45601547Smax.romanov@nginx.com int
nxt_unit_run_once(nxt_unit_ctx_t * ctx)45611543Smax.romanov@nginx.com nxt_unit_run_once(nxt_unit_ctx_t *ctx)
4562743Smax.romanov@nginx.com {
4563743Smax.romanov@nginx.com     int  rc;
4564743Smax.romanov@nginx.com 
4565743Smax.romanov@nginx.com     nxt_unit_ctx_use(ctx);
4566828Salexander.borisov@nginx.com 
4567743Smax.romanov@nginx.com     rc = nxt_unit_run_once_impl(ctx);
4568743Smax.romanov@nginx.com 
45691547Smax.romanov@nginx.com     nxt_unit_ctx_release(ctx);
45701547Smax.romanov@nginx.com 
45711547Smax.romanov@nginx.com     return rc;
45721547Smax.romanov@nginx.com }
45731547Smax.romanov@nginx.com 
45741547Smax.romanov@nginx.com 
45751547Smax.romanov@nginx.com static int
nxt_unit_run_once_impl(nxt_unit_ctx_t * ctx)45761547Smax.romanov@nginx.com nxt_unit_run_once_impl(nxt_unit_ctx_t *ctx)
45771547Smax.romanov@nginx.com {
45781547Smax.romanov@nginx.com     int                  rc;
45791547Smax.romanov@nginx.com     nxt_unit_read_buf_t  *rbuf;
45801547Smax.romanov@nginx.com 
45811547Smax.romanov@nginx.com     rbuf = nxt_unit_read_buf_get(ctx);
45821547Smax.romanov@nginx.com     if (nxt_slow_path(rbuf == NULL)) {
45831547Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
4584743Smax.romanov@nginx.com     }
45851547Smax.romanov@nginx.com 
45861547Smax.romanov@nginx.com     rc = nxt_unit_read_buf(ctx, rbuf);
45871547Smax.romanov@nginx.com     if (nxt_slow_path(rc != NXT_UNIT_OK)) {
45881547Smax.romanov@nginx.com         nxt_unit_read_buf_release(ctx, rbuf);
45891547Smax.romanov@nginx.com 
45901547Smax.romanov@nginx.com         return rc;
45911547Smax.romanov@nginx.com     }
45921547Smax.romanov@nginx.com 
45931547Smax.romanov@nginx.com     rc = nxt_unit_process_msg(ctx, rbuf, NULL);
45941547Smax.romanov@nginx.com     if (nxt_slow_path(rc == NXT_UNIT_ERROR)) {
45951547Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
45961547Smax.romanov@nginx.com     }
45971547Smax.romanov@nginx.com 
45981547Smax.romanov@nginx.com     rc = nxt_unit_process_pending_rbuf(ctx);
45991713Smax.romanov@nginx.com     if (nxt_slow_path(rc == NXT_UNIT_ERROR)) {
46001547Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
46011547Smax.romanov@nginx.com     }
46021547Smax.romanov@nginx.com 
46031547Smax.romanov@nginx.com     nxt_unit_process_ready_req(ctx);
46041547Smax.romanov@nginx.com 
46051547Smax.romanov@nginx.com     return rc;
46061547Smax.romanov@nginx.com }
46071547Smax.romanov@nginx.com 
46081547Smax.romanov@nginx.com 
46091547Smax.romanov@nginx.com static int
nxt_unit_read_buf(nxt_unit_ctx_t * ctx,nxt_unit_read_buf_t * rbuf)46101547Smax.romanov@nginx.com nxt_unit_read_buf(nxt_unit_ctx_t *ctx, nxt_unit_read_buf_t *rbuf)
46111547Smax.romanov@nginx.com {
46121547Smax.romanov@nginx.com     int                   nevents, res, err;
46131547Smax.romanov@nginx.com     nxt_uint_t            nfds;
46141547Smax.romanov@nginx.com     nxt_unit_impl_t       *lib;
46151547Smax.romanov@nginx.com     nxt_unit_ctx_impl_t   *ctx_impl;
46161547Smax.romanov@nginx.com     nxt_unit_port_impl_t  *port_impl;
46171547Smax.romanov@nginx.com     struct pollfd         fds[2];
46181555Smax.romanov@nginx.com 
46191980Smax.romanov@nginx.com     ctx_impl = nxt_container_of(ctx, nxt_unit_ctx_impl_t, ctx);
46201555Smax.romanov@nginx.com 
46211555Smax.romanov@nginx.com     if (ctx_impl->wait_items > 0 || !nxt_unit_chk_ready(ctx)) {
46221555Smax.romanov@nginx.com         return nxt_unit_ctx_port_recv(ctx, ctx_impl->read_port, rbuf);
46231555Smax.romanov@nginx.com     }
46241547Smax.romanov@nginx.com 
46251547Smax.romanov@nginx.com     port_impl = nxt_container_of(ctx_impl->read_port, nxt_unit_port_impl_t,
46261547Smax.romanov@nginx.com                                  port);
46271980Smax.romanov@nginx.com 
46281555Smax.romanov@nginx.com     lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit);
46291555Smax.romanov@nginx.com 
46301555Smax.romanov@nginx.com retry:
46311555Smax.romanov@nginx.com 
46321555Smax.romanov@nginx.com     if (port_impl->from_socket == 0) {
46331547Smax.romanov@nginx.com         res = nxt_unit_port_queue_recv(ctx_impl->read_port, rbuf);
46341666Smax.romanov@nginx.com         if (res == NXT_UNIT_OK) {
46351666Smax.romanov@nginx.com             if (nxt_unit_is_read_socket(rbuf)) {
46361547Smax.romanov@nginx.com                 port_impl->from_socket++;
46371547Smax.romanov@nginx.com 
46381555Smax.romanov@nginx.com                 nxt_unit_debug(ctx, "port{%d,%d} dequeue 1 read_socket %d",
46391555Smax.romanov@nginx.com                                (int) ctx_impl->read_port->id.pid,
46401555Smax.romanov@nginx.com                                (int) ctx_impl->read_port->id.id,
46411555Smax.romanov@nginx.com                                port_impl->from_socket);
46421555Smax.romanov@nginx.com 
46431555Smax.romanov@nginx.com             } else {
46441555Smax.romanov@nginx.com                 nxt_unit_debug(ctx, "port{%d,%d} dequeue %d",
46451555Smax.romanov@nginx.com                                (int) ctx_impl->read_port->id.pid,
46461555Smax.romanov@nginx.com                                (int) ctx_impl->read_port->id.id,
46471555Smax.romanov@nginx.com                                (int) rbuf->size);
46481555Smax.romanov@nginx.com 
46491555Smax.romanov@nginx.com                 return NXT_UNIT_OK;
46501555Smax.romanov@nginx.com             }
46511555Smax.romanov@nginx.com         }
46521555Smax.romanov@nginx.com     }
46531555Smax.romanov@nginx.com 
46541555Smax.romanov@nginx.com     if (nxt_fast_path(nxt_unit_chk_ready(ctx))) {
46551555Smax.romanov@nginx.com         res = nxt_unit_app_queue_recv(ctx, lib->shared_port, rbuf);
46561555Smax.romanov@nginx.com         if (res == NXT_UNIT_OK) {
46571555Smax.romanov@nginx.com             return NXT_UNIT_OK;
46581555Smax.romanov@nginx.com         }
46591555Smax.romanov@nginx.com 
46601980Smax.romanov@nginx.com         fds[1].fd = lib->shared_port->in_fd;
46611980Smax.romanov@nginx.com         fds[1].events = POLLIN;
46621980Smax.romanov@nginx.com 
46631980Smax.romanov@nginx.com         nfds = 2;
46641980Smax.romanov@nginx.com 
46651980Smax.romanov@nginx.com     } else {
46661980Smax.romanov@nginx.com         nfds = 1;
46671980Smax.romanov@nginx.com     }
46681980Smax.romanov@nginx.com 
46691980Smax.romanov@nginx.com     fds[0].fd = ctx_impl->read_port->in_fd;
46701980Smax.romanov@nginx.com     fds[0].events = POLLIN;
46711980Smax.romanov@nginx.com     fds[0].revents = 0;
46721980Smax.romanov@nginx.com 
46731555Smax.romanov@nginx.com     fds[1].revents = 0;
46741555Smax.romanov@nginx.com 
46751547Smax.romanov@nginx.com     nevents = poll(fds, nfds, -1);
46761547Smax.romanov@nginx.com     if (nxt_slow_path(nevents == -1)) {
46771547Smax.romanov@nginx.com         err = errno;
46781547Smax.romanov@nginx.com 
46791547Smax.romanov@nginx.com         if (err == EINTR) {
46801547Smax.romanov@nginx.com             goto retry;
46811980Smax.romanov@nginx.com         }
46821555Smax.romanov@nginx.com 
46831547Smax.romanov@nginx.com         nxt_unit_alert(ctx, "poll(%d,%d) failed: %s (%d)",
46841547Smax.romanov@nginx.com                        fds[0].fd, fds[1].fd, strerror(err), err);
46851547Smax.romanov@nginx.com 
46861547Smax.romanov@nginx.com         rbuf->size = -1;
46871547Smax.romanov@nginx.com 
46881547Smax.romanov@nginx.com         return (err == EAGAIN) ? NXT_UNIT_AGAIN : NXT_UNIT_ERROR;
46891555Smax.romanov@nginx.com     }
46901555Smax.romanov@nginx.com 
46911547Smax.romanov@nginx.com     nxt_unit_debug(ctx, "poll(%d,%d): %d, revents [%04X, %04X]",
46921547Smax.romanov@nginx.com                    fds[0].fd, fds[1].fd, nevents, fds[0].revents,
46931547Smax.romanov@nginx.com                    fds[1].revents);
46941547Smax.romanov@nginx.com 
46951547Smax.romanov@nginx.com     if ((fds[0].revents & POLLIN) != 0) {
46961547Smax.romanov@nginx.com         res = nxt_unit_ctx_port_recv(ctx, ctx_impl->read_port, rbuf);
46971996St.nateldemoura@f5.com         if (res == NXT_UNIT_AGAIN) {
46981555Smax.romanov@nginx.com             goto retry;
46991555Smax.romanov@nginx.com         }
47001555Smax.romanov@nginx.com 
47011547Smax.romanov@nginx.com         return res;
47021555Smax.romanov@nginx.com     }
47031555Smax.romanov@nginx.com 
47041555Smax.romanov@nginx.com     if ((fds[1].revents & POLLIN) != 0) {
47051555Smax.romanov@nginx.com         res = nxt_unit_shared_port_recv(ctx, lib->shared_port, rbuf);
47061555Smax.romanov@nginx.com         if (res == NXT_UNIT_AGAIN) {
47071555Smax.romanov@nginx.com             goto retry;
47081547Smax.romanov@nginx.com         }
47091547Smax.romanov@nginx.com 
47101547Smax.romanov@nginx.com         return res;
47111555Smax.romanov@nginx.com     }
47121555Smax.romanov@nginx.com 
47131555Smax.romanov@nginx.com     nxt_unit_alert(ctx, "poll(%d,%d): %d unexpected revents [%04uXi, %04uXi]",
47141555Smax.romanov@nginx.com                    fds[0].fd, fds[1].fd, nevents, fds[0].revents,
47151555Smax.romanov@nginx.com                    fds[1].revents);
47161555Smax.romanov@nginx.com 
47171555Smax.romanov@nginx.com     return NXT_UNIT_ERROR;
47181555Smax.romanov@nginx.com }
47191555Smax.romanov@nginx.com 
47201555Smax.romanov@nginx.com 
47211555Smax.romanov@nginx.com static int
nxt_unit_chk_ready(nxt_unit_ctx_t * ctx)47221547Smax.romanov@nginx.com nxt_unit_chk_ready(nxt_unit_ctx_t *ctx)
47231547Smax.romanov@nginx.com {
47241547Smax.romanov@nginx.com     nxt_unit_impl_t      *lib;
47251547Smax.romanov@nginx.com     nxt_unit_ctx_impl_t  *ctx_impl;
47261547Smax.romanov@nginx.com 
47271547Smax.romanov@nginx.com     ctx_impl = nxt_container_of(ctx, nxt_unit_ctx_impl_t, ctx);
47281980Smax.romanov@nginx.com     lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit);
47291980Smax.romanov@nginx.com 
47301980Smax.romanov@nginx.com     return (ctx_impl->ready
47311980Smax.romanov@nginx.com             && (lib->request_limit == 0
47321980Smax.romanov@nginx.com                 || lib->request_count < lib->request_limit));
47331980Smax.romanov@nginx.com }
47341980Smax.romanov@nginx.com 
47351980Smax.romanov@nginx.com 
47361980Smax.romanov@nginx.com static int
nxt_unit_process_pending_rbuf(nxt_unit_ctx_t * ctx)47371980Smax.romanov@nginx.com nxt_unit_process_pending_rbuf(nxt_unit_ctx_t *ctx)
47381980Smax.romanov@nginx.com {
47391980Smax.romanov@nginx.com     int                  rc;
47401980Smax.romanov@nginx.com     nxt_queue_t          pending_rbuf;
47411980Smax.romanov@nginx.com     nxt_unit_ctx_impl_t  *ctx_impl;
47421980Smax.romanov@nginx.com     nxt_unit_read_buf_t  *rbuf;
47431547Smax.romanov@nginx.com 
47441547Smax.romanov@nginx.com     ctx_impl = nxt_container_of(ctx, nxt_unit_ctx_impl_t, ctx);
47451547Smax.romanov@nginx.com 
47461547Smax.romanov@nginx.com     pthread_mutex_lock(&ctx_impl->mutex);
4747743Smax.romanov@nginx.com 
47481321Smax.romanov@nginx.com     if (nxt_queue_is_empty(&ctx_impl->pending_rbuf)) {
47491321Smax.romanov@nginx.com         pthread_mutex_unlock(&ctx_impl->mutex);
4750743Smax.romanov@nginx.com 
4751743Smax.romanov@nginx.com         return NXT_UNIT_OK;
47521321Smax.romanov@nginx.com     }
47531321Smax.romanov@nginx.com 
47541547Smax.romanov@nginx.com     nxt_queue_init(&pending_rbuf);
47551321Smax.romanov@nginx.com 
47561321Smax.romanov@nginx.com     nxt_queue_add(&pending_rbuf, &ctx_impl->pending_rbuf);
47571547Smax.romanov@nginx.com     nxt_queue_init(&ctx_impl->pending_rbuf);
47581547Smax.romanov@nginx.com 
47591547Smax.romanov@nginx.com     pthread_mutex_unlock(&ctx_impl->mutex);
47601714Smax.romanov@nginx.com 
47611714Smax.romanov@nginx.com     rc = NXT_UNIT_OK;
47621547Smax.romanov@nginx.com 
47631547Smax.romanov@nginx.com     nxt_queue_each(rbuf, &pending_rbuf, nxt_unit_read_buf_t, link) {
47641547Smax.romanov@nginx.com 
47651547Smax.romanov@nginx.com         if (nxt_fast_path(rc != NXT_UNIT_ERROR)) {
47661547Smax.romanov@nginx.com             rc = nxt_unit_process_msg(&ctx_impl->ctx, rbuf, NULL);
47671547Smax.romanov@nginx.com 
47681547Smax.romanov@nginx.com         } else {
47691547Smax.romanov@nginx.com             nxt_unit_read_buf_release(ctx, rbuf);
47701547Smax.romanov@nginx.com         }
47711547Smax.romanov@nginx.com 
47721713Smax.romanov@nginx.com     } nxt_queue_loop;
47731547Smax.romanov@nginx.com 
47741547Smax.romanov@nginx.com     if (!ctx_impl->ready) {
47751547Smax.romanov@nginx.com         nxt_unit_quit(ctx, NXT_QUIT_GRACEFUL);
47761321Smax.romanov@nginx.com     }
47771321Smax.romanov@nginx.com 
47781547Smax.romanov@nginx.com     return rc;
47791543Smax.romanov@nginx.com }
47801980Smax.romanov@nginx.com 
47811980Smax.romanov@nginx.com 
47821980Smax.romanov@nginx.com static void
nxt_unit_process_ready_req(nxt_unit_ctx_t * ctx)47831980Smax.romanov@nginx.com nxt_unit_process_ready_req(nxt_unit_ctx_t *ctx)
4784743Smax.romanov@nginx.com {
4785743Smax.romanov@nginx.com     int                           res;
4786743Smax.romanov@nginx.com     nxt_queue_t                   ready_req;
4787743Smax.romanov@nginx.com     nxt_unit_impl_t               *lib;
47881321Smax.romanov@nginx.com     nxt_unit_ctx_impl_t           *ctx_impl;
47891547Smax.romanov@nginx.com     nxt_unit_request_info_t       *req;
47901545Smax.romanov@nginx.com     nxt_unit_request_info_impl_t  *req_impl;
47911555Smax.romanov@nginx.com 
47921545Smax.romanov@nginx.com     ctx_impl = nxt_container_of(ctx, nxt_unit_ctx_impl_t, ctx);
47931545Smax.romanov@nginx.com 
47941547Smax.romanov@nginx.com     pthread_mutex_lock(&ctx_impl->mutex);
47951555Smax.romanov@nginx.com 
47961545Smax.romanov@nginx.com     if (nxt_queue_is_empty(&ctx_impl->ready_req)) {
47971545Smax.romanov@nginx.com         pthread_mutex_unlock(&ctx_impl->mutex);
47981547Smax.romanov@nginx.com 
47991547Smax.romanov@nginx.com         return;
48001545Smax.romanov@nginx.com     }
48011545Smax.romanov@nginx.com 
48021545Smax.romanov@nginx.com     nxt_queue_init(&ready_req);
48031545Smax.romanov@nginx.com 
48041545Smax.romanov@nginx.com     nxt_queue_add(&ready_req, &ctx_impl->ready_req);
48051545Smax.romanov@nginx.com     nxt_queue_init(&ctx_impl->ready_req);
48061545Smax.romanov@nginx.com 
48071545Smax.romanov@nginx.com     pthread_mutex_unlock(&ctx_impl->mutex);
48081714Smax.romanov@nginx.com 
48091714Smax.romanov@nginx.com     nxt_queue_each(req_impl, &ready_req,
48101545Smax.romanov@nginx.com                    nxt_unit_request_info_impl_t, port_wait_link)
48111545Smax.romanov@nginx.com     {
48121545Smax.romanov@nginx.com         lib = nxt_container_of(ctx_impl->ctx.unit, nxt_unit_impl_t, unit);
48131545Smax.romanov@nginx.com 
48141545Smax.romanov@nginx.com         req = &req_impl->req;
48151545Smax.romanov@nginx.com 
48161545Smax.romanov@nginx.com         res = nxt_unit_send_req_headers_ack(req);
48171545Smax.romanov@nginx.com         if (nxt_slow_path(res != NXT_UNIT_OK)) {
48181545Smax.romanov@nginx.com             nxt_unit_request_done(req, NXT_UNIT_ERROR);
48191545Smax.romanov@nginx.com 
48201555Smax.romanov@nginx.com             continue;
48211555Smax.romanov@nginx.com         }
48221555Smax.romanov@nginx.com 
48231555Smax.romanov@nginx.com         if (req->content_length
48241555Smax.romanov@nginx.com             > (uint64_t) (req->content_buf->end - req->content_buf->free))
48251555Smax.romanov@nginx.com         {
48261555Smax.romanov@nginx.com             res = nxt_unit_request_hash_add(ctx, req);
48271555Smax.romanov@nginx.com             if (nxt_slow_path(res != NXT_UNIT_OK)) {
48281555Smax.romanov@nginx.com                 nxt_unit_req_warn(req, "failed to add request to hash");
48291555Smax.romanov@nginx.com 
48301555Smax.romanov@nginx.com                 nxt_unit_request_done(req, NXT_UNIT_ERROR);
48311555Smax.romanov@nginx.com 
48321555Smax.romanov@nginx.com                 continue;
48331555Smax.romanov@nginx.com             }
48341555Smax.romanov@nginx.com 
48351555Smax.romanov@nginx.com             /*
48361555Smax.romanov@nginx.com              * If application have separate data handler, we may start
48371555Smax.romanov@nginx.com              * request processing and process data when it is arrived.
48381555Smax.romanov@nginx.com              */
48391555Smax.romanov@nginx.com             if (lib->callbacks.data_handler == NULL) {
48401555Smax.romanov@nginx.com                 continue;
48411555Smax.romanov@nginx.com             }
48421555Smax.romanov@nginx.com         }
48431555Smax.romanov@nginx.com 
48441555Smax.romanov@nginx.com         lib->callbacks.request_handler(&req_impl->req);
48451555Smax.romanov@nginx.com 
48461555Smax.romanov@nginx.com     } nxt_queue_loop;
48471555Smax.romanov@nginx.com }
48481555Smax.romanov@nginx.com 
48491547Smax.romanov@nginx.com 
48501545Smax.romanov@nginx.com int
nxt_unit_run_ctx(nxt_unit_ctx_t * ctx)48511545Smax.romanov@nginx.com nxt_unit_run_ctx(nxt_unit_ctx_t *ctx)
48521545Smax.romanov@nginx.com {
48531545Smax.romanov@nginx.com     int                  rc;
48541545Smax.romanov@nginx.com     nxt_unit_read_buf_t  *rbuf;
48551545Smax.romanov@nginx.com     nxt_unit_ctx_impl_t  *ctx_impl;
48561547Smax.romanov@nginx.com 
48571547Smax.romanov@nginx.com     nxt_unit_ctx_use(ctx);
48581547Smax.romanov@nginx.com 
48591547Smax.romanov@nginx.com     ctx_impl = nxt_container_of(ctx, nxt_unit_ctx_impl_t, ctx);
48601555Smax.romanov@nginx.com 
48611547Smax.romanov@nginx.com     rc = NXT_UNIT_OK;
48621547Smax.romanov@nginx.com 
48631547Smax.romanov@nginx.com     while (nxt_fast_path(ctx_impl->online)) {
48641547Smax.romanov@nginx.com         rbuf = nxt_unit_read_buf_get(ctx);
48651547Smax.romanov@nginx.com         if (nxt_slow_path(rbuf == NULL)) {
48661547Smax.romanov@nginx.com             rc = NXT_UNIT_ERROR;
48671547Smax.romanov@nginx.com             break;
48681547Smax.romanov@nginx.com         }
48691663Smax.romanov@nginx.com 
48701555Smax.romanov@nginx.com     retry:
48711555Smax.romanov@nginx.com 
48721555Smax.romanov@nginx.com         rc = nxt_unit_ctx_port_recv(ctx, ctx_impl->read_port, rbuf);
48731555Smax.romanov@nginx.com         if (rc == NXT_UNIT_AGAIN) {
48741555Smax.romanov@nginx.com             goto retry;
48751555Smax.romanov@nginx.com         }
48761555Smax.romanov@nginx.com 
48771555Smax.romanov@nginx.com         rc = nxt_unit_process_msg(ctx, rbuf, NULL);
48781555Smax.romanov@nginx.com         if (nxt_slow_path(rc == NXT_UNIT_ERROR)) {
48791555Smax.romanov@nginx.com             break;
48801555Smax.romanov@nginx.com         }
48811555Smax.romanov@nginx.com 
48821555Smax.romanov@nginx.com         rc = nxt_unit_process_pending_rbuf(ctx);
48831713Smax.romanov@nginx.com         if (nxt_slow_path(rc == NXT_UNIT_ERROR)) {
48841547Smax.romanov@nginx.com             break;
48851547Smax.romanov@nginx.com         }
48861547Smax.romanov@nginx.com 
48871555Smax.romanov@nginx.com         nxt_unit_process_ready_req(ctx);
48881555Smax.romanov@nginx.com     }
48891555Smax.romanov@nginx.com 
48901555Smax.romanov@nginx.com     nxt_unit_ctx_release(ctx);
48911555Smax.romanov@nginx.com 
48921555Smax.romanov@nginx.com     return rc;
48931555Smax.romanov@nginx.com }
48941547Smax.romanov@nginx.com 
48951547Smax.romanov@nginx.com 
48961547Smax.romanov@nginx.com nxt_inline int
nxt_unit_is_read_queue(nxt_unit_read_buf_t * rbuf)48971547Smax.romanov@nginx.com nxt_unit_is_read_queue(nxt_unit_read_buf_t *rbuf)
48981547Smax.romanov@nginx.com {
48991547Smax.romanov@nginx.com     nxt_port_msg_t  *port_msg;
49001547Smax.romanov@nginx.com 
49011547Smax.romanov@nginx.com     if (nxt_fast_path(rbuf->size == (ssize_t) sizeof(nxt_port_msg_t))) {
49021555Smax.romanov@nginx.com         port_msg = (nxt_port_msg_t *) rbuf->buf;
49031555Smax.romanov@nginx.com 
49041555Smax.romanov@nginx.com         return port_msg->type == _NXT_PORT_MSG_READ_QUEUE;
49051555Smax.romanov@nginx.com     }
49061555Smax.romanov@nginx.com 
49071555Smax.romanov@nginx.com     return 0;
49081555Smax.romanov@nginx.com }
49091555Smax.romanov@nginx.com 
49101555Smax.romanov@nginx.com 
49111555Smax.romanov@nginx.com nxt_inline int
nxt_unit_is_read_socket(nxt_unit_read_buf_t * rbuf)49121555Smax.romanov@nginx.com nxt_unit_is_read_socket(nxt_unit_read_buf_t *rbuf)
49131555Smax.romanov@nginx.com {
49141555Smax.romanov@nginx.com     if (nxt_fast_path(rbuf->size == 1)) {
49151555Smax.romanov@nginx.com         return rbuf->buf[0] == _NXT_PORT_MSG_READ_SOCKET;
49161555Smax.romanov@nginx.com     }
49171555Smax.romanov@nginx.com 
49181555Smax.romanov@nginx.com     return 0;
49191555Smax.romanov@nginx.com }
49201555Smax.romanov@nginx.com 
49211555Smax.romanov@nginx.com 
49221555Smax.romanov@nginx.com nxt_inline int
nxt_unit_is_shm_ack(nxt_unit_read_buf_t * rbuf)49231555Smax.romanov@nginx.com nxt_unit_is_shm_ack(nxt_unit_read_buf_t *rbuf)
49241555Smax.romanov@nginx.com {
49251555Smax.romanov@nginx.com     nxt_port_msg_t  *port_msg;
49261555Smax.romanov@nginx.com 
49271555Smax.romanov@nginx.com     if (nxt_fast_path(rbuf->size == (ssize_t) sizeof(nxt_port_msg_t))) {
49281555Smax.romanov@nginx.com         port_msg = (nxt_port_msg_t *) rbuf->buf;
49291555Smax.romanov@nginx.com 
49301555Smax.romanov@nginx.com         return port_msg->type == _NXT_PORT_MSG_SHM_ACK;
49311555Smax.romanov@nginx.com     }
49321555Smax.romanov@nginx.com 
49331555Smax.romanov@nginx.com     return 0;
49341555Smax.romanov@nginx.com }
49351555Smax.romanov@nginx.com 
49361555Smax.romanov@nginx.com 
49371555Smax.romanov@nginx.com nxt_inline int
nxt_unit_is_quit(nxt_unit_read_buf_t * rbuf)49381555Smax.romanov@nginx.com nxt_unit_is_quit(nxt_unit_read_buf_t *rbuf)
49391555Smax.romanov@nginx.com {
49401555Smax.romanov@nginx.com     nxt_port_msg_t  *port_msg;
49411555Smax.romanov@nginx.com 
49421555Smax.romanov@nginx.com     if (nxt_fast_path(rbuf->size == (ssize_t) sizeof(nxt_port_msg_t))) {
49431555Smax.romanov@nginx.com         port_msg = (nxt_port_msg_t *) rbuf->buf;
49441555Smax.romanov@nginx.com 
49451555Smax.romanov@nginx.com         return port_msg->type == _NXT_PORT_MSG_QUIT;
49461555Smax.romanov@nginx.com     }
49471555Smax.romanov@nginx.com 
49481555Smax.romanov@nginx.com     return 0;
49491555Smax.romanov@nginx.com }
49501555Smax.romanov@nginx.com 
49511555Smax.romanov@nginx.com 
49521555Smax.romanov@nginx.com int
nxt_unit_run_shared(nxt_unit_ctx_t * ctx)49531555Smax.romanov@nginx.com nxt_unit_run_shared(nxt_unit_ctx_t *ctx)
49541555Smax.romanov@nginx.com {
49551555Smax.romanov@nginx.com     int                  rc;
49561555Smax.romanov@nginx.com     nxt_unit_impl_t      *lib;
49571555Smax.romanov@nginx.com     nxt_unit_read_buf_t  *rbuf;
49581547Smax.romanov@nginx.com 
49591547Smax.romanov@nginx.com     nxt_unit_ctx_use(ctx);
49601547Smax.romanov@nginx.com 
49611555Smax.romanov@nginx.com     lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit);
49621555Smax.romanov@nginx.com 
49631555Smax.romanov@nginx.com     rc = NXT_UNIT_OK;
49641547Smax.romanov@nginx.com 
49651547Smax.romanov@nginx.com     while (nxt_fast_path(nxt_unit_chk_ready(ctx))) {
49661547Smax.romanov@nginx.com         rbuf = nxt_unit_read_buf_get(ctx);
49671547Smax.romanov@nginx.com         if (nxt_slow_path(rbuf == NULL)) {
49681663Smax.romanov@nginx.com             rc = NXT_UNIT_ERROR;
49691547Smax.romanov@nginx.com             break;
49701547Smax.romanov@nginx.com         }
49711980Smax.romanov@nginx.com 
49721555Smax.romanov@nginx.com     retry:
49731555Smax.romanov@nginx.com 
49741555Smax.romanov@nginx.com         rc = nxt_unit_shared_port_recv(ctx, lib->shared_port, rbuf);
49751555Smax.romanov@nginx.com         if (rc == NXT_UNIT_AGAIN) {
49761555Smax.romanov@nginx.com             goto retry;
49771555Smax.romanov@nginx.com         }
49781555Smax.romanov@nginx.com 
49791555Smax.romanov@nginx.com         if (nxt_slow_path(rc == NXT_UNIT_ERROR)) {
49801555Smax.romanov@nginx.com             nxt_unit_read_buf_release(ctx, rbuf);
49811555Smax.romanov@nginx.com             break;
49821555Smax.romanov@nginx.com         }
49831555Smax.romanov@nginx.com 
49841555Smax.romanov@nginx.com         rc = nxt_unit_process_msg(ctx, rbuf, NULL);
49851555Smax.romanov@nginx.com         if (nxt_slow_path(rc == NXT_UNIT_ERROR)) {
49861555Smax.romanov@nginx.com             break;
49871555Smax.romanov@nginx.com         }
49881555Smax.romanov@nginx.com     }
49891555Smax.romanov@nginx.com 
49901713Smax.romanov@nginx.com     nxt_unit_ctx_release(ctx);
49911547Smax.romanov@nginx.com 
49921547Smax.romanov@nginx.com     return rc;
49931547Smax.romanov@nginx.com }
49941547Smax.romanov@nginx.com 
49951547Smax.romanov@nginx.com 
49961547Smax.romanov@nginx.com nxt_unit_request_info_t *
nxt_unit_dequeue_request(nxt_unit_ctx_t * ctx)49971547Smax.romanov@nginx.com nxt_unit_dequeue_request(nxt_unit_ctx_t *ctx)
49981547Smax.romanov@nginx.com {
49991547Smax.romanov@nginx.com     int                      rc;
50001547Smax.romanov@nginx.com     nxt_unit_impl_t          *lib;
50011547Smax.romanov@nginx.com     nxt_unit_read_buf_t      *rbuf;
50021713Smax.romanov@nginx.com     nxt_unit_request_info_t  *req;
50031713Smax.romanov@nginx.com 
50041713Smax.romanov@nginx.com     nxt_unit_ctx_use(ctx);
50051713Smax.romanov@nginx.com 
50061713Smax.romanov@nginx.com     lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit);
50071713Smax.romanov@nginx.com 
50081713Smax.romanov@nginx.com     req = NULL;
50091713Smax.romanov@nginx.com 
50101713Smax.romanov@nginx.com     if (nxt_slow_path(!nxt_unit_chk_ready(ctx))) {
50111713Smax.romanov@nginx.com         goto done;
50121713Smax.romanov@nginx.com     }
50131713Smax.romanov@nginx.com 
50141713Smax.romanov@nginx.com     rbuf = nxt_unit_read_buf_get(ctx);
50151713Smax.romanov@nginx.com     if (nxt_slow_path(rbuf == NULL)) {
50161980Smax.romanov@nginx.com         goto done;
50171713Smax.romanov@nginx.com     }
50181713Smax.romanov@nginx.com 
50191713Smax.romanov@nginx.com     rc = nxt_unit_app_queue_recv(ctx, lib->shared_port, rbuf);
50201713Smax.romanov@nginx.com     if (rc != NXT_UNIT_OK) {
50211713Smax.romanov@nginx.com         nxt_unit_read_buf_release(ctx, rbuf);
50221713Smax.romanov@nginx.com         goto done;
50231713Smax.romanov@nginx.com     }
50241713Smax.romanov@nginx.com 
50251980Smax.romanov@nginx.com     (void) nxt_unit_process_msg(ctx, rbuf, &req);
50261713Smax.romanov@nginx.com 
50271720Smax.romanov@nginx.com done:
50281713Smax.romanov@nginx.com 
50291713Smax.romanov@nginx.com     nxt_unit_ctx_release(ctx);
50301713Smax.romanov@nginx.com 
50311713Smax.romanov@nginx.com     return req;
50321713Smax.romanov@nginx.com }
50331713Smax.romanov@nginx.com 
50341713Smax.romanov@nginx.com 
50351713Smax.romanov@nginx.com int
nxt_unit_process_port_msg(nxt_unit_ctx_t * ctx,nxt_unit_port_t * port)50361713Smax.romanov@nginx.com nxt_unit_process_port_msg(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port)
50371713Smax.romanov@nginx.com {
50381713Smax.romanov@nginx.com     int  rc;
50391713Smax.romanov@nginx.com 
50401713Smax.romanov@nginx.com     nxt_unit_ctx_use(ctx);
50411547Smax.romanov@nginx.com 
50421547Smax.romanov@nginx.com     rc = nxt_unit_process_port_msg_impl(ctx, port);
50431547Smax.romanov@nginx.com 
50441547Smax.romanov@nginx.com     nxt_unit_ctx_release(ctx);
50451547Smax.romanov@nginx.com 
50461547Smax.romanov@nginx.com     return rc;
50471547Smax.romanov@nginx.com }
50481547Smax.romanov@nginx.com 
50491547Smax.romanov@nginx.com 
50501547Smax.romanov@nginx.com static int
nxt_unit_process_port_msg_impl(nxt_unit_ctx_t * ctx,nxt_unit_port_t * port)50511547Smax.romanov@nginx.com nxt_unit_process_port_msg_impl(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port)
50521547Smax.romanov@nginx.com {
50531547Smax.romanov@nginx.com     int                  rc;
50541547Smax.romanov@nginx.com     nxt_unit_impl_t      *lib;
50551547Smax.romanov@nginx.com     nxt_unit_read_buf_t  *rbuf;
50561547Smax.romanov@nginx.com 
50571547Smax.romanov@nginx.com     lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit);
50581547Smax.romanov@nginx.com 
50591547Smax.romanov@nginx.com     if (port == lib->shared_port && !nxt_unit_chk_ready(ctx)) {
50601555Smax.romanov@nginx.com         return NXT_UNIT_AGAIN;
50611547Smax.romanov@nginx.com     }
50621547Smax.romanov@nginx.com 
50631980Smax.romanov@nginx.com     rbuf = nxt_unit_read_buf_get(ctx);
50641980Smax.romanov@nginx.com     if (nxt_slow_path(rbuf == NULL)) {
50651980Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
50661980Smax.romanov@nginx.com     }
50671980Smax.romanov@nginx.com 
50681980Smax.romanov@nginx.com     if (port == lib->shared_port) {
50691547Smax.romanov@nginx.com         rc = nxt_unit_shared_port_recv(ctx, port, rbuf);
50701547Smax.romanov@nginx.com 
50711547Smax.romanov@nginx.com     } else {
50721547Smax.romanov@nginx.com         rc = nxt_unit_ctx_port_recv(ctx, port, rbuf);
50731547Smax.romanov@nginx.com     }
50741555Smax.romanov@nginx.com 
50751555Smax.romanov@nginx.com     if (rc != NXT_UNIT_OK) {
50761555Smax.romanov@nginx.com         nxt_unit_read_buf_release(ctx, rbuf);
50771555Smax.romanov@nginx.com         return rc;
50781555Smax.romanov@nginx.com     }
50791555Smax.romanov@nginx.com 
50801555Smax.romanov@nginx.com     rc = nxt_unit_process_msg(ctx, rbuf, NULL);
50811555Smax.romanov@nginx.com     if (nxt_slow_path(rc == NXT_UNIT_ERROR)) {
50821547Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
50831547Smax.romanov@nginx.com     }
50841547Smax.romanov@nginx.com 
50851547Smax.romanov@nginx.com     rc = nxt_unit_process_pending_rbuf(ctx);
50861713Smax.romanov@nginx.com     if (nxt_slow_path(rc == NXT_UNIT_ERROR)) {
50871547Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
50881547Smax.romanov@nginx.com     }
50891547Smax.romanov@nginx.com 
50901547Smax.romanov@nginx.com     nxt_unit_process_ready_req(ctx);
50911547Smax.romanov@nginx.com 
50921547Smax.romanov@nginx.com     return rc;
50931547Smax.romanov@nginx.com }
50941547Smax.romanov@nginx.com 
50951547Smax.romanov@nginx.com 
50961547Smax.romanov@nginx.com void
nxt_unit_done(nxt_unit_ctx_t * ctx)50971547Smax.romanov@nginx.com nxt_unit_done(nxt_unit_ctx_t *ctx)
50981547Smax.romanov@nginx.com {
50991547Smax.romanov@nginx.com     nxt_unit_ctx_release(ctx);
51001547Smax.romanov@nginx.com }
51011547Smax.romanov@nginx.com 
5102743Smax.romanov@nginx.com 
5103743Smax.romanov@nginx.com nxt_unit_ctx_t *
nxt_unit_ctx_alloc(nxt_unit_ctx_t * ctx,void * data)5104743Smax.romanov@nginx.com nxt_unit_ctx_alloc(nxt_unit_ctx_t *ctx, void *data)
51051547Smax.romanov@nginx.com {
5106743Smax.romanov@nginx.com     int                   rc, queue_fd;
5107743Smax.romanov@nginx.com     void                  *mem;
5108743Smax.romanov@nginx.com     nxt_unit_impl_t       *lib;
5109743Smax.romanov@nginx.com     nxt_unit_port_t       *port;
5110743Smax.romanov@nginx.com     nxt_unit_ctx_impl_t   *new_ctx;
5111743Smax.romanov@nginx.com     nxt_unit_port_impl_t  *port_impl;
51121555Smax.romanov@nginx.com 
51131555Smax.romanov@nginx.com     lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit);
51141555Smax.romanov@nginx.com 
51151555Smax.romanov@nginx.com     new_ctx = nxt_unit_malloc(ctx, sizeof(nxt_unit_ctx_impl_t)
51161555Smax.romanov@nginx.com                                    + lib->request_data_size);
51171555Smax.romanov@nginx.com     if (nxt_slow_path(new_ctx == NULL)) {
5118743Smax.romanov@nginx.com         nxt_unit_alert(ctx, "failed to allocate context");
5119743Smax.romanov@nginx.com 
5120743Smax.romanov@nginx.com         return NULL;
51211623Smax.romanov@nginx.com     }
51221623Smax.romanov@nginx.com 
5123743Smax.romanov@nginx.com     rc = nxt_unit_ctx_init(lib, new_ctx, data);
51241544Smax.romanov@nginx.com     if (nxt_slow_path(rc != NXT_UNIT_OK)) {
5125743Smax.romanov@nginx.com         nxt_unit_free(ctx, new_ctx);
5126743Smax.romanov@nginx.com 
5127743Smax.romanov@nginx.com         return NULL;
5128743Smax.romanov@nginx.com     }
51291555Smax.romanov@nginx.com 
51301555Smax.romanov@nginx.com     queue_fd = -1;
51312078Salx.manpages@gmail.com 
51322078Salx.manpages@gmail.com     port = nxt_unit_create_port(&new_ctx->ctx);
51332078Salx.manpages@gmail.com     if (nxt_slow_path(port == NULL)) {
51341555Smax.romanov@nginx.com         goto fail;
51351555Smax.romanov@nginx.com     }
51361555Smax.romanov@nginx.com 
51371555Smax.romanov@nginx.com     new_ctx->read_port = port;
51381663Smax.romanov@nginx.com 
51391544Smax.romanov@nginx.com     queue_fd = nxt_unit_shm_open(&new_ctx->ctx, sizeof(nxt_port_queue_t));
51401544Smax.romanov@nginx.com     if (nxt_slow_path(queue_fd == -1)) {
51411544Smax.romanov@nginx.com         goto fail;
51421544Smax.romanov@nginx.com     }
51431544Smax.romanov@nginx.com 
5144743Smax.romanov@nginx.com     mem = mmap(NULL, sizeof(nxt_port_queue_t),
51451663Smax.romanov@nginx.com                PROT_READ | PROT_WRITE, MAP_SHARED, queue_fd, 0);
51461555Smax.romanov@nginx.com     if (nxt_slow_path(mem == MAP_FAILED)) {
51471555Smax.romanov@nginx.com         nxt_unit_alert(ctx, "mmap(%d) failed: %s (%d)", queue_fd,
51481555Smax.romanov@nginx.com                        strerror(errno), errno);
51491555Smax.romanov@nginx.com 
51501555Smax.romanov@nginx.com         goto fail;
51511555Smax.romanov@nginx.com     }
51521555Smax.romanov@nginx.com 
51531555Smax.romanov@nginx.com     nxt_port_queue_init(mem);
51541555Smax.romanov@nginx.com 
51551555Smax.romanov@nginx.com     port_impl = nxt_container_of(port, nxt_unit_port_impl_t, port);
51561555Smax.romanov@nginx.com     port_impl->queue = mem;
51571555Smax.romanov@nginx.com 
51581555Smax.romanov@nginx.com     rc = nxt_unit_send_port(&new_ctx->ctx, lib->router_port, port, queue_fd);
51591555Smax.romanov@nginx.com     if (nxt_slow_path(rc != NXT_UNIT_OK)) {
51601555Smax.romanov@nginx.com         goto fail;
51611555Smax.romanov@nginx.com     }
51621555Smax.romanov@nginx.com 
51631555Smax.romanov@nginx.com     nxt_unit_close(queue_fd);
51641663Smax.romanov@nginx.com 
51651555Smax.romanov@nginx.com     return &new_ctx->ctx;
51661555Smax.romanov@nginx.com 
51671555Smax.romanov@nginx.com fail:
51681555Smax.romanov@nginx.com 
51691556Smax.romanov@nginx.com     if (queue_fd != -1) {
51701555Smax.romanov@nginx.com         nxt_unit_close(queue_fd);
5171743Smax.romanov@nginx.com     }
51721544Smax.romanov@nginx.com 
51731544Smax.romanov@nginx.com     nxt_unit_ctx_release(&new_ctx->ctx);
51741544Smax.romanov@nginx.com 
51751555Smax.romanov@nginx.com     return NULL;
51761556Smax.romanov@nginx.com }
51771555Smax.romanov@nginx.com 
51781555Smax.romanov@nginx.com 
51791555Smax.romanov@nginx.com static void
nxt_unit_ctx_free(nxt_unit_ctx_impl_t * ctx_impl)51801544Smax.romanov@nginx.com nxt_unit_ctx_free(nxt_unit_ctx_impl_t *ctx_impl)
51811544Smax.romanov@nginx.com {
5182743Smax.romanov@nginx.com     nxt_unit_impl_t                  *lib;
5183743Smax.romanov@nginx.com     nxt_unit_mmap_buf_t              *mmap_buf;
5184743Smax.romanov@nginx.com     nxt_unit_read_buf_t              *rbuf;
51851543Smax.romanov@nginx.com     nxt_unit_request_info_impl_t     *req_impl;
51861543Smax.romanov@nginx.com     nxt_unit_websocket_frame_impl_t  *ws_impl;
5187743Smax.romanov@nginx.com 
51881131Smax.romanov@nginx.com     lib = nxt_container_of(ctx_impl->ctx.unit, nxt_unit_impl_t, unit);
51891131Smax.romanov@nginx.com 
51901665Smax.romanov@nginx.com     nxt_queue_each(req_impl, &ctx_impl->active_req,
51911131Smax.romanov@nginx.com                    nxt_unit_request_info_impl_t, link)
51921131Smax.romanov@nginx.com     {
5193743Smax.romanov@nginx.com         nxt_unit_req_warn(&req_impl->req, "active request on ctx free");
51941543Smax.romanov@nginx.com 
5195743Smax.romanov@nginx.com         nxt_unit_request_done(&req_impl->req, NXT_UNIT_ERROR);
5196743Smax.romanov@nginx.com 
5197743Smax.romanov@nginx.com     } nxt_queue_loop;
5198743Smax.romanov@nginx.com 
5199743Smax.romanov@nginx.com     nxt_unit_mmap_buf_unlink(&ctx_impl->ctx_buf[0]);
5200743Smax.romanov@nginx.com     nxt_unit_mmap_buf_unlink(&ctx_impl->ctx_buf[1]);
5201743Smax.romanov@nginx.com 
5202743Smax.romanov@nginx.com     while (ctx_impl->free_buf != NULL) {
5203743Smax.romanov@nginx.com         mmap_buf = ctx_impl->free_buf;
5204743Smax.romanov@nginx.com         nxt_unit_mmap_buf_unlink(mmap_buf);
52051319Smax.romanov@nginx.com         nxt_unit_free(&ctx_impl->ctx, mmap_buf);
52061319Smax.romanov@nginx.com     }
52071131Smax.romanov@nginx.com 
52081131Smax.romanov@nginx.com     nxt_queue_each(req_impl, &ctx_impl->free_req,
52091131Smax.romanov@nginx.com                    nxt_unit_request_info_impl_t, link)
52101319Smax.romanov@nginx.com     {
52111623Smax.romanov@nginx.com         nxt_unit_request_info_free(req_impl);
52121131Smax.romanov@nginx.com 
5213743Smax.romanov@nginx.com     } nxt_queue_loop;
5214743Smax.romanov@nginx.com 
5215743Smax.romanov@nginx.com     nxt_queue_each(ws_impl, &ctx_impl->free_ws,
5216743Smax.romanov@nginx.com                    nxt_unit_websocket_frame_impl_t, link)
5217743Smax.romanov@nginx.com     {
5218743Smax.romanov@nginx.com         nxt_unit_websocket_frame_free(&ctx_impl->ctx, ws_impl);
5219743Smax.romanov@nginx.com 
5220743Smax.romanov@nginx.com     } nxt_queue_loop;
52211131Smax.romanov@nginx.com 
52221131Smax.romanov@nginx.com     nxt_queue_each(rbuf, &ctx_impl->free_rbuf, nxt_unit_read_buf_t, link)
52231131Smax.romanov@nginx.com     {
52241623Smax.romanov@nginx.com         if (rbuf != &ctx_impl->ctx_read_buf) {
52251131Smax.romanov@nginx.com             nxt_unit_free(&ctx_impl->ctx, rbuf);
52261131Smax.romanov@nginx.com         }
52271131Smax.romanov@nginx.com     } nxt_queue_loop;
52281665Smax.romanov@nginx.com 
52291665Smax.romanov@nginx.com     pthread_mutex_destroy(&ctx_impl->mutex);
52301665Smax.romanov@nginx.com 
52311665Smax.romanov@nginx.com     pthread_mutex_lock(&lib->mutex);
52321665Smax.romanov@nginx.com 
52331665Smax.romanov@nginx.com     nxt_queue_remove(&ctx_impl->link);
52341665Smax.romanov@nginx.com 
52351175Smax.romanov@nginx.com     pthread_mutex_unlock(&lib->mutex);
52361175Smax.romanov@nginx.com 
52371663Smax.romanov@nginx.com     if (nxt_fast_path(ctx_impl->read_port != NULL)) {
52381663Smax.romanov@nginx.com         nxt_unit_remove_port(lib, NULL, &ctx_impl->read_port->id);
5239743Smax.romanov@nginx.com         nxt_unit_port_release(ctx_impl->read_port);
5240743Smax.romanov@nginx.com     }
52411663Smax.romanov@nginx.com 
52421663Smax.romanov@nginx.com     if (ctx_impl != &lib->main_ctx) {
52431544Smax.romanov@nginx.com         nxt_unit_free(&lib->main_ctx.ctx, ctx_impl);
52441980Smax.romanov@nginx.com     }
52451544Smax.romanov@nginx.com 
52461544Smax.romanov@nginx.com     nxt_unit_lib_release(lib);
52471544Smax.romanov@nginx.com }
5248743Smax.romanov@nginx.com 
52491623Smax.romanov@nginx.com 
5250743Smax.romanov@nginx.com /* SOCK_SEQPACKET is disabled to test SOCK_DGRAM on all platforms. */
52511543Smax.romanov@nginx.com #if (0 || NXT_HAVE_AF_UNIX_SOCK_SEQPACKET)
52521543Smax.romanov@nginx.com #define NXT_UNIX_SOCKET  SOCK_SEQPACKET
5253743Smax.romanov@nginx.com #else
5254743Smax.romanov@nginx.com #define NXT_UNIX_SOCKET  SOCK_DGRAM
5255743Smax.romanov@nginx.com #endif
5256743Smax.romanov@nginx.com 
5257743Smax.romanov@nginx.com 
5258743Smax.romanov@nginx.com void
nxt_unit_port_id_init(nxt_unit_port_id_t * port_id,pid_t pid,uint16_t id)5259743Smax.romanov@nginx.com nxt_unit_port_id_init(nxt_unit_port_id_t *port_id, pid_t pid, uint16_t id)
5260743Smax.romanov@nginx.com {
5261743Smax.romanov@nginx.com     nxt_unit_port_hash_id_t  port_hash_id;
5262743Smax.romanov@nginx.com 
5263743Smax.romanov@nginx.com     port_hash_id.pid = pid;
5264743Smax.romanov@nginx.com     port_hash_id.id = id;
5265743Smax.romanov@nginx.com 
5266743Smax.romanov@nginx.com     port_id->pid = pid;
5267743Smax.romanov@nginx.com     port_id->hash = nxt_murmur_hash2(&port_hash_id, sizeof(port_hash_id));
5268743Smax.romanov@nginx.com     port_id->id = id;
5269743Smax.romanov@nginx.com }
5270743Smax.romanov@nginx.com 
5271743Smax.romanov@nginx.com 
5272743Smax.romanov@nginx.com static nxt_unit_port_t *
nxt_unit_create_port(nxt_unit_ctx_t * ctx)5273743Smax.romanov@nginx.com nxt_unit_create_port(nxt_unit_ctx_t *ctx)
5274743Smax.romanov@nginx.com {
5275743Smax.romanov@nginx.com     int                 rc, port_sockets[2];
5276743Smax.romanov@nginx.com     nxt_unit_impl_t     *lib;
5277743Smax.romanov@nginx.com     nxt_unit_port_t     new_port, *port;
52781544Smax.romanov@nginx.com     nxt_unit_process_t  *process;
52791544Smax.romanov@nginx.com 
5280743Smax.romanov@nginx.com     lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit);
5281743Smax.romanov@nginx.com 
5282743Smax.romanov@nginx.com     rc = socketpair(AF_UNIX, NXT_UNIX_SOCKET, 0, port_sockets);
52831544Smax.romanov@nginx.com     if (nxt_slow_path(rc != 0)) {
5284743Smax.romanov@nginx.com         nxt_unit_warn(ctx, "create_port: socketpair() failed: %s (%d)",
5285743Smax.romanov@nginx.com                       strerror(errno), errno);
5286743Smax.romanov@nginx.com 
5287743Smax.romanov@nginx.com         return NULL;
5288743Smax.romanov@nginx.com     }
5289743Smax.romanov@nginx.com 
5290743Smax.romanov@nginx.com #if (NXT_HAVE_SOCKOPT_SO_PASSCRED)
5291743Smax.romanov@nginx.com     int  enable_creds = 1;
5292743Smax.romanov@nginx.com 
52931544Smax.romanov@nginx.com     if (nxt_slow_path(setsockopt(port_sockets[0], SOL_SOCKET, SO_PASSCRED,
5294743Smax.romanov@nginx.com                         &enable_creds, sizeof(enable_creds)) == -1))
5295743Smax.romanov@nginx.com     {
52961996St.nateldemoura@f5.com         nxt_unit_warn(ctx, "failed to set SO_PASSCRED %s", strerror(errno));
52971996St.nateldemoura@f5.com         return NULL;
52981996St.nateldemoura@f5.com     }
52991996St.nateldemoura@f5.com 
53001996St.nateldemoura@f5.com     if (nxt_slow_path(setsockopt(port_sockets[1], SOL_SOCKET, SO_PASSCRED,
53011996St.nateldemoura@f5.com                         &enable_creds, sizeof(enable_creds)) == -1))
53021996St.nateldemoura@f5.com     {
53031996St.nateldemoura@f5.com         nxt_unit_warn(ctx, "failed to set SO_PASSCRED %s", strerror(errno));
53041996St.nateldemoura@f5.com         return NULL;
53051996St.nateldemoura@f5.com     }
53061996St.nateldemoura@f5.com #endif
53071996St.nateldemoura@f5.com 
53081996St.nateldemoura@f5.com     nxt_unit_debug(ctx, "create_port: new socketpair: %d->%d",
53091996St.nateldemoura@f5.com                    port_sockets[0], port_sockets[1]);
53101996St.nateldemoura@f5.com 
53111996St.nateldemoura@f5.com     pthread_mutex_lock(&lib->mutex);
53121996St.nateldemoura@f5.com 
53131996St.nateldemoura@f5.com     process = nxt_unit_process_get(ctx, lib->pid);
5314743Smax.romanov@nginx.com     if (nxt_slow_path(process == NULL)) {
5315743Smax.romanov@nginx.com         pthread_mutex_unlock(&lib->mutex);
5316743Smax.romanov@nginx.com 
5317743Smax.romanov@nginx.com         nxt_unit_close(port_sockets[0]);
5318743Smax.romanov@nginx.com         nxt_unit_close(port_sockets[1]);
53191623Smax.romanov@nginx.com 
5320743Smax.romanov@nginx.com         return NULL;
5321743Smax.romanov@nginx.com     }
5322743Smax.romanov@nginx.com 
53231556Smax.romanov@nginx.com     nxt_unit_port_id_init(&new_port.id, lib->pid, process->next_port_id++);
53241556Smax.romanov@nginx.com 
5325743Smax.romanov@nginx.com     new_port.in_fd = port_sockets[0];
53261544Smax.romanov@nginx.com     new_port.out_fd = port_sockets[1];
5327743Smax.romanov@nginx.com     new_port.data = NULL;
5328743Smax.romanov@nginx.com 
5329743Smax.romanov@nginx.com     pthread_mutex_unlock(&lib->mutex);
5330743Smax.romanov@nginx.com 
5331743Smax.romanov@nginx.com     nxt_unit_process_release(process);
53321544Smax.romanov@nginx.com 
5333743Smax.romanov@nginx.com     port = nxt_unit_add_port(ctx, &new_port, NULL);
5334743Smax.romanov@nginx.com     if (nxt_slow_path(port == NULL)) {
5335743Smax.romanov@nginx.com         nxt_unit_close(port_sockets[0]);
5336743Smax.romanov@nginx.com         nxt_unit_close(port_sockets[1]);
53371543Smax.romanov@nginx.com     }
53381543Smax.romanov@nginx.com 
53391555Smax.romanov@nginx.com     return port;
53401544Smax.romanov@nginx.com }
53411556Smax.romanov@nginx.com 
53421556Smax.romanov@nginx.com 
53431544Smax.romanov@nginx.com static int
nxt_unit_send_port(nxt_unit_ctx_t * ctx,nxt_unit_port_t * dst,nxt_unit_port_t * port,int queue_fd)53441544Smax.romanov@nginx.com nxt_unit_send_port(nxt_unit_ctx_t *ctx, nxt_unit_port_t *dst,
53451544Smax.romanov@nginx.com     nxt_unit_port_t *port, int queue_fd)
5346743Smax.romanov@nginx.com {
5347743Smax.romanov@nginx.com     ssize_t          res;
5348743Smax.romanov@nginx.com     nxt_send_oob_t   oob;
5349743Smax.romanov@nginx.com     nxt_unit_impl_t  *lib;
53501544Smax.romanov@nginx.com     int              fds[2] = { port->out_fd, queue_fd };
53511555Smax.romanov@nginx.com 
5352743Smax.romanov@nginx.com     struct {
5353743Smax.romanov@nginx.com         nxt_port_msg_t            msg;
53541996St.nateldemoura@f5.com         nxt_port_msg_new_port_t   new_port;
5355743Smax.romanov@nginx.com     } m;
53561555Smax.romanov@nginx.com 
5357743Smax.romanov@nginx.com     lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit);
5358743Smax.romanov@nginx.com 
5359743Smax.romanov@nginx.com     m.msg.stream = 0;
5360743Smax.romanov@nginx.com     m.msg.pid = lib->pid;
5361743Smax.romanov@nginx.com     m.msg.reply_port = 0;
5362743Smax.romanov@nginx.com     m.msg.type = _NXT_PORT_MSG_NEW_PORT;
5363743Smax.romanov@nginx.com     m.msg.last = 0;
5364743Smax.romanov@nginx.com     m.msg.mmap = 0;
5365743Smax.romanov@nginx.com     m.msg.nf = 0;
5366743Smax.romanov@nginx.com     m.msg.mf = 0;
5367743Smax.romanov@nginx.com 
5368743Smax.romanov@nginx.com     m.new_port.id = port->id.id;
5369743Smax.romanov@nginx.com     m.new_port.pid = port->id.pid;
5370743Smax.romanov@nginx.com     m.new_port.type = NXT_PROCESS_APP;
5371743Smax.romanov@nginx.com     m.new_port.max_size = 16 * 1024;
5372743Smax.romanov@nginx.com     m.new_port.max_share = 64 * 1024;
5373743Smax.romanov@nginx.com 
53741544Smax.romanov@nginx.com     nxt_socket_msg_oob_init(&oob, fds);
53751544Smax.romanov@nginx.com 
53761488St.nateldemoura@f5.com     res = nxt_unit_port_send(ctx, dst, &m, sizeof(m), &oob);
5377743Smax.romanov@nginx.com 
5378743Smax.romanov@nginx.com     return (res == sizeof(m)) ? NXT_UNIT_OK : NXT_UNIT_ERROR;
5379743Smax.romanov@nginx.com }
53801996St.nateldemoura@f5.com 
53811996St.nateldemoura@f5.com 
nxt_unit_port_use(nxt_unit_port_t * port)53821996St.nateldemoura@f5.com nxt_inline void nxt_unit_port_use(nxt_unit_port_t *port)
53831543Smax.romanov@nginx.com {
53841543Smax.romanov@nginx.com     nxt_unit_port_impl_t  *port_impl;
5385743Smax.romanov@nginx.com 
5386743Smax.romanov@nginx.com     port_impl = nxt_container_of(port, nxt_unit_port_impl_t, port);
5387743Smax.romanov@nginx.com 
53881544Smax.romanov@nginx.com     nxt_atomic_fetch_add(&port_impl->use_count, 1);
53891544Smax.romanov@nginx.com }
53901544Smax.romanov@nginx.com 
53911544Smax.romanov@nginx.com 
nxt_unit_port_release(nxt_unit_port_t * port)53921544Smax.romanov@nginx.com nxt_inline void nxt_unit_port_release(nxt_unit_port_t *port)
53931544Smax.romanov@nginx.com {
53941544Smax.romanov@nginx.com     long                  c;
53951544Smax.romanov@nginx.com     nxt_unit_port_impl_t  *port_impl;
53961544Smax.romanov@nginx.com 
53971544Smax.romanov@nginx.com     port_impl = nxt_container_of(port, nxt_unit_port_impl_t, port);
53981544Smax.romanov@nginx.com 
53991544Smax.romanov@nginx.com     c = nxt_atomic_fetch_add(&port_impl->use_count, -1);
54001544Smax.romanov@nginx.com 
54011544Smax.romanov@nginx.com     if (c == 1) {
54021544Smax.romanov@nginx.com         nxt_unit_debug(NULL, "destroy port{%d,%d} in_fd %d out_fd %d",
54031544Smax.romanov@nginx.com                        (int) port->id.pid, (int) port->id.id,
54041544Smax.romanov@nginx.com                        port->in_fd, port->out_fd);
54051544Smax.romanov@nginx.com 
54061544Smax.romanov@nginx.com         nxt_unit_process_release(port_impl->process);
54071544Smax.romanov@nginx.com 
54081556Smax.romanov@nginx.com         if (port->in_fd != -1) {
54091556Smax.romanov@nginx.com             nxt_unit_close(port->in_fd);
54101556Smax.romanov@nginx.com 
54111544Smax.romanov@nginx.com             port->in_fd = -1;
54121544Smax.romanov@nginx.com         }
54131544Smax.romanov@nginx.com 
54141544Smax.romanov@nginx.com         if (port->out_fd != -1) {
54151556Smax.romanov@nginx.com             nxt_unit_close(port->out_fd);
54161544Smax.romanov@nginx.com 
54171544Smax.romanov@nginx.com             port->out_fd = -1;
54181544Smax.romanov@nginx.com         }
54191544Smax.romanov@nginx.com 
54201544Smax.romanov@nginx.com         if (port_impl->queue != NULL) {
54211556Smax.romanov@nginx.com             munmap(port_impl->queue, (port->id.id == NXT_UNIT_SHARED_PORT_ID)
54221555Smax.romanov@nginx.com                                      ? sizeof(nxt_app_queue_t)
54231555Smax.romanov@nginx.com                                      : sizeof(nxt_port_queue_t));
54241555Smax.romanov@nginx.com         }
54251555Smax.romanov@nginx.com 
54261555Smax.romanov@nginx.com         nxt_unit_free(NULL, port_impl);
54271663Smax.romanov@nginx.com     }
54281555Smax.romanov@nginx.com }
54291555Smax.romanov@nginx.com 
54301555Smax.romanov@nginx.com 
54311555Smax.romanov@nginx.com static nxt_unit_port_t *
nxt_unit_add_port(nxt_unit_ctx_t * ctx,nxt_unit_port_t * port,void * queue)54321623Smax.romanov@nginx.com nxt_unit_add_port(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port, void *queue)
54331544Smax.romanov@nginx.com {
54341544Smax.romanov@nginx.com     int                   rc, ready;
54351544Smax.romanov@nginx.com     nxt_queue_t           awaiting_req;
54361544Smax.romanov@nginx.com     nxt_unit_impl_t       *lib;
54371544Smax.romanov@nginx.com     nxt_unit_port_t       *old_port;
54381555Smax.romanov@nginx.com     nxt_unit_process_t    *process;
5439743Smax.romanov@nginx.com     nxt_unit_port_impl_t  *new_port, *old_port_impl;
54401711Smax.romanov@nginx.com 
54411711Smax.romanov@nginx.com     lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit);
54421711Smax.romanov@nginx.com 
54431711Smax.romanov@nginx.com     pthread_mutex_lock(&lib->mutex);
54441711Smax.romanov@nginx.com 
54451711Smax.romanov@nginx.com     old_port = nxt_unit_port_hash_find(&lib->ports, &port->id, 0);
5446743Smax.romanov@nginx.com 
5447743Smax.romanov@nginx.com     if (nxt_slow_path(old_port != NULL)) {
5448743Smax.romanov@nginx.com         nxt_unit_debug(ctx, "add_port: duplicate port{%d,%d} "
54491452Smax.romanov@nginx.com                             "in_fd %d out_fd %d queue %p",
54501452Smax.romanov@nginx.com                             port->id.pid, port->id.id,
54511452Smax.romanov@nginx.com                             port->in_fd, port->out_fd, queue);
54521452Smax.romanov@nginx.com 
54531452Smax.romanov@nginx.com         if (old_port->data == NULL) {
54541555Smax.romanov@nginx.com             old_port->data = port->data;
54551555Smax.romanov@nginx.com             port->data = NULL;
54561555Smax.romanov@nginx.com         }
54571555Smax.romanov@nginx.com 
54581452Smax.romanov@nginx.com         if (old_port->in_fd == -1) {
54591544Smax.romanov@nginx.com             old_port->in_fd = port->in_fd;
54601544Smax.romanov@nginx.com             port->in_fd = -1;
54611543Smax.romanov@nginx.com         }
54621543Smax.romanov@nginx.com 
54631543Smax.romanov@nginx.com         if (port->in_fd != -1) {
54641544Smax.romanov@nginx.com             nxt_unit_close(port->in_fd);
54651544Smax.romanov@nginx.com             port->in_fd = -1;
54661543Smax.romanov@nginx.com         }
54671543Smax.romanov@nginx.com 
54681543Smax.romanov@nginx.com         if (old_port->out_fd == -1) {
54691452Smax.romanov@nginx.com             old_port->out_fd = port->out_fd;
54701556Smax.romanov@nginx.com             port->out_fd = -1;
54711452Smax.romanov@nginx.com         }
54721452Smax.romanov@nginx.com 
54731452Smax.romanov@nginx.com         if (port->out_fd != -1) {
54741544Smax.romanov@nginx.com             nxt_unit_close(port->out_fd);
54751544Smax.romanov@nginx.com             port->out_fd = -1;
54761543Smax.romanov@nginx.com         }
54771543Smax.romanov@nginx.com 
54781543Smax.romanov@nginx.com         *port = *old_port;
54791452Smax.romanov@nginx.com 
54801556Smax.romanov@nginx.com         nxt_queue_init(&awaiting_req);
54811452Smax.romanov@nginx.com 
54821452Smax.romanov@nginx.com         old_port_impl = nxt_container_of(old_port, nxt_unit_port_impl_t, port);
54831452Smax.romanov@nginx.com 
54841544Smax.romanov@nginx.com         if (old_port_impl->queue == NULL) {
54851543Smax.romanov@nginx.com             old_port_impl->queue = queue;
54861545Smax.romanov@nginx.com         }
54871545Smax.romanov@nginx.com 
54881545Smax.romanov@nginx.com         ready = (port->in_fd != -1 || port->out_fd != -1);
54891545Smax.romanov@nginx.com 
54901555Smax.romanov@nginx.com         /*
54911555Smax.romanov@nginx.com          * Port can be market as 'ready' only after callbacks.add_port() call.
54921555Smax.romanov@nginx.com          * Otherwise, request may try to use the port before callback.
54931555Smax.romanov@nginx.com          */
54941711Smax.romanov@nginx.com         if (lib->callbacks.add_port == NULL && ready) {
54951711Smax.romanov@nginx.com             old_port_impl->ready = ready;
54961711Smax.romanov@nginx.com 
54971711Smax.romanov@nginx.com             if (!nxt_queue_is_empty(&old_port_impl->awaiting_req)) {
54981711Smax.romanov@nginx.com                 nxt_queue_add(&awaiting_req, &old_port_impl->awaiting_req);
54991711Smax.romanov@nginx.com                 nxt_queue_init(&old_port_impl->awaiting_req);
55001711Smax.romanov@nginx.com             }
55011711Smax.romanov@nginx.com         }
55021711Smax.romanov@nginx.com 
55031711Smax.romanov@nginx.com         pthread_mutex_unlock(&lib->mutex);
55041711Smax.romanov@nginx.com 
55051711Smax.romanov@nginx.com         if (lib->callbacks.add_port != NULL && ready) {
55061711Smax.romanov@nginx.com             lib->callbacks.add_port(ctx, old_port);
55071545Smax.romanov@nginx.com 
55081545Smax.romanov@nginx.com             pthread_mutex_lock(&lib->mutex);
55091452Smax.romanov@nginx.com 
55101452Smax.romanov@nginx.com             old_port_impl->ready = ready;
55111711Smax.romanov@nginx.com 
55121544Smax.romanov@nginx.com             if (!nxt_queue_is_empty(&old_port_impl->awaiting_req)) {
55131711Smax.romanov@nginx.com                 nxt_queue_add(&awaiting_req, &old_port_impl->awaiting_req);
55141711Smax.romanov@nginx.com                 nxt_queue_init(&old_port_impl->awaiting_req);
55151711Smax.romanov@nginx.com             }
55161711Smax.romanov@nginx.com 
55171711Smax.romanov@nginx.com             pthread_mutex_unlock(&lib->mutex);
55181711Smax.romanov@nginx.com         }
55191711Smax.romanov@nginx.com 
55201711Smax.romanov@nginx.com         nxt_unit_process_awaiting_req(ctx, &awaiting_req);
55211711Smax.romanov@nginx.com 
55221711Smax.romanov@nginx.com         return old_port;
55231711Smax.romanov@nginx.com     }
55241543Smax.romanov@nginx.com 
55251543Smax.romanov@nginx.com     new_port = NULL;
55261711Smax.romanov@nginx.com     ready = 0;
55271545Smax.romanov@nginx.com 
55281544Smax.romanov@nginx.com     nxt_unit_debug(ctx, "add_port: port{%d,%d} in_fd %d out_fd %d queue %p",
55291544Smax.romanov@nginx.com                    port->id.pid, port->id.id,
55301544Smax.romanov@nginx.com                    port->in_fd, port->out_fd, queue);
55311544Smax.romanov@nginx.com 
55321711Smax.romanov@nginx.com     process = nxt_unit_process_get(ctx, port->id.pid);
55331452Smax.romanov@nginx.com     if (nxt_slow_path(process == NULL)) {
55341555Smax.romanov@nginx.com         goto unlock;
5535743Smax.romanov@nginx.com     }
55361555Smax.romanov@nginx.com 
5537743Smax.romanov@nginx.com     if (port->id.id != NXT_UNIT_SHARED_PORT_ID
55381623Smax.romanov@nginx.com         && port->id.id >= process->next_port_id)
5539743Smax.romanov@nginx.com     {
5540743Smax.romanov@nginx.com         process->next_port_id = port->id.id + 1;
5541743Smax.romanov@nginx.com     }
5542743Smax.romanov@nginx.com 
55431663Smax.romanov@nginx.com     new_port = nxt_unit_malloc(ctx, sizeof(nxt_unit_port_impl_t));
55441663Smax.romanov@nginx.com     if (nxt_slow_path(new_port == NULL)) {
55451663Smax.romanov@nginx.com         nxt_unit_alert(ctx, "add_port: %d,%d malloc() failed",
5546743Smax.romanov@nginx.com                        port->id.pid, port->id.id);
5547743Smax.romanov@nginx.com 
5548743Smax.romanov@nginx.com         goto unlock;
55491623Smax.romanov@nginx.com     }
5550743Smax.romanov@nginx.com 
55511555Smax.romanov@nginx.com     new_port->port = *port;
55521555Smax.romanov@nginx.com 
55531555Smax.romanov@nginx.com     rc = nxt_unit_port_hash_add(&lib->ports, &new_port->port);
5554743Smax.romanov@nginx.com     if (nxt_slow_path(rc != NXT_UNIT_OK)) {
5555743Smax.romanov@nginx.com         nxt_unit_alert(ctx, "add_port: %d,%d hash_add failed",
5556743Smax.romanov@nginx.com                        port->id.pid, port->id.id);
5557743Smax.romanov@nginx.com 
5558743Smax.romanov@nginx.com         nxt_unit_free(ctx, new_port);
5559743Smax.romanov@nginx.com 
5560743Smax.romanov@nginx.com         new_port = NULL;
55611446Smax.romanov@nginx.com 
55621446Smax.romanov@nginx.com         goto unlock;
55631446Smax.romanov@nginx.com     }
55641623Smax.romanov@nginx.com 
55651544Smax.romanov@nginx.com     nxt_queue_insert_tail(&process->ports, &new_port->link);
55661544Smax.romanov@nginx.com 
55671544Smax.romanov@nginx.com     new_port->use_count = 2;
5568743Smax.romanov@nginx.com     new_port->process = process;
5569743Smax.romanov@nginx.com     new_port->queue = queue;
5570743Smax.romanov@nginx.com     new_port->from_socket = 0;
5571743Smax.romanov@nginx.com     new_port->socket_rbuf = NULL;
5572743Smax.romanov@nginx.com 
55731544Smax.romanov@nginx.com     nxt_queue_init(&new_port->awaiting_req);
5574743Smax.romanov@nginx.com 
55751555Smax.romanov@nginx.com     ready = (port->in_fd != -1 || port->out_fd != -1);
55761555Smax.romanov@nginx.com 
55771555Smax.romanov@nginx.com     if (lib->callbacks.add_port == NULL) {
55781545Smax.romanov@nginx.com         new_port->ready = ready;
55791545Smax.romanov@nginx.com 
5580743Smax.romanov@nginx.com     } else {
55811711Smax.romanov@nginx.com         new_port->ready = 0;
55821711Smax.romanov@nginx.com     }
55831711Smax.romanov@nginx.com 
55841711Smax.romanov@nginx.com     process = NULL;
55851711Smax.romanov@nginx.com 
55861711Smax.romanov@nginx.com unlock:
55871711Smax.romanov@nginx.com 
55881711Smax.romanov@nginx.com     pthread_mutex_unlock(&lib->mutex);
55891711Smax.romanov@nginx.com 
55901544Smax.romanov@nginx.com     if (nxt_slow_path(process != NULL)) {
55911544Smax.romanov@nginx.com         nxt_unit_process_release(process);
5592743Smax.romanov@nginx.com     }
5593743Smax.romanov@nginx.com 
5594743Smax.romanov@nginx.com     if (lib->callbacks.add_port != NULL && new_port != NULL && ready) {
5595743Smax.romanov@nginx.com         lib->callbacks.add_port(ctx, &new_port->port);
55961544Smax.romanov@nginx.com 
55971543Smax.romanov@nginx.com         nxt_queue_init(&awaiting_req);
55981543Smax.romanov@nginx.com 
55991543Smax.romanov@nginx.com         pthread_mutex_lock(&lib->mutex);
56001711Smax.romanov@nginx.com 
56011711Smax.romanov@nginx.com         new_port->ready = 1;
56021711Smax.romanov@nginx.com 
56031711Smax.romanov@nginx.com         if (!nxt_queue_is_empty(&new_port->awaiting_req)) {
56041711Smax.romanov@nginx.com             nxt_queue_add(&awaiting_req, &new_port->awaiting_req);
56051711Smax.romanov@nginx.com             nxt_queue_init(&new_port->awaiting_req);
56061711Smax.romanov@nginx.com         }
56071711Smax.romanov@nginx.com 
56081711Smax.romanov@nginx.com         pthread_mutex_unlock(&lib->mutex);
56091711Smax.romanov@nginx.com 
56101711Smax.romanov@nginx.com         nxt_unit_process_awaiting_req(ctx, &awaiting_req);
56111711Smax.romanov@nginx.com     }
56121711Smax.romanov@nginx.com 
56131711Smax.romanov@nginx.com     return (new_port == NULL) ? NULL : &new_port->port;
56141711Smax.romanov@nginx.com }
56151711Smax.romanov@nginx.com 
56161711Smax.romanov@nginx.com 
56171711Smax.romanov@nginx.com static void
nxt_unit_process_awaiting_req(nxt_unit_ctx_t * ctx,nxt_queue_t * awaiting_req)56181711Smax.romanov@nginx.com nxt_unit_process_awaiting_req(nxt_unit_ctx_t *ctx, nxt_queue_t *awaiting_req)
56191711Smax.romanov@nginx.com {
56201711Smax.romanov@nginx.com     nxt_unit_ctx_impl_t           *ctx_impl;
56211711Smax.romanov@nginx.com     nxt_unit_request_info_impl_t  *req_impl;
56221711Smax.romanov@nginx.com 
56231711Smax.romanov@nginx.com     nxt_queue_each(req_impl, awaiting_req,
56241711Smax.romanov@nginx.com                    nxt_unit_request_info_impl_t, port_wait_link)
56251711Smax.romanov@nginx.com     {
56261711Smax.romanov@nginx.com         nxt_queue_remove(&req_impl->port_wait_link);
56271711Smax.romanov@nginx.com 
56281711Smax.romanov@nginx.com         ctx_impl = nxt_container_of(req_impl->req.ctx, nxt_unit_ctx_impl_t,
56291711Smax.romanov@nginx.com                                     ctx);
56301711Smax.romanov@nginx.com 
56311543Smax.romanov@nginx.com         pthread_mutex_lock(&ctx_impl->mutex);
56321711Smax.romanov@nginx.com 
56331711Smax.romanov@nginx.com         nxt_queue_insert_tail(&ctx_impl->ready_req,
56341711Smax.romanov@nginx.com                               &req_impl->port_wait_link);
56351711Smax.romanov@nginx.com 
56361711Smax.romanov@nginx.com         pthread_mutex_unlock(&ctx_impl->mutex);
56371711Smax.romanov@nginx.com 
56381711Smax.romanov@nginx.com         nxt_atomic_fetch_add(&ctx_impl->wait_items, -1);
56391711Smax.romanov@nginx.com 
56401711Smax.romanov@nginx.com         nxt_unit_awake_ctx(ctx, ctx_impl);
56411711Smax.romanov@nginx.com 
56421711Smax.romanov@nginx.com     } nxt_queue_loop;
56431711Smax.romanov@nginx.com }
56441711Smax.romanov@nginx.com 
56451711Smax.romanov@nginx.com 
56461711Smax.romanov@nginx.com static void
nxt_unit_remove_port(nxt_unit_impl_t * lib,nxt_unit_ctx_t * ctx,nxt_unit_port_id_t * port_id)56471711Smax.romanov@nginx.com nxt_unit_remove_port(nxt_unit_impl_t *lib, nxt_unit_ctx_t *ctx,
56481711Smax.romanov@nginx.com     nxt_unit_port_id_t *port_id)
5649743Smax.romanov@nginx.com {
5650743Smax.romanov@nginx.com     nxt_unit_port_t       *port;
5651743Smax.romanov@nginx.com     nxt_unit_port_impl_t  *port_impl;
56521544Smax.romanov@nginx.com 
56531980Smax.romanov@nginx.com     pthread_mutex_lock(&lib->mutex);
56541980Smax.romanov@nginx.com 
5655743Smax.romanov@nginx.com     port = nxt_unit_remove_port_unsafe(lib, port_id);
56561544Smax.romanov@nginx.com 
56571544Smax.romanov@nginx.com     if (nxt_fast_path(port != NULL)) {
5658743Smax.romanov@nginx.com         port_impl = nxt_container_of(port, nxt_unit_port_impl_t, port);
5659743Smax.romanov@nginx.com 
5660743Smax.romanov@nginx.com         nxt_queue_remove(&port_impl->link);
56611544Smax.romanov@nginx.com     }
56621544Smax.romanov@nginx.com 
56631544Smax.romanov@nginx.com     pthread_mutex_unlock(&lib->mutex);
56641544Smax.romanov@nginx.com 
56651544Smax.romanov@nginx.com     if (lib->callbacks.remove_port != NULL && port != NULL) {
56661544Smax.romanov@nginx.com         lib->callbacks.remove_port(&lib->unit, ctx, port);
56671544Smax.romanov@nginx.com     }
5668743Smax.romanov@nginx.com 
5669743Smax.romanov@nginx.com     if (nxt_fast_path(port != NULL)) {
5670743Smax.romanov@nginx.com         nxt_unit_port_release(port);
56711544Smax.romanov@nginx.com     }
56721980Smax.romanov@nginx.com }
56731543Smax.romanov@nginx.com 
56741543Smax.romanov@nginx.com 
56751543Smax.romanov@nginx.com static nxt_unit_port_t *
nxt_unit_remove_port_unsafe(nxt_unit_impl_t * lib,nxt_unit_port_id_t * port_id)56761544Smax.romanov@nginx.com nxt_unit_remove_port_unsafe(nxt_unit_impl_t *lib, nxt_unit_port_id_t *port_id)
56771544Smax.romanov@nginx.com {
5678743Smax.romanov@nginx.com     nxt_unit_port_t  *port;
5679743Smax.romanov@nginx.com 
5680743Smax.romanov@nginx.com     port = nxt_unit_port_hash_find(&lib->ports, port_id, 1);
56811544Smax.romanov@nginx.com     if (nxt_slow_path(port == NULL)) {
56821544Smax.romanov@nginx.com         nxt_unit_debug(NULL, "remove_port: port{%d,%d} not found",
5683743Smax.romanov@nginx.com                        (int) port_id->pid, (int) port_id->id);
56841544Smax.romanov@nginx.com 
5685743Smax.romanov@nginx.com         return NULL;
5686743Smax.romanov@nginx.com     }
5687743Smax.romanov@nginx.com 
56881555Smax.romanov@nginx.com     nxt_unit_debug(NULL, "remove_port: port{%d,%d}, fds %d,%d, data %p",
5689743Smax.romanov@nginx.com                    (int) port_id->pid, (int) port_id->id,
5690743Smax.romanov@nginx.com                    port->in_fd, port->out_fd, port->data);
56911544Smax.romanov@nginx.com 
56921543Smax.romanov@nginx.com     return port;
56931543Smax.romanov@nginx.com }
56941555Smax.romanov@nginx.com 
5695743Smax.romanov@nginx.com 
56961544Smax.romanov@nginx.com static void
nxt_unit_remove_pid(nxt_unit_impl_t * lib,pid_t pid)56971544Smax.romanov@nginx.com nxt_unit_remove_pid(nxt_unit_impl_t *lib, pid_t pid)
56981544Smax.romanov@nginx.com {
5699743Smax.romanov@nginx.com     nxt_unit_process_t  *process;
5700743Smax.romanov@nginx.com 
5701743Smax.romanov@nginx.com     pthread_mutex_lock(&lib->mutex);
57021543Smax.romanov@nginx.com 
57031543Smax.romanov@nginx.com     process = nxt_unit_process_find(lib, pid, 1);
5704743Smax.romanov@nginx.com     if (nxt_slow_path(process == NULL)) {
5705743Smax.romanov@nginx.com         nxt_unit_debug(NULL, "remove_pid: process %d not found", (int) pid);
5706743Smax.romanov@nginx.com 
5707743Smax.romanov@nginx.com         pthread_mutex_unlock(&lib->mutex);
5708743Smax.romanov@nginx.com 
57091543Smax.romanov@nginx.com         return;
5710743Smax.romanov@nginx.com     }
57111543Smax.romanov@nginx.com 
5712743Smax.romanov@nginx.com     nxt_unit_remove_process(lib, process);
5713743Smax.romanov@nginx.com 
5714743Smax.romanov@nginx.com     if (lib->callbacks.remove_pid != NULL) {
5715743Smax.romanov@nginx.com         lib->callbacks.remove_pid(&lib->unit, pid);
5716743Smax.romanov@nginx.com     }
5717743Smax.romanov@nginx.com }
57181543Smax.romanov@nginx.com 
57191543Smax.romanov@nginx.com 
57201543Smax.romanov@nginx.com static void
nxt_unit_remove_process(nxt_unit_impl_t * lib,nxt_unit_process_t * process)57211543Smax.romanov@nginx.com nxt_unit_remove_process(nxt_unit_impl_t *lib, nxt_unit_process_t *process)
57221543Smax.romanov@nginx.com {
5723743Smax.romanov@nginx.com     nxt_queue_t           ports;
5724743Smax.romanov@nginx.com     nxt_unit_port_impl_t  *port;
5725743Smax.romanov@nginx.com 
5726743Smax.romanov@nginx.com     nxt_queue_init(&ports);
57271543Smax.romanov@nginx.com 
5728743Smax.romanov@nginx.com     nxt_queue_add(&ports, &process->ports);
5729743Smax.romanov@nginx.com 
5730743Smax.romanov@nginx.com     nxt_queue_each(port, &ports, nxt_unit_port_impl_t, link) {
5731743Smax.romanov@nginx.com 
5732743Smax.romanov@nginx.com         nxt_unit_remove_port_unsafe(lib, &port->port.id);
5733743Smax.romanov@nginx.com 
5734743Smax.romanov@nginx.com     } nxt_queue_loop;
5735743Smax.romanov@nginx.com 
5736743Smax.romanov@nginx.com     pthread_mutex_unlock(&lib->mutex);
5737743Smax.romanov@nginx.com 
57381544Smax.romanov@nginx.com     nxt_queue_each(port, &ports, nxt_unit_port_impl_t, link) {
5739743Smax.romanov@nginx.com 
5740743Smax.romanov@nginx.com         nxt_queue_remove(&port->link);
5741743Smax.romanov@nginx.com 
5742743Smax.romanov@nginx.com         if (lib->callbacks.remove_port != NULL) {
5743743Smax.romanov@nginx.com             lib->callbacks.remove_port(&lib->unit, NULL, &port->port);
5744743Smax.romanov@nginx.com         }
5745743Smax.romanov@nginx.com 
5746743Smax.romanov@nginx.com         nxt_unit_port_release(&port->port);
5747743Smax.romanov@nginx.com 
57481543Smax.romanov@nginx.com     } nxt_queue_loop;
57491980Smax.romanov@nginx.com 
57501543Smax.romanov@nginx.com     nxt_unit_process_release(process);
57511543Smax.romanov@nginx.com }
57521544Smax.romanov@nginx.com 
5753743Smax.romanov@nginx.com 
5754743Smax.romanov@nginx.com static void
nxt_unit_quit(nxt_unit_ctx_t * ctx,uint8_t quit_param)5755743Smax.romanov@nginx.com nxt_unit_quit(nxt_unit_ctx_t *ctx, uint8_t quit_param)
57561543Smax.romanov@nginx.com {
5757743Smax.romanov@nginx.com     nxt_bool_t                    skip_graceful_broadcast, quit;
5758743Smax.romanov@nginx.com     nxt_unit_impl_t               *lib;
5759743Smax.romanov@nginx.com     nxt_unit_ctx_impl_t           *ctx_impl;
57601543Smax.romanov@nginx.com     nxt_unit_callbacks_t          *cb;
57611980Smax.romanov@nginx.com     nxt_unit_request_info_t       *req;
57621980Smax.romanov@nginx.com     nxt_unit_request_info_impl_t  *req_impl;
57631980Smax.romanov@nginx.com 
57641715Smax.romanov@nginx.com     struct {
57651715Smax.romanov@nginx.com         nxt_port_msg_t            msg;
57661715Smax.romanov@nginx.com         uint8_t                   quit_param;
57671715Smax.romanov@nginx.com     } nxt_packed m;
57681715Smax.romanov@nginx.com 
5769743Smax.romanov@nginx.com     lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit);
57701980Smax.romanov@nginx.com     ctx_impl = nxt_container_of(ctx, nxt_unit_ctx_impl_t, ctx);
57711980Smax.romanov@nginx.com 
57721980Smax.romanov@nginx.com     nxt_unit_debug(ctx, "quit: %d/%d/%d", (int) quit_param, ctx_impl->ready,
57731980Smax.romanov@nginx.com                    ctx_impl->online);
57741980Smax.romanov@nginx.com 
5775743Smax.romanov@nginx.com     if (nxt_slow_path(!ctx_impl->online)) {
57761663Smax.romanov@nginx.com         return;
57771663Smax.romanov@nginx.com     }
57781980Smax.romanov@nginx.com 
57791980Smax.romanov@nginx.com     skip_graceful_broadcast = quit_param == NXT_QUIT_GRACEFUL
57801980Smax.romanov@nginx.com                               && !ctx_impl->ready;
57811980Smax.romanov@nginx.com 
57821663Smax.romanov@nginx.com     cb = &lib->callbacks;
57831663Smax.romanov@nginx.com 
57841663Smax.romanov@nginx.com     if (nxt_fast_path(ctx_impl->ready)) {
57851980Smax.romanov@nginx.com         ctx_impl->ready = 0;
57861980Smax.romanov@nginx.com 
57871663Smax.romanov@nginx.com         if (cb->remove_port != NULL) {
57881715Smax.romanov@nginx.com             cb->remove_port(&lib->unit, ctx, lib->shared_port);
57891715Smax.romanov@nginx.com         }
57901980Smax.romanov@nginx.com     }
57911980Smax.romanov@nginx.com 
57921980Smax.romanov@nginx.com     if (quit_param == NXT_QUIT_GRACEFUL) {
57931980Smax.romanov@nginx.com         pthread_mutex_lock(&ctx_impl->mutex);
57941980Smax.romanov@nginx.com 
57951980Smax.romanov@nginx.com         quit = nxt_queue_is_empty(&ctx_impl->active_req)
57961980Smax.romanov@nginx.com                && nxt_queue_is_empty(&ctx_impl->pending_rbuf)
57971980Smax.romanov@nginx.com                && ctx_impl->wait_items == 0;
57981980Smax.romanov@nginx.com 
57991980Smax.romanov@nginx.com         pthread_mutex_unlock(&ctx_impl->mutex);
58001980Smax.romanov@nginx.com 
58011980Smax.romanov@nginx.com     } else {
58021980Smax.romanov@nginx.com         quit = 1;
58031980Smax.romanov@nginx.com         ctx_impl->quit_param = NXT_QUIT_GRACEFUL;
58041980Smax.romanov@nginx.com     }
58051980Smax.romanov@nginx.com 
58061980Smax.romanov@nginx.com     if (quit) {
58071980Smax.romanov@nginx.com         ctx_impl->online = 0;
58081980Smax.romanov@nginx.com 
58091980Smax.romanov@nginx.com         if (cb->quit != NULL) {
58101980Smax.romanov@nginx.com             cb->quit(ctx);
58111980Smax.romanov@nginx.com         }
58121980Smax.romanov@nginx.com 
58131980Smax.romanov@nginx.com         nxt_queue_each(req_impl, &ctx_impl->active_req,
58141980Smax.romanov@nginx.com                        nxt_unit_request_info_impl_t, link)
58151980Smax.romanov@nginx.com         {
58161980Smax.romanov@nginx.com             req = &req_impl->req;
58171715Smax.romanov@nginx.com 
58181715Smax.romanov@nginx.com             nxt_unit_req_warn(req, "active request on ctx quit");
58191980Smax.romanov@nginx.com 
58201980Smax.romanov@nginx.com             if (cb->close_handler) {
58211980Smax.romanov@nginx.com                 nxt_unit_req_debug(req, "close_handler");
58221980Smax.romanov@nginx.com 
58231980Smax.romanov@nginx.com                 cb->close_handler(req);
58241980Smax.romanov@nginx.com 
58251980Smax.romanov@nginx.com             } else {
58261980Smax.romanov@nginx.com                 nxt_unit_request_done(req, NXT_UNIT_ERROR);
58271980Smax.romanov@nginx.com             }
58281980Smax.romanov@nginx.com 
58291980Smax.romanov@nginx.com         } nxt_queue_loop;
58301980Smax.romanov@nginx.com 
58311980Smax.romanov@nginx.com         if (nxt_fast_path(ctx_impl->read_port != NULL)) {
58321980Smax.romanov@nginx.com             nxt_unit_remove_port(lib, ctx, &ctx_impl->read_port->id);
58331980Smax.romanov@nginx.com         }
58341980Smax.romanov@nginx.com     }
58351980Smax.romanov@nginx.com 
58361980Smax.romanov@nginx.com     if (ctx != &lib->main_ctx.ctx || skip_graceful_broadcast) {
58371980Smax.romanov@nginx.com         return;
58381980Smax.romanov@nginx.com     }
58391980Smax.romanov@nginx.com 
58401980Smax.romanov@nginx.com     memset(&m.msg, 0, sizeof(nxt_port_msg_t));
58411980Smax.romanov@nginx.com 
58421980Smax.romanov@nginx.com     m.msg.pid = lib->pid;
58431663Smax.romanov@nginx.com     m.msg.type = _NXT_PORT_MSG_QUIT;
58441663Smax.romanov@nginx.com     m.quit_param = quit_param;
58451663Smax.romanov@nginx.com 
58461980Smax.romanov@nginx.com     pthread_mutex_lock(&lib->mutex);
58471980Smax.romanov@nginx.com 
58481980Smax.romanov@nginx.com     nxt_queue_each(ctx_impl, &lib->contexts, nxt_unit_ctx_impl_t, link) {
58491980Smax.romanov@nginx.com 
58501980Smax.romanov@nginx.com         if (ctx == &ctx_impl->ctx
58511663Smax.romanov@nginx.com             || ctx_impl->read_port == NULL
58521663Smax.romanov@nginx.com             || ctx_impl->read_port->out_fd == -1)
58531663Smax.romanov@nginx.com         {
58541663Smax.romanov@nginx.com             continue;
58551663Smax.romanov@nginx.com         }
58561663Smax.romanov@nginx.com 
58571663Smax.romanov@nginx.com         (void) nxt_unit_port_send(ctx, ctx_impl->read_port,
58581663Smax.romanov@nginx.com                                   &m, sizeof(m), NULL);
58591663Smax.romanov@nginx.com 
58601663Smax.romanov@nginx.com     } nxt_queue_loop;
58611555Smax.romanov@nginx.com 
58621663Smax.romanov@nginx.com     pthread_mutex_unlock(&lib->mutex);
58631663Smax.romanov@nginx.com }
58641996St.nateldemoura@f5.com 
58651663Smax.romanov@nginx.com 
58661663Smax.romanov@nginx.com static int
nxt_unit_get_port(nxt_unit_ctx_t * ctx,nxt_unit_port_id_t * port_id)58671663Smax.romanov@nginx.com nxt_unit_get_port(nxt_unit_ctx_t *ctx, nxt_unit_port_id_t *port_id)
58681663Smax.romanov@nginx.com {
5869743Smax.romanov@nginx.com     ssize_t              res;
5870743Smax.romanov@nginx.com     nxt_unit_impl_t      *lib;
5871743Smax.romanov@nginx.com     nxt_unit_ctx_impl_t  *ctx_impl;
58721545Smax.romanov@nginx.com 
58731545Smax.romanov@nginx.com     struct {
58741545Smax.romanov@nginx.com         nxt_port_msg_t           msg;
58751545Smax.romanov@nginx.com         nxt_port_msg_get_port_t  get_port;
58761545Smax.romanov@nginx.com     } m;
58771545Smax.romanov@nginx.com 
58781545Smax.romanov@nginx.com     lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit);
58791545Smax.romanov@nginx.com     ctx_impl = nxt_container_of(ctx, nxt_unit_ctx_impl_t, ctx);
58801545Smax.romanov@nginx.com 
58811545Smax.romanov@nginx.com     memset(&m.msg, 0, sizeof(nxt_port_msg_t));
58821545Smax.romanov@nginx.com 
58831545Smax.romanov@nginx.com     m.msg.pid = lib->pid;
58841545Smax.romanov@nginx.com     m.msg.reply_port = ctx_impl->read_port->id.id;
58851545Smax.romanov@nginx.com     m.msg.type = _NXT_PORT_MSG_GET_PORT;
58861545Smax.romanov@nginx.com 
58871545Smax.romanov@nginx.com     m.get_port.id = port_id->id;
58881545Smax.romanov@nginx.com     m.get_port.pid = port_id->pid;
58891545Smax.romanov@nginx.com 
58901545Smax.romanov@nginx.com     nxt_unit_debug(ctx, "get_port: %d %d", (int) port_id->pid,
58911545Smax.romanov@nginx.com                    (int) port_id->id);
58921545Smax.romanov@nginx.com 
58931545Smax.romanov@nginx.com     res = nxt_unit_port_send(ctx, lib->router_port, &m, sizeof(m), NULL);
58941545Smax.romanov@nginx.com     if (nxt_slow_path(res != sizeof(m))) {
58951545Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
58961545Smax.romanov@nginx.com     }
58971545Smax.romanov@nginx.com 
58981545Smax.romanov@nginx.com     return NXT_UNIT_OK;
58991996St.nateldemoura@f5.com }
59001545Smax.romanov@nginx.com 
59011545Smax.romanov@nginx.com 
59021545Smax.romanov@nginx.com static ssize_t
nxt_unit_port_send(nxt_unit_ctx_t * ctx,nxt_unit_port_t * port,const void * buf,size_t buf_size,const nxt_send_oob_t * oob)59031545Smax.romanov@nginx.com nxt_unit_port_send(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port,
59041545Smax.romanov@nginx.com     const void *buf, size_t buf_size, const nxt_send_oob_t *oob)
59051545Smax.romanov@nginx.com {
59061545Smax.romanov@nginx.com     int                   notify;
59071545Smax.romanov@nginx.com     ssize_t               ret;
5908743Smax.romanov@nginx.com     nxt_int_t             rc;
59091544Smax.romanov@nginx.com     nxt_port_msg_t        msg;
59101996St.nateldemoura@f5.com     nxt_unit_impl_t       *lib;
5911743Smax.romanov@nginx.com     nxt_unit_port_impl_t  *port_impl;
59121555Smax.romanov@nginx.com 
59131555Smax.romanov@nginx.com     lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit);
59141555Smax.romanov@nginx.com 
59151555Smax.romanov@nginx.com     port_impl = nxt_container_of(port, nxt_unit_port_impl_t, port);
59161555Smax.romanov@nginx.com     if (port_impl->queue != NULL && (oob == NULL || oob->size == 0)
59171555Smax.romanov@nginx.com         && buf_size <= NXT_PORT_QUEUE_MSG_SIZE)
5918743Smax.romanov@nginx.com     {
5919743Smax.romanov@nginx.com         rc = nxt_port_queue_send(port_impl->queue, buf, buf_size, &notify);
5920743Smax.romanov@nginx.com         if (nxt_slow_path(rc != NXT_OK)) {
59211555Smax.romanov@nginx.com             nxt_unit_alert(ctx, "port_send: port %d,%d queue overflow",
59221996St.nateldemoura@f5.com                            (int) port->id.pid, (int) port->id.id);
59231555Smax.romanov@nginx.com 
59241555Smax.romanov@nginx.com             return -1;
59251555Smax.romanov@nginx.com         }
59261555Smax.romanov@nginx.com 
59271555Smax.romanov@nginx.com         nxt_unit_debug(ctx, "port{%d,%d} enqueue %d notify %d",
59281555Smax.romanov@nginx.com                        (int) port->id.pid, (int) port->id.id,
59291555Smax.romanov@nginx.com                        (int) buf_size, notify);
59301555Smax.romanov@nginx.com 
59311555Smax.romanov@nginx.com         if (notify) {
59321555Smax.romanov@nginx.com             memcpy(&msg, buf, sizeof(nxt_port_msg_t));
59331555Smax.romanov@nginx.com 
59341555Smax.romanov@nginx.com             msg.type = _NXT_PORT_MSG_READ_QUEUE;
59351555Smax.romanov@nginx.com 
59361555Smax.romanov@nginx.com             if (lib->callbacks.port_send == NULL) {
59371555Smax.romanov@nginx.com                 ret = nxt_unit_sendmsg(ctx, port->out_fd, &msg,
59381555Smax.romanov@nginx.com                                        sizeof(nxt_port_msg_t), NULL);
59391555Smax.romanov@nginx.com 
59401555Smax.romanov@nginx.com                 nxt_unit_debug(ctx, "port{%d,%d} send %d read_queue",
59411555Smax.romanov@nginx.com                                (int) port->id.pid, (int) port->id.id,
59421555Smax.romanov@nginx.com                                (int) ret);
59431555Smax.romanov@nginx.com 
59441996St.nateldemoura@f5.com             } else {
59451555Smax.romanov@nginx.com                 ret = lib->callbacks.port_send(ctx, port, &msg,
59461555Smax.romanov@nginx.com                                                sizeof(nxt_port_msg_t), NULL, 0);
59471555Smax.romanov@nginx.com 
59481555Smax.romanov@nginx.com                 nxt_unit_debug(ctx, "port{%d,%d} sendcb %d read_queue",
59491555Smax.romanov@nginx.com                                (int) port->id.pid, (int) port->id.id,
59501555Smax.romanov@nginx.com                                (int) ret);
59511555Smax.romanov@nginx.com             }
59521555Smax.romanov@nginx.com 
59531555Smax.romanov@nginx.com         }
59541555Smax.romanov@nginx.com 
59551555Smax.romanov@nginx.com         return buf_size;
59561555Smax.romanov@nginx.com     }
59571555Smax.romanov@nginx.com 
59581555Smax.romanov@nginx.com     if (port_impl->queue != NULL) {
59591555Smax.romanov@nginx.com         msg.type = _NXT_PORT_MSG_READ_SOCKET;
59601555Smax.romanov@nginx.com 
59611555Smax.romanov@nginx.com         rc = nxt_port_queue_send(port_impl->queue, &msg.type, 1, &notify);
59621555Smax.romanov@nginx.com         if (nxt_slow_path(rc != NXT_OK)) {
59631555Smax.romanov@nginx.com             nxt_unit_alert(ctx, "port_send: port %d,%d queue overflow",
59641555Smax.romanov@nginx.com                            (int) port->id.pid, (int) port->id.id);
59651555Smax.romanov@nginx.com 
59661555Smax.romanov@nginx.com             return -1;
59671555Smax.romanov@nginx.com         }
59681555Smax.romanov@nginx.com 
59691555Smax.romanov@nginx.com         nxt_unit_debug(ctx, "port{%d,%d} enqueue 1 read_socket notify %d",
59701555Smax.romanov@nginx.com                        (int) port->id.pid, (int) port->id.id, notify);
59711555Smax.romanov@nginx.com     }
59721555Smax.romanov@nginx.com 
59731555Smax.romanov@nginx.com     if (lib->callbacks.port_send != NULL) {
59741555Smax.romanov@nginx.com         ret = lib->callbacks.port_send(ctx, port, buf, buf_size,
59751555Smax.romanov@nginx.com                                        oob != NULL ? oob->buf : NULL,
59761555Smax.romanov@nginx.com                                        oob != NULL ? oob->size : 0);
59771555Smax.romanov@nginx.com 
59781555Smax.romanov@nginx.com         nxt_unit_debug(ctx, "port{%d,%d} sendcb %d",
59791544Smax.romanov@nginx.com                        (int) port->id.pid, (int) port->id.id,
59801555Smax.romanov@nginx.com                        (int) ret);
59811996St.nateldemoura@f5.com 
59821996St.nateldemoura@f5.com     } else {
59831555Smax.romanov@nginx.com         ret = nxt_unit_sendmsg(ctx, port->out_fd, buf, buf_size, oob);
59841555Smax.romanov@nginx.com 
59851555Smax.romanov@nginx.com         nxt_unit_debug(ctx, "port{%d,%d} sendmsg %d",
59861555Smax.romanov@nginx.com                        (int) port->id.pid, (int) port->id.id,
59871555Smax.romanov@nginx.com                        (int) ret);
59881555Smax.romanov@nginx.com     }
59891996St.nateldemoura@f5.com 
59901555Smax.romanov@nginx.com     return ret;
59911555Smax.romanov@nginx.com }
59921555Smax.romanov@nginx.com 
59931555Smax.romanov@nginx.com 
59941555Smax.romanov@nginx.com static ssize_t
nxt_unit_sendmsg(nxt_unit_ctx_t * ctx,int fd,const void * buf,size_t buf_size,const nxt_send_oob_t * oob)59951555Smax.romanov@nginx.com nxt_unit_sendmsg(nxt_unit_ctx_t *ctx, int fd,
59961555Smax.romanov@nginx.com     const void *buf, size_t buf_size, const nxt_send_oob_t *oob)
5997743Smax.romanov@nginx.com {
5998743Smax.romanov@nginx.com     int            err;
5999743Smax.romanov@nginx.com     ssize_t        n;
60001543Smax.romanov@nginx.com     struct iovec   iov[1];
60011543Smax.romanov@nginx.com 
60021996St.nateldemoura@f5.com     iov[0].iov_base = (void *) buf;
6003743Smax.romanov@nginx.com     iov[0].iov_len = buf_size;
60041555Smax.romanov@nginx.com 
60051996St.nateldemoura@f5.com retry:
6006743Smax.romanov@nginx.com 
6007743Smax.romanov@nginx.com     n = nxt_sendmsg(fd, iov, 1, oob);
6008743Smax.romanov@nginx.com 
6009743Smax.romanov@nginx.com     if (nxt_slow_path(n == -1)) {
6010743Smax.romanov@nginx.com         err = errno;
60111438Smax.romanov@nginx.com 
60121438Smax.romanov@nginx.com         if (err == EINTR) {
60131996St.nateldemoura@f5.com             goto retry;
60141996St.nateldemoura@f5.com         }
60151996St.nateldemoura@f5.com 
60161555Smax.romanov@nginx.com         /*
60171555Smax.romanov@nginx.com          * FIXME: This should be "alert" after router graceful shutdown
60181555Smax.romanov@nginx.com          * implementation.
60191438Smax.romanov@nginx.com          */
60201438Smax.romanov@nginx.com         nxt_unit_warn(ctx, "sendmsg(%d, %d) failed: %s (%d)",
60211438Smax.romanov@nginx.com                       fd, (int) buf_size, strerror(err), err);
60221438Smax.romanov@nginx.com 
60231438Smax.romanov@nginx.com     } else {
60241438Smax.romanov@nginx.com         nxt_unit_debug(ctx, "sendmsg(%d, %d, %d): %d", fd, (int) buf_size,
60251438Smax.romanov@nginx.com                        (oob != NULL ? (int) oob->size : 0), (int) n);
60261438Smax.romanov@nginx.com     }
60271555Smax.romanov@nginx.com 
6028743Smax.romanov@nginx.com     return n;
6029743Smax.romanov@nginx.com }
60301996St.nateldemoura@f5.com 
60311996St.nateldemoura@f5.com 
60321996St.nateldemoura@f5.com static int
nxt_unit_ctx_port_recv(nxt_unit_ctx_t * ctx,nxt_unit_port_t * port,nxt_unit_read_buf_t * rbuf)60331996St.nateldemoura@f5.com nxt_unit_ctx_port_recv(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port,
60341996St.nateldemoura@f5.com     nxt_unit_read_buf_t *rbuf)
6035743Smax.romanov@nginx.com {
6036743Smax.romanov@nginx.com     int                   res, read;
6037743Smax.romanov@nginx.com     nxt_unit_port_impl_t  *port_impl;
60381547Smax.romanov@nginx.com 
60391555Smax.romanov@nginx.com     port_impl = nxt_container_of(port, nxt_unit_port_impl_t, port);
60401555Smax.romanov@nginx.com 
60411555Smax.romanov@nginx.com     read = 0;
60421555Smax.romanov@nginx.com 
60431555Smax.romanov@nginx.com retry:
60441555Smax.romanov@nginx.com 
60451555Smax.romanov@nginx.com     if (port_impl->from_socket > 0) {
60461555Smax.romanov@nginx.com         if (port_impl->socket_rbuf != NULL
60471555Smax.romanov@nginx.com             && port_impl->socket_rbuf->size > 0)
60481555Smax.romanov@nginx.com         {
60491555Smax.romanov@nginx.com             port_impl->from_socket--;
60501555Smax.romanov@nginx.com 
60511555Smax.romanov@nginx.com             nxt_unit_rbuf_cpy(rbuf, port_impl->socket_rbuf);
60521555Smax.romanov@nginx.com             port_impl->socket_rbuf->size = 0;
60531555Smax.romanov@nginx.com 
60541555Smax.romanov@nginx.com             nxt_unit_debug(ctx, "port{%d,%d} use suspended message %d",
60551555Smax.romanov@nginx.com                            (int) port->id.pid, (int) port->id.id,
60561555Smax.romanov@nginx.com                            (int) rbuf->size);
60571555Smax.romanov@nginx.com 
60581555Smax.romanov@nginx.com             return NXT_UNIT_OK;
60591555Smax.romanov@nginx.com         }
60601555Smax.romanov@nginx.com 
60611555Smax.romanov@nginx.com     } else {
60621555Smax.romanov@nginx.com         res = nxt_unit_port_queue_recv(port, rbuf);
60631555Smax.romanov@nginx.com 
60641555Smax.romanov@nginx.com         if (res == NXT_UNIT_OK) {
60651555Smax.romanov@nginx.com             if (nxt_unit_is_read_socket(rbuf)) {
60661555Smax.romanov@nginx.com                 port_impl->from_socket++;
60671555Smax.romanov@nginx.com 
60681555Smax.romanov@nginx.com                 nxt_unit_debug(ctx, "port{%d,%d} dequeue 1 read_socket %d",
60691555Smax.romanov@nginx.com                                (int) port->id.pid, (int) port->id.id,
60701555Smax.romanov@nginx.com                                port_impl->from_socket);
60711555Smax.romanov@nginx.com 
60721555Smax.romanov@nginx.com                 goto retry;
60731555Smax.romanov@nginx.com             }
60741555Smax.romanov@nginx.com 
60751555Smax.romanov@nginx.com             nxt_unit_debug(ctx, "port{%d,%d} dequeue %d",
60761555Smax.romanov@nginx.com                            (int) port->id.pid, (int) port->id.id,
60771555Smax.romanov@nginx.com                            (int) rbuf->size);
60781555Smax.romanov@nginx.com 
60791555Smax.romanov@nginx.com             return NXT_UNIT_OK;
60801555Smax.romanov@nginx.com         }
60811555Smax.romanov@nginx.com     }
60821555Smax.romanov@nginx.com 
60831555Smax.romanov@nginx.com     if (read) {
60841555Smax.romanov@nginx.com         return NXT_UNIT_AGAIN;
60851555Smax.romanov@nginx.com     }
60861555Smax.romanov@nginx.com 
60871555Smax.romanov@nginx.com     res = nxt_unit_port_recv(ctx, port, rbuf);
60881555Smax.romanov@nginx.com     if (nxt_slow_path(res == NXT_UNIT_ERROR)) {
60891555Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
60901555Smax.romanov@nginx.com     }
60911555Smax.romanov@nginx.com 
60921555Smax.romanov@nginx.com     read = 1;
60931555Smax.romanov@nginx.com 
60941555Smax.romanov@nginx.com     if (nxt_unit_is_read_queue(rbuf)) {
60951555Smax.romanov@nginx.com         nxt_unit_debug(ctx, "port{%d,%d} recv %d read_queue",
60961555Smax.romanov@nginx.com                        (int) port->id.pid, (int) port->id.id, (int) rbuf->size);
60971555Smax.romanov@nginx.com 
60981555Smax.romanov@nginx.com         goto retry;
60991555Smax.romanov@nginx.com     }
61001555Smax.romanov@nginx.com 
61011555Smax.romanov@nginx.com     nxt_unit_debug(ctx, "port{%d,%d} recvmsg %d",
61021555Smax.romanov@nginx.com                    (int) port->id.pid, (int) port->id.id,
61031555Smax.romanov@nginx.com                    (int) rbuf->size);
61041555Smax.romanov@nginx.com 
61051555Smax.romanov@nginx.com     if (res == NXT_UNIT_AGAIN) {
61061555Smax.romanov@nginx.com         return NXT_UNIT_AGAIN;
61071555Smax.romanov@nginx.com     }
61081555Smax.romanov@nginx.com 
61091555Smax.romanov@nginx.com     if (port_impl->from_socket > 0) {
61101555Smax.romanov@nginx.com         port_impl->from_socket--;
61111555Smax.romanov@nginx.com 
61121555Smax.romanov@nginx.com         return NXT_UNIT_OK;
61131555Smax.romanov@nginx.com     }
61141555Smax.romanov@nginx.com 
61151555Smax.romanov@nginx.com     nxt_unit_debug(ctx, "port{%d,%d} suspend message %d",
61161555Smax.romanov@nginx.com                    (int) port->id.pid, (int) port->id.id,
61171555Smax.romanov@nginx.com                    (int) rbuf->size);
61181555Smax.romanov@nginx.com 
61191555Smax.romanov@nginx.com     if (port_impl->socket_rbuf == NULL) {
61201555Smax.romanov@nginx.com         port_impl->socket_rbuf = nxt_unit_read_buf_get(ctx);
61211555Smax.romanov@nginx.com 
61221555Smax.romanov@nginx.com         if (nxt_slow_path(port_impl->socket_rbuf == NULL)) {
61231555Smax.romanov@nginx.com             return NXT_UNIT_ERROR;
61241555Smax.romanov@nginx.com         }
61251555Smax.romanov@nginx.com 
61261555Smax.romanov@nginx.com         port_impl->socket_rbuf->size = 0;
61271555Smax.romanov@nginx.com     }
61281555Smax.romanov@nginx.com 
61291555Smax.romanov@nginx.com     if (port_impl->socket_rbuf->size > 0) {
61301555Smax.romanov@nginx.com         nxt_unit_alert(ctx, "too many port socket messages");
61311555Smax.romanov@nginx.com 
61321555Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
61331555Smax.romanov@nginx.com     }
61341555Smax.romanov@nginx.com 
61351555Smax.romanov@nginx.com     nxt_unit_rbuf_cpy(port_impl->socket_rbuf, rbuf);
61361555Smax.romanov@nginx.com 
61371555Smax.romanov@nginx.com     rbuf->oob.size = 0;
61381555Smax.romanov@nginx.com 
61391555Smax.romanov@nginx.com     goto retry;
61401555Smax.romanov@nginx.com }
61411555Smax.romanov@nginx.com 
61421555Smax.romanov@nginx.com 
61431996St.nateldemoura@f5.com nxt_inline void
nxt_unit_rbuf_cpy(nxt_unit_read_buf_t * dst,nxt_unit_read_buf_t * src)61441555Smax.romanov@nginx.com nxt_unit_rbuf_cpy(nxt_unit_read_buf_t *dst, nxt_unit_read_buf_t *src)
61451555Smax.romanov@nginx.com {
61461555Smax.romanov@nginx.com     memcpy(dst->buf, src->buf, src->size);
61471555Smax.romanov@nginx.com     dst->size = src->size;
61481555Smax.romanov@nginx.com     dst->oob.size = src->oob.size;
61491555Smax.romanov@nginx.com     memcpy(dst->oob.buf, src->oob.buf, src->oob.size);
61501555Smax.romanov@nginx.com }
61511555Smax.romanov@nginx.com 
61521555Smax.romanov@nginx.com 
61531555Smax.romanov@nginx.com static int
nxt_unit_shared_port_recv(nxt_unit_ctx_t * ctx,nxt_unit_port_t * port,nxt_unit_read_buf_t * rbuf)61541996St.nateldemoura@f5.com nxt_unit_shared_port_recv(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port,
61551996St.nateldemoura@f5.com     nxt_unit_read_buf_t *rbuf)
61561555Smax.romanov@nginx.com {
61571555Smax.romanov@nginx.com     int                   res;
61581555Smax.romanov@nginx.com     nxt_unit_port_impl_t  *port_impl;
61591555Smax.romanov@nginx.com 
61601555Smax.romanov@nginx.com     port_impl = nxt_container_of(port, nxt_unit_port_impl_t, port);
61611555Smax.romanov@nginx.com 
61621555Smax.romanov@nginx.com retry:
61631755Smax.romanov@nginx.com 
61641755Smax.romanov@nginx.com     res = nxt_unit_app_queue_recv(ctx, port, rbuf);
61651755Smax.romanov@nginx.com 
61661755Smax.romanov@nginx.com     if (res == NXT_UNIT_OK) {
61671555Smax.romanov@nginx.com         return NXT_UNIT_OK;
61681555Smax.romanov@nginx.com     }
61691555Smax.romanov@nginx.com 
61701980Smax.romanov@nginx.com     if (res == NXT_UNIT_AGAIN) {
61711980Smax.romanov@nginx.com         res = nxt_unit_port_recv(ctx, port, rbuf);
61721980Smax.romanov@nginx.com         if (nxt_slow_path(res == NXT_UNIT_ERROR)) {
61731980Smax.romanov@nginx.com             return NXT_UNIT_ERROR;
61741980Smax.romanov@nginx.com         }
61751555Smax.romanov@nginx.com 
61761555Smax.romanov@nginx.com         if (nxt_unit_is_read_queue(rbuf)) {
61771555Smax.romanov@nginx.com             nxt_app_queue_notification_received(port_impl->queue);
61781555Smax.romanov@nginx.com 
61791555Smax.romanov@nginx.com             nxt_unit_debug(ctx, "port{%d,%d} recv %d read_queue",
61801555Smax.romanov@nginx.com                            (int) port->id.pid, (int) port->id.id, (int) rbuf->size);
61811555Smax.romanov@nginx.com 
61821555Smax.romanov@nginx.com             goto retry;
61831755Smax.romanov@nginx.com         }
61841755Smax.romanov@nginx.com     }
61851555Smax.romanov@nginx.com 
61861555Smax.romanov@nginx.com     return res;
61871555Smax.romanov@nginx.com }
61881555Smax.romanov@nginx.com 
61891555Smax.romanov@nginx.com 
61901555Smax.romanov@nginx.com static int
nxt_unit_port_recv(nxt_unit_ctx_t * ctx,nxt_unit_port_t * port,nxt_unit_read_buf_t * rbuf)61911555Smax.romanov@nginx.com nxt_unit_port_recv(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port,
61921555Smax.romanov@nginx.com     nxt_unit_read_buf_t *rbuf)
61931555Smax.romanov@nginx.com {
61941555Smax.romanov@nginx.com     int              fd, err;
61951555Smax.romanov@nginx.com     size_t           oob_size;
61961555Smax.romanov@nginx.com     struct iovec     iov[1];
61971544Smax.romanov@nginx.com     nxt_unit_impl_t  *lib;
61981547Smax.romanov@nginx.com 
6199743Smax.romanov@nginx.com     lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit);
62001547Smax.romanov@nginx.com 
62011996St.nateldemoura@f5.com     if (lib->callbacks.port_recv != NULL) {
62021544Smax.romanov@nginx.com         oob_size = sizeof(rbuf->oob.buf);
62031544Smax.romanov@nginx.com 
6204743Smax.romanov@nginx.com         rbuf->size = lib->callbacks.port_recv(ctx, port,
6205743Smax.romanov@nginx.com                                               rbuf->buf, sizeof(rbuf->buf),
6206743Smax.romanov@nginx.com                                               rbuf->oob.buf, &oob_size);
62071544Smax.romanov@nginx.com 
62081996St.nateldemoura@f5.com         nxt_unit_debug(ctx, "port{%d,%d} recvcb %d",
62091996St.nateldemoura@f5.com                        (int) port->id.pid, (int) port->id.id, (int) rbuf->size);
62101547Smax.romanov@nginx.com 
62111547Smax.romanov@nginx.com         if (nxt_slow_path(rbuf->size < 0)) {
62121996St.nateldemoura@f5.com             return NXT_UNIT_ERROR;
62131547Smax.romanov@nginx.com         }
62141555Smax.romanov@nginx.com 
62151555Smax.romanov@nginx.com         rbuf->oob.size = oob_size;
62161555Smax.romanov@nginx.com         return NXT_UNIT_OK;
62171547Smax.romanov@nginx.com     }
62181547Smax.romanov@nginx.com 
62191547Smax.romanov@nginx.com     iov[0].iov_base = rbuf->buf;
62201547Smax.romanov@nginx.com     iov[0].iov_len = sizeof(rbuf->buf);
62211996St.nateldemoura@f5.com 
62221547Smax.romanov@nginx.com     fd = port->in_fd;
62231547Smax.romanov@nginx.com 
62241547Smax.romanov@nginx.com retry:
62251547Smax.romanov@nginx.com 
62261547Smax.romanov@nginx.com     rbuf->size = nxt_recvmsg(fd, iov, 1, &rbuf->oob);
6227743Smax.romanov@nginx.com 
62281544Smax.romanov@nginx.com     if (nxt_slow_path(rbuf->size == -1)) {
62291544Smax.romanov@nginx.com         err = errno;
62301438Smax.romanov@nginx.com 
62311438Smax.romanov@nginx.com         if (err == EINTR) {
62321996St.nateldemoura@f5.com             goto retry;
62331547Smax.romanov@nginx.com         }
62341547Smax.romanov@nginx.com 
62351547Smax.romanov@nginx.com         if (err == EAGAIN) {
62361547Smax.romanov@nginx.com             nxt_unit_debug(ctx, "recvmsg(%d) failed: %s (%d)",
62371547Smax.romanov@nginx.com                            fd, strerror(err), err);
62381438Smax.romanov@nginx.com 
62391438Smax.romanov@nginx.com             return NXT_UNIT_AGAIN;
62401438Smax.romanov@nginx.com         }
62411547Smax.romanov@nginx.com 
62421547Smax.romanov@nginx.com         nxt_unit_alert(ctx, "recvmsg(%d) failed: %s (%d)",
62431555Smax.romanov@nginx.com                        fd, strerror(err), err);
62441547Smax.romanov@nginx.com 
62451547Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
62461547Smax.romanov@nginx.com     }
62471547Smax.romanov@nginx.com 
62481438Smax.romanov@nginx.com     nxt_unit_debug(ctx, "recvmsg(%d): %d", fd, (int) rbuf->size);
62491555Smax.romanov@nginx.com 
6250743Smax.romanov@nginx.com     return NXT_UNIT_OK;
62511547Smax.romanov@nginx.com }
62521547Smax.romanov@nginx.com 
62531547Smax.romanov@nginx.com 
62541547Smax.romanov@nginx.com static int
nxt_unit_port_queue_recv(nxt_unit_port_t * port,nxt_unit_read_buf_t * rbuf)62551547Smax.romanov@nginx.com nxt_unit_port_queue_recv(nxt_unit_port_t *port, nxt_unit_read_buf_t *rbuf)
62561547Smax.romanov@nginx.com {
6257743Smax.romanov@nginx.com     nxt_unit_port_impl_t  *port_impl;
6258743Smax.romanov@nginx.com 
6259743Smax.romanov@nginx.com     port_impl = nxt_container_of(port, nxt_unit_port_impl_t, port);
62601555Smax.romanov@nginx.com 
62611555Smax.romanov@nginx.com     rbuf->size = nxt_port_queue_recv(port_impl->queue, rbuf->buf);
62621555Smax.romanov@nginx.com 
62631555Smax.romanov@nginx.com     return (rbuf->size == -1) ? NXT_UNIT_AGAIN : NXT_UNIT_OK;
62641555Smax.romanov@nginx.com }
62651555Smax.romanov@nginx.com 
62661555Smax.romanov@nginx.com 
62671555Smax.romanov@nginx.com static int
nxt_unit_app_queue_recv(nxt_unit_ctx_t * ctx,nxt_unit_port_t * port,nxt_unit_read_buf_t * rbuf)62681555Smax.romanov@nginx.com nxt_unit_app_queue_recv(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port,
62691555Smax.romanov@nginx.com     nxt_unit_read_buf_t *rbuf)
62701555Smax.romanov@nginx.com {
62711555Smax.romanov@nginx.com     uint32_t              cookie;
62721555Smax.romanov@nginx.com     nxt_port_msg_t        *port_msg;
62731555Smax.romanov@nginx.com     nxt_app_queue_t       *queue;
62741980Smax.romanov@nginx.com     nxt_unit_impl_t       *lib;
62751980Smax.romanov@nginx.com     nxt_unit_port_impl_t  *port_impl;
62761555Smax.romanov@nginx.com 
62771555Smax.romanov@nginx.com     struct {
62781555Smax.romanov@nginx.com         nxt_port_msg_t    msg;
62791555Smax.romanov@nginx.com         uint8_t           quit_param;
62801980Smax.romanov@nginx.com     } nxt_packed m;
62811555Smax.romanov@nginx.com 
62821555Smax.romanov@nginx.com     port_impl = nxt_container_of(port, nxt_unit_port_impl_t, port);
62831980Smax.romanov@nginx.com     queue = port_impl->queue;
62841980Smax.romanov@nginx.com 
62851980Smax.romanov@nginx.com retry:
62861980Smax.romanov@nginx.com 
62871980Smax.romanov@nginx.com     rbuf->size = nxt_app_queue_recv(queue, rbuf->buf, &cookie);
62881555Smax.romanov@nginx.com 
62891555Smax.romanov@nginx.com     nxt_unit_debug(NULL, "app_queue_recv: %d", (int) rbuf->size);
62901555Smax.romanov@nginx.com 
62911555Smax.romanov@nginx.com     if (rbuf->size >= (ssize_t) sizeof(nxt_port_msg_t)) {
62921555Smax.romanov@nginx.com         port_msg = (nxt_port_msg_t *) rbuf->buf;
62931555Smax.romanov@nginx.com 
62941555Smax.romanov@nginx.com         if (nxt_app_queue_cancel(queue, cookie, port_msg->stream)) {
62951555Smax.romanov@nginx.com             lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit);
62961555Smax.romanov@nginx.com 
62971555Smax.romanov@nginx.com             if (lib->request_limit != 0) {
62981555Smax.romanov@nginx.com                 nxt_atomic_fetch_add(&lib->request_count, 1);
62991555Smax.romanov@nginx.com 
63001555Smax.romanov@nginx.com                 if (nxt_slow_path(lib->request_count >= lib->request_limit)) {
63011980Smax.romanov@nginx.com                     nxt_unit_debug(ctx, "request limit reached");
63021980Smax.romanov@nginx.com 
63031980Smax.romanov@nginx.com                     memset(&m.msg, 0, sizeof(nxt_port_msg_t));
63041980Smax.romanov@nginx.com 
63051980Smax.romanov@nginx.com                     m.msg.pid = lib->pid;
63061980Smax.romanov@nginx.com                     m.msg.type = _NXT_PORT_MSG_QUIT;
63071980Smax.romanov@nginx.com                     m.quit_param = NXT_QUIT_GRACEFUL;
63081980Smax.romanov@nginx.com 
63091980Smax.romanov@nginx.com                     (void) nxt_unit_port_send(ctx, lib->main_ctx.read_port,
63101980Smax.romanov@nginx.com                                               &m, sizeof(m), NULL);
63111980Smax.romanov@nginx.com                 }
63121980Smax.romanov@nginx.com             }
63131980Smax.romanov@nginx.com 
63141980Smax.romanov@nginx.com             return NXT_UNIT_OK;
63151980Smax.romanov@nginx.com         }
63161996St.nateldemoura@f5.com 
63171980Smax.romanov@nginx.com         nxt_unit_debug(NULL, "app_queue_recv: message cancelled");
63181980Smax.romanov@nginx.com 
63191980Smax.romanov@nginx.com         goto retry;
63201555Smax.romanov@nginx.com     }
63211555Smax.romanov@nginx.com 
63221555Smax.romanov@nginx.com     return (rbuf->size == -1) ? NXT_UNIT_AGAIN : NXT_UNIT_OK;
63231555Smax.romanov@nginx.com }
63241555Smax.romanov@nginx.com 
63251555Smax.romanov@nginx.com 
63261555Smax.romanov@nginx.com nxt_inline int
nxt_unit_close(int fd)63271555Smax.romanov@nginx.com nxt_unit_close(int fd)
63281555Smax.romanov@nginx.com {
63291555Smax.romanov@nginx.com     int  res;
63301555Smax.romanov@nginx.com 
63311555Smax.romanov@nginx.com     res = close(fd);
63321556Smax.romanov@nginx.com 
63331556Smax.romanov@nginx.com     if (nxt_slow_path(res == -1)) {
63341556Smax.romanov@nginx.com         nxt_unit_alert(NULL, "close(%d) failed: %s (%d)",
63351556Smax.romanov@nginx.com                        fd, strerror(errno), errno);
63361556Smax.romanov@nginx.com 
63371556Smax.romanov@nginx.com     } else {
63381556Smax.romanov@nginx.com         nxt_unit_debug(NULL, "close(%d): %d", fd, res);
63391556Smax.romanov@nginx.com     }
63401556Smax.romanov@nginx.com 
63411556Smax.romanov@nginx.com     return res;
63421556Smax.romanov@nginx.com }
63431556Smax.romanov@nginx.com 
63441556Smax.romanov@nginx.com 
63451556Smax.romanov@nginx.com static int
nxt_unit_fd_blocking(int fd)63461556Smax.romanov@nginx.com nxt_unit_fd_blocking(int fd)
63471556Smax.romanov@nginx.com {
63481556Smax.romanov@nginx.com     int  nb;
63491556Smax.romanov@nginx.com 
63501556Smax.romanov@nginx.com     nb = 0;
63511557Smax.romanov@nginx.com 
63521557Smax.romanov@nginx.com     if (nxt_slow_path(ioctl(fd, FIONBIO, &nb) == -1)) {
63531557Smax.romanov@nginx.com         nxt_unit_alert(NULL, "ioctl(%d, FIONBIO, 0) failed: %s (%d)",
63541557Smax.romanov@nginx.com                        fd, strerror(errno), errno);
63551557Smax.romanov@nginx.com 
63561557Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
63571557Smax.romanov@nginx.com     }
63581557Smax.romanov@nginx.com 
63591557Smax.romanov@nginx.com     return NXT_UNIT_OK;
63601557Smax.romanov@nginx.com }
63611557Smax.romanov@nginx.com 
63621557Smax.romanov@nginx.com 
63631557Smax.romanov@nginx.com static nxt_int_t
nxt_unit_port_hash_test(nxt_lvlhsh_query_t * lhq,void * data)63641557Smax.romanov@nginx.com nxt_unit_port_hash_test(nxt_lvlhsh_query_t *lhq, void *data)
63651557Smax.romanov@nginx.com {
63661557Smax.romanov@nginx.com     nxt_unit_port_t          *port;
63671557Smax.romanov@nginx.com     nxt_unit_port_hash_id_t  *port_id;
63681557Smax.romanov@nginx.com 
6369743Smax.romanov@nginx.com     port = data;
6370743Smax.romanov@nginx.com     port_id = (nxt_unit_port_hash_id_t *) lhq->key.start;
6371743Smax.romanov@nginx.com 
6372743Smax.romanov@nginx.com     if (lhq->key.length == sizeof(nxt_unit_port_hash_id_t)
6373743Smax.romanov@nginx.com         && port_id->pid == port->id.pid
6374743Smax.romanov@nginx.com         && port_id->id == port->id.id)
6375743Smax.romanov@nginx.com     {
6376743Smax.romanov@nginx.com         return NXT_OK;
6377743Smax.romanov@nginx.com     }
6378743Smax.romanov@nginx.com 
6379743Smax.romanov@nginx.com     return NXT_DECLINED;
6380743Smax.romanov@nginx.com }
6381743Smax.romanov@nginx.com 
6382743Smax.romanov@nginx.com 
6383743Smax.romanov@nginx.com static const nxt_lvlhsh_proto_t  lvlhsh_ports_proto  nxt_aligned(64) = {
6384743Smax.romanov@nginx.com     NXT_LVLHSH_DEFAULT,
6385743Smax.romanov@nginx.com     nxt_unit_port_hash_test,
6386743Smax.romanov@nginx.com     nxt_unit_lvlhsh_alloc,
6387743Smax.romanov@nginx.com     nxt_unit_lvlhsh_free,
6388743Smax.romanov@nginx.com };
6389743Smax.romanov@nginx.com 
6390743Smax.romanov@nginx.com 
6391743Smax.romanov@nginx.com static inline void
nxt_unit_port_hash_lhq(nxt_lvlhsh_query_t * lhq,nxt_unit_port_hash_id_t * port_hash_id,nxt_unit_port_id_t * port_id)63921616Smax.romanov@nginx.com nxt_unit_port_hash_lhq(nxt_lvlhsh_query_t *lhq,
63931616Smax.romanov@nginx.com     nxt_unit_port_hash_id_t *port_hash_id,
6394743Smax.romanov@nginx.com     nxt_unit_port_id_t *port_id)
6395743Smax.romanov@nginx.com {
6396743Smax.romanov@nginx.com     port_hash_id->pid = port_id->pid;
6397743Smax.romanov@nginx.com     port_hash_id->id = port_id->id;
6398743Smax.romanov@nginx.com 
6399743Smax.romanov@nginx.com     if (nxt_fast_path(port_id->hash != 0)) {
6400743Smax.romanov@nginx.com         lhq->key_hash = port_id->hash;
6401743Smax.romanov@nginx.com 
6402743Smax.romanov@nginx.com     } else {
6403743Smax.romanov@nginx.com         lhq->key_hash = nxt_murmur_hash2(port_hash_id, sizeof(*port_hash_id));
6404743Smax.romanov@nginx.com 
6405743Smax.romanov@nginx.com         port_id->hash = lhq->key_hash;
6406743Smax.romanov@nginx.com 
6407743Smax.romanov@nginx.com         nxt_unit_debug(NULL, "calculate hash for port_id (%d, %d): %04X",
6408743Smax.romanov@nginx.com                        (int) port_id->pid, (int) port_id->id,
6409743Smax.romanov@nginx.com                        (int) port_id->hash);
6410743Smax.romanov@nginx.com     }
6411743Smax.romanov@nginx.com 
6412743Smax.romanov@nginx.com     lhq->key.length = sizeof(nxt_unit_port_hash_id_t);
6413743Smax.romanov@nginx.com     lhq->key.start = (u_char *) port_hash_id;
6414743Smax.romanov@nginx.com     lhq->proto = &lvlhsh_ports_proto;
6415743Smax.romanov@nginx.com     lhq->pool = NULL;
6416743Smax.romanov@nginx.com }
6417743Smax.romanov@nginx.com 
6418743Smax.romanov@nginx.com 
6419743Smax.romanov@nginx.com static int
nxt_unit_port_hash_add(nxt_lvlhsh_t * port_hash,nxt_unit_port_t * port)6420743Smax.romanov@nginx.com nxt_unit_port_hash_add(nxt_lvlhsh_t *port_hash, nxt_unit_port_t *port)
6421743Smax.romanov@nginx.com {
6422743Smax.romanov@nginx.com     nxt_int_t                res;
6423743Smax.romanov@nginx.com     nxt_lvlhsh_query_t       lhq;
6424743Smax.romanov@nginx.com     nxt_unit_port_hash_id_t  port_hash_id;
6425743Smax.romanov@nginx.com 
6426743Smax.romanov@nginx.com     nxt_unit_port_hash_lhq(&lhq, &port_hash_id, &port->id);
6427743Smax.romanov@nginx.com     lhq.replace = 0;
6428743Smax.romanov@nginx.com     lhq.value = port;
6429743Smax.romanov@nginx.com 
6430743Smax.romanov@nginx.com     res = nxt_lvlhsh_insert(port_hash, &lhq);
6431743Smax.romanov@nginx.com 
6432743Smax.romanov@nginx.com     switch (res) {
6433743Smax.romanov@nginx.com 
6434743Smax.romanov@nginx.com     case NXT_OK:
6435743Smax.romanov@nginx.com         return NXT_UNIT_OK;
6436743Smax.romanov@nginx.com 
6437743Smax.romanov@nginx.com     default:
6438743Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
6439743Smax.romanov@nginx.com     }
6440743Smax.romanov@nginx.com }
6441743Smax.romanov@nginx.com 
6442743Smax.romanov@nginx.com 
6443743Smax.romanov@nginx.com static nxt_unit_port_t *
nxt_unit_port_hash_find(nxt_lvlhsh_t * port_hash,nxt_unit_port_id_t * port_id,int remove)6444743Smax.romanov@nginx.com nxt_unit_port_hash_find(nxt_lvlhsh_t *port_hash, nxt_unit_port_id_t *port_id,
6445743Smax.romanov@nginx.com     int remove)
6446743Smax.romanov@nginx.com {
6447743Smax.romanov@nginx.com     nxt_int_t                res;
6448743Smax.romanov@nginx.com     nxt_lvlhsh_query_t       lhq;
64491544Smax.romanov@nginx.com     nxt_unit_port_hash_id_t  port_hash_id;
6450743Smax.romanov@nginx.com 
6451743Smax.romanov@nginx.com     nxt_unit_port_hash_lhq(&lhq, &port_hash_id, port_id);
6452743Smax.romanov@nginx.com 
6453743Smax.romanov@nginx.com     if (remove) {
6454743Smax.romanov@nginx.com         res = nxt_lvlhsh_delete(port_hash, &lhq);
6455743Smax.romanov@nginx.com 
6456743Smax.romanov@nginx.com     } else {
6457743Smax.romanov@nginx.com         res = nxt_lvlhsh_find(port_hash, &lhq);
6458743Smax.romanov@nginx.com     }
6459743Smax.romanov@nginx.com 
6460743Smax.romanov@nginx.com     switch (res) {
6461743Smax.romanov@nginx.com 
6462743Smax.romanov@nginx.com     case NXT_OK:
6463743Smax.romanov@nginx.com         if (!remove) {
6464743Smax.romanov@nginx.com             nxt_unit_port_use(lhq.value);
6465743Smax.romanov@nginx.com         }
6466743Smax.romanov@nginx.com 
6467743Smax.romanov@nginx.com         return lhq.value;
6468743Smax.romanov@nginx.com 
64691544Smax.romanov@nginx.com     default:
64701544Smax.romanov@nginx.com         return NULL;
64711544Smax.romanov@nginx.com     }
64721544Smax.romanov@nginx.com }
6473743Smax.romanov@nginx.com 
6474743Smax.romanov@nginx.com 
6475743Smax.romanov@nginx.com static nxt_int_t
nxt_unit_request_hash_test(nxt_lvlhsh_query_t * lhq,void * data)6476743Smax.romanov@nginx.com nxt_unit_request_hash_test(nxt_lvlhsh_query_t *lhq, void *data)
6477743Smax.romanov@nginx.com {
6478743Smax.romanov@nginx.com     return NXT_OK;
6479743Smax.romanov@nginx.com }
6480743Smax.romanov@nginx.com 
64811131Smax.romanov@nginx.com 
64821131Smax.romanov@nginx.com static const nxt_lvlhsh_proto_t  lvlhsh_requests_proto  nxt_aligned(64) = {
64831131Smax.romanov@nginx.com     NXT_LVLHSH_DEFAULT,
64841131Smax.romanov@nginx.com     nxt_unit_request_hash_test,
64851131Smax.romanov@nginx.com     nxt_unit_lvlhsh_alloc,
64861131Smax.romanov@nginx.com     nxt_unit_lvlhsh_free,
64871131Smax.romanov@nginx.com };
64881131Smax.romanov@nginx.com 
64891131Smax.romanov@nginx.com 
64901131Smax.romanov@nginx.com static int
nxt_unit_request_hash_add(nxt_unit_ctx_t * ctx,nxt_unit_request_info_t * req)64911616Smax.romanov@nginx.com nxt_unit_request_hash_add(nxt_unit_ctx_t *ctx,
64921616Smax.romanov@nginx.com     nxt_unit_request_info_t *req)
64931131Smax.romanov@nginx.com {
64941131Smax.romanov@nginx.com     uint32_t                      *stream;
64951131Smax.romanov@nginx.com     nxt_int_t                     res;
64961131Smax.romanov@nginx.com     nxt_lvlhsh_query_t            lhq;
64971555Smax.romanov@nginx.com     nxt_unit_ctx_impl_t           *ctx_impl;
64981555Smax.romanov@nginx.com     nxt_unit_request_info_impl_t  *req_impl;
64991131Smax.romanov@nginx.com 
65001555Smax.romanov@nginx.com     req_impl = nxt_container_of(req, nxt_unit_request_info_impl_t, req);
65011555Smax.romanov@nginx.com     if (req_impl->in_hash) {
65021555Smax.romanov@nginx.com         return NXT_UNIT_OK;
65031555Smax.romanov@nginx.com     }
65041555Smax.romanov@nginx.com 
65051555Smax.romanov@nginx.com     stream = &req_impl->stream;
65061555Smax.romanov@nginx.com 
65071555Smax.romanov@nginx.com     lhq.key_hash = nxt_murmur_hash2(stream, sizeof(*stream));
65081555Smax.romanov@nginx.com     lhq.key.length = sizeof(*stream);
65091555Smax.romanov@nginx.com     lhq.key.start = (u_char *) stream;
65101131Smax.romanov@nginx.com     lhq.proto = &lvlhsh_requests_proto;
65111131Smax.romanov@nginx.com     lhq.pool = NULL;
65121131Smax.romanov@nginx.com     lhq.replace = 0;
65131131Smax.romanov@nginx.com     lhq.value = req_impl;
65141131Smax.romanov@nginx.com 
65151131Smax.romanov@nginx.com     ctx_impl = nxt_container_of(ctx, nxt_unit_ctx_impl_t, ctx);
65161131Smax.romanov@nginx.com 
65171131Smax.romanov@nginx.com     pthread_mutex_lock(&ctx_impl->mutex);
65181131Smax.romanov@nginx.com 
65191131Smax.romanov@nginx.com     res = nxt_lvlhsh_insert(&ctx_impl->requests, &lhq);
65201131Smax.romanov@nginx.com 
65211555Smax.romanov@nginx.com     pthread_mutex_unlock(&ctx_impl->mutex);
65221555Smax.romanov@nginx.com 
65231555Smax.romanov@nginx.com     switch (res) {
65241555Smax.romanov@nginx.com 
65251555Smax.romanov@nginx.com     case NXT_OK:
65261555Smax.romanov@nginx.com         req_impl->in_hash = 1;
65271555Smax.romanov@nginx.com         return NXT_UNIT_OK;
65281131Smax.romanov@nginx.com 
65291131Smax.romanov@nginx.com     default:
65301131Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
65311131Smax.romanov@nginx.com     }
65321555Smax.romanov@nginx.com }
65331131Smax.romanov@nginx.com 
65341131Smax.romanov@nginx.com 
65351131Smax.romanov@nginx.com static nxt_unit_request_info_t *
nxt_unit_request_hash_find(nxt_unit_ctx_t * ctx,uint32_t stream,int remove)65361131Smax.romanov@nginx.com nxt_unit_request_hash_find(nxt_unit_ctx_t *ctx, uint32_t stream, int remove)
65371131Smax.romanov@nginx.com {
65381131Smax.romanov@nginx.com     nxt_int_t                     res;
65391131Smax.romanov@nginx.com     nxt_lvlhsh_query_t            lhq;
65401131Smax.romanov@nginx.com     nxt_unit_ctx_impl_t           *ctx_impl;
65411555Smax.romanov@nginx.com     nxt_unit_request_info_impl_t  *req_impl;
65421555Smax.romanov@nginx.com 
65431131Smax.romanov@nginx.com     lhq.key_hash = nxt_murmur_hash2(&stream, sizeof(stream));
65441555Smax.romanov@nginx.com     lhq.key.length = sizeof(stream);
65451555Smax.romanov@nginx.com     lhq.key.start = (u_char *) &stream;
65461555Smax.romanov@nginx.com     lhq.proto = &lvlhsh_requests_proto;
65471555Smax.romanov@nginx.com     lhq.pool = NULL;
65481131Smax.romanov@nginx.com 
65491131Smax.romanov@nginx.com     ctx_impl = nxt_container_of(ctx, nxt_unit_ctx_impl_t, ctx);
65501131Smax.romanov@nginx.com 
65511131Smax.romanov@nginx.com     pthread_mutex_lock(&ctx_impl->mutex);
65521131Smax.romanov@nginx.com 
65531131Smax.romanov@nginx.com     if (remove) {
65541131Smax.romanov@nginx.com         res = nxt_lvlhsh_delete(&ctx_impl->requests, &lhq);
65551555Smax.romanov@nginx.com 
65561555Smax.romanov@nginx.com     } else {
65571555Smax.romanov@nginx.com         res = nxt_lvlhsh_find(&ctx_impl->requests, &lhq);
65581555Smax.romanov@nginx.com     }
65591131Smax.romanov@nginx.com 
65601555Smax.romanov@nginx.com     pthread_mutex_unlock(&ctx_impl->mutex);
65611131Smax.romanov@nginx.com 
65621131Smax.romanov@nginx.com     switch (res) {
65631555Smax.romanov@nginx.com 
65641555Smax.romanov@nginx.com     case NXT_OK:
65651555Smax.romanov@nginx.com         req_impl = nxt_container_of(lhq.value, nxt_unit_request_info_impl_t,
65661555Smax.romanov@nginx.com                                     req);
65671131Smax.romanov@nginx.com         if (remove) {
65681131Smax.romanov@nginx.com             req_impl->in_hash = 0;
65691131Smax.romanov@nginx.com         }
65701131Smax.romanov@nginx.com 
65711555Smax.romanov@nginx.com         return lhq.value;
65721555Smax.romanov@nginx.com 
65731618Smax.romanov@nginx.com     default:
65741618Smax.romanov@nginx.com         return NULL;
65751618Smax.romanov@nginx.com     }
65761555Smax.romanov@nginx.com }
65771131Smax.romanov@nginx.com 
65781131Smax.romanov@nginx.com 
65791131Smax.romanov@nginx.com void
nxt_unit_log(nxt_unit_ctx_t * ctx,int level,const char * fmt,...)65801131Smax.romanov@nginx.com nxt_unit_log(nxt_unit_ctx_t *ctx, int level, const char *fmt, ...)
65811131Smax.romanov@nginx.com {
65821131Smax.romanov@nginx.com     int              log_fd, n;
65831131Smax.romanov@nginx.com     char             msg[NXT_MAX_ERROR_STR], *p, *end;
65841131Smax.romanov@nginx.com     pid_t            pid;
6585743Smax.romanov@nginx.com     va_list          ap;
6586743Smax.romanov@nginx.com     nxt_unit_impl_t  *lib;
6587743Smax.romanov@nginx.com 
6588743Smax.romanov@nginx.com     if (nxt_fast_path(ctx != NULL)) {
6589743Smax.romanov@nginx.com         lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit);
6590743Smax.romanov@nginx.com 
6591743Smax.romanov@nginx.com         pid = lib->pid;
6592743Smax.romanov@nginx.com         log_fd = lib->log_fd;
6593743Smax.romanov@nginx.com 
6594743Smax.romanov@nginx.com     } else {
6595743Smax.romanov@nginx.com         pid = nxt_unit_pid;
6596743Smax.romanov@nginx.com         log_fd = STDERR_FILENO;
6597743Smax.romanov@nginx.com     }
6598743Smax.romanov@nginx.com 
6599743Smax.romanov@nginx.com     p = msg;
6600743Smax.romanov@nginx.com     end = p + sizeof(msg) - 1;
66011998St.nateldemoura@f5.com 
6602743Smax.romanov@nginx.com     p = nxt_unit_snprint_prefix(p, end, pid, level);
6603743Smax.romanov@nginx.com 
6604743Smax.romanov@nginx.com     va_start(ap, fmt);
6605743Smax.romanov@nginx.com     p += vsnprintf(p, end - p, fmt, ap);
6606743Smax.romanov@nginx.com     va_end(ap);
6607743Smax.romanov@nginx.com 
6608743Smax.romanov@nginx.com     if (nxt_slow_path(p > end)) {
6609743Smax.romanov@nginx.com         memcpy(end - 5, "[...]", 5);
6610743Smax.romanov@nginx.com         p = end;
6611743Smax.romanov@nginx.com     }
6612743Smax.romanov@nginx.com 
6613743Smax.romanov@nginx.com     *p++ = '\n';
6614743Smax.romanov@nginx.com 
6615743Smax.romanov@nginx.com     n = write(log_fd, msg, p - msg);
6616743Smax.romanov@nginx.com     if (nxt_slow_path(n < 0)) {
6617743Smax.romanov@nginx.com         fprintf(stderr, "Failed to write log: %.*s", (int) (p - msg), msg);
6618743Smax.romanov@nginx.com     }
6619743Smax.romanov@nginx.com }
6620743Smax.romanov@nginx.com 
6621743Smax.romanov@nginx.com 
6622743Smax.romanov@nginx.com void
nxt_unit_req_log(nxt_unit_request_info_t * req,int level,const char * fmt,...)6623743Smax.romanov@nginx.com nxt_unit_req_log(nxt_unit_request_info_t *req, int level, const char *fmt, ...)
6624743Smax.romanov@nginx.com {
6625743Smax.romanov@nginx.com     int                           log_fd, n;
6626743Smax.romanov@nginx.com     char                          msg[NXT_MAX_ERROR_STR], *p, *end;
6627743Smax.romanov@nginx.com     pid_t                         pid;
6628743Smax.romanov@nginx.com     va_list                       ap;
6629743Smax.romanov@nginx.com     nxt_unit_impl_t               *lib;
6630743Smax.romanov@nginx.com     nxt_unit_request_info_impl_t  *req_impl;
6631743Smax.romanov@nginx.com 
6632743Smax.romanov@nginx.com     if (nxt_fast_path(req != NULL)) {
6633743Smax.romanov@nginx.com         lib = nxt_container_of(req->ctx->unit, nxt_unit_impl_t, unit);
6634743Smax.romanov@nginx.com 
6635743Smax.romanov@nginx.com         pid = lib->pid;
6636743Smax.romanov@nginx.com         log_fd = lib->log_fd;
6637743Smax.romanov@nginx.com 
6638743Smax.romanov@nginx.com     } else {
6639743Smax.romanov@nginx.com         pid = nxt_unit_pid;
6640743Smax.romanov@nginx.com         log_fd = STDERR_FILENO;
6641743Smax.romanov@nginx.com     }
6642743Smax.romanov@nginx.com 
6643743Smax.romanov@nginx.com     p = msg;
6644743Smax.romanov@nginx.com     end = p + sizeof(msg) - 1;
66451998St.nateldemoura@f5.com 
6646743Smax.romanov@nginx.com     p = nxt_unit_snprint_prefix(p, end, pid, level);
6647743Smax.romanov@nginx.com 
6648743Smax.romanov@nginx.com     if (nxt_fast_path(req != NULL)) {
6649743Smax.romanov@nginx.com         req_impl = nxt_container_of(req, nxt_unit_request_info_impl_t, req);
6650743Smax.romanov@nginx.com 
6651743Smax.romanov@nginx.com         p += snprintf(p, end - p, "#%"PRIu32": ", req_impl->stream);
6652743Smax.romanov@nginx.com     }
6653743Smax.romanov@nginx.com 
6654743Smax.romanov@nginx.com     va_start(ap, fmt);
6655743Smax.romanov@nginx.com     p += vsnprintf(p, end - p, fmt, ap);
6656743Smax.romanov@nginx.com     va_end(ap);
66571131Smax.romanov@nginx.com 
6658743Smax.romanov@nginx.com     if (nxt_slow_path(p > end)) {
6659743Smax.romanov@nginx.com         memcpy(end - 5, "[...]", 5);
6660743Smax.romanov@nginx.com         p = end;
6661743Smax.romanov@nginx.com     }
6662743Smax.romanov@nginx.com 
6663743Smax.romanov@nginx.com     *p++ = '\n';
6664743Smax.romanov@nginx.com 
6665743Smax.romanov@nginx.com     n = write(log_fd, msg, p - msg);
6666743Smax.romanov@nginx.com     if (nxt_slow_path(n < 0)) {
6667743Smax.romanov@nginx.com         fprintf(stderr, "Failed to write log: %.*s", (int) (p - msg), msg);
6668743Smax.romanov@nginx.com     }
6669743Smax.romanov@nginx.com }
6670743Smax.romanov@nginx.com 
6671743Smax.romanov@nginx.com 
6672743Smax.romanov@nginx.com static const char * nxt_unit_log_levels[] = {
6673743Smax.romanov@nginx.com     "alert",
6674743Smax.romanov@nginx.com     "error",
6675743Smax.romanov@nginx.com     "warn",
6676743Smax.romanov@nginx.com     "notice",
6677743Smax.romanov@nginx.com     "info",
6678743Smax.romanov@nginx.com     "debug",
6679743Smax.romanov@nginx.com };
6680743Smax.romanov@nginx.com 
6681743Smax.romanov@nginx.com 
6682743Smax.romanov@nginx.com static char *
nxt_unit_snprint_prefix(char * p,char * end,pid_t pid,int level)6683743Smax.romanov@nginx.com nxt_unit_snprint_prefix(char *p, char *end, pid_t pid, int level)
6684743Smax.romanov@nginx.com {
6685743Smax.romanov@nginx.com     struct tm        tm;
6686743Smax.romanov@nginx.com     struct timespec  ts;
6687743Smax.romanov@nginx.com 
6688743Smax.romanov@nginx.com     (void) clock_gettime(CLOCK_REALTIME, &ts);
66892256Sa.clayton@nginx.com 
6690743Smax.romanov@nginx.com #if (NXT_HAVE_LOCALTIME_R)
6691743Smax.romanov@nginx.com     (void) localtime_r(&ts.tv_sec, &tm);
6692743Smax.romanov@nginx.com #else
6693743Smax.romanov@nginx.com     tm = *localtime(&ts.tv_sec);
6694743Smax.romanov@nginx.com #endif
6695743Smax.romanov@nginx.com 
6696743Smax.romanov@nginx.com #if (NXT_DEBUG)
6697743Smax.romanov@nginx.com     p += snprintf(p, end - p,
6698743Smax.romanov@nginx.com                   "%4d/%02d/%02d %02d:%02d:%02d.%03d ",
6699743Smax.romanov@nginx.com                   tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
6700743Smax.romanov@nginx.com                   tm.tm_hour, tm.tm_min, tm.tm_sec,
6701743Smax.romanov@nginx.com                   (int) ts.tv_nsec / 1000000);
67021512Svbart@nginx.com #else
6703743Smax.romanov@nginx.com     p += snprintf(p, end - p,
6704743Smax.romanov@nginx.com                   "%4d/%02d/%02d %02d:%02d:%02d ",
6705743Smax.romanov@nginx.com                   tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
6706743Smax.romanov@nginx.com                   tm.tm_hour, tm.tm_min, tm.tm_sec);
6707743Smax.romanov@nginx.com #endif
67081512Svbart@nginx.com 
67091512Svbart@nginx.com     p += snprintf(p, end - p,
67101512Svbart@nginx.com                   "[%s] %d#%"PRIu64" [unit] ", nxt_unit_log_levels[level],
67111512Svbart@nginx.com                   (int) pid,
67121512Svbart@nginx.com                   (uint64_t) (uintptr_t) nxt_thread_get_tid());
67131512Svbart@nginx.com 
6714743Smax.romanov@nginx.com     return p;
6715743Smax.romanov@nginx.com }
6716743Smax.romanov@nginx.com 
6717743Smax.romanov@nginx.com 
6718743Smax.romanov@nginx.com static void *
nxt_unit_lvlhsh_alloc(void * data,size_t size)6719743Smax.romanov@nginx.com nxt_unit_lvlhsh_alloc(void *data, size_t size)
6720743Smax.romanov@nginx.com {
6721743Smax.romanov@nginx.com     int   err;
6722743Smax.romanov@nginx.com     void  *p;
6723743Smax.romanov@nginx.com 
67241616Smax.romanov@nginx.com     err = posix_memalign(&p, size, size);
67251616Smax.romanov@nginx.com 
6726743Smax.romanov@nginx.com     if (nxt_fast_path(err == 0)) {
67271616Smax.romanov@nginx.com         nxt_unit_debug(NULL, "posix_memalign(%d, %d): %p",
67281616Smax.romanov@nginx.com                        (int) size, (int) size, p);
67291616Smax.romanov@nginx.com         return p;
67301616Smax.romanov@nginx.com     }
6731743Smax.romanov@nginx.com 
6732743Smax.romanov@nginx.com     nxt_unit_alert(NULL, "posix_memalign(%d, %d) failed: %s (%d)",
67331616Smax.romanov@nginx.com                    (int) size, (int) size, strerror(err), err);
67341616Smax.romanov@nginx.com     return NULL;
6735743Smax.romanov@nginx.com }
6736743Smax.romanov@nginx.com 
6737743Smax.romanov@nginx.com 
67381616Smax.romanov@nginx.com static void
nxt_unit_lvlhsh_free(void * data,void * p)67391616Smax.romanov@nginx.com nxt_unit_lvlhsh_free(void *data, void *p)
6740743Smax.romanov@nginx.com {
6741743Smax.romanov@nginx.com     nxt_unit_free(NULL, p);
6742743Smax.romanov@nginx.com }
67431593Smax.romanov@nginx.com 
67441616Smax.romanov@nginx.com 
67451616Smax.romanov@nginx.com void *
nxt_unit_malloc(nxt_unit_ctx_t * ctx,size_t size)67461616Smax.romanov@nginx.com nxt_unit_malloc(nxt_unit_ctx_t *ctx, size_t size)
67471623Smax.romanov@nginx.com {
67481616Smax.romanov@nginx.com     void  *p;
67491616Smax.romanov@nginx.com 
67501616Smax.romanov@nginx.com     p = malloc(size);
67511623Smax.romanov@nginx.com 
67521623Smax.romanov@nginx.com     if (nxt_fast_path(p != NULL)) {
67531616Smax.romanov@nginx.com #if (NXT_DEBUG_ALLOC)
67541616Smax.romanov@nginx.com         nxt_unit_debug(ctx, "malloc(%d): %p", (int) size, p);
67551616Smax.romanov@nginx.com #endif
67561616Smax.romanov@nginx.com 
67571616Smax.romanov@nginx.com     } else {
67581616Smax.romanov@nginx.com         nxt_unit_alert(ctx, "malloc(%d) failed: %s (%d)",
67591710Smax.romanov@nginx.com                        (int) size, strerror(errno), errno);
67601623Smax.romanov@nginx.com     }
67611710Smax.romanov@nginx.com 
67621616Smax.romanov@nginx.com     return p;
67631616Smax.romanov@nginx.com }
67641623Smax.romanov@nginx.com 
67651616Smax.romanov@nginx.com 
67661616Smax.romanov@nginx.com void
nxt_unit_free(nxt_unit_ctx_t * ctx,void * p)67671616Smax.romanov@nginx.com nxt_unit_free(nxt_unit_ctx_t *ctx, void *p)
67681616Smax.romanov@nginx.com {
67691616Smax.romanov@nginx.com #if (NXT_DEBUG_ALLOC)
67701616Smax.romanov@nginx.com     nxt_unit_debug(ctx, "free(%p)", p);
67711616Smax.romanov@nginx.com #endif
67721623Smax.romanov@nginx.com 
67731623Smax.romanov@nginx.com     free(p);
67741616Smax.romanov@nginx.com }
67751710Smax.romanov@nginx.com 
67761623Smax.romanov@nginx.com 
67771710Smax.romanov@nginx.com static int
nxt_unit_memcasecmp(const void * p1,const void * p2,size_t length)67781616Smax.romanov@nginx.com nxt_unit_memcasecmp(const void *p1, const void *p2, size_t length)
67791616Smax.romanov@nginx.com {
67801616Smax.romanov@nginx.com     u_char        c1, c2;
67811616Smax.romanov@nginx.com     nxt_int_t     n;
67821616Smax.romanov@nginx.com     const u_char  *s1, *s2;
67831593Smax.romanov@nginx.com 
67841593Smax.romanov@nginx.com     s1 = p1;
67851593Smax.romanov@nginx.com     s2 = p2;
67861593Smax.romanov@nginx.com 
67871593Smax.romanov@nginx.com     while (length-- != 0) {
67881593Smax.romanov@nginx.com         c1 = *s1++;
67891593Smax.romanov@nginx.com         c2 = *s2++;
67901593Smax.romanov@nginx.com 
67911593Smax.romanov@nginx.com         c1 = nxt_lowcase(c1);
67921593Smax.romanov@nginx.com         c2 = nxt_lowcase(c2);
67931593Smax.romanov@nginx.com 
67941593Smax.romanov@nginx.com         n = c1 - c2;
67951593Smax.romanov@nginx.com 
67961593Smax.romanov@nginx.com         if (n != 0) {
67971593Smax.romanov@nginx.com             return n;
67981593Smax.romanov@nginx.com         }
67991593Smax.romanov@nginx.com     }
68001593Smax.romanov@nginx.com 
68011593Smax.romanov@nginx.com     return 0;
68021593Smax.romanov@nginx.com }
68031593Smax.romanov@nginx.com