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, ¬ify);
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, ¬ify);
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