...
 
Commits (2)
......@@ -24,7 +24,7 @@ Build-Depends: debhelper (>= 10),
po-debconf,
quilt,
zlib1g-dev
Standards-Version: 4.1.3
Standards-Version: 4.1.4
Homepage: http://nginx.net
Vcs-Git: https://salsa.debian.org/nginx-team/nginx.git
Vcs-Browser: https://salsa.debian.org/nginx-team/nginx
......@@ -439,6 +439,7 @@ Description: virtual host traffic status module for Nginx
the live activity monitoring of nginx plus.
.
VTS provides access to virtual host status information.
Package: libnginx-mod-http-auth-ldap
Architecture: any
Depends: ${misc:Depends}, ${shlibs:Depends}
......@@ -447,12 +448,14 @@ Description: LDAP authentication module for Nginx
.
The module uses LDAP as a backend for simple http authentication. It
also allows one to use multiple LDAP servers.
Package: libnginx-mod-http-upsync
Architecture: any
Depends: ${misc:Depends}, ${shlibs:Depends}
Description: dynamic upstreams via consul or etcd for Nginx
Sync upstreams from consul or etcd, dynamically modify backend servers
attributes like weight, max_fails etc. without the need to reload nginx.
Package: libnginx-mod-http-stream-server-traffic-status
Architecture: any
Depends: ${misc:Depends}, ${shlibs:Depends},
......
......@@ -34,7 +34,7 @@ Patch:
Module: nchan
Homepage: https://github.com/slact/nchan
Version: 1.2.5
Version: 1.2.6
Files-Excluded: dev nchan_logo.png NchanSubscriber.js
Module: http-uploadprogress
......
......@@ -22,7 +22,7 @@ In a web browser, you can use Websocket or EventSource natively, or the [NchanSu
## Status and History
The latest Nchan release is 1.2.5 (March 20, 2019) ([changelog](https://nchan.io/changelog)).
The latest Nchan release is 1.2.6 (June 18, 2019) ([changelog](https://nchan.io/changelog)).
The first iteration of Nchan was written in 2009-2010 as the [Nginx HTTP Push Module](https://pushmodule.slact.net), and was vastly refactored into its present state in 2014-2016.
......@@ -1264,10 +1264,10 @@ Additionally, `nchan_stub_status` data is also exposed as variables. These are a
- **nchan_max_channel_id_length** `<number>`
arguments: 1
default: `512`
default: `1024`
context: http, server, location
legacy name: push_max_channel_id_length
> Maximum permissible channel id length (number of characters). Longer ids will be truncated.
> Maximum permissible channel id length (number of characters). This settings applies to ids before they may be split by the `nchan_channel_id_split_delimiter` Requests with a channel id that is too long will receive a `403 Forbidden` response.
- **nchan_max_channel_subscribers** `<number>`
arguments: 1
......
1.2.6 (Jun. 18 2019)
fix: when using Redis, a channel can stop receiving new messages if
they are published faster than they can be sent to subscribers and the
message buffer is sufficiently small
fix: websocket PONG response did not contain PING frame data
fix: multiplexed channels may stop receiving messages
fix (security): specially crafted websocket publisher requests when using Redis
may result in use-after-free memory access
fix: Nginx config reload may result in crash when using Redis cluster
1.2.5 (Mar. 20 2019)
fix: using multiplexed channels with Redis in backup mode may result in worker crash
fix: nchan_publisher_channel_id could not be set exclusively in a publisher location
......
......@@ -674,8 +674,8 @@ CfCmd.new do
group: "security",
tags: ['publisher', 'subscriber', 'channel-id' ],
value: "<number>",
default: 512,
info: "Maximum permissible channel id length (number of characters). Longer ids will be truncated."
default: 1024,
info: "Maximum permissible channel id length (number of characters). This settings applies to ids before they may be split by the `nchan_channel_id_split_delimiter` Requests with a channel id that is too long will receive a `403 Forbidden` response."
nchan_max_channel_subscribers [:main, :srv, :loc],
:ngx_conf_set_num_slot,
......
#define NCHAN_VERSION "1.2.5"
#define NCHAN_VERSION "1.2.6"
......@@ -1069,7 +1069,7 @@ static memstore_channel_head_t *chanhead_memstore_create(ngx_str_t *channel_id,
#endif
head->multi=NULL;
head->multi_count = 0;
head->multi_waiting = 0;
head->multi_subscribers_pending = 0;
//set channel
ngx_memcpy(&head->channel.id, &head->id, sizeof(ngx_str_t));
......@@ -1088,7 +1088,6 @@ static memstore_channel_head_t *chanhead_memstore_create(ngx_str_t *channel_id,
head->spooler.running=0;
head->multi_waiting = 0;
if((n = parse_multi_id(&head->id, ids)) > 0) {
memstore_multi_t *multi;
int16_t *tags_latest, *tags_oldest;
......@@ -1127,11 +1126,13 @@ static memstore_channel_head_t *chanhead_memstore_create(ngx_str_t *channel_id,
}
head->multi_count = n;
head->multi_subscribers_pending = n;
head->multi = multi;
head->owner = head->slot; //multis are always self-owned
}
else {
head->multi_count = 0;
head->multi_subscribers_pending = n;
head->latest_msgid.time = 0;
head->latest_msgid.tag.fixed[0] = 0;
......
......@@ -57,7 +57,7 @@ struct memstore_channel_head_s {
uint16_t reserved;
#endif
uint8_t multi_waiting;
uint8_t multi_subscribers_pending;
uint8_t multi_count;
memstore_multi_t *multi;
......
......@@ -1977,6 +1977,7 @@ static void nchan_store_create_main_conf(ngx_conf_t *cf, nchan_main_conf_t *mcf)
//reset redis_conf_head for reloads
redis_conf_head = NULL;
nodeset_destroy_all(); //reset all nodesets before loading config
}
void redis_store_prepare_to_exit_worker() {
......@@ -2021,7 +2022,6 @@ static void nchan_store_exit_worker(ngx_cycle_t *cycle) {
//OLD
//rbtree_walk(&redis_data_tree, (rbtree_walk_callback_pt )redis_data_tree_exiter_stage2, &chanheads);
nodeset_destroy_all();
//OLD
......
......@@ -881,7 +881,6 @@ void node_set_role(redis_node_t *node, redis_node_role_t role) {
node->peers.master = NULL;
}
for(cur = nchan_list_first(&node->peers.slaves); cur != NULL; cur = nchan_list_next(cur)) {
assert((*cur)->peers.master == node);
node_remove_peer(*cur, node);
}
nchan_list_empty(&node->peers.slaves);
......
......@@ -388,6 +388,7 @@ static ngx_int_t spool_fetch_msg_callback(ngx_int_t code, nchan_msg_t *msg, fetc
if(spool->reserved == 0) {
destroy_spool(spool);
}
spool_fetch_msg(nuspool);
}
else if(spool->id.tagcount == 1 && nchan_compare_msgids(&spool->id, &oldest_msg_id) == 0) {
// oldest msgid not found or expired. that means there are no messages in this channel,
......
......@@ -44,9 +44,9 @@ static void change_sub_count(memstore_channel_head_t *ch, ngx_int_t n) {
static ngx_int_t sub_enqueue(ngx_int_t status, void *ptr, sub_data_t *d) {
DBG("%p enqueued (%p %V %i) %V", d->multi->sub, d->multi_chanhead, &d->multi_chanhead->id, d->n, &d->multi->id);
assert(d->multi_chanhead->multi_waiting > 0);
d->multi_chanhead->multi_waiting --;
if(d->multi_chanhead->multi_waiting == 0) {
assert(d->multi_chanhead->multi_subscribers_pending > 0);
d->multi_chanhead->multi_subscribers_pending --;
if(d->multi_chanhead->multi_subscribers_pending == 0) {
memstore_ready_chanhead_unless_stub(d->multi_chanhead);
}
......@@ -56,7 +56,7 @@ static ngx_int_t sub_enqueue(ngx_int_t status, void *ptr, sub_data_t *d) {
static ngx_int_t sub_dequeue(ngx_int_t status, void *ptr, sub_data_t* d) {
DBG("%p dequeued (%p %V %i) %V", d->multi->sub, d->multi_chanhead, &d->multi_chanhead->id, d->n, &d->multi->id);
d->multi_chanhead->status = WAITING;
d->multi_chanhead->multi_waiting++;
d->multi_chanhead->multi_subscribers_pending++;
d->multi->sub = NULL;
return NGX_OK;
......@@ -152,18 +152,19 @@ subscriber_t *memstore_multi_subscriber_create(memstore_channel_head_t *chanhead
sub->destroy_after_dequeue = 1;
sub->dequeue_after_response = 0;
//DBG("create multi sub for %V (n=%i) pending=%i", &chanhead->multi[n].id, n, chanhead->multi_subscribers_pending);
d->multi = &chanhead->multi[n];
d->multi->sub = sub;
d->multi_chanhead = chanhead;
d->n = n;
chanhead->multi_waiting++;
d->target_chanhead = target_ch;
assert(chanhead->multi_subscribers_pending > 0);
target_ch->spooler.fn->add(&target_ch->spooler, sub);
multi_subs = chanhead->shared->sub_count;
d->target_chanhead = target_ch;
change_sub_count(target_ch, multi_subs);
DBG("%p created with privdata %p", d->multi->sub, d);
......
......@@ -472,7 +472,7 @@ static ngx_int_t websocket_publish_callback(ngx_int_t status, nchan_channel_t *c
}
d = NULL;
if(websocket_release(&fsub->sub, 0) == NGX_ABORT) {
if(websocket_release(&fsub->sub, 0) == NGX_ABORT || fsub->sub.status == DEAD) {
//zombie publisher
//nothing more to do, we're finished here
return NGX_OK;
......@@ -839,10 +839,6 @@ ngx_int_t websocket_subscriber_destroy(subscriber_t *sub) {
websocket_delete_timers(fsub);
nchan_free_msg_id(&sub->last_msgid);
//debug
if(fsub->cln) {
fsub->cln->data = NULL;
}
//ngx_memset(fsub, 0x13, sizeof(*fsub));
ws_destroy_msgpool(fsub);
if(fsub->deflate.zstream_in) {
......@@ -1155,9 +1151,9 @@ static ngx_int_t websocket_reserve(subscriber_t *self) {
}
static ngx_int_t websocket_release(subscriber_t *self, uint8_t nodestroy) {
full_subscriber_t *fsub = (full_subscriber_t *)self;
//DBG("%p release for req %p, reservations: %i", self, fsub->sub.request, self->reserved);
assert(self->reserved > 0);
self->reserved--;
//DBG("%p release for req %p, reservations: %i", self, fsub->sub.request, self->reserved);
if(nodestroy == 0 && fsub->awaiting_destruction == 1 && self->reserved == 0) {
websocket_subscriber_destroy(self);
return NGX_ABORT;
......@@ -1305,8 +1301,6 @@ static void websocket_reading(ngx_http_request_t *r) {
ngx_connection_t *c;
ngx_buf_t *msgbuf, buf;
//ngx_str_t msg_in_str;
int close_code;
ngx_str_t close_reason;
c = r->connection;
rev = c->read;
......@@ -1389,66 +1383,75 @@ static void websocket_reading(ngx_http_request_t *r) {
case WEBSOCKET_OPCODE_PING:
case WEBSOCKET_OPCODE_PONG:
case WEBSOCKET_OPCODE_CLOSE:
if (frame->payload_len == 0) {
frame->payload = NULL;
}
else if(frame->payload_len < 1024) {
u_char payloadbuf[1024];
frame->payload = payloadbuf;
frame->last = frame->payload;
set_buffer(&buf, frame->payload, frame->last, frame->payload_len);
if ((rc = ws_recv(c, rev, &buf, frame->payload_len)) != NGX_OK) {
ERR("ws_recv NOT OK when receiving payload");
goto exit;
}
if (frame->mask) {
websocket_unmask_frame(frame);
}
}
else {
//ERROR: frame too big
websocket_send_close_frame(fsub, CLOSE_MESSAGE_TOO_BIG, NULL);
return websocket_reading_finalize(r);
}
switch(frame->opcode) {
case WEBSOCKET_OPCODE_PING:
DBG("%p got pinged", fsub);
websocket_send_frame(fsub, WEBSOCKET_PONG_LAST_FRAME_BYTE, 0, NULL);
break;
case WEBSOCKET_OPCODE_PONG:
DBG("%p Got ponged", fsub);
if(fsub->awaiting_pong) {
fsub->awaiting_pong = 0;
}
// unsolicited pongs are ok too as per
// https://tools.ietf.org/html/rfc6455#page-37
break;
{ //block-scope these vars
u_char payloadbuf[1024];
int close_code;
ngx_str_t payload_str;
nchan_buf_and_chain_t *bc;
case WEBSOCKET_OPCODE_CLOSE:
fsub->received_close_frame = 1;
if(frame->payload_len >= 2) {
ngx_memcpy(&close_code, frame->payload, 2);
close_code = ntohs(close_code);
close_reason.data = frame->payload + 2;
close_reason.len = frame->payload_len - 2;
}
else {
close_code = 0;
close_reason.data = (u_char *)"";
close_reason.len = 0;
if (frame->payload_len == 0) {
frame->payload = NULL;
}
else if(frame->payload_len < 1024) {
frame->payload = payloadbuf;
frame->last = frame->payload;
set_buffer(&buf, frame->payload, frame->last, frame->payload_len);
if ((rc = ws_recv(c, rev, &buf, frame->payload_len)) != NGX_OK) {
ERR("ws_recv NOT OK when receiving payload");
goto exit;
}
DBG("%p wants to close (code %i reason \"%V\")", fsub, close_code, &close_reason);
if(!fsub->sent_close_frame) {
websocket_send_close_frame(fsub, close_code, &close_reason);
if (frame->mask) {
websocket_unmask_frame(frame);
}
}
else {
//ERROR: frame too big
websocket_send_close_frame(fsub, CLOSE_MESSAGE_TOO_BIG, NULL);
return websocket_reading_finalize(r);
break; //good practice?
}
switch(frame->opcode) {
case WEBSOCKET_OPCODE_PING:
bc = nchan_bufchain_pool_reserve(fsub->ctx->bcp, 1);
DBG("%p got pinged", fsub);
init_buf(&bc->buf, 1);
payload_str.data = frame->payload;
payload_str.len = frame->payload_len;
set_buf_to_str(&bc->buf, &payload_str);
websocket_send_frame(fsub, WEBSOCKET_PONG_LAST_FRAME_BYTE, frame->payload_len, &bc->chain);
break;
case WEBSOCKET_OPCODE_PONG:
DBG("%p Got ponged", fsub);
if(fsub->awaiting_pong) {
fsub->awaiting_pong = 0;
}
// unsolicited pongs are ok too as per
// https://tools.ietf.org/html/rfc6455#page-37
break;
case WEBSOCKET_OPCODE_CLOSE:
fsub->received_close_frame = 1;
if(frame->payload_len >= 2) {
ngx_memcpy(&close_code, frame->payload, 2);
close_code = ntohs(close_code);
payload_str.data = frame->payload + 2;
payload_str.len = frame->payload_len - 2;
}
else {
close_code = 0;
payload_str.data = (u_char *)"";
payload_str.len = 0;
}
DBG("%p wants to close (code %i reason \"%V\")", fsub, close_code, &payload_str);
if(!fsub->sent_close_frame) {
websocket_send_close_frame(fsub, close_code, &payload_str);
}
return websocket_reading_finalize(r);
break; //good practice?
}
}
break;
case WEBSOCKET_OPCODE_TEXT:
case WEBSOCKET_OPCODE_BINARY:
......
From 26d7114ac82195cd4f7db606d7762a6cff9132ad Mon Sep 17 00:00:00 2001
From: Hiroaki Nakamura <hnakamur@gmail.com>
Date: Fri, 12 Feb 2016 09:03:35 +0900
Subject: [PATCH] Convert a config file to build a dynamic module
Origin: other, https://github.com/FRiCKLE/ngx_cache_purge/pull/45
---
config | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/config b/config
index 34f42ec..b900680 100644
--- a/config
+++ b/config
@@ -15,7 +15,17 @@ if [ "$HTTP_UWSGI" = "YES" ]; then
fi
ngx_addon_name=ngx_http_cache_purge_module
-HTTP_MODULES="$HTTP_MODULES ngx_http_cache_purge_module"
-NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_cache_purge_module.c"
+CACHE_PURGE_SRCS="$ngx_addon_dir/ngx_cache_purge_module.c"
+
+if [ -n "$ngx_module_link" ]; then
+ ngx_module_type=HTTP
+ ngx_module_name="$ngx_addon_name"
+ ngx_module_srcs="$CACHE_PURGE_SRCS"
+
+ . auto/module
+else
+ HTTP_MODULES="$HTTP_MODULES $ngx_addon_name"
+ NGX_ADDON_SRCS="$NGX_ADDON_SRCS $CACHE_PURGE_SRCS"
+fi
have=NGX_CACHE_PURGE_MODULE . auto/have
From: Pawel Sulowicz <Pawel.Sulowicz@grupaonet.pl>
Date: Thu, 2 Feb 2017 09:39:37 +0100
Subject: [PATCH] Fix compatibility with nginx-1.11.6+
Origin: other, https://github.com/FRiCKLE/ngx_cache_purge/pull/51
---
ngx_cache_purge_module.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/ngx_cache_purge_module.c b/ngx_cache_purge_module.c
index 62d3818..fd1ebde 100644
--- a/ngx_cache_purge_module.c
+++ b/ngx_cache_purge_module.c
@@ -492,7 +492,11 @@ typedef struct {
ngx_str_t body_source;
# endif /* nginx_version < 1007008 */
+# if (nginx_version >= 1011006)
+ ngx_http_complex_value_t *method;
+# else
ngx_str_t method;
+# endif /* nginx_version >= 1011006 */
ngx_str_t location;
ngx_str_t url;
dynamic-module.patch
segfault-1.11.6.patch
v0.1.1 [Wed Jul 04 2018 YoungJoo.Kim <vozltx@gmail.com>]
* Feature: added server_traffic_status_average_method directive to support
for selecting an average formula.
* Feature: added server_traffic_status_histogram_buckets directive to set
the histogram type of request processing time.
* Bugfix: fixed to display all A records of server without zone directive
in the upstream block.
* Compatibility: fixed ngx_current_msec that changed in nginx-1.13.10
v0.1.0 [Mon Feb 20 2017 YoungJoo.Kim <vozltx@gmail.com>]
* The first version.
# vi:set ft=changelog ts=4 sw=4 et fdm=marker:
Copyright (C) 2017, YoungJoo.Kim <vozltx@gmail.com>
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
Nginx stream server traffic status core module
==========
[![License](http://img.shields.io/badge/license-BSD-brightgreen.svg)](https://github.com/vozlt/nginx-module-stream-sts/blob/master/LICENSE)
Nginx stream server traffic status core module
Table of Contents
=================
* [Version](#version)
* [Dependencies](#dependencies)
* [Screenshots](#screenshots)
* [Installation](#installation)
* [Synopsis](#synopsis)
* [Description](#description)
* [Variables](https://github.com/vozlt/nginx-module-sts#variables)
* [Directives](#directives)
* [server_traffic_status](https://github.com/vozlt/nginx-module-sts#server_traffic_status)
* [server_traffic_status_zone](https://github.com/vozlt/nginx-module-sts#server_traffic_status_zone)
* [server_traffic_status_filter](https://github.com/vozlt/nginx-module-sts#server_traffic_status_filter)
* [server_traffic_status_filter_by_set_key](https://github.com/vozlt/nginx-module-sts#server_traffic_status_filter_by_set_key)
* [server_traffic_status_filter_check_duplicate](https://github.com/vozlt/nginx-module-sts#server_traffic_status_filter_check_duplicate)
* [server_traffic_status_limit](https://github.com/vozlt/nginx-module-sts#server_traffic_status_limit)
* [server_traffic_status_limit_traffic](https://github.com/vozlt/nginx-module-sts#server_traffic_status_limit_traffic)
* [server_traffic_status_limit_traffic_by_set_key](https://github.com/vozlt/nginx-module-sts#server_traffic_status_limit_traffic_by_set_key)
* [server_traffic_status_limit_check_duplicate](https://github.com/vozlt/nginx-module-sts#server_traffic_status_limit_check_duplicate)
* [server_traffic_status_average_method](https://github.com/vozlt/nginx-module-sts#server_traffic_status_average_method)
* [server_traffic_status_histogram_buckets](https://github.com/vozlt/nginx-module-sts#server_traffic_status_histogram_buckets)
* [See Also](#see-also)
* [TODO](#todo)
* [Donation](#donation)
* [Author](#author)
## Version
This document describes nginx-module-stream-sts `v0.1.1` released on 04 Feb 2018.
## Dependencies
* [nginx](http://nginx.org)
* [nginx-module-sts](https://github.com/vozlt/nginx-module-sts)
## Compatibility
* Nginx
* 1.11.5 \<= (last tested: 1.15.0)
Earlier versions does not work.
## Screenshots
![nginx-module-sts screenshot](https://cloud.githubusercontent.com/assets/3648408/23112117/e8c56cda-f770-11e6-9c68-f57cbf4dd542.png "screenshot with deault")
## Installation
1. Clone the git repository.
```
shell> git clone git://github.com/vozlt/nginx-module-sts.git
```
```
shell> git clone git://github.com/vozlt/nginx-module-stream-sts.git
```
2. Add the module to the build configuration by adding
```
--with-stream
--add-module=/path/to/nginx-module-sts
--add-module=/path/to/nginx-module-stream-sts
```
3. Build the nginx binary.
4. Install the nginx binary.
## Synopsis
```Nginx
http {
stream_server_traffic_status_zone;
...
server {
...
location /status {
stream_server_traffic_status_display;
stream_server_traffic_status_display_format html;
}
}
}
stream {
server_traffic_status_zone;
...
server {
...
}
}
```
## Description
This is an Nginx module that provides access to stream server traffic status information.
This is a porting version of the [nginx-module-vts](https://github.com/vozlt/nginx-module-vts) to the NGINX "stream" subsystem so as to support the same features in [nginx-module-vts](https://github.com/vozlt/nginx-module-vts).
It contains the current status such as servers, upstreams, user-defined filter.
This module is the core module of two modules([nginx-module-sts](https://github.com/vozlt/nginx-module-sts), [nginx-module-stream-sts](https://github.com/vozlt/nginx-module-stream-sts)).
The functions of each module are as follows:
* [nginx-module-stream-sts](https://github.com/vozlt/nginx-module-stream-sts)
* Support for implementing stream server stats.
* Support for implementing stream filter.
* Support for implementing stream limit.
* Support for implementing stream embedded variables.
* [nginx-module-sts](https://github.com/vozlt/nginx-module-sts)
* Support for implementing display of stream server stats.
* Support for implementing control of stream server stats.
## See Also
* [nginx-module-sts](https://github.com/vozlt/nginx-module-sts)
* [nginx-module-vts](https://github.com/vozlt/nginx-module-vts)
## TODO
## Donation
[![License](http://img.shields.io/badge/PAYPAL-DONATE-yellow.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=PWWSYKQ9VKH38&lc=KR&currency_code=USD&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted)
## Author
YoungJoo.Kim(김영주) [<vozltx@gmail.com>]
ngx_addon_name=ngx_stream_server_traffic_status_module
STREAM_STS_SRCS=" \
$ngx_addon_dir/src/ngx_stream_server_traffic_status_module.c \
$ngx_addon_dir/src/ngx_stream_server_traffic_status_string.c \
$ngx_addon_dir/src/ngx_stream_server_traffic_status_shm.c \
$ngx_addon_dir/src/ngx_stream_server_traffic_status_node.c \
$ngx_addon_dir/src/ngx_stream_server_traffic_status_filter.c \
$ngx_addon_dir/src/ngx_stream_server_traffic_status_limit.c \
$ngx_addon_dir/src/ngx_stream_server_traffic_status_variables.c \
"
STREAM_STS_DEPS=" \
$ngx_addon_dir/src/ngx_stream_server_traffic_status_module.h \
$ngx_addon_dir/src/ngx_stream_server_traffic_status_string.h \
$ngx_addon_dir/src/ngx_stream_server_traffic_status_shm.h \
$ngx_addon_dir/src/ngx_stream_server_traffic_status_node.h \
$ngx_addon_dir/src/ngx_stream_server_traffic_status_filter.h \
$ngx_addon_dir/src/ngx_stream_server_traffic_status_limit.h \
$ngx_addon_dir/src/ngx_stream_server_traffic_status_variables.h \
"
if test -n "$ngx_module_link"; then
ngx_module_type=STREAM
ngx_module_name=$ngx_addon_name
ngx_module_srcs="$STREAM_STS_SRCS"
ngx_module_deps="$STREAM_STS_DEPS"
. auto/module
else
STREAM_MODULES="$STREAM_MODULES $ngx_addon_name"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $STREAM_STS_SRCS"
NGX_ADDON_DEPS="$NGX_ADDON_DEPS $STREAM_STS_DEPS"
fi
# vi:set ft=sh ts=4 sw=4 et fdm=marker:
/*
* Copyright (C) YoungJoo Kim (vozlt)
*/
#ifndef _NGX_STREAM_STS_FILTER_H_INCLUDED_
#define _NGX_STREAM_STS_FILTER_H_INCLUDED_
typedef struct {
ngx_stream_complex_value_t filter_key;
ngx_stream_complex_value_t filter_name;
} ngx_stream_server_traffic_status_filter_t;
typedef struct {
ngx_str_t key;
} ngx_stream_server_traffic_status_filter_key_t;
typedef struct {
uint32_t hash;
ngx_uint_t index;
} ngx_stream_server_traffic_status_filter_uniq_t;
typedef struct {
ngx_stream_server_traffic_status_node_t *node;
} ngx_stream_server_traffic_status_filter_node_t;
int ngx_libc_cdecl ngx_stream_server_traffic_status_filter_cmp_hashs(
const void *one, const void *two);
int ngx_libc_cdecl ngx_stream_server_traffic_status_filter_cmp_keys(
const void *one, const void *two);
ngx_int_t ngx_stream_server_traffic_status_filter_unique(
ngx_pool_t *pool, ngx_array_t **keys);
ngx_int_t ngx_stream_server_traffic_status_filter_get_keys(
ngx_stream_session_t *s, ngx_array_t **filter_keys,
ngx_rbtree_node_t *node);
ngx_int_t ngx_stream_server_traffic_status_filter_get_nodes(
ngx_stream_session_t *s, ngx_array_t **filter_nodes,
ngx_str_t *name, ngx_rbtree_node_t *node);
char *ngx_stream_server_traffic_status_filter_by_set_key(ngx_conf_t *cf,
ngx_command_t *cmd, void *conf);
#endif /* _NGX_STREAM_STS_FILTER_H_INCLUDED_ */
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
/*
* Copyright (C) YoungJoo Kim (vozlt)
*/
#ifndef _NGX_STREAM_STS_LIMIT_H_INCLUDED_
#define _NGX_STREAM_STS_LIMIT_H_INCLUDED_
typedef struct {
ngx_stream_complex_value_t key;
ngx_stream_complex_value_t variable;
ngx_atomic_t size;
ngx_uint_t code;
unsigned type; /* unsigned type:5 */
} ngx_stream_server_traffic_status_limit_t;
ngx_int_t ngx_stream_server_traffic_status_limit_handler(ngx_stream_session_t *s);
ngx_int_t ngx_stream_server_traffic_status_limit_handler_traffic(ngx_stream_session_t *s,
ngx_array_t *traffics);
ngx_int_t ngx_stream_server_traffic_status_limit_traffic_unique(
ngx_pool_t *pool, ngx_array_t **keys);
char *ngx_stream_server_traffic_status_limit_traffic(ngx_conf_t *cf,
ngx_command_t *cmd, void *conf);
char *ngx_stream_server_traffic_status_limit_traffic_by_set_key(ngx_conf_t *cf,
ngx_command_t *cmd, void *conf);
#endif /* _NGX_STREAM_STS_LIMIT_H_INCLUDED_ */
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
/*
* Copyright (C) YoungJoo Kim (vozlt)
*/
#ifndef _NGX_STREAM_STS_MODULE_H_INCLUDED_
#define _NGX_STREAM_STS_MODULE_H_INCLUDED_
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_stream.h>
#include "ngx_stream_server_traffic_status_string.h"
#include "ngx_stream_server_traffic_status_node.h"
#define NGX_STREAM_SERVER_TRAFFIC_STATUS_UPSTREAM_NO 0
#define NGX_STREAM_SERVER_TRAFFIC_STATUS_UPSTREAM_UA 1
#define NGX_STREAM_SERVER_TRAFFIC_STATUS_UPSTREAM_UG 2
#define NGX_STREAM_SERVER_TRAFFIC_STATUS_UPSTREAM_FG 3
#define NGX_STREAM_SERVER_TRAFFIC_STATUS_UPSTREAMS (u_char *) "NO\0UA\0UG\0FG\0"
#define NGX_STREAM_SERVER_TRAFFIC_STATUS_NODE_NONE 0
#define NGX_STREAM_SERVER_TRAFFIC_STATUS_NODE_FIND 1
#define NGX_STREAM_SERVER_TRAFFIC_STATUS_KEY_SEPARATOR (u_char) 0x1f
#define NGX_STREAM_SERVER_TRAFFIC_STATUS_AVERAGE_METHOD_AMM 0
#define NGX_STREAM_SERVER_TRAFFIC_STATUS_AVERAGE_METHOD_WMA 1
#define NGX_STREAM_SERVER_TRAFFIC_STATUS_DEFAULT_SHM_NAME "stream_server_traffic_status"
#define NGX_STREAM_SERVER_TRAFFIC_STATUS_DEFAULT_SHM_SIZE 0xfffff
#define NGX_STREAM_SERVER_TRAFFIC_STATUS_DEFAULT_AVG_PERIOD 60
#define ngx_stream_server_traffic_status_add_rc(s, n) { \
if(s < 200) {n->stat_1xx_counter++;} \
else if(s < 300) {n->stat_2xx_counter++;} \
else if(s < 400) {n->stat_3xx_counter++;} \
else if(s < 500) {n->stat_4xx_counter++;} \
else {n->stat_5xx_counter++;} \
}
#define ngx_stream_server_traffic_status_add_oc(o, c) { \
if (o->stat_connect_counter > c->stat_connect_counter) { \
c->stat_connect_counter_oc++; \
} \
if (o->stat_in_bytes > c->stat_in_bytes) { \
c->stat_in_bytes_oc++; \
} \
if (o->stat_out_bytes > c->stat_out_bytes) { \
c->stat_out_bytes_oc++; \
} \
if (o->stat_1xx_counter > c->stat_1xx_counter) { \
c->stat_1xx_counter_oc++; \
} \
if (o->stat_2xx_counter > c->stat_2xx_counter) { \
c->stat_2xx_counter_oc++; \
} \
if (o->stat_3xx_counter > c->stat_3xx_counter) { \
c->stat_2xx_counter_oc++; \
} \
if (o->stat_4xx_counter > c->stat_4xx_counter) { \
c->stat_4xx_counter_oc++; \
} \
if (o->stat_5xx_counter > c->stat_5xx_counter) { \
c->stat_5xx_counter_oc++; \
} \
if (o->stat_session_time_counter > c->stat_session_time_counter) { \
c->stat_session_time_counter_oc++; \
} \
}
#define ngx_stream_server_traffic_status_group_to_string(n) (u_char *) ( \
(n > 3) \
? NGX_STREAM_SERVER_TRAFFIC_STATUS_UPSTREAMS \
: NGX_STREAM_SERVER_TRAFFIC_STATUS_UPSTREAMS + 3 * n \
)
#define ngx_stream_server_traffic_status_string_to_group(s) (unsigned) ( \
{ \
unsigned n = NGX_STREAM_SERVER_TRAFFIC_STATUS_UPSTREAM_NO; \
if (*s == 'N' && *(s + 1) == 'O') { \
n = NGX_STREAM_SERVER_TRAFFIC_STATUS_UPSTREAM_NO; \
} else if (*s == 'U' && *(s + 1) == 'A') { \
n = NGX_STREAM_SERVER_TRAFFIC_STATUS_UPSTREAM_UA; \
} else if (*s == 'U' && *(s + 1) == 'G') { \
n = NGX_STREAM_SERVER_TRAFFIC_STATUS_UPSTREAM_UG; \
} else if (*s == 'F' && *(s + 1) == 'G') { \
n = NGX_STREAM_SERVER_TRAFFIC_STATUS_UPSTREAM_FG; \
} \
n; \
} \
)
#define ngx_stream_server_traffic_status_triangle(n) (unsigned) ( \
n * (n + 1) / 2 \
)
typedef struct {
ngx_rbtree_t *rbtree;
/* array of ngx_stream_server_traffic_status_filter_t */
ngx_array_t *filter_keys;
/* array of ngx_stream_server_traffic_status_limit_t */
ngx_array_t *limit_traffics;
/* array of ngx_stream_server_traffic_status_limit_t */
ngx_array_t *limit_filter_traffics;
ngx_flag_t enable;
ngx_flag_t filter_check_duplicate;
ngx_flag_t limit_check_duplicate;
ngx_stream_upstream_main_conf_t *upstream;
ngx_str_t shm_name;
ssize_t shm_size;
} ngx_stream_server_traffic_status_ctx_t;
typedef struct {
ngx_shm_zone_t *shm_zone;
ngx_str_t shm_name;
ngx_flag_t enable;
ngx_flag_t filter;
ngx_flag_t filter_check_duplicate;
/* array of ngx_stream_server_traffic_status_filter_t */
ngx_array_t *filter_keys;
ngx_flag_t limit;
ngx_flag_t limit_check_duplicate;
/* array of ngx_stream_server_traffic_status_limit_t */
ngx_array_t *limit_traffics;
/* array of ngx_stream_server_traffic_status_limit_t */
ngx_array_t *limit_filter_traffics;
ngx_stream_server_traffic_status_node_t stats;
ngx_msec_t start_msec;
ngx_flag_t average_method;
ngx_msec_t average_period;
/* array of ngx_stream_server_traffic_status_node_histogram_t */
ngx_array_t *histogram_buckets;
ngx_rbtree_node_t **node_caches;
} ngx_stream_server_traffic_status_conf_t;
ngx_msec_t ngx_stream_server_traffic_status_current_msec(void);
ngx_msec_int_t ngx_stream_server_traffic_status_session_time(ngx_stream_session_t *s);
ngx_msec_int_t ngx_stream_server_traffic_status_upstream_response_time(ngx_stream_session_t *s,
uintptr_t data);
extern ngx_module_t ngx_stream_server_traffic_status_module;
#endif /* _NGX_STREAM_STS_MODULE_H_INCLUDED_ */
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
/*
* Copyright (C) YoungJoo Kim (vozlt)
*/
#ifndef _NGX_STREAM_STS_NODE_H_INCLUDED_
#define _NGX_STREAM_STS_NODE_H_INCLUDED_
#define NGX_STREAM_SERVER_TRAFFIC_STATUS_DEFAULT_QUEUE_LEN 64
#define NGX_STREAM_SERVER_TRAFFIC_STATUS_DEFAULT_BUCKET_LEN 32
typedef struct {
ngx_msec_t time;
ngx_msec_int_t msec;
} ngx_stream_server_traffic_status_node_time_t;
typedef struct {
ngx_stream_server_traffic_status_node_time_t times[NGX_STREAM_SERVER_TRAFFIC_STATUS_DEFAULT_QUEUE_LEN];
ngx_int_t front;
ngx_int_t rear;
ngx_int_t len;
} ngx_stream_server_traffic_status_node_time_queue_t;
typedef struct {
ngx_msec_int_t msec;
ngx_atomic_t counter;
} ngx_stream_server_traffic_status_node_histogram_t;
typedef struct {
ngx_stream_server_traffic_status_node_histogram_t buckets[NGX_STREAM_SERVER_TRAFFIC_STATUS_DEFAULT_BUCKET_LEN];
ngx_int_t len;
} ngx_stream_server_traffic_status_node_histogram_bucket_t;
typedef struct {
/* unsigned type:5 */
unsigned type;
ngx_atomic_t connect_time_counter;
ngx_msec_t connect_time;
ngx_stream_server_traffic_status_node_time_queue_t connect_times;
ngx_stream_server_traffic_status_node_histogram_bucket_t connect_buckets;
ngx_atomic_t first_byte_time_counter;
ngx_msec_t first_byte_time;
ngx_stream_server_traffic_status_node_time_queue_t first_byte_times;
ngx_stream_server_traffic_status_node_histogram_bucket_t first_byte_buckets;
ngx_atomic_t session_time_counter;
ngx_msec_t session_time;
ngx_stream_server_traffic_status_node_time_queue_t session_times;
ngx_stream_server_traffic_status_node_histogram_bucket_t session_buckets;
} ngx_stream_server_traffic_status_node_upstream_t;
typedef struct {
u_char color;
ngx_atomic_t stat_connect_counter;
ngx_atomic_t stat_in_bytes;
ngx_atomic_t stat_out_bytes;
ngx_atomic_t stat_1xx_counter;
ngx_atomic_t stat_2xx_counter;
ngx_atomic_t stat_3xx_counter;
ngx_atomic_t stat_4xx_counter;
ngx_atomic_t stat_5xx_counter;
ngx_atomic_t stat_session_time_counter;
ngx_msec_t stat_session_time;
ngx_stream_server_traffic_status_node_time_queue_t stat_session_times;
ngx_stream_server_traffic_status_node_histogram_bucket_t stat_session_buckets;
/* deals with the overflow of variables */
ngx_atomic_t stat_connect_counter_oc;
ngx_atomic_t stat_in_bytes_oc;
ngx_atomic_t stat_out_bytes_oc;
ngx_atomic_t stat_1xx_counter_oc;
ngx_atomic_t stat_2xx_counter_oc;
ngx_atomic_t stat_3xx_counter_oc;
ngx_atomic_t stat_4xx_counter_oc;
ngx_atomic_t stat_5xx_counter_oc;
ngx_atomic_t stat_session_time_counter_oc;
ngx_atomic_t stat_u_connect_time_counter_oc;
ngx_atomic_t stat_u_first_byte_time_counter_oc;
ngx_atomic_t stat_u_session_time_counter_oc;
ngx_stream_server_traffic_status_node_upstream_t stat_upstream;
ngx_uint_t port;
int protocol;
u_short len;
u_char data[1];
} ngx_stream_server_traffic_status_node_t;
ngx_int_t ngx_stream_server_traffic_status_node_generate_key(ngx_pool_t *pool,
ngx_str_t *buf, ngx_str_t *dst, unsigned type);
ngx_int_t ngx_stream_server_traffic_status_node_position_key(ngx_str_t *buf,
size_t pos);
ngx_rbtree_node_t *ngx_stream_server_traffic_status_node_lookup(
ngx_rbtree_t *rbtree, ngx_str_t *key, uint32_t hash);
void ngx_stream_server_traffic_status_node_zero(
ngx_stream_server_traffic_status_node_t *stsn);
void ngx_stream_server_traffic_status_node_init(ngx_stream_session_t *s,
ngx_stream_server_traffic_status_node_t *stsn);
void ngx_stream_server_traffic_status_node_set(ngx_stream_session_t *s,
ngx_stream_server_traffic_status_node_t *stsn);
void ngx_stream_server_traffic_status_node_time_queue_zero(
ngx_stream_server_traffic_status_node_time_queue_t *q);
void ngx_stream_server_traffic_status_node_time_queue_init(
ngx_stream_server_traffic_status_node_time_queue_t *q);
void ngx_stream_server_traffic_status_node_time_queue_insert(
ngx_stream_server_traffic_status_node_time_queue_t *q,
ngx_msec_int_t x);
ngx_int_t ngx_stream_server_traffic_status_node_time_queue_push(
ngx_stream_server_traffic_status_node_time_queue_t *q,
ngx_msec_int_t x);
ngx_int_t ngx_stream_server_traffic_status_node_time_queue_pop(
ngx_stream_server_traffic_status_node_time_queue_t *q,
ngx_stream_server_traffic_status_node_time_t *x);
ngx_msec_t ngx_stream_server_traffic_status_node_time_queue_average(
ngx_stream_server_traffic_status_node_time_queue_t *q,
ngx_int_t method, ngx_msec_t period);
ngx_msec_t ngx_stream_server_traffic_status_node_time_queue_amm(
ngx_stream_server_traffic_status_node_time_queue_t *q,
ngx_msec_t period);
ngx_msec_t ngx_stream_server_traffic_status_node_time_queue_wma(
ngx_stream_server_traffic_status_node_time_queue_t *q,
ngx_msec_t period);
void ngx_stream_server_traffic_status_node_histogram_bucket_init(
ngx_stream_session_t *s,
ngx_stream_server_traffic_status_node_histogram_bucket_t *b);
void ngx_stream_server_traffic_status_node_histogram_observe(
ngx_stream_server_traffic_status_node_histogram_bucket_t *b,
ngx_msec_int_t x);
ngx_int_t ngx_stream_server_traffic_status_find_name(ngx_stream_session_t *s,
ngx_str_t *buf);
ngx_rbtree_node_t *ngx_stream_server_traffic_status_find_node(ngx_stream_session_t *s,
ngx_str_t *key, unsigned type, uint32_t key_hash);
ngx_int_t ngx_stream_server_traffic_status_node_member_cmp(ngx_str_t *member, const char *name);
ngx_atomic_uint_t ngx_stream_server_traffic_status_node_member(ngx_stream_server_traffic_status_node_t *stsn,
ngx_str_t *member);
#endif /* _NGX_STREAM_STS_NODE_H_INCLUDED_ */
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
/*
* Copyright (C) YoungJoo Kim (vozlt)
*/
#ifndef _NGX_STREAM_STS_SHM_H_INCLUDED_
#define _NGX_STREAM_STS_SHM_H_INCLUDED_
ngx_int_t ngx_stream_server_traffic_status_shm_add_server(ngx_stream_session_t *s);
ngx_int_t ngx_stream_server_traffic_status_shm_add_filter(ngx_stream_session_t *s);
ngx_int_t ngx_stream_server_traffic_status_shm_add_upstream(ngx_stream_session_t *s);
#endif /* _NGX_STREAM_STS_SHM_H_INCLUDED_ */
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
/*
* Copyright (C) YoungJoo Kim (vozlt)
*/
#include <ngx_config.h>
#include <ngx_core.h>
#include "ngx_stream_server_traffic_status_string.h"
#if !defined(nginx_version) || nginx_version < 1007009
/* from src/core/ngx_string.c in v1.7.9 */
uintptr_t
ngx_stream_server_traffic_status_escape_json(u_char *dst, u_char *src, size_t size)
{
u_char ch;
ngx_uint_t len;
if (dst == NULL) {
len = 0;
while (size) {
ch = *src++;
if (ch == '\\' || ch == '"') {
len++;
} else if (ch <= 0x1f) {
len += sizeof("\\u001F") - 2;
}
size--;
}
return (uintptr_t) len;
}
while (size) {
ch = *src++;
if (ch > 0x1f) {
if (ch == '\\' || ch == '"') {
*dst++ = '\\';
}
*dst++ = ch;
} else {
*dst++ = '\\'; *dst++ = 'u'; *dst++ = '0'; *dst++ = '0';
*dst++ = '0' + (ch >> 4);
ch &= 0xf;
*dst++ = (ch < 10) ? ('0' + ch) : ('A' + ch - 10);
}
size--;
}
return (uintptr_t) dst;
}
#endif
ngx_int_t
ngx_stream_server_traffic_status_escape_json_pool(ngx_pool_t *pool,
ngx_str_t *buf, ngx_str_t *dst)
{
u_char *p;
buf->len = dst->len * 6;
buf->data = ngx_pcalloc(pool, buf->len);
if (buf->data == NULL) {
*buf = *dst;
return NGX_ERROR;
}
p = buf->data;
#if !defined(nginx_version) || nginx_version < 1007009
p = (u_char *) ngx_stream_server_traffic_status_escape_json(p, dst->data, dst->len);
#else
p = (u_char *) ngx_escape_json(p, dst->data, dst->len);
#endif
buf->len = ngx_strlen(buf->data);
return NGX_OK;
}
ngx_int_t
ngx_stream_server_traffic_status_copy_str(ngx_pool_t *pool,
ngx_str_t *buf, ngx_str_t *dst)
{
u_char *p;
buf->len = dst->len;
buf->data = ngx_pcalloc(pool, dst->len + 1); /* 1 byte for terminating '\0' */
if (buf->data == NULL) {
return NGX_ERROR;
}
p = buf->data;
ngx_memcpy(p, dst->data, dst->len);
return NGX_OK;
}
ngx_int_t
ngx_stream_server_traffic_status_replace_chrc(ngx_str_t *buf,
u_char in, u_char to)
{
size_t len;
u_char *p;
p = buf->data;
len = buf->len;
while(len--) {
if (*p == in) {
*p = to;
}
p++;
}
return NGX_OK;
}
ngx_int_t
ngx_stream_server_traffic_status_replace_strc(ngx_str_t *buf,
ngx_str_t *dst, u_char c)
{
size_t n, len;
u_char *p, *o;
p = o = buf->data;
n = 0;
/* we need the buf's last '\0' for ngx_strstrn() */
if (*(buf->data + buf->len) != 0) {
return NGX_ERROR;
}
while ((p = ngx_strstrn(p, (char *) dst->data, dst->len - 1)) != NULL) {
n++;
len = buf->len - (p - o) - (n * dst->len) + n - 1;
*p++ = c;
ngx_memmove(p, p + dst->len - 1, len);
}
if (n > 0) {
buf->len = buf->len - (n * dst->len) + n;
}
return NGX_OK;
}
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
/*
* Copyright (C) YoungJoo Kim (vozlt)
*/
#ifndef _NGX_STREAM_STS_STRING_H_INCLUDED_
#define _NGX_STREAM_STS_STRING_H_INCLUDED_
#if !defined(nginx_version) || nginx_version < 1007009
uintptr_t ngx_stream_server_traffic_status_escape_json(u_char *dst, u_char *src, size_t size);
#endif
ngx_int_t ngx_stream_server_traffic_status_escape_json_pool(ngx_pool_t *pool,
ngx_str_t *buf, ngx_str_t *dst);
ngx_int_t ngx_stream_server_traffic_status_copy_str(ngx_pool_t *pool,
ngx_str_t *buf, ngx_str_t *dst);
ngx_int_t ngx_stream_server_traffic_status_replace_chrc(ngx_str_t *buf,
u_char in, u_char to);
ngx_int_t ngx_stream_server_traffic_status_replace_strc(ngx_str_t *buf,
ngx_str_t *dst, u_char c);
#endif /* _NGX_STREAM_STS_STRING_H_INCLUDED_ */
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
/*
* Copyright (C) YoungJoo Kim (vozlt)
*/
#include <ngx_config.h>
#include "ngx_stream_server_traffic_status_module.h"
#include "ngx_stream_server_traffic_status_variables.h"
static ngx_stream_variable_t ngx_stream_server_traffic_status_vars[] = {
{ ngx_string("sts_connect_counter"), NULL,
ngx_stream_server_traffic_status_node_variable,
offsetof(ngx_stream_server_traffic_status_node_t, stat_connect_counter),
NGX_STREAM_VAR_NOCACHEABLE, 0 },
{ ngx_string("sts_in_bytes"), NULL,
ngx_stream_server_traffic_status_node_variable,
offsetof(ngx_stream_server_traffic_status_node_t, stat_in_bytes),
NGX_STREAM_VAR_NOCACHEABLE, 0 },
{ ngx_string("sts_out_bytes"), NULL,
ngx_stream_server_traffic_status_node_variable,
offsetof(ngx_stream_server_traffic_status_node_t, stat_out_bytes),
NGX_STREAM_VAR_NOCACHEABLE, 0 },
{ ngx_string("sts_1xx_counter"), NULL,
ngx_stream_server_traffic_status_node_variable,
offsetof(ngx_stream_server_traffic_status_node_t, stat_1xx_counter),
NGX_STREAM_VAR_NOCACHEABLE, 0 },
{ ngx_string("sts_2xx_counter"), NULL,
ngx_stream_server_traffic_status_node_variable,
offsetof(ngx_stream_server_traffic_status_node_t, stat_2xx_counter),
NGX_STREAM_VAR_NOCACHEABLE, 0 },
{ ngx_string("sts_3xx_counter"), NULL,
ngx_stream_server_traffic_status_node_variable,
offsetof(ngx_stream_server_traffic_status_node_t, stat_3xx_counter),
NGX_STREAM_VAR_NOCACHEABLE, 0 },
{ ngx_string("sts_4xx_counter"), NULL,
ngx_stream_server_traffic_status_node_variable,
offsetof(ngx_stream_server_traffic_status_node_t, stat_4xx_counter),
NGX_STREAM_VAR_NOCACHEABLE, 0 },
{ ngx_string("sts_5xx_counter"), NULL,
ngx_stream_server_traffic_status_node_variable,
offsetof(ngx_stream_server_traffic_status_node_t, stat_5xx_counter),
NGX_STREAM_VAR_NOCACHEABLE, 0 },
{ ngx_string("sts_session_time"), NULL,
ngx_stream_server_traffic_status_node_variable,
offsetof(ngx_stream_server_traffic_status_node_t, stat_session_time),
NGX_STREAM_VAR_NOCACHEABLE, 0 },
{ ngx_null_string, NULL, NULL, 0, 0, 0 }
};
ngx_int_t
ngx_stream_server_traffic_status_node_variable(ngx_stream_session_t *s,
ngx_stream_variable_value_t *v, uintptr_t data)
{
u_char *p;
unsigned type;
ngx_int_t rc;
ngx_str_t key, dst;
ngx_slab_pool_t *shpool;
ngx_rbtree_node_t *node;
ngx_stream_server_traffic_status_node_t *stsn;
ngx_stream_server_traffic_status_conf_t *stscf;
stscf = ngx_stream_get_module_srv_conf(s, ngx_stream_server_traffic_status_module);
rc = ngx_stream_server_traffic_status_find_name(s, &dst);
if (rc != NGX_OK) {
return NGX_ERROR;
}
type = NGX_STREAM_SERVER_TRAFFIC_STATUS_UPSTREAM_NO;
rc = ngx_stream_server_traffic_status_node_generate_key(s->connection->pool, &key, &dst, type);
if (rc != NGX_OK) {
return NGX_ERROR;
}
if (key.len == 0) {
return NGX_ERROR;
}
shpool = (ngx_slab_pool_t *) stscf->shm_zone->shm.addr;
ngx_shmtx_lock(&shpool->mutex);
node = ngx_stream_server_traffic_status_find_node(s, &key, type, 0);
if (node == NULL) {
goto not_found;
}
p = ngx_pnalloc(s->connection->pool, NGX_ATOMIC_T_LEN);
if (p == NULL) {
goto not_found;
}
stsn = (ngx_stream_server_traffic_status_node_t *) &node->color;
v->len = ngx_sprintf(p, "%uA", *((ngx_atomic_t *) ((char *) stsn + data))) - p;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = p;
goto done;
not_found:
v->not_found = 1;
done:
stscf->node_caches[type] = node;
ngx_shmtx_unlock(&shpool->mutex);
return NGX_OK;
}
ngx_int_t
ngx_stream_server_traffic_status_add_variables(ngx_conf_t *cf)
{
ngx_stream_variable_t *var, *v;
for (v = ngx_stream_server_traffic_status_vars; v->name.len; v++) {
var = ngx_stream_add_variable(cf, &v->name, v->flags);
if (var == NULL) {
return NGX_ERROR;
}
var->get_handler = v->get_handler;
var->data = v->data;
}
return NGX_OK;
}
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
/*
* Copyright (C) YoungJoo Kim (vozlt)
*/
#ifndef _NGX_STREAM_STS_VARIABLES_H_INCLUDED_
#define _NGX_STREAM_STS_VARIABLES_H_INCLUDED_
ngx_int_t ngx_stream_server_traffic_status_node_variable(ngx_stream_session_t *s,
ngx_stream_variable_value_t *v, uintptr_t data);
ngx_int_t ngx_stream_server_traffic_status_add_variables(ngx_conf_t *cf);
#endif /* _NGX_STREAM_STS_VARIABLES_H_INCLUDED_ */
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
# vi:set ft=perl ts=4 sw=4 et fdm=marker:
use Test::Nginx::Socket;
plan tests => repeat_each() * blocks() * 6;
no_shuffle();
run_tests();
__DATA__
=== TEST 1: filter_by_set_key
--- main_config
stream {
server_traffic_status_zone;
upstream backend {
server localhost:1984;
}
server {
listen 1985;
server_traffic_status_filter_by_set_key $protocol protocol;
proxy_pass backend;
}
}
--- http_config
stream_server_traffic_status_zone;
--- config
location /status {
stream_server_traffic_status_display;
stream_server_traffic_status_display_format json;
access_log off;
}
location /stream {
proxy_pass http://localhost:1985/return;
}
--- user_files eval
[
['return/file.txt' => '{"return":"OK"}']
]
--- request eval
[
'GET /status/format/json',
'GET /stream/file.txt',
'GET /status/format/json'
]
--- response_body_like eval
[
'nginxVersion',
'OK',
'streamFilterZones.*protocol.*TCP'
]
# vi:set ft=perl ts=4 sw=4 et fdm=marker:
use Test::Nginx::Socket;
plan tests => repeat_each() * blocks() * 6;
no_shuffle();
run_tests();
__DATA__
=== TEST 1: filter_check_duplicate on
--- main_config
stream {
server_traffic_status_zone;
upstream backend {
server localhost:1984;
}
server {
listen 1985;
server_traffic_status_filter_check_duplicate on;
server_traffic_status_filter_by_set_key $protocol protocol;
server_traffic_status_filter_by_set_key $protocol protocol;
proxy_pass backend;
}
}
--- http_config
stream_server_traffic_status_zone;
--- config
location /status {
stream_server_traffic_status_display;
stream_server_traffic_status_display_format json;
access_log off;
}
location /stream {
proxy_pass http://localhost:1985/return;
}
--- user_files eval
[
['return/file.txt' => '{"return":"OK"}']
]
--- request eval
[
'GET /stream/file.txt',
'GET /status/control?cmd=status&group=filter&zone=protocol@TCP',
'GET /status/control?cmd=status&group=filter&zone=protocol@TCP'
]
--- response_body_like eval