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 #ifndef _NXT_UNIT_H_INCLUDED_ 7743Smax.romanov@nginx.com #define _NXT_UNIT_H_INCLUDED_ 8743Smax.romanov@nginx.com 9743Smax.romanov@nginx.com 10743Smax.romanov@nginx.com #include <inttypes.h> 11743Smax.romanov@nginx.com #include <sys/types.h> 12743Smax.romanov@nginx.com #include <string.h> 13743Smax.romanov@nginx.com 14*877Salexander.borisov@nginx.com #include "nxt_unit_version.h" 15743Smax.romanov@nginx.com #include "nxt_unit_typedefs.h" 16743Smax.romanov@nginx.com 17*877Salexander.borisov@nginx.com 18743Smax.romanov@nginx.com enum { 19743Smax.romanov@nginx.com NXT_UNIT_OK = 0, 20743Smax.romanov@nginx.com NXT_UNIT_ERROR = 1, 21743Smax.romanov@nginx.com }; 22743Smax.romanov@nginx.com 23743Smax.romanov@nginx.com enum { 24743Smax.romanov@nginx.com NXT_UNIT_LOG_ALERT = 0, 25743Smax.romanov@nginx.com NXT_UNIT_LOG_ERR = 1, 26743Smax.romanov@nginx.com NXT_UNIT_LOG_WARN = 2, 27743Smax.romanov@nginx.com NXT_UNIT_LOG_NOTICE = 3, 28743Smax.romanov@nginx.com NXT_UNIT_LOG_INFO = 4, 29743Smax.romanov@nginx.com NXT_UNIT_LOG_DEBUG = 5, 30743Smax.romanov@nginx.com }; 31743Smax.romanov@nginx.com 32743Smax.romanov@nginx.com #define NXT_UNIT_INIT_ENV "NXT_UNIT_INIT" 33743Smax.romanov@nginx.com 34743Smax.romanov@nginx.com /* 35743Smax.romanov@nginx.com * Mostly opaque structure with library state. 36743Smax.romanov@nginx.com * 37743Smax.romanov@nginx.com * Only user defined 'data' pointer exposed here. The rest is unit 38743Smax.romanov@nginx.com * implementation specific and hidden. 39743Smax.romanov@nginx.com */ 40743Smax.romanov@nginx.com struct nxt_unit_s { 41743Smax.romanov@nginx.com void *data; /* User defined data. */ 42743Smax.romanov@nginx.com }; 43743Smax.romanov@nginx.com 44743Smax.romanov@nginx.com /* 45743Smax.romanov@nginx.com * Thread context. 46743Smax.romanov@nginx.com * 47743Smax.romanov@nginx.com * First (main) context is provided 'for free'. To receive and process 48743Smax.romanov@nginx.com * requests in other thread, one need to allocate context and use it 49743Smax.romanov@nginx.com * further in this thread. 50743Smax.romanov@nginx.com */ 51743Smax.romanov@nginx.com struct nxt_unit_ctx_s { 52743Smax.romanov@nginx.com void *data; /* User context-specific data. */ 53743Smax.romanov@nginx.com nxt_unit_t *unit; 54743Smax.romanov@nginx.com }; 55743Smax.romanov@nginx.com 56743Smax.romanov@nginx.com /* 57743Smax.romanov@nginx.com * Unit port identification structure. 58743Smax.romanov@nginx.com * 59743Smax.romanov@nginx.com * Each port can be uniquely identified by listen process id (pid) and port id. 60743Smax.romanov@nginx.com * This identification is required to refer the port from different process. 61743Smax.romanov@nginx.com */ 62743Smax.romanov@nginx.com struct nxt_unit_port_id_s { 63743Smax.romanov@nginx.com pid_t pid; 64743Smax.romanov@nginx.com uint32_t hash; 65743Smax.romanov@nginx.com uint16_t id; 66743Smax.romanov@nginx.com }; 67743Smax.romanov@nginx.com 68743Smax.romanov@nginx.com /* 69743Smax.romanov@nginx.com * unit provides port storage which is able to store and find the following 70743Smax.romanov@nginx.com * data structures. 71743Smax.romanov@nginx.com */ 72743Smax.romanov@nginx.com struct nxt_unit_port_s { 73743Smax.romanov@nginx.com nxt_unit_port_id_t id; 74743Smax.romanov@nginx.com 75743Smax.romanov@nginx.com int in_fd; 76743Smax.romanov@nginx.com int out_fd; 77743Smax.romanov@nginx.com 78743Smax.romanov@nginx.com void *data; 79743Smax.romanov@nginx.com }; 80743Smax.romanov@nginx.com 81743Smax.romanov@nginx.com 82743Smax.romanov@nginx.com struct nxt_unit_buf_s { 83743Smax.romanov@nginx.com char *start; 84743Smax.romanov@nginx.com char *free; 85743Smax.romanov@nginx.com char *end; 86743Smax.romanov@nginx.com }; 87743Smax.romanov@nginx.com 88743Smax.romanov@nginx.com 89743Smax.romanov@nginx.com struct nxt_unit_request_info_s { 90743Smax.romanov@nginx.com nxt_unit_t *unit; 91743Smax.romanov@nginx.com nxt_unit_ctx_t *ctx; 92743Smax.romanov@nginx.com 93743Smax.romanov@nginx.com nxt_unit_port_id_t request_port; 94743Smax.romanov@nginx.com nxt_unit_port_id_t response_port; 95743Smax.romanov@nginx.com 96743Smax.romanov@nginx.com nxt_unit_request_t *request; 97743Smax.romanov@nginx.com nxt_unit_buf_t *request_buf; 98743Smax.romanov@nginx.com 99743Smax.romanov@nginx.com nxt_unit_response_t *response; 100743Smax.romanov@nginx.com nxt_unit_buf_t *response_buf; 101743Smax.romanov@nginx.com uint32_t response_max_fields; 102743Smax.romanov@nginx.com 103743Smax.romanov@nginx.com nxt_unit_buf_t *content_buf; 104743Smax.romanov@nginx.com uint64_t content_length; 105743Smax.romanov@nginx.com 106743Smax.romanov@nginx.com void *data; 107743Smax.romanov@nginx.com }; 108743Smax.romanov@nginx.com 109743Smax.romanov@nginx.com /* 110743Smax.romanov@nginx.com * Set of application-specific callbacks. Application may leave all optional 111743Smax.romanov@nginx.com * callbacks as NULL. 112743Smax.romanov@nginx.com */ 113743Smax.romanov@nginx.com struct nxt_unit_callbacks_s { 114743Smax.romanov@nginx.com /* 115743Smax.romanov@nginx.com * Process request data. Unlike all other callback, this callback 116743Smax.romanov@nginx.com * need to be defined by application. 117743Smax.romanov@nginx.com */ 118743Smax.romanov@nginx.com void (*request_handler)(nxt_unit_request_info_t *req); 119743Smax.romanov@nginx.com 120743Smax.romanov@nginx.com /* Add new Unit port to communicate with process pid. Optional. */ 121743Smax.romanov@nginx.com int (*add_port)(nxt_unit_ctx_t *, nxt_unit_port_t *port); 122743Smax.romanov@nginx.com 123743Smax.romanov@nginx.com /* Remove previously added port. Optional. */ 124743Smax.romanov@nginx.com void (*remove_port)(nxt_unit_ctx_t *, nxt_unit_port_id_t *port_id); 125743Smax.romanov@nginx.com 126743Smax.romanov@nginx.com /* Remove all data associated with process pid including ports. Optional. */ 127743Smax.romanov@nginx.com void (*remove_pid)(nxt_unit_ctx_t *, pid_t pid); 128743Smax.romanov@nginx.com 129743Smax.romanov@nginx.com /* Gracefully quit the application. Optional. */ 130743Smax.romanov@nginx.com void (*quit)(nxt_unit_ctx_t *); 131743Smax.romanov@nginx.com 132743Smax.romanov@nginx.com /* Send data and control to process pid using port id. Optional. */ 133743Smax.romanov@nginx.com ssize_t (*port_send)(nxt_unit_ctx_t *, nxt_unit_port_id_t *port_id, 134743Smax.romanov@nginx.com const void *buf, size_t buf_size, 135743Smax.romanov@nginx.com const void *oob, size_t oob_size); 136743Smax.romanov@nginx.com 137743Smax.romanov@nginx.com /* Receive data on port id. Optional. */ 138743Smax.romanov@nginx.com ssize_t (*port_recv)(nxt_unit_ctx_t *, nxt_unit_port_id_t *port_id, 139743Smax.romanov@nginx.com void *buf, size_t buf_size, void *oob, size_t oob_size); 140743Smax.romanov@nginx.com 141743Smax.romanov@nginx.com }; 142743Smax.romanov@nginx.com 143743Smax.romanov@nginx.com 144743Smax.romanov@nginx.com struct nxt_unit_init_s { 145743Smax.romanov@nginx.com void *data; /* Opaque pointer to user-defined data. */ 146743Smax.romanov@nginx.com void *ctx_data; /* Opaque pointer to user-defined data. */ 147743Smax.romanov@nginx.com int max_pending_requests; 148743Smax.romanov@nginx.com 149743Smax.romanov@nginx.com uint32_t request_data_size; 150743Smax.romanov@nginx.com 151743Smax.romanov@nginx.com nxt_unit_callbacks_t callbacks; 152743Smax.romanov@nginx.com 153743Smax.romanov@nginx.com nxt_unit_port_t ready_port; 154743Smax.romanov@nginx.com uint32_t ready_stream; 155743Smax.romanov@nginx.com nxt_unit_port_t read_port; 156743Smax.romanov@nginx.com int log_fd; 157743Smax.romanov@nginx.com }; 158743Smax.romanov@nginx.com 159743Smax.romanov@nginx.com 160743Smax.romanov@nginx.com typedef ssize_t (*nxt_unit_read_func_t)(nxt_unit_read_info_t *read_info, 161743Smax.romanov@nginx.com void *dst, size_t size); 162743Smax.romanov@nginx.com 163743Smax.romanov@nginx.com 164743Smax.romanov@nginx.com struct nxt_unit_read_info_s { 165743Smax.romanov@nginx.com nxt_unit_read_func_t read; 166743Smax.romanov@nginx.com int eof; 167743Smax.romanov@nginx.com uint32_t buf_size; 168743Smax.romanov@nginx.com void *data; 169743Smax.romanov@nginx.com }; 170743Smax.romanov@nginx.com 171743Smax.romanov@nginx.com 172743Smax.romanov@nginx.com /* 173743Smax.romanov@nginx.com * Initialize Unit application library with necessary callbacks and 174743Smax.romanov@nginx.com * ready/reply port parameters, send 'READY' response to master. 175743Smax.romanov@nginx.com */ 176743Smax.romanov@nginx.com nxt_unit_ctx_t *nxt_unit_init(nxt_unit_init_t *); 177743Smax.romanov@nginx.com 178743Smax.romanov@nginx.com /* 179743Smax.romanov@nginx.com * Process received message, invoke configured callbacks. 180743Smax.romanov@nginx.com * 181743Smax.romanov@nginx.com * If application implements it's own event loop, each datagram received 182743Smax.romanov@nginx.com * from port socket should be initially processed by unit. This function 183743Smax.romanov@nginx.com * may invoke other application-defined callback for message processing. 184743Smax.romanov@nginx.com */ 185743Smax.romanov@nginx.com int nxt_unit_process_msg(nxt_unit_ctx_t *, nxt_unit_port_id_t *port_id, 186743Smax.romanov@nginx.com void *buf, size_t buf_size, void *oob, size_t oob_size); 187743Smax.romanov@nginx.com 188743Smax.romanov@nginx.com /* 189743Smax.romanov@nginx.com * Main function useful in case when application does not have it's own 190743Smax.romanov@nginx.com * event loop. nxt_unit_run() starts infinite message wait and process loop. 191743Smax.romanov@nginx.com * 192743Smax.romanov@nginx.com * for (;;) { 193743Smax.romanov@nginx.com * app_lib->port_recv(...); 194743Smax.romanov@nginx.com * nxt_unit_process_msg(...); 195743Smax.romanov@nginx.com * } 196743Smax.romanov@nginx.com * 197743Smax.romanov@nginx.com * The normally function returns when QUIT message received from Unit. 198743Smax.romanov@nginx.com */ 199743Smax.romanov@nginx.com int nxt_unit_run(nxt_unit_ctx_t *); 200743Smax.romanov@nginx.com 201828Salexander.borisov@nginx.com int nxt_unit_run_once(nxt_unit_ctx_t *ctx); 202828Salexander.borisov@nginx.com 203743Smax.romanov@nginx.com /* Destroy application library object. */ 204743Smax.romanov@nginx.com void nxt_unit_done(nxt_unit_ctx_t *); 205743Smax.romanov@nginx.com 206743Smax.romanov@nginx.com /* 207743Smax.romanov@nginx.com * Allocate and initialize new execution context with new listen port to 208743Smax.romanov@nginx.com * process requests in other thread. 209743Smax.romanov@nginx.com */ 210743Smax.romanov@nginx.com nxt_unit_ctx_t *nxt_unit_ctx_alloc(nxt_unit_ctx_t *, void *); 211743Smax.romanov@nginx.com 212743Smax.romanov@nginx.com /* Free unused context. It is not required to free main context. */ 213743Smax.romanov@nginx.com void nxt_unit_ctx_free(nxt_unit_ctx_t *); 214743Smax.romanov@nginx.com 215743Smax.romanov@nginx.com /* Initialize port_id, calculate hash. */ 216743Smax.romanov@nginx.com void nxt_unit_port_id_init(nxt_unit_port_id_t *port_id, pid_t pid, uint16_t id); 217743Smax.romanov@nginx.com 218743Smax.romanov@nginx.com /* 219743Smax.romanov@nginx.com * Create extra incoming port, perform all required actions to propogate 220743Smax.romanov@nginx.com * the port to Unit server. Fills structure referenced by port_id with 221743Smax.romanov@nginx.com * current pid and new port id. 222743Smax.romanov@nginx.com */ 223743Smax.romanov@nginx.com int nxt_unit_create_send_port(nxt_unit_ctx_t *, nxt_unit_port_id_t *dst, 224743Smax.romanov@nginx.com nxt_unit_port_id_t *port_id); 225743Smax.romanov@nginx.com 226743Smax.romanov@nginx.com /* Default 'add_port' implementation. */ 227743Smax.romanov@nginx.com int nxt_unit_add_port(nxt_unit_ctx_t *, nxt_unit_port_t *port); 228743Smax.romanov@nginx.com 229743Smax.romanov@nginx.com /* Find previously added port. */ 230743Smax.romanov@nginx.com nxt_unit_port_t *nxt_unit_find_port(nxt_unit_ctx_t *, 231743Smax.romanov@nginx.com nxt_unit_port_id_t *port_id); 232743Smax.romanov@nginx.com 233743Smax.romanov@nginx.com /* Find, fill output 'port' and remove port from storage. */ 234743Smax.romanov@nginx.com void nxt_unit_find_remove_port(nxt_unit_ctx_t *, nxt_unit_port_id_t *port_id, 235743Smax.romanov@nginx.com nxt_unit_port_t *port); 236743Smax.romanov@nginx.com 237743Smax.romanov@nginx.com /* Default 'remove_port' implementation. */ 238743Smax.romanov@nginx.com void nxt_unit_remove_port(nxt_unit_ctx_t *, nxt_unit_port_id_t *port_id); 239743Smax.romanov@nginx.com 240743Smax.romanov@nginx.com /* Default 'remove_pid' implementation. */ 241743Smax.romanov@nginx.com void nxt_unit_remove_pid(nxt_unit_ctx_t *, pid_t pid); 242743Smax.romanov@nginx.com 243743Smax.romanov@nginx.com /* Default 'quit' implementation. */ 244743Smax.romanov@nginx.com void nxt_unit_quit(nxt_unit_ctx_t *); 245743Smax.romanov@nginx.com 246743Smax.romanov@nginx.com /* Default 'port_send' implementation. */ 247743Smax.romanov@nginx.com ssize_t nxt_unit_port_send(nxt_unit_ctx_t *, int fd, 248743Smax.romanov@nginx.com const void *buf, size_t buf_size, 249743Smax.romanov@nginx.com const void *oob, size_t oob_size); 250743Smax.romanov@nginx.com 251743Smax.romanov@nginx.com /* Default 'port_recv' implementation. */ 252743Smax.romanov@nginx.com ssize_t nxt_unit_port_recv(nxt_unit_ctx_t *, int fd, void *buf, size_t buf_size, 253743Smax.romanov@nginx.com void *oob, size_t oob_size); 254743Smax.romanov@nginx.com 255743Smax.romanov@nginx.com /* Calculates hash for given field name. */ 256743Smax.romanov@nginx.com uint16_t nxt_unit_field_hash(const char* name, size_t name_length); 257743Smax.romanov@nginx.com 258743Smax.romanov@nginx.com /* Split host for server name and port. */ 259743Smax.romanov@nginx.com void nxt_unit_split_host(char *host_start, uint32_t host_length, 260743Smax.romanov@nginx.com char **name, uint32_t *name_length, char **port, uint32_t *port_length); 261743Smax.romanov@nginx.com 262743Smax.romanov@nginx.com /* Group duplicate fields for easy enumeration. */ 263743Smax.romanov@nginx.com void nxt_unit_request_group_dup_fields(nxt_unit_request_info_t *req); 264743Smax.romanov@nginx.com 265743Smax.romanov@nginx.com /* 266743Smax.romanov@nginx.com * Allocate response structure capable to store limited numer of fields. 267743Smax.romanov@nginx.com * The structure may be accessed directly via req->response pointer or 268743Smax.romanov@nginx.com * filled step-by-step using functions add_field and add_content. 269743Smax.romanov@nginx.com */ 270743Smax.romanov@nginx.com int nxt_unit_response_init(nxt_unit_request_info_t *req, 271743Smax.romanov@nginx.com uint16_t status, uint32_t max_fields_count, uint32_t max_fields_size); 272743Smax.romanov@nginx.com 273743Smax.romanov@nginx.com int nxt_unit_response_realloc(nxt_unit_request_info_t *req, 274743Smax.romanov@nginx.com uint32_t max_fields_count, uint32_t max_fields_size); 275743Smax.romanov@nginx.com 276743Smax.romanov@nginx.com int nxt_unit_response_is_init(nxt_unit_request_info_t *req); 277743Smax.romanov@nginx.com 278743Smax.romanov@nginx.com int nxt_unit_response_add_field(nxt_unit_request_info_t *req, 279743Smax.romanov@nginx.com const char* name, uint8_t name_length, 280743Smax.romanov@nginx.com const char* value, uint32_t value_length); 281743Smax.romanov@nginx.com 282743Smax.romanov@nginx.com int nxt_unit_response_add_content(nxt_unit_request_info_t *req, 283743Smax.romanov@nginx.com const void* src, uint32_t size); 284743Smax.romanov@nginx.com 285743Smax.romanov@nginx.com /* 286743Smax.romanov@nginx.com * Send prepared response to Unit server. Response structure destroyed during 287743Smax.romanov@nginx.com * this call. 288743Smax.romanov@nginx.com */ 289743Smax.romanov@nginx.com int nxt_unit_response_send(nxt_unit_request_info_t *req); 290743Smax.romanov@nginx.com 291743Smax.romanov@nginx.com int nxt_unit_response_is_sent(nxt_unit_request_info_t *req); 292743Smax.romanov@nginx.com 293743Smax.romanov@nginx.com nxt_unit_buf_t *nxt_unit_response_buf_alloc(nxt_unit_request_info_t *req, 294743Smax.romanov@nginx.com uint32_t size); 295743Smax.romanov@nginx.com 296743Smax.romanov@nginx.com int nxt_unit_buf_send(nxt_unit_buf_t *buf); 297743Smax.romanov@nginx.com 298743Smax.romanov@nginx.com void nxt_unit_buf_free(nxt_unit_buf_t *buf); 299743Smax.romanov@nginx.com 300743Smax.romanov@nginx.com nxt_unit_buf_t *nxt_unit_buf_next(nxt_unit_buf_t *buf); 301743Smax.romanov@nginx.com 302743Smax.romanov@nginx.com uint32_t nxt_unit_buf_max(void); 303743Smax.romanov@nginx.com 304743Smax.romanov@nginx.com uint32_t nxt_unit_buf_min(void); 305743Smax.romanov@nginx.com 306743Smax.romanov@nginx.com int nxt_unit_response_write(nxt_unit_request_info_t *req, const void *start, 307743Smax.romanov@nginx.com size_t size); 308743Smax.romanov@nginx.com 309743Smax.romanov@nginx.com int nxt_unit_response_write_cb(nxt_unit_request_info_t *req, 310743Smax.romanov@nginx.com nxt_unit_read_info_t *read_info); 311743Smax.romanov@nginx.com 312743Smax.romanov@nginx.com ssize_t nxt_unit_request_read(nxt_unit_request_info_t *req, void *dst, 313743Smax.romanov@nginx.com size_t size); 314743Smax.romanov@nginx.com 315743Smax.romanov@nginx.com void nxt_unit_request_done(nxt_unit_request_info_t *req, int rc); 316743Smax.romanov@nginx.com 317743Smax.romanov@nginx.com 318743Smax.romanov@nginx.com void nxt_unit_log(nxt_unit_ctx_t *ctx, int level, const char* fmt, ...); 319743Smax.romanov@nginx.com 320743Smax.romanov@nginx.com void nxt_unit_req_log(nxt_unit_request_info_t *req, int level, 321743Smax.romanov@nginx.com const char* fmt, ...); 322743Smax.romanov@nginx.com 323743Smax.romanov@nginx.com #if (NXT_DEBUG) 324743Smax.romanov@nginx.com 325743Smax.romanov@nginx.com #define nxt_unit_debug(ctx, fmt, ARGS...) \ 326743Smax.romanov@nginx.com nxt_unit_log(ctx, NXT_UNIT_LOG_DEBUG, fmt, ##ARGS) 327743Smax.romanov@nginx.com 328743Smax.romanov@nginx.com #define nxt_unit_req_debug(req, fmt, ARGS...) \ 329743Smax.romanov@nginx.com nxt_unit_req_log(req, NXT_UNIT_LOG_DEBUG, fmt, ##ARGS) 330743Smax.romanov@nginx.com 331743Smax.romanov@nginx.com #else 332743Smax.romanov@nginx.com 333743Smax.romanov@nginx.com #define nxt_unit_debug(ctx, fmt, ARGS...) 334743Smax.romanov@nginx.com 335743Smax.romanov@nginx.com #define nxt_unit_req_debug(req, fmt, ARGS...) 336743Smax.romanov@nginx.com 337743Smax.romanov@nginx.com #endif 338743Smax.romanov@nginx.com 339743Smax.romanov@nginx.com 340743Smax.romanov@nginx.com #define nxt_unit_warn(ctx, fmt, ARGS...) \ 341743Smax.romanov@nginx.com nxt_unit_log(ctx, NXT_UNIT_LOG_WARN, fmt, ##ARGS) 342743Smax.romanov@nginx.com 343743Smax.romanov@nginx.com #define nxt_unit_req_warn(req, fmt, ARGS...) \ 344743Smax.romanov@nginx.com nxt_unit_req_log(req, NXT_UNIT_LOG_WARN, fmt, ##ARGS) 345743Smax.romanov@nginx.com 346743Smax.romanov@nginx.com #define nxt_unit_error(ctx, fmt, ARGS...) \ 347743Smax.romanov@nginx.com nxt_unit_log(ctx, NXT_UNIT_LOG_ERR, fmt, ##ARGS) 348743Smax.romanov@nginx.com 349743Smax.romanov@nginx.com #define nxt_unit_req_error(req, fmt, ARGS...) \ 350743Smax.romanov@nginx.com nxt_unit_req_log(req, NXT_UNIT_LOG_ERR, fmt, ##ARGS) 351743Smax.romanov@nginx.com 352743Smax.romanov@nginx.com #define nxt_unit_alert(ctx, fmt, ARGS...) \ 353743Smax.romanov@nginx.com nxt_unit_log(ctx, NXT_UNIT_LOG_ALERT, fmt, ##ARGS) 354743Smax.romanov@nginx.com 355743Smax.romanov@nginx.com #define nxt_unit_req_alert(req, fmt, ARGS...) \ 356743Smax.romanov@nginx.com nxt_unit_req_log(req, NXT_UNIT_LOG_ALERT, fmt, ##ARGS) 357743Smax.romanov@nginx.com 358743Smax.romanov@nginx.com 359743Smax.romanov@nginx.com #endif /* _NXT_UNIT_H_INCLUDED_ */ 360