├── t ├── dns_install.sh ├── test.com.zone ├── test1.com.zone ├── named.conf ├── ngx_test_macro.h ├── md5testfile ├── nginx_dynamic.conf ├── config ├── nginx.conf ├── ngx_poold_test_module.c ├── ngx_rbuf_test_module.c ├── ngx_event_resolver_test_module.c ├── ngx_event_timer_test_module.c ├── ngx_dynamic_resolver_test_module.c ├── ngx_dynamic_conf_test_module.c ├── ngx_timerd_test_module.c ├── ngx_map_test_module.c ├── ngx_http_dynamic_test_module.c └── ngx_toolkit_misc_test_module.c ├── doc ├── ngx-poold.md ├── ngx-rbuf.md ├── ngx-toolkit-misc.md ├── ngx-event-timer-module.md ├── ngx-event-resolver-module.md ├── ngx-map.md ├── ngx-dynamic-resolver-module.md └── ngx-dynamic-conf-module.md ├── ngx_http_dynamic.h ├── ngx_event_timer_module.h ├── ngx_event_resolver.h ├── COPYRIGHT ├── README.md ├── ngx_poold.h ├── ngx_rbuf.h ├── ngx_dynamic_resolver.h ├── ngx_timerd.h ├── config ├── ngx_dynamic_conf.h ├── ngx_map.h ├── ngx_toolkit_misc.h ├── ngx_poold.c ├── ngx_rbuf.c ├── ngx_event_timer_module.c ├── ngx_timerd.c ├── ngx_map.c ├── ngx_event_resolver.c ├── ngx_toolkit_misc.c ├── ngx_http_trace_module.c └── ngx_dynamic_resolver.c /t/dns_install.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | yum install -y bind bind-chroot bind-utils 4 | cp -f named.conf /etc/ 5 | cp -f test.com.zone /var/named/ 6 | chgrp named /etc/named.conf 7 | chgrp named /var/named/test.com.zone 8 | -------------------------------------------------------------------------------- /t/test.com.zone: -------------------------------------------------------------------------------- 1 | $TTL 3H 2 | @ IN SOA @ wj19840501.gmail.com. ( 3 | 0 ; serial 4 | 1D ; refresh 5 | 1H ; retry 6 | 1W ; expire 7 | 3H ; minimum 8 | ) 9 | 10 | @ IN NS dns 11 | dns IN A 192.168.84.254 12 | www IN A 1.1.1.1 13 | www IN A 1.1.1.2 14 | www IN A 1.1.1.3 15 | -------------------------------------------------------------------------------- /t/test1.com.zone: -------------------------------------------------------------------------------- 1 | $TTL 3H 2 | @ IN SOA @ wj19840501.gmail.com. ( 3 | 0 ; serial 4 | 1D ; refresh 5 | 1H ; retry 6 | 1W ; expire 7 | 3H ; minimum 8 | ) 9 | 10 | @ IN NS dns 11 | dns IN A 192.168.84.254 12 | www IN A 1.1.1.4 13 | www IN A 1.1.1.5 14 | www IN A 1.1.1.6 15 | -------------------------------------------------------------------------------- /t/named.conf: -------------------------------------------------------------------------------- 1 | options { 2 | directory "/var/named"; 3 | recursion no; 4 | }; 5 | 6 | logging { 7 | channel default_debug { 8 | file "data/named.run"; 9 | severity dynamic; 10 | }; 11 | }; 12 | 13 | zone "test.com." { 14 | type master; 15 | file "test.com.zone"; 16 | }; 17 | 18 | zone "test1.com." { 19 | type master; 20 | file "test1.com.zone"; 21 | }; 22 | 23 | include "/etc/named.rfc1912.zones"; 24 | include "/etc/named.root.key"; 25 | 26 | -------------------------------------------------------------------------------- /doc/ngx-poold.md: -------------------------------------------------------------------------------- 1 | # ngx-poold 2 | --- 3 | ## Instructions 4 | 5 | Pool debug for check whether pool is destroy or destroy twice 6 | 7 | ## API 8 | 9 | **NGX\_CREATE\_POOL** 10 | 11 | #define NGX_CREATE_POOL(size, log) 12 | 13 | Replace NGX\_CREATE\_POOL instead of ngx\_create\_pool, it will record position creating pool. must use with NGX\_DESTROY\_POOL 14 | 15 | **NGX\_DESTROY\_POOL** 16 | 17 | #define NGX_DESTROY_POOL(pool) 18 | 19 | Replace NGX\_DESTROY\_POOL instead of ngx\_destroy\_pool, it will delete info which NGX\_CREATE\_POOL add. If pool not register in record pool, the pool will not destroy, and log delete twice log and position call the NGX\_DESTROY\_POOL. -------------------------------------------------------------------------------- /ngx_http_dynamic.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) AlexWoo(Wu Jie) wj19840501@gmail.com 3 | */ 4 | 5 | 6 | #ifndef _NGX_HTTP_DYNAMIC_H_INCLUDED_ 7 | #define _NGX_HTTP_DYNAMIC_H_INCLUDED_ 8 | 9 | 10 | #include 11 | #include 12 | 13 | 14 | typedef struct { 15 | void *(*create_main_conf)(ngx_conf_t *cf); 16 | char *(*init_main_conf)(ngx_conf_t *cf, void *conf); 17 | 18 | void *(*create_srv_conf)(ngx_conf_t *cf); 19 | char *(*init_srv_conf)(ngx_conf_t *cf, void *conf); 20 | 21 | void *(*create_loc_conf)(ngx_conf_t *cf); 22 | char *(*init_loc_conf)(ngx_conf_t *cf, void *conf); 23 | } ngx_http_dynamic_module_t; 24 | 25 | 26 | void *ngx_http_get_module_main_dconf(ngx_http_request_t *r, ngx_module_t *m); 27 | void *ngx_http_get_module_srv_dconf(ngx_http_request_t *r, ngx_module_t *m); 28 | void *ngx_http_get_module_loc_dconf(ngx_http_request_t *r, ngx_module_t *m); 29 | 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /ngx_event_timer_module.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) AlexWoo(Wu Jie) wj19840501@gmail.com 3 | */ 4 | 5 | 6 | #ifndef _NGX_EVENT_TIMER_MODULE_H_INCLUDED_ 7 | #define _NGX_EVENT_TIMER_MODULE_H_INCLUDED_ 8 | 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | 16 | typedef void (* ngx_timer_handler_pt)(void *data); 17 | 18 | /* 19 | * return value: 20 | * return timerid for successd, NGX_ERROR for failed 21 | * paras: 22 | * tv : timer interval to trigger handler 23 | * h : timer handler 24 | * data : data of h para 25 | */ 26 | ngx_int_t ngx_event_timer_add_timer(ngx_msec_t tv, 27 | ngx_timer_handler_pt h, void *data); 28 | 29 | /* 30 | * paras: 31 | * timerid: value return in ngx_timer_add_timer 32 | */ 33 | void ngx_event_timer_del_timer(ngx_uint_t timerid); 34 | 35 | /* 36 | * paras: 37 | * r: http request to query status of event timer 38 | */ 39 | ngx_chain_t *ngx_event_timer_state(ngx_http_request_t *r); 40 | 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /doc/ngx-rbuf.md: -------------------------------------------------------------------------------- 1 | # ngx-rbuf 2 | --- 3 | ## Instructions 4 | 5 | A recycled chainbuf for nginx 6 | 7 | ## API 8 | 9 | **header file** 10 | 11 | For using this API, You should include the header file as below: 12 | 13 | #include "ngx_rbuf.h" 14 | 15 | **ngx\_get\_chainbuf** 16 | 17 | ngx_chain_t *ngx_get_chainbuf(size_t size, ngx_flag_t alloc_rbuf); 18 | 19 | Interface for get a chain with buf, if alloc\_rbuf is set to 1, rbuf will alloc a buf with size set in paras; if alloc\_rbuf is set to 0, size is nonsense here. 20 | 21 | Notice, for recycled buf better memory manager, the size should be same for the same usage. Such as chunk size in nginx rtmp module. 22 | 23 | 24 | **ngx\_put\_chainbuf** 25 | 26 | void ngx_put_chainbuf(ngx_chain_t *cl); 27 | 28 | Interface for recycle chain with buf alloc from rbuf 29 | 30 | **ngx\_rbuf\_statee** 31 | 32 | ngx_chain_t *ngx_rbuf_state(ngx_http_request_t *r); 33 | 34 | Interface for query rbuf state, result: 35 | 36 | ngx_rbuf_nalloc_node: 1 37 | ngx_rbuf_nalloc_buf: 1 38 | ngx_rbuf_nfree_buf: 1 39 | ngx_rbuf_nalloc_chain: 3 40 | ngx_rbuf_nalloc_chain: 3 41 | -------------------------------------------------------------------------------- /ngx_event_resolver.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) AlexWoo(Wu Jie) wj19840501@gmail.com 3 | */ 4 | 5 | 6 | 7 | #ifndef _NGX_EVENT_RESOLVER_H_INCLUDED_ 8 | #define _NGX_EVENT_RESOLVER_H_INCLUDED_ 9 | 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | 17 | /* 18 | * paras: 19 | * data : user private data set in ngx_event_resolver_start_resolver 20 | * addrs : addrs resolv by DNS 21 | * naddrs: number of addrs resolv by DNS 22 | */ 23 | typedef void (* ngx_event_resolver_handler_pt)(void *data, 24 | ngx_resolver_addr_t *addrs, ngx_uint_t naddrs); 25 | 26 | 27 | /* 28 | * paras: 29 | * domain: domain for resolving 30 | * h : callback handler 31 | * data : data for callback 32 | */ 33 | void ngx_event_resolver_start_resolver(ngx_str_t *domain, 34 | ngx_event_resolver_handler_pt h, void *data); 35 | 36 | /* 37 | * paras: 38 | * r: http request to query status of event resolver 39 | */ 40 | ngx_chain_t *ngx_event_resolver_state(ngx_http_request_t *r); 41 | 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /t/ngx_test_macro.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) AlexWoo(Wu Jie) wj19840501@gmail.com 3 | */ 4 | 5 | 6 | #ifndef _NGX_TEST_MACRO_H_INCLUDE_ 7 | #define _NGX_TEST_MACRO_H_INCLUDE_ 8 | 9 | 10 | #include 11 | #include 12 | 13 | 14 | static ngx_int_t count = 0; 15 | static ngx_int_t pass = 0; 16 | 17 | #define NGX_TEST_INIT count = 0, pass = 0; 18 | 19 | #define NGX_TEST_ISOK(testcase) \ 20 | { \ 21 | ngx_int_t __ret = testcase; \ 22 | ++count; \ 23 | if (__ret) ++pass; \ 24 | ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, 0, " TEST "#testcase"%s",\ 25 | (__ret ? " ...OK" : " ...ERROR")); \ 26 | } 27 | 28 | #define NGX_TEST_INT(di, si) \ 29 | (di == si) 30 | 31 | static ngx_inline ngx_int_t 32 | ngx_test_str(ngx_str_t *nstr, char *cstr) 33 | { 34 | size_t len; 35 | 36 | len = ngx_strlen(cstr); 37 | 38 | return (nstr->len == len && ngx_memcmp(nstr->data, cstr, len) == 0); 39 | } 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /COPYRIGHT: -------------------------------------------------------------------------------- 1 | Copyright (C) 2016-2020, by Jie Wu "AlexWoo" . 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 1. Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 | ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 | OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 | SUCH DAMAGE. 24 | 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Module nginx-toolkit-module 2 | --- 3 | ## Instructions 4 | 5 | Nginx event toolkit modules. It contains modules below, and will add more in the future. 6 | 7 | - [ngx-event-timer-module](doc/ngx-event-timer-module.md) 8 | 9 | Independent timer for nginx 10 | 11 | - [ngx-event-resolver-module](doc/ngx-event-resolver-module.md) 12 | 13 | Common resovler in event modules, just like http resolver, stream resolver in nginx, but can be used by http modules, stream modules and other modules 14 | 15 | - [ngx-dynamic-resolver-module](doc/ngx-dynamic-resolver-module.md) 16 | 17 | System will resolver domain in dynamic resolver every few seconds configured 18 | 19 | The module will return addr whose domain is resolved in dynamic resolver, otherwise, the module will add domain into dynamic resolver, resolv domain by event resolver, and call callback when resolved 20 | 21 | - [ngx-dynamic-conf-module](doc/ngx-dynamic-conf-module.md) 22 | 23 | System will reload conf when nginx dynamic config file change. Developer can use this module to reload file without reload nginx worker 24 | 25 | Now it support NGX\_CORE\_MODULE and NGX\_HTTP\_MODULE 26 | 27 | - [ngx-map](doc/ngx-map.md) 28 | 29 | A map implement use ngx\_rbtree 30 | 31 | - [ngx-rbuf](doc/ngx-rbuf.md) 32 | 33 | A recycled chainbuf for nginx 34 | 35 | - [ngx-toolkit-misc](doc/ngx-toolkit-misc.md) 36 | 37 | Misc toolkit functions 38 | -------------------------------------------------------------------------------- /t/md5testfile: -------------------------------------------------------------------------------- 1 | Copyright (C) 2016-2020, by Jie Wu "AlexWoo" . 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 1. Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 | ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 | OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 | SUCH DAMAGE. 24 | 25 | -------------------------------------------------------------------------------- /t/nginx_dynamic.conf: -------------------------------------------------------------------------------- 1 | dynamic_test_i 200; 2 | dynamic_test_s hello_world; 3 | 4 | http { 5 | main_int 1000; 6 | main_str gogogo; 7 | 8 | #defult server 9 | server { 10 | srv_int 1; 11 | srv_str default; 12 | } 13 | 14 | #wildcard_head 15 | server { 16 | srv_int 2; 17 | srv_str wildcard_head; 18 | server_name *.baidu.com; 19 | } 20 | 21 | #wildcard_tail 22 | server { 23 | srv_int 3; 24 | srv_str wildcard_tail; 25 | server_name www.google.*; 26 | } 27 | 28 | #hash 29 | server { 30 | srv_int 4; 31 | srv_str hash; 32 | server_name sports.sina.com.cn; 33 | 34 | location = / { 35 | loc_int 1; 36 | loc_str =/; 37 | } 38 | 39 | location / { 40 | loc_int 2; 41 | loc_str /; 42 | } 43 | 44 | location ^~ /test1/ { 45 | loc_int 3; 46 | loc_str ^~/test1/; 47 | } 48 | 49 | location ~* \.(gif|jpg|jpeg)$ { 50 | loc_int 4; 51 | loc_str ~*\.(gif|jpg|jpeg)$; 52 | } 53 | 54 | location /test { 55 | loc_int 5; 56 | loc_str /test; 57 | } 58 | } 59 | 60 | #pcre 61 | server { 62 | srv_int 5; 63 | srv_str pcre; 64 | server_name ~^flv(?!.*(dl\.))[A-Za-z0-9]*\.test\.com$; 65 | } 66 | 67 | #multi 68 | server { 69 | srv_int 6; 70 | srv_str multi; 71 | server_name ~^flv(?!.*(dl\.))[A-Za-z0-9]*\.haha\.com$ www.sohu.com; 72 | server_name *.qq.com; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /ngx_poold.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) AlexWoo(Wu Jie) wj19840501@gmail.com 3 | */ 4 | 5 | 6 | #ifndef _NGX_POOL_DEBUG_H_INCLUDED_ 7 | #define _NGX_POOL_DEBUG_H_INCLUDED_ 8 | 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | 15 | #if (NGX_DEBUG) 16 | 17 | #define NGX_CREATE_POOL(size, log) \ 18 | ngx_create_pool_debug(size, log, __FILE__, __LINE__) 19 | 20 | #else 21 | 22 | #define NGX_CREATE_POOL(size, log) \ 23 | ngx_create_pool(size, log) 24 | 25 | #endif 26 | 27 | 28 | #if (NGX_DEBUG) 29 | 30 | #define NGX_DESTROY_POOL(pool) \ 31 | ngx_destroy_pool_debug(pool, __FILE__, __LINE__) 32 | 33 | #else 34 | 35 | #define NGX_DESTROY_POOL(pool) \ 36 | ngx_destroy_pool(pool) 37 | 38 | #endif 39 | 40 | 41 | /* 42 | * create pool and record where to create it for debugging 43 | * such as pool not destroy 44 | * 45 | * paras: 46 | * size: pool size for pool creating interface in raw ngx_create_pool 47 | * log: log for pool creating interface in raw ngx_create_pool 48 | * file: use __FILE__ for recording file 49 | * line: use __LINE__ for recording line 50 | * return: 51 | * pool for successd, NULL for failed 52 | */ 53 | ngx_pool_t *ngx_create_pool_debug(size_t size, ngx_log_t *log, 54 | char *file, int line); 55 | 56 | 57 | /* 58 | * destroy pool for debugging, use as pair for ngx_create_pool_debug 59 | * 60 | * paras: 61 | * pool: pool for pool destroying interface in ran ngx_destroy_pool 62 | * file: use __FILE__ for recording file 63 | * line: use __LINE__ for recording line 64 | */ 65 | void ngx_destroy_pool_debug(ngx_pool_t *pool, char *file, int line); 66 | 67 | 68 | /* 69 | * paras: 70 | * r: http request to query status of rbuf 71 | */ 72 | ngx_chain_t *ngx_poold_state(ngx_http_request_t *r, unsigned detail); 73 | 74 | 75 | #endif 76 | -------------------------------------------------------------------------------- /ngx_rbuf.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) AlexWoo(Wu Jie) wj19840501@gmail.com 3 | */ 4 | 5 | 6 | #ifndef _NGX_RBUF_H_INCLUDED_ 7 | #define _NGX_RBUF_H_INCLUDED_ 8 | 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | 15 | ngx_chain_t *ngx_get_chainbuf_debug(size_t size, ngx_flag_t alloc_rbuf, 16 | char *file, int line); 17 | void ngx_put_chainbuf_debug(ngx_chain_t *cl, char *file, int len); 18 | 19 | /* 20 | * paras: 21 | * size: buffer size for allocate 22 | * alloc_rbuf: whether alloc rbuf 23 | * return: 24 | * nginx chain 25 | */ 26 | #define ngx_get_chainbuf(size, alloc_rbuf) \ 27 | ngx_get_chainbuf_debug(size, alloc_rbuf, __FILE__, __LINE__); 28 | 29 | /* 30 | * paras: 31 | * cl: nginx chain return by ngx_rtmp_shared_get_chainbuf 32 | */ 33 | #define ngx_put_chainbuf(cl) \ 34 | ngx_put_chainbuf_debug(cl, __FILE__, __LINE__); 35 | 36 | 37 | /* 38 | * paras: 39 | * cl: nginx chain return by ngx_rtmp_shared_get_chainbuf 40 | */ 41 | #define ngx_put_chainbufs(cl) \ 42 | { \ 43 | ngx_chain_t *l; \ 44 | \ 45 | l = cl; \ 46 | while (l) { \ 47 | cl = l->next; \ 48 | ngx_put_chainbuf_debug(l, __FILE__, __LINE__); \ 49 | l = cl; \ 50 | } \ 51 | } 52 | 53 | /* 54 | * paras: 55 | * r: http request to query status of rbuf 56 | */ 57 | ngx_chain_t *ngx_rbuf_state(ngx_http_request_t *r, unsigned detail); 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /ngx_dynamic_resolver.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) AlexWoo(Wu Jie) wj19840501@gmail.com 3 | */ 4 | 5 | 6 | #ifndef _NGX_DYNAMIC_RESOLVER_H_INCLUDED_ 7 | #define _NGX_DYNAMIC_RESOLVER_H_INCLUDED_ 8 | 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | 15 | /* 16 | * paras: 17 | * data : user private data set in ngx_dynamic_resolver_start_resolver 18 | * sa : sock address get 19 | * socklen: sock address len, 0 for get none address 20 | */ 21 | typedef void (* ngx_dynamic_resolver_handler_pt)(void *data, 22 | struct sockaddr *sa, socklen_t socklen); 23 | 24 | /* 25 | * add domain into dynamic resolver 26 | * 27 | * paras: 28 | * domain: domain for DNS query 29 | */ 30 | 31 | void ngx_dynamic_resolver_add_domain(ngx_str_t *domain, ngx_cycle_t *cycle); 32 | 33 | /* 34 | * del domain from dynamic resolver 35 | * 36 | * paras: 37 | * domain: domain for DNS query 38 | */ 39 | void ngx_dynamic_resolver_del_domain(ngx_str_t *domain); 40 | 41 | /* 42 | * get addr from dynamic resolver by domain if exist, 43 | * otherwise, get from resolver configured into event resolver 44 | * and add domain into dynamic resolver 45 | * 46 | * paras: 47 | * domain: domain for DNS query 48 | * h : callback handler 49 | * data : data for callback 50 | */ 51 | void ngx_dynamic_resolver_start_resolver(ngx_str_t *domain, 52 | ngx_dynamic_resolver_handler_pt h, void *data); 53 | 54 | /* 55 | * get addr from dynamic resolver by domain, 56 | * 57 | * return: 58 | * 0 for failed 59 | * socklen for successd 60 | * 61 | * paras: 62 | * domain: domain for query 63 | * sa : sockaddr for domain 64 | */ 65 | socklen_t ngx_dynamic_resolver_gethostbyname(ngx_str_t *domain, 66 | struct sockaddr *sa); 67 | 68 | /* 69 | * paras: 70 | * r: http request to query status of dynamic resolver 71 | */ 72 | ngx_chain_t *ngx_dynamic_resolver_state(ngx_http_request_t *r); 73 | 74 | 75 | #endif 76 | -------------------------------------------------------------------------------- /t/config: -------------------------------------------------------------------------------- 1 | ngx_addon_name=ngx_toolkit_test_module 2 | 3 | 4 | CORE_MODULES="$CORE_MODULES 5 | ngx_dynamic_core_test_module \ 6 | " 7 | 8 | HTTP_MODULES="$HTTP_MODULES \ 9 | ngx_event_timer_test_module \ 10 | ngx_event_resolver_test_module \ 11 | ngx_dynamic_resolver_test_module \ 12 | ngx_dynamic_conf_test_module \ 13 | ngx_http_dynamic_test_module \ 14 | ngx_toolkit_misc_test_module \ 15 | ngx_map_test_module \ 16 | ngx_rbuf_test_module \ 17 | ngx_poold_test_module \ 18 | ngx_timerd_test_module \ 19 | " 20 | 21 | NGX_ADDON_SRCS="$NGX_ADDON_SRCS \ 22 | $ngx_addon_dir/ngx_event_timer_test_module.c \ 23 | $ngx_addon_dir/ngx_event_resolver_test_module.c \ 24 | $ngx_addon_dir/ngx_dynamic_resolver_test_module.c \ 25 | $ngx_addon_dir/ngx_dynamic_conf_test_module.c \ 26 | $ngx_addon_dir/ngx_http_dynamic_test_module.c \ 27 | $ngx_addon_dir/ngx_toolkit_misc_test_module.c \ 28 | $ngx_addon_dir/ngx_map_test_module.c \ 29 | $ngx_addon_dir/ngx_rbuf_test_module.c \ 30 | $ngx_addon_dir/ngx_poold_test_module.c \ 31 | $ngx_addon_dir/ngx_timerd_test_module.c \ 32 | " 33 | -------------------------------------------------------------------------------- /ngx_timerd.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) AlexWoo(Wu Jie) wj19840501@gmail.com 3 | */ 4 | 5 | 6 | #ifndef _NGX_TIMER_DEBUG_H_INCLUDED_ 7 | #define _NGX_TIMER_DEBUG_H_INCLUDED_ 8 | 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | 15 | #if (NGX_DEBUG) 16 | 17 | #define NGX_ADD_TIMER(ev, timer, fpoff) \ 18 | ngx_add_timer_debug(ev, timer, fpoff, __FILE__, __LINE__) 19 | 20 | #else 21 | 22 | #define NGX_ADD_TIMER(ev, timer, fpoff) \ 23 | ngx_add_timer(ev, timer) 24 | 25 | #endif 26 | 27 | 28 | #if (NGX_DEBUG) 29 | 30 | #define NGX_DEL_TIMER(ev, footprint) \ 31 | ngx_del_timer_debug(ev, footprint, __FILE__, __LINE__) 32 | 33 | #else 34 | 35 | #define NGX_DEL_TIMER(ev, footprint) \ 36 | ngx_del_timer(ev) 37 | 38 | #endif 39 | 40 | /* 41 | * generate a new footprint 42 | * 43 | * return: 44 | * footprint 45 | */ 46 | ngx_uint_t ngx_timerd_footprint(); 47 | 48 | 49 | /* 50 | * add timer and record where to add it for debugging 51 | * such as timer not destroy 52 | * 53 | * paras: 54 | * ev: nginx event for timer 55 | * timer: timer interval for triggering timer 56 | * fpoff: footprint offset in event data 57 | * file: use __FILE__ for recording file 58 | * line: use __LINE__ for recording line 59 | * return: 60 | * pool for successd, NULL for failed 61 | */ 62 | void ngx_add_timer_debug(ngx_event_t *ev, ngx_msec_t timer, off_t fpoff, 63 | char *file, int line); 64 | 65 | 66 | /* 67 | * destroy pool for debugging, use as pair for ngx_create_pool_debug 68 | * 69 | * paras: 70 | * ev: nginx event for timer 71 | * footprint: footprint value in user event data 72 | * file: use __FILE__ for recording file 73 | * line: use __LINE__ for recording line 74 | */ 75 | void ngx_del_timer_debug(ngx_event_t *ev, ngx_uint_t footprint, 76 | char *file, int line); 77 | 78 | 79 | /* 80 | * paras: 81 | * r: http request to query status of rbuf 82 | */ 83 | ngx_chain_t *ngx_timerd_state(ngx_http_request_t *r, unsigned detail); 84 | 85 | 86 | #endif 87 | -------------------------------------------------------------------------------- /doc/ngx-toolkit-misc.md: -------------------------------------------------------------------------------- 1 | # ngx-toolkit-misc 2 | --- 3 | ## Instructions 4 | 5 | Misc toolkit functions 6 | 7 | ## API 8 | 9 | **header file** 10 | 11 | For using this API, You should include the header file as below: 12 | 13 | #include "ngx_toolkit_misc.h" 14 | 15 | **structure** 16 | 17 | /* 18 | * scheme://[user@]host[:port]/path[?args][#fragment] 19 | */ 20 | typedef struct { 21 | ngx_str_t scheme; 22 | ngx_str_t user; 23 | ngx_str_t host; 24 | ngx_str_t port; 25 | ngx_str_t path; 26 | ngx_str_t args; 27 | ngx_str_t fragment; 28 | 29 | ngx_str_t host_with_port; /* host[:port] */ 30 | ngx_str_t uri_with_args; /* /path[?args][#fragment] */ 31 | } ngx_request_url_t; 32 | 33 | **ngx\_parse\_request\_url** 34 | 35 | ngx_int_t ngx_parse_request_url(ngx_request_url_t *request_url, ngx_str_t *url); 36 | 37 | parse request url format as: scheme://[user@]host[:port]/path[?args][#fragment] 38 | 39 | - return value: 40 | 41 | - NGX_OK: parse success 42 | - NGX_ERROR: request url format error 43 | 44 | - paras: 45 | 46 | - request_url: url parse result return to user, all paras in request url is segment point to url 47 | - url: request url for parse 48 | 49 | 50 | **ngx\_request\_port** 51 | 52 | in_port_t ngx_request_port(ngx_str_t *scheme, ngx_str_t *port); 53 | 54 | convert port to in_port_t according to scheme and port 55 | 56 | - return value: 57 | 58 | - If port is set to correct number range in [1, 65535], return port 59 | - If port is set to non correct value, return 0 60 | - If port is not set, return default value for scheme: 61 | 62 | - 80 for http 63 | - 443 for https 64 | - 1935 for rtmp 65 | - 0 for others now 66 | 67 | - values: 68 | 69 | - scheme : sheme string like http https or rtmp 70 | - port : port for convert to in_port_t 71 | 72 | 73 | **ngx\_md5\_file** 74 | 75 | #define NGX_MD5KEY_LEN 32 76 | 77 | ngx_int_t ngx_md5_file(ngx_fd_t fd, u_char md5key[NGX_MD5KEY_LEN]); 78 | 79 | calculating file md5key as md5sum in shell 80 | 81 | - return value: 82 | 83 | - NGX_OK: calculating success 84 | - NGX_ERROR: calculating error such as file is not exist 85 | 86 | - paras: 87 | 88 | - fd: file desc for calculating md5key 89 | - md5key: md5key result -------------------------------------------------------------------------------- /config: -------------------------------------------------------------------------------- 1 | ngx_addon_name=ngx_toolkit_module 2 | 3 | 4 | CORE_MODULES="$CORE_MODULES \ 5 | ngx_http_dynamic_module \ 6 | " 7 | 8 | EVENT_MODULES="$EVENT_MODULES \ 9 | ngx_event_timer_module \ 10 | ngx_dynamic_conf_module \ 11 | ngx_event_resolver_module \ 12 | ngx_dynamic_resolver_module \ 13 | " 14 | 15 | HTTP_MODULES="$HTTP_MODULES \ 16 | ngx_http_dynamic_core_module \ 17 | ngx_http_trace_module \ 18 | " 19 | 20 | NGX_ADDON_SRCS="$NGX_ADDON_SRCS \ 21 | $ngx_addon_dir/ngx_event_timer_module.c \ 22 | $ngx_addon_dir/ngx_event_resolver.c \ 23 | $ngx_addon_dir/ngx_dynamic_resolver.c \ 24 | $ngx_addon_dir/ngx_dynamic_conf.c \ 25 | $ngx_addon_dir/ngx_http_dynamic.c \ 26 | $ngx_addon_dir/ngx_toolkit_misc.c \ 27 | $ngx_addon_dir/ngx_map.c \ 28 | $ngx_addon_dir/ngx_rbuf.c \ 29 | $ngx_addon_dir/ngx_poold.c \ 30 | $ngx_addon_dir/ngx_timerd.c \ 31 | $ngx_addon_dir/ngx_http_trace_module.c \ 32 | " 33 | 34 | NGX_ADDON_DEPS="$NGX_ADDON_DEPS \ 35 | $ngx_addon_dir/ngx_event_timer_module.h \ 36 | $ngx_addon_dir/ngx_event_resolver.h \ 37 | $ngx_addon_dir/ngx_dynamic_resolver.h \ 38 | $ngx_addon_dir/ngx_dynamic_conf.h \ 39 | $ngx_addon_dir/ngx_http_dynamic.h \ 40 | $ngx_addon_dir/ngx_toolkit_misc.h \ 41 | $ngx_addon_dir/ngx_map.h \ 42 | $ngx_addon_dir/ngx_rbuf.h \ 43 | $ngx_addon_dir/ngx_poold.h \ 44 | $ngx_addon_dir/ngx_timerd.h \ 45 | " 46 | 47 | CFLAGS="$CFLAGS -I $ngx_addon_dir" 48 | -------------------------------------------------------------------------------- /t/nginx.conf: -------------------------------------------------------------------------------- 1 | 2 | user root; 3 | worker_processes 1; 4 | 5 | #error_log logs/error.log; 6 | #error_log logs/error.log notice; 7 | error_log logs/error.log info; 8 | #error_log logs/error.log debug; 9 | 10 | #pid logs/nginx.pid; 11 | 12 | dynamic_conf conf/nginx_dynamic.conf 10; 13 | dynamic_log logs/error_dynamic.log info; 14 | 15 | events { 16 | worker_connections 1024; 17 | worker_timers 1024; 18 | resolver 192.168.84.254 valid=20s; 19 | resolver_timeout 10s; 20 | dynamic_refresh_interval 5m; 21 | } 22 | 23 | http { 24 | include mime.types; 25 | default_type application/octet-stream; 26 | 27 | sendfile on; 28 | 29 | keepalive_timeout 65; 30 | 31 | server { 32 | listen 80; 33 | server_name localhost; 34 | 35 | location /trace1/ { 36 | proxy_http_version 1.1; 37 | proxy_set_header Host $host; 38 | proxy_set_header X-Real-IP $remote_addr; 39 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 40 | proxy_set_header Connection ""; 41 | proxy_set_header X-NTM-Parentid $ntm_currentid; 42 | proxy_set_header X-NTM-Currentid $ntm_newid; 43 | proxy_pass http://127.0.0.1/trace/; 44 | } 45 | 46 | location /trace/ { 47 | echo $http_x_ntm_traceid; 48 | echo $http_x_ntm_currentid; 49 | echo $http_x_ntm_parentid; 50 | echo $http_x_ntm_debug; 51 | echo "trace variables"; 52 | echo $ntm_traceid; 53 | echo $ntm_currentid; 54 | echo $ntm_parentid; 55 | echo $ntm_debug; 56 | } 57 | 58 | location /event_timer_test/ { 59 | event_timer_test; 60 | } 61 | 62 | location /event_resolver_test/ { 63 | event_resolver_test; 64 | } 65 | 66 | location /dynamic_resolver_test/ { 67 | dynamic_resolver_test 192.168.84.4 www.test1.com; 68 | } 69 | 70 | location /dynamic_conf_test/ { 71 | dynamic_conf_test; 72 | } 73 | 74 | location / { 75 | http_dynamic_test; 76 | } 77 | 78 | location /map_test/ { 79 | map_test; 80 | } 81 | 82 | location /toolkit_misc_test/ { 83 | toolkit_misc_test; 84 | } 85 | 86 | location /rbuf_test/ { 87 | rbuf_test; 88 | } 89 | 90 | location /poold_test/ { 91 | poold_test; 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /doc/ngx-event-timer-module.md: -------------------------------------------------------------------------------- 1 | # Module ngx-event-timer-module 2 | --- 3 | ## Instructions 4 | 5 | Independent timer for nginx 6 | 7 | ## Directives 8 | 9 | Syntax : worker_timers number; 10 | Default : worker_timers 1024; 11 | Context : events 12 | 13 | Sets the maximum number of timers that can be used in worker process. 14 | 15 | events { 16 | ... 17 | worker_timers 1024; 18 | } 19 | 20 | ## API 21 | 22 | **header file** 23 | 24 | For using this API, You should include the header file as below: 25 | 26 | #include "ngx_event_timer_module.h" 27 | 28 | **registe domain** 29 | 30 | ngx_int_t ngx_event_timer_add_timer(ngx_msec_t tv, 31 | ngx_timer_handler_pt h, void *data); 32 | 33 | - return value: 34 | 35 | return timerid for successd, NGX_ERROR for failed. 36 | 37 | Error: 38 | 39 | - h is NULL 40 | - not enough timer for assigned 41 | 42 | - paras: 43 | 44 | - tv : timer interval to trigger handler 45 | - h : timer handler 46 | - data : data of h para 47 | 48 | Register a timer handler, timer interval is tv, measured by millisecond. When timer triggered, h will be called, using data as function parameters. 49 | 50 | h's protype is: 51 | 52 | typedef void (* ngx_timer_handler_pt)(void *data); 53 | 54 | - return value: 55 | 56 | None 57 | 58 | - paras: 59 | 60 | - data: data set in ngx\_event\_timer\_add\_timer, for paras transmit 61 | 62 | **del timer** 63 | 64 | void ngx_event_timer_del_timer(ngx_uint_t timerid); 65 | 66 | - return value: 67 | 68 | void 69 | 70 | - paras: 71 | 72 | - timerid: return by ngx\_event\_timer\_add\_timer 73 | 74 | Deregister timer handler. 75 | 76 | ## Build 77 | 78 | cd to NGINX source directory & run this: 79 | 80 | ./configure --add-module=/path/to/nginx-toolkit-module/ 81 | make && make install 82 | 83 | ## Example 84 | 85 | See t/ngx\_event\_timer\_test\_module.c as reference 86 | 87 | Build: 88 | 89 | ./configure --add-module=/path/to/nginx-toolkit-module/t/ --add-module=/path/to/nginx-toolkit-module/ 90 | make && make install 91 | 92 | Configure: 93 | 94 | location /event_timer_test/ { 95 | event_timer_test; 96 | } 97 | 98 | Test: 99 | 100 | add timer 101 | 102 | curl -XPOST -v "http://127.0.0.1/event_timer_test/timer?time=3s" 103 | 104 | Test module will start a timer when process init. It will log after 3 seconds, set in args: 105 | 106 | 2016/12/10 18:48:37 [error] 20295#0: event timer test timer handler 107 | 108 | del timer 109 | 110 | curl -XDELETE -v "http://127.0.0.1/event_timer_test/timer?timerid=1" 111 | 112 | Test module will stop a timer whose timerid is 1 113 | -------------------------------------------------------------------------------- /ngx_dynamic_conf.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) AlexWoo(Wu Jie) wj19840501@gmail.com 3 | */ 4 | 5 | 6 | 7 | #ifndef _NGX_DYNAMIC_COMMAND_H_INCLUDED_ 8 | #define _NGX_DYNAMIC_COMMAND_H_INCLUDED_ 9 | 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | 16 | typedef struct { 17 | ngx_str_t name; 18 | void *(*create_conf)(ngx_conf_t *cf); 19 | char *(*init_conf)(ngx_conf_t *cf, void *conf); 20 | } ngx_dynamic_core_module_t; 21 | 22 | 23 | #if (NGX_PCRE) 24 | typedef struct { 25 | ngx_regex_t *regex; 26 | ngx_str_t name; 27 | } ngx_dynamic_regex_t; 28 | #endif 29 | 30 | #if 0 31 | /* 32 | * if use dynamic conf, module define should use 33 | * NGX_MODULE_V1_DYNAMIC_PADDING and set 34 | * module dynamic context and 35 | * module dynamic directives as bellow 36 | */ 37 | ngx_module_t ngx_test_module = { 38 | NGX_MODULE_V1, 39 | &ngx_test_module_ctx, /* module context */ 40 | ngx_test_commands, /* module directives */ 41 | NGX_CORE_MODULE, /* module type */ 42 | NULL, /* init master */ 43 | NULL, /* init module */ 44 | NULL, /* init process */ 45 | NULL, /* init thread */ 46 | NULL, /* exit thread */ 47 | NULL, /* exit process */ 48 | NULL, /* exit master */ 49 | &ngx_test_module_dctx, /* module dynamic context */ 50 | ngx_test_dcommands, /* module dynamic directives */ 51 | NGX_MODULE_V1_DYNAMIC_PADDING 52 | }; 53 | #endif 54 | #define NGX_MODULE_V1_DYNAMIC_PADDING 0, 0, 0, 0, 0, 0 55 | 56 | extern ngx_uint_t ngx_core_max_module; 57 | 58 | /* 59 | * return value: 60 | * return NGX_OK for successd, NGX_ERROR for failed 61 | * paras: 62 | * cf: ngx_conf_t passed from ngx_dynamic_conf_load_conf 63 | * init: only ngx_dynamic_conf_load_conf set 1, otherwise set 0 64 | */ 65 | ngx_int_t ngx_dynamic_conf_parse(ngx_conf_t *cf, unsigned init); 66 | 67 | /* 68 | * return value: 69 | * return regex context 70 | * paras: 71 | * cf: ngx_conf_t passed in dynamic cmd handler 72 | * rc: regex options 73 | */ 74 | #if (NGX_PCRE) 75 | ngx_dynamic_regex_t *ngx_dynamic_regex_compile(ngx_conf_t *cf, 76 | ngx_regex_compile_t *rc); 77 | #endif 78 | 79 | int ngx_dynamic_cmp_dns_wildcards(const void *one, const void *two); 80 | 81 | void *ngx_get_dconf(ngx_module_t *m); 82 | 83 | 84 | #endif 85 | -------------------------------------------------------------------------------- /t/ngx_poold_test_module.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "ngx_poold.h" 5 | 6 | 7 | static char *ngx_poold_test(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); 8 | 9 | 10 | static ngx_command_t ngx_poold_test_commands[] = { 11 | 12 | { ngx_string("poold_test"), 13 | NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS, 14 | ngx_poold_test, 15 | 0, 16 | 0, 17 | NULL }, 18 | 19 | ngx_null_command 20 | }; 21 | 22 | 23 | static ngx_http_module_t ngx_poold_test_module_ctx = { 24 | NULL, /* preconfiguration */ 25 | NULL, /* postconfiguration */ 26 | 27 | NULL, /* create main configuration */ 28 | NULL, /* init main configuration */ 29 | 30 | NULL, /* create server configuration */ 31 | NULL, /* merge server configuration */ 32 | 33 | NULL, /* create location configuration */ 34 | NULL /* merge location configuration */ 35 | }; 36 | 37 | 38 | ngx_module_t ngx_poold_test_module = { 39 | NGX_MODULE_V1, 40 | &ngx_poold_test_module_ctx, /* module context */ 41 | ngx_poold_test_commands, /* module directives */ 42 | NGX_HTTP_MODULE, /* module type */ 43 | NULL, /* init master */ 44 | NULL, /* init module */ 45 | NULL, /* init process */ 46 | NULL, /* init thread */ 47 | NULL, /* exit thread */ 48 | NULL, /* exit process */ 49 | NULL, /* exit master */ 50 | NGX_MODULE_V1_PADDING 51 | }; 52 | 53 | 54 | static ngx_int_t 55 | ngx_poold_test_handler(ngx_http_request_t *r) 56 | { 57 | ngx_chain_t *out; 58 | ngx_pool_t *pool; 59 | 60 | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "poold test handler"); 61 | 62 | pool = NGX_CREATE_POOL(4096, r->connection->log); 63 | 64 | pool = NGX_CREATE_POOL(1024, r->connection->log); 65 | 66 | NGX_DESTROY_POOL(pool); 67 | 68 | NGX_DESTROY_POOL(pool); 69 | 70 | r->headers_out.status = NGX_HTTP_OK; 71 | ngx_http_send_header(r); 72 | 73 | out = ngx_poold_state(r, 1); 74 | out->buf->last_buf = 1; 75 | 76 | return ngx_http_output_filter(r, out); 77 | } 78 | 79 | 80 | static char * 81 | ngx_poold_test(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 82 | { 83 | ngx_http_core_loc_conf_t *clcf; 84 | 85 | clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); 86 | clcf->handler = ngx_poold_test_handler; 87 | 88 | return NGX_CONF_OK; 89 | } 90 | 91 | -------------------------------------------------------------------------------- /doc/ngx-event-resolver-module.md: -------------------------------------------------------------------------------- 1 | # Module ngx-event-resolver-module 2 | --- 3 | ## Instructions 4 | 5 | Common resovler in event modules, just like http resolver, stream resolver in nginx, but can be used by http modules, stream modules and other modules 6 | 7 | ## Directives 8 | 9 | Syntax : resolver address ... [valid=time] [ipv6=on|off]; 10 | Default : - 11 | Context : events 12 | 13 | Configures name servers used to resolve names into addresses, for example: 14 | 15 | > resolver 127.0.0.1 [::1]:5353; 16 | 17 | An address can be specified as a domain name or IP address, and an optional port. If port is not specified, the port 53 is used. Name servers are queried in a round-robin fashion. 18 | 19 | By default, nginx will look up both IPv4 and IPv6 addresses while resolving. If looking up of IPv6 addresses is not desired, the ipv6=off parameter can be specified. 20 | 21 | By default, nginx caches answers using the TTL value of a response. The optional valid parameter allows overriding it: 22 | 23 | > resolver 127.0.0.1 [::1]:5353 valid=30s; 24 | 25 | Syntax : resolver_timeout time; 26 | Default : resolver_timeout 60s; 27 | Context : events 28 | 29 | Sets a timeout for name resolution, for example: 30 | 31 | > resolver\_timeout 5s; 32 | 33 | Example: 34 | 35 | events { 36 | resolver 192.168.84.254 valid=20s; 37 | resolver_timeout 10s; 38 | } 39 | 40 | ## API 41 | 42 | **header file** 43 | 44 | For using this API, You should include the header file as below: 45 | 46 | #include "ngx_event_resolver.h" 47 | 48 | **resolver a domain** 49 | 50 | void ngx_event_resolver_start_resolver(ngx_str_t *domain, 51 | ngx_event_resolver_handler_pt h, void *data); 52 | 53 | - return value: 54 | 55 | None 56 | 57 | - paras: 58 | 59 | - domain: domain for resolving 60 | - h : callback handler 61 | - data : data for callback 62 | 63 | h's protype is: 64 | 65 | typedef void (* ngx_event_resolver_handler_pt)(void *data, 66 | ngx_resolver_addr_t *addrs, ngx_uint_t naddrs); 67 | 68 | - return value: 69 | 70 | None 71 | 72 | - paras: 73 | 74 | - data : user private data set in ngx\_event\_resolver\_start\_resolver 75 | - addrs : addrs resolv by DNS 76 | - naddrs: number of addrs resolv by DNS 77 | 78 | 79 | ## Build 80 | 81 | cd to NGINX source directory & run this: 82 | 83 | ./configure --add-module=/path/to/nginx-toolkit-module/ 84 | make && make install 85 | 86 | ## Example 87 | 88 | See t/ngx\_event\_resolver\_test\_module.c as reference 89 | 90 | Build: 91 | 92 | ./configure --with-debug --add-module=/path/to/nginx-toolkit-module/ --add-module=/path/to/nginx-toolkit-module/t 93 | make && make install 94 | 95 | Configure: 96 | 97 | events { 98 | resolver 192.168.84.254 114.114.114.114 valid=20s; 99 | resolver_timeout 10s; 100 | } 101 | 102 | http { 103 | 104 | ... 105 | 106 | server { 107 | 108 | ... 109 | 110 | location /event_resolver_test/ { 111 | event_resolver_test; 112 | } 113 | } 114 | } 115 | 116 | Install bind server 117 | 118 | /path/to/nginx-toolkit-module/t/dns_install.sh 119 | 120 | modify /var/named/test.com.zone dns ip address to fit your enviroment 121 | 122 | Test: 123 | 124 | - add domain for resolving 125 | 126 | curl -v "http://127.0.0.1/event_resolver_test/domain?domain=www.test.com" 127 | -------------------------------------------------------------------------------- /ngx_map.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) AlexWoo(Wu Jie) wj19840501@gmail.com 3 | */ 4 | 5 | 6 | #ifndef _NGX_MAP_H_INCLUDED_ 7 | #define _NGX_MAP_H_INCLUDED_ 8 | 9 | 10 | #include 11 | #include 12 | 13 | 14 | /* 15 | * key: key for map node 16 | */ 17 | typedef ngx_rbtree_key_t (* ngx_map_hash_pt)(intptr_t key); 18 | 19 | /* 20 | * if key1 < key2, return -1 21 | * if key1 = key2, return 0 22 | * if key1 > key2, return 1 23 | */ 24 | typedef int (* ngx_cmp_pt)(intptr_t key1, intptr_t key2); 25 | 26 | 27 | /* ngx_str_t */ 28 | ngx_rbtree_key_t ngx_map_hash_str(intptr_t key); 29 | int ngx_cmp_str(intptr_t key1, intptr_t key2); 30 | 31 | /* ngx_uint_t */ 32 | ngx_rbtree_key_t ngx_map_hash_uint(intptr_t key); 33 | int ngx_cmp_uint(intptr_t key1, intptr_t key2); 34 | 35 | /* ngx_int_t */ 36 | ngx_rbtree_key_t ngx_map_hash_int(intptr_t key); 37 | int ngx_cmp_int(intptr_t key1, intptr_t key2); 38 | 39 | 40 | typedef struct { 41 | ngx_rbtree_t rbtree; 42 | ngx_rbtree_node_t sentinel; 43 | ngx_map_hash_pt hash; 44 | ngx_cmp_pt cmp; 45 | } ngx_map_t; 46 | 47 | typedef struct { 48 | ngx_rbtree_node_t rn; 49 | intptr_t raw_key; 50 | ngx_map_t *map; 51 | } ngx_map_node_t; 52 | 53 | 54 | /* 55 | * return value: 56 | * None 57 | * paras: 58 | * map : map for initial 59 | * hash: hash func for calc key's hash 60 | * cmp : cmp func for cmp two keys 61 | */ 62 | void ngx_map_init(ngx_map_t *map, ngx_map_hash_pt hash, ngx_cmp_pt cmp); 63 | 64 | /* 65 | * return value: 66 | * if map is empty return 1, else return 0 67 | */ 68 | #define ngx_map_empty(map) (map->rbtree.root == map->rbtree.sentinel) 69 | 70 | /* 71 | * return value: 72 | * the mininum key map node, if map is empty, return NULL 73 | * paras: 74 | * map: map for operate 75 | */ 76 | ngx_map_node_t *ngx_map_begin(ngx_map_t *map); 77 | 78 | /* 79 | * return value: 80 | * the maximum key map node, if map is empty, return NULL 81 | * paras: 82 | * map: map for operate 83 | */ 84 | ngx_map_node_t *ngx_map_rbegin(ngx_map_t *map); 85 | 86 | /* 87 | * return value: 88 | * the next bigger key map node, if none, return NULL 89 | * paras: 90 | * n : current node 91 | */ 92 | ngx_map_node_t *ngx_map_next(ngx_map_node_t *n); 93 | 94 | /* 95 | * return value: 96 | * the next smaller key map node, if none, return NULL 97 | * paras: 98 | * n : current node 99 | */ 100 | ngx_map_node_t *ngx_map_prev(ngx_map_node_t *n); 101 | 102 | /* 103 | * return value: 104 | * None 105 | * paras: 106 | * map : map for operate 107 | * node : map node for inserting into map 108 | * covered: 1 for covered if key is same, 0 do nothing if key is same 109 | */ 110 | void ngx_map_insert(ngx_map_t *map, ngx_map_node_t *node, ngx_flag_t covered); 111 | 112 | /* 113 | * return value: 114 | * None 115 | * paras: 116 | * map: map for operate 117 | * key: map node key for deleting from map 118 | */ 119 | void ngx_map_delete(ngx_map_t *map, intptr_t key); 120 | 121 | /* 122 | * return value: 123 | * node in map searching by key, NULL for not found 124 | * paras: 125 | * map: map for operate 126 | * key: node key for searching 127 | */ 128 | ngx_map_node_t *ngx_map_find(ngx_map_t *map, intptr_t key); 129 | 130 | 131 | #endif 132 | -------------------------------------------------------------------------------- /doc/ngx-map.md: -------------------------------------------------------------------------------- 1 | # ngx-map 2 | --- 3 | ## Instructions 4 | 5 | A map implement use ngx_rbtree 6 | 7 | ## API 8 | 9 | **header file** 10 | 11 | For using this API, You should include the header file as below: 12 | 13 | #include "ngx_map.h" 14 | 15 | **structure** 16 | 17 | typedef struct { 18 | ngx_rbtree_t rbtree; 19 | ngx_rbtree_node_t sentinel; 20 | ngx_map_hash_pt hash; 21 | ngx_cmp_pt cmp; 22 | } ngx_map_t; 23 | 24 | typedef struct { 25 | ngx_rbtree_node_t rn; 26 | intptr_t raw_key; 27 | ngx_map_t *map; 28 | } ngx_map_node_t; 29 | 30 | use ngx\_map\_t instance as a map, use ngx\_map\_init to initial. Put ngx\_map\_node\_t in your structure, and set raw_key, then you can insert your node in the map. Use raw_key, you can find node in map, or delete node in map. 31 | 32 | **ngx\_map\_init** 33 | 34 | void ngx_map_init(ngx_map_t *map, ngx_map_hash_pt hash, ngx_cmp_pt cmp) 35 | 36 | Interface for init a map, hash is hash func handler to calculate hashkey for rawkey, cmp is compare func handler for compare two raw_key, when raw_keys' hashkey is same. 37 | 38 | We support base hash and cmp func as below: 39 | 40 | /* ngx_str_t */ 41 | ngx_rbtree_key_t ngx_map_hash_str(intptr_t key) 42 | int ngx_cmp_str(intptr_t key1, intptr_t key2) 43 | 44 | /* ngx_uint_t */ 45 | ngx_rbtree_key_t ngx_map_hash_uint(intptr_t key) 46 | int ngx_cmp_uint(intptr_t key1, intptr_t key2) 47 | 48 | /* ngx_int_t */ 49 | ngx_rbtree_key_t ngx_map_hash_int(intptr_t key) 50 | int ngx_cmp_int(intptr_t key1, intptr_t key2) 51 | 52 | User also can use own hash and cmp func with protype below: 53 | 54 | /* 55 | * key: key for map node 56 | */ 57 | typedef ngx_rbtree_key_t (* ngx_map_hash_pt)(intptr_t key); 58 | 59 | /* 60 | * if key1 < key2, return -1 61 | * if key1 = key2, return 0 62 | * if key1 > key2, return 1 63 | */ 64 | typedef int (* ngx_cmp_pt)(intptr_t key1, intptr_t key2); 65 | 66 | **ngx\_map\_empty** 67 | 68 | #define ngx_map_empty(map) (map->rbtree.root == map->rbtree.sentinel) 69 | 70 | If map is empty, return 1, else, return false 71 | 72 | **ngx\_map\_begin** 73 | 74 | ngx_map_node_t *ngx_map_begin(ngx_map_t *map) 75 | 76 | Return the mininum key node of map 77 | 78 | **ngx\_map\_rbegin** 79 | 80 | ngx_map_node_t *ngx_map_rbegin(ngx_map_t *map) 81 | 82 | Return the maxinum key node of map 83 | 84 | **ngx\_map\_next** 85 | 86 | ngx_map_node_t *ngx_map_next(ngx_map_node_t *n) 87 | 88 | Return the next node of n, if n is the maximum key node in map, return NULL 89 | 90 | **ngx\_map\_prev** 91 | 92 | ngx_map_node_t *ngx_map_prev(ngx_map_node_t *n) 93 | 94 | Return the previous node of n, if n is the mininum key node in map, return NULL 95 | 96 | **ngx\_map\_insert** 97 | 98 | void ngx_map_insert(ngx_map_t *map, ngx_map_node_t *node, ngx_flag_t covered) 99 | 100 | Interface for insert a node in map. New node will force replace old node in map if raw_key is same when covered set to 1. Otherwise, new node can't insert in map 101 | 102 | **ngx\_map\_delete** 103 | 104 | void ngx_map_delete(ngx_map_t *map, intptr_t key) 105 | 106 | Interface for delete a node in map, if node's raw_key equal to key in paras. If node is not exist, do nothing. 107 | 108 | **ngx\_map\_find** 109 | 110 | ngx_map_node_t *ngx_map_find(ngx_map_t *map, intptr_t key) 111 | 112 | Interface for find a node in map, if node's raw_key equal to key in paras. If node is not exist, return NULL. -------------------------------------------------------------------------------- /doc/ngx-dynamic-resolver-module.md: -------------------------------------------------------------------------------- 1 | # Module ngx-dynamic-resolver-module 2 | --- 3 | ## Instructions 4 | 5 | System will resolver domain in dynamic resolver every few seconds configured. 6 | 7 | The module will return addr whose domain is resolved in dynamic resolver, otherwise, the module will add domain into dynamic resolver, resolv domain by event resolver, and call callback when resolved. 8 | 9 | ## Directives 10 | 11 | Syntax : dynamic_refresh_interval time; 12 | Default : dynamic_refresh_interval 5m; 13 | Context : events 14 | 15 | Set time interval for DNS query frequency, 0 for shutdown this function. 16 | 17 | Syntax : dynamic_domain_buckets number; 18 | Default : dynamic_domain_buckets 101; 19 | Context : events 20 | 21 | Bucket for dynamic resolver domain hash table. Use prime key is Recommended. 22 | 23 | Example: 24 | 25 | events { 26 | resolver 192.168.84.254 valid=1m; 27 | dynamic_refresh_interval 5m; 28 | dynamic_domain_buckets 1001; 29 | } 30 | 31 | ## API 32 | 33 | **header file** 34 | 35 | For using this API, You should include the header file as below: 36 | 37 | #include "ngx_dynamic_resolver.h" 38 | 39 | **start resolver** 40 | 41 | void ngx_dynamic_resolver_start_resolver(ngx_str_t *domain, 42 | ngx_dynamic_resolver_handler_pt h, void *data); 43 | 44 | - return value: 45 | 46 | - None 47 | 48 | - paras: 49 | 50 | - domain: domain for DNS query 51 | - h : callback handler 52 | - data : data for callback 53 | 54 | h's protype is: 55 | 56 | typedef void (* ngx_dynamic_resolver_handler_pt)(void *data, 57 | struct sockaddr *sa, socklen_t socklen); 58 | 59 | - return value: 60 | 61 | - None 62 | 63 | - paras: 64 | 65 | - data : user private data set in ngx\_dynamic\_resolver\_start\_resolver 66 | - sa : sock address get 67 | - socklen: sock address len, 0 for get none address 68 | 69 | **gethostbyname** 70 | 71 | socklen_t ngx_dynamic_resolver_gethostbyname(ngx_str_t *domain, struct sockaddr *sa); 72 | 73 | - return value: 74 | 75 | - socklen for successd 76 | - 0 for failed 77 | 78 | - paras: 79 | 80 | - domain: domain for query 81 | - sa : sock address get 82 | 83 | **add domain** 84 | 85 | void ngx_dynamic_resolver_add_domain(ngx_str_t *domain); 86 | 87 | - return value: 88 | 89 | - None 90 | 91 | - paras: 92 | 93 | - domain: domain for query 94 | 95 | 96 | **del domain** 97 | 98 | void ngx_dynamic_resolver_del_domain(ngx_str_t *domain); 99 | 100 | - return value: 101 | 102 | - None 103 | 104 | - paras: 105 | 106 | - domain: domain for DNS query 107 | 108 | ## Build 109 | 110 | cd to NGINX source directory & run this: 111 | 112 | ./configure --add-module=/path/to/nginx-toolkit-module/ 113 | make && make install 114 | 115 | ## Example 116 | 117 | See t/ngx\_dynamic\_resolver\_test\_module.c as reference 118 | 119 | Build: 120 | 121 | ./configure --with-debug --add-module=/path/to/nginx-toolkit-module/ --add-module=/path/to/nginx-toolkit-module/t 122 | make && make install 123 | 124 | Configure: 125 | 126 | events { 127 | resolver 192.168.84.254 valid=1m; 128 | dynamic_refresh_interval 5m; 129 | } 130 | 131 | http { 132 | 133 | ... 134 | 135 | server { 136 | 137 | ... 138 | 139 | location /dynamic_resolver_test/ { 140 | dynamic_resolver_test 192.168.84.4 www.test1.com; 141 | } 142 | } 143 | } 144 | 145 | Test: 146 | 147 | - sync resolver 148 | 149 | curl -v 'http://127.0.0.1/dynamic_resolver_test/resolver?domain=www.test1.com&sync=1' 150 | 151 | - start resolver 152 | 153 | curl -v 'http://127.0.0.1/dynamic_resolver_test/resolver?domain=www.test.com' 154 | 155 | - del domain 156 | 157 | curl -XDELETE -v 'http://127.0.0.1/dynamic_resolver_test/resolver?domain=www.test.com' 158 | -------------------------------------------------------------------------------- /t/ngx_rbuf_test_module.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "../ngx_rbuf.h" 5 | 6 | 7 | static char *ngx_rbuf_test(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); 8 | 9 | 10 | static ngx_command_t ngx_rbuf_test_commands[] = { 11 | 12 | { ngx_string("rbuf_test"), 13 | NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS, 14 | ngx_rbuf_test, 15 | 0, 16 | 0, 17 | NULL }, 18 | 19 | ngx_null_command 20 | }; 21 | 22 | 23 | static ngx_http_module_t ngx_rbuf_test_module_ctx = { 24 | NULL, /* preconfiguration */ 25 | NULL, /* postconfiguration */ 26 | 27 | NULL, /* create main configuration */ 28 | NULL, /* init main configuration */ 29 | 30 | NULL, /* create server configuration */ 31 | NULL, /* merge server configuration */ 32 | 33 | NULL, /* create location configuration */ 34 | NULL /* merge location configuration */ 35 | }; 36 | 37 | 38 | ngx_module_t ngx_rbuf_test_module = { 39 | NGX_MODULE_V1, 40 | &ngx_rbuf_test_module_ctx, /* module context */ 41 | ngx_rbuf_test_commands, /* module directives */ 42 | NGX_HTTP_MODULE, /* module type */ 43 | NULL, /* init master */ 44 | NULL, /* init module */ 45 | NULL, /* init process */ 46 | NULL, /* init thread */ 47 | NULL, /* exit thread */ 48 | NULL, /* exit process */ 49 | NULL, /* exit master */ 50 | NGX_MODULE_V1_PADDING 51 | }; 52 | 53 | 54 | static ngx_int_t 55 | ngx_rbuf_test_handler(ngx_http_request_t *r) 56 | { 57 | ngx_str_t size; 58 | ngx_int_t key; 59 | ngx_chain_t *cl, *cl1, *cl2; 60 | ngx_chain_t *out; 61 | 62 | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "rbuf test handler"); 63 | 64 | if (ngx_http_arg(r, (u_char *) "size", sizeof("size") - 1, &size) 65 | != NGX_OK) 66 | { 67 | return NGX_HTTP_BAD_REQUEST; 68 | } 69 | 70 | key = ngx_atoi(size.data, size.len); 71 | cl = ngx_get_chainbuf(key, 1); 72 | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "cl: %p", cl); 73 | 74 | cl1 = ngx_get_chainbuf(key, 0); 75 | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "cl1: %p", cl1); 76 | cl1->buf->start = cl->buf->start; 77 | cl1->buf->end = cl->buf->end; 78 | cl1->buf->pos = cl->buf->pos; 79 | cl1->buf->last = cl->buf->last; 80 | 81 | cl2 = ngx_get_chainbuf(key, 0); 82 | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "cl2: %p", cl2); 83 | cl2->buf->start = cl->buf->start; 84 | cl2->buf->end = cl->buf->end; 85 | cl2->buf->pos = cl->buf->pos; 86 | cl2->buf->last = cl->buf->last; 87 | 88 | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "rbuf free"); 89 | 90 | ngx_put_chainbuf(cl2); 91 | 92 | ngx_put_chainbuf(cl); 93 | 94 | ngx_put_chainbuf(cl1); 95 | 96 | r->headers_out.status = NGX_HTTP_OK; 97 | ngx_http_send_header(r); 98 | 99 | out = ngx_rbuf_state(r, 1); 100 | out->buf->last_buf = 1; 101 | 102 | return ngx_http_output_filter(r, out); 103 | } 104 | 105 | 106 | static char * 107 | ngx_rbuf_test(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 108 | { 109 | ngx_http_core_loc_conf_t *clcf; 110 | 111 | clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); 112 | clcf->handler = ngx_rbuf_test_handler; 113 | 114 | return NGX_CONF_OK; 115 | } 116 | 117 | -------------------------------------------------------------------------------- /ngx_toolkit_misc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) AlexWoo(Wu Jie) wj19840501@gmail.com 3 | */ 4 | 5 | 6 | #ifndef _NGX_TOOLKIT_MISC_H_INCLUDED_ 7 | #define _NGX_TOOLKIT_MISC_H_INCLUDED_ 8 | 9 | 10 | #include 11 | #include 12 | 13 | 14 | /* 15 | * scheme://[user@]host[:port]/path[?args][#fragment] 16 | */ 17 | typedef struct { 18 | ngx_str_t scheme; 19 | ngx_str_t user; 20 | ngx_str_t host; 21 | ngx_str_t port; 22 | ngx_str_t path; 23 | ngx_str_t args; 24 | ngx_str_t fragment; 25 | 26 | ngx_str_t host_with_port; /* host[:port] */ 27 | ngx_str_t uri_with_args; /* /path[?args][#fragment] */ 28 | } ngx_request_url_t; 29 | 30 | 31 | #define NGX_MD5KEY_LEN 32 32 | 33 | 34 | /* 35 | * gen 32 random string 36 | * 37 | * return value: 38 | * None 39 | * paras: 40 | * id: u_char[32] to get random id 41 | */ 42 | void ngx_random32(u_char *id); 43 | 44 | 45 | /* 46 | * parse request url format as: 47 | * scheme://[user@]host[:port]/path[?args][#fragment] 48 | * 49 | * return value: 50 | * NGX_OK : parse success 51 | * NGX_ERROR: request url format error 52 | * paras: 53 | * request_url: url parse result return to user, 54 | * all paras in request url is segment point to url 55 | * url : request url for parse 56 | */ 57 | ngx_int_t ngx_parse_request_url(ngx_request_url_t *request_url, ngx_str_t *url); 58 | 59 | /* 60 | * convert port to in_port_t according to scheme and port 61 | * 62 | * return value: 63 | * If port is set to correct number range in [1, 65535], return port 64 | * If port is set to non correct value, return 0 65 | * If port is not set, return default value for scheme: 66 | * 80 for http 67 | * 443 for https 68 | * 1935 for rtmp 69 | * 0 for others now 70 | * values: 71 | * scheme : sheme string like http https or rtmp 72 | * port : port for convert to in_port_t 73 | */ 74 | in_port_t ngx_request_port(ngx_str_t *scheme, ngx_str_t *port); 75 | 76 | /* 77 | * calculating file md5key as md5sum in shell 78 | * 79 | * return value: 80 | * NGX_OK : calculating success 81 | * NGX_ERROR: calculating error such as file is not exist 82 | * paras: 83 | * fd : file desc for calculating md5key 84 | * md5key: md5key result 85 | */ 86 | ngx_int_t ngx_md5_file(ngx_fd_t fd, u_char md5key[NGX_MD5KEY_LEN]); 87 | 88 | 89 | /* 90 | * copy str 91 | * 92 | * return value: 93 | * NGX_OK: copy successd 94 | * NGX_ERROR: copy failed 95 | * paras: 96 | * pool: for alloc space for storing str 97 | * dst: str copy to 98 | * src: str copy from 99 | */ 100 | ngx_int_t ngx_copy_str(ngx_pool_t *pool, ngx_str_t *dst, ngx_str_t *src); 101 | 102 | 103 | /* 104 | * parse text to struct sockaddr 105 | * 106 | * return value: 107 | * 0: if text is not ipv4/ipv6/unix address 108 | * >0: socklen for sa 109 | * 110 | * paras: 111 | * sa: struct sockadd parse to 112 | * text: ipv4/ipv6/unix address for parsing, text could have port 113 | * len: text's length 114 | */ 115 | socklen_t ngx_sock_pton(struct sockaddr *sa, u_char *text, size_t len); 116 | 117 | 118 | #ifdef NGX_DEBUG 119 | 120 | #define NGX_START_TIMING \ 121 | struct timeval __start, __end; \ 122 | ngx_gettimeofday(&__start); 123 | 124 | #define NGX_STOP_TIMING(log, msg) \ 125 | ngx_gettimeofday(&__end); \ 126 | ngx_log_error(NGX_LOG_INFO, log, 0, msg " spend %ui us", \ 127 | (__end.tv_sec - __start.tv_sec) * 1000000 \ 128 | + (__end.tv_usec - __start.tv_usec)); 129 | 130 | #else 131 | 132 | #define NGX_START_TIMING 133 | #define NGX_STOP_TIMING(log, msg) 134 | 135 | #endif 136 | 137 | #endif 138 | -------------------------------------------------------------------------------- /t/ngx_event_resolver_test_module.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "ngx_event_resolver.h" 5 | 6 | 7 | static char *ngx_event_resolver_test(ngx_conf_t *cf, ngx_command_t *cmd, 8 | void *conf); 9 | 10 | 11 | static ngx_command_t ngx_event_resolver_test_commands[] = { 12 | 13 | { ngx_string("event_resolver_test"), 14 | NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS, 15 | ngx_event_resolver_test, 16 | 0, 17 | 0, 18 | NULL }, 19 | 20 | ngx_null_command 21 | }; 22 | 23 | 24 | static ngx_http_module_t ngx_event_resolver_test_module_ctx = { 25 | NULL, /* preconfiguration */ 26 | NULL, /* postconfiguration */ 27 | 28 | NULL, /* create main configuration */ 29 | NULL, /* init main configuration */ 30 | 31 | NULL, /* create server configuration */ 32 | NULL, /* merge server configuration */ 33 | 34 | NULL, /* create location configuration */ 35 | NULL /* merge location configuration */ 36 | }; 37 | 38 | 39 | ngx_module_t ngx_event_resolver_test_module = { 40 | NGX_MODULE_V1, 41 | &ngx_event_resolver_test_module_ctx, /* module context */ 42 | ngx_event_resolver_test_commands, /* module directives */ 43 | NGX_HTTP_MODULE, /* module type */ 44 | NULL, /* init master */ 45 | NULL, /* init module */ 46 | NULL, /* init process */ 47 | NULL, /* init thread */ 48 | NULL, /* exit thread */ 49 | NULL, /* exit process */ 50 | NULL, /* exit master */ 51 | NGX_MODULE_V1_PADDING 52 | }; 53 | 54 | 55 | static void 56 | ngx_event_resolver_test_result(void *data, ngx_resolver_addr_t *addrs, 57 | ngx_uint_t naddrs) 58 | { 59 | ngx_chain_t *cl, **ll; 60 | ngx_buf_t *b; 61 | size_t len; 62 | ngx_int_t rc; 63 | ngx_uint_t i; 64 | ngx_http_request_t *r; 65 | u_char text[NGX_SOCKADDRLEN]; 66 | 67 | r = data; 68 | 69 | r->headers_out.status = NGX_HTTP_OK; 70 | 71 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "send header"); 72 | 73 | if (naddrs == 0) { 74 | r->headers_out.content_length_n = 0; 75 | r->header_only = 1; 76 | } 77 | 78 | rc = ngx_http_send_header(r); 79 | if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { 80 | ngx_http_finalize_request(r, rc); 81 | return; 82 | } 83 | 84 | ll = &cl; 85 | for (i = 0; i < naddrs; ++i) { 86 | len = ngx_sock_ntop(addrs[i].sockaddr, addrs[i].socklen, text, 87 | NGX_SOCKADDRLEN, 0) + 1; 88 | 89 | b = ngx_create_temp_buf(r->pool, len); 90 | 91 | if (b == NULL) { 92 | ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); 93 | return; 94 | } 95 | 96 | b->last = ngx_snprintf(b->last, len, "%s\n", text); 97 | if (i == naddrs - 1) { 98 | b->last_buf = 1; 99 | b->last_in_chain = 1; 100 | } 101 | 102 | *ll = ngx_alloc_chain_link(r->pool); 103 | (*ll)->buf = b; 104 | (*ll)->next = NULL; 105 | ll = &(*ll)->next; 106 | } 107 | 108 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "send body"); 109 | 110 | ngx_http_output_filter(r, cl); 111 | 112 | ngx_http_finalize_request(r, NGX_OK); 113 | } 114 | 115 | static ngx_int_t 116 | ngx_event_resolver_test_handler(ngx_http_request_t *r) 117 | { 118 | ngx_str_t domain; 119 | 120 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 121 | "event resolver test handler"); 122 | 123 | if (ngx_http_arg(r, (u_char *) "domain", sizeof("domain") - 1, &domain) 124 | != NGX_OK) 125 | { 126 | return NGX_HTTP_BAD_REQUEST; 127 | } 128 | 129 | ++r->count; 130 | 131 | ngx_event_resolver_start_resolver(&domain, 132 | ngx_event_resolver_test_result, r); 133 | 134 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 135 | "after start resolver"); 136 | 137 | return NGX_DONE; 138 | } 139 | 140 | 141 | static char * 142 | ngx_event_resolver_test(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 143 | { 144 | ngx_http_core_loc_conf_t *clcf; 145 | 146 | clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); 147 | clcf->handler = ngx_event_resolver_test_handler; 148 | 149 | return NGX_CONF_OK; 150 | } 151 | -------------------------------------------------------------------------------- /t/ngx_event_timer_test_module.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "ngx_event_timer_module.h" 5 | 6 | 7 | static char *ngx_event_timer_test(ngx_conf_t *cf, ngx_command_t *cmd, 8 | void *conf); 9 | 10 | static ngx_command_t ngx_event_timer_test_commands[] = { 11 | 12 | { ngx_string("event_timer_test"), 13 | NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS, 14 | ngx_event_timer_test, 15 | 0, 16 | 0, 17 | NULL }, 18 | 19 | ngx_null_command 20 | }; 21 | 22 | 23 | static ngx_http_module_t ngx_event_timer_test_module_ctx = { 24 | NULL, /* preconfiguration */ 25 | NULL, /* postconfiguration */ 26 | 27 | NULL, /* create main configuration */ 28 | NULL, /* init main configuration */ 29 | 30 | NULL, /* create server configuration */ 31 | NULL, /* merge server configuration */ 32 | 33 | NULL, /* create location configuration */ 34 | NULL /* merge location configuration */ 35 | }; 36 | 37 | 38 | ngx_module_t ngx_event_timer_test_module = { 39 | NGX_MODULE_V1, 40 | &ngx_event_timer_test_module_ctx, /* module context */ 41 | ngx_event_timer_test_commands, /* module directives */ 42 | NGX_HTTP_MODULE, /* module type */ 43 | NULL, /* init master */ 44 | NULL, /* init module */ 45 | NULL, /* init process */ 46 | NULL, /* init thread */ 47 | NULL, /* exit thread */ 48 | NULL, /* exit process */ 49 | NULL, /* exit master */ 50 | NGX_MODULE_V1_PADDING 51 | }; 52 | 53 | 54 | static void 55 | ngx_event_timer_test_timer_handler(void *data) 56 | { 57 | ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, 58 | "event timer test timer handler"); 59 | } 60 | 61 | static ngx_int_t 62 | ngx_event_timer_test_handler(ngx_http_request_t *r) 63 | { 64 | ngx_chain_t cl; 65 | ngx_buf_t *b; 66 | size_t len; 67 | ngx_int_t rc, timerid; 68 | ngx_msec_t time; 69 | ngx_str_t arg; 70 | 71 | ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, 72 | "event timer test handler"); 73 | 74 | if (r->method == NGX_HTTP_DELETE) { 75 | len = sizeof("delete timer timerid=NGX_OFF_T_LEN\n") - 1; 76 | 77 | if (ngx_http_arg(r, (u_char *) "timerid", 7, &arg) != NGX_OK) { 78 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 79 | "event timer test, no timerid in http args"); 80 | return NGX_HTTP_BAD_REQUEST; 81 | } 82 | 83 | timerid = ngx_atoi(arg.data, arg.len); 84 | if (timerid == NGX_ERROR) { 85 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 86 | "event timer test, timerid arg not int type"); 87 | return NGX_HTTP_BAD_REQUEST; 88 | } 89 | 90 | ngx_event_timer_del_timer(timerid); 91 | } else if (r->method == NGX_HTTP_POST) { 92 | len = sizeof("add timer timerid=NGX_OFF_T_LEN\n") - 1; 93 | 94 | if (ngx_http_arg(r, (u_char *) "time", 4, &arg) != NGX_OK) { 95 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 96 | "event timer test, no time in http args"); 97 | return NGX_HTTP_BAD_REQUEST; 98 | } 99 | 100 | time = ngx_parse_time(&arg, 0); 101 | if (time == (ngx_msec_t) NGX_ERROR) { 102 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 103 | "event timer test, time arg not time type"); 104 | return NGX_HTTP_BAD_REQUEST; 105 | } 106 | 107 | timerid = ngx_event_timer_add_timer(time, 108 | ngx_event_timer_test_timer_handler, NULL); 109 | } else { 110 | return NGX_HTTP_BAD_REQUEST; 111 | } 112 | 113 | r->headers_out.status = NGX_HTTP_OK; 114 | 115 | rc = ngx_http_send_header(r); 116 | if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { 117 | return rc; 118 | } 119 | 120 | b = ngx_create_temp_buf(r->pool, len); 121 | 122 | if (b == NULL) { 123 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 124 | } 125 | 126 | if (r->method == NGX_HTTP_DELETE) { 127 | b->last = ngx_snprintf(b->last, len, 128 | "delete timer timerid=%i\n", timerid); 129 | } else { 130 | b->last = ngx_snprintf(b->last, len, 131 | "add timer timerid=%i\n", timerid); 132 | } 133 | b->last_buf = 1; 134 | b->last_in_chain = 1; 135 | 136 | cl.buf = b; 137 | cl.next = NULL; 138 | 139 | return ngx_http_output_filter(r, &cl); 140 | } 141 | 142 | static char * 143 | ngx_event_timer_test(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 144 | { 145 | ngx_http_core_loc_conf_t *clcf; 146 | 147 | clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); 148 | clcf->handler = ngx_event_timer_test_handler; 149 | 150 | return NGX_CONF_OK; 151 | } 152 | -------------------------------------------------------------------------------- /ngx_poold.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) AlexWoo(Wu Jie) wj19840501@gmail.com 3 | */ 4 | 5 | 6 | #include "ngx_poold.h" 7 | #include "ngx_map.h" 8 | 9 | 10 | typedef struct ngx_poold_node_s ngx_poold_node_t; 11 | 12 | static ngx_pool_t *ngx_poold_pool; 13 | 14 | static ngx_map_t ngx_poold_map; 15 | static ngx_poold_node_t *ngx_poold_free_node; 16 | 17 | static ngx_uint_t ngx_poold_nalloc; 18 | static ngx_uint_t ngx_poold_nfree; 19 | 20 | 21 | struct ngx_poold_node_s { 22 | ngx_map_node_t m; /* map node */ 23 | ngx_poold_node_t *next; /* free node */ 24 | 25 | ngx_pool_t *pool; 26 | char *file; /* file create pool */ 27 | int line; /* line create pool */ 28 | }; 29 | 30 | 31 | static ngx_int_t 32 | ngx_poold_init() 33 | { 34 | ngx_poold_pool = ngx_create_pool(4096, ngx_cycle->log); 35 | if (ngx_poold_pool == NULL) { 36 | return NGX_ERROR; 37 | } 38 | 39 | ngx_map_init(&ngx_poold_map, ngx_map_hash_uint, ngx_cmp_uint); 40 | ngx_poold_free_node = NULL; 41 | 42 | ngx_poold_nalloc = 0; 43 | ngx_poold_nfree = 0; 44 | 45 | return NGX_OK; 46 | } 47 | 48 | 49 | static ngx_poold_node_t * 50 | ngx_poold_get_node() 51 | { 52 | ngx_poold_node_t *n; 53 | 54 | n = ngx_poold_free_node; 55 | if (n == NULL) { 56 | n = ngx_pcalloc(ngx_poold_pool, sizeof(ngx_poold_node_t)); 57 | if (n == NULL) { 58 | return NULL; 59 | } 60 | 61 | ++ngx_poold_nalloc; 62 | } else { 63 | ngx_poold_free_node = n->next; 64 | ngx_memzero(n, sizeof(ngx_poold_node_t)); 65 | 66 | --ngx_poold_nfree; 67 | } 68 | 69 | return n; 70 | } 71 | 72 | 73 | static void 74 | ngx_poold_put_node(ngx_poold_node_t *node) 75 | { 76 | if (ngx_poold_pool == NULL) { 77 | return; 78 | } 79 | 80 | if (node == NULL) { 81 | return; 82 | } 83 | 84 | node->next = ngx_poold_free_node; 85 | ngx_poold_free_node = node; 86 | 87 | ++ngx_poold_nfree; 88 | } 89 | 90 | 91 | ngx_pool_t * 92 | ngx_create_pool_debug(size_t size, ngx_log_t *log, char *file, int line) 93 | { 94 | ngx_poold_node_t *node; 95 | 96 | if (ngx_poold_pool == NULL) { 97 | ngx_poold_init(); 98 | } 99 | 100 | /* construct a poold node */ 101 | node = ngx_poold_get_node(); 102 | node->pool = ngx_create_pool(size, log); 103 | node->file = file; 104 | node->line = line; 105 | 106 | /* record node in poold map */ 107 | node->m.raw_key = (intptr_t) node->pool; 108 | ngx_map_insert(&ngx_poold_map, &node->m, 0); 109 | 110 | return node->pool; 111 | } 112 | 113 | 114 | void 115 | ngx_destroy_pool_debug(ngx_pool_t *pool, char *file, int line) 116 | { 117 | ngx_poold_node_t *node; 118 | ngx_map_node_t *m; 119 | 120 | /* get node by pool */ 121 | m = ngx_map_find(&ngx_poold_map, (intptr_t) pool); 122 | if (m == NULL) { 123 | ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, 0, 124 | "destroy pool twice: %s:%d", file, line); 125 | return; 126 | } 127 | ngx_map_delete(&ngx_poold_map, (intptr_t) pool); 128 | node = (ngx_poold_node_t *) ((char *) m - offsetof(ngx_poold_node_t, m)); 129 | 130 | ngx_destroy_pool(pool); 131 | 132 | /* put node in poold map */ 133 | ngx_poold_put_node(node); 134 | } 135 | 136 | 137 | ngx_chain_t * 138 | ngx_poold_state(ngx_http_request_t *r, unsigned detail) 139 | { 140 | ngx_chain_t *cl; 141 | ngx_buf_t *b; 142 | size_t len; 143 | #if (NGX_DEBUG) 144 | ngx_map_node_t *node; 145 | ngx_poold_node_t *pn; 146 | size_t len1; 147 | ngx_uint_t n; 148 | #endif 149 | 150 | len = sizeof("##########ngx debug pool##########\n") - 1 151 | + sizeof("ngx_poold nalloc node: \n") - 1 + NGX_OFF_T_LEN 152 | + sizeof("ngx_poold nfree node: \n") - 1 + NGX_OFF_T_LEN; 153 | 154 | #if (NGX_DEBUG) 155 | 156 | /* node for create pool */ 157 | if (detail) { 158 | n = ngx_poold_nalloc - ngx_poold_nfree; 159 | /* " file:line\n" */ 160 | len1 = 4 + 256 + 1 + NGX_OFF_T_LEN + 1; 161 | len += len1 * n; 162 | } 163 | 164 | #endif 165 | 166 | cl = ngx_alloc_chain_link(r->pool); 167 | if (cl == NULL) { 168 | return NULL; 169 | } 170 | cl->next = NULL; 171 | 172 | b = ngx_create_temp_buf(r->pool, len); 173 | if (b == NULL) { 174 | return NULL; 175 | } 176 | cl->buf = b; 177 | 178 | b->last = ngx_snprintf(b->last, len, 179 | "##########ngx debug pool##########\n" 180 | "ngx_poold nalloc node: %ui\nngx_poold nfree node: %ui\n", 181 | ngx_poold_nalloc, ngx_poold_nfree); 182 | 183 | #if (NGX_DEBUG) 184 | 185 | if (detail) { 186 | for (node = ngx_map_begin(&ngx_poold_map); node; 187 | node = ngx_map_next(node)) 188 | { 189 | /* m is first element of ngx_poold_node_t */ 190 | pn = (ngx_poold_node_t *) node; 191 | b->last = ngx_snprintf(b->last, len1, " %s:%d\n", 192 | pn->file, pn->line); 193 | } 194 | } 195 | 196 | #endif 197 | 198 | return cl; 199 | } 200 | -------------------------------------------------------------------------------- /ngx_rbuf.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) AlexWoo(Wu Jie) wj19840501@gmail.com 3 | */ 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | #include "ngx_map.h" 10 | 11 | 12 | static ngx_pool_t *ngx_rbuf_pool; 13 | 14 | static ngx_map_t ngx_rbuf_map; 15 | static ngx_uint_t ngx_rbuf_nalloc_node; 16 | 17 | static ngx_uint_t ngx_rbuf_nalloc_chain; 18 | static ngx_uint_t ngx_rbuf_nfree_chain; 19 | 20 | static ngx_map_t ngx_rbuf_using; 21 | 22 | 23 | typedef struct { 24 | ngx_map_node_t node; 25 | ngx_chain_t *free; 26 | } ngx_chainbuf_node_t; 27 | 28 | typedef struct { 29 | ngx_chain_t cl; 30 | ngx_buf_t buf; 31 | 32 | #if (NGX_DEBUG) 33 | 34 | ngx_map_node_t node; 35 | char *file; 36 | int line; 37 | 38 | #endif 39 | 40 | size_t size; 41 | u_char alloc[]; 42 | } ngx_chainbuf_t; 43 | 44 | 45 | static ngx_int_t 46 | ngx_rbuf_init() 47 | { 48 | ngx_rbuf_pool = ngx_create_pool(4096, ngx_cycle->log); 49 | if (ngx_rbuf_pool == NULL) { 50 | return NGX_ERROR; 51 | } 52 | 53 | ngx_map_init(&ngx_rbuf_map, ngx_map_hash_uint, ngx_cmp_uint); 54 | ngx_rbuf_nalloc_node = 0; 55 | 56 | ngx_rbuf_nalloc_chain = 0; 57 | ngx_rbuf_nfree_chain = 0; 58 | 59 | ngx_map_init(&ngx_rbuf_using, ngx_map_hash_uint, ngx_cmp_uint); 60 | 61 | return NGX_OK; 62 | } 63 | 64 | 65 | ngx_chain_t * 66 | ngx_get_chainbuf_debug(size_t size, ngx_flag_t alloc_rbuf, char *file, int line) 67 | { 68 | ngx_chainbuf_node_t *cn; 69 | ngx_map_node_t *node; 70 | ngx_chainbuf_t *cb; 71 | ngx_chain_t *cl; 72 | 73 | if (ngx_rbuf_pool == NULL) { 74 | ngx_rbuf_init(); 75 | } 76 | 77 | node = ngx_map_find(&ngx_rbuf_map, size); 78 | if (node == NULL) { /* new size */ 79 | cn = ngx_pcalloc(ngx_rbuf_pool, sizeof(ngx_chainbuf_node_t)); 80 | if (cn == NULL) { 81 | return NULL; 82 | } 83 | 84 | node = &cn->node; 85 | node->raw_key = size; 86 | ngx_map_insert(&ngx_rbuf_map, node, 0); 87 | 88 | ++ngx_rbuf_nalloc_node; 89 | } else { 90 | cn = (ngx_chainbuf_node_t *) node; 91 | } 92 | 93 | cl = cn->free; 94 | if (cl) { 95 | cn->free = cl->next; 96 | cl->next = NULL; 97 | cb = (ngx_chainbuf_t *) cl; 98 | 99 | --ngx_rbuf_nfree_chain; 100 | } else { 101 | cb = ngx_pcalloc(ngx_rbuf_pool, sizeof(ngx_chainbuf_t) + size); 102 | if (cb == NULL) { 103 | return NULL; 104 | } 105 | 106 | cl = &cb->cl; 107 | cl->buf = &cb->buf; 108 | cb->size = size; 109 | 110 | ++ngx_rbuf_nalloc_chain; 111 | } 112 | 113 | cb->buf.last = cb->buf.pos = cb->buf.start = cb->alloc; 114 | cb->buf.end = cb->alloc + size; 115 | cb->buf.memory = 1; 116 | 117 | #if (NGX_DEBUG) 118 | 119 | // record chainbuf in using map 120 | cb->file = file; 121 | cb->line = line; 122 | cb->node.raw_key = (intptr_t) cl; 123 | ngx_map_insert(&ngx_rbuf_using, &cb->node, 0); 124 | 125 | #endif 126 | 127 | return cl; 128 | } 129 | 130 | void 131 | ngx_put_chainbuf_debug(ngx_chain_t *cl, char *file, int line) 132 | { 133 | ngx_chainbuf_node_t *cn; 134 | ngx_map_node_t *node; 135 | ngx_chainbuf_t *cb; 136 | 137 | 138 | if (ngx_rbuf_pool == NULL) { 139 | return; 140 | } 141 | 142 | if (cl == NULL) { 143 | return; 144 | } 145 | 146 | cb = (ngx_chainbuf_t *) cl; 147 | node = ngx_map_find(&ngx_rbuf_map, cb->size); 148 | if (node == NULL) { 149 | return; 150 | } 151 | 152 | cn = (ngx_chainbuf_node_t *) node; 153 | cl->next = cn->free; 154 | cn->free = cl; 155 | 156 | ++ngx_rbuf_nfree_chain; 157 | 158 | #if (NGX_DEBUG) 159 | 160 | // delete chainbuf from using map 161 | if (ngx_map_find(&ngx_rbuf_using, (intptr_t) cl) == NULL) { 162 | ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, 0, 163 | "destroy chainbuf twice: %s:%d", file, line); 164 | return; 165 | } 166 | ngx_map_delete(&ngx_rbuf_using, (intptr_t) cl); 167 | 168 | #endif 169 | } 170 | 171 | ngx_chain_t * 172 | ngx_rbuf_state(ngx_http_request_t *r, unsigned detail) 173 | { 174 | ngx_chain_t *cl; 175 | ngx_buf_t *b; 176 | size_t len; 177 | #if (NGX_DEBUG) 178 | size_t len1; 179 | ngx_uint_t n; 180 | ngx_chainbuf_t *cb; 181 | ngx_map_node_t *node; 182 | #endif 183 | 184 | len = sizeof("##########ngx rbuf state##########\n") - 1 185 | + sizeof("ngx_rbuf nalloc node: \n") - 1 + NGX_OFF_T_LEN 186 | + sizeof("ngx_rbuf nalloc chain: \n") - 1 + NGX_OFF_T_LEN 187 | + sizeof("ngx_rbuf nfree chain: \n") - 1 + NGX_OFF_T_LEN; 188 | 189 | #if (NGX_DEBUG) 190 | 191 | if (detail) { 192 | n = ngx_rbuf_nalloc_chain - ngx_rbuf_nfree_chain; 193 | /* " file:line\n" */ 194 | len1 = 4 + 256 + 1 + NGX_OFF_T_LEN + 1; 195 | len += len1 * n; 196 | } 197 | 198 | #endif 199 | 200 | cl = ngx_alloc_chain_link(r->pool); 201 | if (cl == NULL) { 202 | return NULL; 203 | } 204 | cl->next = NULL; 205 | 206 | b = ngx_create_temp_buf(r->pool, len); 207 | if (b == NULL) { 208 | return NULL; 209 | } 210 | cl->buf = b; 211 | 212 | b->last = ngx_snprintf(b->last, len, 213 | "##########ngx rbuf state##########\nngx_rbuf nalloc node: %ui\n" 214 | "ngx_rbuf nalloc chain: %ui\nngx_rbuf nfree chain: %ui\n", 215 | ngx_rbuf_nalloc_node, ngx_rbuf_nalloc_chain, ngx_rbuf_nfree_chain); 216 | 217 | #if (NGX_DEBUG) 218 | 219 | if (detail) { 220 | for (node = ngx_map_begin(&ngx_rbuf_using); node; 221 | node = ngx_map_next(node)) 222 | { 223 | cb = (ngx_chainbuf_t *) ((char *) node 224 | - offsetof(ngx_chainbuf_t, node)); 225 | b->last = ngx_snprintf(b->last, len1, " %s:%d\n", 226 | cb->file, cb->line); 227 | } 228 | } 229 | 230 | #endif 231 | 232 | return cl; 233 | } 234 | -------------------------------------------------------------------------------- /t/ngx_dynamic_resolver_test_module.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "ngx_dynamic_resolver.h" 5 | 6 | 7 | static char *ngx_dynamic_resolver_test(ngx_conf_t *cf, ngx_command_t *cmd, 8 | void *conf); 9 | 10 | 11 | typedef struct { 12 | ngx_flag_t sync; 13 | } ngx_dynamic_resolver_test_ctx_t; 14 | 15 | 16 | static ngx_command_t ngx_dynamic_resolver_test_commands[] = { 17 | 18 | { ngx_string("dynamic_resolver_test"), 19 | NGX_HTTP_LOC_CONF|NGX_CONF_ANY, 20 | ngx_dynamic_resolver_test, 21 | 0, 22 | 0, 23 | NULL }, 24 | 25 | ngx_null_command 26 | }; 27 | 28 | 29 | static ngx_http_module_t ngx_dynamic_resolver_test_module_ctx = { 30 | NULL, /* preconfiguration */ 31 | NULL, /* postconfiguration */ 32 | 33 | NULL, /* create main configuration */ 34 | NULL, /* init main configuration */ 35 | 36 | NULL, /* create server configuration */ 37 | NULL, /* merge server configuration */ 38 | 39 | NULL, /* create location configuration */ 40 | NULL /* merge location configuration */ 41 | }; 42 | 43 | 44 | ngx_module_t ngx_dynamic_resolver_test_module = { 45 | NGX_MODULE_V1, 46 | &ngx_dynamic_resolver_test_module_ctx, /* module context */ 47 | ngx_dynamic_resolver_test_commands, /* module directives */ 48 | NGX_HTTP_MODULE, /* module type */ 49 | NULL, /* init master */ 50 | NULL, /* init module */ 51 | NULL, /* init process */ 52 | NULL, /* init thread */ 53 | NULL, /* exit thread */ 54 | NULL, /* exit process */ 55 | NULL, /* exit master */ 56 | NGX_MODULE_V1_PADDING 57 | }; 58 | 59 | 60 | static void 61 | ngx_dynamic_resolver_test_result(void *data, struct sockaddr *sa, socklen_t len) 62 | { 63 | ngx_dynamic_resolver_test_ctx_t *ctx; 64 | ngx_chain_t cl; 65 | ngx_buf_t *b; 66 | ngx_int_t rc; 67 | ngx_http_request_t *r; 68 | u_char text[NGX_SOCKADDRLEN]; 69 | 70 | r = data; 71 | 72 | r->headers_out.status = NGX_HTTP_OK; 73 | 74 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "send header"); 75 | 76 | if (len == 0) { 77 | r->headers_out.content_length_n = 0; 78 | r->header_only = 1; 79 | } 80 | 81 | ctx = ngx_http_get_module_ctx(r, ngx_dynamic_resolver_test_module); 82 | if (ctx == NULL) { 83 | ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); 84 | return; 85 | } 86 | 87 | rc = ngx_http_send_header(r); 88 | if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { 89 | ngx_http_finalize_request(r, rc); 90 | return; 91 | } 92 | 93 | ngx_memzero(text, sizeof(text)); 94 | len = ngx_sock_ntop(sa, len, text, NGX_SOCKADDRLEN, 0) + 1; 95 | 96 | b = ngx_create_temp_buf(r->pool, len); 97 | 98 | if (b == NULL) { 99 | ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); 100 | return; 101 | } 102 | 103 | b->last = ngx_snprintf(b->last, len, "%s\n", text); 104 | b->last_buf = 1; 105 | b->last_in_chain = 1; 106 | 107 | cl.buf = b; 108 | cl.next = NULL; 109 | 110 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "send body"); 111 | 112 | ngx_http_output_filter(r, &cl); 113 | 114 | if (ctx->sync) { 115 | return; 116 | } 117 | 118 | ngx_http_finalize_request(r, NGX_OK); 119 | } 120 | 121 | static ngx_int_t 122 | ngx_dynamic_resolver_test_handler(ngx_http_request_t *r) 123 | { 124 | ngx_dynamic_resolver_test_ctx_t *ctx; 125 | ngx_str_t domain, sync; 126 | struct sockaddr sa; 127 | socklen_t len; 128 | 129 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 130 | "dynamic resolver test handler"); 131 | 132 | ctx = ngx_pcalloc(r->pool, sizeof(ngx_dynamic_resolver_test_ctx_t)); 133 | if (ctx == NULL) { 134 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 135 | } 136 | ngx_http_set_ctx(r, ctx, ngx_dynamic_resolver_test_module); 137 | 138 | if (ngx_http_arg(r, (u_char *) "domain", 6, &domain) != NGX_OK) { 139 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 140 | "dynamic resolver test, no domain in http args"); 141 | return NGX_HTTP_BAD_REQUEST; 142 | } 143 | 144 | if (ngx_http_arg(r, (u_char *) "sync", 4, &sync) == NGX_OK) { 145 | ctx->sync = 1; 146 | } 147 | 148 | if (r->method == NGX_HTTP_GET && ctx->sync == 0) { 149 | r->count++; 150 | ngx_dynamic_resolver_start_resolver(&domain, 151 | ngx_dynamic_resolver_test_result, r); 152 | 153 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 154 | "dynamic resolver test, after start resolver"); 155 | return NGX_DONE; 156 | } else if (r->method == NGX_HTTP_GET && ctx->sync) { 157 | ngx_memzero(&sa, sizeof(sa)); 158 | len = ngx_dynamic_resolver_gethostbyname(&domain, &sa); 159 | ngx_dynamic_resolver_test_result(r, &sa, len); 160 | 161 | return NGX_OK; 162 | } else if (r->method != NGX_HTTP_DELETE) { 163 | return NGX_HTTP_BAD_REQUEST; 164 | } 165 | 166 | ngx_dynamic_resolver_del_domain(&domain); 167 | 168 | r->headers_out.status = NGX_HTTP_OK; 169 | r->headers_out.content_length_n = 0; 170 | r->header_only = 1; 171 | 172 | return ngx_http_send_header(r); 173 | } 174 | 175 | 176 | static char * 177 | ngx_dynamic_resolver_test(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 178 | { 179 | ngx_http_core_loc_conf_t *clcf; 180 | ngx_str_t *value; 181 | ngx_uint_t i; 182 | 183 | clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); 184 | clcf->handler = ngx_dynamic_resolver_test_handler; 185 | 186 | value = cf->args->elts; 187 | 188 | for (i = 1; i < cf->args->nelts; ++i) { 189 | ngx_dynamic_resolver_add_domain(&value[i], cf->cycle); 190 | } 191 | 192 | return NGX_CONF_OK; 193 | } 194 | -------------------------------------------------------------------------------- /t/ngx_dynamic_conf_test_module.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "ngx_dynamic_conf.h" 5 | 6 | 7 | /******************************************************************************/ 8 | static void *ngx_dynamic_core_test_create_conf(ngx_conf_t *cf); 9 | static char *ngx_dynamic_core_test_init_conf(ngx_conf_t *cf, void *conf); 10 | 11 | 12 | typedef struct { 13 | ngx_uint_t i; 14 | ngx_str_t s; 15 | } ngx_dynamic_core_test_conf_t; 16 | 17 | 18 | ngx_core_module_t ngx_dynamic_core_test_module_ctx = { 19 | ngx_string("dynamic_core_test"), 20 | NULL, 21 | NULL 22 | }; 23 | 24 | static ngx_command_t ngx_dynamic_core_test_dcommands[] = { 25 | 26 | { ngx_string("dynamic_test_i"), 27 | NGX_MAIN_CONF|NGX_CONF_TAKE1, 28 | ngx_conf_set_num_slot, 29 | 0, 30 | offsetof(ngx_dynamic_core_test_conf_t, i), 31 | NULL }, 32 | 33 | { ngx_string("dynamic_test_s"), 34 | NGX_MAIN_CONF|NGX_CONF_TAKE1, 35 | ngx_conf_set_str_slot, 36 | 0, 37 | offsetof(ngx_dynamic_core_test_conf_t, s), 38 | NULL }, 39 | 40 | ngx_null_command 41 | }; 42 | 43 | 44 | static ngx_dynamic_core_module_t ngx_dynamic_core_test_module_dctx = { 45 | ngx_string("dynamic_core_test"), 46 | ngx_dynamic_core_test_create_conf, 47 | ngx_dynamic_core_test_init_conf 48 | }; 49 | 50 | 51 | ngx_module_t ngx_dynamic_core_test_module = { 52 | NGX_MODULE_V1, 53 | &ngx_dynamic_core_test_module_ctx, /* module context */ 54 | NULL, /* module directives */ 55 | NGX_CORE_MODULE, /* module type */ 56 | NULL, /* init master */ 57 | NULL, /* init module */ 58 | NULL, /* init process */ 59 | NULL, /* init thread */ 60 | NULL, /* exit thread */ 61 | NULL, /* exit process */ 62 | NULL, /* exit master */ 63 | (uintptr_t) &ngx_dynamic_core_test_module_dctx, /* module dynamic context */ 64 | (uintptr_t) ngx_dynamic_core_test_dcommands, /* module dynamic directives */ 65 | NGX_MODULE_V1_DYNAMIC_PADDING 66 | }; 67 | 68 | 69 | static void * 70 | ngx_dynamic_core_test_create_conf(ngx_conf_t *cf) 71 | { 72 | ngx_dynamic_core_test_conf_t *conf; 73 | 74 | conf = ngx_pcalloc(cf->pool, sizeof(ngx_dynamic_core_test_conf_t)); 75 | if (conf == NULL) { 76 | return NULL; 77 | } 78 | 79 | conf->i = NGX_CONF_UNSET_UINT; 80 | 81 | return conf; 82 | } 83 | 84 | 85 | static char * 86 | ngx_dynamic_core_test_init_conf(ngx_conf_t *cf, void *conf) 87 | { 88 | ngx_dynamic_core_test_conf_t *dctcf; 89 | 90 | dctcf = conf; 91 | 92 | ngx_conf_init_uint_value(dctcf->i, 1000); 93 | 94 | return NGX_CONF_OK; 95 | } 96 | /******************************************************************************/ 97 | 98 | 99 | static char *ngx_dynamic_conf_test(ngx_conf_t *cf, ngx_command_t *cmd, 100 | void *conf); 101 | 102 | 103 | #define MAXBUFSIZE 4096 104 | 105 | 106 | static ngx_command_t ngx_dynamic_conf_test_commands[] = { 107 | 108 | { ngx_string("dynamic_conf_test"), 109 | NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS, 110 | ngx_dynamic_conf_test, 111 | 0, 112 | 0, 113 | NULL }, 114 | 115 | ngx_null_command 116 | }; 117 | 118 | 119 | static ngx_http_module_t ngx_dynamic_conf_test_module_ctx = { 120 | NULL, /* preconfiguration */ 121 | NULL, /* postconfiguration */ 122 | 123 | NULL, /* create main configuration */ 124 | NULL, /* init main configuration */ 125 | 126 | NULL, /* create server configuration */ 127 | NULL, /* merge server configuration */ 128 | 129 | NULL, /* create location configuration */ 130 | NULL /* merge location configuration */ 131 | }; 132 | 133 | 134 | ngx_module_t ngx_dynamic_conf_test_module = { 135 | NGX_MODULE_V1, 136 | &ngx_dynamic_conf_test_module_ctx, /* module context */ 137 | ngx_dynamic_conf_test_commands, /* module directives */ 138 | NGX_HTTP_MODULE, /* module type */ 139 | NULL, /* init master */ 140 | NULL, /* init module */ 141 | NULL, /* init process */ 142 | NULL, /* init thread */ 143 | NULL, /* exit thread */ 144 | NULL, /* exit process */ 145 | NULL, /* exit master */ 146 | NGX_MODULE_V1_PADDING 147 | }; 148 | 149 | 150 | static ngx_int_t 151 | ngx_dynamic_conf_test_handler(ngx_http_request_t *r) 152 | { 153 | ngx_chain_t cl; 154 | ngx_buf_t *b; 155 | ngx_dynamic_core_test_conf_t *dctcf; 156 | 157 | ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "dynamic conf test handler"); 158 | 159 | b = ngx_create_temp_buf(r->pool, MAXBUFSIZE); 160 | 161 | if (b == NULL) { 162 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 163 | } 164 | 165 | dctcf = (ngx_dynamic_core_test_conf_t *) 166 | ngx_get_dconf(&ngx_dynamic_core_test_module); 167 | if (dctcf == NULL) { 168 | ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, 169 | "dynamic conf test handler, dynamic conf not configured"); 170 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 171 | } 172 | 173 | r->headers_out.status = NGX_HTTP_OK; 174 | 175 | ngx_http_send_header(r); 176 | 177 | b->last = ngx_snprintf(b->last, MAXBUFSIZE, "dynamic core test %ui [%V]\n", 178 | dctcf->i, &dctcf->s); 179 | b->last_buf = 1; 180 | b->last_in_chain = 1; 181 | 182 | cl.buf = b; 183 | cl.next = NULL; 184 | 185 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "send body"); 186 | 187 | return ngx_http_output_filter(r, &cl); 188 | } 189 | 190 | 191 | static char * 192 | ngx_dynamic_conf_test(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 193 | { 194 | ngx_http_core_loc_conf_t *clcf; 195 | 196 | clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); 197 | clcf->handler = ngx_dynamic_conf_test_handler; 198 | 199 | return NGX_CONF_OK; 200 | } 201 | -------------------------------------------------------------------------------- /t/ngx_timerd_test_module.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "ngx_timerd.h" 5 | 6 | 7 | static char *ngx_timerd_test(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); 8 | 9 | 10 | typedef struct { 11 | ngx_pool_t *pool; 12 | ngx_event_t ev; 13 | ngx_uint_t footprint; 14 | } ngx_timer_test_data_t; 15 | 16 | 17 | static ngx_command_t ngx_timerd_test_commands[] = { 18 | 19 | { ngx_string("timerd_test"), 20 | NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS, 21 | ngx_timerd_test, 22 | 0, 23 | 0, 24 | NULL }, 25 | 26 | ngx_null_command 27 | }; 28 | 29 | 30 | static ngx_http_module_t ngx_timerd_test_module_ctx = { 31 | NULL, /* preconfiguration */ 32 | NULL, /* postconfiguration */ 33 | 34 | NULL, /* create main configuration */ 35 | NULL, /* init main configuration */ 36 | 37 | NULL, /* create server configuration */ 38 | NULL, /* merge server configuration */ 39 | 40 | NULL, /* create location configuration */ 41 | NULL /* merge location configuration */ 42 | }; 43 | 44 | 45 | ngx_module_t ngx_timerd_test_module = { 46 | NGX_MODULE_V1, 47 | &ngx_timerd_test_module_ctx, /* module context */ 48 | ngx_timerd_test_commands, /* module directives */ 49 | NGX_HTTP_MODULE, /* module type */ 50 | NULL, /* init master */ 51 | NULL, /* init module */ 52 | NULL, /* init process */ 53 | NULL, /* init thread */ 54 | NULL, /* exit thread */ 55 | NULL, /* exit process */ 56 | NULL, /* exit master */ 57 | NGX_MODULE_V1_PADDING 58 | }; 59 | 60 | 61 | static void 62 | ngx_timerd_test_timer(ngx_event_t *ev) 63 | { 64 | ngx_timer_test_data_t *data; 65 | 66 | data = ev->data; 67 | 68 | ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, 0, "timerd test timer: %p %ui", 69 | data, data->footprint); 70 | } 71 | 72 | 73 | static ngx_int_t 74 | ngx_timerd_test_handler(ngx_http_request_t *r) 75 | { 76 | ngx_chain_t *out; 77 | 78 | // normal timer trigger 79 | ngx_timer_test_data_t *test; 80 | ngx_pool_t *pool; 81 | 82 | pool = ngx_create_pool(4096, r->connection->log); 83 | test = ngx_pcalloc(pool, sizeof(ngx_timer_test_data_t)); 84 | 85 | test->pool = pool; 86 | test->footprint = ngx_timerd_footprint(); 87 | test->ev.data = test; 88 | test->ev.handler = ngx_timerd_test_timer; 89 | NGX_ADD_TIMER(&test->ev, 5000, offsetof(ngx_timer_test_data_t, footprint)); 90 | 91 | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, 92 | "!!!!!!!!!!normal timer trigger: %p %ui", test, test->footprint); 93 | 94 | // delete timer twice 95 | ngx_timer_test_data_t *test1; 96 | ngx_pool_t *pool1; 97 | 98 | pool1 = ngx_create_pool(4096, r->connection->log); 99 | test1 = ngx_pcalloc(pool1, sizeof(ngx_timer_test_data_t)); 100 | 101 | test1->pool = pool1; 102 | test1->footprint = ngx_timerd_footprint(); 103 | test1->ev.data = test1; 104 | test1->ev.handler = ngx_timerd_test_timer; 105 | NGX_ADD_TIMER(&test1->ev, 5000, offsetof(ngx_timer_test_data_t, footprint)); 106 | 107 | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, 108 | "!!!!!!!!!!delete timer twice: %p %ui", test1, test1->footprint); 109 | NGX_DEL_TIMER(&test1->ev, test1->footprint); 110 | NGX_DEL_TIMER(&test1->ev, test1->footprint); 111 | 112 | // timer trigger after event destroy 113 | ngx_timer_test_data_t *test2; 114 | ngx_pool_t *pool2; 115 | 116 | pool2 = ngx_create_pool(4096, r->connection->log); 117 | test2 = ngx_pcalloc(pool2, sizeof(ngx_timer_test_data_t)); 118 | 119 | test2->pool = pool2; 120 | test2->footprint = ngx_timerd_footprint(); 121 | test2->ev.data = test2; 122 | test2->ev.handler = ngx_timerd_test_timer; 123 | NGX_ADD_TIMER(&test2->ev, 5000, offsetof(ngx_timer_test_data_t, footprint)); 124 | 125 | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, 126 | "!!!!!!!!!!timer trigger after event destroy: %p %ui", 127 | test2, test2->footprint); 128 | test2->footprint = ngx_timerd_footprint(); 129 | 130 | ngx_destroy_pool(pool2); 131 | 132 | // delete timer after event destroy 133 | ngx_timer_test_data_t *test3; 134 | ngx_pool_t *pool3; 135 | 136 | pool3 = ngx_create_pool(4096, r->connection->log); 137 | test3 = ngx_pcalloc(pool3, sizeof(ngx_timer_test_data_t)); 138 | 139 | test3->pool = pool3; 140 | test3->footprint = ngx_timerd_footprint(); 141 | test3->ev.data = test3; 142 | test3->ev.handler = ngx_timerd_test_timer; 143 | NGX_ADD_TIMER(&test3->ev, 5000, offsetof(ngx_timer_test_data_t, footprint)); 144 | 145 | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, 146 | "!!!!!!!!!!delete timer after event destroy: %p %ui", 147 | test3, test3->footprint); 148 | test3->footprint = ngx_timerd_footprint(); 149 | 150 | NGX_DEL_TIMER(&test3->ev, test3->footprint); 151 | 152 | ngx_destroy_pool(pool3); 153 | 154 | 155 | // add timer after event destroy 156 | ngx_timer_test_data_t *test4; 157 | ngx_pool_t *pool4; 158 | 159 | pool4 = ngx_create_pool(4096, r->connection->log); 160 | test4 = ngx_pcalloc(pool4, sizeof(ngx_timer_test_data_t)); 161 | 162 | test4->pool = pool4; 163 | test4->footprint = ngx_timerd_footprint(); 164 | test4->ev.data = test4; 165 | test4->ev.handler = ngx_timerd_test_timer; 166 | NGX_ADD_TIMER(&test4->ev, 5000, offsetof(ngx_timer_test_data_t, footprint)); 167 | 168 | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, 169 | "!!!!!!!!!!add timer after event destroy: %p %ui", 170 | test4, test4->footprint); 171 | test4->footprint = ngx_timerd_footprint(); 172 | 173 | NGX_ADD_TIMER(&test4->ev, 5000, offsetof(ngx_timer_test_data_t, footprint)); 174 | 175 | ngx_destroy_pool(pool4); 176 | 177 | 178 | r->headers_out.status = NGX_HTTP_OK; 179 | ngx_http_send_header(r); 180 | 181 | out = ngx_timerd_state(r, 1); 182 | out->buf->last_buf = 1; 183 | 184 | return ngx_http_output_filter(r, out); 185 | } 186 | 187 | 188 | static char * 189 | ngx_timerd_test(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 190 | { 191 | ngx_http_core_loc_conf_t *clcf; 192 | 193 | clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); 194 | clcf->handler = ngx_timerd_test_handler; 195 | 196 | return NGX_CONF_OK; 197 | } 198 | 199 | -------------------------------------------------------------------------------- /ngx_event_timer_module.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) AlexWoo(Wu Jie) wj19840501@gmail.com 3 | */ 4 | 5 | 6 | #include "ngx_event_timer_module.h" 7 | 8 | 9 | static ngx_int_t ngx_event_timer_process_init(ngx_cycle_t *cycle); 10 | 11 | static void *ngx_event_timer_create_conf(ngx_cycle_t *cycle); 12 | static char *ngx_event_timer_init_conf(ngx_cycle_t *cycle, void *conf); 13 | 14 | 15 | typedef struct { 16 | ngx_uint_t timerid; 17 | 18 | ngx_event_t event; 19 | 20 | ngx_timer_handler_pt handler; 21 | void *data; 22 | } ngx_event_timer_ctx_t; 23 | 24 | typedef struct { 25 | ngx_uint_t timer_n; 26 | 27 | ngx_event_timer_ctx_t *timer_ctx; /* array to store timers */ 28 | 29 | ngx_event_timer_ctx_t *free_timers; /* timer unused */ 30 | ngx_uint_t free_timer_n; 31 | } ngx_event_timer_conf_t; 32 | 33 | 34 | static ngx_str_t event_timer_name = ngx_string("event_timer"); 35 | 36 | 37 | static ngx_command_t ngx_event_timer_commands[] = { 38 | 39 | { ngx_string("worker_timers"), 40 | NGX_EVENT_CONF|NGX_CONF_TAKE1, 41 | ngx_conf_set_num_slot, 42 | 0, 43 | offsetof(ngx_event_timer_conf_t, timer_n), 44 | NULL }, 45 | 46 | ngx_null_command 47 | }; 48 | 49 | 50 | ngx_event_module_t ngx_event_timer_module_ctx = { 51 | &event_timer_name, 52 | ngx_event_timer_create_conf, /* create configuration */ 53 | ngx_event_timer_init_conf, /* init configuration */ 54 | 55 | { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL } 56 | }; 57 | 58 | 59 | /* this module use ngx_cycle->log */ 60 | ngx_module_t ngx_event_timer_module = { 61 | NGX_MODULE_V1, 62 | &ngx_event_timer_module_ctx, /* module context */ 63 | ngx_event_timer_commands, /* module directives */ 64 | NGX_EVENT_MODULE, /* module type */ 65 | NULL, /* init master */ 66 | NULL, /* init module */ 67 | ngx_event_timer_process_init, /* init process */ 68 | NULL, /* init thread */ 69 | NULL, /* exit thread */ 70 | NULL, /* exit process */ 71 | NULL, /* exit master */ 72 | NGX_MODULE_V1_PADDING 73 | }; 74 | 75 | 76 | static void * 77 | ngx_event_timer_create_conf(ngx_cycle_t *cycle) 78 | { 79 | ngx_event_timer_conf_t *conf; 80 | 81 | conf = ngx_pcalloc(cycle->pool, sizeof(ngx_event_timer_conf_t)); 82 | if (conf == NULL) { 83 | return NULL; 84 | } 85 | 86 | conf->timer_n = NGX_CONF_UNSET_UINT; 87 | 88 | return conf; 89 | } 90 | 91 | static char * 92 | ngx_event_timer_init_conf(ngx_cycle_t *cycle, void *conf) 93 | { 94 | ngx_event_timer_conf_t *etcf = conf; 95 | 96 | ngx_conf_init_uint_value(etcf->timer_n, 1024); 97 | 98 | return NGX_CONF_OK; 99 | } 100 | 101 | static ngx_int_t 102 | ngx_event_timer_process_init(ngx_cycle_t *cycle) 103 | { 104 | ngx_event_timer_conf_t *etcf; 105 | ngx_event_timer_ctx_t *t, *next; 106 | ngx_uint_t i; 107 | 108 | etcf = ngx_event_get_conf(cycle->conf_ctx, ngx_event_timer_module); 109 | 110 | if (etcf->timer_n == 0) { 111 | return NGX_OK; 112 | } 113 | 114 | etcf->timer_ctx = 115 | ngx_alloc(sizeof(ngx_event_timer_ctx_t) * etcf->timer_n, cycle->log); 116 | if (etcf->timer_ctx == NULL) { 117 | return NGX_ERROR; 118 | } 119 | 120 | t = etcf->timer_ctx; 121 | 122 | i = etcf->timer_n; 123 | next = NULL; 124 | 125 | do { 126 | --i; 127 | 128 | t[i].timerid = i; 129 | t[i].event.timer_set = 0; 130 | t[i].event.log = NULL; 131 | t[i].handler = NULL; 132 | t[i].data = next; 133 | 134 | next = &t[i]; 135 | } while (i); 136 | 137 | etcf->free_timers = next; 138 | etcf->free_timer_n = etcf->timer_n; 139 | 140 | return NGX_OK; 141 | } 142 | 143 | static ngx_event_timer_ctx_t * 144 | ngx_event_timer_get_timer() 145 | { 146 | ngx_event_timer_conf_t *etcf; 147 | ngx_event_timer_ctx_t *free; 148 | 149 | etcf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_event_timer_module); 150 | 151 | free = etcf->free_timers; 152 | if (etcf->free_timer_n == 0) { 153 | ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, 154 | "nginx event timer module, no free timer"); 155 | return NULL; 156 | } 157 | 158 | etcf->free_timers = free->data; 159 | --etcf->free_timer_n; 160 | 161 | return free; 162 | } 163 | 164 | static void 165 | ngx_event_timer_free_timer(ngx_event_timer_ctx_t *ctx) 166 | { 167 | ngx_event_timer_conf_t *etcf; 168 | 169 | etcf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_event_timer_module); 170 | 171 | ctx->data = etcf->free_timers; 172 | etcf->free_timers = ctx; 173 | ++etcf->free_timer_n; 174 | } 175 | 176 | static void 177 | ngx_event_timer_event_handler(ngx_event_t *e) 178 | { 179 | ngx_event_timer_ctx_t *ctx; 180 | 181 | ctx = e->data; 182 | 183 | if (ctx->handler) { 184 | ctx->handler(ctx->data); 185 | } 186 | 187 | ngx_event_timer_free_timer(ctx); 188 | } 189 | 190 | ngx_int_t 191 | ngx_event_timer_add_timer(ngx_msec_t tv, ngx_timer_handler_pt h, void *data) 192 | { 193 | ngx_event_timer_ctx_t *ctx; 194 | 195 | if (h == NULL) { 196 | return NGX_ERROR; 197 | } 198 | 199 | ctx = ngx_event_timer_get_timer(); 200 | if (ctx == NULL) { 201 | return NGX_ERROR; 202 | } 203 | 204 | ctx->event.handler = ngx_event_timer_event_handler; 205 | ctx->event.data = ctx; 206 | 207 | ctx->handler = h; 208 | ctx->data = data; 209 | 210 | if (ctx->event.log == NULL) { 211 | ctx->event.log = ngx_cycle->log; 212 | } 213 | 214 | ngx_event_add_timer(&ctx->event, tv); 215 | 216 | return ctx->timerid; 217 | } 218 | 219 | void 220 | ngx_event_timer_del_timer(ngx_uint_t timerid) 221 | { 222 | ngx_event_timer_ctx_t *ctx; 223 | ngx_event_timer_conf_t *etcf; 224 | 225 | etcf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_event_timer_module); 226 | 227 | ctx = &etcf->timer_ctx[timerid]; 228 | 229 | if (!ctx->event.timer_set) { 230 | ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0, 231 | "timer has already deleted"); 232 | return; 233 | } 234 | 235 | ngx_event_del_timer(&ctx->event); 236 | ngx_event_timer_free_timer(ctx); 237 | } 238 | 239 | ngx_chain_t * 240 | ngx_event_timer_state(ngx_http_request_t *r) 241 | { 242 | ngx_event_timer_conf_t *etcf; 243 | ngx_chain_t *cl; 244 | ngx_buf_t *b; 245 | size_t len; 246 | 247 | etcf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_event_timer_module); 248 | 249 | len = sizeof("##########event timer state##########\n") - 1 250 | + sizeof("ngx_event_timer alloc: \n") - 1 + NGX_OFF_T_LEN 251 | + sizeof("ngx_event_timer free: \n") - 1 + NGX_OFF_T_LEN; 252 | 253 | cl = ngx_alloc_chain_link(r->pool); 254 | if (cl == NULL) { 255 | return NULL; 256 | } 257 | cl->next = NULL; 258 | 259 | b = ngx_create_temp_buf(r->pool, len); 260 | if (b == NULL) { 261 | return NULL; 262 | } 263 | cl->buf = b; 264 | 265 | b->last = ngx_snprintf(b->last, len, 266 | "##########event timer state##########\n" 267 | "ngx_event_timer alloc: %ui\nngx_event_timer free: %ui\n", 268 | etcf->timer_n, etcf->free_timer_n); 269 | 270 | return cl; 271 | } 272 | -------------------------------------------------------------------------------- /ngx_timerd.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) AlexWoo(Wu Jie) wj19840501@gmail.com 3 | */ 4 | 5 | 6 | #include "ngx_timerd.h" 7 | #include "ngx_map.h" 8 | 9 | 10 | typedef struct ngx_timerd_node_s ngx_timerd_node_t; 11 | 12 | static ngx_pool_t *ngx_timerd_pool; 13 | 14 | static ngx_map_t ngx_timerd_map; 15 | static ngx_timerd_node_t *ngx_timerd_free_node; 16 | 17 | static ngx_uint_t timerd_footprint; 18 | static ngx_uint_t ngx_timerd_nalloc; 19 | static ngx_uint_t ngx_timerd_nfree; 20 | 21 | 22 | struct ngx_timerd_node_s { 23 | ngx_map_node_t m; /* map node */ 24 | ngx_timerd_node_t *next; /* free node */ 25 | 26 | ngx_uint_t footprint; 27 | off_t fpoff; 28 | ngx_event_t ev; 29 | 30 | ngx_event_t *uev; 31 | char *file; /* file create pool */ 32 | int line; /* line create pool */ 33 | }; 34 | 35 | 36 | static ngx_int_t 37 | ngx_timerd_init() 38 | { 39 | ngx_timerd_pool = ngx_create_pool(4096, ngx_cycle->log); 40 | if (ngx_timerd_pool == NULL) { 41 | return NGX_ERROR; 42 | } 43 | 44 | ngx_map_init(&ngx_timerd_map, ngx_map_hash_uint, ngx_cmp_uint); 45 | ngx_timerd_free_node = NULL; 46 | 47 | ngx_timerd_nalloc = 0; 48 | ngx_timerd_nfree = 0; 49 | 50 | return NGX_OK; 51 | } 52 | 53 | 54 | static ngx_timerd_node_t * 55 | ngx_timerd_get_node() 56 | { 57 | ngx_timerd_node_t *n; 58 | 59 | n = ngx_timerd_free_node; 60 | if (n == NULL) { 61 | n = ngx_pcalloc(ngx_timerd_pool, sizeof(ngx_timerd_node_t)); 62 | if (n == NULL) { 63 | return NULL; 64 | } 65 | 66 | ++ngx_timerd_nalloc; 67 | } else { 68 | ngx_timerd_free_node = n->next; 69 | ngx_memzero(n, sizeof(ngx_timerd_node_t)); 70 | 71 | --ngx_timerd_nfree; 72 | } 73 | 74 | return n; 75 | } 76 | 77 | 78 | static void 79 | ngx_timerd_put_node(ngx_timerd_node_t *node) 80 | { 81 | if (ngx_timerd_pool == NULL) { 82 | return; 83 | } 84 | 85 | if (node == NULL) { 86 | return; 87 | } 88 | 89 | node->next = ngx_timerd_free_node; 90 | ngx_timerd_free_node = node; 91 | 92 | ++ngx_timerd_nfree; 93 | } 94 | 95 | 96 | static void 97 | ngx_timerd_wrap(ngx_event_t *ev) 98 | { 99 | ngx_timerd_node_t *node; 100 | ngx_event_t *uev; 101 | ngx_uint_t *fp; 102 | 103 | node = ev->data; 104 | uev = node->uev; 105 | 106 | fp = (ngx_uint_t *) ((char *) (uev->data) + node->fpoff); 107 | if (*fp != node->footprint) { 108 | ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, 0, 109 | "timer wrap, timer trigger but not timer owner: %s:%d", 110 | node->file, node->line); 111 | return; 112 | } 113 | 114 | ngx_map_delete(&ngx_timerd_map, (intptr_t) uev); 115 | 116 | uev->timer_set = 0; 117 | uev->timedout = 1; 118 | 119 | uev->handler(uev); 120 | 121 | ngx_timerd_put_node(node); 122 | } 123 | 124 | 125 | ngx_uint_t 126 | ngx_timerd_footprint() 127 | { 128 | return timerd_footprint++; 129 | } 130 | 131 | 132 | void 133 | ngx_add_timer_debug(ngx_event_t *ev, ngx_msec_t timer, off_t fpoff, 134 | char *file, int line) 135 | { 136 | ngx_timerd_node_t *node; 137 | ngx_map_node_t *m; 138 | ngx_uint_t *fp; 139 | 140 | if (ngx_timerd_pool == NULL) { 141 | ngx_timerd_init(); 142 | } 143 | 144 | fp = (ngx_uint_t *) ((char *) ev->data + fpoff); 145 | 146 | m = ngx_map_find(&ngx_timerd_map, (intptr_t) ev); 147 | if (m == NULL) { // first add 148 | node = ngx_timerd_get_node(); 149 | 150 | node->m.raw_key = (intptr_t) ev; 151 | ngx_map_insert(&ngx_timerd_map, &node->m, 0); 152 | 153 | node->footprint = *fp; 154 | node->fpoff = fpoff; 155 | 156 | node->ev.log = ngx_cycle->log; 157 | node->ev.data = node; 158 | node->ev.handler = ngx_timerd_wrap; 159 | 160 | node->uev = ev; 161 | node->file = file; 162 | node->line = line; 163 | } else { 164 | node = (ngx_timerd_node_t *) ((char *) m - 165 | offsetof(ngx_timerd_node_t, m)); 166 | if (node->footprint != *fp) { 167 | ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, 0, 168 | "add timer but not timer owner(%s:%d): %s:%d", 169 | node->file, node->line, file, line); 170 | return; 171 | } 172 | } 173 | 174 | ev->timer_set = 1; 175 | ngx_add_timer(&node->ev, timer); 176 | } 177 | 178 | 179 | void 180 | ngx_del_timer_debug(ngx_event_t *ev, ngx_uint_t footprint, char *file, int line) 181 | { 182 | ngx_timerd_node_t *node; 183 | ngx_map_node_t *m; 184 | 185 | /* get node by pool */ 186 | m = ngx_map_find(&ngx_timerd_map, (intptr_t) ev); 187 | if (m == NULL) { 188 | ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, 0, 189 | "delete timer twice: %s:%d", file, line); 190 | return; 191 | } 192 | 193 | node = (ngx_timerd_node_t *) ((char *) m - offsetof(ngx_timerd_node_t, m)); 194 | if (node->footprint != footprint) { 195 | ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, 0, 196 | "delete timer but not timer owner: %s:%d", file, line); 197 | return; 198 | } 199 | 200 | ngx_map_delete(&ngx_timerd_map, (intptr_t) ev); 201 | 202 | if (node->ev.timer_set) { 203 | ev->timer_set = 0; 204 | ngx_del_timer(&node->ev); 205 | } 206 | 207 | if (node->ev.posted) { 208 | ngx_delete_posted_event(&node->ev); 209 | } 210 | 211 | /* put node in timerd map */ 212 | ngx_timerd_put_node(node); 213 | } 214 | 215 | 216 | ngx_chain_t * 217 | ngx_timerd_state(ngx_http_request_t *r, unsigned detail) 218 | { 219 | ngx_chain_t *cl; 220 | ngx_buf_t *b; 221 | size_t len; 222 | #if (NGX_DEBUG) 223 | ngx_map_node_t *node; 224 | ngx_timerd_node_t *pn; 225 | size_t len1; 226 | ngx_uint_t n; 227 | #endif 228 | 229 | len = sizeof("##########ngx debug pool##########\n") - 1 230 | + sizeof("ngx_timerd nalloc node: \n") - 1 + NGX_OFF_T_LEN 231 | + sizeof("ngx_timerd nfree node: \n") - 1 + NGX_OFF_T_LEN; 232 | 233 | #if (NGX_DEBUG) 234 | 235 | /* node for create pool */ 236 | if (detail) { 237 | n = ngx_timerd_nalloc - ngx_timerd_nfree; 238 | /* " file:line\n" */ 239 | len1 = 4 + 256 + 1 + NGX_OFF_T_LEN + 1; 240 | len += len1 * n; 241 | } 242 | 243 | #endif 244 | 245 | cl = ngx_alloc_chain_link(r->pool); 246 | if (cl == NULL) { 247 | return NULL; 248 | } 249 | cl->next = NULL; 250 | 251 | b = ngx_create_temp_buf(r->pool, len); 252 | if (b == NULL) { 253 | return NULL; 254 | } 255 | cl->buf = b; 256 | 257 | b->last = ngx_snprintf(b->last, len, 258 | "##########ngx debug pool##########\n" 259 | "ngx_timerd nalloc node: %ui\nngx_timerd nfree node: %ui\n", 260 | ngx_timerd_nalloc, ngx_timerd_nfree); 261 | 262 | #if (NGX_DEBUG) 263 | 264 | if (detail) { 265 | for (node = ngx_map_begin(&ngx_timerd_map); node; 266 | node = ngx_map_next(node)) 267 | { 268 | /* m is first element of ngx_timerd_node_t */ 269 | pn = (ngx_timerd_node_t *) node; 270 | b->last = ngx_snprintf(b->last, len1, " %s:%d\n", 271 | pn->file, pn->line); 272 | } 273 | } 274 | 275 | #endif 276 | 277 | return cl; 278 | } 279 | -------------------------------------------------------------------------------- /t/ngx_map_test_module.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "ngx_map.h" 5 | #include "ngx_test_macro.h" 6 | 7 | 8 | static char *ngx_map_test(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); 9 | 10 | 11 | static ngx_command_t ngx_map_test_commands[] = { 12 | 13 | { ngx_string("map_test"), 14 | NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS, 15 | ngx_map_test, 16 | 0, 17 | 0, 18 | NULL }, 19 | 20 | ngx_null_command 21 | }; 22 | 23 | 24 | static ngx_http_module_t ngx_map_test_module_ctx = { 25 | NULL, /* preconfiguration */ 26 | NULL, /* postconfiguration */ 27 | 28 | NULL, /* create main configuration */ 29 | NULL, /* init main configuration */ 30 | 31 | NULL, /* create server configuration */ 32 | NULL, /* merge server configuration */ 33 | 34 | NULL, /* create location configuration */ 35 | NULL /* merge location configuration */ 36 | }; 37 | 38 | 39 | ngx_module_t ngx_map_test_module = { 40 | NGX_MODULE_V1, 41 | &ngx_map_test_module_ctx, /* module context */ 42 | ngx_map_test_commands, /* module directives */ 43 | NGX_HTTP_MODULE, /* module type */ 44 | NULL, /* init master */ 45 | NULL, /* init module */ 46 | NULL, /* init process */ 47 | NULL, /* init thread */ 48 | NULL, /* exit thread */ 49 | NULL, /* exit process */ 50 | NULL, /* exit master */ 51 | NGX_MODULE_V1_PADDING 52 | }; 53 | 54 | 55 | #define MAP_NODE_INIT_STR(n, k) \ 56 | ngx_map_node_t n; \ 57 | static ngx_str_t k = ngx_string(#k); \ 58 | ngx_memzero(&n, sizeof(ngx_map_node_t)); \ 59 | n.raw_key = (intptr_t) &k; 60 | 61 | #define MAP_NODE_PRINT_KEY_STR(n) \ 62 | { \ 63 | ngx_str_t *s = (ngx_str_t *) (n)->raw_key; \ 64 | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, \ 65 | "!!!!!!!!!!!!!!!!%V", s); \ 66 | } 67 | 68 | static ngx_int_t 69 | ngx_map_test_handler(ngx_http_request_t *r) 70 | { 71 | ngx_buf_t *b; 72 | ngx_chain_t cl; 73 | size_t len; 74 | ngx_map_t map; 75 | 76 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 77 | "map test handler"); 78 | 79 | ngx_memzero(&map, sizeof(ngx_map_t)); 80 | ngx_map_init(&map, ngx_map_hash_str, ngx_cmp_str); 81 | 82 | MAP_NODE_INIT_STR(n1, k1) 83 | MAP_NODE_INIT_STR(n2, k2) 84 | MAP_NODE_INIT_STR(n3, k3) 85 | MAP_NODE_INIT_STR(n4, k4) 86 | MAP_NODE_INIT_STR(n5, k5) 87 | MAP_NODE_INIT_STR(n6, k6) 88 | MAP_NODE_INIT_STR(n7, k7) 89 | MAP_NODE_INIT_STR(n8, k8) 90 | MAP_NODE_INIT_STR(n9, k9) 91 | MAP_NODE_INIT_STR(n10, k10) 92 | ngx_map_node_t n11; 93 | static ngx_str_t k11 = ngx_string("k5"); 94 | ngx_memzero(&n11, sizeof(ngx_map_node_t)); 95 | n11.raw_key = (intptr_t) &k11; 96 | 97 | ngx_map_insert(&map, &n1, 0); 98 | ngx_map_insert(&map, &n2, 0); 99 | ngx_map_insert(&map, &n3, 0); 100 | ngx_map_insert(&map, &n4, 0); 101 | ngx_map_insert(&map, &n5, 0); 102 | ngx_map_insert(&map, &n6, 0); 103 | ngx_map_insert(&map, &n7, 0); 104 | ngx_map_insert(&map, &n8, 0); 105 | ngx_map_insert(&map, &n9, 0); 106 | ngx_map_insert(&map, &n10, 0); 107 | ngx_map_insert(&map, &n11, 0); 108 | 109 | NGX_TEST_INIT 110 | 111 | ngx_map_node_t *n; 112 | n = ngx_map_begin(&map); 113 | MAP_NODE_PRINT_KEY_STR(n) 114 | NGX_TEST_ISOK(&n1 == n) 115 | 116 | n = ngx_map_next(n); 117 | MAP_NODE_PRINT_KEY_STR(n) 118 | NGX_TEST_ISOK(&n2 == n) 119 | 120 | n = ngx_map_next(n); 121 | MAP_NODE_PRINT_KEY_STR(n) 122 | NGX_TEST_ISOK(&n3 == n) 123 | 124 | n = ngx_map_next(n); 125 | MAP_NODE_PRINT_KEY_STR(n) 126 | NGX_TEST_ISOK(&n4 == n) 127 | 128 | n = ngx_map_next(n); 129 | MAP_NODE_PRINT_KEY_STR(n) 130 | NGX_TEST_ISOK(&n5 == n) 131 | 132 | n = ngx_map_next(n); 133 | MAP_NODE_PRINT_KEY_STR(n) 134 | NGX_TEST_ISOK(&n6 == n) 135 | 136 | n = ngx_map_next(n); 137 | MAP_NODE_PRINT_KEY_STR(n) 138 | NGX_TEST_ISOK(&n7 == n) 139 | 140 | n = ngx_map_next(n); 141 | MAP_NODE_PRINT_KEY_STR(n) 142 | NGX_TEST_ISOK(&n8 == n) 143 | 144 | n = ngx_map_next(n); 145 | MAP_NODE_PRINT_KEY_STR(n) 146 | NGX_TEST_ISOK(&n9 == n) 147 | 148 | n = ngx_map_next(n); 149 | MAP_NODE_PRINT_KEY_STR(n) 150 | NGX_TEST_ISOK(&n10 == n) 151 | 152 | n = ngx_map_next(n); 153 | NGX_TEST_ISOK(NULL == n) 154 | 155 | n = ngx_map_rbegin(&map); 156 | MAP_NODE_PRINT_KEY_STR(n) 157 | NGX_TEST_ISOK(&n10 == n) 158 | 159 | n = ngx_map_prev(n); 160 | MAP_NODE_PRINT_KEY_STR(n) 161 | NGX_TEST_ISOK(&n9 == n) 162 | 163 | n = ngx_map_prev(n); 164 | MAP_NODE_PRINT_KEY_STR(n) 165 | NGX_TEST_ISOK(&n8 == n) 166 | 167 | n = ngx_map_prev(n); 168 | MAP_NODE_PRINT_KEY_STR(n) 169 | NGX_TEST_ISOK(&n7 == n) 170 | 171 | n = ngx_map_prev(n); 172 | MAP_NODE_PRINT_KEY_STR(n) 173 | NGX_TEST_ISOK(&n6 == n) 174 | 175 | n = ngx_map_prev(n); 176 | MAP_NODE_PRINT_KEY_STR(n) 177 | NGX_TEST_ISOK(&n5 == n) 178 | 179 | n = ngx_map_prev(n); 180 | MAP_NODE_PRINT_KEY_STR(n) 181 | NGX_TEST_ISOK(&n4 == n) 182 | 183 | n = ngx_map_prev(n); 184 | MAP_NODE_PRINT_KEY_STR(n) 185 | NGX_TEST_ISOK(&n3 == n) 186 | 187 | n = ngx_map_prev(n); 188 | MAP_NODE_PRINT_KEY_STR(n) 189 | NGX_TEST_ISOK(&n2 == n) 190 | 191 | n = ngx_map_prev(n); 192 | MAP_NODE_PRINT_KEY_STR(n) 193 | NGX_TEST_ISOK(&n1 == n) 194 | 195 | n = ngx_map_prev(n); 196 | NGX_TEST_ISOK(NULL == n) 197 | 198 | static ngx_str_t kk1 = ngx_string("k100"); 199 | NGX_TEST_ISOK(NULL == ngx_map_find(&map, (intptr_t) &kk1)) 200 | 201 | static ngx_str_t kk2 = ngx_string("k5"); 202 | NGX_TEST_ISOK(&n5 == ngx_map_find(&map, (intptr_t) &kk2)) 203 | 204 | ngx_map_insert(&map, &n11, 1); 205 | NGX_TEST_ISOK(&n11 == ngx_map_find(&map, (intptr_t) &kk2)) 206 | 207 | static ngx_str_t kk3 = ngx_string("k8"); 208 | ngx_map_delete(&map, (intptr_t) &kk3); 209 | NGX_TEST_ISOK(NULL == ngx_map_find(&map, (intptr_t) &kk3)) 210 | 211 | static ngx_str_t kk4 = ngx_string("k8"); 212 | ngx_map_insert(&map, &n8, 1); 213 | NGX_TEST_ISOK(&n8 == ngx_map_find(&map, (intptr_t) &kk4)) 214 | 215 | static ngx_str_t kk5 = ngx_string("k7"); 216 | NGX_TEST_ISOK(&n7 == ngx_map_find(&map, (intptr_t) &kk5)) 217 | 218 | r->headers_out.status = NGX_HTTP_OK; 219 | 220 | ngx_http_send_header(r); 221 | 222 | len = sizeof("TEST cases 4294967296, 4294967296 pass\n") - 1; 223 | b = ngx_create_temp_buf(r->pool, len); 224 | 225 | if (b == NULL) { 226 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 227 | } 228 | 229 | b->last = ngx_snprintf(b->last, len, "TEST cases %d, %d pass\n", 230 | count, pass); 231 | b->last_buf = 1; 232 | b->last_in_chain = 1; 233 | 234 | cl.buf = b; 235 | cl.next = NULL; 236 | 237 | return ngx_http_output_filter(r, &cl); 238 | } 239 | 240 | 241 | static char * 242 | ngx_map_test(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 243 | { 244 | ngx_http_core_loc_conf_t *clcf; 245 | 246 | clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); 247 | clcf->handler = ngx_map_test_handler; 248 | 249 | return NGX_CONF_OK; 250 | } 251 | 252 | -------------------------------------------------------------------------------- /ngx_map.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) AlexWoo(Wu Jie) wj19840501@gmail.com 3 | */ 4 | 5 | 6 | #include "ngx_map.h" 7 | 8 | 9 | static void 10 | ngx_map_rbtree_insert_value(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node, 11 | ngx_rbtree_node_t *sentinel) 12 | { 13 | ngx_rbtree_node_t **p; 14 | intptr_t *raw_key, *raw_key_temp; 15 | ngx_map_t **map; 16 | 17 | for (;;) { 18 | 19 | if (node->key < temp->key) { 20 | p = &temp->left; 21 | } else if (node->key > temp->key) { 22 | p = &temp->right; 23 | } else { 24 | raw_key = (intptr_t *)((char *) node 25 | + offsetof(ngx_map_node_t, raw_key)); 26 | raw_key_temp = (intptr_t *)((char *) temp 27 | + offsetof(ngx_map_node_t, raw_key)); 28 | map = (ngx_map_t **)((char *) node + offsetof(ngx_map_node_t, map)); 29 | 30 | switch ((*map)->cmp(*raw_key, *raw_key_temp)) { 31 | case -1: 32 | p = &temp->left; 33 | break; 34 | case 1: 35 | p = &temp->right; 36 | break; 37 | default: /* key is duplicate */ 38 | return; 39 | } 40 | } 41 | 42 | if (*p == sentinel) { 43 | break; 44 | } 45 | 46 | temp = *p; 47 | } 48 | 49 | *p = node; 50 | node->parent = temp; 51 | node->left = sentinel; 52 | node->right = sentinel; 53 | ngx_rbt_red(node); 54 | } 55 | 56 | void 57 | ngx_map_init(ngx_map_t *map, ngx_map_hash_pt hash, ngx_cmp_pt cmp) 58 | { 59 | ngx_rbtree_init(&map->rbtree, &map->sentinel, ngx_map_rbtree_insert_value); 60 | map->hash = hash; 61 | map->cmp = cmp; 62 | } 63 | 64 | ngx_map_node_t * 65 | ngx_map_begin(ngx_map_t *map) 66 | { 67 | ngx_rbtree_node_t *p; 68 | 69 | if (ngx_map_empty(map)) { 70 | return NULL; 71 | } 72 | 73 | p = map->rbtree.root; 74 | 75 | for (;;) { 76 | if (p->left == map->rbtree.sentinel) { 77 | break; 78 | } 79 | 80 | p = p->left; 81 | } 82 | 83 | return (ngx_map_node_t *) p; 84 | } 85 | 86 | ngx_map_node_t * 87 | ngx_map_rbegin(ngx_map_t *map) 88 | { 89 | ngx_rbtree_node_t *p; 90 | 91 | if (ngx_map_empty(map)) { 92 | return NULL; 93 | } 94 | 95 | p = map->rbtree.root; 96 | 97 | for (;;) { 98 | if (p->right == map->rbtree.sentinel) { 99 | break; 100 | } 101 | 102 | p = p->right; 103 | } 104 | 105 | return (ngx_map_node_t *) p; 106 | } 107 | 108 | ngx_map_node_t * 109 | ngx_map_next(ngx_map_node_t *n) 110 | { 111 | ngx_map_t *map; 112 | ngx_rbtree_node_t *p, *top; 113 | 114 | map = n->map; 115 | p = &n->rn; 116 | top = NULL; 117 | 118 | if (p->right != map->rbtree.sentinel) { 119 | // current node has right subtree 120 | top = p->right; 121 | } else { 122 | for (;;) { 123 | if (p == map->rbtree.root) { 124 | return NULL; 125 | } 126 | 127 | if (p->parent->left == p) { 128 | return (ngx_map_node_t *) p->parent; 129 | } 130 | 131 | // p->parent->right == p 132 | p = p->parent; 133 | } 134 | } 135 | 136 | // get the mininum node 137 | p = top; 138 | for (;;) { 139 | if (p->left == map->rbtree.sentinel) { 140 | break; 141 | } 142 | 143 | p = p->left; 144 | } 145 | 146 | return (ngx_map_node_t *) p; 147 | } 148 | 149 | ngx_map_node_t * 150 | ngx_map_prev(ngx_map_node_t *n) 151 | { 152 | ngx_map_t *map; 153 | ngx_rbtree_node_t *p, *top; 154 | 155 | map = n->map; 156 | p = &n->rn; 157 | top = NULL; 158 | 159 | if (p->left != map->rbtree.sentinel) { 160 | // current node has left subtree 161 | top = p->left; 162 | } else { 163 | for (;;) { 164 | if (p == map->rbtree.root) { 165 | return NULL; 166 | } 167 | 168 | if (p->parent->right == p) { 169 | return (ngx_map_node_t *) p->parent; 170 | } 171 | 172 | // p->parent->left == p 173 | p = p->parent; 174 | } 175 | } 176 | 177 | // get the maximum node 178 | p = top; 179 | for (;;) { 180 | if (p->right == map->rbtree.sentinel) { 181 | break; 182 | } 183 | 184 | p = p->right; 185 | } 186 | 187 | return (ngx_map_node_t *) p; 188 | } 189 | 190 | void 191 | ngx_map_insert(ngx_map_t *map, ngx_map_node_t *node, ngx_flag_t covered) 192 | { 193 | ngx_map_node_t *n; 194 | 195 | node->rn.key = map->hash(node->raw_key); 196 | node->map = map; 197 | 198 | n = ngx_map_find(map, node->raw_key); 199 | if (n == NULL) { 200 | ngx_rbtree_insert(&map->rbtree, &node->rn); 201 | } else if (covered) { 202 | ngx_map_delete(map, node->raw_key); 203 | ngx_rbtree_insert(&map->rbtree, &node->rn); 204 | } 205 | } 206 | 207 | void 208 | ngx_map_delete(ngx_map_t *map, intptr_t key) 209 | { 210 | ngx_map_node_t *node; 211 | 212 | node = ngx_map_find(map, key); 213 | if (node) { 214 | ngx_rbtree_delete(&map->rbtree, &node->rn); 215 | } 216 | } 217 | 218 | ngx_map_node_t * 219 | ngx_map_find(ngx_map_t *map, intptr_t key) 220 | { 221 | ngx_rbtree_node_t *p; 222 | ngx_rbtree_key_t k; 223 | intptr_t *key_temp; 224 | 225 | if (ngx_map_empty(map)) { 226 | return NULL; 227 | } 228 | 229 | k = map->hash(key); 230 | p = map->rbtree.root; 231 | 232 | for (;;) { 233 | if (k < p->key) { 234 | p = p->left; 235 | } else if (k > p->key) { 236 | p = p->right; 237 | } else { 238 | key_temp = (intptr_t *)((char *) p 239 | + offsetof(ngx_map_node_t, raw_key)); 240 | 241 | switch (map->cmp(key, *key_temp)) { 242 | case -1: 243 | p = p->left; 244 | break; 245 | case 1: 246 | p = p->right; 247 | break; 248 | case 0: 249 | return (ngx_map_node_t *) p; 250 | } 251 | } 252 | 253 | if (p == map->rbtree.sentinel) { 254 | return NULL; 255 | } 256 | } 257 | } 258 | 259 | 260 | /* ngx_str_t */ 261 | ngx_rbtree_key_t 262 | ngx_map_hash_str(intptr_t key) 263 | { 264 | ngx_str_t *k; 265 | 266 | k = (ngx_str_t *) key; 267 | 268 | return ngx_hash_key(k->data, k->len); 269 | } 270 | 271 | int 272 | ngx_cmp_str(intptr_t key1, intptr_t key2) 273 | { 274 | ngx_str_t *k1, *k2; 275 | ngx_int_t rc; 276 | 277 | k1 = (ngx_str_t *) key1; 278 | k2 = (ngx_str_t *) key2; 279 | 280 | rc = ngx_memn2cmp(k1->data, k2->data, k1->len, k2->len); 281 | 282 | if (rc < 0) { 283 | return -1; 284 | } else if (rc > 0) { 285 | return 1; 286 | } else { 287 | return 0; 288 | } 289 | } 290 | 291 | /* ngx_uint_t */ 292 | ngx_rbtree_key_t 293 | ngx_map_hash_uint(intptr_t key) 294 | { 295 | return (ngx_rbtree_key_t) key; 296 | } 297 | 298 | int 299 | ngx_cmp_uint(intptr_t key1, intptr_t key2) 300 | { 301 | if ((ngx_uint_t) key1 < (ngx_uint_t) key2) { 302 | return -1; 303 | } else if ((ngx_uint_t) key1 > (ngx_uint_t) key2) { 304 | return 1; 305 | } else { 306 | return 0; 307 | } 308 | } 309 | 310 | /* ngx_int_t */ 311 | ngx_rbtree_key_t 312 | ngx_map_hash_int(intptr_t key) 313 | { 314 | return (ngx_rbtree_key_t) key; 315 | } 316 | 317 | int 318 | ngx_cmp_int(intptr_t key1, intptr_t key2) 319 | { 320 | if ((ngx_int_t) key1 < (ngx_int_t) key2) { 321 | return -1; 322 | } else if ((ngx_int_t) key1 > (ngx_int_t) key2) { 323 | return 1; 324 | } else { 325 | return 0; 326 | } 327 | } 328 | -------------------------------------------------------------------------------- /ngx_event_resolver.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) AlexWoo(Wu Jie) wj19840501@gmail.com 3 | */ 4 | 5 | 6 | #include "ngx_event_resolver.h" 7 | 8 | 9 | static void *ngx_event_resolver_create_conf(ngx_cycle_t *cycle); 10 | static char *ngx_event_resolver_init_conf(ngx_cycle_t *cycle, void *conf); 11 | 12 | static char *ngx_event_resolver(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); 13 | 14 | 15 | typedef struct ngx_event_resolver_ctx_s ngx_event_resolver_ctx_t; 16 | 17 | struct ngx_event_resolver_ctx_s { 18 | ngx_event_resolver_handler_pt handler; 19 | void *data; 20 | ngx_event_resolver_ctx_t *next; 21 | }; 22 | 23 | typedef struct { 24 | ngx_msec_t resolver_timeout; 25 | ngx_resolver_t *resolver; 26 | ngx_event_resolver_ctx_t *free_ctx; 27 | 28 | ngx_uint_t nalloc; 29 | ngx_uint_t nfree; 30 | } ngx_event_resolver_conf_t; 31 | 32 | 33 | static ngx_str_t event_resolver_name = ngx_string("event_resolver"); 34 | 35 | 36 | static ngx_command_t ngx_event_resolver_commands[] = { 37 | 38 | { ngx_string("resolver"), 39 | NGX_EVENT_CONF|NGX_CONF_1MORE, 40 | ngx_event_resolver, 41 | 0, 42 | 0, 43 | NULL }, 44 | 45 | { ngx_string("resolver_timeout"), 46 | NGX_EVENT_CONF|NGX_CONF_TAKE1, 47 | ngx_conf_set_msec_slot, 48 | 0, 49 | offsetof(ngx_event_resolver_conf_t, resolver_timeout), 50 | NULL }, 51 | 52 | ngx_null_command 53 | }; 54 | 55 | 56 | ngx_event_module_t ngx_event_resolver_module_ctx = { 57 | &event_resolver_name, 58 | ngx_event_resolver_create_conf, /* create configuration */ 59 | ngx_event_resolver_init_conf, /* init configuration */ 60 | 61 | { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL } 62 | }; 63 | 64 | 65 | /* this module use ngx_cycle->log */ 66 | ngx_module_t ngx_event_resolver_module = { 67 | NGX_MODULE_V1, 68 | &ngx_event_resolver_module_ctx, /* module context */ 69 | ngx_event_resolver_commands, /* module directives */ 70 | NGX_EVENT_MODULE, /* module type */ 71 | NULL, /* init master */ 72 | NULL, /* init module */ 73 | NULL, /* init process */ 74 | NULL, /* init thread */ 75 | NULL, /* exit thread */ 76 | NULL, /* exit process */ 77 | NULL, /* exit master */ 78 | NGX_MODULE_V1_PADDING 79 | }; 80 | 81 | 82 | static void * 83 | ngx_event_resolver_create_conf(ngx_cycle_t *cycle) 84 | { 85 | ngx_event_resolver_conf_t *conf; 86 | 87 | conf = ngx_pcalloc(cycle->pool, sizeof(ngx_event_resolver_conf_t)); 88 | if (conf == NULL) { 89 | return NULL; 90 | } 91 | 92 | conf->resolver_timeout = NGX_CONF_UNSET_MSEC; 93 | 94 | return conf; 95 | } 96 | 97 | static char * 98 | ngx_event_resolver_init_conf(ngx_cycle_t *cycle, void *conf) 99 | { 100 | ngx_event_resolver_conf_t *ercf = conf; 101 | 102 | ngx_conf_init_msec_value(ercf->resolver_timeout, 60000); 103 | 104 | return NGX_CONF_OK; 105 | } 106 | 107 | static char * 108 | ngx_event_resolver(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 109 | { 110 | ngx_event_resolver_conf_t *ercf = conf; 111 | 112 | ngx_str_t *value; 113 | 114 | if (ercf->resolver) { 115 | return "is duplicate"; 116 | } 117 | 118 | value = cf->args->elts; 119 | 120 | ercf->resolver = ngx_resolver_create(cf, &value[1], cf->args->nelts - 1); 121 | if (ercf->resolver == NULL) { 122 | return NGX_CONF_ERROR; 123 | } 124 | 125 | return NGX_CONF_OK; 126 | } 127 | 128 | 129 | static ngx_event_resolver_ctx_t * 130 | ngx_event_resolver_get_ctx() 131 | { 132 | ngx_event_resolver_ctx_t *ctx; 133 | ngx_event_resolver_conf_t *ercf; 134 | 135 | ercf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_event_resolver_module); 136 | 137 | ctx = ercf->free_ctx; 138 | if (ctx == NULL) { 139 | ctx = ngx_pcalloc(ngx_cycle->pool, sizeof(ngx_event_resolver_ctx_t)); 140 | ++ercf->nalloc; 141 | } else { 142 | ercf->free_ctx = ctx->next; 143 | ctx->next = NULL; 144 | --ercf->nfree; 145 | } 146 | 147 | return ctx; 148 | } 149 | 150 | static void 151 | ngx_event_resolver_put_ctx(ngx_event_resolver_ctx_t *ctx) 152 | { 153 | ngx_event_resolver_conf_t *ercf; 154 | 155 | ercf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_event_resolver_module); 156 | 157 | ctx->next = ercf->free_ctx; 158 | ercf->free_ctx = ctx; 159 | ++ercf->nfree; 160 | } 161 | 162 | static void 163 | ngx_event_resolver_handler(ngx_resolver_ctx_t *ctx) 164 | { 165 | ngx_event_resolver_ctx_t *erctx; 166 | 167 | erctx = ctx->data; 168 | 169 | if (ctx->state) { 170 | ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, 171 | "event resolver, domain '%V' could not be resolved (%i: %s)", 172 | &ctx->name, ctx->state, ngx_resolver_strerror(ctx->state)); 173 | erctx->handler(erctx->data, NULL, 0); 174 | 175 | goto failed; 176 | } 177 | 178 | erctx->handler(erctx->data, ctx->addrs, ctx->naddrs); 179 | 180 | failed: 181 | ngx_resolve_name_done(ctx); 182 | ngx_event_resolver_put_ctx(erctx); 183 | } 184 | 185 | void 186 | ngx_event_resolver_start_resolver(ngx_str_t *domain, 187 | ngx_event_resolver_handler_pt h, void *data) 188 | { 189 | ngx_event_resolver_conf_t *ercf; 190 | ngx_event_resolver_ctx_t *erctx; 191 | ngx_resolver_ctx_t *ctx, temp; 192 | 193 | ercf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_event_resolver_module); 194 | 195 | ngx_log_debug1(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, "event resolver, " 196 | "start resolv domain '%V'", domain); 197 | 198 | if (ercf->resolver == NULL) { 199 | ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "event resolver, " 200 | "resolver does not configured"); 201 | h(data, NULL, 0); 202 | 203 | return; 204 | } 205 | 206 | temp.name = *domain; 207 | 208 | erctx = ngx_event_resolver_get_ctx(); 209 | if (erctx == NULL) { 210 | return; 211 | } 212 | erctx->handler = h; 213 | erctx->data = data; 214 | 215 | ctx = ngx_resolve_start(ercf->resolver, &temp); 216 | if (ctx == NULL) { 217 | goto failed; 218 | } 219 | 220 | if (ctx == NGX_NO_RESOLVER) { 221 | ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "event resolver, " 222 | "no resolver defined to resolv %V", domain); 223 | goto failed; 224 | } 225 | 226 | ctx->name = *domain; 227 | ctx->handler = ngx_event_resolver_handler; 228 | ctx->data = erctx; 229 | ctx->timeout = ercf->resolver_timeout; 230 | 231 | if (ngx_resolve_name(ctx) != NGX_OK) { 232 | ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "event resolver, " 233 | "resolv %V failed", domain); 234 | 235 | goto failed; 236 | } 237 | 238 | return; 239 | 240 | failed: 241 | h(data, NULL, 0); 242 | 243 | if (ctx == NULL || ctx == NGX_NO_RESOLVER) { 244 | ngx_resolve_name_done(ctx); 245 | ngx_event_resolver_put_ctx(erctx); 246 | } 247 | } 248 | 249 | ngx_chain_t * 250 | ngx_event_resolver_state(ngx_http_request_t *r) 251 | { 252 | ngx_event_resolver_conf_t *ercf; 253 | ngx_chain_t *cl; 254 | ngx_buf_t *b; 255 | size_t len; 256 | 257 | ercf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_event_resolver_module); 258 | 259 | len = sizeof("##########event resolver state##########\n") - 1 260 | + sizeof("ngx_event_resolver alloc: \n") - 1 + NGX_OFF_T_LEN 261 | + sizeof("ngx_event_resolver free: \n") - 1 + NGX_OFF_T_LEN; 262 | 263 | cl = ngx_alloc_chain_link(r->pool); 264 | if (cl == NULL) { 265 | return NULL; 266 | } 267 | cl->next = NULL; 268 | 269 | b = ngx_create_temp_buf(r->pool, len); 270 | if (b == NULL) { 271 | return NULL; 272 | } 273 | cl->buf = b; 274 | 275 | b->last = ngx_snprintf(b->last, len, 276 | "##########event resolver state##########\n" 277 | "ngx_event_resolver alloc: %ui\nngx_event_resolver free: %ui\n", 278 | ercf->nalloc, ercf->nfree); 279 | 280 | return cl; 281 | } 282 | -------------------------------------------------------------------------------- /doc/ngx-dynamic-conf-module.md: -------------------------------------------------------------------------------- 1 | # Module ngx-dynamic-conf-module 2 | --- 3 | ## Instructions 4 | 5 | System will reload conf when nginx dynamic config file change. Developer can use this module to reload file without reload nginx worker. 6 | 7 | Now it support NGX\_CORE\_MODULE and NGX\_HTTP\_MODULE 8 | 9 | ## Directives 10 | 11 | Syntax : dynamic_conf dynamic_file time; 12 | Default : - 13 | Context : main 14 | 15 | Set dynamic config file and interval system checked file changed. 16 | 17 | Syntax : dynamic_log log_file level; 18 | Default : - 19 | Context : main 20 | 21 | Set dynamic conf load log file and log level. If not configured, use cycle log as default. 22 | 23 | Example: 24 | 25 | dynamic_conf conf/nginx_dynamic.conf 10; 26 | dynamic_log logs/error_dynamic.log info; 27 | 28 | ## API 29 | 30 | ### MAIN dynamic conf 31 | 32 | **header file** 33 | 34 | For using this API, You should include the header file as below: 35 | 36 | #include "ngx_dynamic_conf.h" 37 | 38 | **dynamic module define** 39 | 40 | typedef struct { 41 | ngx_str_t name; 42 | void *(*create_conf)(ngx_conf_t *cf); 43 | char *(*init_conf)(ngx_conf_t *cf, void *conf); 44 | } ngx_dynamic_core_module_t; 45 | 46 | dynamic conf module define as below 47 | 48 | ngx_module_t ngx_test_module = { 49 | NGX_MODULE_V1, 50 | &ngx_test_module_ctx, /* module context */ 51 | ngx_test_commands, /* module directives */ 52 | NGX_CORE_MODULE, /* module type */ 53 | NULL, /* init master */ 54 | NULL, /* init module */ 55 | NULL, /* init process */ 56 | NULL, /* init thread */ 57 | NULL, /* exit thread */ 58 | NULL, /* exit process */ 59 | NULL, /* exit master */ 60 | (uintptr_t) &ngx_test_module_dctx, /* module dynamic context */ 61 | (uintptr_t) ngx_test_dcommands, /* module dynamic directives */ 62 | NGX_MODULE_V1_DYNAMIC_PADDING 63 | }; 64 | 65 | **module dynamic context** struct define as above, **module dynamic directives** define use ngx\_command\_t. Use ngx\_dynamic\_core\_test\_module define in t/ngx\_dynamic\_conf\_test\_module.c as reference 66 | 67 | **ngx\_dynamic\_conf\_parse** 68 | 69 | ngx_int_t ngx_dynamic_conf_parse(ngx_conf_t *cf, unsigned init) 70 | 71 | - return value: 72 | 73 | - return NGX\_OK for successd, NGX\_ERROR for failed 74 | 75 | - paras: 76 | 77 | - cf : ngx\_conf\_t passed from ngx\_dynamic\_conf\_load_conf 78 | - init : only ngx\_dynamic\_conf\_load\_conf set 1, otherwise set 0 79 | 80 | This interface is supported for other dynamic conf module, such as ngx\_conf\_parse 81 | 82 | **ngx\_dynamic\_regex\_compile** 83 | 84 | typedef struct { 85 | ngx_regex_t *regex; 86 | ngx_str_t name; 87 | } ngx_dynamic_regex_t; 88 | 89 | ngx_dynamic_regex_t *ngx_dynamic_regex_compile(ngx_conf_t *cf, 90 | ngx_regex_compile_t *rc); 91 | 92 | - return value: 93 | 94 | - return regex context 95 | 96 | - paras: 97 | 98 | - cf: ngx\_conf\_t passed in dynamic cmd handler 99 | - rc: regex options 100 | 101 | compile regex 102 | 103 | **ngx\_get\_dconf** 104 | 105 | void *ngx_get_dconf(ngx_module_t *m) 106 | 107 | return NGX\_CORE\_MODULE dynamic config for module 108 | 109 | ### HTTP dynamic conf 110 | 111 | **header file** 112 | 113 | For using this API, You should include the header file as below: 114 | 115 | #include "ngx_dynamic_conf.h" 116 | 117 | **dynamic module define** 118 | 119 | dynamic conf module define is same as MAIN dynamic conf 120 | 121 | http dynamic conf context define as below: 122 | 123 | typedef struct { 124 | void *(*create_main_conf)(ngx_conf_t *cf); 125 | char *(*init_main_conf)(ngx_conf_t *cf, void *conf); 126 | 127 | void *(*create_srv_conf)(ngx_conf_t *cf); 128 | char *(*init_srv_conf)(ngx_conf_t *cf, void *conf); 129 | 130 | void *(*create_loc_conf)(ngx_conf_t *cf); 131 | char *(*init_loc_conf)(ngx_conf_t *cf, void *conf); 132 | } ngx_http_dynamic_module_t; 133 | 134 | **notice:** http dynamic conf do not support merge 135 | 136 | **ngx\_http\_get\_module\_main\_dconf** 137 | 138 | void *ngx_http_get_module_main_dconf(ngx_http_request_t *r, ngx_module_t *m); 139 | 140 | return http request main dynamic conf for module m 141 | 142 | **ngx\_http\_get\_module\_srv\_dconf** 143 | 144 | void *ngx_http_get_module_srv_dconf(ngx_http_request_t *r, ngx_module_t *m); 145 | 146 | return http request srv dynamic conf for module m 147 | 148 | **ngx\_http\_get\_module\_loc\_dconf** 149 | 150 | void *ngx_http_get_module_loc_dconf(ngx_http_request_t *r, ngx_module_t *m); 151 | 152 | return http request loc dynamic conf for module m 153 | 154 | ## Build 155 | 156 | cd to NGINX source directory & run this: 157 | 158 | ./configure --add-module=/path/to/nginx-toolkit-module/ 159 | make && make install 160 | 161 | ## Example 162 | 163 | See 164 | 165 | - t/ngx\_dynamic\_conf\_test\_module.c as MAIN conf for usage of dynamic conf 166 | - t/ngx\_http\_dynamic\_test\_module.c as HTTP conf for usage of http dynamic conf 167 | 168 | **Build:** 169 | 170 | ./configure --with-debug --add-module=/path/to/nginx-toolkit-module/ --add-module=/path/to/nginx-toolkit-module/t 171 | make && make install 172 | 173 | **Configure:** 174 | 175 | dynamic_conf conf/nginx_dynamic.conf 10; 176 | dynamic_log logs/error_dynamic.log info; 177 | 178 | http { 179 | 180 | ... 181 | 182 | server { 183 | 184 | ... 185 | 186 | location /dynamic_conf_test/ { 187 | dynamic_conf_test; 188 | } 189 | } 190 | } 191 | 192 | **Dynamic Configure:** 193 | 194 | dynamic_test_i 200; 195 | dynamic_test_s hello_world; 196 | 197 | http { 198 | main_int 1000; 199 | main_str gogogo; 200 | 201 | #defult server 202 | server { 203 | srv_int 1; 204 | srv_str default; 205 | } 206 | 207 | #wildcard_head 208 | server { 209 | srv_int 2; 210 | srv_str wildcard_head; 211 | serverid baidu; 212 | server_name *.baidu.com; 213 | } 214 | 215 | #wildcard_tail 216 | server { 217 | srv_int 3; 218 | srv_str wildcard_tail; 219 | serverid google; 220 | server_name www.google.*; 221 | } 222 | 223 | #hash 224 | server { 225 | srv_int 4; 226 | srv_str hash; 227 | serverid sina; 228 | server_name sports.sina.com.cn; 229 | 230 | location = / { 231 | loc_int 1; 232 | loc_str =/; 233 | } 234 | 235 | location / { 236 | loc_int 2; 237 | loc_str /; 238 | } 239 | 240 | location ^~ /test1/ { 241 | loc_int 3; 242 | loc_str ^~/test1/; 243 | } 244 | 245 | location ~* \.(gif|jpg|jpeg)$ { 246 | loc_int 4; 247 | loc_str ~*\.(gif|jpg|jpeg)$; 248 | } 249 | 250 | location /test { 251 | loc_int 5; 252 | loc_str /test; 253 | } 254 | } 255 | 256 | #pcre 257 | server { 258 | srv_int 5; 259 | srv_str pcre; 260 | serverid test; 261 | server_name ~^flv(?!.*(dl\.))[A-Za-z0-9]*\.test\.com$; 262 | } 263 | 264 | #multi 265 | server { 266 | srv_int 6; 267 | srv_str multi; 268 | serverid others; 269 | server_name ~^flv(?!.*(dl\.))[A-Za-z0-9]*\.haha\.com$ www.sohu.com; 270 | server_name *.qq.com; 271 | } 272 | } 273 | 274 | **Test:** 275 | 276 | - Main for dynamic config 277 | 278 | get conf configured in dynamic config file for test module 279 | 280 | curl -v 'http://127.0.0.1/dynamic_conf_test/test' 281 | 282 | change config in dynamic config, the test api will return new config value after dynamic conf refresh 283 | 284 | - Main for http 285 | 286 | curl -v 'http://127.0.0.1/' 287 | 288 | change config in http block of dynamic config, the test api will return new config value after dynamic conf refresh 289 | 290 | - Server for http 291 | 292 | - defult server 293 | 294 | curl -v 'http://127.0.0.1/http_dynamic_test/test' 295 | curl -v -H 'Host: github.com' 'http://127.0.0.1/http_dynamic_test/test' 296 | 297 | - wildcard_head 298 | 299 | curl -v -H 'Host: map.baidu.com' 'http://127.0.0.1/http_dynamic_test/test' 300 | 301 | - wildcard_tail 302 | 303 | curl -v -H 'Host: www.google.co.jp' 'http://127.0.0.1/http_dynamic_test/test' 304 | 305 | - hash 306 | 307 | curl -v -H 'Host: sports.sina.com.cn' 'http://127.0.0.1/http_dynamic_test/test' 308 | 309 | - pcre 310 | 311 | curl -v -H 'Host: flvdl7a8e4223.test.com' 'http://127.0.0.1/http_dynamic_test/test' 312 | 313 | - multi 314 | 315 | curl -v -H 'Host: flvdl7a8e4223.haha.com' 'http://127.0.0.1/http_dynamic_test/test' 316 | curl -v -H 'Host: www.sohu.com' 'http://127.0.0.1/http_dynamic_test/test' 317 | curl -v -H 'Host: v.qq.com' 'http://127.0.0.1/http_dynamic_test/test' 318 | 319 | - Location for http 320 | 321 | - no location 322 | 323 | curl -v -H 'Host: flvdl7a8e4223.haha.com' 'http://127.0.0.1/' 324 | 325 | - location = / 326 | 327 | curl -v -H 'Host: sports.sina.com.cn' 'http://127.0.0.1/' 328 | 329 | - location / 330 | 331 | curl -v -H 'Host: sports.sina.com.cn' 'http://127.0.0.1/t' 332 | 333 | - location ^~ /test1/ 334 | 335 | curl -v -H 'Host: sports.sina.com.cn' 'http://127.0.0.1/test1/123' 336 | 337 | - ~* \.(gif|jpg|jpeg)$ 338 | 339 | curl -v -H 'Host: sports.sina.com.cn' 'http://127.0.0.1/test/123.gif' 340 | 341 | - /test 342 | 343 | curl -v -H 'Host: sports.sina.com.cn' 'http://127.0.0.1/test/123' 344 | -------------------------------------------------------------------------------- /t/ngx_http_dynamic_test_module.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "ngx_dynamic_conf.h" 5 | #include "ngx_http_dynamic.h" 6 | 7 | 8 | static char *ngx_http_dynamic_test(ngx_conf_t *cf, ngx_command_t *cmd, 9 | void *conf); 10 | 11 | static void *ngx_http_dynamic_test_create_main_conf(ngx_conf_t *cf); 12 | static char *ngx_http_dynamic_test_init_main_conf(ngx_conf_t *cf, void *conf); 13 | static void *ngx_http_dynamic_test_create_srv_conf(ngx_conf_t *cf); 14 | static char *ngx_http_dynamic_test_init_srv_conf(ngx_conf_t *cf, void *conf); 15 | static void *ngx_http_dynamic_test_create_loc_conf(ngx_conf_t *cf); 16 | static char *ngx_http_dynamic_test_init_loc_conf(ngx_conf_t *cf, void *conf); 17 | 18 | #define MAXBUFSIZE 4096 19 | 20 | typedef struct { 21 | ngx_uint_t mi; 22 | ngx_str_t ms; 23 | } ngx_http_dynamic_test_main_conf_t; 24 | 25 | typedef struct { 26 | ngx_uint_t si; 27 | ngx_str_t ss; 28 | } ngx_http_dynamic_test_srv_conf_t; 29 | 30 | typedef struct { 31 | ngx_uint_t li; 32 | ngx_str_t ls; 33 | } ngx_http_dynamic_test_loc_conf_t; 34 | 35 | 36 | static ngx_command_t ngx_http_dynamic_test_commands[] = { 37 | 38 | { ngx_string("http_dynamic_test"), 39 | NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS, 40 | ngx_http_dynamic_test, 41 | 0, 42 | 0, 43 | NULL }, 44 | 45 | ngx_null_command 46 | }; 47 | 48 | static ngx_http_module_t ngx_http_dynamic_test_module_ctx = { 49 | NULL, /* preconfiguration */ 50 | NULL, /* postconfiguration */ 51 | 52 | NULL, /* create main configuration */ 53 | NULL, /* init main configuration */ 54 | 55 | NULL, /* create server configuration */ 56 | NULL, /* merge server configuration */ 57 | 58 | NULL, /* create location configuration */ 59 | NULL /* merge location configuration */ 60 | }; 61 | 62 | static ngx_command_t ngx_http_dynamic_test_dcommands[] = { 63 | 64 | { ngx_string("main_int"), 65 | NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, 66 | ngx_conf_set_num_slot, 67 | 0, 68 | offsetof(ngx_http_dynamic_test_main_conf_t, mi), 69 | NULL }, 70 | 71 | { ngx_string("main_str"), 72 | NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, 73 | ngx_conf_set_str_slot, 74 | 0, 75 | offsetof(ngx_http_dynamic_test_main_conf_t, ms), 76 | NULL }, 77 | 78 | { ngx_string("srv_int"), 79 | NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, 80 | ngx_conf_set_num_slot, 81 | 0, 82 | offsetof(ngx_http_dynamic_test_srv_conf_t, si), 83 | NULL }, 84 | 85 | { ngx_string("srv_str"), 86 | NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, 87 | ngx_conf_set_str_slot, 88 | 0, 89 | offsetof(ngx_http_dynamic_test_srv_conf_t, ss), 90 | NULL }, 91 | 92 | { ngx_string("loc_int"), 93 | NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 94 | ngx_conf_set_num_slot, 95 | 0, 96 | offsetof(ngx_http_dynamic_test_loc_conf_t, li), 97 | NULL }, 98 | 99 | { ngx_string("loc_str"), 100 | NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 101 | ngx_conf_set_str_slot, 102 | 0, 103 | offsetof(ngx_http_dynamic_test_loc_conf_t, ls), 104 | NULL }, 105 | 106 | ngx_null_command 107 | }; 108 | 109 | static ngx_http_dynamic_module_t ngx_http_dynamic_test_module_dctx = { 110 | ngx_http_dynamic_test_create_main_conf, /* create main configuration */ 111 | ngx_http_dynamic_test_init_main_conf, /* init main configuration */ 112 | 113 | ngx_http_dynamic_test_create_srv_conf, /* create server configuration */ 114 | ngx_http_dynamic_test_init_srv_conf, /* init server configuration */ 115 | 116 | ngx_http_dynamic_test_create_loc_conf, /* create location configuration */ 117 | ngx_http_dynamic_test_init_loc_conf /* init location configuration */ 118 | }; 119 | 120 | ngx_module_t ngx_http_dynamic_test_module = { 121 | NGX_MODULE_V1, 122 | &ngx_http_dynamic_test_module_ctx, /* module context */ 123 | ngx_http_dynamic_test_commands, /* module directives */ 124 | NGX_HTTP_MODULE, /* module type */ 125 | NULL, /* init master */ 126 | NULL, /* init module */ 127 | NULL, /* init process */ 128 | NULL, /* init thread */ 129 | NULL, /* exit thread */ 130 | NULL, /* exit process */ 131 | NULL, /* exit master */ 132 | (uintptr_t) &ngx_http_dynamic_test_module_dctx, /* module dynamic context */ 133 | (uintptr_t) ngx_http_dynamic_test_dcommands, /* module dynamic directives */ 134 | NGX_MODULE_V1_DYNAMIC_PADDING 135 | }; 136 | 137 | 138 | static void * 139 | ngx_http_dynamic_test_create_main_conf(ngx_conf_t *cf) 140 | { 141 | ngx_http_dynamic_test_main_conf_t *conf; 142 | 143 | conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_dynamic_test_main_conf_t)); 144 | if (conf == NULL) { 145 | return NULL; 146 | } 147 | 148 | conf->mi = NGX_CONF_UNSET_UINT; 149 | 150 | return conf; 151 | } 152 | 153 | static char * 154 | ngx_http_dynamic_test_init_main_conf(ngx_conf_t *cf, void *conf) 155 | { 156 | ngx_http_dynamic_test_main_conf_t *hdtmcf; 157 | 158 | hdtmcf = conf; 159 | 160 | ngx_conf_init_uint_value(hdtmcf->mi, 100); 161 | 162 | if (hdtmcf->ms.len == 0) { 163 | ngx_str_set(&hdtmcf->ms, "test for ms"); 164 | } 165 | 166 | return NGX_CONF_OK; 167 | } 168 | 169 | static void * 170 | ngx_http_dynamic_test_create_srv_conf(ngx_conf_t *cf) 171 | { 172 | ngx_http_dynamic_test_srv_conf_t *conf; 173 | 174 | conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_dynamic_test_srv_conf_t)); 175 | if (conf == NULL) { 176 | return NULL; 177 | } 178 | 179 | conf->si = NGX_CONF_UNSET_UINT; 180 | 181 | return conf; 182 | } 183 | 184 | static char * 185 | ngx_http_dynamic_test_init_srv_conf(ngx_conf_t *cf, void *conf) 186 | { 187 | ngx_http_dynamic_test_srv_conf_t *hdtscf; 188 | 189 | hdtscf = conf; 190 | 191 | ngx_conf_init_uint_value(hdtscf->si, 100); 192 | 193 | if (hdtscf->ss.len == 0) { 194 | ngx_str_set(&hdtscf->ss, "test for ss"); 195 | } 196 | 197 | return NGX_CONF_OK; 198 | } 199 | 200 | static void * 201 | ngx_http_dynamic_test_create_loc_conf(ngx_conf_t *cf) 202 | { 203 | ngx_http_dynamic_test_loc_conf_t *conf; 204 | 205 | conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_dynamic_test_loc_conf_t)); 206 | if (conf == NULL) { 207 | return NULL; 208 | } 209 | 210 | conf->li = NGX_CONF_UNSET_UINT; 211 | 212 | return conf; 213 | } 214 | 215 | static char * 216 | ngx_http_dynamic_test_init_loc_conf(ngx_conf_t *cf, void *conf) 217 | { 218 | ngx_http_dynamic_test_loc_conf_t *hdtlcf; 219 | 220 | hdtlcf = conf; 221 | 222 | ngx_conf_init_uint_value(hdtlcf->li, 100); 223 | 224 | if (hdtlcf->ls.len == 0) { 225 | ngx_str_set(&hdtlcf->ls, "test for ls"); 226 | } 227 | 228 | return NGX_CONF_OK; 229 | } 230 | 231 | static ngx_int_t 232 | ngx_http_dynamic_test_handler(ngx_http_request_t *r) 233 | { 234 | ngx_chain_t cl; 235 | ngx_buf_t *b; 236 | ngx_http_dynamic_test_main_conf_t *hdtmcf; 237 | ngx_http_dynamic_test_srv_conf_t *hdtscf; 238 | ngx_http_dynamic_test_loc_conf_t *hdtlcf; 239 | 240 | ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "http dynamic test handler"); 241 | 242 | b = ngx_create_temp_buf(r->pool, MAXBUFSIZE); 243 | 244 | if (b == NULL) { 245 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 246 | } 247 | 248 | hdtmcf = ngx_http_get_module_main_dconf(r, &ngx_http_dynamic_test_module); 249 | if (hdtmcf == NULL) { 250 | ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, 251 | "dynamic conf test handler, dynamic main conf not configured"); 252 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 253 | } 254 | 255 | hdtscf = ngx_http_get_module_srv_dconf(r, &ngx_http_dynamic_test_module); 256 | if (hdtscf == NULL) { 257 | ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, 258 | "dynamic conf test handler, dynamic srv conf not configured"); 259 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 260 | } 261 | 262 | hdtlcf = ngx_http_get_module_loc_dconf(r, &ngx_http_dynamic_test_module); 263 | if (hdtlcf == NULL) { 264 | ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, 265 | "dynamic conf test handler, dynamic loc conf not configured"); 266 | } 267 | 268 | r->headers_out.status = NGX_HTTP_OK; 269 | 270 | ngx_http_send_header(r); 271 | 272 | b->last = ngx_snprintf(b->last, MAXBUFSIZE, 273 | "dynamic core test mi:%ui ms:%V\n", hdtmcf->mi, &hdtmcf->ms); 274 | b->last = ngx_snprintf(b->last, MAXBUFSIZE, 275 | "dynamic core test si:%ui ss:%V\n", hdtscf->si, &hdtscf->ss); 276 | if (hdtlcf) { 277 | b->last = ngx_snprintf(b->last, MAXBUFSIZE, 278 | "dynamic core test li:%ui ls:%V\n", hdtlcf->li, &hdtlcf->ls); 279 | } 280 | b->last_buf = 1; 281 | b->last_in_chain = 1; 282 | 283 | cl.buf = b; 284 | cl.next = NULL; 285 | 286 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "send body"); 287 | 288 | return ngx_http_output_filter(r, &cl); 289 | } 290 | 291 | static char * 292 | ngx_http_dynamic_test(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 293 | { 294 | ngx_http_core_loc_conf_t *clcf; 295 | 296 | clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); 297 | clcf->handler = ngx_http_dynamic_test_handler; 298 | 299 | return NGX_CONF_OK; 300 | } 301 | -------------------------------------------------------------------------------- /t/ngx_toolkit_misc_test_module.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "ngx_toolkit_misc.h" 5 | #include "ngx_test_macro.h" 6 | 7 | 8 | static char *ngx_toolkit_misc_test(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); 9 | 10 | 11 | static ngx_command_t ngx_toolkit_misc_test_commands[] = { 12 | 13 | { ngx_string("toolkit_misc_test"), 14 | NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS, 15 | ngx_toolkit_misc_test, 16 | 0, 17 | 0, 18 | NULL }, 19 | 20 | ngx_null_command 21 | }; 22 | 23 | 24 | static ngx_http_module_t ngx_toolkit_misc_test_module_ctx = { 25 | NULL, /* preconfiguration */ 26 | NULL, /* postconfiguration */ 27 | 28 | NULL, /* create main configuration */ 29 | NULL, /* init main configuration */ 30 | 31 | NULL, /* create server configuration */ 32 | NULL, /* merge server configuration */ 33 | 34 | NULL, /* create location configuration */ 35 | NULL /* merge location configuration */ 36 | }; 37 | 38 | 39 | ngx_module_t ngx_toolkit_misc_test_module = { 40 | NGX_MODULE_V1, 41 | &ngx_toolkit_misc_test_module_ctx, /* module context */ 42 | ngx_toolkit_misc_test_commands, /* module directives */ 43 | NGX_HTTP_MODULE, /* module type */ 44 | NULL, /* init master */ 45 | NULL, /* init module */ 46 | NULL, /* init process */ 47 | NULL, /* init thread */ 48 | NULL, /* exit thread */ 49 | NULL, /* exit process */ 50 | NULL, /* exit master */ 51 | NGX_MODULE_V1_PADDING 52 | }; 53 | 54 | 55 | static ngx_int_t 56 | ngx_parse_toolkit_misc_test(ngx_int_t ret, char *url, char *scheme, char *user, 57 | char *host, char *port, char *path, char *args, char *fragment, 58 | char *host_with_port, char *uri_with_args) 59 | { 60 | ngx_int_t _ret; 61 | ngx_str_t _url; 62 | ngx_request_url_t rurl; 63 | 64 | ngx_memzero(&rurl, sizeof(ngx_request_url_t)); 65 | _url.data = (u_char *) url; 66 | _url.len = ngx_strlen(url); 67 | 68 | _ret = ngx_parse_request_url(&rurl, &_url); 69 | if (ret != _ret) { 70 | return 0; 71 | } 72 | 73 | if (_ret == NGX_ERROR) { 74 | return 1; 75 | } 76 | 77 | #define TEST(para) \ 78 | if (para == NULL && rurl.para.len) { \ 79 | return 0; \ 80 | } else if (para && ngx_test_str(&rurl.para, para) == NGX_ERROR) { \ 81 | return 0; \ 82 | } 83 | 84 | TEST(scheme) 85 | TEST(user) 86 | TEST(host) 87 | TEST(port) 88 | TEST(path) 89 | TEST(args) 90 | TEST(fragment) 91 | TEST(host_with_port) 92 | TEST(uri_with_args) 93 | 94 | #undef TEST 95 | 96 | return 1; 97 | } 98 | 99 | static ngx_int_t 100 | ngx_request_port_test(in_port_t expect, char *scheme, char *port) 101 | { 102 | in_port_t ret; 103 | ngx_str_t _scheme, _port; 104 | 105 | _scheme.data = (u_char *) scheme; 106 | _scheme.len = ngx_strlen(scheme); 107 | 108 | _port.data = (u_char *) port; 109 | _port.len = ngx_strlen(port); 110 | 111 | ret = ngx_request_port(&_scheme, &_port); 112 | 113 | return ret == expect; 114 | } 115 | 116 | static ngx_int_t 117 | ngx_toolkit_misc_test_handler(ngx_http_request_t *r) 118 | { 119 | ngx_buf_t *b; 120 | ngx_chain_t cl; 121 | size_t len; 122 | ngx_fd_t fd; 123 | u_char md5key[NGX_MD5KEY_LEN]; 124 | ngx_str_t file; 125 | 126 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 127 | "request url test handler"); 128 | 129 | NGX_TEST_INIT 130 | 131 | NGX_TEST_ISOK(ngx_parse_toolkit_misc_test(NGX_ERROR, "test", 132 | NULL, 133 | NULL, NULL, NULL, 134 | NULL, NULL, NULL, 135 | NULL, NULL)); 136 | NGX_TEST_ISOK(ngx_parse_toolkit_misc_test(NGX_ERROR, "http://", 137 | NULL, 138 | NULL, NULL, NULL, 139 | NULL, NULL, NULL, 140 | NULL, NULL)); 141 | NGX_TEST_ISOK(ngx_parse_toolkit_misc_test(NGX_ERROR, "http://alex@", 142 | NULL, 143 | NULL, NULL, NULL, 144 | NULL, NULL, NULL, 145 | NULL, NULL)); 146 | NGX_TEST_ISOK(ngx_parse_toolkit_misc_test(NGX_OK, "http://alex@test", 147 | "http", 148 | "alex", "test", NULL, 149 | NULL, NULL, NULL, 150 | "test", NULL)); 151 | NGX_TEST_ISOK(ngx_parse_toolkit_misc_test(NGX_ERROR, "http://alex@test:", 152 | NULL, 153 | NULL, NULL, NULL, 154 | NULL, NULL, NULL, 155 | NULL, NULL)); 156 | NGX_TEST_ISOK(ngx_parse_toolkit_misc_test(NGX_OK, "http://alex@test:8080", 157 | "http", 158 | "alex", "test", "8080", 159 | NULL, NULL, NULL, 160 | "test:8080", NULL)); 161 | NGX_TEST_ISOK(ngx_parse_toolkit_misc_test(NGX_ERROR, "http://@test:8080", 162 | NULL, 163 | NULL, NULL, NULL, 164 | NULL, NULL, NULL, 165 | NULL, NULL)); 166 | NGX_TEST_ISOK(ngx_parse_toolkit_misc_test(NGX_OK, "http://test", 167 | "http", 168 | NULL, "test", NULL, 169 | NULL, NULL, NULL, 170 | "test", NULL)); 171 | NGX_TEST_ISOK(ngx_parse_toolkit_misc_test(NGX_ERROR, "http://test:", 172 | NULL, 173 | NULL, NULL, NULL, 174 | NULL, NULL, NULL, 175 | NULL, NULL)); 176 | NGX_TEST_ISOK(ngx_parse_toolkit_misc_test(NGX_OK, "http://test:8080", 177 | "http", 178 | NULL, "test", "8080", 179 | NULL, NULL, NULL, 180 | "test:8080", NULL)); 181 | NGX_TEST_ISOK(ngx_parse_toolkit_misc_test(NGX_OK, "http://test:8080/", 182 | "http", 183 | NULL, "test", "8080", 184 | NULL, NULL, NULL, 185 | "test:8080", NULL)); 186 | NGX_TEST_ISOK(ngx_parse_toolkit_misc_test(NGX_OK, "http://test:8080/live", 187 | "http", 188 | NULL, "test", "8080", 189 | "live", NULL, NULL, 190 | "test:8080", "live")); 191 | NGX_TEST_ISOK(ngx_parse_toolkit_misc_test(NGX_OK, 192 | "http://alex@test/live/test", 193 | "http", 194 | "alex", "test", "8080", 195 | "live/test", NULL, NULL, 196 | "test", "live/test")); 197 | NGX_TEST_ISOK(ngx_parse_toolkit_misc_test(NGX_ERROR, 198 | "http://alex@test:80/live/test?", 199 | NULL, 200 | NULL, NULL, NULL, 201 | NULL, NULL, NULL, 202 | NULL, NULL)); 203 | NGX_TEST_ISOK(ngx_parse_toolkit_misc_test(NGX_OK, 204 | "http://alex@test:80/live/test?a=b&c=d", 205 | "http", 206 | "alex", "test", "80", 207 | "live/test", "a=b&c=d", NULL, 208 | "test:80", "live/test?a=b&c=d")); 209 | NGX_TEST_ISOK(ngx_parse_toolkit_misc_test(NGX_ERROR, 210 | "http://alex@/live/test?a=b&c=d", 211 | NULL, 212 | NULL, NULL, NULL, 213 | NULL, NULL, NULL, 214 | NULL, NULL)); 215 | NGX_TEST_ISOK(ngx_parse_toolkit_misc_test(NGX_OK, 216 | "http://alex@test:8080/live/test?a=b&c=d#test", 217 | "http", 218 | "alex", "test", "8080", 219 | "live/test", "a=b&c=d", "test", 220 | "test:8080", "live/test?a=b&c=d#test")); 221 | 222 | NGX_TEST_ISOK(ngx_request_port_test(0, "", "abcd")); 223 | NGX_TEST_ISOK(ngx_request_port_test(1234, "", "1234")); 224 | NGX_TEST_ISOK(ngx_request_port_test(0, "", "102222")); 225 | NGX_TEST_ISOK(ngx_request_port_test(0, "rtp", "")); 226 | NGX_TEST_ISOK(ngx_request_port_test(80, "http", "")); 227 | NGX_TEST_ISOK(ngx_request_port_test(443, "https", "")); 228 | NGX_TEST_ISOK(ngx_request_port_test(1935, "rtmp", "")); 229 | 230 | file.data = (u_char *) "/usr/local/nginx/conf/md5testfile"; 231 | file.len = sizeof("/usr/local/nginx/conf/md5testfile") - 1; 232 | 233 | fd = ngx_open_file(file.data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0); 234 | if (fd == NGX_INVALID_FILE) { 235 | ngx_log_error(NGX_LOG_ERR, r->connection->log, ngx_errno, 236 | ngx_open_file_n " %s failed", file.data); 237 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 238 | } 239 | 240 | if (ngx_md5_file(fd, md5key)) { 241 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 242 | "md5 file %V failed", &file); 243 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 244 | } 245 | 246 | NGX_TEST_ISOK(ngx_memcmp(md5key, "d4309a79dbeaeb6d7811734ce483db59", 32) 247 | == 0); 248 | 249 | ngx_close_file(fd); 250 | 251 | 252 | r->headers_out.status = NGX_HTTP_OK; 253 | 254 | ngx_http_send_header(r); 255 | 256 | len = sizeof("TEST cases 4294967296, 4294967296 pass\n") - 1; 257 | b = ngx_create_temp_buf(r->pool, len); 258 | 259 | if (b == NULL) { 260 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 261 | } 262 | 263 | b->last = ngx_snprintf(b->last, len, "TEST cases %d, %d pass\n", 264 | count, pass); 265 | b->last_buf = 1; 266 | b->last_in_chain = 1; 267 | 268 | cl.buf = b; 269 | cl.next = NULL; 270 | 271 | return ngx_http_output_filter(r, &cl); 272 | } 273 | 274 | 275 | static char * 276 | ngx_toolkit_misc_test(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 277 | { 278 | ngx_http_core_loc_conf_t *clcf; 279 | 280 | clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); 281 | clcf->handler = ngx_toolkit_misc_test_handler; 282 | 283 | return NGX_CONF_OK; 284 | } 285 | 286 | -------------------------------------------------------------------------------- /ngx_toolkit_misc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) AlexWoo(Wu Jie) wj19840501@gmail.com 3 | */ 4 | 5 | 6 | #include "ngx_toolkit_misc.h" 7 | #include 8 | 9 | 10 | typedef struct { 11 | ngx_str_t scheme; 12 | in_port_t port; 13 | } ngx_scheme_port_t; 14 | 15 | 16 | ngx_scheme_port_t ngx_sheme_port[] = { 17 | { ngx_string("http"), 80 }, 18 | { ngx_string("https"), 443 }, 19 | { ngx_string("rtmp"), 1935 }, 20 | { ngx_null_string, 0 } 21 | }; 22 | 23 | 24 | #define FILEBUFSIZE 8192 25 | 26 | 27 | void 28 | ngx_random32(u_char *id) 29 | { 30 | ngx_sprintf(id, "%08xD%08xD%08xD%08xD", 31 | (uint32_t) ngx_random(), (uint32_t) ngx_random(), 32 | (uint32_t) ngx_random(), (uint32_t) ngx_random()); 33 | } 34 | 35 | socklen_t 36 | ngx_sock_pton_unix(struct sockaddr *sa, u_char *text, size_t len) 37 | { 38 | #if NGX_HAVE_UNIX_DOMAIN 39 | u_char *path; 40 | struct sockaddr_un *saun; 41 | 42 | // skip 'unix:' 43 | path = text + 5; 44 | len -= 5; 45 | 46 | if (len == 0) { 47 | ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, 0, 48 | "no path in the unix domain"); 49 | return 0; 50 | } 51 | 52 | ++len; // sun_path need '\0' as end 53 | if (len > sizeof(saun->sun_path)) { 54 | ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, 0, 55 | "too long path in the unix domain socket"); 56 | return 0; 57 | } 58 | 59 | saun = (struct sockaddr_un *) sa; 60 | saun->sun_family = AF_UNIX; 61 | (void) ngx_cpystrn((u_char *) saun->sun_path, path, len); 62 | 63 | return sizeof(struct sockaddr_un); 64 | 65 | #else 66 | ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, 0, 67 | "the unix domain sockets are not supported on this platform"); 68 | 69 | return 0; 70 | #endif 71 | } 72 | 73 | socklen_t 74 | ngx_sock_pton_inet6(struct sockaddr *sa, u_char *text, size_t len) 75 | { 76 | #if NGX_HAVE_INET6 77 | struct in6_addr inaddr6; 78 | struct sockaddr_in6 *sin6; 79 | u_char *p, *last; 80 | ngx_int_t port; 81 | size_t alen, plen; 82 | 83 | last = text + len; 84 | p = ngx_strlchr(text, last, ']'); 85 | 86 | if (p == NULL || p == last - 1) { 87 | ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, 0, 88 | "not a ipv6 address format"); 89 | return 0; 90 | } 91 | 92 | ++text; 93 | alen = p - text; 94 | 95 | /* 96 | * prevent MSVC8 warning: 97 | * potentially uninitialized local variable 'inaddr6' used 98 | */ 99 | ngx_memzero(&inaddr6, sizeof(struct in6_addr)); 100 | 101 | if (ngx_inet6_addr(text, alen, inaddr6.s6_addr) != NGX_OK) { 102 | // not ipv6 address 103 | return 0; 104 | } 105 | 106 | sa->sa_family = AF_INET6; 107 | 108 | sin6 = (struct sockaddr_in6 *) sa; 109 | ngx_memcpy(sin6->sin6_addr.s6_addr, inaddr6.s6_addr, 16); 110 | 111 | ++p; 112 | if (*p == ':') { // has port 113 | ++p; 114 | plen = last - p; 115 | 116 | port = ngx_atoi(p, plen); 117 | if (port < 0 || port > 65535) { 118 | ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, 0, 119 | "invalid port: %i", port); 120 | return 0; 121 | } 122 | 123 | ngx_inet_set_port(sa, (in_port_t) port); 124 | } 125 | 126 | return sizeof(struct sockaddr_in6); 127 | 128 | #else 129 | ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, 0, 130 | "the INET6 sockets are not supported on this platform"); 131 | 132 | return 0; 133 | #endif 134 | } 135 | 136 | socklen_t 137 | ngx_sock_pton_inet(struct sockaddr *sa, u_char *text, size_t len) 138 | { 139 | in_addr_t inaddr; 140 | struct sockaddr_in *sin; 141 | u_char *p, *last; 142 | ngx_int_t port; 143 | size_t alen, plen; 144 | 145 | last = text + len; 146 | p = ngx_strlchr(text, last, ':'); 147 | alen = len; 148 | 149 | if (p != NULL) { // have port 150 | alen = p - text; 151 | } 152 | 153 | inaddr = ngx_inet_addr(text, alen); 154 | if (inaddr == INADDR_NONE) { 155 | // not ipv4 address 156 | return 0; 157 | } 158 | 159 | sa->sa_family = AF_INET; 160 | 161 | sin = (struct sockaddr_in *) sa; 162 | sin->sin_addr.s_addr = inaddr; 163 | 164 | if (p != NULL) { // has port 165 | ++p; 166 | plen = last - p; 167 | 168 | port = ngx_atoi(p, plen); 169 | if (port < 0 || port > 65535) { 170 | ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, 0, 171 | "invalid port: %i", port); 172 | return 0; 173 | } 174 | 175 | ngx_inet_set_port(sa, (in_port_t) port); 176 | } 177 | 178 | return sizeof(struct sockaddr_in); 179 | } 180 | 181 | ngx_int_t 182 | ngx_parse_request_url(ngx_request_url_t *request_url, ngx_str_t *url) 183 | { 184 | u_char *last, *host_last; 185 | u_char *scheme; 186 | u_char *user, *host, *port; 187 | u_char *path, *args, *fragment; 188 | 189 | /* NULL url */ 190 | if (url->len == 0) { 191 | return NGX_ERROR; 192 | } 193 | 194 | last = url->data + url->len; 195 | 196 | scheme = url->data; 197 | 198 | user = (u_char *) ngx_strnstr(scheme, "://", last - scheme); 199 | 200 | if (user == NULL) { 201 | return NGX_ERROR; 202 | } 203 | 204 | request_url->scheme.data = scheme; 205 | request_url->scheme.len = user - scheme; 206 | 207 | user += 3; 208 | if (user >= last) { 209 | return NGX_ERROR; 210 | } 211 | 212 | host_last = ngx_strlchr(user, last, '/'); 213 | if (host_last == NULL) { 214 | host_last = last; 215 | } 216 | 217 | host = ngx_strlchr(user, host_last, '@'); 218 | if (host == NULL) { /* no user */ 219 | host = user; 220 | } else { 221 | if (user == host) { /* user is "" */ 222 | return NGX_ERROR; 223 | } 224 | 225 | request_url->user.data = user; 226 | request_url->user.len = host - user; 227 | ++host; 228 | if (host == host_last) { /* no host */ 229 | return NGX_ERROR; 230 | } 231 | } 232 | 233 | port = ngx_strlchr(host, host_last, ':'); 234 | if (port == NULL) { /* no port */ 235 | request_url->host.data = host; 236 | request_url->host.len = host_last - host; 237 | 238 | request_url->host_with_port = request_url->host; 239 | } else { 240 | request_url->host.data = host; 241 | request_url->host.len = port - host; 242 | ++port; 243 | if (port == host_last) { /* port error */ 244 | return NGX_ERROR; 245 | } 246 | 247 | request_url->port.data = port; 248 | request_url->port.len = host_last - port; 249 | 250 | request_url->host_with_port.data = host; 251 | request_url->host_with_port.len = host_last - host; 252 | } 253 | 254 | path = ++host_last; 255 | if (path >= last) { /* no path */ 256 | goto done; 257 | } 258 | 259 | args = ngx_strlchr(path, last, '?'); 260 | if (args == NULL) { /* no args */ 261 | request_url->path.data = path; 262 | request_url->path.len = last - path; 263 | 264 | request_url->uri_with_args = request_url->path; 265 | 266 | goto done; 267 | } else { 268 | request_url->path.data = path; 269 | request_url->path.len = args - path; 270 | ++args; 271 | if (args == last) { /* args error */ 272 | return NGX_ERROR; 273 | } 274 | } 275 | 276 | fragment = ngx_strlchr(args, last, '#'); 277 | if (fragment == NULL) { /* no fragment */ 278 | request_url->args.data = args; 279 | request_url->args.len = last - args; 280 | } else { 281 | request_url->args.data = args; 282 | request_url->args.len = fragment - args; 283 | ++fragment; 284 | if (fragment == last) { /* fragment error */ 285 | return NGX_ERROR; 286 | } 287 | 288 | request_url->fragment.data = fragment; 289 | request_url->fragment.len = last - fragment; 290 | } 291 | 292 | request_url->uri_with_args.data = path; 293 | request_url->uri_with_args.len = last - path; 294 | 295 | done: 296 | return NGX_OK; 297 | } 298 | 299 | in_port_t 300 | ngx_request_port(ngx_str_t *scheme, ngx_str_t *port) 301 | { 302 | ngx_int_t p; 303 | ngx_scheme_port_t *sp; 304 | 305 | if (port->len) { 306 | p = ngx_atoi(port->data, port->len); 307 | if (p < 1 || p > 65535) { /* invalid port */ 308 | return 0; 309 | } 310 | 311 | return p; 312 | } 313 | 314 | for (sp = ngx_sheme_port; sp->port != 0; ++sp) { 315 | if (sp->scheme.len == scheme->len 316 | && ngx_memcmp(sp->scheme.data, scheme->data, scheme->len) == 0) 317 | { 318 | return sp->port; 319 | } 320 | } 321 | 322 | return 0; 323 | } 324 | 325 | ngx_int_t 326 | ngx_md5_file(ngx_fd_t fd, u_char md5key[NGX_MD5KEY_LEN]) 327 | { 328 | ngx_md5_t ctx; 329 | u_char buf[FILEBUFSIZE]; 330 | u_char md5[16]; 331 | ssize_t n; 332 | ngx_uint_t i; 333 | u_char *p; 334 | 335 | ngx_md5_init(&ctx); 336 | 337 | for (;;) { 338 | n = ngx_read_fd(fd, buf, FILEBUFSIZE); 339 | 340 | if (n == 0) { /* read eof of file */ 341 | break; 342 | } 343 | 344 | if (n == NGX_FILE_ERROR) { 345 | return NGX_ERROR; 346 | } 347 | 348 | ngx_md5_update(&ctx, buf, n); 349 | } 350 | 351 | ngx_md5_final(md5, &ctx); 352 | 353 | p = md5key; 354 | for (i = 0; i < 16; ++i) { 355 | p = ngx_sprintf(p, "%02xi", md5[i]); 356 | } 357 | 358 | return NGX_OK; 359 | } 360 | 361 | ngx_int_t 362 | ngx_copy_str(ngx_pool_t *pool, ngx_str_t *dst, ngx_str_t *src) 363 | { 364 | if (src->len == 0) { 365 | return NGX_OK; 366 | } 367 | 368 | dst->len = src->len; 369 | dst->data = ngx_palloc(pool, src->len); 370 | if (dst->data == NULL) { 371 | return NGX_ERROR; 372 | } 373 | 374 | ngx_memcpy(dst->data, src->data, src->len); 375 | 376 | return NGX_OK; 377 | } 378 | 379 | socklen_t 380 | ngx_sock_pton(struct sockaddr *sa, u_char *text, size_t len) 381 | { 382 | if (len >= 5 && ngx_strncasecmp(text, (u_char *) "unix:", 5) == 0) { 383 | return ngx_sock_pton_unix(sa, text, len); 384 | } 385 | 386 | if (len && text[0] == '[') { 387 | return ngx_sock_pton_inet6(sa, text, len); 388 | } 389 | 390 | return ngx_sock_pton_inet(sa, text, len); 391 | } 392 | -------------------------------------------------------------------------------- /ngx_http_trace_module.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) AlexWoo(Wu Jie) wj19840501@gmail.com 3 | */ 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | #include "ngx_toolkit_misc.h" 10 | 11 | 12 | typedef struct { 13 | ngx_flag_t trace; 14 | } ngx_http_trace_main_conf_t; 15 | 16 | 17 | typedef struct { 18 | u_char traceid[32]; /* X-NTM-Traceid */ 19 | u_char cid[32]; /* X-NTM-Currentid */ 20 | u_char pid[32]; /* X-NTM-Parentid */ 21 | ngx_flag_t debug; /* X-NTM-Debug */ 22 | ngx_uint_t raw_level; /* raw log level */ 23 | } ngx_http_trace_ctx_t; 24 | 25 | 26 | static void *ngx_http_trace_create_main_conf(ngx_conf_t *cf); 27 | static char *ngx_http_trace_init_main_conf(ngx_conf_t *cf, void *conf); 28 | 29 | static char *ngx_http_trace(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); 30 | 31 | static ngx_int_t ngx_http_trace_add_variables(ngx_conf_t *cf); 32 | static ngx_int_t ngx_http_trace_init(ngx_conf_t *cf); 33 | 34 | static ngx_int_t ngx_http_trace_traceid_variable(ngx_http_request_t *r, 35 | ngx_http_variable_value_t *v, uintptr_t data); 36 | static ngx_int_t ngx_http_trace_currentid_variable(ngx_http_request_t *r, 37 | ngx_http_variable_value_t *v, uintptr_t data); 38 | static ngx_int_t ngx_http_trace_parentid_variable(ngx_http_request_t *r, 39 | ngx_http_variable_value_t *v, uintptr_t data); 40 | static ngx_int_t ngx_http_trace_debug_variable(ngx_http_request_t *r, 41 | ngx_http_variable_value_t *v, uintptr_t data); 42 | static ngx_int_t ngx_http_trace_newid_variable(ngx_http_request_t *r, 43 | ngx_http_variable_value_t *v, uintptr_t data); 44 | 45 | 46 | static ngx_command_t ngx_http_trace_commands[] = { 47 | 48 | { ngx_string("http_trace"), 49 | NGX_HTTP_MAIN_CONF|NGX_CONF_NOARGS, 50 | ngx_http_trace, 51 | 0, 52 | 0, 53 | NULL }, 54 | 55 | ngx_null_command 56 | }; 57 | 58 | 59 | static ngx_http_module_t ngx_http_trace_module_ctx = { 60 | ngx_http_trace_add_variables, /* preconfiguration */ 61 | ngx_http_trace_init, /* postconfiguration */ 62 | 63 | ngx_http_trace_create_main_conf, /* create main configuration */ 64 | ngx_http_trace_init_main_conf, /* init main configuration */ 65 | 66 | NULL, /* create server configuration */ 67 | NULL, /* merge server configuration */ 68 | 69 | NULL, /* create location configuration */ 70 | NULL /* merge location configuration */ 71 | }; 72 | 73 | 74 | ngx_module_t ngx_http_trace_module = { 75 | NGX_MODULE_V1, 76 | &ngx_http_trace_module_ctx, /* module context */ 77 | ngx_http_trace_commands, /* module directives */ 78 | NGX_HTTP_MODULE, /* module type */ 79 | NULL, /* init master */ 80 | NULL, /* init module */ 81 | NULL, /* init process */ 82 | NULL, /* init thread */ 83 | NULL, /* exit thread */ 84 | NULL, /* exit process */ 85 | NULL, /* exit master */ 86 | NGX_MODULE_V1_PADDING 87 | }; 88 | 89 | 90 | static ngx_http_variable_t ngx_http_trace_vars[] = { 91 | 92 | { ngx_string("ntm_traceid"), NULL, 93 | ngx_http_trace_traceid_variable, 0, 0, 0 }, 94 | 95 | { ngx_string("ntm_currentid"), NULL, 96 | ngx_http_trace_currentid_variable, 0, 0, 0 }, 97 | 98 | { ngx_string("ntm_parentid"), NULL, 99 | ngx_http_trace_parentid_variable, 0, 0, 0 }, 100 | 101 | { ngx_string("ntm_debug"), NULL, 102 | ngx_http_trace_debug_variable, 0, 0, 0 }, 103 | 104 | { ngx_string("ntm_newid"), NULL, 105 | ngx_http_trace_newid_variable, 0, 0, 0 }, 106 | 107 | { ngx_null_string, NULL, NULL, 0, 0, 0 } 108 | }; 109 | 110 | 111 | static u_char * 112 | ngx_http_trace_log_error(ngx_log_t *log, u_char *buf, size_t len) 113 | { 114 | u_char *p; 115 | ngx_http_request_t *r; 116 | ngx_http_log_ctx_t *ctx; 117 | ngx_http_trace_ctx_t *tctx; 118 | ngx_str_t traceid, currentid, parentid; 119 | 120 | if (log->action) { 121 | p = ngx_snprintf(buf, len, " while %s", log->action); 122 | len -= p - buf; 123 | buf = p; 124 | } 125 | 126 | ctx = log->data; 127 | 128 | p = ngx_snprintf(buf, len, ", client: %V", &ctx->connection->addr_text); 129 | len -= p - buf; 130 | buf = p; 131 | 132 | r = ctx->request; 133 | 134 | if (r) { 135 | p = r->log_handler(r, ctx->current_request, p, len); 136 | len -= p - buf; 137 | buf = p; 138 | 139 | } else { 140 | p = ngx_snprintf(p, len, ", server: %V", 141 | &ctx->connection->listening->addr_text); 142 | len -= p - buf; 143 | buf = p; 144 | } 145 | 146 | tctx = ngx_http_get_module_ctx(r, ngx_http_trace_module); 147 | if (tctx) { 148 | traceid.data = tctx->traceid; 149 | traceid.len = sizeof(tctx->traceid); 150 | 151 | currentid.data = tctx->cid; 152 | currentid.len = sizeof(tctx->cid); 153 | 154 | parentid.data = tctx->pid; 155 | parentid.len = sizeof(tctx->pid); 156 | 157 | p = ngx_snprintf(p, len, ", [NGINX-TRACE] traceid: %V, currentid: %V, " 158 | "parentid: %V [NGINX-TRACE-END]", 159 | &traceid, ¤tid, &parentid); 160 | } 161 | 162 | return p; 163 | } 164 | 165 | 166 | // First request without X-NTM-Traceid X-NTM-Currentid or X-NTM-Parentid 167 | // Need to gen these ids and set X-NTM headers in main request 168 | static ngx_int_t 169 | ngx_http_trace_first_request(ngx_http_request_t *r, ngx_http_trace_ctx_t *ctx) 170 | { 171 | ngx_table_elt_t *h; 172 | 173 | ngx_random32(ctx->traceid); 174 | ngx_random32(ctx->cid); 175 | ngx_sprintf(ctx->pid, "00000000000000000000000000000000"); 176 | 177 | // Set X-NTM-Traceid 178 | h = ngx_list_push(&r->headers_in.headers); 179 | if (h == NULL) { 180 | return NGX_ERROR; 181 | } 182 | 183 | h->key.data = (u_char *) "X-NTM-Traceid"; 184 | h->key.len = sizeof("X-NTM-Traceid") - 1; 185 | 186 | h->value.data = ctx->traceid; 187 | h->value.len = sizeof(ctx->traceid); 188 | 189 | h->lowcase_key = ngx_pnalloc(r->pool, h->key.len); 190 | if (h->lowcase_key == NULL) { 191 | return NGX_ERROR; 192 | } 193 | h->hash = ngx_hash_strlow(h->lowcase_key, h->key.data, h->key.len); 194 | 195 | // Set X-NTM-Currentid 196 | h = ngx_list_push(&r->headers_in.headers); 197 | if (h == NULL) { 198 | return NGX_ERROR; 199 | } 200 | 201 | h->key.data = (u_char *) "X-NTM-Currentid"; 202 | h->key.len = sizeof("X-NTM-Currentid") - 1; 203 | 204 | h->value.data = ctx->cid; 205 | h->value.len = sizeof(ctx->cid); 206 | 207 | h->lowcase_key = ngx_pnalloc(r->pool, h->key.len); 208 | if (h->lowcase_key == NULL) { 209 | return NGX_ERROR; 210 | } 211 | h->hash = ngx_hash_strlow(h->lowcase_key, h->key.data, h->key.len); 212 | 213 | // Set X-NTM-Parentid 214 | h = ngx_list_push(&r->headers_in.headers); 215 | if (h == NULL) { 216 | return NGX_ERROR; 217 | } 218 | 219 | h->key.data = (u_char *) "X-NTM-Parentid"; 220 | h->key.len = sizeof("X-NTM-Parentid") - 1; 221 | 222 | h->value.data = ctx->pid; 223 | h->value.len = sizeof(ctx->pid); 224 | 225 | h->lowcase_key = ngx_pnalloc(r->pool, h->key.len); 226 | if (h->lowcase_key == NULL) { 227 | return NGX_ERROR; 228 | } 229 | h->hash = ngx_hash_strlow(h->lowcase_key, h->key.data, h->key.len); 230 | 231 | return NGX_OK; 232 | } 233 | 234 | 235 | static ngx_int_t 236 | ngx_http_trace_handler(ngx_http_request_t *r) 237 | { 238 | ngx_http_trace_main_conf_t *tmcf; 239 | ngx_http_trace_ctx_t *ctx; 240 | ngx_http_variable_value_t v; 241 | ngx_str_t header; 242 | 243 | if (r != r->main) { // subrequest 244 | return NGX_DECLINED; 245 | } 246 | 247 | tmcf = ngx_http_get_module_main_conf(r, ngx_http_trace_module); 248 | if (!tmcf->trace) { 249 | return NGX_DECLINED; 250 | } 251 | 252 | ctx = ngx_http_get_module_ctx(r, ngx_http_trace_module); 253 | if (ctx) { // ctx already create, enter twice 254 | return NGX_DECLINED; 255 | } 256 | 257 | ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_trace_ctx_t)); 258 | if (ctx == NULL) { 259 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 260 | } 261 | ngx_http_set_ctx(r, ctx, ngx_http_trace_module); 262 | 263 | // traceid currentid parentid log into nginx error log 264 | r->connection->log->handler = ngx_http_trace_log_error; 265 | 266 | // Get X-NTM-Debug 267 | header.data = (u_char *) "http_x_ntm_debug"; 268 | header.len = sizeof("http_x_ntm_debug") - 1; 269 | ngx_http_variable_unknown_header(&v, &header, &r->headers_in.headers.part, 270 | sizeof("http_") - 1); 271 | if (!v.not_found && v.len == 1 && v.data[0] == '1') { 272 | // Has header X-NTM-Debug: 1 273 | ctx->debug = 1; 274 | ctx->raw_level = r->connection->log->log_level; 275 | r->connection->log->log_level = NGX_LOG_DEBUG; 276 | } 277 | 278 | // Get X-NTM-Traceid 279 | header.data = (u_char *) "http_x_ntm_traceid"; 280 | header.len = sizeof("http_x_ntm_traceid") - 1; 281 | ngx_http_variable_unknown_header(&v, &header, &r->headers_in.headers.part, 282 | sizeof("http_") - 1); 283 | if (v.not_found) { 284 | goto notfound; 285 | } 286 | 287 | ngx_memcpy(ctx->traceid, v.data, ngx_min(v.len, sizeof(ctx->traceid))); 288 | 289 | // Get X-NTM-Currentid 290 | header.data = (u_char *) "http_x_ntm_currentid"; 291 | header.len = sizeof("http_x_ntm_currentid") - 1; 292 | ngx_http_variable_unknown_header(&v, &header, &r->headers_in.headers.part, 293 | sizeof("http_") - 1); 294 | if (v.not_found) { 295 | goto notfound; 296 | } 297 | 298 | ngx_memcpy(ctx->cid, v.data, ngx_min(v.len, sizeof(ctx->cid))); 299 | 300 | // Get X-NTM-Parentid 301 | header.data = (u_char *) "http_x_ntm_parentid"; 302 | header.len = sizeof("http_x_ntm_parentid") - 1; 303 | ngx_http_variable_unknown_header(&v, &header, &r->headers_in.headers.part, 304 | sizeof("http_") - 1); 305 | if (v.not_found) { 306 | goto notfound; 307 | } 308 | 309 | ngx_memcpy(ctx->pid, v.data, ngx_min(v.len, sizeof(ctx->pid))); 310 | 311 | return NGX_DECLINED; 312 | 313 | notfound: 314 | 315 | if (ngx_http_trace_first_request(r, ctx) != NGX_OK) { 316 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 317 | } 318 | 319 | return NGX_DECLINED; 320 | } 321 | 322 | 323 | static ngx_int_t 324 | ngx_http_trace_end_handler(ngx_http_request_t *r) 325 | { 326 | ngx_http_trace_ctx_t *ctx; 327 | 328 | ctx = ngx_http_get_module_ctx(r, ngx_http_trace_module); 329 | if (ctx == NULL || ctx->debug == 0) { 330 | return NGX_OK; 331 | } 332 | 333 | r->connection->log->log_level = ctx->raw_level; 334 | 335 | return NGX_OK; 336 | } 337 | 338 | 339 | static ngx_int_t 340 | ngx_http_trace_traceid_variable(ngx_http_request_t *r, 341 | ngx_http_variable_value_t *v, uintptr_t data) 342 | { 343 | ngx_http_trace_ctx_t *ctx; 344 | 345 | ctx = ngx_http_get_module_ctx(r, ngx_http_trace_module); 346 | if (ctx == NULL) { 347 | v->not_found = 1; 348 | return NGX_OK; 349 | } 350 | 351 | v->data = ctx->traceid; 352 | v->len = sizeof(ctx->traceid); 353 | v->valid = 1; 354 | v->no_cacheable = 0; 355 | v->not_found = 0; 356 | 357 | return NGX_OK; 358 | } 359 | 360 | 361 | static ngx_int_t 362 | ngx_http_trace_currentid_variable(ngx_http_request_t *r, 363 | ngx_http_variable_value_t *v, uintptr_t data) 364 | { 365 | ngx_http_trace_ctx_t *ctx; 366 | 367 | ctx = ngx_http_get_module_ctx(r, ngx_http_trace_module); 368 | if (ctx == NULL) { 369 | v->not_found = 1; 370 | return NGX_OK; 371 | } 372 | 373 | v->data = ctx->cid; 374 | v->len = sizeof(ctx->cid); 375 | v->valid = 1; 376 | v->no_cacheable = 0; 377 | v->not_found = 0; 378 | 379 | return NGX_OK; 380 | } 381 | 382 | 383 | static ngx_int_t 384 | ngx_http_trace_parentid_variable(ngx_http_request_t *r, 385 | ngx_http_variable_value_t *v, uintptr_t data) 386 | { 387 | ngx_http_trace_ctx_t *ctx; 388 | 389 | ctx = ngx_http_get_module_ctx(r, ngx_http_trace_module); 390 | if (ctx == NULL) { 391 | v->not_found = 1; 392 | return NGX_OK; 393 | } 394 | 395 | v->data = ctx->pid; 396 | v->len = sizeof(ctx->pid); 397 | v->valid = 1; 398 | v->no_cacheable = 0; 399 | v->not_found = 0; 400 | 401 | return NGX_OK; 402 | } 403 | 404 | 405 | static ngx_int_t 406 | ngx_http_trace_debug_variable(ngx_http_request_t *r, 407 | ngx_http_variable_value_t *v, uintptr_t data) 408 | { 409 | ngx_http_trace_ctx_t *ctx; 410 | 411 | ctx = ngx_http_get_module_ctx(r, ngx_http_trace_module); 412 | if (ctx == NULL) { 413 | v->not_found = 1; 414 | return NGX_OK; 415 | } 416 | 417 | if (ctx->debug) { 418 | v->data = (u_char *) "1"; 419 | } else { 420 | v->data = (u_char *) "0"; 421 | } 422 | 423 | v->len = sizeof("1") - 1; 424 | v->valid = 1; 425 | v->no_cacheable = 0; 426 | v->not_found = 0; 427 | 428 | return NGX_OK; 429 | } 430 | 431 | 432 | static ngx_int_t 433 | ngx_http_trace_newid_variable(ngx_http_request_t *r, 434 | ngx_http_variable_value_t *v, uintptr_t data) 435 | { 436 | ngx_http_trace_ctx_t *ctx; 437 | u_char *newid; 438 | 439 | ctx = ngx_http_get_module_ctx(r, ngx_http_trace_module); 440 | if (ctx == NULL) { 441 | v->not_found = 1; 442 | return NGX_OK; 443 | } 444 | 445 | newid = ngx_pcalloc(r->pool, sizeof(ctx->cid)); 446 | if (newid == NULL) { 447 | return NGX_ERROR; 448 | } 449 | 450 | // fill newid 451 | ngx_random32(newid); 452 | 453 | v->data = newid; 454 | v->len = sizeof(ctx->cid); 455 | v->valid = 1; 456 | v->no_cacheable = 0; 457 | v->not_found = 0; 458 | 459 | return NGX_OK; 460 | } 461 | 462 | 463 | static void * 464 | ngx_http_trace_create_main_conf(ngx_conf_t *cf) 465 | { 466 | ngx_http_trace_main_conf_t *conf; 467 | 468 | conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_trace_main_conf_t)); 469 | if (conf == NULL) { 470 | return NULL; 471 | } 472 | 473 | conf->trace = NGX_CONF_UNSET; 474 | 475 | return conf; 476 | } 477 | 478 | 479 | static char * 480 | ngx_http_trace_init_main_conf(ngx_conf_t *cf, void *conf) 481 | { 482 | ngx_http_trace_main_conf_t *tmcf; 483 | 484 | tmcf = conf; 485 | 486 | ngx_conf_init_value(tmcf->trace, 0); 487 | 488 | return NGX_CONF_OK; 489 | } 490 | 491 | 492 | static char * 493 | ngx_http_trace(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 494 | { 495 | ngx_http_trace_main_conf_t *tmcf; 496 | 497 | tmcf = conf; 498 | 499 | if (tmcf->trace != NGX_CONF_UNSET) { 500 | return "is duplicate"; 501 | } 502 | 503 | tmcf->trace = 1; 504 | 505 | return NGX_CONF_OK; 506 | } 507 | 508 | 509 | static ngx_int_t 510 | ngx_http_trace_add_variables(ngx_conf_t *cf) 511 | { 512 | ngx_http_variable_t *var, *v; 513 | 514 | for (v = ngx_http_trace_vars; v->name.len; v++) { 515 | var = ngx_http_add_variable(cf, &v->name, v->flags); 516 | if (var == NULL) { 517 | return NGX_ERROR; 518 | } 519 | 520 | var->get_handler = v->get_handler; 521 | var->data = v->data; 522 | } 523 | 524 | return NGX_OK; 525 | } 526 | 527 | 528 | static ngx_int_t 529 | ngx_http_trace_init(ngx_conf_t *cf) 530 | { 531 | ngx_http_handler_pt *h; 532 | ngx_http_core_main_conf_t *cmcf; 533 | 534 | cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); 535 | 536 | h = ngx_array_push(&cmcf->phases[NGX_HTTP_POST_READ_PHASE].handlers); 537 | if (h == NULL) { 538 | return NGX_ERROR; 539 | } 540 | 541 | *h = ngx_http_trace_handler; 542 | 543 | h = ngx_array_push(&cmcf->phases[NGX_HTTP_LOG_PHASE].handlers); 544 | if (h == NULL) { 545 | return NGX_ERROR; 546 | } 547 | 548 | *h = ngx_http_trace_end_handler; 549 | 550 | return NGX_OK; 551 | } 552 | -------------------------------------------------------------------------------- /ngx_dynamic_resolver.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) AlexWoo(Wu Jie) wj19840501@gmail.com 3 | */ 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | #include "ngx_event_timer_module.h" 10 | #include "ngx_event_resolver.h" 11 | #include "ngx_dynamic_resolver.h" 12 | #include "ngx_toolkit_misc.h" 13 | 14 | 15 | static ngx_int_t ngx_dynamic_resolver_process_init(ngx_cycle_t *cycle); 16 | 17 | static void *ngx_dynamic_resolver_create_conf(ngx_cycle_t *cycle); 18 | static char *ngx_dynamic_resolver_init_conf(ngx_cycle_t *cycle, void *conf); 19 | 20 | 21 | #define MAX_DOMAIN_LEN 128 22 | #define MAX_ADDRS 8 23 | 24 | 25 | typedef struct ngx_dynamic_resolver_ctx_s ngx_dynamic_resolver_ctx_t; 26 | typedef struct ngx_dynamic_resolver_domain_s ngx_dynamic_resolver_domain_t; 27 | 28 | struct ngx_dynamic_resolver_ctx_s { 29 | ngx_dynamic_resolver_handler_pt h; 30 | void *data; 31 | 32 | ngx_dynamic_resolver_ctx_t *next; 33 | }; 34 | 35 | typedef struct { 36 | struct sockaddr sockaddr; 37 | socklen_t socklen; 38 | u_short priority; 39 | u_short weight; 40 | } ngx_dynamic_resolver_addr_t; 41 | 42 | struct ngx_dynamic_resolver_domain_s { 43 | ngx_str_t domain; 44 | u_char domain_cstr[MAX_DOMAIN_LEN]; 45 | 46 | ngx_uint_t naddrs; 47 | ngx_dynamic_resolver_addr_t addrs[MAX_ADDRS]; 48 | 49 | ngx_dynamic_resolver_ctx_t *ctx; 50 | 51 | ngx_dynamic_resolver_domain_t *next; 52 | }; 53 | 54 | typedef struct { 55 | ngx_msec_t refresh_interval; 56 | 57 | size_t domain_buckets; 58 | ngx_dynamic_resolver_domain_t **resolver_hash; 59 | 60 | ngx_dynamic_resolver_ctx_t *free_ctx; 61 | ngx_dynamic_resolver_domain_t *free_domain; 62 | 63 | ngx_uint_t nalloc_ctx; 64 | ngx_uint_t nfree_ctx; 65 | ngx_uint_t nalloc_domain; 66 | ngx_uint_t nfree_domain; 67 | } ngx_dynamic_resolver_conf_t; 68 | 69 | 70 | static ngx_str_t dynamic_resolver_name = ngx_string("dynamic_resolver"); 71 | 72 | 73 | static ngx_command_t ngx_dynamic_resolver_commands[] = { 74 | 75 | { ngx_string("dynamic_refresh_interval"), 76 | NGX_EVENT_CONF|NGX_CONF_TAKE1, 77 | ngx_conf_set_msec_slot, 78 | 0, 79 | offsetof(ngx_dynamic_resolver_conf_t, refresh_interval), 80 | NULL }, 81 | 82 | { ngx_string("dynamic_domain_buckets"), 83 | NGX_EVENT_CONF|NGX_CONF_TAKE1, 84 | ngx_conf_set_num_slot, 85 | 0, 86 | offsetof(ngx_dynamic_resolver_conf_t, domain_buckets), 87 | NULL }, 88 | 89 | ngx_null_command 90 | }; 91 | 92 | 93 | ngx_event_module_t ngx_dynamic_resolver_module_ctx = { 94 | &dynamic_resolver_name, 95 | ngx_dynamic_resolver_create_conf, /* create configuration */ 96 | ngx_dynamic_resolver_init_conf, /* init configuration */ 97 | 98 | { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL } 99 | }; 100 | 101 | 102 | /* this module use ngx_cycle->log */ 103 | ngx_module_t ngx_dynamic_resolver_module = { 104 | NGX_MODULE_V1, 105 | &ngx_dynamic_resolver_module_ctx, /* module context */ 106 | ngx_dynamic_resolver_commands, /* module directives */ 107 | NGX_EVENT_MODULE, /* module type */ 108 | NULL, /* init master */ 109 | NULL, /* init module */ 110 | ngx_dynamic_resolver_process_init, /* init process */ 111 | NULL, /* init thread */ 112 | NULL, /* exit thread */ 113 | NULL, /* exit process */ 114 | NULL, /* exit master */ 115 | NGX_MODULE_V1_PADDING 116 | }; 117 | 118 | 119 | static void * 120 | ngx_dynamic_resolver_create_conf(ngx_cycle_t *cycle) 121 | { 122 | ngx_dynamic_resolver_conf_t *conf; 123 | 124 | conf = ngx_pcalloc(cycle->pool, sizeof(ngx_dynamic_resolver_conf_t)); 125 | if (conf == NULL) { 126 | return NULL; 127 | } 128 | 129 | conf->refresh_interval = NGX_CONF_UNSET_MSEC; 130 | conf->domain_buckets = NGX_CONF_UNSET_UINT; 131 | 132 | return conf; 133 | } 134 | 135 | static char * 136 | ngx_dynamic_resolver_init_conf(ngx_cycle_t *cycle, void *conf) 137 | { 138 | ngx_dynamic_resolver_conf_t *drcf = conf; 139 | 140 | ngx_conf_init_msec_value(drcf->refresh_interval, 0); 141 | ngx_conf_init_uint_value(drcf->domain_buckets, 101); 142 | 143 | if (drcf->refresh_interval > 0 && drcf->domain_buckets > 0) { 144 | drcf->resolver_hash = ngx_pcalloc(cycle->pool, 145 | sizeof(ngx_dynamic_resolver_domain_t *) * drcf->domain_buckets); 146 | } 147 | 148 | return NGX_CONF_OK; 149 | } 150 | 151 | /* reuse for ngx_dynamic_resolver_ctx_t */ 152 | static ngx_dynamic_resolver_ctx_t * 153 | ngx_dynamic_resolver_get_ctx(ngx_cycle_t *cycle) 154 | { 155 | ngx_dynamic_resolver_conf_t *drcf; 156 | ngx_dynamic_resolver_ctx_t *ctx; 157 | 158 | drcf = ngx_event_get_conf(cycle->conf_ctx, ngx_dynamic_resolver_module); 159 | 160 | ctx = drcf->free_ctx; 161 | 162 | if (ctx == NULL) { 163 | ctx = ngx_pcalloc(cycle->pool, sizeof(ngx_dynamic_resolver_ctx_t)); 164 | 165 | if (ctx == NULL) { 166 | ngx_log_error(NGX_LOG_ERR, cycle->log, 0, "dynamic resolver, " 167 | "alloc memory dynamic resolver ctx failed"); 168 | return NULL; 169 | } 170 | ++drcf->nalloc_ctx; 171 | } else { 172 | drcf->free_ctx = drcf->free_ctx->next; 173 | ngx_memzero(ctx, sizeof(ngx_dynamic_resolver_ctx_t)); 174 | --drcf->nfree_ctx; 175 | } 176 | 177 | return ctx; 178 | } 179 | 180 | static void 181 | ngx_dynamic_resolver_put_ctx(ngx_dynamic_resolver_ctx_t *ctx, 182 | ngx_cycle_t *cycle) 183 | { 184 | ngx_dynamic_resolver_conf_t *drcf; 185 | 186 | drcf = ngx_event_get_conf(cycle->conf_ctx, ngx_dynamic_resolver_module); 187 | 188 | ctx->next = drcf->free_ctx; 189 | drcf->free_ctx = ctx; 190 | ++drcf->nfree_ctx; 191 | } 192 | 193 | /* reuse for ngx_dynamic_resolver_domain_t */ 194 | static ngx_dynamic_resolver_domain_t * 195 | ngx_dynamic_resolver_get_domain(ngx_cycle_t *cycle) 196 | { 197 | ngx_dynamic_resolver_conf_t *drcf; 198 | ngx_dynamic_resolver_domain_t *domain; 199 | 200 | drcf = ngx_event_get_conf(cycle->conf_ctx, ngx_dynamic_resolver_module); 201 | 202 | domain = drcf->free_domain; 203 | 204 | if (domain == NULL) { 205 | domain = ngx_pcalloc(cycle->pool, 206 | sizeof(ngx_dynamic_resolver_domain_t)); 207 | 208 | if (domain == NULL) { 209 | ngx_log_error(NGX_LOG_ERR, cycle->log, 0, "dynamic resolver, " 210 | "alloc memory dynamic resolver domain failed"); 211 | return NULL; 212 | } 213 | ++drcf->nalloc_domain; 214 | } else { 215 | drcf->free_domain = drcf->free_domain->next; 216 | ngx_memzero(domain, sizeof(ngx_dynamic_resolver_domain_t)); 217 | --drcf->nfree_domain; 218 | } 219 | 220 | return domain; 221 | } 222 | 223 | static void 224 | ngx_dynamic_resolver_put_domain(ngx_dynamic_resolver_domain_t *domain, 225 | ngx_cycle_t *cycle) 226 | { 227 | ngx_dynamic_resolver_conf_t *drcf; 228 | 229 | drcf = ngx_event_get_conf(cycle->conf_ctx, ngx_dynamic_resolver_module); 230 | 231 | domain->next = drcf->free_domain; 232 | drcf->free_domain = domain; 233 | ++drcf->nfree_domain; 234 | } 235 | 236 | 237 | static void 238 | ngx_dynamic_resolver_on_result(void *data, ngx_resolver_addr_t *addrs, 239 | ngx_uint_t naddrs) 240 | { 241 | ngx_dynamic_resolver_domain_t *domain; 242 | ngx_dynamic_resolver_ctx_t *ctx; 243 | ngx_uint_t i, n; 244 | 245 | domain = data; 246 | 247 | if (domain == NULL) { 248 | ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, 0, "dynamic resolver, " 249 | "%V has been deleted", &domain->domain); 250 | return; 251 | } 252 | 253 | if (naddrs == 0) { 254 | ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, 0, "dynamic resolver, " 255 | "domain '%V' resolver failed", &domain->domain); 256 | 257 | while (domain->ctx) { 258 | ctx = domain->ctx; 259 | domain->ctx = ctx->next; 260 | 261 | ctx->h(ctx->data, NULL, 0); 262 | ngx_dynamic_resolver_put_ctx(ctx, (ngx_cycle_t *) ngx_cycle); 263 | } 264 | 265 | return; 266 | } 267 | 268 | domain->naddrs = ngx_min(naddrs, MAX_ADDRS); 269 | for (i = 0; i < domain->naddrs; ++i) { 270 | ngx_memcpy(&domain->addrs[i].sockaddr, addrs[i].sockaddr, 271 | addrs[i].socklen); 272 | domain->addrs[i].socklen = addrs[i].socklen; 273 | domain->addrs[i].priority = addrs[i].priority; 274 | domain->addrs[i].weight = addrs[i].weight; 275 | 276 | n = ngx_random() % domain->naddrs; 277 | 278 | while (domain->ctx) { 279 | ngx_log_debug1(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, 280 | "dynamic resolver, resolver '%V' successd", 281 | &domain->domain); 282 | ctx = domain->ctx; 283 | domain->ctx = ctx->next; 284 | 285 | ctx->h(ctx->data, &domain->addrs[n].sockaddr, 286 | domain->addrs[n].socklen); 287 | ngx_dynamic_resolver_put_ctx(ctx, (ngx_cycle_t *) ngx_cycle); 288 | 289 | ++n; 290 | n %= domain->naddrs; 291 | } 292 | } 293 | } 294 | 295 | static void 296 | ngx_dynamic_resolver_on_timer(void *data) 297 | { 298 | ngx_dynamic_resolver_conf_t *drcf; 299 | ngx_dynamic_resolver_domain_t *domain; 300 | ngx_uint_t i; 301 | 302 | if (ngx_exiting) { 303 | return; 304 | } 305 | 306 | drcf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_dynamic_resolver_module); 307 | 308 | for (i = 0; i < drcf->domain_buckets; ++i) { 309 | domain = drcf->resolver_hash[i]; 310 | while (domain) { 311 | ngx_log_debug1(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, 312 | "dynamic resolver, on timer start resolver %V", 313 | &domain->domain); 314 | 315 | ngx_event_resolver_start_resolver(&domain->domain, 316 | ngx_dynamic_resolver_on_result, domain); 317 | domain = domain->next; 318 | } 319 | } 320 | 321 | ngx_event_timer_add_timer(drcf->refresh_interval, 322 | ngx_dynamic_resolver_on_timer, NULL); 323 | } 324 | 325 | static ngx_int_t 326 | ngx_dynamic_resolver_process_init(ngx_cycle_t *cycle) 327 | { 328 | ngx_dynamic_resolver_conf_t *drcf; 329 | 330 | drcf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_dynamic_resolver_module); 331 | if (drcf->refresh_interval == 0) { 332 | return NGX_OK; 333 | } 334 | 335 | ngx_event_timer_add_timer(0, ngx_dynamic_resolver_on_timer, NULL); 336 | 337 | return NGX_OK; 338 | } 339 | 340 | 341 | void 342 | ngx_dynamic_resolver_add_domain(ngx_str_t *domain, ngx_cycle_t *cycle) 343 | { 344 | ngx_dynamic_resolver_conf_t *drcf; 345 | ngx_dynamic_resolver_domain_t *d; 346 | ngx_uint_t idx; 347 | struct sockaddr sa; 348 | socklen_t len; 349 | u_char temp[MAX_DOMAIN_LEN]; 350 | 351 | if (domain == NULL || domain->len == 0) { 352 | ngx_log_error(NGX_LOG_ERR, cycle->log, 0, 353 | "dynamic resolver add, domain is NULL"); 354 | return; 355 | } 356 | 357 | len = ngx_sock_pton(&sa, domain->data, domain->len); 358 | /* addr is IP address */ 359 | if (len) { 360 | ngx_log_error(NGX_LOG_DEBUG_CORE, cycle->log, 0, 361 | "dynamic resolver add, domain is ipv4/ipv6/unix address"); 362 | 363 | return; 364 | } 365 | 366 | drcf = ngx_event_get_conf(cycle->conf_ctx, ngx_dynamic_resolver_module); 367 | if (drcf->refresh_interval == 0) { 368 | ngx_log_error(NGX_LOG_ERR, cycle->log, 0, "dynamic resolver add, " 369 | "dynamic resolver closed when add domain"); 370 | return; 371 | } 372 | 373 | if (domain->len > MAX_DOMAIN_LEN) { 374 | ngx_log_error(NGX_LOG_ERR, cycle->log, 0, "dynamic resolver add, " 375 | "domain length(%z) is too long", domain->len); 376 | return; 377 | } 378 | 379 | ngx_memzero(temp, MAX_DOMAIN_LEN); 380 | idx = ngx_hash_strlow(temp, domain->data, domain->len); 381 | idx %= drcf->domain_buckets; 382 | 383 | ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0, "dynamic resolver add, " 384 | "prepare add %V in %d slot", domain, idx); 385 | 386 | for (d = drcf->resolver_hash[idx]; d; d = d->next) { 387 | 388 | if (d->domain.len == domain->len && 389 | ngx_memcmp(d->domain.data, temp, domain->len) == 0) 390 | { 391 | ngx_log_debug1(NGX_LOG_DEBUG_CORE, cycle->log, 0, 392 | "dynamic resolver add, %V is in dynamic resolv hash table", 393 | domain); 394 | return; 395 | } 396 | } 397 | 398 | d = ngx_dynamic_resolver_get_domain(cycle); 399 | if (d == NULL) { 400 | return; 401 | } 402 | 403 | /* add domain in dynamic resolver */ 404 | d->next = drcf->resolver_hash[idx]; 405 | drcf->resolver_hash[idx] = d; 406 | 407 | ngx_memcpy(d->domain_cstr, temp, MAX_DOMAIN_LEN); 408 | d->domain.data = d->domain_cstr; 409 | d->domain.len = domain->len; 410 | } 411 | 412 | void 413 | ngx_dynamic_resolver_del_domain(ngx_str_t *domain) 414 | { 415 | ngx_dynamic_resolver_conf_t *drcf; 416 | ngx_dynamic_resolver_domain_t **pd, *d; 417 | ngx_dynamic_resolver_ctx_t *ctx; 418 | ngx_uint_t idx; 419 | struct sockaddr sa; 420 | socklen_t len; 421 | u_char temp[MAX_DOMAIN_LEN]; 422 | 423 | if (domain == NULL || domain->len == 0) { 424 | ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, 425 | "dynamic resolver del, domain is NULL"); 426 | return; 427 | } 428 | 429 | len = ngx_sock_pton(&sa, domain->data, domain->len); 430 | /* addr is IP address */ 431 | if (len) { 432 | ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, 433 | "dynamic resolver del, domain is ipv4/ipv6/unix address"); 434 | 435 | return; 436 | } 437 | 438 | drcf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_dynamic_resolver_module); 439 | if (drcf->refresh_interval == 0) { 440 | ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "dynamic resolver del, " 441 | "dynamic resolver closed when del domain"); 442 | return; 443 | } 444 | 445 | if (domain->len > MAX_DOMAIN_LEN) { 446 | ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "dynamic resolver del, " 447 | "domain length(%z) is too long", domain->len); 448 | return; 449 | } 450 | 451 | ngx_memzero(temp, MAX_DOMAIN_LEN); 452 | idx = ngx_hash_strlow(temp, domain->data, domain->len); 453 | idx %= drcf->domain_buckets; 454 | 455 | ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, 0, "dynamic resolver del, " 456 | "prepare del %V in %d slot", domain, idx); 457 | 458 | for (pd = &drcf->resolver_hash[idx]; *pd; pd = &(*pd)->next) { 459 | 460 | if ((*pd)->domain.len == domain->len && 461 | ngx_memcmp((*pd)->domain.data, temp, domain->len) == 0) 462 | { 463 | d= *pd; 464 | *pd = (*pd)->next; 465 | 466 | while (d->ctx) { 467 | ctx = d->ctx; 468 | d->ctx = ctx->next; 469 | 470 | ctx->h(ctx->data, NULL, 0); 471 | ngx_dynamic_resolver_put_ctx(ctx, (ngx_cycle_t *) ngx_cycle); 472 | } 473 | 474 | ngx_dynamic_resolver_put_domain(d, (ngx_cycle_t *) ngx_cycle); 475 | 476 | return; 477 | } 478 | } 479 | 480 | ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, 0, "dynamic resolver del, " 481 | "%V is not in dynamic resolv hash table", domain); 482 | } 483 | 484 | void 485 | ngx_dynamic_resolver_start_resolver(ngx_str_t *domain, 486 | ngx_dynamic_resolver_handler_pt h, void *data) 487 | { 488 | ngx_dynamic_resolver_conf_t *drcf; 489 | ngx_dynamic_resolver_domain_t *d; 490 | ngx_dynamic_resolver_ctx_t *ctx; 491 | ngx_uint_t idx, n; 492 | struct sockaddr sa; 493 | socklen_t len; 494 | u_char temp[MAX_DOMAIN_LEN]; 495 | 496 | if (domain == NULL || domain->len == 0) { 497 | ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, 498 | "dynamic resolver async, domain is NULL"); 499 | return; 500 | } 501 | 502 | len = ngx_sock_pton(&sa, domain->data, domain->len); 503 | /* addr is ipv4/ipv6/unix address */ 504 | if (len) { 505 | ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, 506 | "dynamic resolver async, domain is ipv4/ipv6/unix address"); 507 | 508 | h(data, &sa, len); 509 | 510 | return; 511 | } 512 | 513 | drcf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_dynamic_resolver_module); 514 | if (drcf->refresh_interval == 0) { 515 | ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "dynamic resolver async, " 516 | "dynamic resolver closed when start resolver"); 517 | goto failed; 518 | } 519 | 520 | if (domain->len > MAX_DOMAIN_LEN) { 521 | ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "dynamic resolver async, " 522 | "domain length(%z) is too long", domain->len); 523 | goto failed; 524 | } 525 | 526 | ngx_memzero(temp, MAX_DOMAIN_LEN); 527 | idx = ngx_hash_strlow(temp, domain->data, domain->len); 528 | idx %= drcf->domain_buckets; 529 | 530 | d = drcf->resolver_hash[idx]; 531 | while (d) { 532 | if (d->domain.len == domain->len && 533 | ngx_memcmp(d->domain.data, temp, domain->len) == 0) 534 | { 535 | break; 536 | } 537 | 538 | ctx = ctx->next; 539 | } 540 | 541 | if (d == NULL) { /* not found */ 542 | d = ngx_dynamic_resolver_get_domain((ngx_cycle_t *) ngx_cycle); 543 | if (d == NULL) { 544 | goto failed; 545 | } 546 | 547 | /* add domain in dynamic resolver */ 548 | d->next = drcf->resolver_hash[idx]; 549 | drcf->resolver_hash[idx] = d; 550 | 551 | ngx_memcpy(d->domain_cstr, temp, MAX_DOMAIN_LEN); 552 | d->domain.data = d->domain_cstr; 553 | d->domain.len = domain->len; 554 | } 555 | 556 | /* domain is not resolved */ 557 | if (d->naddrs == 0) { 558 | 559 | /* add call back in resolver list */ 560 | ctx = ngx_dynamic_resolver_get_ctx((ngx_cycle_t *) ngx_cycle); 561 | if (ctx == NULL) { 562 | goto failed; 563 | } 564 | 565 | ngx_log_debug1(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, 566 | "dynamic resolver async, domain '%V' is not resolved", 567 | &d->domain); 568 | ctx->h = h; 569 | ctx->data = data; 570 | 571 | ctx->next = d->ctx; 572 | d->ctx = ctx; 573 | 574 | ngx_event_resolver_start_resolver(&d->domain, 575 | ngx_dynamic_resolver_on_result, d); 576 | 577 | return; 578 | } 579 | 580 | ngx_log_debug1(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, 581 | "dynamic resolver async, domain '%V' is resolved, call directly", 582 | &d->domain); 583 | 584 | /* call callback */ 585 | n = ngx_random() % d->naddrs; 586 | h(data, &d->addrs[n].sockaddr, d->addrs[n].socklen); 587 | 588 | return; 589 | 590 | failed: 591 | 592 | h(data, NULL, 0); 593 | } 594 | 595 | socklen_t 596 | ngx_dynamic_resolver_gethostbyname(ngx_str_t *domain, struct sockaddr *sa) 597 | { 598 | ngx_dynamic_resolver_conf_t *drcf; 599 | ngx_dynamic_resolver_domain_t *d; 600 | ngx_uint_t idx, n; 601 | socklen_t len; 602 | u_char temp[MAX_DOMAIN_LEN]; 603 | 604 | if (domain == NULL) { 605 | ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, 606 | "dynamic resolver sync, domain is NULL"); 607 | return 0; 608 | } 609 | 610 | len = ngx_sock_pton(sa, domain->data, domain->len); 611 | /* addr is ipv4/ipv6/unix address */ 612 | if (len) { 613 | ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, 614 | "dynamic resolver sync, domain is ipv4/ipv6/unix address"); 615 | 616 | return len; 617 | } 618 | 619 | drcf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_dynamic_resolver_module); 620 | if (drcf->refresh_interval == 0) { 621 | ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "dynamic resolver sync, " 622 | "dynamic resolver closed when start resolver"); 623 | return 0; 624 | } 625 | 626 | if (domain->len > MAX_DOMAIN_LEN) { 627 | ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "dynamic resolver sync, " 628 | "domain length(%z) is too long", domain->len); 629 | return 0; 630 | } 631 | 632 | ngx_memzero(temp, MAX_DOMAIN_LEN); 633 | idx = ngx_hash_strlow(temp, domain->data, domain->len); 634 | idx %= drcf->domain_buckets; 635 | 636 | d = drcf->resolver_hash[idx]; 637 | while (d) { 638 | if (d->domain.len == domain->len && 639 | ngx_memcmp(d->domain.data, temp, domain->len) == 0) 640 | { 641 | if (d->naddrs == 0) { 642 | ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, 0, 643 | "dynamic resolver sync, domain '%V' is not resolved", 644 | &d->domain); 645 | return 0; 646 | } 647 | 648 | n = ngx_random() % d->naddrs; 649 | ngx_memcpy(sa, &d->addrs[n].sockaddr, d->addrs[n].socklen); 650 | 651 | return d->addrs[n].socklen; 652 | } 653 | 654 | d = d->next; 655 | } 656 | 657 | ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, 0, "dynamic resolver sync, " 658 | "domain '%V' is not in dynamic resolver table", domain); 659 | 660 | return 0; 661 | } 662 | 663 | ngx_chain_t * 664 | ngx_dynamic_resolver_state(ngx_http_request_t *r) 665 | { 666 | ngx_dynamic_resolver_conf_t *drcf; 667 | ngx_chain_t *cl; 668 | ngx_buf_t *b; 669 | size_t len; 670 | 671 | drcf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_dynamic_resolver_module); 672 | 673 | len = sizeof("##########dynamic resolver state##########\n") - 1 674 | + sizeof("ngx_dynamic_resolver alloc ctx: \n") - 1 + NGX_OFF_T_LEN 675 | + sizeof("ngx_dynamic_resolver free ctx: \n") - 1 + NGX_OFF_T_LEN 676 | + sizeof("ngx_dynamic_resolver alloc domain: \n") - 1 + NGX_OFF_T_LEN 677 | + sizeof("ngx_dynamic_resolver free domain: \n") - 1 + NGX_OFF_T_LEN; 678 | 679 | cl = ngx_alloc_chain_link(r->pool); 680 | if (cl == NULL) { 681 | return NULL; 682 | } 683 | cl->next = NULL; 684 | 685 | b = ngx_create_temp_buf(r->pool, len); 686 | if (b == NULL) { 687 | return NULL; 688 | } 689 | cl->buf = b; 690 | 691 | b->last = ngx_snprintf(b->last, len, 692 | "##########dynamic resolver state##########\n" 693 | "ngx_dynamic_resolver alloc ctx: %ui\n" 694 | "ngx_dynamic_resolver free ctx: %ui\n" 695 | "ngx_dynamic_resolver alloc domain: %ui\n" 696 | "ngx_dynamic_resolver free domain: %ui\n", 697 | drcf->nalloc_ctx, drcf->nfree_ctx, 698 | drcf->nalloc_domain, drcf->nfree_domain); 699 | 700 | return cl; 701 | } 702 | --------------------------------------------------------------------------------