├── LICENCE ├── NchanSubscriber.js ├── README.md ├── changelog.txt ├── cloc-exclude.txt ├── config ├── dev ├── .gitignore ├── Gemfile ├── authserver.rb ├── bench-parallel.sh ├── bench.rb ├── bench │ ├── bench │ │ ├── master.lua │ │ ├── publisher.lua │ │ ├── slave.lua │ │ ├── subscriber.lua │ │ └── util.lua │ ├── benchi.lua │ ├── config.lua │ ├── cqb.lua │ ├── deps │ │ ├── base64.lua │ │ ├── coro-channel.lua │ │ ├── coro-net.lua │ │ ├── http-codec.lua │ │ ├── redis-callback-client.lua │ │ ├── redis-client.lua │ │ ├── redis-codec.lua │ │ ├── sha1 │ │ │ ├── init.lua │ │ │ └── test-sha1.lua │ │ ├── websocket-client.lua │ │ └── websocket-codec.lua │ ├── lib │ │ └── luvit │ │ │ ├── pub.lua │ │ │ └── sub.lua │ ├── lredis │ └── pprint.lua ├── benchan.rb ├── benchmarks-data.ods ├── bl.txt ├── cert-key.pem ├── cert.pem ├── chattertest.rb ├── debug.sh ├── dev.conf ├── examine_coredump.sh ├── flock.rb ├── flood.rb ├── gen_config_commands.rb ├── gengource.sh ├── longtest.rb ├── memparse.lua ├── multiconn.c ├── multiconn.sh ├── nchan_tools-gem │ ├── .gitignore │ ├── CODE_OF_CONDUCT.md │ ├── Gemfile │ ├── LICENSE.txt │ ├── README.md │ ├── Rakefile │ ├── bin │ │ ├── console │ │ └── setup │ ├── exe │ │ ├── nchan-benchmark │ │ ├── nchan-pub │ │ ├── nchan-redis-debug │ │ └── nchan-sub │ ├── lib │ │ ├── nchan_tools.rb │ │ └── nchan_tools │ │ │ ├── benchmark.rb │ │ │ ├── pubsub.rb │ │ │ ├── rdsck.rb │ │ │ └── version.rb │ └── nchan_tools.gemspec ├── nginx-cachemanager.conf ├── nginx-pkg │ ├── .gitignore │ ├── PKGBUILD │ ├── bl.txt │ ├── install │ ├── nchan │ ├── nginx.conf │ ├── nginx.logrotate │ ├── nginx.service │ ├── ngx_slab.patch │ └── track-pool.patch ├── nginx-proxy.conf ├── nginx.conf ├── nginx.sh ├── package │ ├── .gitignore │ ├── fedora │ │ ├── build-nginx-with-nchan.sh │ │ ├── nchan.spec │ │ ├── nchan_no_HTTP_HEADERS.patch │ │ └── nginx-auto-cc-gcc.patch │ ├── nginx-nchan-static │ │ ├── .gitignore │ │ ├── PKGBUILD │ │ ├── nginx.conf │ │ ├── nginx.logrotate │ │ └── nginx.service │ ├── pkgs │ │ ├── .gitignore │ │ └── .gitkeep │ └── repackage.sh ├── prepare.sh ├── pressure.rb ├── pub-multi.rb ├── pub.rb ├── python_check.sh ├── rebuild.sh ├── redis-cluster │ ├── .gitignore │ ├── README.md │ ├── __init__.py │ ├── cluster.py │ ├── cluster_info_output.py │ ├── cluster_location.py │ ├── cluster_node.py │ ├── cluster_node_failure.py │ ├── cluster_shutdown.sh │ ├── cluster_shutdown_by_rediscli.py │ ├── cluster_start.py │ ├── cluster_state_information.py │ ├── cluster_timeout.sh │ ├── cluster_timeout_failover.sh │ ├── config.json │ ├── constants.py │ ├── delete_cluster.py │ ├── node_details.py │ ├── primary_node_failure.sh │ ├── slave_node_failure.sh │ ├── test │ │ ├── README.md │ │ ├── __init__.py │ │ ├── test_cluster_info.py │ │ └── test_cluster_start.py │ └── utils.py ├── redis-tls │ ├── ca.crt │ ├── ca.key │ ├── ca.txt │ ├── client.crt │ ├── client.key │ ├── openssl.cnf │ ├── redis.crt │ ├── redis.dh │ ├── redis.key │ ├── server.crt │ └── server.key ├── redis-trib.rb ├── redis.conf ├── redocument.rb ├── rsck.sh ├── sub.rb ├── test-parallel.sh ├── test.rb ├── vg.supp └── wstest.py ├── nchan_logo.png └── src ├── .gitignore ├── nchan_commands.rb ├── nchan_config_commands.c ├── nchan_defs.c ├── nchan_defs.h ├── nchan_module.c ├── nchan_module.h ├── nchan_setup.c ├── nchan_types.h ├── nchan_variables.c ├── nchan_variables.h ├── nchan_version.h ├── nchan_websocket_publisher.c ├── nchan_websocket_publisher.h ├── store ├── memory │ ├── groups.c │ ├── groups.h │ ├── ipc-handlers.c │ ├── ipc-handlers.h │ ├── ipc.c │ ├── ipc.h │ ├── memstore.c │ ├── recycloc.c │ ├── store-private.h │ └── store.h ├── ngx_rwlock.c ├── ngx_rwlock.h ├── redis │ ├── cmp.c │ ├── cmp.h │ ├── hiredis │ │ ├── .gitignore │ │ ├── .travis.yml │ │ ├── CHANGELOG.md │ │ ├── COPYING │ │ ├── Makefile │ │ ├── README.md │ │ ├── alloc.c │ │ ├── alloc.h │ │ ├── async.c │ │ ├── async.h │ │ ├── async_private.h │ │ ├── dict.c │ │ ├── dict.h │ │ ├── fmacros.h │ │ ├── hiredis.c │ │ ├── hiredis.h │ │ ├── hiredis_ssl.h │ │ ├── net.c │ │ ├── net.h │ │ ├── read.c │ │ ├── read.h │ │ ├── sds.c │ │ ├── sds.h │ │ ├── sdsalloc.h │ │ ├── sockcompat.c │ │ ├── sockcompat.h │ │ ├── ssl.c │ │ ├── test.c │ │ └── win32.h │ ├── rdsstore.c │ ├── redis-lua-scripts │ │ ├── .gitignore │ │ ├── Gemfile │ │ ├── add_fakesub.lua │ │ ├── channel_keepalive.lua │ │ ├── delete.lua │ │ ├── find_channel.lua │ │ ├── get_message.lua │ │ ├── get_message_from_key.lua │ │ ├── get_subscriber_info_id.lua │ │ ├── nostore_publish_multiexec_channel_info.lua │ │ ├── publish.lua │ │ ├── request_subscriber_info.lua │ │ ├── rsck.lua │ │ ├── subscriber_register.lua │ │ ├── subscriber_unregister.lua │ │ └── testscripts.rb │ ├── redis_lua_commands.c │ ├── redis_lua_commands.h │ ├── redis_nginx_adapter.c │ ├── redis_nginx_adapter.h │ ├── redis_nodeset.c │ ├── redis_nodeset.h │ ├── redis_nodeset_parser.c │ ├── redis_nodeset_parser.h │ ├── redis_nodeset_stats.c │ ├── store-private.h │ └── store.h ├── spool.c ├── spool.h ├── store_common.c └── store_common.h ├── subscribers ├── benchmark.c ├── benchmark.h ├── common.c ├── common.h ├── eventsource.c ├── eventsource.h ├── getmsg_proxy.c ├── getmsg_proxy.h ├── http-chunked.c ├── http-chunked.h ├── http-multipart-mixed.c ├── http-multipart-mixed.h ├── http-raw-stream.c ├── http-raw-stream.h ├── internal.c ├── internal.h ├── intervalpoll.c ├── intervalpoll.h ├── longpoll-private.h ├── longpoll.c ├── longpoll.h ├── memstore_ipc.c ├── memstore_ipc.h ├── memstore_multi.c ├── memstore_multi.h ├── memstore_redis.c ├── memstore_redis.h ├── websocket.c └── websocket.h ├── uthash.h └── util ├── hdr_histogram.c ├── hdr_histogram.h ├── nchan_accumulator.c ├── nchan_accumulator.h ├── nchan_benchmark.c ├── nchan_benchmark.h ├── nchan_bufchainpool.c ├── nchan_bufchainpool.h ├── nchan_channel_id.c ├── nchan_channel_id.h ├── nchan_debug.c ├── nchan_debug.h ├── nchan_fake_request.c ├── nchan_fake_request.h ├── nchan_list.c ├── nchan_list.h ├── nchan_msg.c ├── nchan_msg.h ├── nchan_output.c ├── nchan_output.h ├── nchan_output_info.c ├── nchan_output_info.h ├── nchan_rbtree.c ├── nchan_rbtree.h ├── nchan_reaper.c ├── nchan_reaper.h ├── nchan_reuse_queue.c ├── nchan_reuse_queue.h ├── nchan_slist.c ├── nchan_slist.h ├── nchan_stats.c ├── nchan_stats.h ├── nchan_subrequest.c ├── nchan_subrequest.h ├── nchan_thingcache.c ├── nchan_thingcache.h ├── nchan_timequeue.c ├── nchan_timequeue.h ├── nchan_util.c ├── nchan_util.h ├── ngx_nchan_hacked_slab.c ├── ngx_nchan_hacked_slab.h ├── shmem.c └── shmem.h /LICENCE: -------------------------------------------------------------------------------- 1 | This work is distributed under the MIT Licence. 2 | 3 | Written by Leo Ponomarev (slact) 2009-2015. 4 | 5 | Permission is hereby granted, free of charge, to any person 6 | obtaining a copy of this software and associated documentation 7 | files (the "Software"), to deal in the Software without 8 | restriction, including without limitation the rights to use, 9 | copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the 11 | Software is furnished to do so, subject to the following 12 | conditions: 13 | 14 | The above authorship notice and this permission notice shall be 15 | included in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 19 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 21 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 22 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 24 | OTHER DEALINGS IN THE SOFTWARE. 25 | -------------------------------------------------------------------------------- /cloc-exclude.txt: -------------------------------------------------------------------------------- 1 | src/uthash.h 2 | src/hiredis 3 | src/util/ngx_nchan_hacked_slab.c 4 | src/util/hdr_histogram.c 5 | src/util/hdr_histogram.h 6 | src/store/redis/cmp.c 7 | src/store/redis/cmp.h 8 | src/store/redis/redis_lua_commands.h 9 | src/nginx-source 10 | src/nchan_config_commands.c 11 | dev/bench 12 | dev/nginx-pkg 13 | dev/clang-analyzer 14 | dev/package 15 | dev/src 16 | dev/redis-trib.rb 17 | -------------------------------------------------------------------------------- /dev/.gitignore: -------------------------------------------------------------------------------- 1 | coredump/* 2 | clang-analyzer/* 3 | .nginx.thisrun.conf 4 | Gemfile.lock 5 | errors*.log 6 | vgcore.* 7 | captions.txt 8 | nginx 9 | .bundle 10 | .profdata 11 | nchan_tools-gem/*.gem 12 | bench/ -------------------------------------------------------------------------------- /dev/Gemfile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | source 'https://rubygems.org' 3 | gem 'typhoeus' 4 | gem 'json' 5 | gem 'oga' 6 | 7 | gem 'irb' 8 | gem 'pry' 9 | gem 'rdoc' 10 | gem 'pry-byebug' 11 | gem 'pry-coolline' 12 | gem 'pry-doc' 13 | gem 'pry-git' 14 | gem 'pry-inline' 15 | gem 'pry-rescue' 16 | #gem 'pry-stack_explorer' 17 | #gem 'pry-state' 18 | gem 'pry-syntax-hacks' 19 | gem 'pry-theme' 20 | 21 | gem 'celluloid', "~>0.17.4" 22 | if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.2.2') 23 | gem 'nio4r', '~>1.2.1' 24 | end 25 | gem 'celluloid-io' 26 | gem 'nchan_tools', :path => "./nchan_tools-gem" 27 | #gem "memory_profiler", :git => "https://github.com/slact/memory_profiler.git" 28 | 29 | gem 'rack', "~> 2.2.4" 30 | gem 'reel', :git => "https://github.com/celluloid/reel.git" 31 | gem 'reel-rack', :git => "https://github.com/slact/reel-rack.git" 32 | 33 | gem 'minitest' 34 | gem 'minitest-reporters' 35 | 36 | 37 | gem "async" 38 | gem "async-io" 39 | gem "async-http" 40 | gem "async-websocket" 41 | gem "falcon" 42 | gem "async-await" 43 | gem "thread-local" 44 | gem "colorize" 45 | 46 | gem 'fpm', :git => "https://github.com/slact/fpm.git" 47 | 48 | gem 'hsss', "~> 0.1.23" 49 | -------------------------------------------------------------------------------- /dev/bench-parallel.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | par=$1 3 | if [[ -z "$par" ]]; then 4 | par=5 5 | echo "No parallel count given. Assuming $par." 6 | fi 7 | if ! [[ $par =~ ^[0-9]+$ ]]; then 8 | echo "Parallel count isn't a number." > /dev/stderr 9 | exit 1 10 | fi 11 | 12 | for ((i = 0; i < $par; i++)); do 13 | 14 | echo ./bench.rb ${@:2} 15 | ./bench.rb ${@:2} & 16 | done 17 | 18 | jobs=$(jobs -p) 19 | #echo "jobs are $jobs" 20 | killjobs() { 21 | for job_pid in $jobs; do 22 | kill $job_pid 23 | done 24 | } 25 | 26 | trap killjobs SIGINT 27 | wait $jobs 28 | -------------------------------------------------------------------------------- /dev/bench/config.lua: -------------------------------------------------------------------------------- 1 | local uri="%s://localhost:8082/%s/%s" 2 | local num_chans = 1 3 | local subs_per_channel=30000 4 | 5 | local chans = {} 6 | 7 | for i=1,num_chans do 8 | local channel = tostring(math.random(100000)) 9 | table.insert(chans, { 10 | pub = uri:format("http", "pub", channel), 11 | sub = uri:format("ws", "sub/broadcast", channel), 12 | n = subs_per_channel 13 | }) 14 | end 15 | 16 | return chans 17 | -------------------------------------------------------------------------------- /dev/bench/cqb.lua: -------------------------------------------------------------------------------- 1 | #!/usr/bin/luajit 2 | local cqueues = require "cqueues" 3 | local thread = require "cqueues.thread" 4 | 5 | local argparse = require "argparse" 6 | local Json = require "cjson" 7 | local pp = require('pprint') 8 | local mm = require "mm" 9 | local ut = require("bench.util") 10 | 11 | local parser = argparse("script", "thing thinger.") 12 | parser:option("--redis", "Redis orchestration server url.", "127.0.0.1:6379") 13 | parser:option("--config", "Pub/sub config lua file.", "config.lua") 14 | parser:option("--subs", "max subscribers for slave (default: 20000).", 50000) 15 | parser:option("--threads", "number of slave threads (default: 4).", 4) 16 | parser:flag("--master", "Be master") 17 | parser:flag("--slave", "Be slave") 18 | 19 | 20 | local opt = parser:parse(args) 21 | opt.slave_threads = tonumber(opt.slave_threads) 22 | opt.subscribers = tonumber(opt.subscribers) 23 | 24 | local cq=cqueues.new() 25 | 26 | ut.accessorize(cq) 27 | 28 | if not opt.slave and not opt.master then 29 | print("Role setting missing, assuming --slave") 30 | opt.slave = true 31 | end 32 | 33 | local slave_threads = setmetatable({}, {__mode='k'}) 34 | 35 | if opt.slave then 36 | local opt_json = Json.encode(opt) 37 | for i=1,tonumber(opt.threads) do 38 | local thread, con = cq:newThread(function(con, threadnum, opt_json) 39 | local cqueues = require "cqueues" 40 | local Json = require "cjson" 41 | local ut = require("bench.util") 42 | --local pp = require "pprint" 43 | local cq = cqueues.new() 44 | ut.accessorize(cq) 45 | local opt = Json.decode(opt_json) 46 | local Slave = require "bench.slave" 47 | local slave = Slave(cq, opt) 48 | print("started slave thread " .. threadnum) 49 | cq:wrap(function() 50 | for ln in con:lines() do 51 | if ln == "exit" then 52 | slave:on("stop", function() 53 | print("quit from slave thread " .. threadnum) --quit stuff 54 | con:write("exited\n") 55 | end) 56 | slave:stop() 57 | end 58 | end 59 | end) 60 | assert(cq:loop()) 61 | end, opt_json) 62 | slave_threads[thread] = con 63 | end 64 | end 65 | 66 | if opt.master then 67 | local master = require "bench.master" 68 | local conf_chunk, err = loadfile(opt.config) 69 | if conf_chunk then 70 | opt.config = conf_chunk() 71 | pp(opt.config) 72 | else 73 | print("Config not found at " .. opt.config ..".") 74 | os.exit(1) 75 | end 76 | master(cq, opt) 77 | end 78 | 79 | 80 | local force_quit 81 | cq:handleSignal({"SIGINT", "SIGTERM"}, function() 82 | local exiting = 0 83 | local exited = 0 84 | 85 | if force_quit then 86 | print("\nNo more waiting around. Quit!") 87 | os.exit(1) 88 | end 89 | 90 | print("\nShutting down slaves... ^C again to force-quit.") 91 | 92 | for thread, con in pairs(slave_threads) do 93 | con:write("exit\n") 94 | exiting = exiting + 1 95 | cq:wrap(function() 96 | for ln in con:lines() do 97 | if ln == "exited" then 98 | exited = exited + 1 99 | if exited == exiting then 100 | print("we're done here") 101 | os.exit(1) 102 | end 103 | end 104 | end 105 | end) 106 | end 107 | 108 | if exiting == 0 then 109 | print("no slave threads. quit now") 110 | os.exit(1) 111 | end 112 | 113 | force_quit = 1 114 | end) 115 | 116 | 117 | assert(cq:loop()) 118 | for err in cq:errors() do 119 | print(err) 120 | end 121 | -------------------------------------------------------------------------------- /dev/bench/deps/redis-client.lua: -------------------------------------------------------------------------------- 1 | --[[lit-meta 2 | name = "creationix/redis-client" 3 | version = "1.1.0" 4 | description = "A coroutine based client for Redis" 5 | tags = {"coro", "redis"} 6 | license = "MIT" 7 | author = { name = "Tim Caswell" } 8 | homepage = "https://github.com/creationix/redis-luvit" 9 | dependencies = { 10 | "creationix/redis-codec@1.0.2", 11 | "creationix/coro-net@2.2.0", 12 | } 13 | ]] 14 | 15 | local codec = require('redis-codec') 16 | local connect = require('coro-net').connect 17 | 18 | return function (config) 19 | if not config then config = {} end 20 | 21 | local read, write = assert(connect{ 22 | host = config.host or "localhost", 23 | port = config.port or 6379, 24 | encode = codec.encode, 25 | decode = codec.decode, 26 | }) 27 | 28 | return function (command, ...) 29 | if not command then return write() end 30 | write {command, ...} 31 | local res = read() 32 | if type(res) == "table" and res.error then 33 | error(res.error) 34 | end 35 | return res 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /dev/bench/deps/redis-codec.lua: -------------------------------------------------------------------------------- 1 | --[[lit-meta 2 | name = "slact/redis-codec" 3 | version = "1.0.3" 4 | description = "Pure Lua codec for RESP (REdis Serialization Protocol) + nils-in-lists-fix" 5 | tags = {"codec", "redis"} 6 | license = "MIT" 7 | author = { name = "Tim Caswell" } 8 | homepage = "https://github.com/slact/redis-luvit" 9 | ]] 10 | 11 | local function encode(list) 12 | local len = #list 13 | local parts = {"*" .. len .. '\r\n'} 14 | for i = 1, len do 15 | local str = tostring(list[i]) 16 | parts[i + 1] = "$" .. #str .. "\r\n" .. str .. "\r\n" 17 | end 18 | return table.concat(parts) 19 | end 20 | 21 | local byte = string.byte 22 | local find = string.find 23 | local sub = string.sub 24 | 25 | local function innerDecode(chunk, index) 26 | if #chunk < 1 then return end 27 | local first = byte(chunk, index) 28 | if first == 43 then -- '+' Simple string 29 | local start = find(chunk, "\r\n", index, true) 30 | if not start then return end 31 | return sub(chunk, index + 1, start - 1), start + 2 32 | elseif first == 45 then -- '-' Error 33 | local start = find(chunk, "\r\n", index, true) 34 | if not start then return end 35 | return {error=sub(chunk, index + 1, start - 1)}, start + 2 36 | elseif first == 58 then -- ':' Integer 37 | local start = find(chunk, "\r\n", index, true) 38 | if not start then return end 39 | return tonumber(sub(chunk, index + 1, start - 1)), start + 2 40 | elseif first == 36 then -- '$' Bulk String 41 | local start = find(chunk, "\r\n", index, true) 42 | if not start then return end 43 | local len = tonumber(sub(chunk, index + 1, start - 1)) 44 | if len == -1 then 45 | return nil, start + 2 46 | end 47 | if #chunk < start + 3 + len then return end 48 | return sub(chunk, start + 2, start + 1 + len), start + 4 + len 49 | elseif first == 42 then -- '*' List 50 | local start = find(chunk, "\r\n", index, true) 51 | if not start then return end 52 | local len = tonumber(sub(chunk, index + 1, start - 1)) 53 | if len == -1 then 54 | return nil, start + 2 55 | end 56 | local list = {} 57 | index = start + 2 58 | for i = 1, len do 59 | local value 60 | value, index = innerDecode(chunk, index) 61 | --if not value then return end 62 | list[i] = value or false 63 | end 64 | return list, index 65 | else 66 | local list = {} 67 | local stop = find(chunk, "\r\n", index, true) 68 | if not stop then return end 69 | while index < stop do 70 | local e = find(chunk, " ", index, true) 71 | if not e then 72 | list[#list + 1] = sub(chunk, index, stop - 1) 73 | break 74 | end 75 | list[#list + 1] = sub(chunk, index, e - 1) 76 | index = e + 1 77 | end 78 | return list, stop + 2 79 | end 80 | end 81 | 82 | local function decode(chunk) 83 | local value, index = innerDecode(chunk, 1) 84 | if not index then return end 85 | return value, sub(chunk, index) 86 | end 87 | 88 | return { 89 | encode = encode, 90 | decode = decode, 91 | } 92 | -------------------------------------------------------------------------------- /dev/bench/deps/sha1/test-sha1.lua: -------------------------------------------------------------------------------- 1 | 2 | local sha1 = require('./init') 3 | assert(sha1("") == "da39a3ee5e6b4b0d3255bfef95601890afd80709") 4 | assert(sha1("abc") == "a9993e364706816aba3e25717850c26c9cd0d89d") 5 | assert(sha1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") 6 | == "84983e441c3bd26ebaae4aa1f95129e5e54670f1") 7 | assert(sha1("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu") 8 | == "a49b2446a02c645bf419f995b67091253a04a259") 9 | assert(sha1(string.rep("a", 1000000)) 10 | == "34aa973cd4c4daa4f61eeb2bdbad27316534016f") 11 | local sum = sha1() 12 | sum.update("a") 13 | sum.update("bc") 14 | assert(sum.digest() == "a9993e364706816aba3e25717850c26c9cd0d89d") 15 | sum = sha1() 16 | local aa = string.rep("a", 1000) 17 | for i = 1, 1000 do 18 | sum.update(aa) 19 | end 20 | assert(sum.digest() == "34aa973cd4c4daa4f61eeb2bdbad27316534016f") 21 | 22 | print("All tests pass") 23 | -------------------------------------------------------------------------------- /dev/bench/deps/websocket-client.lua: -------------------------------------------------------------------------------- 1 | --[[lit-meta 2 | name = "creationix/websocket-client" 3 | version = "3.0.1" 4 | description = "A coroutine based client for Websockets" 5 | tags = {"coro", "websocket"} 6 | license = "MIT" 7 | author = { name = "Tim Caswell" } 8 | homepage = "https://github.com/creationix/redis-luvit" 9 | dependencies = { 10 | "luvit/http-codec@2.0.0", 11 | "creationix/websocket-codec@2.0.0", 12 | "creationix/coro-net@2.0.0", 13 | } 14 | ]] 15 | 16 | local connect = require('coro-net').connect 17 | local websocketCodec = require('websocket-codec') 18 | local httpCodec = require('http-codec') 19 | 20 | return function (url, subprotocol, options) 21 | options = options or {} 22 | local headers = options.headers or {} 23 | 24 | local protocol, host, port, path = string.match(url, "^(wss?)://([^:/]+):?(%d*)(/?[^#]*)") 25 | local tls = options.tls 26 | if protocol == "ws" then 27 | port = tonumber(port) or 80 28 | elseif protocol == "wss" then 29 | port = tonumber(port) or 443 30 | if not tls then tls = {} end 31 | else 32 | error("Sorry, only ws:// or wss:// protocols supported") 33 | end 34 | if #path == 0 then path = "/" end 35 | 36 | local read, write, socket, updateDecoder, updateEncoder = assert(connect{ 37 | tls = tls, 38 | host = host, 39 | port = port, 40 | encode = httpCodec.encoder(), 41 | decode = httpCodec.decoder(), 42 | }) 43 | 44 | -- Perform the websocket handshake 45 | assert(websocketCodec.handshake({ 46 | host = host, 47 | path = path, 48 | protocol = subprotocol 49 | }, function (req) 50 | for _ = 1, #headers do 51 | req[#req + 1] = headers[1] 52 | end 53 | write(req) 54 | local res = read() 55 | if not res then error("Missing server response") end 56 | if res.code == 400 then 57 | -- p { req = req, res = res } 58 | local reason = read() or res.reason 59 | error("Invalid request: " .. reason) 60 | end 61 | return res 62 | end)) 63 | 64 | -- Upgrade the protocol to websocket 65 | updateDecoder(websocketCodec.decode) 66 | updateEncoder(websocketCodec.encode) 67 | 68 | return read, write, socket 69 | end 70 | -------------------------------------------------------------------------------- /dev/bench/lib/luvit/pub.lua: -------------------------------------------------------------------------------- 1 | local Url = require "url" 2 | local tls = require "tls" 3 | local net = require 'net' 4 | --local Emitter = require("core").Emitter 5 | --local utils = require('utils') 6 | local httpCodec = require 'http-codec' 7 | 8 | local Publisher = function(raw_url) 9 | local httpEncode = httpCodec.encoder() 10 | local httpDecode = httpCodec.decoder() 11 | 12 | local sock 13 | local url = Url.parse(raw_url) 14 | local opt = {port = url.port, host = url.hostname} 15 | local use_tls 16 | if url.protocol == "https" then 17 | use_tls = true 18 | url.port = url.port or 443 19 | else 20 | use_tls = false 21 | url.port = url.port or 80 22 | end 23 | 24 | local self 25 | local recv = function(data) 26 | --p(data) 27 | local head, body, done 28 | head, data = httpDecode(data) 29 | body, data = httpDecode(data) 30 | done, data = httpDecode(data) 31 | if head.code >= 300 or head.code <200 then 32 | error("Publisher error code: " .. head.code) 33 | end 34 | --p("message sent.") 35 | end 36 | self = { 37 | connect = function(self) 38 | sock = (use_tls and tls or net).connect(opt) 39 | sock:on("data", recv) 40 | end, 41 | post = function(self, msg, args) 42 | msg = tostring(msg) 43 | sock:write(httpEncode({ 44 | method = "POST", 45 | path = url.path, 46 | {"Host", url.host}, 47 | {"Content-Length", #msg} 48 | })) 49 | sock:write(httpEncode(msg)) 50 | end, 51 | disconnect = function(self) 52 | 53 | end 54 | } 55 | 56 | return self 57 | end 58 | 59 | return Publisher 60 | -------------------------------------------------------------------------------- /dev/bench/lredis: -------------------------------------------------------------------------------- 1 | lredis.git/lredis -------------------------------------------------------------------------------- /dev/benchan.rb: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | bundle exec nchan-benchmark "$@" 3 | -------------------------------------------------------------------------------- /dev/benchmarks-data.ods: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/slact/nchan/9c6909d0a4c4611479b7182ac29b2065a5845614/dev/benchmarks-data.ods -------------------------------------------------------------------------------- /dev/bl.txt: -------------------------------------------------------------------------------- 1 | fun:*ngx_pstrdup* 2 | src:ngx_string.c 3 | src:ngx_http_gzip_filter_module.c 4 | fun:ngx_writev 5 | -------------------------------------------------------------------------------- /dev/cert-key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCWRtFsEEwp6eUH 3 | vnaaxxuYooIiCRP0Jw6217aNaz3xSFZhqQph0LpK+942Yv9+oFxneSMFl4BSncBt 4 | AXv68UE8y1bFxfcwqHDvjrbxqPqC2louD+f4GVNWDEiqhX2UTc8LoB0V96KuKFv9 5 | 31y33vNjS8KE1FIHifEZFlU5C/+CpAHCGT/LJH336bPFWCEvsMUGww4bXaIym6UM 6 | Jrkt6leE03eJ0ZDA1uHp3TWq6L7z9iJsjKppluXDMMlAas0Rj3YkhF2XhVD/achG 7 | CanzIWl3i0B4c4SrcCCzHOa0UtWtDQwoks/Q41rMTVAHDBGt8tjP0utVR+Vnx7uu 8 | ta37lQFXAgMBAAECggEBAItMzigL224m4CUTisHiu1P7oAGIxLRX2C3pO9FPjbWx 9 | xlD07yjI4UdMvilQD2IDqGRKSAqQ62Sp0ou5CoINTNnb622dGoxCN534fuD4MG9H 10 | lLyKBg9W+ocTD/DxmPz2O2ydWRjZ2jTyOIPWnw3aX2a1/XQ/lGJkndcReqJM2ubv 11 | UQgT5vIJCF4OMPPYWntgFi2GbdGAl8kKCiU6wQ0q9g3Y/EmuyEpY8uVbRV7nN65i 12 | 3YRU4EHACOZiFNfh12hFeAWMWbaEVsyx3bmdmkfI1kiu/Rddr1HzHoOR+HNN0jrr 13 | E6d3cyzGE7XX0lTpTjzMcHX2PmzvH7Y3Lh1Jz+WqlJECgYEAxFfutjvuJoa4yDhG 14 | 9S/7/AoUUdY2LhxBin8QpI+XkSHGQaP22X6vwvncjnK85nq/5Wi1tKaFQ72+df9Q 15 | hP3s5sgVrb41FAbm6a9KuR2FGL63LH6pGrj9X6yMT+ZHIW+V/kpaA4/bVBvLh/dp 16 | GEYQnZGJvrgRBis46AFVi4lvm/0CgYEAw++x+IFzEEE7x5A7AcrrWYl6V2eBPWIA 17 | lcnFuhosKUTgAry4pmofG+kblgI89droINF/aFrJyBa2HV/WLZH5p08hplr1/FuD 18 | DZoyHA5CQOvp210NXOTGti0JWFtH3W7Wz32Bj/e8gDz6ZuzsXDtdP9fiA52NqSG2 19 | BiaFCSOLcOMCgYBFyvwPyz3cdAc7JMYUYfownWSbsomP2ntxv7kqxeAatubCboZQ 20 | ybewlyDPgfmj8/5CjfYJQSgd7FTHnPoCTEDpyDXsjLBRbiKm7qihJN0q7qAuMNfr 21 | p9ZpK+y0eibOu9uViNh2a6yLOVYf/tJczosZd6J/KO7kQnj3/4FpGHGUAQKBgCVA 22 | cSm6EtJIVMFAXreciNphFO2BNEUjWNEhp4IWb8b43U4n60NYccmwrBn9GvHzSKbU 23 | rdB9UlfEWaOEEQhg9IImvVMPgC0WiPgRFO3YmCgXskKOknfS1yTTsy8lS6iB5j1U 24 | s0lX5HLNJR5kdRuj/bqhpMrjLYe2bREGSczPATfZAoGBALYbnEP85H0N1iKIh/jV 25 | gkKzS38el73tD8kVCCfy/B//fDzcL+M8Km0nDQI/NGISkLgsle4iGOX2P/GHDeJ9 26 | tNtxEAYNHZxs0ueisqa1kvUjOZi2JMq8+HoymLvADGrZPLZoIl5S874ixmX+yPfu 27 | oICCZTZruu/op86/owdlmS43 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /dev/cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDpTCCAo2gAwIBAgIJAMIK26NcV4+mMA0GCSqGSIb3DQEBCwUAMGkxCzAJBgNV 3 | BAYTAlhYMQ0wCwYDVQQIDARub25lMSQwIgYDVQQKDBtuY2hhbiB0ZXN0aW5nIHVu 4 | Y29ycG9yYXRpb24xETAPBgNVBAsMCHN1aXRlIC05MRIwEAYDVQQDDAlsb2NhbGhv 5 | c3QwHhcNMTUxMjI5MTkwNDE5WhcNMTYxMjI4MTkwNDE5WjBpMQswCQYDVQQGEwJY 6 | WDENMAsGA1UECAwEbm9uZTEkMCIGA1UECgwbbmNoYW4gdGVzdGluZyB1bmNvcnBv 7 | cmF0aW9uMREwDwYDVQQLDAhzdWl0ZSAtOTESMBAGA1UEAwwJbG9jYWxob3N0MIIB 8 | IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlkbRbBBMKenlB752mscbmKKC 9 | IgkT9CcOtte2jWs98UhWYakKYdC6SvveNmL/fqBcZ3kjBZeAUp3AbQF7+vFBPMtW 10 | xcX3MKhw74628aj6gtpaLg/n+BlTVgxIqoV9lE3PC6AdFfeirihb/d9ct97zY0vC 11 | hNRSB4nxGRZVOQv/gqQBwhk/yyR99+mzxVghL7DFBsMOG12iMpulDCa5LepXhNN3 12 | idGQwNbh6d01qui+8/YibIyqaZblwzDJQGrNEY92JIRdl4VQ/2nIRgmp8yFpd4tA 13 | eHOEq3AgsxzmtFLVrQ0MKJLP0ONazE1QBwwRrfLYz9LrVUflZ8e7rrWt+5UBVwID 14 | AQABo1AwTjAdBgNVHQ4EFgQUV64KJ1He/hQ91ylmFediO7zqaGowHwYDVR0jBBgw 15 | FoAUV64KJ1He/hQ91ylmFediO7zqaGowDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0B 16 | AQsFAAOCAQEAOh6IUcVtSKix2Da9izAyJGt76rmk8wny61d6hWYbv/kBDLoWN93r 17 | yBrPBKHeGp8oivcofShKBMACbGttu1ZOLrvXMvtJvg8oixyODQxBKKDWKERhmZwW 18 | 5/RYma5Uh+DHVeKyEfy8zz0Io51jksWJUZ0NIzU+PtDHSsR7sCG+HS0BUEYgzyvr 19 | fWvRwdKN+lXLvoaAuvEGmT5gnWtJYqrvLYq7548xl0CZbjRUlQpxt9/XdpIVRQwh 20 | 23BucARPEgps7uv6SXXzsFLcrmjUkGJZ1itORYvT4QpaD40DAq+2hiI4u5594Stp 21 | Dl6MJ43WlnWQCd5FakZpvcW5ZuBbDYkxkQ== 22 | -----END CERTIFICATE----- 23 | -------------------------------------------------------------------------------- /dev/chattertest.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | require 'test/unit' 3 | require 'securerandom' 4 | require "./pubsub.rb" 5 | 6 | #invocation: ./chattertest.rb [channel] [pub/sub] [concurrency/message] 7 | role, channel, sub_concurrency, pub_msg = nil, nil, nil, nil 8 | #parse args 9 | raise "Not enough args. ./chattertest.rb [channel] [pub/sub] [concurrency/message]" if ARGV.length < 3 10 | channel=ARGV[0] 11 | role=ARGV[1] 12 | sub_concurrency=ARGV[2].to_i if role=="sub" 13 | pub_msg=ARGV[2] if role=="pub" 14 | 15 | 16 | def url(part) 17 | "http://127.0.0.1:8082/#{part}" 18 | end 19 | def pubsub(concurrent_clients=1, opt={}) 20 | urlpart=opt[:urlpart] || 'broadcast' 21 | timeout = opt[:timeout] || 120 22 | sub_url=opt[:sub] || "sub/#{urlpart}/" 23 | pub_url=opt[:pub] || "pub/" 24 | chan_id = opt[:channel] || SecureRandom.hex 25 | sub = Subscriber.new url("#{sub_url}#{chan_id}"), concurrent_clients, timeout: timeout, quit_message: 'FIN' 26 | pub = Publisher.new url("#{pub_url}#{chan_id}") 27 | return pub, sub 28 | end 29 | 30 | 31 | pub, sub = pubsub(sub_concurrency, channel: channel) 32 | if role=="sub" 33 | puts "Subscribing #{sub_concurrency} client(s) to channel #{channel}." 34 | sub.on_message do |msg| 35 | puts "got message \"#{msg.to_s}\"" 36 | end 37 | sub.run false 38 | elsif role=="pub" 39 | puts "Publishing #{pub_msg} to channel #{channel}" 40 | pub.post pub_msg 41 | else 42 | raise "unknown role #{role}" 43 | end -------------------------------------------------------------------------------- /dev/debug.sh: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | TESTDIR=`pwd` 3 | SRCDIR=$(readlink -m $TESTDIR/../src) 4 | if [[ "$1" = <-> ]]; then 5 | sudo kdbg -p $1 $SRCDIR/nginx 6 | else 7 | kdbg $SRCDIR/nginx $1 8 | fi 9 | 10 | -------------------------------------------------------------------------------- /dev/dev.conf: -------------------------------------------------------------------------------- 1 | #!/bin/sh #good enough highlighting 2 | worker_processes 16; 3 | worker_rlimit_nofile 150000; 4 | 5 | #error_log /dev/stderr debug; 6 | error_log /dev/stderr notice; 7 | #error_log err.log notice; 8 | 9 | pid /tmp/nchan-test-nginx.pid; 10 | daemon off; 11 | 12 | events { 13 | worker_connections 50000; 14 | } 15 | 16 | http { 17 | #include mime.types; 18 | default_type application/octet-stream; 19 | 20 | nchan_max_reserved_memory 1024M; 21 | 22 | access_log off; 23 | sendfile on; 24 | tcp_nopush on; 25 | tcp_nodelay on; 26 | keepalive_timeout 30s; 27 | types_hash_max_size 2048; 28 | client_max_body_size 10M; 29 | server_tokens off; 30 | gzip on; 31 | 32 | server { 33 | listen 127.0.0.1:8083; 34 | location ~ /action/pub/(\w+)$ { 35 | nchan_publisher; 36 | nchan_channel_id $1; 37 | nchan_message_timeout 5s; 38 | nchan_message_buffer_length 10; 39 | } 40 | } 41 | 42 | server { 43 | listen 127.0.0.1:8082; 44 | location /action/subauth { 45 | proxy_pass http://127.0.0.1:8053/subauth; 46 | proxy_pass_request_body off; 47 | proxy_set_header Content-Length ""; 48 | proxy_set_header X-Subscriber-Type $nchan_subscriber_type; 49 | proxy_set_header X-Prev-Message-Id $nchan_prev_message_id; 50 | proxy_set_header X-Channel-Id $nchan_channel_id; 51 | proxy_set_header X-Original-URI $request_uri; 52 | proxy_set_header X-Forwarded-For $remote_addr; 53 | } 54 | location ~ /action/sub/(\w+)$ { 55 | nchan_subscriber; 56 | nchan_channel_id $1; 57 | nchan_authorize_request /action/subauth; 58 | client_body_timeout 65; 59 | keepalive_timeout 65; 60 | send_timeout 60; 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /dev/examine_coredump.sh: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | target=$1 3 | core_dir="./coredump" 4 | if [ -z $target ]; then 5 | target=$(realpath ./nginx) 6 | dump=$core_dir/last.core 7 | else 8 | dump=$core_dir/$target.core 9 | fi 10 | 11 | mkdir $core_dir 2>/dev/null 12 | 13 | echo "saving coredump for $target at $dump" 14 | 15 | sudo coredumpctl dump $target > $dump 16 | sudo kdbg ./nginx "$dump" 2>/dev/null 17 | # rm "$dump" #keep it around for now 18 | -------------------------------------------------------------------------------- /dev/flood.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | require 'securerandom' 3 | require_relative 'pubsub.rb' 4 | require 'json' 5 | require 'celluloid/current' 6 | 7 | seed = 10 8 | MAX_CHANS= 5 9 | 10 | SUB_URL="http://127.0.0.1:8082/sub/broadcast/" 11 | PUB_URL="http://127.0.0.1:8082/pub/" 12 | 13 | class Chans 14 | 15 | 16 | class Chan 17 | 18 | class PubWrap 19 | include Celluloid::IO 20 | def initialize(url, opt={}) 21 | @pub=Publisher.new(url, opt) 22 | end 23 | def post(stuff, chans) 24 | @pub.post stuff 25 | chans.published! 26 | end 27 | end 28 | 29 | attr_accessor :id, :sub, :pub 30 | def initialize(id, chan, subscriber_opt={}) 31 | @id=id 32 | @sub=Subscriber.new("#{SUB_URL}#{id}", 1, subscriber_opt.merge(client: :websocket, quit_message: 'FIN')) 33 | @sub.run 34 | @pub=Publisher.new("#{PUB_URL}#{id}") 35 | @chan = chan 36 | end 37 | 38 | def pub(what) 39 | if PubWrap === @pub 40 | @pub.async.post(what, @chan) 41 | else 42 | @pub.post(what) 43 | @chan.published! 44 | end 45 | end 46 | end 47 | 48 | attr_accessor :published 49 | def published! 50 | @published += 1 51 | end 52 | 53 | def initialize(seed=0) 54 | @rng = Random.new(seed) 55 | @chans = [] 56 | @msgs = ["hey", "what", "wuh", "hello!"*100, "longer"*150] 57 | @sent=0 58 | @published = 0 59 | end 60 | 61 | def chid 62 | id="" 63 | num=rand(2..45) 64 | num.times do 65 | id << (65 + rand(26)).chr 66 | end 67 | id 68 | end 69 | 70 | private :chid 71 | 72 | def chan 73 | rn = @rng.rand(MAX_CHANS) 74 | chan = @chans[rn] 75 | unless chan 76 | chan = Chan.new(chid, self) 77 | @chans << chan 78 | end 79 | chan 80 | end 81 | 82 | def pubrand 83 | mn = @rng.rand(@msgs.length) 84 | chan.pub(@msgs[mn]) 85 | end 86 | 87 | def randmsg 88 | 89 | end 90 | end 91 | 92 | 93 | class OutputTimer 94 | include Celluloid 95 | attr_reader :fired, :timer 96 | 97 | def initialize(chans, interval = 1) 98 | @chans = chans 99 | @prev_count = 0 100 | @interval = interval 101 | @last_msg_length = 0 102 | @timer = every(interval) do 103 | pubd = @chans.published 104 | puts "Publishing at #{(pubd - @prev_count) / interval} msgs/sec (total: #{pubd})" 105 | @prev_count = pubd 106 | end 107 | end 108 | end 109 | 110 | chans = Chans.new 111 | out = OutputTimer.new(chans) 112 | 113 | loop do 114 | chans.pubrand 115 | end 116 | -------------------------------------------------------------------------------- /dev/gengource.sh: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | 3 | seconds_per_day=0.04 4 | file_resolution="640x320" 5 | git log --no-walk --tags --reverse --simplify-by-decoration --pretty="format:%ct|%D" > captions.txt 6 | 7 | gource_opt=( 8 | --highlight-dirs 9 | --multi-sampling 10 | --camera-mode overview 11 | -c 4 12 | --seconds-per-day $seconds_per_day 13 | --max-file-lag 1 14 | --auto-skip-seconds 1 15 | --date-format "%b %d %Y" 16 | --caption-file ./captions.txt 17 | --caption-duration 10 18 | --caption-offset 1 19 | ) 20 | 21 | ffmpeg_opt=( 22 | -y 23 | -r 60 24 | -f image2pipe 25 | -vcodec ppm 26 | -i - 27 | -vcodec libx264 28 | -pix_fmt yuv420p 29 | -threads 0 30 | -bf 0 31 | -preset veryslow 32 | -crf 28 33 | ) 34 | 35 | 36 | 37 | if [[ -z $1 ]]; then 38 | gource ./ $gource_opt 39 | else 40 | gource_opt+=(--viewport $file_resolution 41 | --hide mouse,progress) 42 | gource ./ $gource_opt -o - | ffmpeg $ffmpeg_opt $1 43 | fi 44 | 45 | rm captions.txt 46 | -------------------------------------------------------------------------------- /dev/multiconn.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define PORT 8082 12 | 13 | // create more looback interfaces with: 14 | // I=0; while [ $I -lt 11 ]; do ifconfig lo:$I 127.0.0.$((I+2)) netmask 255.0.0.0 up; I=$((I+1)); done 15 | 16 | char request[] = 17 | "GET /sub/broadcast/%s HTTP/1.1\r\n" 18 | "Host: localhost:8082\r\n" 19 | "Accept: text/event-stream\r\n" 20 | "User-Agent: pubsub.rb NchanTools::Subscriber::EventSourceClient #%d\r\n" 21 | "\r\n"; 22 | 23 | int main(int argc, char const* argv[]) 24 | { 25 | int id = 1; 26 | int ifc; 27 | struct rlimit rlimit; 28 | 29 | getrlimit(RLIMIT_NOFILE, &rlimit); 30 | rlimit.rlim_cur = 1000000; 31 | setrlimit(RLIMIT_NOFILE, &rlimit); 32 | 33 | for (ifc = 1; ifc <= atoi(argv[1]); ifc++) { 34 | while (1) { 35 | char interface[12]; 36 | int sock = 0, valread, client_fd; 37 | struct sockaddr_in serv_addr; 38 | char buffer[1024] = { 0 }; 39 | 40 | if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 41 | perror("Socket creation error"); 42 | break; 43 | } 44 | 45 | if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int)) < 0) 46 | perror("setsockopt(SO_REUSEADDR) failed"); 47 | 48 | if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &(int){1}, sizeof(int)) < 0) 49 | perror("setsockopt(SO_REUSEADDR) failed"); 50 | 51 | serv_addr.sin_family = AF_INET; 52 | serv_addr.sin_port = htons(PORT); 53 | 54 | sprintf(interface, "127.0.0.%d", ifc); 55 | if (inet_pton(AF_INET, interface, &serv_addr.sin_addr) <= 0) { 56 | perror("Invalid address - Address not supported"); 57 | break; 58 | } 59 | 60 | if ((client_fd = connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr))) < 0) { 61 | perror("Connection Failed"); 62 | break; 63 | } 64 | 65 | sprintf(buffer, request, argv[2], id++); 66 | send(sock, buffer, strlen(buffer), 0); 67 | 68 | printf("Launched conn %d\n", id); 69 | } 70 | } 71 | 72 | while (1) 73 | sleep(10); 74 | return 0; 75 | } -------------------------------------------------------------------------------- /dev/multiconn.sh: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | 3 | if [ "$#" -ne 2 ] 4 | then 5 | echo "Usage: ./multiconn.sh " 6 | fi 7 | 8 | IFNUMBER=$1 # about 28232 connections each interface 9 | CHANNEL=$2 10 | I=0 11 | 12 | while [ $I -lt $((IFNUMBER-1)) ] 13 | do 14 | sudo ifconfig lo:$I 127.0.0.$((I+2)) netmask 255.0.0.0 up 15 | I=$((I+1)) 16 | done 17 | gcc -o multiconn multiconn.c 18 | ./multiconn $IFNUMBER $CHANNEL -------------------------------------------------------------------------------- /dev/nchan_tools-gem/.gitignore: -------------------------------------------------------------------------------- 1 | /.bundle/ 2 | /.yardoc 3 | /_yardoc/ 4 | /coverage/ 5 | /doc/ 6 | /pkg/ 7 | /spec/reports/ 8 | /tmp/ 9 | -------------------------------------------------------------------------------- /dev/nchan_tools-gem/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | In the spirit of inclusiveness, cooperation and community, this software is 2 | distributed with the strictly enforced CYHTFYW Code of Conduct. Failure to 3 | comply with this code may result in punitive action and loss of privilege. 4 | 5 | ## CYHTFYW Code of Conduct: 6 | 7 | 1. Conduct yourself however the fuck you want. 8 | -------------------------------------------------------------------------------- /dev/nchan_tools-gem/Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } 4 | 5 | # Specify your gem's dependencies in nchan_tools.gemspec 6 | gemspec 7 | -------------------------------------------------------------------------------- /dev/nchan_tools-gem/LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 Leo Ponomarev 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /dev/nchan_tools-gem/README.md: -------------------------------------------------------------------------------- 1 | # NchanTools 2 | 3 | these here be development tools for Nchan. Documentation forthcoming someday maybe. 4 | -------------------------------------------------------------------------------- /dev/nchan_tools-gem/Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | task :default => :spec 3 | -------------------------------------------------------------------------------- /dev/nchan_tools-gem/bin/console: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require "bundler/setup" 4 | require "nchan_tools" 5 | 6 | # You can add fixtures and/or initialization code here to make experimenting 7 | # with your gem easier. You can also use a different console, if you like. 8 | 9 | # (If you use this, don't forget to add pry to your Gemfile!) 10 | # require "pry" 11 | # Pry.start 12 | 13 | require "irb" 14 | IRB.start(__FILE__) 15 | -------------------------------------------------------------------------------- /dev/nchan_tools-gem/bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | IFS=$'\n\t' 4 | set -vx 5 | 6 | bundle install 7 | 8 | # Do any other automated setup that you need to do here 9 | -------------------------------------------------------------------------------- /dev/nchan_tools-gem/exe/nchan-benchmark: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require 'securerandom' 4 | require 'nchan_tools/benchmark' 5 | require "optparse" 6 | require 'timers' 7 | require 'json' 8 | require "HDRHistogram" 9 | 10 | verbose = false 11 | save_csv = false 12 | csv_columns = NchanTools::Benchmark::CSV_COLUMNS_DEFAULT 13 | init_args = {} 14 | 15 | opt_parser=OptionParser.new do |opts| 16 | opts.on("-v", "--verbose", "somewhat rather extraneously wordful output") do 17 | verbose = true 18 | end 19 | opts.on("--csv FILENAME", "Append results to file in CSV format") do |f| 20 | save_csv = f 21 | end 22 | opts.on("--csv-columns col1,col2,...", "csv columns list") do |f| 23 | csv_columns = f.split(/\W+/).map(&:to_sym) 24 | end 25 | opts.on("-t", "--time TIME", "Time to run benchmark") do |v| 26 | init_args[:time] = v 27 | end 28 | opts.on("-r", "--msgrate NUMBER", "Message publishing rate per minute per channel") do |v| 29 | init_args[:messages_per_channel_per_minute] = v 30 | end 31 | opts.on("-p", "--msgpadding NUMBER", "Message padding, in bytes") do |v| 32 | init_args[:message_padding_bytes] = v 33 | end 34 | opts.on("-c", "--channels NUMBER", "Number of channels") do |v| 35 | init_args[:channels] = v 36 | end 37 | opts.on("-s", "--subscribers NUMBER", "Subscribers per channel") do |v| 38 | init_args[:subscribers_per_channel] = v 39 | end 40 | end 41 | opt_parser.banner="Usage: nchan-benchmark [options] url1 url2 url3..." 42 | opt_parser.parse! 43 | 44 | urls = [] 45 | urls += ARGV 46 | begin 47 | urls += STDIN.read_nonblock(100000).split /\s*\n+\s*/ 48 | rescue IO::WaitReadable 49 | rescue EOFError 50 | end 51 | 52 | urls.uniq! 53 | 54 | benchan = NchanTools::Benchmark.new urls, init_args 55 | benchan.run 56 | benchan.results 57 | benchan.append_csv_file(save_csv, csv_columns) if save_csv 58 | 59 | -------------------------------------------------------------------------------- /dev/nchan_tools-gem/exe/nchan-pub: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'securerandom' 3 | require 'nchan_tools/pubsub' 4 | require "optparse" 5 | server= "localhost:8082" 6 | msg=false 7 | loop=false 8 | repeat_sec=0.5 9 | content_type=nil 10 | eventsource_event=nil 11 | msg_gen = false 12 | on_response=Proc.new {} 13 | method=:POST 14 | runonce=false 15 | accept = nil 16 | timeout = 3 17 | verbose = nil 18 | url=nil 19 | websocket = nil 20 | 21 | opt=OptionParser.new do |opts| 22 | opts.on("-s", "--server SERVER (#{server})", "server and port.") {|v| server=v} 23 | opts.on("--url FULL_URL", "publishing url") {|v| url=v} 24 | opts.on("-v", "--verbose", "Blabberhttp"){verbose=true} 25 | opts.on("-l", "--loop [SECONDS]", "re-send message every N seconds (#{repeat_sec})") do |v| 26 | loop=true 27 | repeat_sec=Float(v) unless v.nil? 28 | end 29 | opts.on("-M", "--method [#{method}]", "method for request to server"){|v| method= v.upcase.to_sym} 30 | opts.on("-m", "--message MSG", "publish this message instead of prompting"){|v| msg=v} 31 | opts.on("-1", "--once", "run once then exit"){runonce=true} 32 | opts.on("-a", "--accept TYPE", "set Accept header"){|v| accept=v} 33 | opts.on("-c", "--content-type TYPE", "set content-type for all messages"){|v| content_type=v} 34 | opts.on( "--eventsource_event EVENT", "event: line for eversource subscribers"){|v| eventsource_event=v} 35 | opts.on("-e", "--eval RUBY_BLOCK", '{|n| "message #{n}" }'){|v| msg_gen = eval " Proc.new #{v} "} 36 | opts.on("-w", "--websocket", "user websocket to publish"){websocket = true} 37 | opts.on("-d", "--delete", "delete channel via a DELETE request"){method = :DELETE} 38 | opts.on("-p", "--put", "create channel without submitting message"){method = :PUT} 39 | opts.on("-t", "--timeout SECONDS", "publishing timeout (sec). default #{timeout} sec"){|v| timeout = v.to_i} 40 | opts.on("-r", "--response", 'Show response code and body') do 41 | on_response = Proc.new do |code, body| 42 | puts code 43 | puts body 44 | end 45 | end 46 | end 47 | opt.banner="Usage: pub.rb [options] url" 48 | opt.parse! 49 | 50 | url ||= "http://#{server}#{ARGV.last}" 51 | 52 | puts "Publishing to #{url}." 53 | 54 | 55 | loopmsg=("\r"*20) + "sending message #" 56 | 57 | pub = NchanTools::Publisher.new url, nostore: true, timeout: timeout, verbose: verbose, websocket: websocket 58 | pub.accept=accept 59 | pub.nofail=true 60 | repeat=true 61 | i=1 62 | if loop then 63 | puts "Press enter to send message." 64 | end 65 | while repeat do 66 | if msg or msg_gen 67 | if loop 68 | sleep repeat_sec 69 | print "#{loopmsg} #{i}" 70 | elsif !runonce 71 | STDIN.gets 72 | end 73 | if msg 74 | pub.submit msg, method, content_type, eventsource_event, &on_response 75 | elsif msg_gen 76 | this_msg = msg_gen.call(i).to_s 77 | puts this_msg 78 | pub.submit this_msg, method, content_type, eventsource_event, &on_response 79 | end 80 | else 81 | if loop 82 | puts "Can't repeat with custom message. use -m option" 83 | end 84 | puts "Enter message, press enter twice." 85 | message = "" 86 | while((line = STDIN.gets) != "\n") do #doesn't work when there are parameters. wtf? 87 | message << line 88 | end 89 | message=message[0..-2] #remove trailing newline 90 | 91 | pub.submit message, method, content_type, eventsource_event, &on_response 92 | puts "" 93 | end 94 | i+=1 95 | exit 0 if runonce 96 | end 97 | -------------------------------------------------------------------------------- /dev/nchan_tools-gem/exe/nchan-redis-debug: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require "redis" 4 | require "optparse" 5 | require 'nchan_tools/rdsck' 6 | 7 | opt = { 8 | url: "redis://127.0.0.1:6379/", 9 | verbose: false, 10 | command: nil 11 | } 12 | 13 | opt_parser=OptionParser.new do |opts| 14 | opts.on("--url", "--url REDIS_URL (#{opt[:url]})", "Redis server and port..") do |v| 15 | opt[:url]=v 16 | end 17 | opts.on("-q", "--quiet", "output only results without any other information") do 18 | opt[:quiet]=true 19 | end 20 | opts.on("--list-channels", "list all Nchan channels on Redis server or cluster") do |v| 21 | opt[:command]=:filter_channels 22 | end 23 | opts.on("--watch-channels", "watch for changes in Nchan channels on Redis server or cluster") do |v| 24 | opt[:command]=:watch_channels 25 | end 26 | opts.on("--set-notify-keyspace-events", "when using --watch-channels, sets the notify-keyspace-events Redis config before starting. May not be possible if the redis 'config' command is disabled") do 27 | opt[:set_notify_keyspace_events] = true 28 | end 29 | opts.on("--filter-channels-min-subscribers=[NUMBER]") do |v| 30 | opt[:command]||=:filter_channels 31 | opt[:min_subscribers]=v.to_i 32 | end 33 | end 34 | opt_parser.banner= <<~EOB 35 | Debugging tools for the Redis server or cluster backing Nchan. 36 | Usage: nchan-redis-debug [options] 37 | 38 | WARNING: --list-channels and --filter-channels-* options for this tool 39 | use the Redis SCAN command. This may increase CPU load on the Redis 40 | server and may affect the latency of Nchan requests. 41 | USE THESE OPTIONS WITH GREAT CARE 42 | 43 | Example: 44 | nchan-redis-debug --url redis:// --filter-channels-min-subscribers=10 45 | EOB 46 | opt_parser.parse! 47 | 48 | opt[:verbose] = !opt[:quiet] 49 | 50 | rdsck = Rdsck.new opt 51 | if not rdsck.connect 52 | STDERR.puts "failed to connect to #{opt[:url]}" 53 | exit 1 54 | end 55 | 56 | case opt[:command] 57 | when :filter_channels 58 | rdsck.dbg "scanning for channels #{opt[:min_subscribers] && "with subscribers >= #{opt[:min_subscribers]}"}" 59 | chans = rdsck.filter_channels(min_subscribers: opt[:min_subscribers]) 60 | rdsck.dbg "found #{chans.count} channel#{chans.count != 1 && "s"}#{chans.count == 0 ? "." : ":"}" 61 | puts chans.join("\n") 62 | when :watch_channels 63 | rdsck.dbg "watching for channels #{opt[:min_subscribers] && "with subscribers >= #{opt[:min_subscribers]}"}" 64 | rdsck.watch_channels({min_subscribers: opt[:min_subscribers]}, opt[:set_notify_keyspace_events]) 65 | else 66 | puts "Nothing to do" 67 | end 68 | -------------------------------------------------------------------------------- /dev/nchan_tools-gem/lib/nchan_tools.rb: -------------------------------------------------------------------------------- 1 | require "nchan_tools/version" 2 | 3 | module NchanTools 4 | # Your code goes here... 5 | end 6 | -------------------------------------------------------------------------------- /dev/nchan_tools-gem/lib/nchan_tools/version.rb: -------------------------------------------------------------------------------- 1 | module NchanTools 2 | VERSION = "0.1.12" 3 | end 4 | -------------------------------------------------------------------------------- /dev/nchan_tools-gem/nchan_tools.gemspec: -------------------------------------------------------------------------------- 1 | 2 | lib = File.expand_path("../lib", __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require "nchan_tools/version" 5 | 6 | Gem::Specification.new do |spec| 7 | spec.name = "nchan_tools" 8 | spec.version = NchanTools::VERSION 9 | spec.authors = ["Leo Ponomarev"] 10 | spec.email = ["leo@nchan.io"] 11 | 12 | spec.summary = %q{Development and testing utilities for Nchan} 13 | spec.description = %q{publishing, subscribing, testing, and benchmarking utilities for Nchan.} 14 | spec.homepage = "https://nchan.io" 15 | spec.license = "WTFPL" 16 | 17 | # Specify which files should be added to the gem when it is released. 18 | # The `git ls-files -z` loads the files in the RubyGem that have been added into git. 19 | spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do 20 | `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } 21 | end 22 | spec.bindir = "exe" 23 | spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } 24 | spec.require_paths = ["lib"] 25 | 26 | spec.add_dependency 'typhoeus' 27 | spec.add_dependency 'json' 28 | spec.add_dependency 'oga' 29 | spec.add_dependency "celluloid" 30 | spec.add_dependency "celluloid-io" 31 | spec.add_dependency "HDRHistogram" 32 | spec.add_dependency "redis", "~>4.2.0" 33 | spec.add_dependency "async" 34 | spec.add_dependency "async-redis" 35 | 36 | spec.add_dependency "websocket-driver" 37 | spec.add_dependency 'websocket-extensions' 38 | spec.add_dependency "permessage_deflate" 39 | spec.add_dependency 'http_parser.rb' 40 | if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.2.2') 41 | spec.add_dependency 'http-2' 42 | end 43 | spec.add_development_dependency "pry" 44 | spec.add_development_dependency "bundler" 45 | spec.add_development_dependency "rake" 46 | end 47 | -------------------------------------------------------------------------------- /dev/nginx-cachemanager.conf: -------------------------------------------------------------------------------- 1 | worker_processes 4; 2 | #debug_points stop; 3 | #error_log /dev/stderr debug; 4 | error_log /dev/stderr notice; 5 | #error_log err.log notice; 6 | pid /tmp/nginx-debug.pid; 7 | 8 | events { 9 | worker_connections 90000; 10 | accept_mutex on; 11 | } 12 | 13 | http { 14 | access_log /dev/stdout; 15 | proxy_cache_path /tmp levels=1:2 keys_zone=cache:1m; 16 | 17 | server { 18 | listen 8000; 19 | location / { 20 | proxy_cache cache; 21 | } 22 | } 23 | 24 | server { 25 | listen 8082; 26 | # root ./; 27 | location ~ /pub/(\w+)$ { 28 | set $push_channel_id $1; 29 | push_publisher; 30 | push_min_message_buffer_length 5; 31 | push_max_message_buffer_length 20; 32 | push_message_timeout 5s; 33 | push_channel_group test; 34 | } 35 | 36 | location ~ /sub/broadcast/(\w+)$ { 37 | push_subscriber; 38 | push_channel_group test; 39 | set $push_channel_id $1; 40 | push_subscriber_concurrency broadcast; 41 | } 42 | location ~ /sub/first/(\w+)$ { 43 | push_subscriber; 44 | push_channel_group test; 45 | set $push_channel_id $1; 46 | push_subscriber_concurrency first; 47 | } 48 | location ~ /sub/last/(\w+)$ { 49 | push_subscriber; 50 | push_channel_group test; 51 | set $push_channel_id $1; 52 | push_subscriber_concurrency last; 53 | } 54 | 55 | #authorized channels only -- publishers must create the channel before subscribing 56 | location ~ /sub/authorized/(\w+)$ { 57 | push_authorized_channels_only on; 58 | push_subscriber; 59 | push_channel_group test; 60 | set $push_channel_id $1; 61 | } 62 | 63 | 64 | 65 | 66 | } 67 | } -------------------------------------------------------------------------------- /dev/nginx-pkg/.gitignore: -------------------------------------------------------------------------------- 1 | src 2 | pkg 3 | *.tar.gz 4 | *.pkg.tar* 5 | *no_pool.patch 6 | ngx_debug_pool/ 7 | lua-nginx-module/ 8 | nginx/ -------------------------------------------------------------------------------- /dev/nginx-pkg/bl.txt: -------------------------------------------------------------------------------- 1 | fun:ngx_regex_module_init 2 | fun:ngx_http_script_copy_capture_len_code 3 | fun:ngx_http_script_copy_capture_code 4 | fun:ngx_http_parse_request_line 5 | fun:ngx_writev 6 | src:*ngx_writev_chain.c 7 | -------------------------------------------------------------------------------- /dev/nginx-pkg/install: -------------------------------------------------------------------------------- 1 | #!sh 2 | post_install() { 3 | post_upgrade 4 | } 5 | post_upgrade() { 6 | rm -fv /etc/nginx/http 2>/dev/null 7 | ln -sf /usr/share/nginx/http /etc/nginx/html 8 | } 9 | post_uninstall() { 10 | rm /etc/nginx/http 11 | } 12 | -------------------------------------------------------------------------------- /dev/nginx-pkg/nchan: -------------------------------------------------------------------------------- 1 | ../../ -------------------------------------------------------------------------------- /dev/nginx-pkg/nginx.conf: -------------------------------------------------------------------------------- 1 | NGINX_CONFIG=/etc/nginx/conf/nginx.conf 2 | -------------------------------------------------------------------------------- /dev/nginx-pkg/nginx.logrotate: -------------------------------------------------------------------------------- 1 | /var/log/nginx/*log /var/log/nginx/*/*log { 2 | daily 3 | create 640 http log 4 | compress 5 | postrotate 6 | [ ! -f /run/nginx.pid ] || kill -USR1 `cat /run/nginx.pid` 7 | endscript 8 | } 9 | -------------------------------------------------------------------------------- /dev/nginx-pkg/nginx.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=A high performance web server and a reverse proxy server 3 | After=syslog.target network.target 4 | 5 | [Service] 6 | Type=forking 7 | PIDFile=/run/nginx.pid 8 | ExecStartPre=/usr/sbin/nginx -t -q -g 'pid /run/nginx.pid; daemon on; master_process on;' 9 | ExecStart=/usr/sbin/nginx -g 'pid /run/nginx.pid; daemon on; master_process on;' 10 | ExecReload=/usr/sbin/nginx -g 'pid /run/nginx.pid; daemon on; master_process on;' -s reload 11 | ExecStop=/usr/sbin/nginx -g 'pid /run/nginx.pid;' -s quit 12 | 13 | [Install] 14 | WantedBy=multi-user.target 15 | -------------------------------------------------------------------------------- /dev/nginx-pkg/ngx_slab.patch: -------------------------------------------------------------------------------- 1 | diff --git a/src/core/ngx_slab.c b/src/core/ngx_slab.c 2 | --- a/src/core/ngx_slab.c 3 | +++ b/src/core/ngx_slab.c 4 | @@ -129,6 +129,8 @@ ngx_slab_init(ngx_slab_pool_t *pool) 5 | pool->pages->slab = pages; 6 | } 7 | 8 | + pool->last = pool->pages + pages; 9 | + 10 | pool->log_nomem = 1; 11 | pool->log_ctx = &pool->zero; 12 | pool->zero = '\0'; 13 | @@ -626,6 +628,8 @@ ngx_slab_alloc_pages(ngx_slab_pool_t *po 14 | if (page->slab >= pages) { 15 | 16 | if (page->slab > pages) { 17 | + page[page->slab - 1].prev = (uintptr_t) &page[pages]; 18 | + 19 | page[pages].slab = page->slab - pages; 20 | page[pages].next = page->next; 21 | page[pages].prev = page->prev; 22 | @@ -672,7 +676,8 @@ static void 23 | ngx_slab_free_pages(ngx_slab_pool_t *pool, ngx_slab_page_t *page, 24 | ngx_uint_t pages) 25 | { 26 | - ngx_slab_page_t *prev; 27 | + ngx_uint_t type; 28 | + ngx_slab_page_t *prev, *join; 29 | 30 | page->slab = pages--; 31 | 32 | @@ -686,6 +691,53 @@ ngx_slab_free_pages(ngx_slab_pool_t *poo 33 | page->next->prev = page->prev; 34 | } 35 | 36 | + join = page + page->slab; 37 | + 38 | + if (join < pool->last) { 39 | + type = join->prev & NGX_SLAB_PAGE_MASK; 40 | + 41 | + if (type == NGX_SLAB_PAGE && join->next != NULL) { 42 | + pages += join->slab; 43 | + page->slab += join->slab; 44 | + 45 | + prev = (ngx_slab_page_t *) (join->prev & ~NGX_SLAB_PAGE_MASK); 46 | + prev->next = join->next; 47 | + join->next->prev = join->prev; 48 | + 49 | + join->slab = NGX_SLAB_PAGE_FREE; 50 | + join->next = NULL; 51 | + join->prev = NGX_SLAB_PAGE; 52 | + } 53 | + } 54 | + 55 | + if (page > pool->pages) { 56 | + join = page - 1; 57 | + type = join->prev & NGX_SLAB_PAGE_MASK; 58 | + 59 | + if (type == NGX_SLAB_PAGE && join->slab == NGX_SLAB_PAGE_FREE) { 60 | + join = (ngx_slab_page_t *) (join->prev & ~NGX_SLAB_PAGE_MASK); 61 | + } 62 | + 63 | + if (type == NGX_SLAB_PAGE && join->next != NULL) { 64 | + pages += join->slab; 65 | + join->slab += page->slab; 66 | + 67 | + prev = (ngx_slab_page_t *) (join->prev & ~NGX_SLAB_PAGE_MASK); 68 | + prev->next = join->next; 69 | + join->next->prev = join->prev; 70 | + 71 | + page->slab = NGX_SLAB_PAGE_FREE; 72 | + page->next = NULL; 73 | + page->prev = NGX_SLAB_PAGE; 74 | + 75 | + page = join; 76 | + } 77 | + } 78 | + 79 | + if (pages) { 80 | + page[pages].prev = (uintptr_t) page; 81 | + } 82 | + 83 | page->prev = (uintptr_t) &pool->free; 84 | page->next = pool->free.next; 85 | 86 | diff --git a/src/core/ngx_slab.h b/src/core/ngx_slab.h 87 | --- a/src/core/ngx_slab.h 88 | +++ b/src/core/ngx_slab.h 89 | @@ -29,6 +29,7 @@ typedef struct { 90 | size_t min_shift; 91 | 92 | ngx_slab_page_t *pages; 93 | + ngx_slab_page_t *last; 94 | ngx_slab_page_t free; 95 | 96 | u_char *start; 97 | 98 | -- -------------------------------------------------------------------------------- /dev/nginx-pkg/track-pool.patch: -------------------------------------------------------------------------------- 1 | --- nginx/src/core/ngx_palloc.c 2018-07-03 17:21:34.582927058 -0400 2 | +++ nginx-patched/src/core/ngx_palloc.c.new 2018-07-03 17:21:08.246149440 -0400 3 | @@ -7,6 +7,7 @@ 4 | 5 | #include 6 | #include 7 | +#include 8 | 9 | 10 | static ngx_inline void *ngx_palloc_small(ngx_pool_t *pool, size_t size, 11 | @@ -39,6 +40,8 @@ 12 | p->cleanup = NULL; 13 | p->log = log; 14 | 15 | + p->locked = 0; 16 | + p->total_allocd = 0; 17 | return p; 18 | } 19 | 20 | @@ -116,12 +119,18 @@ 21 | pool->current = pool; 22 | pool->chain = NULL; 23 | pool->large = NULL; 24 | + pool->locked = 0; 25 | + pool->total_allocd=0; 26 | } 27 | 28 | 29 | void * 30 | ngx_palloc(ngx_pool_t *pool, size_t size) 31 | { 32 | + if(pool->locked) { 33 | + raise(SIGABRT); 34 | + } 35 | + pool->total_allocd+=size; 36 | #if !(NGX_DEBUG_PALLOC) 37 | if (size <= pool->max) { 38 | return ngx_palloc_small(pool, size, 1); 39 | --- nginx/src/core/ngx_palloc.h 2018-07-03 17:21:34.582927058 -0400 40 | +++ nginx-patched/src/core/ngx_palloc.h.new 2018-07-03 17:21:17.296187571 -0400 41 | @@ -62,6 +62,8 @@ 42 | ngx_pool_large_t *large; 43 | ngx_pool_cleanup_t *cleanup; 44 | ngx_log_t *log; 45 | + unsigned locked; 46 | + size_t total_allocd; 47 | }; 48 | 49 | 50 | -------------------------------------------------------------------------------- /dev/nginx-proxy.conf: -------------------------------------------------------------------------------- 1 | worker_processes 3; 2 | pid /tmp/pushmodule-test-nginx-proxy.pid; 3 | daemon off; 4 | 5 | events { 6 | worker_connections 90000; 7 | accept_mutex on; 8 | } 9 | 10 | error_log /dev/stderr notice; 11 | 12 | http { 13 | access_log /dev/null; 14 | client_body_temp_path /tmp/ 1 2; 15 | sendfile on; 16 | keepalive_timeout 65; 17 | server { 18 | listen 8083; 19 | location / { 20 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 21 | proxy_set_header Host $http_host; 22 | proxy_redirect off; 23 | proxy_pass http://localhost:8082; 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /dev/package/.gitignore: -------------------------------------------------------------------------------- 1 | pkgs/* -------------------------------------------------------------------------------- /dev/package/fedora/build-nginx-with-nchan.sh: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | 3 | nchan_root=~/sandbox/nchan 4 | 5 | NGINX_VER=`nginx -v 2>&1 | sed "s/nginx version:\snginx\/\+//g"` 6 | echo "building for nginx version $NGINX_VER" 7 | 8 | echo -ne "nchan version:" 9 | read NCHAN_VER 10 | 11 | pushd ~/rpmbuild/SOURCES/ 12 | 13 | _nginx_src="nginx-${NGINX_VER}.tar.gz" 14 | if [[ ! -e $_nginx_src ]]; then 15 | wget "https://nginx.org/download/${_nginx_src}" 16 | wget "https://nginx.org/download/${_nginx_src}.asc" 17 | fi 18 | 19 | if [[ $NCHAN_VER == "master" ]]; then 20 | _nchan_tag="${NCHAN_VER}" 21 | else 22 | _nchan_tag="v${NCHAN_VER}" 23 | fi 24 | 25 | if [[ ! -e ${_nchan_tag}.tar.gz ]]; then 26 | wget "https://github.com/slact/nchan/archive/${_nchan_tag}.tar.gz" 27 | fi 28 | 29 | if [[ ! -e nchan_no_HTTP_HEADERS.patch ]]; then 30 | cp "$nchan_root/dev/package/fedora/nchan_no_HTTP_HEADERS.patch" ./ 31 | fi 32 | 33 | if [[ ! -e nginx-auto-cc-gcc.patch ]]; then 34 | cp "$nchan_root/dev/package/fedora/nginx-auto-cc-gcc.patch" ./ 35 | fi 36 | 37 | popd 38 | 39 | 40 | rm ~/rpmbuild/SRPMS/* -Rfv 41 | rm ~/rpmbuild/RPMS/* -Rfv 42 | 43 | pushd $nchan_root/dev/package/fedora/ 44 | 45 | #git reset --hard HEAD 46 | #git pull 47 | 48 | rpmbuild --define "nchan_ver $NCHAN_VER" --define "nginx_ver $NGINX_VER" -ba nchan.spec 49 | 50 | popd 51 | 52 | scp ~/rpmbuild/RPMS/x86_64/nginx-mod-nchan-1*.x86_64.rpm ~/rpmbuild/SRPMS/nginx-mod-nchan-1*.src.rpm 10.0.2.2:/tmp 53 | -------------------------------------------------------------------------------- /dev/package/fedora/nchan_no_HTTP_HEADERS.patch: -------------------------------------------------------------------------------- 1 | --- config.orig 2016-11-24 00:55:25.825028144 -0500 2 | +++ config 2016-11-24 01:03:24.898558057 -0500 3 | @@ -89,7 +89,7 @@ 4 | 5 | ngx_module_incs=$ngx_addon_dir/src 6 | 7 | -have=NGX_HTTP_HEADERS . auto/have 8 | +#have=NGX_HTTP_HEADERS . auto/have 9 | 10 | if test -n "$ngx_module_link"; then 11 | ngx_module_type=HTTP 12 | -------------------------------------------------------------------------------- /dev/package/fedora/nginx-auto-cc-gcc.patch: -------------------------------------------------------------------------------- 1 | --- auto/cc/gcc.orig 2007-03-22 08:34:53.000000000 -0600 2 | +++ auto/cc/gcc 2007-03-22 08:58:47.000000000 -0600 3 | @@ -172,7 +172,9 @@ 4 | 5 | 6 | # stop on warning 7 | -CFLAGS="$CFLAGS -Werror" 8 | +# This combined with Fedora's FORTIFY_SOURCE=2 option causes it nginx 9 | +# to not compile. 10 | +#CFLAGS="$CFLAGS -Werror" 11 | 12 | # debug 13 | CFLAGS="$CFLAGS -g" 14 | -------------------------------------------------------------------------------- /dev/package/nginx-nchan-static/.gitignore: -------------------------------------------------------------------------------- 1 | pkg/ 2 | src/ 3 | nchan/ 4 | *.tar.gz 5 | *.pkg.* -------------------------------------------------------------------------------- /dev/package/nginx-nchan-static/nginx.conf: -------------------------------------------------------------------------------- 1 | NGINX_CONFIG=/etc/nginx/nginx.conf 2 | -------------------------------------------------------------------------------- /dev/package/nginx-nchan-static/nginx.logrotate: -------------------------------------------------------------------------------- 1 | /var/log/nginx/*log 2 | /var/log/nginx/*/*log 3 | { 4 | daily 5 | missingok 6 | create 640 http log 7 | compress 8 | postrotate 9 | [ ! -f /run/nginx.pid ] || kill -USR1 `cat /run/nginx.pid` 10 | endscript 11 | } 12 | -------------------------------------------------------------------------------- /dev/package/nginx-nchan-static/nginx.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=A high performance web server and a reverse proxy server 3 | After=network.target 4 | 5 | [Service] 6 | Type=forking 7 | PIDFile=/run/nginx.pid 8 | PrivateDevices=yes 9 | SyslogLevel=err 10 | 11 | ExecStartPre=/usr/bin/nginx -t -q -g 'pid /run/nginx.pid; error_log stderr;' 12 | ExecStart=/usr/bin/nginx -g 'pid /run/nginx.pid; error_log stderr;' 13 | ExecReload=/usr/bin/kill -HUP $MAINPID 14 | KillSignal=SIGQUIT 15 | KillMode=mixed 16 | 17 | [Install] 18 | WantedBy=multi-user.target 19 | -------------------------------------------------------------------------------- /dev/package/pkgs/.gitignore: -------------------------------------------------------------------------------- 1 | *.tar 2 | *.deb 3 | *.pkg.* -------------------------------------------------------------------------------- /dev/package/pkgs/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/slact/nchan/9c6909d0a4c4611479b7182ac29b2065a5845614/dev/package/pkgs/.gitkeep -------------------------------------------------------------------------------- /dev/package/repackage.sh: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | mydir=${0:a:h} 3 | 4 | pkgdir=$mydir/pkgs 5 | 6 | rm $pkgdir/* -fv >/dev/null 2>/dev/null 7 | 8 | pushd $mydir/nginx-nchan-static 9 | MTUNE_GENERIC=1 PKGDEST="$pkgdir" makepkg 10 | popd 11 | 12 | pushd $pkgdir 13 | archpkg=`echo *pkg.tar.xz` 14 | 15 | tarname=${archpkg:r} 16 | tarname=${tarname:r} 17 | tarname=${tarname:r} 18 | 19 | echo $tarname 20 | 21 | bundle exec fpm -s pacman -t tar -n "$tarname" $archpkg 22 | gzip -f "$tarname.tar" 23 | 24 | bundle exec fpm -s pacman --no-auto-depends -t deb $archpkg 25 | #bundle exec fpm -s pacman -t rpm $archpkg 26 | #bundle exec fpm -s pacman -t osxpkg $archpkg 27 | 28 | popd 29 | -------------------------------------------------------------------------------- /dev/prepare.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | UNAME=$(uname -a) 3 | 4 | case $UNAME in 5 | *Debian*) 6 | echo "it's debian" 7 | 8 | #stuff needed to build nginx + nchan 9 | sudo apt-get install -y libssl-dev libpcre3-dev zsh 10 | 11 | #ruby deps 12 | sudo apt-get install -y libxslt-dev libxml2-dev 13 | 14 | #build tools 15 | sudo apt-get install -y lua5.2 ruby bundler 16 | bundle install 17 | 18 | #convenience tools 19 | sudo apt-get install -y emacs-nox htop lsof strace ack-grep 20 | 21 | ;; 22 | esac 23 | -------------------------------------------------------------------------------- /dev/pub-multi.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | require 'securerandom' 3 | require_relative 'pubsub.rb' 4 | require "optparse" 5 | server= "localhost:8082" 6 | msg=false 7 | loop=false 8 | repeat_sec=0.5 9 | content_type=nil 10 | on_response=Proc.new {} 11 | method=:POST 12 | runonce=false 13 | 14 | #Typhoeus::Config.verbose=true 15 | 16 | pubs = [] 17 | ARGV.each do |v| 18 | url = "http://#{server}/pub/#{v}" 19 | puts "Publishing to #{url}." 20 | pub = [v, Publisher.new(url, :timeout => 10000)] 21 | pub[1].nofail = true 22 | pubs << pub 23 | end 24 | 25 | repeat=true 26 | i=1 27 | 28 | while repeat do 29 | puts "press enter to send message ##{i}" 30 | STDIN.gets 31 | n=0 32 | pubs.each do |p| 33 | n+=1 34 | this_msg = "#{p.first} (#{n}) -- #{i}" 35 | p.last.submit this_msg, method, content_type, &on_response 36 | puts "sent #{this_msg}" 37 | end 38 | i+=1 39 | end 40 | -------------------------------------------------------------------------------- /dev/pub.rb: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | bundle exec nchan-pub "$@" 3 | -------------------------------------------------------------------------------- /dev/python_check.sh: -------------------------------------------------------------------------------- 1 | # check if pip3 is installed 2 | if ! which pip3 > /dev/null; then 3 | # check if pyenv is installed 4 | export PYENV_ROOT=$1/pyenv 5 | if [ ! -f $PYENV_ROOT/bin/pyenv ]; then 6 | curl https://pyenv.run | zsh 7 | fi 8 | PATH=$PYENV_ROOT/bin:$PATH 9 | 10 | # check if pyenv python is installed 11 | PY_VERSION=`ls -1 $PYENV_ROOT/versions 2>/dev/null | tail -1` 12 | if [ -z $PY_VERSION ]; then 13 | pyenv install 3.12 14 | PY_VERSION=`ls -1 $PYENV_ROOT/versions 2>/dev/null | tail -1` 15 | fi 16 | PATH=$PYENV_ROOT/versions/$PY_VERSION/bin:$PATH 17 | fi 18 | 19 | # check if boto3 is install 20 | if ! python3 -c 'import boto3' 2> /dev/null; then 21 | pip3 install boto3 22 | fi 23 | -------------------------------------------------------------------------------- /dev/redis-cluster/.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | redis-configs -------------------------------------------------------------------------------- /dev/redis-cluster/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/slact/nchan/9c6909d0a4c4611479b7182ac29b2065a5845614/dev/redis-cluster/__init__.py -------------------------------------------------------------------------------- /dev/redis-cluster/cluster_info_output.py: -------------------------------------------------------------------------------- 1 | from utils import open_file, write_on_file, close_file,is_file_present,get_current_path, get_cluster_configuration 2 | from constants import CLUSTER_CONFIG_PATH, FILE_MODE_READ, FILE_MODE_WRITE,REPLICAS_PER_SHARD,USER_AUTH,PASSWORD,\ 3 | NUMBER_OF_SHARDS 4 | import json 5 | from cluster import Cluster 6 | 7 | def get_cluster_information(config_list): 8 | 9 | #Create cluster object 10 | cluster = Cluster(number_of_shards=int(config_list[NUMBER_OF_SHARDS]), replicas_per_shard=int(config_list[REPLICAS_PER_SHARD]), 11 | use_auth=config_list[USER_AUTH],password=config_list[PASSWORD]) 12 | 13 | node_info_list = cluster.get_cluster_info() 14 | 15 | json_string = json.dumps([z.__dict__ for z in node_info_list], indent=4) 16 | json_file = open_file('{}'.format("data.json"), FILE_MODE_WRITE) 17 | write_on_file(json_file, json_string) 18 | close_file(json_file) 19 | 20 | if __name__ == "__main__": 21 | #Check For cluster Information file present or not 22 | if(is_file_present(get_current_path()+CLUSTER_CONFIG_PATH)): 23 | #Get all the required cluster information 24 | config_list=get_cluster_configuration(CLUSTER_CONFIG_PATH,FILE_MODE_READ) 25 | if config_list: 26 | #Store all the Cluster Information in json file 27 | get_cluster_information(config_list) -------------------------------------------------------------------------------- /dev/redis-cluster/cluster_location.py: -------------------------------------------------------------------------------- 1 | from enum import Enum 2 | 3 | class ClusterLocation(Enum): 4 | '''Enum to indicate where a cluster lies''' 5 | ELASTICACHE = "elasticache" 6 | LOCAL = "local" 7 | -------------------------------------------------------------------------------- /dev/redis-cluster/cluster_node.py: -------------------------------------------------------------------------------- 1 | from constants import APPEND_ONLY, CLUSTER_CONFIG_FILE, CLUSTER_ENABLED, CLUSTER_NODE_TIMEOUT 2 | from constants import REDIS_CONFIG_FILE_NAME, START_REDIS_SERVER_CMD, REDIS_CONFIG_FOLDER, REDIS_START_PORT,REDIS_CLI_CMD,\ 3 | SHUTDOWN_CMD,AUTHENTICATION_CMD 4 | from utils import change_directory 5 | from utils import join_path_components, create_directory, run_subprocess, get_current_path 6 | from utils import open_file, write_on_file 7 | 8 | 9 | class ClusterNode: 10 | 11 | def __init__(self, cluster_path, node_port, password=None): 12 | self.cluster_path = cluster_path 13 | self.node_port = node_port 14 | self.password = password 15 | 16 | def create_node(self): 17 | node_path = join_path_components(self.cluster_path, str(self.node_port)) 18 | create_directory(node_path) 19 | redis_config_path = join_path_components(node_path, REDIS_CONFIG_FILE_NAME) 20 | self.create_node_config(redis_config_path) 21 | 22 | def create_node_config(self, redis_config_path): 23 | file = open_file(file_path=redis_config_path, mode='a') 24 | self.add_node_config(file) 25 | 26 | def start_node(self): 27 | 28 | curr_path = join_path_components(self.cluster_path, str(self.node_port)) 29 | change_directory(curr_path) 30 | run_subprocess([START_REDIS_SERVER_CMD]) 31 | 32 | def destroy_node(self): 33 | 34 | #Redis Cli shutdown Command to destroy node 35 | if self.password: 36 | run_subprocess([REDIS_CLI_CMD+str(self.node_port)+AUTHENTICATION_CMD+self.password+SHUTDOWN_CMD]) 37 | else: 38 | run_subprocess([REDIS_CLI_CMD+str(self.node_port)+SHUTDOWN_CMD]) 39 | 40 | def add_node_config(self, file): 41 | write_on_file(file, "port " + str(self.node_port)) 42 | write_on_file(file, "cluster-enabled " + CLUSTER_ENABLED) 43 | write_on_file(file, "cluster-config-file " + CLUSTER_CONFIG_FILE) 44 | write_on_file(file, "cluster-node-timeout " + CLUSTER_NODE_TIMEOUT) 45 | if self.password: 46 | write_on_file(file, "requirepass {}".format(self.password)) 47 | write_on_file(file, "masterauth {}".format(self.password)) 48 | write_on_file(file, "appendonly " + APPEND_ONLY) 49 | 50 | def get_node_password(self): 51 | node_path = join_path_components(self.cluster_path, str(REDIS_START_PORT)) 52 | redis_config_path = join_path_components(node_path, REDIS_CONFIG_FILE_NAME) 53 | file_pass=open(redis_config_path,"r") 54 | lines=file_pass.read().splitlines() 55 | password = lines[4].split(' ') 56 | if (password[0] == "requirepass"): 57 | return password[1] 58 | -------------------------------------------------------------------------------- /dev/redis-cluster/cluster_shutdown.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo "The process will shut down and will lose all the data to process press Y , to cancel press any button apart from Y" 3 | read value 4 | 5 | if [ $value == "y" ] || [ $value == "Y" ] 6 | then 7 | ps -ef | grep redis-server | awk '{print $2}' | xargs kill -9 8 | fi 9 | -------------------------------------------------------------------------------- /dev/redis-cluster/cluster_shutdown_by_rediscli.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | from cluster import Cluster 3 | from constants import REDIS_START_PORT,CLUSTER_CONFIG_PATH,CLUSTER_SHUTDOWN_WARN,FILE_MODE_READ,NUMBER_OF_SHARDS,\ 4 | USER_AUTH,PASSWORD,REPLICAS_PER_SHARD 5 | from utils import get_current_path,is_file_present,open_file,load_json,get_cluster_configuration 6 | 7 | 8 | def destroy_cluster_via_redis_cli(config_list): 9 | 10 | #Create Cluster Object 11 | cluster = Cluster(number_of_shards=int(config_list[NUMBER_OF_SHARDS]), replicas_per_shard=int(config_list[REPLICAS_PER_SHARD]), 12 | use_auth=config_list[USER_AUTH],password=config_list[PASSWORD]) 13 | 14 | #Warning Message for Cluster Shutdown 15 | destroy_cluster = input (CLUSTER_SHUTDOWN_WARN+'\n') 16 | 17 | #Check for Cluster Shutdown 18 | if destroy_cluster=='Y' or destroy_cluster=='y': 19 | cluster.destroy_cluster() 20 | 21 | if __name__ == "__main__": 22 | #Check For cluster Information file present or not 23 | if(is_file_present(get_current_path()+CLUSTER_CONFIG_PATH)): 24 | #Get all the required cluster information 25 | config_list=get_cluster_configuration(CLUSTER_CONFIG_PATH,FILE_MODE_READ) 26 | if config_list: 27 | #Call for destroy cluster 28 | destroy_cluster_via_redis_cli(config_list) 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /dev/redis-cluster/cluster_state_information.py: -------------------------------------------------------------------------------- 1 | from utils import run_subprocess, get_current_path, write_on_file, open_file, close_file 2 | from cluster_node import ClusterNode 3 | from constants import REDIS_CLI_CMD, CLUSTER_NODES_INFO, REDIS_CONFIG_FOLDER, REDIS_START_PORT,\ 4 | NO_AUTH_WARNING,CLUSTER_NODES_CMD,AUTHENTICATION_CMD,FILE_MODE_WRITE,CLUSTER_STATE_INFORMATION 5 | 6 | 7 | def get_cluster_info(): 8 | info_file = open_file(get_current_path()+CLUSTER_STATE_INFORMATION,FILE_MODE_WRITE) 9 | 10 | cluster_node = ClusterNode(cluster_path=get_current_path() + REDIS_CONFIG_FOLDER, node_port=REDIS_START_PORT) 11 | password = cluster_node.get_node_password() 12 | if password: 13 | cmd = REDIS_CLI_CMD + str(REDIS_START_PORT) +AUTHENTICATION_CMD+ str(password) +NO_AUTH_WARNING+CLUSTER_NODES_CMD 14 | a = run_subprocess([cmd], info_file, info_file) 15 | else: 16 | a = run_subprocess([CLUSTER_NODES_INFO], info_file, info_file) 17 | write_on_file(info_file, 'NODE INFO:') 18 | 19 | close_file(info_file) 20 | 21 | 22 | if __name__ == "__main__": 23 | get_cluster_info() 24 | -------------------------------------------------------------------------------- /dev/redis-cluster/cluster_timeout.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #Get start port From cluster Information 4 | startPort=`cat cluster_information.json |jq '.start_port'` 5 | 6 | #Get Password From cluster Information 7 | password=`cat cluster_information.json |jq '.password'` 8 | password="${password#?}" 9 | password="${password%?}" 10 | 11 | 12 | #Show Cluster Nodes 13 | if [ ! -z "$password" -a "$password" != " " ] ;then 14 | redis-cli -p $startPort -a $password cluster nodes 15 | echo "Node Ports :" 16 | redis-cli -p $startPort -a $password --no-auth-warning cluster nodes |cut -d ':' -f2|cut -d'-' -f1|cut -d '@' -f2|cut -c 2- 17 | 18 | else 19 | redis-cli -p $startPort cluster nodes 20 | echo "Nodes Ports :" 21 | redis-cli -p $startPort cluster nodes |cut -d ':' -f2|cut -d'-' -f1|cut -d '@' -f2|cut -c 2- 22 | 23 | fi 24 | 25 | #Enter the Node Port for process id check 26 | echo "Enter the port for timeout followed by failover" 27 | read port_number 28 | 29 | 30 | if [[ ! -z "$port_number" ]] 31 | then 32 | #process Id for the particular port 33 | process_id=$(ps -ef |grep redis-server |grep $port_number |awk '{print $2}') 34 | else 35 | echo "Port Number required for timeout " 36 | exit 0 37 | fi 38 | 39 | 40 | kill -SIGSTOP $process_id 41 | 42 | sleep 10 43 | kill -SIGCONT $process_id 44 | 45 | #Show Cluster Nodes 46 | if [ ! -z "$password" -a "$password" != " " ] ;then 47 | redis-cli -p $startPort -a $password cluster nodes 48 | 49 | else 50 | redis-cli -p $startPort cluster nodes 51 | 52 | fi -------------------------------------------------------------------------------- /dev/redis-cluster/cluster_timeout_failover.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #Get start port From cluster Information 4 | startPort=`cat cluster_information.json |jq '.start_port'` 5 | 6 | #Get Password From cluster Information 7 | password=`cat cluster_information.json |jq '.password'` 8 | password="${password#?}" 9 | password="${password%?}" 10 | 11 | #Show Cluster Nodes 12 | if [ ! -z "$password" -a "$password" != " " ] ;then 13 | redis-cli -p $startPort -a $password cluster nodes 14 | echo "Node Ports :" 15 | redis-cli -p $startPort -a $password --no-auth-warning cluster nodes |cut -d ':' -f2|cut -d'-' -f1|cut -d '@' -f2|cut -c 2- 16 | 17 | else 18 | redis-cli -p $startPort cluster nodes 19 | echo "Nodes Ports :" 20 | redis-cli -p $startPort cluster nodes |cut -d ':' -f2|cut -d'-' -f1|cut -d '@' -f2|cut -c 2- 21 | 22 | fi 23 | 24 | #Enter the Node Port for process id check 25 | echo "Enter the port for timeout followed by failover" 26 | read port_number 27 | 28 | 29 | if [[ ! -z "$port_number" ]] 30 | then 31 | #process Id for the particular port 32 | process_id=$(ps -ef |grep redis-server |grep $port_number |awk '{print $2}') 33 | else 34 | echo "Port Number required for timeout " 35 | exit 0 36 | fi 37 | 38 | #Hold on the process 39 | kill -SIGSTOP $process_id 40 | 41 | sleep 10 42 | 43 | #Show Cluster Nodes 44 | if [ ! -z "$password" -a "$password" != " " ] ;then 45 | redis-cli -p $startPort -a $password cluster nodes 46 | 47 | else 48 | redis-cli -p $startPort cluster nodes 49 | 50 | fi -------------------------------------------------------------------------------- /dev/redis-cluster/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "local": { 3 | "shards": 4, 4 | "replicas": 2, 5 | "auth": false, 6 | "ip": "127.0.0.1", 7 | "start_port": 6379 8 | }, 9 | "elasticache":{ 10 | "CacheNodeType":"cache.t3.small", 11 | "EngineVersion":"6.2", 12 | "ReplicationGroupDescription":"Sample cache with cluster mode enabled", 13 | "ReplicationGroupId":"rep-group-1", 14 | "NumNodeGroups":4, 15 | "ReplicasPerNodeGroup":2 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /dev/redis-cluster/constants.py: -------------------------------------------------------------------------------- 1 | REDIS_CONFIG_FOLDER = '/redis-configs' 2 | REDIS_START_PORT = 6379 3 | REDIS_CONFIG_FILE_NAME = 'redis.conf' 4 | CLUSTER_ENABLED = 'yes' 5 | CLUSTER_CONFIG_FILE = 'nodes.conf' 6 | CLUSTER_NODE_TIMEOUT = '5000' 7 | APPEND_ONLY = 'yes' 8 | START_REDIS_SERVER_CMD = 'redis-server ./redis.conf' 9 | DEFAULT_IP = '127.0.0.1' 10 | REDIS_CLI_CMD = 'redis-cli -p ' 11 | CLUSTER_NODES_INFO = 'redis-cli -p ' + str(REDIS_START_PORT) + ' cluster nodes' 12 | CLUSTER_CONFIG_PATH='/cluster_information.json' 13 | CLUSTER_SHUTDOWN_WARN="The process will shut down and will lose all the data to process press Y , to cancel press any button apart from Y" 14 | FILE_MODE_APPEND='a' 15 | FILE_MODE_READ='r' 16 | FILE_MODE_WRITE='w' 17 | NUMBER_OF_SHARDS='number_of_shards' 18 | REPLICAS_PER_SHARD='replicas_per_shard' 19 | USER_AUTH='user_auth' 20 | PASSWORD='password' 21 | SHUTDOWN_CMD=' shutdown' 22 | AUTHENTICATION_CMD=' -a ' 23 | NO_AUTH_WARNING=' --no-auth-warning' 24 | CLUSTER_NODES_CMD=' cluster nodes' 25 | EMPTY_STRING="" 26 | START_PORT='start_port' 27 | CLUSTER_STATE_INFORMATION='/cluster_state_info.txt' 28 | READING_MODE = 'r' 29 | CONFIG_FILE_PATH = './config.json' 30 | KEYWORD_CLUSTER = 'cluster' 31 | ARG_PREFIX = '--' 32 | ARG_KEYWORD_AUTH = 'auth' 33 | ARG_KEYWORD_START_PORT = 'start_port' 34 | ARG_KEYWORD_SHARDS = 'shards' 35 | ARG_KEYWORD_REPLICAS = 'replicas' 36 | ARG_KEYWORD_IP = 'ip' 37 | ARG_KEYWORD_PASSWORD= 'password' 38 | ARG_KEYWORD_NUMNODEGROUPS = 'numnodegroups' 39 | ARG_KEYWORD_REPLICASPERNODEGROUP = 'replicaspernodegroup' 40 | ARG_KEYWORD_CACHENODETYPE = 'cachenodetype' 41 | ARG_KEYWORD_ENGINEVERSION = 'engineversion' 42 | ARG_KEYWORD_REPLICATIONGROUPDESCRIPTION = 'replicationgroupdescription' 43 | ARG_KEYWORD_REPLICATIONGROUPID = 'replicationgroupid' 44 | ARG_KEYWORD_RETAINPRIMARYCLUSTER = 'retainprimarycluster' 45 | CLUSTER_SHUTDOWN_CMD = 'ps -ef | grep redis-server | awk \'{print $2}\' | xargs kill -9' 46 | REDIS_ENGINE = 'redis' 47 | ELASTICACHE_PARSER='elasticache' 48 | LOCAL_PARSER='local' 49 | ARGS_NUM = 5 50 | CONFIG_DEFAULT_STRING = '{"shards": 3, "replicas": 1, "auth": "False", "ip": "127.0.0.1", "start_port": 6379}' 51 | CLUSTER_SHUTDOWN_CMD = 'ps -ef | grep redis-server | awk \'{print $2}\' | xargs kill -9' -------------------------------------------------------------------------------- /dev/redis-cluster/delete_cluster.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import logging 3 | import boto3 4 | from cluster_location import ClusterLocation 5 | from cluster_shutdown_by_rediscli import shutdown_cluster 6 | from cluster_start import ArgumentRequirementState 7 | from constants import ARG_KEYWORD_REPLICATIONGROUPID, ARG_KEYWORD_RETAINPRIMARYCLUSTER, ARG_PREFIX 8 | from utils import add_cli_args_to_arg_parser 9 | 10 | logging.basicConfig(level=logging.INFO) 11 | 12 | def delete_elasticache_cluster(args): 13 | client = boto3.client('elasticache') 14 | response = client.delete_replication_group( 15 | ReplicationGroupId=args.replicationgroupid, 16 | RetainPrimaryCluster=args.retainprimarycluster, 17 | ) 18 | logging.info(response) 19 | 20 | def get_args_for_elasticache_cluster(elasticache_parser, main_parser): 21 | ec_cli_arguments = [ 22 | ((ARG_PREFIX+ARG_KEYWORD_REPLICATIONGROUPID,), {'type':str, 'required':ArgumentRequirementState.REQUIRED.value}), 23 | ((ARG_PREFIX+ARG_KEYWORD_RETAINPRIMARYCLUSTER,), {'action':argparse.BooleanOptionalAction, 'required':ArgumentRequirementState.REQUIRED.value}), 24 | ] 25 | 26 | # Arguments provided from command line are added to Argument Parser. 27 | elasticache_parser = add_cli_args_to_arg_parser(elasticache_parser, ec_cli_arguments) 28 | return main_parser 29 | 30 | def get_delete_cluster_args(): 31 | '''Reads arguments from command line''' 32 | parser = argparse.ArgumentParser() 33 | subparser = parser.add_subparsers(dest='location') 34 | local = subparser.add_parser('local') 35 | elasticache = subparser.add_parser('elasticache') 36 | parser = get_args_for_elasticache_cluster(elasticache, parser) 37 | args = parser.parse_args() 38 | return args 39 | 40 | if __name__ == '__main__': 41 | args = get_delete_cluster_args() 42 | if args.location == ClusterLocation.LOCAL.value: 43 | shutdown_cluster() 44 | elif args.location == ClusterLocation.ELASTICACHE.value: 45 | delete_elasticache_cluster(args) 46 | else: 47 | print("Insufficient Arguments: Please mention which cluster to delete.") 48 | -------------------------------------------------------------------------------- /dev/redis-cluster/node_details.py: -------------------------------------------------------------------------------- 1 | from subprocess import PIPE 2 | from utils import run_subprocess 3 | from constants import REDIS_CLI_CMD 4 | 5 | 6 | class Node: 7 | 8 | def __init__(self, node_details, password): 9 | self.port_number = self.get_curr_node(node_details) 10 | self.node_id = self.get_node_id(node_details) 11 | self.ip = self.get_node_ip(node_details) 12 | self.role = self.get_node_role(node_details, password) 13 | self.status = self.get_status_of_node(node_details) 14 | 15 | def get_curr_node(self, node_details): 16 | try: 17 | ip_address = node_details[1].split(':') 18 | return ip_address[1].split('@')[0] 19 | except IndexError as e: 20 | print(e) 21 | return None 22 | except Exception as e: 23 | print(e) 24 | return None 25 | 26 | def get_node_id(self, node_details): 27 | try: 28 | return node_details[0] 29 | except IndexError as e: 30 | print(e) 31 | return None 32 | except Exception as e: 33 | print(e) 34 | return None 35 | 36 | def get_node_ip(self, node_details): 37 | try: 38 | ip_port = node_details[1].split(':') 39 | return ip_port[0] 40 | except IndexError as e: 41 | print(e) 42 | return None 43 | except Exception as e: 44 | print(e) 45 | return None 46 | 47 | def get_node_role(self, node_details, password): 48 | try: 49 | status_of_node = node_details[7] 50 | if status_of_node == "connected": 51 | if password: 52 | cmd = REDIS_CLI_CMD + self.get_curr_node( 53 | node_details) + ' -a ' + password + " --no-auth-warning info | grep ^role" 54 | ps = run_subprocess([cmd], PIPE) 55 | else: 56 | cmd = REDIS_CLI_CMD + self.get_curr_node(node_details) + " info | grep ^role" 57 | ps = run_subprocess([cmd], PIPE) 58 | node_role = ps.communicate()[0].decode("utf-8").splitlines() 59 | node_role = node_role[0].split(':')[1] 60 | else: 61 | node_role = node_details[2].split(',')[0] 62 | return node_role 63 | 64 | except IndexError as e: 65 | print(e) 66 | return None 67 | except Exception as e: 68 | print(e) 69 | return None 70 | 71 | def get_status_of_node(self, node_details): 72 | try: 73 | return node_details[7] 74 | except IndexError as e: 75 | print(e) 76 | return None 77 | except Exception as e: 78 | print(e) 79 | return None 80 | 81 | 82 | class NodeDetailsFromOuput: 83 | def get_details(self, cluster_info_output, total_nodes, password): 84 | cluster_info_output = cluster_info_output.decode("utf-8").splitlines() 85 | node_info_list = [] 86 | for nodes in range(total_nodes): 87 | node_details = cluster_info_output[nodes].split(' ') 88 | node_info = Node(node_details, password) 89 | node_info_list.append(node_info) 90 | return node_info_list 91 | -------------------------------------------------------------------------------- /dev/redis-cluster/primary_node_failure.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #Get start port From cluster Information 4 | startPort=`cat cluster_information.json |jq '.start_port'` 5 | 6 | #Get Password From cluster Information 7 | password=`cat cluster_information.json |jq '.password'` 8 | password="${password#?}" 9 | password="${password%?}" 10 | 11 | #Show the cluster Nodes 12 | if [ ! -z "$password" -a "$password" != " " ] ;then 13 | redis-cli -p $startPort -a $password cluster nodes 14 | #Master Node Ports 15 | echo "Primary Node Ports :" 16 | redis-cli -p $startPort -a $password --no-auth-warning cluster nodes |grep master|cut -d ':' -f2|cut -d'-' -f1|cut -d '@' -f2|cut -c 2- 17 | 18 | else 19 | redis-cli -p $startPort cluster nodes 20 | echo "Primary Nodes Ports :" 21 | #Master Node Ports 22 | redis-cli -p $startPort cluster nodes |grep master|cut -d ':' -f2|cut -d'-' -f1|cut -d '@' -f2|cut -c 2- 23 | 24 | fi 25 | 26 | #Enter the Node Port for process id check 27 | echo "Enter the port for failover" 28 | read port_number 29 | 30 | #process Id for the particular port 31 | process_id=$(ps -ef |grep redis-server |grep $port_number |awk '{print $2}') 32 | 33 | 34 | if [ ! -z "$process_id" ] 35 | then 36 | #Kill the process by process id 37 | kill -9 $process_id 38 | if [ ! -z "$password" -a "$password" != " " ]; then 39 | #Show the cluster Nodes 40 | redis-cli -p $startPort -a $password --no-auth-warning cluster nodes 41 | 42 | else 43 | #Show the cluster Nodes 44 | redis-cli -p $startPort cluster nodes 45 | fi 46 | else 47 | echo "This Node is a failed node or is not a master node " 48 | fi 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /dev/redis-cluster/slave_node_failure.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #Get start port From cluster Information 4 | startPort=`cat cluster_information.json |jq '.start_port'` 5 | 6 | #Get Password From cluster Information 7 | password=`cat cluster_information.json |jq '.password'` 8 | password="${password#?}" 9 | password="${password%?}" 10 | 11 | #Show Cluster Nodes 12 | if [ ! -z "$password" -a "$password" != " " ] ;then 13 | redis-cli -p $startPort -a $password cluster nodes 14 | echo "Replica Node Ports :" 15 | #Replica Node Ports 16 | redis-cli -p $startPort -a $password --no-auth-warning cluster nodes |grep slave|cut -d ':' -f2|cut -d'-' -f1|cut -d '@' -f2|cut -c 2- 17 | 18 | else 19 | redis-cli -p $startPort cluster nodes 20 | echo "Replica Node Ports :" 21 | #Replica Node Ports 22 | redis-cli -p $startPort cluster nodes |grep slave|cut -d ':' -f2|cut -d'-' -f1|cut -d '@' -f2|cut -c 2- 23 | 24 | fi 25 | 26 | #Enter Replica Port Number for Failover 27 | echo "Enter the port for failover" 28 | read port_number 29 | 30 | #Process Id of the particular Port 31 | process_id=$(ps -ef |grep redis-server |grep $port_number |awk '{print $2}') 32 | 33 | #Show the cluster Nodes 34 | if [ ! -z "$process_id" ] 35 | then 36 | kill -9 $process_id 37 | if [ ! -z "$password" -a "$password" != " " ]; then 38 | #Show Cluster Nodes 39 | redis-cli -p $startPort -a $password --no-auth-warning cluster nodes 40 | 41 | else 42 | #Show Cluster Nodes 43 | redis-cli -p $startPort cluster nodes 44 | fi 45 | else 46 | echo "This Node is a failed node or is not a slave node " 47 | fi 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /dev/redis-cluster/test/README.md: -------------------------------------------------------------------------------- 1 | # Run Tests 2 | To run all tests: 3 | ``` 4 | python3 -m unittest discover 5 | ``` 6 | 7 | To run a specific test module: 8 | ``` 9 | python3 -m unittest test. 10 | ``` 11 | 12 | To run a specific test case: 13 | ``` 14 | python3 -m unittest test.. 15 | ``` 16 | -------------------------------------------------------------------------------- /dev/redis-cluster/test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/slact/nchan/9c6909d0a4c4611479b7182ac29b2065a5845614/dev/redis-cluster/test/__init__.py -------------------------------------------------------------------------------- /dev/redis-cluster/test/test_cluster_info.py: -------------------------------------------------------------------------------- 1 | import time 2 | import unittest 3 | import os 4 | import pathlib 5 | from cluster_info import get_cluster_info 6 | 7 | 8 | class TestClusterInfo(unittest.TestCase): 9 | def test_info(self): 10 | file_path = str(pathlib.Path().resolve()) + "/cluster_info.txt" 11 | self.assertFalse(os.path.exists(file_path)) 12 | get_cluster_info() 13 | time.sleep(10) 14 | self.assertTrue(os.path.exists(file_path)) 15 | 16 | 17 | if __name__ == '__main__': 18 | unittest.main() -------------------------------------------------------------------------------- /dev/redis-cluster/utils.py: -------------------------------------------------------------------------------- 1 | import pathlib 2 | import os 3 | import shutil 4 | import uuid 5 | import subprocess 6 | import json 7 | 8 | from constants import READING_MODE 9 | 10 | 11 | def get_current_path(): 12 | return str(pathlib.Path().resolve()) 13 | 14 | 15 | def is_directory_present(path): 16 | return os.path.exists(path) and os.path.isdir(path) 17 | 18 | 19 | def remove_directory(path): 20 | shutil.rmtree(path) 21 | 22 | 23 | def create_directory(path): 24 | os.mkdir(path) 25 | 26 | 27 | def change_directory(path): 28 | os.chdir(path) 29 | 30 | def is_file_present(path): 31 | return os.path.exists(path) 32 | 33 | 34 | def remove_file(path): 35 | os.remove(path) 36 | 37 | 38 | def join_path_components(path1, path2): 39 | return os.path.join(path1, path2) 40 | 41 | 42 | def generate_password(): 43 | ''' 44 | Returns a randomly generated password i.e. a random 45 | UUID as a 32-character lowercase hexadecimal string 46 | ''' 47 | return uuid.uuid4().hex 48 | 49 | 50 | def open_file(file_path, mode): 51 | return open(file_path, mode) 52 | 53 | 54 | def write_on_file(file, data): 55 | file.write(data + "\n") 56 | 57 | def close_file(file): 58 | file.close() 59 | 60 | 61 | def load_json(file): 62 | return json.load(file) 63 | 64 | 65 | 66 | def dump_json(list): 67 | return json.dumps(list,indent=4) 68 | 69 | 70 | def run_subprocess(cmd_, stdout=None, stderr=None): 71 | return subprocess.Popen(cmd_, stdout = stdout, stderr = stderr, shell=True) 72 | 73 | 74 | def get_cluster_configuration(path,mode): 75 | file=open_file(get_current_path()+path,mode) 76 | config_list=load_json(file) 77 | return config_list 78 | 79 | 80 | 81 | def load_json(json_str): 82 | ''' 83 | Converts and returns JSON as python dict from given JSON string 84 | ''' 85 | try: 86 | return json.loads(json_str) 87 | except ValueError as e: 88 | print(e) 89 | return None 90 | 91 | def read_json_file(file_path): 92 | ''' 93 | Returns JSON as python dict after reading from given JSON file 94 | ''' 95 | try: 96 | with open(file_path, READING_MODE) as file: 97 | return load_json(file.read()) 98 | except FileNotFoundError: 99 | print('WARNING: The file `{}` could not be found.'.format(file_path)) 100 | return None 101 | except OSError as e: 102 | print(e) 103 | 104 | 105 | def str2bool(bool_str): 106 | ''' 107 | Converts string value to boolean value 108 | ''' 109 | return bool_str.lower() in ("yes", "true", "t", "1", "y") 110 | 111 | def add_cli_args_to_arg_parser(parser, cli_args): 112 | ''' 113 | Arguments provided from command line are added to Argument Parser 114 | ''' 115 | for arg, options in cli_args: 116 | parser.add_argument(*arg, **options) 117 | return parser 118 | 119 | def get_cluster_info_using_args(args): 120 | if args.auth: 121 | cmd = REDIS_CLI_CMD + str(args.start_port) + ' -a ' + str(args.password) + ' cluster nodes' 122 | cluster_info = subprocess.check_output([cmd]) 123 | else: 124 | cluster_info = subprocess.check_output([CLUSTER_NODES_INFO]) 125 | 126 | return cluster_info 127 | -------------------------------------------------------------------------------- /dev/redis-tls/ca.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIFSzCCAzOgAwIBAgIUJJs4Yqn7zGblATVU6EM8FvZsOAwwDQYJKoZIhvcNAQEL 3 | BQAwNTETMBEGA1UECgwKUmVkaXMgVGVzdDEeMBwGA1UEAwwVQ2VydGlmaWNhdGUg 4 | QXV0aG9yaXR5MB4XDTIxMTIwMzIwNTU1NFoXDTMxMTIwMTIwNTU1NFowNTETMBEG 5 | A1UECgwKUmVkaXMgVGVzdDEeMBwGA1UEAwwVQ2VydGlmaWNhdGUgQXV0aG9yaXR5 6 | MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtiVJte4fxuxiBHZVN/ad 7 | qVs1mODhQwrjJnhaGlvLJHxUcF0jt2p+X+vHJA0LaNCAiJ8YI3WAJRhezxE1LdGz 8 | 4MjE4h5LfUEvhBsdhaTNQMrXw2qcXv0fr2B+dMEkFz8NhO6WP7PY9zWxbQAeOs+0 9 | pwguJ8Jo1ZGkEQAL9L6gAzrIoV/bIrWtfgeq0zn/vvAM325KEbHJfWPecRKb/7bd 10 | 1UOur/Ce0J1vErgsm9bwg5PwWGQQMRtjiEhQekyrobcV9reOZo6HcDuNpc469ERV 11 | 9yCrxh6LDkBrNlLkO2drwJ2Z3F5pMXkP5BR0/YbLqYdxJjFmUnMg/kPkvdFUg9ag 12 | MMJRp8XCDgLx3tc5izNOI/h6we+YEn2whMv4ZcVSqMbLTvhipAGO/9aZRD8KyXzg 13 | YqreCMaWjAK/4Ah71HgGYwSzRvGNnq2qjiPHhW/t2y/7knQ8NJ3dh9ZXJvKbGQ/K 14 | yrEaYS/YQpK8jMEK5t+1dwKhCPApm61nE56Bs68g+rFYDLEEBQX/eM68M73LRudW 15 | jRHn0am875iGRZ+/zUZB71ecKyFUG+gIvhSjTUVl8TIRe0zSeqBGu7UqL50MWsqR 16 | QQVMDCvllMqtROwpsgZD4zgNnLmAAz74SzLw1gyU6NC0/NA9Q4qQjfmkVW2hurSD 17 | OxEJwxjoOKeCxgMy3jvYnI8CAwEAAaNTMFEwHQYDVR0OBBYEFFBOMjFFFm3MvQVV 18 | qfafmN37O5mEMB8GA1UdIwQYMBaAFFBOMjFFFm3MvQVVqfafmN37O5mEMA8GA1Ud 19 | EwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIBAI5SZhCkk+mglnn9qacEYcON 20 | nl4+mejZZZ1p7BMsqjJgMdqSY7+OCpWbFzZdcGmJDeUNqK+57Y06WeAQf8E/vCah 21 | L8jsRK6rnz9B1zFKYMm8u1go0bS9r1dKZWZIv+BiWEOORa+OgYkGoGxJaqa6p6Bi 22 | lOC2/xwgGSpV9kUNLzSMgbvdDNXsiiYOnMaJrHFkwuKjwSJVaCriYE0+uR2iyLx6 23 | EBexy71zvVi9ig6mGP4T/GTfPGNhKcw0zzgwhH2JMdXIcr0EvTZjQWLGXjDiZ6ao 24 | En7JEu/hrd1k45epAmbIfGv1JUKo9WtfZZE7wHCeTdB/AFRW33TOwTeOWSsW7t7/ 25 | 5D4wRMai1xcM6aLybUb9ceqAzcZ/0BEovEtqI7Q15t3T2HQ3NEXX4IhLcmcSaFYn 26 | X06zgH6t/pwoLP4C/c15lrwCv17gwzS7T5g5lYtNK5mCG0psNbvaKHRjYFkHvaXa 27 | lGolYQPHHNtsWrVI8Pwmr2JTuvIWXKN/uuPksVU9/TjzyWZZbbYtCoF38U/nbtfu 28 | ajDOGs6LDs4NOa2ZBaw87sxO4Yy0VLhq1nHDT7XkRoqvNVdbwQIEVXL0eVw9qWvZ 29 | u/WaRtZoLiEwuN4LukYNB9t6FoWTO6N+c7Ul/Pi69dTPHGQyZGFxh5+erUM7nWCP 30 | dM/3W6fZSi4WcdxPioey 31 | -----END CERTIFICATE----- 32 | -------------------------------------------------------------------------------- /dev/redis-tls/ca.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIJKQIBAAKCAgEAtiVJte4fxuxiBHZVN/adqVs1mODhQwrjJnhaGlvLJHxUcF0j 3 | t2p+X+vHJA0LaNCAiJ8YI3WAJRhezxE1LdGz4MjE4h5LfUEvhBsdhaTNQMrXw2qc 4 | Xv0fr2B+dMEkFz8NhO6WP7PY9zWxbQAeOs+0pwguJ8Jo1ZGkEQAL9L6gAzrIoV/b 5 | IrWtfgeq0zn/vvAM325KEbHJfWPecRKb/7bd1UOur/Ce0J1vErgsm9bwg5PwWGQQ 6 | MRtjiEhQekyrobcV9reOZo6HcDuNpc469ERV9yCrxh6LDkBrNlLkO2drwJ2Z3F5p 7 | MXkP5BR0/YbLqYdxJjFmUnMg/kPkvdFUg9agMMJRp8XCDgLx3tc5izNOI/h6we+Y 8 | En2whMv4ZcVSqMbLTvhipAGO/9aZRD8KyXzgYqreCMaWjAK/4Ah71HgGYwSzRvGN 9 | nq2qjiPHhW/t2y/7knQ8NJ3dh9ZXJvKbGQ/KyrEaYS/YQpK8jMEK5t+1dwKhCPAp 10 | m61nE56Bs68g+rFYDLEEBQX/eM68M73LRudWjRHn0am875iGRZ+/zUZB71ecKyFU 11 | G+gIvhSjTUVl8TIRe0zSeqBGu7UqL50MWsqRQQVMDCvllMqtROwpsgZD4zgNnLmA 12 | Az74SzLw1gyU6NC0/NA9Q4qQjfmkVW2hurSDOxEJwxjoOKeCxgMy3jvYnI8CAwEA 13 | AQKCAgAx/xg1hPBaBOZ+vRB1NQ9fvjZ/CTMr2OAy3hQ1af7fu/TdhuNX5DZeE/Ts 14 | k1wPYDP3zFuu2ADdrcvQYLPNKOOMDu/j9VbZQbxOMbcvyOXCJCuHa0sS074PwJfV 15 | anKCov8N/wNk5vPmH2ndNowVro+yzY8FwNpPzRNQy0d83ZpEaK1Lhmk7JM1Da81a 16 | /2+QtImEBtzz8G4TKgeT1/zT+xj3AgYAKzccoior5DvyZtRL+Z6eVJEROahfbyIP 17 | /92YnQ29U/MVeYf5qY8e9PW/uMYz+FbOIfIfblU/aw9UsvWjwF7MW2nad5WCEI9w 18 | S8C5fwDy79pbRVjIElDGPaBKM+5yHRKKK8WDmDnxz5MuRmu0/OyDydXFd1pc045N 19 | 768l4y0hdBYfwGbxzsv4TSRPCqsmXW6KpGAG1vSsbsj6gt5EeGqwE5lSzeC8Z05+ 20 | gOOnjmMrXq8v00Gj/+moBaETiHopGvrTLeOQ7Wl1Jz+LmPUGgZVOmz08hFnXyCBO 21 | J3QhXL5TQmmycI9I/vrmXu4hOvmCwJrY3aQRsP/wR1YdO8sEjqNWQW0XfjYg9pD+ 22 | W/eTNPhUcspEjfgMCRr+ftXFe1Z0apKZN4QUqyP9+GnJ4m3SRbcjdu7QIj7NeyjL 23 | jgOlqa59+91RYXj4EB8z82YwCrRrd9YpbjzYxRjvb4TMTFMc8QKCAQEA5T+PKyqZ 24 | Pub/eI3Q2C0y7SKCuUB8j2+QrnKE5IT8tprbpsvRYADqh/MfcYSDHdSZncQRQm50 25 | hIJ1yt6XD6u5lD8UXbwT7sMBr1D43WP94gFjg++3/GB0fac1tcfth80kkRSgaacY 26 | b0NBX767AOQ6A5veVyNfWsogRFGLkLtb6g1SPKcI5U7Moba3EOI0Xz8hVmqbjCtZ 27 | TMVzKY5WDlKzjrEOpqj770AInGei2msydBu7vQZMoYceRHqtaFkyH+tHyOnXF/ed 28 | TFNjK4wTz4t7K0uDXjbKmSbINXLDZuHEqJmwHL2BQEe3Mqcu+pRnOKHGf+Yz5kRx 29 | hXxnpDDZIJ6ZFwKCAQEAy2acLbN8XmlsF4t39c4GxBVWVSE/a02hej/w0SJLllRj 30 | iJVb+vyGwoGN/wZzPd78Zvw5It1RyID2sX2g+CWBK5aWMJSkYxCO40fcNAO3rW2O 31 | juxDrCBtu71HEw5EzCWkzLORNEzf8/51l9lUfhS29fGKDQ0geoo4h3vgHRy0IGyy 32 | j2NrWlfvU+qADPKiHr5hwT59MSbAOB6rytjtUnxe7QYUkfWjniNxVhuiCVPtguTd 33 | TXinS8zkc0ZyikCYb0cgxNug52WTNIL+Tt8TdY3U7+ummPHUCMf3dOLNqJJQqpLQ 34 | zT0OHZDlj9rAxnF6H1SYYe0NF9MjZItc+/i60bfTSQKCAQEA1lROLjVtgPnG75bn 35 | IrVfX4VcYoZ/7jqIMhCvXldXTgIKSi9UWUWCAAi15RPW4hTaaj3dRRavqROvvTPO 36 | V8BdiNRQ3jHxENEQyjAR/Cp4OszBlaCRi0tCnheuh32b/dM11M5MC3tFxQBEJpfT 37 | jknSU31uqllP1ToUYMs8iNwiWviJYltoXbsGZkrFbOuPu1zydjDFrI76tmQD/14r 38 | 5sg7R7UR1Y83u79KTbA2+a4vRY6IP3mcO4hwK+XmKiD6VA1M1/KIPsgqMCnmFdio 39 | zOnDBf9bmsHvOLChjhb1yUJa8qZ9mOEz7j0eciUMLwqAVtopE3rOGwLyf7KH02I4 40 | Hd8pkQKCAQB/upEK9fJ8y1EQvAl594YyLoAHd5h+xsJHpc2RVysGXTof9ENNqrTp 41 | gjfsVV2bFeOEvJEYvsjz02CXdx/VlJ+4ApmQKlfMygIg4eh7VXZL10e1otKgTcD7 42 | K1JtugEj/eOulHjz0e61Jy8rS1QO1O1MJwEdTwf9S71R/01umq7Wycub1b/9fMkS 43 | 9mixONDr43w5wQcXDZGZ7FDPUkg+C1IFIFNckVfNH861Vyb7GpRFJXl/g+vy4tj3 44 | Nt8IyKWxA4aleJJjnVrCmBwg5V8v7AAzJdV5qCsR1Jkl8qNZX4B+jTHIILYzhOFT 45 | 4/g45dvdvt7uZ9FYC8PnCMk8hiazOe/ZAoIBAQCxgHolzZKGA6LXe7yDn9IT+Yx1 46 | 4tRF/lFiSKCkr1Kd/Lhqy7Pc22sn8/x1ZY5DpIXkPH9H0+W3krEPtjq0LOW4M/yr 47 | hUN0u9/lWNjx+8sH97QTZZTMawL/DkQ+E09voxyXeDq2R00lVZn7qgQW2OgbjLak 48 | mFaKGeekihIz8lus6BpoymUCql3uhNqpAHQl7jDkdVSMZnVDoXe+tElkXrvDw+HL 49 | K7v57ybLtu5Gru4v6JkYyJzzUiinr67JmghEtGlsUTaiVyLII90Sp9oKgoh1Fs2h 50 | rukek57GtvaUwIDnAVS5Arvl0Sw0ONhdPSOieYU2x1WrSk5qazSqoh0WOi7L 51 | -----END RSA PRIVATE KEY----- 52 | -------------------------------------------------------------------------------- /dev/redis-tls/ca.txt: -------------------------------------------------------------------------------- 1 | 6DEF4546CBFC2E6DF63227E69FC3CF9C449B20E6 2 | -------------------------------------------------------------------------------- /dev/redis-tls/client.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIEEDCCAfigAwIBAgIUbe9FRsv8Lm32Mifmn8PPnESbIOUwDQYJKoZIhvcNAQEL 3 | BQAwNTETMBEGA1UECgwKUmVkaXMgVGVzdDEeMBwGA1UEAwwVQ2VydGlmaWNhdGUg 4 | QXV0aG9yaXR5MB4XDTIxMTIwMzIwNTU1NVoXDTIyMTIwMzIwNTU1NVowKzETMBEG 5 | A1UECgwKUmVkaXMgVGVzdDEUMBIGA1UEAwwLQ2xpZW50LW9ubHkwggEiMA0GCSqG 6 | SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDqg0EJhkdWexWd+3XbXLj+XzLToZYZX27G 7 | euucD4nJ1stOIX/gB21dhOPYYkiYmMp6CKtL8ueTmiun2b4SodyKJALwRt2KnWNk 8 | zMYbmwvI7oE9csymZs9F3LotS8T3w7ADmCdpjMpUZ2VHa9ns4dEMdCTWC5yONF3a 9 | cOcyqGB2RO637Aq57PEkSzuxNTidAk8XVbTCnBLy+DRXqEdETAHiI376AqD2ep5Q 10 | rcU4JSrnrfjE//gR2sUoNPcRM24QLCyY/M5LOQ24KKB5mhrnZPpId11v1rwaOffB 11 | R76889p4aauLdclzx9RggttXSkrg19F+MOSK793hdCcmv/1hfZ0HAgMBAAGjIjAg 12 | MAsGA1UdDwQEAwIFoDARBglghkgBhvhCAQEEBAMCB4AwDQYJKoZIhvcNAQELBQAD 13 | ggIBAKjdT8eO5ZFgGT5/aBlLbGlPmp6Pps2+rKx6y89B5rdbGOIdN3998Z8A7bkO 14 | 1vupiAjM7cBxPrVRvyzKhE/ks9Bvp7VMfF7H+9BJ503p4Ue8DV97moQKHcyxB34b 15 | yw4/6XLZH714OIUjuqInhSJlVfuzC+ih6l+wTCsIsUIjsTDetP7zEKI2OXR9t9kj 16 | y28jNgS7JYkUG8QrXEXWo2IIE8SyUQpATLVt1TaODibpf5LrU9rNrpYLSRl3j0Ts 17 | /UUuINtNyvkEJtNUpATx+M2TJg8nHGxQM5ItftmEkXoMCRFU3s8TaqkW+t4JDlyP 18 | 6G+nk9nMHLL+7nDwBCbUL7ekG81C4CwJu7YeKKibrVyvaJJYPusgpzyoHL7ty28/ 19 | KcbxLBaPWl9TaDV/mB5O8miavtv5UOnmFfoz94SgBfn9vhZTIxbESCjpaNk/pfOO 20 | zBZHcscmxXkcGfkaue8Ki0Ju+bk+2coJAKtBZINyLVqYYuMJvrFu5JehE+Dix2QV 21 | XZ0BBgQYTQ/L5ObIjGxK+KPxMIVoMb6cEUZ6yGetKXo7Ge+cWD91cY1Lo0uevEgx 22 | VRVoc2pmtdPiwHiksKDDYg3v7msyTy28oHh/nphHW2WIGHi9s90fIV3hwwBNuYLS 23 | R8HM19cUTnUkw+Ets1cbq9POnpP5QnnQzdaG3SMnKJ/muCRE 24 | -----END CERTIFICATE----- 25 | -------------------------------------------------------------------------------- /dev/redis-tls/client.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEowIBAAKCAQEA6oNBCYZHVnsVnft121y4/l8y06GWGV9uxnrrnA+JydbLTiF/ 3 | 4AdtXYTj2GJImJjKegirS/Lnk5orp9m+EqHciiQC8Ebdip1jZMzGG5sLyO6BPXLM 4 | pmbPRdy6LUvE98OwA5gnaYzKVGdlR2vZ7OHRDHQk1gucjjRd2nDnMqhgdkTut+wK 5 | uezxJEs7sTU4nQJPF1W0wpwS8vg0V6hHREwB4iN++gKg9nqeUK3FOCUq5634xP/4 6 | EdrFKDT3ETNuECwsmPzOSzkNuCigeZoa52T6SHddb9a8Gjn3wUe+vPPaeGmri3XJ 7 | c8fUYILbV0pK4NfRfjDkiu/d4XQnJr/9YX2dBwIDAQABAoIBAHSyQ9bdfvpF3Yfz 8 | 7b3u8g+Ch+RP8EVH+/PAjyXlhYdu31RNzzhH+eAjlM3EeqOUxIzda4Arq5kDit3H 9 | uJHFAd2r9dpjKTMlBqTOUXbDPKYMKTvOuI/FcTcuk2ae4bD5K8leGZ6odLZzjS5x 10 | OMxrwn8T/JCWzpzk6h8dN685oma3Crclbfb2+zlBgkm1yTDXUc6iAaCzzu3xOWM5 11 | utWtMjU/SeVLoC5q0OzC3Uutu79g9pSSaCIuRrt5UK835EQcKyACkhSUc43Bbn3e 12 | lg6aMTv5VYTPHojANrjOUh5C7hz7amniT3DboEKyQdnHKxklIErcItZChnGrK0Lc 13 | IXWoXSECgYEA+ucj9YFau97rAKDf3R65PeqwCldB0rqmsFqDSE78ntT+3fRinyKE 14 | XJrdOx9duSl4TgFYRfTw6Nxnb24uFp/WPD98thl8L2LMbnPA+tvh8WBqTE2RPIxJ 15 | U/P8ckQ4Jy1U79MwjeBz/GCBoH4YhTfpwKzH6g7+vh8NLMWHoHifRAsCgYEA70bf 16 | t83uWTCtijJWp0Visx4cUoLL84dZhxgHhuw0Oi5yOU4NO/7Ebk0BOVE+M6BHxOhy 17 | j/IY27+imwGPaL1rA5CPzypu5wuQSQND0jpLjZ11BNcAfMLLj6q3EfhFCezW0Xgt 18 | rDZESs9I0QAfLT6L9mE3YqYZx+bwR9uWt0NpDHUCgYEAybUu/H0cw7KnvN6Yenzr 19 | sXJOSlHx8gbqYRazOlt9zfcwWqHQ81xditFZj+FciLJlLFj6bWtIjfw7D6NFXBzt 20 | r4vep8r/Ql0sOpPGjiZdk57Odj9ZxpKFlP+ucPKVLjHMee2PuE+9DyVKsQsOjXLw 21 | 8lw1b97UP2ZZQigfLAwtBhcCgYB/E88BGTd62uVvvehTkgAnTNiR4bFbtwiPPO3S 22 | dGQQelZjpNZWhKniQrdhr4ovdPJo22LsnBEjtBUx6ZQ2dlL9Y6tcxRZ9UqDghgFh 23 | B2DU50kctuslV3cw5+OugYJ5EPXN7duj2HZQnOH5Te1A5DUFNwBpPfn3Nulp4G+d 24 | CQojeQKBgBrX7RuhBjuZprgrm0XYCUrfMAd0WIwcpqUyvlyqC9PWRI8cpvgoFHZs 25 | r8N7Wdxu9ilzD96VibXMxwYmrJLbQNE9mqJUL1/fnUscoUje03T4zfvK6WY8Nq7L 26 | vZOKDy57ZdOfX5JqC3dwTFJaYH54JzzbvyCN62Z5KcZUqMVd6f5v 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /dev/redis-tls/openssl.cnf: -------------------------------------------------------------------------------- 1 | [ server_cert ] 2 | keyUsage = digitalSignature, keyEncipherment 3 | nsCertType = server 4 | 5 | [ client_cert ] 6 | keyUsage = digitalSignature, keyEncipherment 7 | nsCertType = client 8 | -------------------------------------------------------------------------------- /dev/redis-tls/redis.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIID6DCCAdACFG3vRUbL/C5t9jIn5p/Dz5xEmyDmMA0GCSqGSIb3DQEBCwUAMDUx 3 | EzARBgNVBAoMClJlZGlzIFRlc3QxHjAcBgNVBAMMFUNlcnRpZmljYXRlIEF1dGhv 4 | cml0eTAeFw0yMTEyMDMyMDU1NTVaFw0yMjEyMDMyMDU1NTVaMCwxEzARBgNVBAoM 5 | ClJlZGlzIFRlc3QxFTATBgNVBAMMDEdlbmVyaWMtY2VydDCCASIwDQYJKoZIhvcN 6 | AQEBBQADggEPADCCAQoCggEBANpStsjya6MBTnZiK4uoOTLvAXZ9NdLb5J5yX5ng 7 | EwgCdGykg+nhfFQymV3JnPL7ZvORYmpWJ0rtpoVmoOCgKgU9didtMdxxPfvxTpxC 8 | aUmryBxA1BMV/cESa2uLmWV9sXoK6aXnP3/vPuNBNlPL6cQGi/PZQBtFtQjXPZ52 9 | rTtJKZOJZNPFSzmGkhnqXJ7XQMe47hKXhw4Mw9pVAo2veY6k2xHtr1qt4iT3+G9F 10 | /mvrMni/MKWPG8JHNJoYLUeUK4pqWoS03vRn4grFIEW/OaiIDU/S4d5MqNm/y9ze 11 | 5yPgFm3HKYSw6H23TMNwHC5ncooqJIHgso58zqV5yrk5/6ECAwEAATANBgkqhkiG 12 | 9w0BAQsFAAOCAgEAGVznut7gJ4cfQ0L4Ma4nnS7zbJMonSdcjCGR81UC7M1BYEVl 13 | JGOo9GQ8efKNTRMZWFaiPutKebGxYkSoQ6OVj4DKNTjmsWGBwfgc3fipvYVxHeRh 14 | KzgPRTexFGidDk0dPbe4ZUe7QxiJmijbWKWSRQowds+09ve1sTuQ/USmflsu/weT 15 | 6+VMwYJHuALmDgo9f11zu1GjnH3r8rVpoDFxvHqZLHmtXT+9AaHyz3jTe1cTsU1U 16 | T//8YPKeajG1NRBkQpvgXzJkLrzJQjfdOEB8b6I4qkaoSWnojlnvBN1LrCPw1teV 17 | eWXYMflBBQivVyqphWEOdfEAvvGVv4AryZWaX1WMn7J4ysXCGJRNjDT+6olVC1gE 18 | d2+oMDmHa8ynyivxUAWDN2oGkoS3x83GGImWp0rCHGuMbSygQC+lCW9cVeEpQvfv 19 | MjCNqE46NyQAqoUhJLklpv/VxNGKvsYqIV9WiC7qnB8VphPj2QzMFltkpTHCYH4Z 20 | qEOnLU9n81XxByQ6Gu2IAML4RvIjB5e5bOwzNkeJFyTnj2xmTufIJuw2BTiPhty2 21 | 3ISVl0HKgoyiFFZ5RnSjNRj1DFw6ArfuQ/JyD5vLz/jzaO9A1eBCNqz8xZIFQOjP 22 | 5BoaOmFcYp/fpZM/pXZP6PJydHgr4yhCA9qbnZSq3zOeL03cSFGDkZ0VT5c= 23 | -----END CERTIFICATE----- 24 | -------------------------------------------------------------------------------- /dev/redis-tls/redis.dh: -------------------------------------------------------------------------------- 1 | -----BEGIN DH PARAMETERS----- 2 | MIIBCAKCAQEA/GPDt9rRib3B5+z52OKA3x2ui79r7SrNzbwaFduuQWBinVIWy1os 3 | HEYES8jwZfWrwuQTCMGCfZXb+o4LE7sWsRjfallIE8qwu3f27SCNu39ZgsHvuXf5 4 | nLYn0Aa+gQyLfp2SF3BTCCF03uzymn41YCgZi0Z5aY3GOc537kerSLDMw2oopZCI 5 | 90htt+2PSOBcGdW2ltSQWpBwYRDAaJWMGn9NUoaTAjWSSu1uN5k0qzNj1KL7Y9et 6 | YcakLLfal8zdbC519Bty7j4wS09XQf611O/a8wyyy+0/IuNFNAyER0psp76mNZnf 7 | IQeuzmjbK/iSHAHQizRVod9LyVOPf4AEawIBAg== 8 | -----END DH PARAMETERS----- 9 | -------------------------------------------------------------------------------- /dev/redis-tls/redis.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpQIBAAKCAQEA2lK2yPJrowFOdmIri6g5Mu8Bdn010tvknnJfmeATCAJ0bKSD 3 | 6eF8VDKZXcmc8vtm85FialYnSu2mhWag4KAqBT12J20x3HE9+/FOnEJpSavIHEDU 4 | ExX9wRJra4uZZX2xegrppec/f+8+40E2U8vpxAaL89lAG0W1CNc9nnatO0kpk4lk 5 | 08VLOYaSGepcntdAx7juEpeHDgzD2lUCja95jqTbEe2vWq3iJPf4b0X+a+syeL8w 6 | pY8bwkc0mhgtR5QrimpahLTe9GfiCsUgRb85qIgNT9Lh3kyo2b/L3N7nI+AWbccp 7 | hLDofbdMw3AcLmdyiiokgeCyjnzOpXnKuTn/oQIDAQABAoIBAGxiObnil0ryABjH 8 | PaT0W4kMnCZNnKXUYlfCofFLC0ejqFazCYXXWhiWkgq8Zz09T2vFlh0CLjmFZ3C8 9 | dUtuV84IKBsEm4c7dLEZp5PtaEWZkRttl5ruBO6PjWJziDCZSL00o6+n8J87j3XU 10 | TvsktSWKtnnVNX0Uiv4blMyRUAioq83/73cLZKyVPw7WQm5mi5KSYc/A3q0HB6Rn 11 | G1RZHjJIcS+bLlrzP9KoQp1pWlpMDuaT5lSoc+bMgohTVqCc1nzWYy9QBD4VbcMS 12 | AYRCsBrlIowTaESTpTOOybwN1cbPvqNnQGFAApaPkKSPp6w5ihGGp4S2Db1ZGTyZ 13 | kPcU0AECgYEA7dZSeCrxKz38oE5hNDF5P/f/Shd8as2T64iirpyWSEY89/NqAIpS 14 | GGCAcNd7bykMeEO+o+THa5prA4Fhr0oi5r+OKELKHCo9F7fU84zEnU3SjZ9mScQ3 15 | twh+W2mUTmk4h5mniJrDDVKRdjbUt45/H85ACUmf0+Pt3bzPO217PYECgYEA6v7l 16 | AJstj1hM9YAdO26kXvTdVjE8R8XmUD8jC6icWO/JS35pg0DNQsbt2GuUJK2OGw4F 17 | /tla2u02nQeDcSguImLhK0PJw514FVR5b2fUfDkNwXW51gTSaym8hequyXIKVbvl 18 | v/1+sSN/m4z1cBD5t8/G0OQ4wwFnWav4d/wEEiECgYEAgW8L/p3QFepsG4nMWK08 19 | AVYjttzFNxKeF6aKcmCBYN/ouj/cRmMAfoe2HrMGV96NDL5Bd8w/ww2Mg6Hb2ZuN 20 | FurUoJCIkX9jNA81cz3+mmUJ200OS8LfV1rl+TWiInIc857pj+w5jnyK8Tyx0xtX 21 | j6WdL/DDbHs0rmHcncjdMwECgYEAqhK2HD0yuQbYE+mXvnayAYNIWWQi03MX38YC 22 | ECMEnJ1WWwvvQy34IDcm1jXtrqnpKg15K1uVlNKPbxCMAa5pzTsw6YYTFT73NMDB 23 | bm5/6zPDj9srFwjAXQyEw4r42xRtBGWLvuqw8XTWmvZmf6fZgz2eD3rM1d1DNjPv 24 | DK9ZJuECgYEAwMSlMOcPRcZo9rx/Qr1Qf7NvnWsJdKs62aMtRlYT0ccZ8wG1sc3j 25 | u+yBUylLmNZ8PWQCnGLBpd4P8s2H3vERVAFQ9XtSncJQDbYg5scQ1DaIcyxXTc93 26 | 473mh/RKadTZTZMNeeUh6iEz3rQ+eoxw07s5JDnJVlHyIk7ZjGTomQY= 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /dev/redis-tls/server.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIEEDCCAfigAwIBAgIUbe9FRsv8Lm32Mifmn8PPnESbIOQwDQYJKoZIhvcNAQEL 3 | BQAwNTETMBEGA1UECgwKUmVkaXMgVGVzdDEeMBwGA1UEAwwVQ2VydGlmaWNhdGUg 4 | QXV0aG9yaXR5MB4XDTIxMTIwMzIwNTU1NVoXDTIyMTIwMzIwNTU1NVowKzETMBEG 5 | A1UECgwKUmVkaXMgVGVzdDEUMBIGA1UEAwwLU2VydmVyLW9ubHkwggEiMA0GCSqG 6 | SIb3DQEBAQUAA4IBDwAwggEKAoIBAQC4hPbLhqJdeadxi9vtQ+EFIcPiUZPF2/Lp 7 | ih6OmHXL49QbzrZY6Q4M3MHUwVYkAL9ySjvC7UR17DQU33XIcqH0zV59/dNtGY5D 8 | VMEQ4yjqnkTxXsP2VLY4n2GFO93ERaYltJQ0yca4uhYQno2dGJzoIPc2k5Ap9r/x 9 | PkDgJt8QCRq8YFr0MYbbxfS4UsVNw623Zzww64XrXN/sr7BRlhMxDxbkeRU8IWt4 10 | BqqqVUGdH4adVcKLDuretPP6OXKEp1gRcpptsi1zIjvZA47njirfvmOwXC7da5TQ 11 | NMPu2ptz8FzA1sAl9hRYh41tuQJjf7JSGRsqsfgGaO8O35nHM4UJAgMBAAGjIjAg 12 | MAsGA1UdDwQEAwIFoDARBglghkgBhvhCAQEEBAMCBkAwDQYJKoZIhvcNAQELBQAD 13 | ggIBABapTzr9iZJAoW1nW6k1MUyQogUGugZ5Frp8fD4+e9EN7xPS+i9UgXCMflee 14 | oEe2MuZJEiIDklD8/Fnhi4yIR2th9IqifHPTNewTsASDUYG/IrXJJeEhxNnor//0 15 | bSD4/XUxxDDRs1JazbJmg7cU1pwDyN8iVS3tVtejgZN1cghEeyAReR4zFwEF1ngZ 16 | ZMRIZr2Ks4TXzB1pDUW1x4pmW37/lXX7STfPj4oq8+VYSlqou6FL+dcqZ6Uc7tLO 17 | DM+3YbFoVyBzVm5aNgwV7qhEgyIevI1nK7hWi13LV1YwUdQDqsZsyimn4u5WWSIc 18 | aFm2s7n7ACNSINFAwhbEC/xkK5UO53xk9PoS9miR+rtjnVXQZNX9ZoI4vGc6UnMF 19 | x2AZhCWnPN65jHxRQmEh4g8+o2oyREZW35f862u9PfwbtogVf/D5xQJQT8iS9Xja 20 | /1ZI1LYmqTW6RB6jF2Zhf7q11BokwDFc7C+clmn2hYtoAB9XYUwM+yO/GeWG5eDz 21 | RmpqgXMwZ5w7hgQliHou9ARYJwoTnauscs9faPM4+U/o+5QUT1yjl/DYe3AUiy9Z 22 | vVmoLcVRxdG7SMESkHLqOvsC7v0c5ifJy/dJKJK62xAwkszsBfWBkY/1njDWxoaQ 23 | +mp2BDMA61NAWyELfuSYXltgbWAf5nzzneZQ2Er5UmJXzoIX 24 | -----END CERTIFICATE----- 25 | -------------------------------------------------------------------------------- /dev/redis-tls/server.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpgIBAAKCAQEAuIT2y4aiXXmncYvb7UPhBSHD4lGTxdvy6Yoejph1y+PUG862 3 | WOkODNzB1MFWJAC/cko7wu1Edew0FN91yHKh9M1eff3TbRmOQ1TBEOMo6p5E8V7D 4 | 9lS2OJ9hhTvdxEWmJbSUNMnGuLoWEJ6NnRic6CD3NpOQKfa/8T5A4CbfEAkavGBa 5 | 9DGG28X0uFLFTcOtt2c8MOuF61zf7K+wUZYTMQ8W5HkVPCFreAaqqlVBnR+GnVXC 6 | iw7q3rTz+jlyhKdYEXKabbItcyI72QOO544q375jsFwu3WuU0DTD7tqbc/BcwNbA 7 | JfYUWIeNbbkCY3+yUhkbKrH4BmjvDt+ZxzOFCQIDAQABAoIBAQC0qMqR/uHdr4y3 8 | 6X2M0pbwVVzaq5CJeo5dBfRhHPjIhepYx41Vg+lTwpis3Bag7XKEThYxBemvo3Ji 9 | tV82wLW9X44SwYBOI2VcmxDkneSjwg4yXNx0xAAddD8hGbpJvv+rjyBEhwJgPyH3 10 | Z6WzmDOYOx6Qeu39iC/p3U/bp3Ni2D2IhriqiZonTPLgAbs8Hb9TDZSyxe7QtL08 11 | UnTOY2Nl8R++w35zwA8mC45by1fPyQdZRD5nsjToBBWehX84naH4AcOA/Pz+cNNp 12 | Kow+RHEQbY/lLGswiTzHJaFxc71BnSlZ25VJzf/DpDWhyC0LUIvItYZ35gUoTBRO 13 | R5r6vdphAoGBANxa5Sc6cFyPdJhaAG80mgHPL27ldyv2jd19v8HD/J4/WWqh4ppb 14 | ZA6im/qeE6FN84MIjqclHDFagvDlsWPy22FkyF9ywJqY+FTuHJrROd5qX9qIqP0c 15 | Zhc3ED7m036Ury9MNJXVEMh2RIdtdnAaajpUXu9DdKOE9n+3yBPEw7+dAoGBANZe 16 | FMBCkxkTPtUJH8pbe5rwndeeWVXJ3aTO1W+hheJqOBBecElD/gHimILfJH7OwfTf 17 | xuB+yQfI1FIMiCE3ecAfFM3N7jDD0HqCw7H9zFWA56SRq/7dvLzxwlkRrZL+B3OQ 18 | 0AijRuCGE7eQgrrOcY+7hpSiSdhtHF4ks/PkIL1dAoGBALGCX3scbouB3NEmH5d1 19 | 7mJqvrE9FKVLtriopiK3ePcZ3TQzONJTsOTBRZm8Yd/dZb8204P+Nxni6fyZbC8x 20 | 4lwwzeFmFZX0iIgSUOS+izmKw7DNyiQsDmnBJ8skM1eS+xTE9M+GlkCGVWorWe+w 21 | t8ZJVTi1RG69m70DFaAnL/FZAoGBANGOUvbHngjLOYcETmGBIMoMIiEgGPC2T8fG 22 | sftYiQsXDwthZp8YqnypSLHW9VRJRm3dPAtFpbvIZVZ4DbN7Cbf4KlwtzYU6Rtkc 23 | b7XWByQmyUulY9/YX6LNK1Hq6CVj02Dz1Yo8IxNlvmyaBlIbcgQyK5OtOkcqEqst 24 | cgUfo6m5AoGBAM4kkduEn3tPg9j6bMLQMqp5INuIwbLatj9KvJvx98qdLkSYOGcg 25 | UvdM5ca+teYJ2vt5E+BRRzRxdq2uinZ3BUeQIV1M1jyod4pMheaRr7cPT5V0mSpX 26 | lGImUXmpUA7WrfYVxVn6D4xdYBCBcA5rrMG0BC6E/hsURaky77Uew8zS 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /dev/rsck.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | server="127.0.0.1" 5 | port="6379" 6 | db="0" 7 | dir=$(dirname $0) 8 | pushd $dir > /dev/null 9 | fulldir=$(pwd) 10 | popd > /dev/null 11 | 12 | while getopts "s:p:d:t:l:h" opt; do 13 | case $opt in 14 | s) 15 | server=$OPTARG;; 16 | p) 17 | port=$OPTARG;; 18 | d) 19 | db=$OPTARG;; 20 | t) 21 | interval=$OPTARG;; 22 | l) 23 | logfile=$OPTARG;; 24 | h) 25 | echo "nchan redis server data consistency check" 26 | echo " -s [server]" 27 | echo " -p [port]" 28 | echo " -d [db number]" 29 | echo " -t [minutes] repeat at this interval" 30 | echo " -l [logfile] log results to this file" 31 | ;; 32 | \?) 33 | exit 1 34 | ;; 35 | esac 36 | done 37 | 38 | url="redis://$server:$port/$db" 39 | 40 | if [[ $interval ]]; then 41 | echo "rsck $url every $interval minutes" 42 | else 43 | echo "rsck $url" 44 | fi 45 | 46 | if [[ $logfile ]]; then 47 | echo "logging to $logfile" 48 | fi 49 | 50 | if [[ $interval ]]; then 51 | sleeptime=$(echo "$interval * 60" | bc) 52 | fi 53 | while true; do 54 | ret=$(redis-cli -p 8537 --eval $dir/../src/store/redis/scripts/rsck.lua --raw) 55 | echo $ret 56 | 57 | if [[ $logfile ]]; then 58 | printf "$(date)\n$ret\n\n" >> $logfile 59 | fi 60 | 61 | if [[ ! $interval ]]; then 62 | break 63 | else 64 | sleep $sleeptime 65 | fi 66 | done 67 | 68 | -------------------------------------------------------------------------------- /dev/sub.rb: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | bundle exec nchan-sub "$@" 3 | -------------------------------------------------------------------------------- /dev/test-parallel.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | par=$1 3 | if [[ -z "$par" ]]; then 4 | par=5 5 | echo "No parallel count given. Assuming $par." 6 | fi 7 | if ! [[ $par =~ ^[0-9]+$ ]]; then 8 | echo "Parallel count isn't a number." > /dev/stderr 9 | exit 1 10 | fi 11 | 12 | for ((i = 0; i < $par; i++)); do 13 | 14 | echo bundle exec ./test.rb ${@:2} 15 | bundle exec ./test.rb ${@:2} & 16 | done 17 | 18 | jobs=$(jobs -p) 19 | #echo "jobs are $jobs" 20 | killjobs() { 21 | for job_pid in $jobs; do 22 | kill $job_pid 23 | done 24 | } 25 | 26 | trap killjobs SIGINT 27 | wait $jobs 28 | -------------------------------------------------------------------------------- /dev/vg.supp: -------------------------------------------------------------------------------- 1 | { 2 | 3 | Memcheck:Param 4 | epoll_ctl(event) 5 | fun:epoll_ctl 6 | fun:ngx_epoll_test_rdhup 7 | fun:ngx_epoll_init 8 | fun:ngx_event_process_init 9 | fun:ngx_worker_process_init 10 | fun:ngx_worker_process_cycle 11 | fun:ngx_spawn_process 12 | fun:ngx_start_worker_processes 13 | fun:ngx_master_process_cycle 14 | fun:main 15 | } 16 | 17 | { 18 | 19 | Memcheck:Param 20 | epoll_pwait(sigmask) 21 | fun:epoll_pwait 22 | fun:ngx_epoll_process_events 23 | fun:ngx_process_events_and_timers 24 | fun:ngx_worker_process_cycle 25 | fun:ngx_spawn_process 26 | fun:ngx_start_worker_processes 27 | fun:ngx_master_process_cycle 28 | fun:main 29 | } 30 | 31 | { 32 | 33 | Memcheck:Param 34 | epoll_pwait(sigmask) 35 | fun:epoll_pwait 36 | fun:ngx_epoll_test_rdhup 37 | fun:ngx_epoll_init 38 | fun:ngx_event_process_init 39 | fun:ngx_worker_process_init 40 | fun:ngx_worker_process_cycle 41 | fun:ngx_spawn_process 42 | fun:ngx_start_worker_processes 43 | fun:ngx_master_process_cycle 44 | fun:main 45 | } 46 | 47 | 48 | { 49 | 50 | Memcheck:Leak 51 | match-leak-kinds: reachable 52 | fun:malloc 53 | fun:ngx_alloc 54 | fun:ngx_init_setproctitle 55 | fun:ngx_os_init 56 | fun:main 57 | } 58 | { 59 | 60 | Memcheck:Leak 61 | match-leak-kinds: reachable,possible 62 | fun:malloc 63 | fun:ngx_alloc 64 | fun:ngx_epoll_init 65 | fun:ngx_event_process_init 66 | fun:ngx_worker_process_init 67 | fun:ngx_worker_process_cycle 68 | fun:ngx_spawn_process 69 | fun:ngx_start_worker_processes 70 | fun:ngx_master_process_cycle 71 | fun:main 72 | } 73 | { 74 | 75 | Memcheck:Leak 76 | match-leak-kinds: reachable,possible 77 | fun:malloc 78 | fun:ngx_alloc 79 | fun:ngx_event_process_init 80 | fun:ngx_worker_process_init 81 | fun:ngx_worker_process_cycle 82 | fun:ngx_spawn_process 83 | fun:ngx_start_worker_processes 84 | fun:ngx_master_process_cycle 85 | fun:main 86 | } 87 | 88 | { 89 | 90 | Memcheck:Leak 91 | match-leak-kinds: reachable 92 | ... 93 | fun:ngx_save_argv 94 | fun:main 95 | } 96 | { 97 | 98 | Memcheck:Leak 99 | match-leak-kinds: reachable 100 | fun:malloc 101 | fun:ngx_strerror_init 102 | fun:main 103 | } 104 | 105 | { 106 | 107 | Memcheck:Leak 108 | match-leak-kinds: definite 109 | fun:malloc 110 | fun:ngx_alloc 111 | fun:ngx_set_environment 112 | fun:ngx_worker_process_init 113 | fun:ngx_worker_process_cycle 114 | fun:ngx_spawn_process 115 | fun:ngx_start_worker_processes 116 | fun:ngx_master_process_cycle 117 | fun:main 118 | } 119 | 120 | { 121 | 122 | Memcheck:Leak 123 | match-leak-kinds: reachable 124 | ... 125 | fun:ngx_ssl_init 126 | fun:main 127 | } 128 | 129 | { 130 | 131 | Memcheck:Leak 132 | match-leak-kinds: reachable 133 | ... 134 | fun:ngx_http_lua_set_ssl 135 | fun:ngx_http_lua_merge_loc_conf 136 | fun:ngx_http_merge_servers 137 | fun:ngx_http_block 138 | fun:ngx_conf_handler 139 | fun:ngx_conf_parse 140 | fun:ngx_init_cycle 141 | fun:main 142 | } 143 | 144 | { 145 | 146 | Memcheck:Leak 147 | match-leak-kinds: reachable,possible 148 | fun:malloc 149 | fun:ngx_alloc 150 | fun:ngx_crc32_table_init 151 | fun:main 152 | } 153 | -------------------------------------------------------------------------------- /dev/wstest.py: -------------------------------------------------------------------------------- 1 | import websocket 2 | import thread 3 | import time 4 | 5 | 6 | 7 | 8 | def on_message(ws, message): 9 | print "got: message %s" % message 10 | 11 | def on_error(ws, error): 12 | print error 13 | 14 | def on_close(ws): 15 | print "### closed ###" 16 | 17 | def on_open(ws): 18 | def run(*args): 19 | for i in range(10): 20 | #time.sleep(0.1) 21 | for y in range(100): 22 | print "send Hello %d %d" % (i, y) 23 | ws.send("Hello %d %d" % (i, y)) 24 | print "thread terminating..." 25 | thread.start_new_thread(run, ()) 26 | 27 | 28 | 29 | if __name__ == "__main__": 30 | websocket.enableTrace(True) 31 | url = "ws://localhost:8082/pub/foo" 32 | #url = "ws://localhost:8082/upstream_pubsub/foo" 33 | #url = "ws://localhost:7000/" 34 | ws = websocket.WebSocketApp(url, 35 | on_message = on_message, 36 | on_error = on_error, 37 | on_close = on_close) 38 | ws.on_open = on_open 39 | ws.run_forever() 40 | -------------------------------------------------------------------------------- /nchan_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/slact/nchan/9c6909d0a4c4611479b7182ac29b2065a5845614/nchan_logo.png -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | nginx 2 | nginx-source -------------------------------------------------------------------------------- /src/nchan_module.h: -------------------------------------------------------------------------------- 1 | #ifndef NCHAN_MODULE_H 2 | #define NCHAN_MODULE_H 3 | //#define NCHAN_SUBSCRIBER_LEAK_DEBUG 1 4 | //#define NCHAN_MSG_RESERVE_DEBUG 1 5 | //#define NCHAN_MSG_LEAK_DEBUG 1 6 | 7 | //debugging config 8 | //#define FAKESHARD 1 9 | //#define FAKE_SHMEM 1 10 | #if FAKESHARD 11 | //#define PUB_FAKE_WORKER 0 12 | //#define SUB_FAKE_WORKER 1 13 | //#define ONE_FAKE_CHANNEL_OWNER 2 14 | #define MAX_FAKE_WORKERS 5 15 | #endif 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | //building for old versions 22 | #ifndef NGX_MAX_INT_T_VALUE 23 | #if (NGX_PTR_SIZE == 4) 24 | #define NGX_MAX_INT_T_VALUE 2147483647 25 | #else 26 | #define NGX_MAX_INT_T_VALUE 9223372036854775807 27 | #endif 28 | #endif 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | extern ngx_pool_t *nchan_pool; 43 | extern ngx_int_t nchan_worker_processes; 44 | extern ngx_module_t ngx_nchan_module; 45 | extern nchan_store_t *nchan_store; 46 | 47 | extern int nchan_stub_status_enabled; 48 | extern int nchan_redis_stats_enabled; 49 | 50 | ngx_int_t nchan_stub_status_handler(ngx_http_request_t *r); 51 | ngx_int_t nchan_pubsub_handler(ngx_http_request_t *r); 52 | ngx_int_t nchan_group_handler(ngx_http_request_t *r); 53 | ngx_int_t nchan_subscriber_info_handler(ngx_http_request_t *r); 54 | ngx_int_t nchan_benchmark_handler(ngx_http_request_t *r); 55 | ngx_int_t nchan_redis_stats_handler(ngx_http_request_t *r); 56 | 57 | time_t nchan_loc_conf_message_timeout(nchan_loc_conf_t *cf); 58 | ngx_int_t nchan_loc_conf_max_messages(nchan_loc_conf_t *cf); 59 | 60 | ngx_int_t nchan_maybe_send_channel_event_message(ngx_http_request_t *, channel_event_type_t); 61 | 62 | size_t nchan_get_used_shmem(void); 63 | 64 | #define nchan_log(level, log, errno, fmt, args...) ngx_log_error(level, log, errno, "nchan: " fmt, ##args) 65 | #define nchan_log_notice(fmt, args...) nchan_log(NGX_LOG_NOTICE, ngx_cycle->log, 0, fmt, ##args) 66 | #define nchan_log_warning(fmt, args...) nchan_log(NGX_LOG_WARN, ngx_cycle->log, 0, fmt, ##args) 67 | #define nchan_log_error(fmt, args...) nchan_log(NGX_LOG_ERR, ngx_cycle->log, 0, fmt, ##args) 68 | #define nchan_log_ooshm_error(fmt, args...) nchan_log(NGX_LOG_ERR, ngx_cycle->log, 0, "Out of shared memory while " fmt ". Increase nchan_max_reserved_memory.", ##args) 69 | 70 | #define nchan_log_request_warning(request, fmt, args...) ngx_log_error(NGX_LOG_WARN, (request)->connection->log, 0, "nchan: " fmt, ##args) 71 | #define nchan_log_request_error(request, fmt, args...) ngx_log_error(NGX_LOG_ERR, ((request) ? (request)->connection->log : ngx_cycle->log), 0, "nchan: " fmt, ##args) 72 | 73 | #endif /*NCHAN_MODULE_H*/ 74 | -------------------------------------------------------------------------------- /src/nchan_variables.h: -------------------------------------------------------------------------------- 1 | ngx_int_t nchan_add_variables(ngx_conf_t *cf); -------------------------------------------------------------------------------- /src/nchan_version.h: -------------------------------------------------------------------------------- 1 | #define NCHAN_VERSION "1.3.7" 2 | -------------------------------------------------------------------------------- /src/nchan_websocket_publisher.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "subscribers/websocket.h" 3 | #include 4 | 5 | //#define DEBUG_LEVEL NGX_LOG_WARN 6 | #define DEBUG_LEVEL NGX_LOG_DEBUG 7 | 8 | #define DBG(fmt, arg...) ngx_log_error(DEBUG_LEVEL, ngx_cycle->log, 0, "WEBSOCKET_PUBLISHER:" fmt, ##arg) 9 | #define ERR(fmt, arg...) ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "WEBSOCKET_PUBLISHER:" fmt, ##arg) 10 | 11 | static nchan_llist_timed_t ws_pub_head; 12 | 13 | void nchan_websocket_publisher_llist_init() { 14 | DBG("init WS publisher llist"); 15 | ws_pub_head.prev = &ws_pub_head; 16 | ws_pub_head.next = &ws_pub_head; 17 | ws_pub_head.data = NULL; 18 | ws_pub_head.time = 0; 19 | } 20 | 21 | 22 | static nchan_llist_timed_t *nchan_ws_llist_enqueue(subscriber_t *sub) { 23 | nchan_llist_timed_t *cur, *last; 24 | if((cur = ngx_alloc(sizeof(*cur), ngx_cycle->log)) == NULL) { 25 | ERR("couldn't allocate llink for websocket publisher"); 26 | return NULL; 27 | } 28 | last = ws_pub_head.prev; 29 | 30 | cur->prev = last; 31 | last->next = cur; 32 | 33 | cur->next = &ws_pub_head; 34 | ws_pub_head.prev = cur; 35 | 36 | cur->time = ngx_time(); 37 | cur->data = (void *)sub; 38 | return cur; 39 | } 40 | 41 | static ngx_int_t nchan_ws_llink_destroy(nchan_llist_timed_t *cur) { 42 | nchan_llist_timed_t *prev, *next; 43 | prev = cur->prev; 44 | next = cur->next; 45 | 46 | prev->next = next; 47 | next->prev = prev; 48 | 49 | ngx_memset(cur, 0xC4, sizeof(*cur)); //debugstuffs 50 | ngx_free(cur); 51 | return NGX_OK; 52 | } 53 | 54 | static void ws_publisher_dequeue_callback(subscriber_t *sub, void *privdata) { 55 | nchan_ws_llink_destroy((nchan_llist_timed_t *)privdata); 56 | } 57 | 58 | static ngx_str_t pub_name = ngx_string("websocket"); 59 | 60 | ngx_int_t nchan_create_websocket_publisher(ngx_http_request_t *r) { 61 | subscriber_t *sub; 62 | nchan_llist_timed_t *sub_link; 63 | nchan_request_ctx_t *ctx = ngx_http_get_module_ctx(r, ngx_nchan_module); 64 | if(ctx) { 65 | ctx->publisher_type = &pub_name; 66 | } 67 | 68 | if((sub = websocket_subscriber_create(r, NULL)) == NULL) { 69 | ERR("couldn't create websocket publisher."); 70 | return NGX_ERROR; 71 | } 72 | 73 | if((sub_link = nchan_ws_llist_enqueue(sub)) == NULL) { 74 | websocket_subscriber_destroy(sub); 75 | ERR("couldn't create websocket publisher llink"); 76 | return NGX_ERROR; 77 | } 78 | 79 | sub->fn->set_dequeue_callback(sub, ws_publisher_dequeue_callback, sub_link); 80 | sub->fn->enqueue(sub); 81 | return NGX_OK; 82 | } 83 | -------------------------------------------------------------------------------- /src/nchan_websocket_publisher.h: -------------------------------------------------------------------------------- 1 | void nchan_websocket_publisher_llist_init(); 2 | ngx_int_t nchan_create_websocket_publisher(ngx_http_request_t *r); -------------------------------------------------------------------------------- /src/store/memory/groups.h: -------------------------------------------------------------------------------- 1 | #ifndef MEMSTORE_GROUPS_HEADER 2 | #define MEMSTORE_GROUPS_HEADER 3 | #include 4 | #include 5 | 6 | typedef struct { 7 | rbtree_seed_t tree; 8 | } memstore_groups_t; 9 | 10 | typedef struct group_tree_node_s group_tree_node_t ; 11 | 12 | #include "store-private.h" 13 | 14 | typedef struct group_callback_s group_callback_t ; 15 | struct group_callback_s { 16 | callback_pt cb; 17 | void *pd; 18 | group_callback_t *next; 19 | char *label; 20 | }; 21 | 22 | struct group_tree_node_s { 23 | ngx_str_t name; //local memory copy of group name 24 | nchan_group_t *group; 25 | group_callback_t *when_ready_head; 26 | group_callback_t *when_ready_tail; 27 | memstore_channel_head_t *owned_chanhead_head; 28 | time_t getting_group; 29 | }; 30 | 31 | ngx_int_t memstore_groups_init(memstore_groups_t *); 32 | ngx_int_t memstore_groups_shutdown(memstore_groups_t *); 33 | 34 | 35 | ngx_int_t memstore_group_find(memstore_groups_t *gp, ngx_str_t *name, callback_pt cb, void *pd); 36 | ngx_int_t memstore_group_find_from_groupnode(memstore_groups_t *gp, group_tree_node_t *gtn, callback_pt cb, void *pd); 37 | 38 | 39 | group_tree_node_t *memstore_groupnode_get(memstore_groups_t *gp, ngx_str_t *name); 40 | nchan_group_t *memstore_group_owner_find(memstore_groups_t *gp, ngx_str_t *name, int *group_just_created); 41 | ngx_int_t memstore_group_receive(memstore_groups_t *gp, nchan_group_t *shm_group); 42 | ngx_int_t memstore_group_delete(memstore_groups_t *gp, ngx_str_t *name, callback_pt cb, void *pd); 43 | ngx_int_t memstore_group_receive_delete(memstore_groups_t *gp, nchan_group_t *shm_group); 44 | 45 | ngx_int_t memstore_group_add_channel(memstore_channel_head_t *ch); 46 | ngx_int_t memstore_group_remove_channel(memstore_channel_head_t *ch); 47 | 48 | void memstore_group_associate_own_channel(memstore_channel_head_t *ch); 49 | void memstore_group_dissociate_own_channel(memstore_channel_head_t *ch); 50 | 51 | ngx_int_t memstore_group_add_message(group_tree_node_t *gtn, nchan_msg_t *msg); 52 | ngx_int_t memstore_group_remove_message(group_tree_node_t *gtn, nchan_msg_t *msg); 53 | 54 | ngx_int_t memstore_group_add_subscribers(group_tree_node_t *gtn, int count); 55 | #endif //MEMSTORE_GROUPS_HEADER 56 | -------------------------------------------------------------------------------- /src/store/memory/ipc-handlers.h: -------------------------------------------------------------------------------- 1 | #include "store-private.h" 2 | 3 | typedef void (*ipc_handler_pt)(ngx_int_t, void *); 4 | 5 | ngx_int_t memstore_ipc_send_subscribe(ngx_int_t owner, ngx_str_t *shm_chid, memstore_channel_head_t *, nchan_loc_conf_t *); 6 | ngx_int_t memstore_ipc_send_memstore_subscriber_keepalive(ngx_int_t dst, ngx_str_t *chid, subscriber_t *sub, memstore_channel_head_t *ch); 7 | ngx_int_t memstore_ipc_send_unsubscribe(ngx_int_t dst, ngx_str_t *chid, void *subscriber, void* privdata); 8 | ngx_int_t memstore_ipc_send_unsubscribed(ngx_int_t dst, ngx_str_t *chid, void* privdata); 9 | ngx_int_t memstore_ipc_send_publish_message(ngx_int_t dst, ngx_str_t *chid, nchan_msg_t *shm_msg, nchan_loc_conf_t *cf, callback_pt callback, void *privdata); 10 | ngx_int_t memstore_ipc_send_publish_status(ngx_int_t dst, ngx_str_t *chid, ngx_int_t status_code, const ngx_str_t *status_line, callback_pt callback, void *privdata); 11 | ngx_int_t memstore_ipc_send_publish_notice(ngx_int_t dst, ngx_str_t *chid, ngx_int_t notice_code, void *notice_data); 12 | ngx_int_t memstore_ipc_send_get_message(ngx_int_t owner, ngx_str_t *shm_chid, nchan_msg_id_t *msgid, void * privdata); 13 | ngx_int_t memstore_ipc_send_delete(ngx_int_t owner, ngx_str_t *shm_chid, callback_pt callback, void *privdata); 14 | void memstore_ipc_alert_handler(ngx_int_t sender, ngx_uint_t code, void *data); 15 | ngx_int_t memstore_ipc_send_get_channel_info(ngx_int_t dst, ngx_str_t *chid, nchan_loc_conf_t *cf, callback_pt callback, void* privdata); 16 | ngx_int_t memstore_ipc_send_channel_existence_check(ngx_int_t dst, ngx_str_t *chid, nchan_loc_conf_t *cf, callback_pt callback, void* privdata); 17 | ngx_int_t memstore_ipc_broadcast_group(nchan_group_t *shared_group); 18 | ngx_int_t memstore_ipc_send_get_group(ngx_int_t dst, ngx_str_t *group_id); 19 | ngx_int_t memstore_ipc_broadcast_group_delete(nchan_group_t *shared_group); 20 | ngx_int_t memstore_ipc_send_flood_test(ngx_int_t dst); 21 | 22 | ngx_int_t memstore_ipc_broadcast_benchmark_initialize(void *bench); 23 | ngx_int_t memstore_ipc_broadcast_benchmark_run(void); 24 | ngx_int_t memstore_ipc_broadcast_benchmark_stop(void); 25 | ngx_int_t memstore_ipc_broadcast_benchmark_finish(void); 26 | ngx_int_t memstore_ipc_broadcast_benchmark_abort(void); 27 | 28 | ngx_int_t memstore_ipc_broadcast_redis_stats_request(void *nodeset, callback_pt cb, void *pd); 29 | -------------------------------------------------------------------------------- /src/store/memory/ipc.h: -------------------------------------------------------------------------------- 1 | #ifndef NCHAN_IPC_H 2 | #define NCHAN_IPC_H 3 | 4 | #define IPC_DATA_SIZE 64 5 | //#define IPC_DATA_SIZE 80 6 | 7 | typedef struct { 8 | char data[IPC_DATA_SIZE]; 9 | time_t time_sent; 10 | int16_t src_slot; 11 | uint16_t worker_generation; 12 | uint8_t code; 13 | } ipc_alert_t; 14 | 15 | #define IPC_WRITEBUF_SIZE 32 16 | 17 | typedef struct ipc_writebuf_overflow_s ipc_writebuf_overflow_t; 18 | struct ipc_writebuf_overflow_s { 19 | ipc_alert_t alert; 20 | ipc_writebuf_overflow_t *next; 21 | }; 22 | 23 | typedef struct ipc_writebuf_s ipc_writebuf_t; 24 | struct ipc_writebuf_s { 25 | //a ring buffer with a linked-list overflow for writing alerts, 26 | uint16_t n; 27 | uint16_t first; 28 | int32_t overflow_n; 29 | ipc_writebuf_overflow_t *overflow_first; 30 | ipc_writebuf_overflow_t *overflow_last; 31 | ipc_alert_t alerts[IPC_WRITEBUF_SIZE]; 32 | }; //ipc_writebuf_t 33 | 34 | typedef struct ipc_s ipc_t; 35 | 36 | typedef struct { 37 | ipc_t *ipc; //useful for write events 38 | ngx_socket_t pipe[2]; 39 | ngx_connection_t *c; 40 | ipc_writebuf_t wbuf; 41 | unsigned active:1; 42 | } ipc_process_t; 43 | 44 | struct ipc_s { 45 | const char *name; 46 | 47 | ipc_process_t process[NGX_MAX_PROCESSES]; 48 | 49 | void (*handler)(ngx_int_t, ngx_uint_t, void*); 50 | 51 | ngx_int_t workers; 52 | ngx_int_t worker_slots[NGX_MAX_PROCESSES]; 53 | }; //ipc_t 54 | 55 | ngx_int_t ipc_init(ipc_t *ipc); 56 | ngx_int_t ipc_open(ipc_t *ipc, ngx_cycle_t *cycle, ngx_int_t workers, void (*slot_callback)(int slot, int worker)); 57 | ngx_int_t ipc_set_handler(ipc_t *ipc, void (*alert_handler)(ngx_int_t, ngx_uint_t , void *data)); 58 | ngx_int_t ipc_register_worker(ipc_t *ipc, ngx_cycle_t *cycle); 59 | ngx_int_t ipc_close(ipc_t *ipc, ngx_cycle_t *cycle); 60 | 61 | ngx_int_t ipc_broadcast_alert(ipc_t *ipc, ngx_uint_t code, void *data, size_t data_size); 62 | ngx_int_t ipc_alert(ipc_t *ipc, ngx_int_t slot, ngx_uint_t code, void *data, size_t data_size); 63 | 64 | size_t ipc_worker_slots(const ipc_t *ipc, const ngx_int_t **workerslots_array); 65 | 66 | #endif //NCHAN_IPC_H 67 | -------------------------------------------------------------------------------- /src/store/memory/recycloc.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define DBG(...) ngx_log_error(DEBUG_LEVEL, ngx_cycle->log, 0, __VA_ARGS__) 4 | #define ERR(...) ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, __VA_ARGS__) 5 | 6 | typedef struct recycloc_trash_s recycloc_trash_t; 7 | typedef struct recycloc_s recycloc_t; 8 | 9 | struct recycloc_llist_s { 10 | void *data; 11 | struct recycloc_page_t *prev; 12 | struct recycloc_page_t *next; 13 | }; 14 | 15 | struct recycloc_s { 16 | const char *name; 17 | recycloc_llist_s *head; 18 | recycloc_llist_s *tail; 19 | recycloc_llist_s *prealloc_start; 20 | recycloc_llist_s *prealloc_end; 21 | } 22 | 23 | recycloc_t *recycloc_init(const char *name, recycloc_t *ptr, size_t data_size, size_t prealloc_count) { 24 | recycloc_t rec = NULL; 25 | if(page_size > ngx_pagesize) { 26 | ERR("can't create recycloc: page_size %i > ngx_pagesize %i", page_size, ngx_pagesize); 27 | return NULL; 28 | } 29 | if(!(rec = ngx_alloc(sizeof(recycloc_t) + page_size))){ 30 | ERR("can't alloc enough (%i) memory for recycloc", sizeof(recycloc_t) + page_size); 31 | return NULL; 32 | } 33 | rec->name=name; 34 | rec->data_size = data_size; 35 | return rec; 36 | 37 | 38 | } 39 | 40 | void * recycloc_alloc(recycloc_t *self); 41 | 42 | 43 | 44 | recycloc_t *recycloc_destroy(recycloc_t *self) { 45 | 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/store/memory/store.h: -------------------------------------------------------------------------------- 1 | #ifndef NCHAN_MEMSTORE_H 2 | #define NCHAN_MEMSTORE_H 3 | 4 | extern nchan_store_t nchan_store_memory; 5 | 6 | ngx_int_t memstore_channel_owner(ngx_str_t *id); 7 | 8 | extern void *nchan_store_memory_shmem; 9 | 10 | nchan_loc_conf_shared_data_t *memstore_get_conf_shared_data(nchan_loc_conf_t *cf); 11 | ngx_int_t memstore_reserve_conf_shared_data(nchan_loc_conf_t *cf); 12 | ngx_int_t nchan_nginx_worker_procslot(ngx_int_t worker_number); 13 | #endif //NCHAN_MEMSTORE_H 14 | -------------------------------------------------------------------------------- /src/store/ngx_rwlock.h: -------------------------------------------------------------------------------- 1 | void ngx_rwlock_init(ngx_rwlock_t *lock); 2 | void ngx_rwlock_release_write(ngx_rwlock_t *lock); 3 | void ngx_rwlock_reserve_write(ngx_rwlock_t *lock); 4 | void ngx_rwlock_release_read(ngx_rwlock_t *lock); 5 | void ngx_rwlock_reserve_read(ngx_rwlock_t *lock); -------------------------------------------------------------------------------- /src/store/redis/hiredis/.gitignore: -------------------------------------------------------------------------------- 1 | /hiredis-test 2 | /examples/hiredis-example* 3 | /*.o 4 | /*.so 5 | /*.dylib 6 | /*.a 7 | /*.pc 8 | *.dSYM 9 | tags 10 | -------------------------------------------------------------------------------- /src/store/redis/hiredis/COPYING: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009-2011, Salvatore Sanfilippo 2 | Copyright (c) 2010-2011, Pieter Noordhuis 3 | 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, 10 | this list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of Redis nor the names of its contributors may be used 17 | to endorse or promote products derived from this software without specific 18 | prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 21 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 24 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 27 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /src/store/redis/hiredis/alloc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, Michael Grunder 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * * Redistributions of source code must retain the above copyright notice, 10 | * this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * * Neither the name of Redis nor the names of its contributors may be used 15 | * to endorse or promote products derived from this software without 16 | * specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #include "fmacros.h" 32 | #include "alloc.h" 33 | #include 34 | #include 35 | 36 | hiredisAllocFuncs hiredisAllocFns = { 37 | .mallocFn = malloc, 38 | .callocFn = calloc, 39 | .reallocFn = realloc, 40 | .strdupFn = strdup, 41 | .freeFn = free, 42 | }; 43 | 44 | /* Override hiredis' allocators with ones supplied by the user */ 45 | hiredisAllocFuncs hiredisSetAllocators(hiredisAllocFuncs *override) { 46 | hiredisAllocFuncs orig = hiredisAllocFns; 47 | 48 | hiredisAllocFns = *override; 49 | 50 | return orig; 51 | } 52 | 53 | /* Reset allocators to use libc defaults */ 54 | void hiredisResetAllocators(void) { 55 | hiredisAllocFns = (hiredisAllocFuncs) { 56 | .mallocFn = malloc, 57 | .callocFn = calloc, 58 | .reallocFn = realloc, 59 | .strdupFn = strdup, 60 | .freeFn = free, 61 | }; 62 | } 63 | 64 | #ifdef _WIN32 65 | 66 | void *hi_malloc(size_t size) { 67 | return hiredisAllocFns.mallocFn(size); 68 | } 69 | 70 | void *hi_calloc(size_t nmemb, size_t size) { 71 | return hiredisAllocFns.callocFn(nmemb, size); 72 | } 73 | 74 | void *hi_realloc(void *ptr, size_t size) { 75 | return hiredisAllocFns.reallocFn(ptr, size); 76 | } 77 | 78 | char *hi_strdup(const char *str) { 79 | return hiredisAllocFns.strdupFn(str); 80 | } 81 | 82 | void hi_free(void *ptr) { 83 | hiredisAllocFns.freeFn(ptr); 84 | } 85 | 86 | #endif 87 | -------------------------------------------------------------------------------- /src/store/redis/hiredis/alloc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, Michael Grunder 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * * Redistributions of source code must retain the above copyright notice, 10 | * this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * * Neither the name of Redis nor the names of its contributors may be used 15 | * to endorse or promote products derived from this software without 16 | * specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef HIREDIS_ALLOC_H 32 | #define HIREDIS_ALLOC_H 33 | 34 | #include /* for size_t */ 35 | 36 | #ifdef __cplusplus 37 | extern "C" { 38 | #endif 39 | 40 | /* Structure pointing to our actually configured allocators */ 41 | typedef struct hiredisAllocFuncs { 42 | void *(*mallocFn)(size_t); 43 | void *(*callocFn)(size_t,size_t); 44 | void *(*reallocFn)(void*,size_t); 45 | char *(*strdupFn)(const char*); 46 | void (*freeFn)(void*); 47 | } hiredisAllocFuncs; 48 | 49 | hiredisAllocFuncs hiredisSetAllocators(hiredisAllocFuncs *ha); 50 | void hiredisResetAllocators(void); 51 | 52 | #ifndef _WIN32 53 | 54 | /* Hiredis' configured allocator function pointer struct */ 55 | extern hiredisAllocFuncs hiredisAllocFns; 56 | 57 | static inline void *hi_malloc(size_t size) { 58 | return hiredisAllocFns.mallocFn(size); 59 | } 60 | 61 | static inline void *hi_calloc(size_t nmemb, size_t size) { 62 | return hiredisAllocFns.callocFn(nmemb, size); 63 | } 64 | 65 | static inline void *hi_realloc(void *ptr, size_t size) { 66 | return hiredisAllocFns.reallocFn(ptr, size); 67 | } 68 | 69 | static inline char *hi_strdup(const char *str) { 70 | return hiredisAllocFns.strdupFn(str); 71 | } 72 | 73 | static inline void hi_free(void *ptr) { 74 | hiredisAllocFns.freeFn(ptr); 75 | } 76 | 77 | #else 78 | 79 | void *hi_malloc(size_t size); 80 | void *hi_calloc(size_t nmemb, size_t size); 81 | void *hi_realloc(void *ptr, size_t size); 82 | char *hi_strdup(const char *str); 83 | void hi_free(void *ptr); 84 | 85 | #endif 86 | 87 | #ifdef __cplusplus 88 | } 89 | #endif 90 | 91 | #endif /* HIREDIS_ALLOC_H */ 92 | -------------------------------------------------------------------------------- /src/store/redis/hiredis/async_private.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2011, Salvatore Sanfilippo 3 | * Copyright (c) 2010-2011, Pieter Noordhuis 4 | * 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the distribution. 15 | * * Neither the name of Redis nor the names of its contributors may be used 16 | * to endorse or promote products derived from this software without 17 | * specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 23 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 | * POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | #ifndef __HIREDIS_ASYNC_PRIVATE_H 33 | #define __HIREDIS_ASYNC_PRIVATE_H 34 | 35 | #define _EL_ADD_READ(ctx) \ 36 | do { \ 37 | refreshTimeout(ctx); \ 38 | if ((ctx)->ev.addRead) (ctx)->ev.addRead((ctx)->ev.data); \ 39 | } while (0) 40 | #define _EL_DEL_READ(ctx) do { \ 41 | if ((ctx)->ev.delRead) (ctx)->ev.delRead((ctx)->ev.data); \ 42 | } while(0) 43 | #define _EL_ADD_WRITE(ctx) \ 44 | do { \ 45 | refreshTimeout(ctx); \ 46 | if ((ctx)->ev.addWrite) (ctx)->ev.addWrite((ctx)->ev.data); \ 47 | } while (0) 48 | #define _EL_DEL_WRITE(ctx) do { \ 49 | if ((ctx)->ev.delWrite) (ctx)->ev.delWrite((ctx)->ev.data); \ 50 | } while(0) 51 | #define _EL_CLEANUP(ctx) do { \ 52 | if ((ctx)->ev.cleanup) (ctx)->ev.cleanup((ctx)->ev.data); \ 53 | ctx->ev.cleanup = NULL; \ 54 | } while(0); 55 | 56 | static inline void refreshTimeout(redisAsyncContext *ctx) { 57 | #define REDIS_TIMER_ISSET(tvp) \ 58 | (tvp && ((tvp)->tv_sec || (tvp)->tv_usec)) 59 | 60 | #define REDIS_EL_TIMER(ac, tvp) \ 61 | if ((ac)->ev.scheduleTimer && REDIS_TIMER_ISSET(tvp)) { \ 62 | (ac)->ev.scheduleTimer((ac)->ev.data, *(tvp)); \ 63 | } 64 | 65 | if (ctx->c.flags & REDIS_CONNECTED) { 66 | REDIS_EL_TIMER(ctx, ctx->c.command_timeout); 67 | } else { 68 | REDIS_EL_TIMER(ctx, ctx->c.connect_timeout); 69 | } 70 | } 71 | 72 | void __redisAsyncDisconnect(redisAsyncContext *ac); 73 | void redisProcessCallbacks(redisAsyncContext *ac); 74 | 75 | #endif /* __HIREDIS_ASYNC_PRIVATE_H */ 76 | -------------------------------------------------------------------------------- /src/store/redis/hiredis/fmacros.h: -------------------------------------------------------------------------------- 1 | #ifndef __HIREDIS_FMACRO_H 2 | #define __HIREDIS_FMACRO_H 3 | 4 | #define _XOPEN_SOURCE 600 5 | #define _POSIX_C_SOURCE 200112L 6 | 7 | #if defined(__APPLE__) && defined(__MACH__) 8 | /* Enable TCP_KEEPALIVE */ 9 | #define _DARWIN_C_SOURCE 10 | #endif 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /src/store/redis/hiredis/net.h: -------------------------------------------------------------------------------- 1 | /* Extracted from anet.c to work properly with Hiredis error reporting. 2 | * 3 | * Copyright (c) 2009-2011, Salvatore Sanfilippo 4 | * Copyright (c) 2010-2014, Pieter Noordhuis 5 | * Copyright (c) 2015, Matt Stancliff , 6 | * Jan-Erik Rediger 7 | * 8 | * All rights reserved. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions are met: 12 | * 13 | * * Redistributions of source code must retain the above copyright notice, 14 | * this list of conditions and the following disclaimer. 15 | * * Redistributions in binary form must reproduce the above copyright 16 | * notice, this list of conditions and the following disclaimer in the 17 | * documentation and/or other materials provided with the distribution. 18 | * * Neither the name of Redis nor the names of its contributors may be used 19 | * to endorse or promote products derived from this software without 20 | * specific prior written permission. 21 | * 22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 23 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 26 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 | * POSSIBILITY OF SUCH DAMAGE. 33 | */ 34 | 35 | #ifndef __NET_H 36 | #define __NET_H 37 | 38 | #include "hiredis.h" 39 | 40 | void redisNetClose(redisContext *c); 41 | ssize_t redisNetRead(redisContext *c, char *buf, size_t bufcap); 42 | ssize_t redisNetWrite(redisContext *c); 43 | 44 | int redisCheckSocketError(redisContext *c); 45 | int redisContextSetTimeout(redisContext *c, const struct timeval tv); 46 | int redisContextConnectTcp(redisContext *c, const char *addr, int port, const struct timeval *timeout); 47 | int redisContextConnectBindTcp(redisContext *c, const char *addr, int port, 48 | const struct timeval *timeout, 49 | const char *source_addr); 50 | int redisContextConnectUnix(redisContext *c, const char *path, const struct timeval *timeout); 51 | int redisKeepAlive(redisContext *c, int interval); 52 | int redisCheckConnectDone(redisContext *c, int *completed); 53 | 54 | int redisSetTcpNoDelay(redisContext *c); 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /src/store/redis/hiredis/sdsalloc.h: -------------------------------------------------------------------------------- 1 | /* SDSLib 2.0 -- A C dynamic strings library 2 | * 3 | * Copyright (c) 2006-2015, Salvatore Sanfilippo 4 | * Copyright (c) 2015, Oran Agra 5 | * Copyright (c) 2015, Redis Labs, Inc 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions are met: 10 | * 11 | * * Redistributions of source code must retain the above copyright notice, 12 | * this list of conditions and the following disclaimer. 13 | * * Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * * Neither the name of Redis nor the names of its contributors may be used 17 | * to endorse or promote products derived from this software without 18 | * specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 24 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 | * POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | /* SDS allocator selection. 34 | * 35 | * This file is used in order to change the SDS allocator at compile time. 36 | * Just define the following defines to what you want to use. Also add 37 | * the include of your alternate allocator if needed (not needed in order 38 | * to use the default libc allocator). */ 39 | 40 | #include "alloc.h" 41 | 42 | #define s_malloc hi_malloc 43 | #define s_realloc hi_realloc 44 | #define s_free hi_free 45 | -------------------------------------------------------------------------------- /src/store/redis/hiredis/win32.h: -------------------------------------------------------------------------------- 1 | #ifndef _WIN32_HELPER_INCLUDE 2 | #define _WIN32_HELPER_INCLUDE 3 | #ifdef _MSC_VER 4 | 5 | #include /* for struct timeval */ 6 | 7 | #ifndef inline 8 | #define inline __inline 9 | #endif 10 | 11 | #ifndef strcasecmp 12 | #define strcasecmp stricmp 13 | #endif 14 | 15 | #ifndef strncasecmp 16 | #define strncasecmp strnicmp 17 | #endif 18 | 19 | #ifndef va_copy 20 | #define va_copy(d,s) ((d) = (s)) 21 | #endif 22 | 23 | #ifndef snprintf 24 | #define snprintf c99_snprintf 25 | 26 | __inline int c99_vsnprintf(char* str, size_t size, const char* format, va_list ap) 27 | { 28 | int count = -1; 29 | 30 | if (size != 0) 31 | count = _vsnprintf_s(str, size, _TRUNCATE, format, ap); 32 | if (count == -1) 33 | count = _vscprintf(format, ap); 34 | 35 | return count; 36 | } 37 | 38 | __inline int c99_snprintf(char* str, size_t size, const char* format, ...) 39 | { 40 | int count; 41 | va_list ap; 42 | 43 | va_start(ap, format); 44 | count = c99_vsnprintf(str, size, format, ap); 45 | va_end(ap); 46 | 47 | return count; 48 | } 49 | #endif 50 | #endif /* _MSC_VER */ 51 | 52 | #ifdef _WIN32 53 | #define strerror_r(errno,buf,len) strerror_s(buf,len,errno) 54 | #endif /* _WIN32 */ 55 | 56 | #endif /* _WIN32_HELPER_INCLUDE */ 57 | -------------------------------------------------------------------------------- /src/store/redis/redis-lua-scripts/.gitignore: -------------------------------------------------------------------------------- 1 | Gemfile.lock 2 | -------------------------------------------------------------------------------- /src/store/redis/redis-lua-scripts/Gemfile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | source 'https://rubygems.org' 3 | gem 'pry' 4 | gem 'pry-debundle' 5 | gem 'pry-rescue' 6 | 7 | gem 'minitest' 8 | gem 'minitest-reporters' 9 | 10 | gem "redis" 11 | gem "hsss" 12 | -------------------------------------------------------------------------------- /src/store/redis/redis-lua-scripts/add_fakesub.lua: -------------------------------------------------------------------------------- 1 | --input: keys: [], values: [namespace, channel_id, number, time, nginx_worker_id] 2 | --output: -none- 3 | 4 | redis.call('echo', ' ####### ADD_FAKESUBS ####### ') 5 | local ns = ARGV[1] 6 | local id = ARGV[2] 7 | local num = tonumber(ARGV[3]) 8 | local time = tonumber(ARGV[4]) 9 | local ngx_worker_id = ARGV[5] 10 | 11 | if num==nil then 12 | return {err="fakesub number not given"} 13 | end 14 | 15 | local chan_key = ('%s{channel:%s}'):format(ns, id) 16 | local subs_key = ('%s{channel:%s}:subscriber_counts'):format(ns, id) 17 | 18 | local res = redis.pcall('EXISTS', chan_key) 19 | if type(res) == "table" and res["err"] then 20 | return {err = ("CLUSTER KEYSLOT ERROR. %i %s"):format(num, id)} 21 | end 22 | 23 | local exists = res == 1 24 | 25 | local old_current_count = 0 26 | 27 | if exists or (not exists and num > 0) then 28 | old_current_count = redis.call('HINCRBY', chan_key, 'fake_subscribers', num) 29 | if time then 30 | redis.call('HSET', chan_key, 'last_seen_fake_subscriber', time) 31 | end 32 | if not exists then 33 | redis.call('EXPIRE', chan_key, 5) --something small 34 | end 35 | end 36 | 37 | local res = redis.pcall('EXISTS', subs_key) 38 | if type(res) == "table" and res["err"] then 39 | return {err = ("CLUSTER KEYSLOT ERROR. %i %s"):format(num, id)} 40 | end 41 | redis.call('HINCRBY', subs_key, ngx_worker_id, num) 42 | local subs_key_pttl = tonumber(redis.call('PTTL', subs_key)) 43 | if subs_key_pttl < 0 then 44 | subs_key_pttl = redis.call('PTTL', chan_key) 45 | if subs_key_pttl <= 0 then 46 | --60 seconds to get your shit together 47 | subs_key_pttl = 60 48 | end 49 | redis.call('PEXPIRE', subs_key, subs_key_pttl) 50 | end 51 | 52 | return nil 53 | -------------------------------------------------------------------------------- /src/store/redis/redis-lua-scripts/channel_keepalive.lua: -------------------------------------------------------------------------------- 1 | --input: keys: [], values: [namespace, channel_id, ttl_msec, ttl_safety_margin_msec] 2 | -- ttl_msec is for when there are no messages but at least 1 subscriber. 3 | --output: seconds until next keepalive is expected, or -1 for "let it disappear" 4 | redis.call('ECHO', ' ####### CHANNEL KEEPALIVE ####### ') 5 | local ns=ARGV[1] 6 | local id=ARGV[2] 7 | local ttl=tonumber(ARGV[3]) 8 | local ttl_safety_margin=tonumber(ARGV[4]) 9 | if not ttl then 10 | return {err="Invalid channel keepalive TTL (3rd arg)"} 11 | end 12 | 13 | --safe ttl is a bit greater than the expected ttl, so that Nchan can update it before it expires 14 | local safe_ttl = ttl + ttl_safety_margin 15 | 16 | local ch = ('%s{channel:%s}'):format(ns, id) 17 | local key= { 18 | channel= ch, --hash 19 | messages= ch..':messages', --list 20 | subscribers = ch..':subscribers', --list 21 | subscriber_counts = ch..':subscriber_counts' --hash 22 | } 23 | 24 | local subs_count = tonumber(redis.call('HGET', key.channel, "subscribers")) or 0 25 | local msgs_count = tonumber(redis.call('LLEN', key.messages)) or 0 26 | local actual_ttl = tonumber(redis.call('PTTL', key.channel)) 27 | 28 | 29 | if subs_count <= 0 then 30 | return -1 31 | end 32 | 33 | if msgs_count > 0 and actual_ttl > safe_ttl then 34 | local return_ttl = actual_ttl - ttl_safety_margin > 0 and actual_ttl - ttl_safety_margin or math.ceil(actual_ttl / 2) 35 | return return_ttl 36 | end 37 | 38 | --refresh ttl 39 | redis.call('PEXPIRE', key.channel, safe_ttl); 40 | redis.call('PEXPIRE', key.messages, safe_ttl); 41 | redis.call('PEXPIRE', key.subscribers, safe_ttl); 42 | redis.call('PEXPIRE', key.subscriber_counts, safe_ttl); 43 | 44 | return ttl 45 | 46 | -------------------------------------------------------------------------------- /src/store/redis/redis-lua-scripts/delete.lua: -------------------------------------------------------------------------------- 1 | --input: keys: [], values: [ namespace, channel_id, publish_command, use_accurate_subscriber_count ] 2 | --output: channel_hash {ttl, time_last_seen, subscribers, messages} or nil 3 | -- delete this channel and all its messages 4 | local ns = ARGV[1] 5 | local id = ARGV[2] 6 | local publish_command = ARGV[3] 7 | local use_accurate_subscriber_count = tonumber(ARGV[4])~=0 8 | local ch = ('%s{channel:%s}'):format(ns, id) 9 | local key_msg= ch..':msg:%s' --not finished yet 10 | local key_channel=ch 11 | local messages= ch..':messages' 12 | local subscribers=ch..':subscribers' 13 | local pubsub= ch..':pubsub' 14 | local subscriber_counts = ch..':subscriber_counts' 15 | 16 | redis.replicate_commands() 17 | 18 | redis.call('echo', ' ####### DELETE #######') 19 | local num_messages = 0 20 | --delete all the messages right now mister! 21 | local msg 22 | while true do 23 | msg = redis.call('LPOP', messages) 24 | if msg then 25 | num_messages = num_messages + 1 26 | redis.call('DEL', key_msg:format(msg)) 27 | else 28 | break 29 | end 30 | end 31 | 32 | local del_msgpack =cmsgpack.pack({"alert", "delete channel", id}) 33 | for k,channel_key in pairs(redis.call('SMEMBERS', subscribers)) do 34 | redis.call('PUBLISH', channel_key, del_msgpack) 35 | end 36 | 37 | local tohash=function(arr) 38 | if type(arr)~="table" then 39 | return nil 40 | end 41 | local h = {} 42 | local k=nil 43 | for i, v in ipairs(arr) do 44 | if k == nil then 45 | k=v 46 | else 47 | h[k]=v; k=nil 48 | end 49 | end 50 | return h 51 | end 52 | 53 | local channel = nil 54 | local subscriber_count = nil 55 | if redis.call('EXISTS', key_channel) ~= 0 then 56 | channel = tohash(redis.call('hgetall', key_channel)) 57 | --leave some crumbs behind showing this channel was just deleted 58 | redis.call('setex', ch..":deleted", 5, 1) 59 | 60 | if use_accurate_subscriber_count then 61 | local sub_counts = tohash(redis.call("HGETALL", subscriber_counts)) 62 | subscriber_count = 0 63 | for k, v in pairs(sub_counts) do 64 | v = tonumber(v) 65 | local res = redis.call("PUBSUB", "NUMSUB", k) 66 | if tonumber(res[2]) >= 1 and v > 0 then 67 | subscriber_count = subscriber_count + tonumber(v) 68 | else 69 | redis.call("HDEL", subscriber_counts, k) 70 | end 71 | end 72 | else 73 | subscriber_count = tonumber(channel.fake_subscribers) or tonumber(channel.subscribers) 74 | end 75 | 76 | end 77 | 78 | redis.call('DEL', key_channel, messages, subscribers, subscriber_counts) 79 | redis.call('PUBLISH', pubsub, del_msgpack) 80 | 81 | if channel then 82 | return { 83 | tonumber(channel.ttl) or 0, 84 | tonumber(channel.last_seen_fake_subscriber) or 0, 85 | subscriber_count or 0, 86 | channel.current_message or "", 87 | tonumber(num_messages) 88 | } 89 | else 90 | return nil 91 | end 92 | -------------------------------------------------------------------------------- /src/store/redis/redis-lua-scripts/find_channel.lua: -------------------------------------------------------------------------------- 1 | --input: keys: [], values: [ namespace, channel_id, use_accurate_subscriber_count ] 2 | --output: channel_hash {ttl, time_last_seen, subscribers, last_channel_id, messages} or nil 3 | -- finds and return the info hash of a channel, or nil of channel not found 4 | local ns = ARGV[1] 5 | local id = ARGV[2] 6 | local use_accurate_subscriber_count = tonumber(ARGV[3]) ~= 0 7 | 8 | local channel_key = ('%s{channel:%s}'):format(ns, id) 9 | local messages_key = channel_key..':messages' 10 | local subscriber_counts = channel_key..':subscriber_counts' 11 | 12 | redis.replicate_commands() 13 | 14 | redis.call('echo', ' ####### FIND_CHANNEL ######## ') 15 | 16 | --check old entries 17 | local oldestmsg=function(list_key, old_fmt) 18 | local old, oldkey 19 | local n, del=0,0 20 | while true do 21 | n=n+1 22 | old=redis.call('lindex', list_key, -1) 23 | if old then 24 | oldkey=old_fmt:format(old) 25 | local ex=redis.call('exists', oldkey) 26 | if ex==1 then 27 | return oldkey 28 | else 29 | redis.call('rpop', list_key) 30 | del=del+1 31 | end 32 | else 33 | break 34 | end 35 | end 36 | end 37 | 38 | local tohash=function(arr) 39 | if type(arr)~="table" then 40 | return nil 41 | end 42 | local h = {} 43 | local k=nil 44 | for i, v in ipairs(arr) do 45 | if k == nil then 46 | k=v 47 | else 48 | --dbg(k.."="..v) 49 | h[k]=v; k=nil 50 | end 51 | end 52 | return h 53 | end 54 | 55 | if redis.call('EXISTS', channel_key) ~= 0 then 56 | local ch = tohash(redis.call('hgetall', channel_key)) 57 | 58 | local msgs_count 59 | if redis.call("TYPE", messages_key)['ok'] == 'list' then 60 | oldestmsg(messages_key, channel_key ..':msg:%s') 61 | msgs_count = tonumber(redis.call('llen', messages_key)) 62 | else 63 | msgs_count = 0 64 | end 65 | 66 | local subscriber_count 67 | if use_accurate_subscriber_count then 68 | local sub_counts = tohash(redis.call("HGETALL", subscriber_counts)) 69 | subscriber_count = 0 70 | for k, v in pairs(sub_counts) do 71 | v = tonumber(v) 72 | local res = redis.call("PUBSUB", "NUMSUB", k) 73 | if tonumber(res[2]) >= 1 and v > 0 then 74 | subscriber_count = subscriber_count + tonumber(v) 75 | else 76 | redis.call("HDEL", subscriber_counts, k) 77 | end 78 | end 79 | else 80 | subscriber_count = tonumber(ch.fake_subscribers) or tonumber(ch.subscribers) 81 | end 82 | 83 | return { 84 | tonumber(ch.ttl) or 0, 85 | tonumber(ch.last_seen_fake_subscriber) or 0, 86 | subscriber_count or 0, 87 | ch.current_message or "", 88 | msgs_count 89 | } 90 | else 91 | return nil 92 | end 93 | -------------------------------------------------------------------------------- /src/store/redis/redis-lua-scripts/get_message_from_key.lua: -------------------------------------------------------------------------------- 1 | --input: keys: [message_key], values: [] 2 | --output: msg_ttl, msg_time, msg_tag, prev_msg_time, prev_msg_tag, message, content_type, eventsource_event, compression, channel_subscriber_count 3 | local key = KEYS[1] 4 | 5 | local ttl = redis.call('TTL', key) 6 | local time, tag, prev_time, prev_tag, data, content_type, es_event, compression = unpack(redis.call('HMGET', key, 'time', 'tag', 'prev_time', 'prev_tag', 'data', 'content_type', 'eventsource_event', 'compression')) 7 | 8 | return {ttl, time, tag, prev_time or 0, prev_tag or 0, data or "", content_type or "", es_event or "", tonumber(compression or 0)} 9 | -------------------------------------------------------------------------------- /src/store/redis/redis-lua-scripts/get_subscriber_info_id.lua: -------------------------------------------------------------------------------- 1 | --input: keys: [unique_request_id_key], values: [] 2 | --output: next_unique_request_id_integer 3 | local key = KEYS[1] 4 | 5 | redis.call("ECHO", "###### GET SUBSCRIBER INFO ID ##########") 6 | 7 | local resp = redis.pcall("INCR", key) 8 | local val 9 | if type(resp) ~= "number" then 10 | redis.call("SET", key, "0") 11 | val = redis.call("INCR", key) 12 | else 13 | val = resp 14 | end 15 | 16 | redis.call("ECHO", "val: " .. val) 17 | 18 | return val 19 | -------------------------------------------------------------------------------- /src/store/redis/redis-lua-scripts/nostore_publish_multiexec_channel_info.lua: -------------------------------------------------------------------------------- 1 | --input: keys: [], values: [ namespace, channel_id, use_accurate_subscriber_count ] 2 | --output: {subscribers_count, last_subscriber_seed}, or nil of channel not found 3 | 4 | local ns = ARGV[1] 5 | local id = ARGV[2] 6 | local use_accurate_subscriber_count = tonumber(ARGV[3]) ~= 0 7 | 8 | local channel_key = ('%s{channel:%s}'):format(ns, id) 9 | local subscriber_counts = channel_key..':subscriber_counts' 10 | 11 | redis.replicate_commands() 12 | 13 | redis.call('echo', ' ####### NOSTORE_PUBLISH_MULTIEXEC_CHANNEL_INFO ######## ') 14 | 15 | if redis.call('exists', channel_key) ~= 1 then 16 | return {0, 0} 17 | end 18 | 19 | local tohash=function(arr) 20 | if type(arr)~="table" then 21 | return nil 22 | end 23 | local h = {} 24 | local k=nil 25 | for i, v in ipairs(arr) do 26 | if k == nil then 27 | k=v 28 | else 29 | --dbg(k.."="..v) 30 | h[k]=v; k=nil 31 | end 32 | end 33 | return h 34 | end 35 | 36 | local last_seen = tonumber(redis.call('HGET', channel_key, 'last_seen_fake_subscriber')) 37 | 38 | local subscriber_count 39 | if use_accurate_subscriber_count then 40 | local sub_counts = tohash(redis.call("HGETALL", subscriber_counts)) 41 | subscriber_count = 0 42 | for k, v in pairs(sub_counts) do 43 | v = tonumber(v) 44 | local res = redis.call("PUBSUB", "NUMSUB", k) 45 | if tonumber(res[2]) >= 1 and v > 0 then 46 | subscriber_count = subscriber_count + tonumber(v) 47 | else 48 | redis.call("HDEL", subscriber_counts, k) 49 | end 50 | end 51 | else 52 | subscriber_count = tonumber(redis.call('HGET', channel_key, 'fake_subscribers')) 53 | end 54 | 55 | 56 | return {last_seen or 0, subscriber_count or 0} 57 | -------------------------------------------------------------------------------- /src/store/redis/redis-lua-scripts/request_subscriber_info.lua: -------------------------------------------------------------------------------- 1 | --input: keys: [], values: [ namespace, channel_id, info_response_id ] 2 | --output: -nothing- 3 | 4 | local ns = ARGV[1] 5 | local channel_id = ARGV[2] 6 | local response_id = tonumber(ARGV[3]) 7 | local pubsub = ('%s{channel:%s}:pubsub'):format(ns, channel_id) 8 | 9 | redis.call('echo', ' ####### REQUEST_SUBSCRIBER_INFO #######') 10 | 11 | local alert_msgpack =cmsgpack.pack({"alert", "subscriber info", response_id}) 12 | 13 | redis.call('PUBLISH', pubsub, alert_msgpack) 14 | 15 | return true 16 | -------------------------------------------------------------------------------- /src/store/redis/redis-lua-scripts/subscriber_register.lua: -------------------------------------------------------------------------------- 1 | --input: keys: [], values: [namespace, channel_id, subscriber_id, active_ttl_msec, ttl_safety_margin_msec, time, want_channel_settings] 2 | -- 'subscriber_id' can be '-' for new id, or an existing id 3 | -- 'active_ttl_msec' is channel ttl with non-zero subscribers. -1 to persist, >0 ttl in msec 4 | -- 'ttl_safety_margin_msec' is number of seconds before TTL that Nchan issues a keepalive recheck 5 | --output: subscriber_id, num_current_subscribers, next_keepalive_time, channel_buffer_length 6 | -- 'channel_buffer_length' is returned only if want_channel_settings is 1 7 | 8 | local ns, id, sub_id, active_ttl, ttl_safety_margin, time = ARGV[1], ARGV[2], ARGV[3], tonumber(ARGV[4]), tonumber(ARGV[5]), tonumber(ARGV[6]) 9 | local want_channel_settings = tonumber(ARGV[6]) == 1 10 | 11 | --local dbg = function(...) redis.call('echo', table.concat({...})); end 12 | 13 | redis.call('echo', ' ######## SUBSCRIBER REGISTER SCRIPT ####### ') 14 | local ch=("%s{channel:%s}"):format(ns, id) 15 | local keys = { 16 | channel = ch, 17 | messages = ch..':messages', 18 | subscribers = ch..':subscribers', 19 | subscriber_counts = ch..':subscriber_counts' 20 | } 21 | 22 | local setkeyttl=function(ttl) 23 | for i,v in pairs(keys) do 24 | if ttl > 0 then 25 | redis.call('PEXPIRE', v, ttl) 26 | else 27 | redis.call('PERSIST', v) 28 | end 29 | end 30 | end 31 | 32 | local sub_count 33 | 34 | if sub_id == "-" then 35 | sub_id = tonumber(redis.call('HINCRBY', keys.channel, "last_subscriber_id", 1)) 36 | sub_count=tonumber(redis.call('hincrby', keys.channel, 'subscribers', 1)) 37 | else 38 | sub_count=tonumber(redis.call('hget', keys.channel, 'subscribers')) 39 | end 40 | if time then 41 | redis.call('hset', keys.channel, "last_seen_subscriber", time) 42 | end 43 | 44 | local next_keepalive 45 | local actual_ttl = tonumber(redis.call('PTTL', keys.channel)) 46 | local safe_ttl = active_ttl + ttl_safety_margin 47 | if actual_ttl < safe_ttl then 48 | setkeyttl(safe_ttl) 49 | next_keepalive = active_ttl 50 | else 51 | next_keepalive = (actual_ttl - ttl_safety_margin > 0) and (actual_ttl - ttl_safety_margin) or math.ceil(actual_ttl / 2) 52 | end 53 | 54 | 55 | local ret = {sub_id, sub_count, next_keepalive} 56 | if want_channel_settings then 57 | local max_messages = tonumber(redis.call('hget', keys.channel, 'max_stored_messages')) 58 | table.insert(ret, max_messages) 59 | end 60 | 61 | return ret 62 | -------------------------------------------------------------------------------- /src/store/redis/redis-lua-scripts/subscriber_unregister.lua: -------------------------------------------------------------------------------- 1 | --input: keys: [], values: [namespace, channel_id, subscriber_id, empty_ttl] 2 | -- 'subscriber_id' is an existing id 3 | -- 'empty_ttl' is channel ttl when without subscribers. 0 to delete immediately, -1 to persist, >0 ttl in sec 4 | --output: subscriber_id, num_current_subscribers 5 | 6 | local ns, id, sub_id, empty_ttl = ARGV[1], ARGV[2], ARGV[3], tonumber(ARGV[4]) or 20 7 | 8 | --local dbg = function(...) redis.call('echo', table.concat({...})); end 9 | 10 | redis.call('echo', ' ######## SUBSCRIBER UNREGISTER SCRIPT ####### ') 11 | local ch=('%s{channel:%s}'):format(ns, id) 12 | local keys = { 13 | channel = ch, 14 | messages = ch..':messages', 15 | subscribers = ch..':subscribers', 16 | subscriber_counts = ch..':subscriber_counts' 17 | } 18 | 19 | local setkeyttl=function(ttl) 20 | for i,v in pairs(keys) do 21 | if ttl > 0 then 22 | redis.call('expire', v, ttl) 23 | elseif ttl < 0 then 24 | redis.call('persist', v) 25 | else 26 | redis.call('del', v) 27 | end 28 | end 29 | end 30 | 31 | local sub_count = 0 32 | 33 | local res = redis.pcall('EXISTS', keys.channel) 34 | if type(res) == "table" and res["err"] then 35 | return {err = ("CLUSTER KEYSLOT ERROR. %i %s"):format(empty_ttl, id)} 36 | end 37 | 38 | if res ~= 0 then 39 | sub_count = redis.call('hincrby', keys.channel, 'subscribers', -1) 40 | 41 | if sub_count == 0 and tonumber(redis.call('LLEN', keys.messages)) == 0 then 42 | setkeyttl(empty_ttl) 43 | elseif sub_count < 0 then 44 | return {err="Subscriber count for channel " .. id .. " less than zero: " .. sub_count} 45 | end 46 | else 47 | --dbg("channel ", id, " already gone") 48 | end 49 | 50 | return {sub_id, sub_count} 51 | -------------------------------------------------------------------------------- /src/store/redis/redis_nginx_adapter.h: -------------------------------------------------------------------------------- 1 | //Copyright (c) 2014 Wandenberg Peixoto under the MIT Licence 2 | //Coptright (c) 2015-2021 slact 3 | #ifndef __REDIS_NGINX_ADAPTER_H 4 | #define __REDIS_NGINX_ADAPTER_H 5 | 6 | #if NCHAN_HAVE_HIREDIS_WITH_SOCKADDR 7 | #include 8 | #include 9 | #else 10 | #include 11 | #include 12 | #endif 13 | 14 | #include 15 | #include 16 | 17 | void redis_nginx_init(void); 18 | int redis_nginx_event_attach(redisAsyncContext *ac); 19 | void redis_nginx_force_close_context(redisAsyncContext **context); 20 | void redis_nginx_close_context(redisAsyncContext **context); 21 | 22 | #endif // __REDIS_NGINX_ADAPTER_H 23 | -------------------------------------------------------------------------------- /src/store/redis/redis_nodeset_parser.h: -------------------------------------------------------------------------------- 1 | #ifndef REDIS_NODESET_PARSER_H 2 | #define REDIS_NODESET_PARSER_H 3 | 4 | #define MAX_CLUSTER_NODE_PARSED_LINES 512 5 | #define MAX_NODE_SLAVES_PARSED 512 6 | 7 | #include 8 | #include "store-private.h" 9 | 10 | typedef struct { 11 | ngx_str_t line; 12 | ngx_str_t id; //node id 13 | ngx_str_t address; //address as known by redis 14 | ngx_str_t hostname; 15 | ngx_int_t port; 16 | ngx_str_t flags; 17 | 18 | ngx_str_t master_id; //if slave 19 | ngx_str_t ping_sent; 20 | ngx_str_t pong_recv; 21 | ngx_str_t config_epoch; 22 | ngx_str_t link_state; //connected or disconnected 23 | 24 | ngx_str_t slots; 25 | ngx_int_t slot_ranges_count; 26 | 27 | unsigned connected:1; 28 | unsigned master:1; 29 | unsigned noaddr:1; 30 | unsigned failed:1; 31 | unsigned maybe_failed:1; 32 | unsigned handshake:1; 33 | unsigned self:1; 34 | } cluster_nodes_line_t; 35 | 36 | redis_connect_params_t *parse_info_slaves(redis_node_t *node, const char *info, size_t *count); 37 | redis_connect_params_t *parse_info_master(redis_node_t *node, const char *info); 38 | cluster_nodes_line_t *parse_cluster_nodes(redis_node_t *node, const char *clusternodes, size_t *count); 39 | int parse_cluster_node_slots(cluster_nodes_line_t *l, redis_slot_range_t *ranges); 40 | #endif /*REDIS_NODESET_PARSER_H */ 41 | -------------------------------------------------------------------------------- /src/store/redis/store.h: -------------------------------------------------------------------------------- 1 | #ifndef NCHAN_REDIS_STORE_H 2 | #define NCHAN_REDIS_STORE_H 3 | 4 | #define NCHAN_REDIS_DEFAULT_PING_INTERVAL_TIME 4*60 5 | #define NCHAN_REDIS_DEFAULT_PUBSUB_MESSAGE_MSGKEY_SIZE 1024*5 6 | extern const nchan_backoff_settings_t NCHAN_REDIS_DEFAULT_CLUSTER_CHECK_INTERVAL; 7 | extern const nchan_backoff_settings_t NCHAN_REDIS_DEFAULT_RECONNECT_DELAY; 8 | extern const nchan_backoff_settings_t NCHAN_REDIS_DEFAULT_CLUSTER_RECOVERY_DELAY; 9 | extern const nchan_backoff_settings_t NCHAN_REDIS_DEFAULT_IDLE_CHANNEL_TTL; 10 | 11 | extern nchan_store_t nchan_store_redis; 12 | 13 | ngx_int_t nchan_store_redis_fakesub_add(ngx_str_t *channel_id, nchan_loc_conf_t *cf, ngx_int_t count, uint8_t shutting_down); 14 | void redis_store_prepare_to_exit_worker(); // hark! a hack!! 15 | 16 | ngx_int_t nchan_store_redis_add_active_loc_conf(ngx_conf_t *cf, nchan_loc_conf_t *loc_conf); 17 | ngx_int_t nchan_store_redis_remove_active_loc_conf(ngx_conf_t *cf, nchan_loc_conf_t *loc_conf); 18 | 19 | int nchan_store_redis_ready(nchan_loc_conf_t *cf); 20 | int nchan_store_redis_validate_url(ngx_str_t *url); 21 | 22 | 23 | 24 | ngx_int_t redis_store_callback_on_connected(nchan_loc_conf_t *cf, ngx_msec_t max_wait, callback_pt cb, void *privdata); 25 | 26 | #endif // NCHAN_REDIS_STORE_H 27 | -------------------------------------------------------------------------------- /src/store/store_common.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "store_common.h" 3 | 4 | void nchan_exit_notice_about_remaining_things(char *thing, char *where, ngx_int_t num) { 5 | if(num > 0) { 6 | nchan_log_notice("%i %s%s remain%s %sat exit", num, thing, num == 1 ? "" : "s", num == 1 ? "s" : "", where == NULL ? "" : where); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/store/store_common.h: -------------------------------------------------------------------------------- 1 | #undef uthash_malloc 2 | #undef uthash_free 3 | #define uthash_malloc(sz) ngx_alloc(sz, ngx_cycle->log) 4 | #define uthash_free(ptr,sz) ngx_free(ptr) 5 | 6 | #define STR(buf) (buf)->data, (buf)->len 7 | #define BUF(buf) (buf)->pos, ((buf)->last - (buf)->pos) 8 | 9 | #define NCHAN_DEFAULT_SUBSCRIBER_POOL_SIZE (5 * 1024) 10 | #define NCHAN_DEFAULT_CHANHEAD_CLEANUP_INTERVAL 1000 11 | 12 | void nchan_exit_notice_about_remaining_things(char *thing, char *where, ngx_int_t num); 13 | -------------------------------------------------------------------------------- /src/subscribers/benchmark.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "internal.h" 4 | #include "benchmark.h" 5 | #include 6 | 7 | //#define DEBUG_LEVEL NGX_LOG_WARN 8 | #define DEBUG_LEVEL NGX_LOG_DEBUG 9 | 10 | #define DBG(fmt, arg...) ngx_log_error(DEBUG_LEVEL, ngx_cycle->log, 0, "SUB:BENCHMARK:" fmt, ##arg) 11 | #define ERR(fmt, arg...) ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "SUB:BENCHMARK:" fmt, ##arg) 12 | 13 | typedef struct { 14 | subscriber_t *sub; 15 | nchan_benchmark_t *bench; 16 | } sub_data_t; 17 | 18 | static ngx_int_t sub_enqueue(ngx_int_t status, void *ptr, sub_data_t *d) { 19 | if(nchan_benchmark_active()) { 20 | ngx_atomic_fetch_add(d->bench->shared.subscribers_enqueued, 1); 21 | } 22 | nchan_stats_worker_incr(subscribers, 1); //needs to be done manually for INTERNAL subs 23 | return NGX_OK; 24 | } 25 | 26 | static ngx_int_t sub_dequeue(ngx_int_t status, void *ptr, sub_data_t* d) { 27 | if(nchan_benchmark_active()) { 28 | ngx_atomic_fetch_add(d->bench->shared.subscribers_dequeued, 1); 29 | } 30 | nchan_stats_worker_incr(subscribers, -1); //needs to be done manually for INTERNAL subs 31 | return NGX_OK; 32 | } 33 | 34 | static ngx_int_t sub_respond_message(ngx_int_t status, void *ptr, sub_data_t* d) { 35 | nchan_msg_t *msg = ptr; 36 | uint64_t msec = nchan_benchmark_message_delivery_msec(msg); 37 | if(nchan_benchmark_active()) { 38 | hdr_record_value(d->bench->data.msg_delivery_latency, msec); 39 | d->bench->data.msg_received++; 40 | } 41 | return NGX_OK; 42 | } 43 | 44 | static ngx_int_t sub_respond_status(ngx_int_t status, void *ptr, sub_data_t *d) { 45 | return NGX_OK; 46 | } 47 | 48 | static ngx_int_t sub_respond_notice(ngx_int_t notice, void *ptr, sub_data_t *d) { 49 | return NGX_OK; 50 | } 51 | 52 | static ngx_str_t sub_name = ngx_string("benchmark"); 53 | 54 | subscriber_t *benchmark_subscriber_create(nchan_benchmark_t *bench) { 55 | static nchan_msg_id_t newest_msgid = NCHAN_NEWEST_MSGID; 56 | sub_data_t *d; 57 | subscriber_t *sub; 58 | nchan_loc_conf_t *cf = bench->loc_conf; 59 | struct timeval tv; 60 | 61 | sub = internal_subscriber_create_init(&sub_name, cf, sizeof(*d), (void **)&d, (callback_pt )sub_enqueue, (callback_pt )sub_dequeue, (callback_pt )sub_respond_message, (callback_pt )sub_respond_status, (callback_pt )sub_respond_notice, NULL); 62 | 63 | sub->last_msgid = newest_msgid; 64 | sub->destroy_after_dequeue = 1; 65 | d->sub = sub; 66 | d->bench = bench; 67 | ngx_gettimeofday(&tv); 68 | 69 | 70 | DBG("%p benchmark subscriber created with privdata %p", sub, d); 71 | return sub; 72 | } 73 | -------------------------------------------------------------------------------- /src/subscribers/benchmark.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | subscriber_t *benchmark_subscriber_create(nchan_benchmark_t *bench); 4 | -------------------------------------------------------------------------------- /src/subscribers/common.h: -------------------------------------------------------------------------------- 1 | ngx_int_t nchan_subscriber_subscribe(subscriber_t *sub, ngx_str_t *ch_id); 2 | 3 | ngx_int_t nchan_subscriber_authorize_subscribe_request(subscriber_t *sub, ngx_str_t *ch_id); 4 | ngx_int_t nchan_subscriber_subscribe_request(subscriber_t *sub); 5 | ngx_int_t nchan_subscriber_unsubscribe_request(subscriber_t *sub); 6 | ngx_int_t nchan_subscriber_subrequest_cleanup(subscriber_t *sub); 7 | 8 | ngx_int_t nchan_cleverly_output_headers_only_for_later_response(ngx_http_request_t *r); 9 | 10 | ngx_str_t *nchan_request_multipart_boundary(ngx_http_request_t *r, nchan_request_ctx_t *ctx); 11 | 12 | ngx_int_t nchan_request_set_content_type_multipart_boundary_header(ngx_http_request_t *r, nchan_request_ctx_t *ctx); 13 | 14 | ngx_int_t nchan_subscriber_receive_notice(subscriber_t *, ngx_int_t code, void *data); 15 | 16 | 17 | nchan_fakereq_subrequest_data_t *nchan_subscriber_subrequest(subscriber_t *sub, nchan_requestmachine_request_params_t *params); 18 | 19 | 20 | void nchan_subscriber_timeout_ev_handler(ngx_event_t *ev); 21 | void nchan_subscriber_init(subscriber_t *sub, const subscriber_t *tmpl, ngx_http_request_t *r, nchan_msg_id_t *msgid); 22 | void nchan_subscriber_init_timeout_timer(subscriber_t *sub, ngx_event_t *ev); 23 | void nchan_subscriber_common_setup(subscriber_t *sub, subscriber_type_t type, ngx_str_t *name, subscriber_fn_t *fn, ngx_int_t enable_sub_unsub_callbacks, ngx_int_t dequeue_after_response); 24 | ngx_int_t nchan_subscriber_init_msgid_reusepool(nchan_request_ctx_t *ctx, ngx_pool_t *request_pool); 25 | ngx_str_t nchan_subscriber_set_recyclable_msgid_str(nchan_request_ctx_t *ctx, nchan_msg_id_t *msgid); 26 | 27 | ngx_int_t nchan_subscriber_publish_info(subscriber_t *sub, uintptr_t channel_id_number); 28 | -------------------------------------------------------------------------------- /src/subscribers/eventsource.h: -------------------------------------------------------------------------------- 1 | subscriber_t *eventsource_subscriber_create(ngx_http_request_t *r, nchan_msg_id_t *msg_id); 2 | //ngx_int_t eventsource_subscriber_destroy(subscriber_t *sub); 3 | 4 | ngx_int_t nchan_detect_eventsource_request(ngx_http_request_t *r); -------------------------------------------------------------------------------- /src/subscribers/getmsg_proxy.h: -------------------------------------------------------------------------------- 1 | subscriber_t *getmsg_proxy_subscriber_create(nchan_msg_id_t *msgid, callback_pt cb, void *pd); 2 | -------------------------------------------------------------------------------- /src/subscribers/http-chunked.h: -------------------------------------------------------------------------------- 1 | subscriber_t *http_chunked_subscriber_create(ngx_http_request_t *r, nchan_msg_id_t *msg_id); 2 | //ngx_int_t http_chunked_subscriber_destroy(subscriber_t *sub); 3 | 4 | ngx_int_t nchan_detect_chunked_subscriber_request(ngx_http_request_t *r); -------------------------------------------------------------------------------- /src/subscribers/http-multipart-mixed.h: -------------------------------------------------------------------------------- 1 | subscriber_t *http_multipart_subscriber_create(ngx_http_request_t *r, nchan_msg_id_t *msg_id); 2 | 3 | ngx_int_t nchan_detect_multipart_subscriber_request(ngx_http_request_t *r); -------------------------------------------------------------------------------- /src/subscribers/http-raw-stream.h: -------------------------------------------------------------------------------- 1 | subscriber_t *http_raw_stream_subscriber_create(ngx_http_request_t *r, nchan_msg_id_t *msg_id); 2 | -------------------------------------------------------------------------------- /src/subscribers/internal.h: -------------------------------------------------------------------------------- 1 | #define NCHAN_DEFAULT_INTERNAL_SUBSCRIBER_POOL_SIZE 1024 2 | 3 | typedef struct { 4 | subscriber_t sub; 5 | callback_pt enqueue; 6 | callback_pt dequeue; 7 | callback_pt respond_message; 8 | callback_pt respond_status; 9 | callback_pt notify; 10 | callback_pt destroy; 11 | ngx_event_t timeout_ev; 12 | subscriber_callback_pt enqueue_callback; 13 | void *enqueue_callback_data; 14 | subscriber_callback_pt dequeue_callback; 15 | void *dequeue_callback_data; 16 | void *privdata; 17 | unsigned already_dequeued:1; 18 | unsigned awaiting_destruction:1; 19 | } internal_subscriber_t; 20 | 21 | extern subscriber_t *internal_subscriber_create(ngx_str_t *, nchan_loc_conf_t *cf, size_t pd_sz, void **pd); 22 | extern ngx_int_t internal_subscriber_destroy(subscriber_t *sub); 23 | 24 | subscriber_t *internal_subscriber_create_init(ngx_str_t *sub_name, nchan_loc_conf_t *cf, size_t pd_sz, void **pd, callback_pt enqueue, callback_pt dequeue, callback_pt respond_message, callback_pt respond_status, callback_pt notify_handler, callback_pt destroy_handler); 25 | ngx_int_t internal_subscriber_set_name(subscriber_t *sub, ngx_str_t *name); 26 | ngx_int_t internal_subscriber_set_enqueue_handler(subscriber_t *sub, callback_pt handler); 27 | ngx_int_t internal_subscriber_set_dequeue_handler(subscriber_t *sub, callback_pt handler); 28 | ngx_int_t internal_subscriber_set_notify_handler(subscriber_t *sub, callback_pt handler); 29 | ngx_int_t internal_subscriber_set_respond_message_handler(subscriber_t *sub, callback_pt handler); 30 | ngx_int_t internal_subscriber_set_respond_status_handler(subscriber_t *sub, callback_pt handler); 31 | ngx_int_t internal_subscriber_set_destroy_handler(subscriber_t *sub, callback_pt handler); 32 | void *internal_subscriber_get_privdata(subscriber_t *sub); 33 | -------------------------------------------------------------------------------- /src/subscribers/intervalpoll.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "longpoll.h" 4 | #include "longpoll-private.h" 5 | #include "intervalpoll.h" 6 | 7 | //#define DEBUG_LEVEL NGX_LOG_WARN 8 | #define DEBUG_LEVEL NGX_LOG_DEBUG 9 | 10 | #define DBG(fmt, arg...) ngx_log_error(DEBUG_LEVEL, ngx_cycle->log, 0, "SUB:INTERVALPOLL:" fmt, ##arg) 11 | #define ERR(fmt, arg...) ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "SUB:INTERVALPOLL:" fmt, ##arg) 12 | #include 13 | 14 | static ngx_str_t sub_name = ngx_string("intervalpoll"); 15 | 16 | subscriber_t *intervalpoll_subscriber_create(ngx_http_request_t *r, nchan_msg_id_t *msg_id) { 17 | subscriber_t *sub; 18 | full_subscriber_t *fsub; 19 | nchan_request_ctx_t *ctx = ngx_http_get_module_ctx(r, ngx_nchan_module); 20 | sub = longpoll_subscriber_create(r, msg_id); 21 | 22 | fsub = (full_subscriber_t *)sub; 23 | 24 | fsub->data.act_as_intervalpoll = 1; 25 | 26 | sub->name = &sub_name; 27 | sub->type = INTERVALPOLL; 28 | 29 | if(ctx) { 30 | ctx->subscriber_type = sub->name; 31 | } 32 | return sub; 33 | } 34 | -------------------------------------------------------------------------------- /src/subscribers/intervalpoll.h: -------------------------------------------------------------------------------- 1 | subscriber_t *intervalpoll_subscriber_create(ngx_http_request_t *r, nchan_msg_id_t *msg_id); -------------------------------------------------------------------------------- /src/subscribers/longpoll-private.h: -------------------------------------------------------------------------------- 1 | typedef struct nchan_longpoll_multimsg_s nchan_longpoll_multimsg_t; 2 | struct nchan_longpoll_multimsg_s { 3 | nchan_msg_t *msg; 4 | nchan_longpoll_multimsg_t *next; 5 | }; 6 | 7 | typedef struct { 8 | ngx_http_cleanup_t *cln; 9 | subscriber_callback_pt enqueue_callback; 10 | void *enqueue_callback_data; 11 | subscriber_callback_pt dequeue_callback; 12 | void *dequeue_callback_data; 13 | ngx_event_t timeout_ev; 14 | ngx_event_t ping_ev; 15 | 16 | nchan_longpoll_multimsg_t *multimsg_first; 17 | nchan_longpoll_multimsg_t *multimsg_last; 18 | 19 | unsigned act_as_intervalpoll:1; 20 | unsigned holding:1; 21 | unsigned finalize_request:1; 22 | unsigned already_responded:1; 23 | unsigned awaiting_destruction:1; 24 | unsigned shook_hands:1; 25 | } subscriber_data_t; 26 | 27 | typedef struct { 28 | subscriber_t sub; 29 | subscriber_data_t data; 30 | void *privdata; 31 | } full_subscriber_t; 32 | 33 | ngx_int_t longpoll_enqueue(subscriber_t *self); 34 | ngx_int_t longpoll_dequeue(subscriber_t *self); 35 | 36 | void subscriber_maybe_dequeue_after_status_response(full_subscriber_t *fsub, ngx_int_t status_code); 37 | 38 | ngx_int_t subscriber_respond_unqueued_status(full_subscriber_t *fsub, ngx_int_t status_code, const ngx_str_t *status_line, ngx_chain_t *status_body); 39 | -------------------------------------------------------------------------------- /src/subscribers/longpoll.h: -------------------------------------------------------------------------------- 1 | subscriber_t *longpoll_subscriber_create(ngx_http_request_t *r, nchan_msg_id_t *msg_id); 2 | ngx_int_t longpoll_subscriber_destroy(subscriber_t *sub); -------------------------------------------------------------------------------- /src/subscribers/memstore_ipc.h: -------------------------------------------------------------------------------- 1 | #define MEMSTORE_IPC_SUBSCRIBER_TIMEOUT 5 2 | subscriber_t *memstore_ipc_subscriber_create(ngx_int_t originator_slot, ngx_str_t *chid, nchan_loc_conf_t *cf, void* foreign_chanhead); 3 | 4 | ngx_int_t memstore_ipc_subscriber_unhook(subscriber_t *sub); 5 | ngx_int_t memstore_ipc_subscriber_keepalive_renew(subscriber_t *sub); 6 | -------------------------------------------------------------------------------- /src/subscribers/memstore_multi.h: -------------------------------------------------------------------------------- 1 | #define NCHAN_SUB_MULTI_NOTIFY_ADDSUB 0 2 | subscriber_t *memstore_multi_subscriber_create(memstore_channel_head_t *chanhead, uint8_t n); 3 | -------------------------------------------------------------------------------- /src/subscribers/memstore_redis.h: -------------------------------------------------------------------------------- 1 | #define MEMSTORE_REDIS_SUBSCRIBER_TIMEOUT 10 2 | subscriber_t *memstore_redis_subscriber_create(memstore_channel_head_t *chanhead); 3 | ngx_int_t memstore_redis_subscriber_destroy(subscriber_t *sub); 4 | -------------------------------------------------------------------------------- /src/subscribers/websocket.h: -------------------------------------------------------------------------------- 1 | subscriber_t *websocket_subscriber_create(ngx_http_request_t *r, nchan_msg_id_t *msg_id); 2 | ngx_int_t websocket_subscriber_destroy(subscriber_t *sub); 3 | ngx_int_t websocket_intercept_published_message(subscriber_t *sub, void (*)(subscriber_t *, nchan_msg_t *)); 4 | 5 | ngx_int_t nchan_detect_websocket_request(ngx_http_request_t *r); 6 | -------------------------------------------------------------------------------- /src/util/nchan_accumulator.h: -------------------------------------------------------------------------------- 1 | #ifndef NCHAN_ACCUMULATOR_H 2 | #define NCHAN_ACCUMULATOR_H 3 | 4 | #include 5 | #include 6 | 7 | typedef enum { 8 | ACCUMULATOR_EXP_DECAY_FLOAT, 9 | ACCUMULATOR_SUM 10 | } nchan_accumulator_type_t; 11 | 12 | 13 | typedef struct { 14 | double value; 15 | double weight; 16 | double lambda; 17 | } nchan_accumulator_float_exponentially_decayed_data_t; 18 | 19 | typedef struct { 20 | ngx_atomic_int_t value; 21 | ngx_atomic_int_t weight; 22 | } nchan_accumulator_sum_data_t; 23 | 24 | typedef struct { 25 | union { 26 | nchan_accumulator_float_exponentially_decayed_data_t ed_float; 27 | nchan_accumulator_sum_data_t sum; 28 | } data; 29 | 30 | ngx_time_t last_update; 31 | 32 | nchan_accumulator_type_t type; 33 | } nchan_accumulator_t; 34 | 35 | int nchan_accumulator_update(nchan_accumulator_t *acc, double val); 36 | int nchan_accumulator_atomic_update(nchan_accumulator_t *acc, double val); 37 | 38 | double nchan_accumulator_value(nchan_accumulator_t *acc); 39 | double nchan_accumulator_weight(nchan_accumulator_t *acc); 40 | double nchan_accumulator_value(nchan_accumulator_t *acc); 41 | int nchan_accumulator_init(nchan_accumulator_t *acc, nchan_accumulator_type_t type, double halflife); 42 | int nchan_accumulator_merge(nchan_accumulator_t *merge_dst, nchan_accumulator_t *merge_src); 43 | void nchan_accumulator_reset(nchan_accumulator_t *acc); 44 | 45 | #endif //NCHAN_ACCUMULATOR_H 46 | -------------------------------------------------------------------------------- /src/util/nchan_benchmark.h: -------------------------------------------------------------------------------- 1 | #ifndef NCHAN_BENCHMARK_H 2 | #define NCHAN_BENCHMARK_H 3 | 4 | #include 5 | #include 6 | 7 | typedef struct { 8 | struct hdr_histogram* msg_publishing_latency; 9 | struct hdr_histogram* msg_delivery_latency; 10 | struct hdr_histogram* subscriber_readiness_latency; 11 | uint64_t msg_sent; 12 | uint64_t msg_send_confirmed; 13 | uint64_t msg_send_failed; 14 | uint64_t msg_received; 15 | } nchan_benchmark_data_t; 16 | 17 | typedef struct { 18 | uint64_t n; 19 | ngx_atomic_t msg_count; 20 | u_char *msgbuf; 21 | } nchan_benchmark_channel_t; 22 | 23 | typedef struct { 24 | ngx_atomic_t *subscribers_enqueued; 25 | ngx_atomic_t *subscribers_dequeued; 26 | nchan_benchmark_channel_t *channels; 27 | } nchan_benchmark_shared_t; 28 | 29 | 30 | #define NCHAN_BENCHMARK_INACTIVE 0 31 | #define NCHAN_BENCHMARK_INITIALIZING 1 32 | #define NCHAN_BENCHMARK_READY 2 33 | #define NCHAN_BENCHMARK_RUNNING 3 34 | #define NCHAN_BENCHMARK_FINISHED 4 35 | 36 | typedef struct nchan_benchmark_s nchan_benchmark_t; 37 | struct nchan_benchmark_s { 38 | subscriber_t *client; 39 | nchan_benchmark_conf_t *config; 40 | nchan_loc_conf_t *loc_conf; 41 | uint32_t id; 42 | struct { 43 | time_t init; 44 | time_t start; 45 | time_t end; 46 | } time; 47 | struct { 48 | void *ready; 49 | void *running; 50 | void *finishing; 51 | void **publishers; 52 | } timer; 53 | u_char *msgbuf; 54 | ngx_atomic_int_t *state; 55 | struct { 56 | size_t n; 57 | subscriber_t **array; 58 | } subs; 59 | unsigned base_msg_period; 60 | int waiting_for_results; 61 | nchan_benchmark_shared_t shared; 62 | nchan_benchmark_data_t data; 63 | 64 | }; //nchan_benchmark_t 65 | 66 | int nchan_benchmark_active(void); 67 | 68 | ngx_int_t nchan_benchmark_init_module(ngx_cycle_t *cycle); 69 | ngx_int_t nchan_benchmark_init_worker(ngx_cycle_t *cycle); 70 | ngx_int_t nchan_benchmark_exit_master(ngx_cycle_t *cycle); 71 | 72 | ngx_int_t nchan_benchmark_initialize(void); 73 | ngx_int_t nchan_benchmark_initialize_from_ipc(ngx_int_t initiating_worker_slot, nchan_loc_conf_t *cf, time_t time_start, uint32_t id, nchan_benchmark_shared_t *shared_data); 74 | ngx_int_t nchan_benchmark_run(void); 75 | 76 | ngx_int_t nchan_benchmark_stop(void); 77 | ngx_int_t nchan_benchmark_dequeue_subscribers(void); 78 | ngx_int_t nchan_benchmark_finish_response(void); 79 | ngx_str_t *nchan_hdrhistogram_serialize(const struct hdr_histogram* hdr, ngx_pool_t *pool); 80 | ngx_int_t nchan_benchmark_receive_finished_data(nchan_benchmark_data_t *data); 81 | ngx_int_t nchan_benchmark_finish(void); 82 | ngx_int_t nchan_benchmark_abort(void); 83 | ngx_int_t nchan_benchmark_cleanup(void); 84 | 85 | ngx_int_t nchan_benchmark_channel_id(int n, ngx_str_t *chid); 86 | uint64_t nchan_benchmark_message_delivery_msec(nchan_msg_t *msg); 87 | nchan_benchmark_t *nchan_benchmark_get_active(void); 88 | 89 | 90 | ngx_int_t nchan_benchmark_ws_initialize(ngx_http_request_t *r); 91 | #endif //NCHAN_BENCHMARK_H 92 | -------------------------------------------------------------------------------- /src/util/nchan_bufchainpool.h: -------------------------------------------------------------------------------- 1 | #ifndef NCHAN_BUFCHAINPOOL_H 2 | #define NCHAN_BUFCHAINPOOL_H 3 | #include 4 | 5 | typedef struct { 6 | ngx_chain_t chain; 7 | ngx_buf_t buf; 8 | } nchan_buf_and_chain_t; 9 | 10 | typedef struct nchan_bufchain_link_s nchan_bufchain_link_t; 11 | struct nchan_bufchain_link_s { 12 | nchan_bufchain_link_t *next; 13 | nchan_buf_and_chain_t bc; 14 | }; 15 | 16 | typedef struct nchan_file_link_s nchan_file_link_t; 17 | struct nchan_file_link_s{ 18 | nchan_file_link_t *next; 19 | ngx_file_t file; 20 | }; 21 | 22 | typedef struct { 23 | ngx_int_t bc_count; 24 | ngx_int_t file_count; 25 | ngx_int_t bc_recycle_count; 26 | ngx_int_t file_recycle_count; 27 | nchan_bufchain_link_t *bc_head; 28 | nchan_bufchain_link_t *bc_recycle_head; 29 | nchan_file_link_t *file_head; 30 | nchan_file_link_t *file_recycle_head; 31 | ngx_pool_t *pool; 32 | 33 | struct { 34 | size_t length; 35 | ngx_int_t count; 36 | ngx_chain_t *head; 37 | ngx_chain_t *tail; 38 | 39 | ngx_int_t recycle_count; 40 | ngx_chain_t *recycle_head; 41 | } bc; 42 | } nchan_bufchain_pool_t; 43 | 44 | ngx_int_t nchan_bufchain_pool_init(nchan_bufchain_pool_t *bcp, ngx_pool_t *pool); 45 | nchan_buf_and_chain_t *nchan_bufchain_pool_reserve(nchan_bufchain_pool_t *bcp, ngx_int_t count); 46 | ngx_file_t *nchan_bufchain_pool_reserve_file(nchan_bufchain_pool_t *bcp); 47 | void nchan_bufchain_pool_refresh_files(nchan_bufchain_pool_t *bcp); 48 | void nchan_bufchain_pool_flush(nchan_bufchain_pool_t *bcp); 49 | 50 | ngx_chain_t *nchan_bufchain_first_chain(nchan_bufchain_pool_t *bcp); 51 | size_t nchan_bufchain_length(nchan_bufchain_pool_t *bcp); 52 | ngx_int_t nchan_bufchain_append_buf(nchan_bufchain_pool_t *bcp, ngx_buf_t *buf); 53 | ngx_int_t nchan_bufchain_append_str(nchan_bufchain_pool_t *bcp, ngx_str_t *str); 54 | ngx_int_t nchan_bufchain_append_cstr(nchan_bufchain_pool_t *bcp, char *cstr); 55 | 56 | #endif //NCHAN_BUFCHAINPOOL_H 57 | -------------------------------------------------------------------------------- /src/util/nchan_channel_id.h: -------------------------------------------------------------------------------- 1 | ngx_str_t *nchan_get_channel_id(ngx_http_request_t *r, pub_or_sub_t what, ngx_int_t fail_hard); 2 | ngx_int_t nchan_channel_id_is_multi(ngx_str_t *id); 3 | ngx_str_t *nchan_get_group_name(ngx_http_request_t *r, nchan_loc_conf_t *cf, nchan_request_ctx_t *ctx); 4 | ngx_str_t nchan_get_group_from_channel_id(ngx_str_t *id); 5 | 6 | ngx_str_t *nchan_get_subscriber_info_response_channel_id(ngx_http_request_t *r, uintptr_t request_id); 7 | -------------------------------------------------------------------------------- /src/util/nchan_debug.c: -------------------------------------------------------------------------------- 1 | #include "nchan_debug.h" 2 | #include 3 | 4 | #define STRINGIFY_ENUM(val) \ 5 | case val: \ 6 | return #val; 7 | 8 | char *nchan_msg_status_to_cstr(nchan_msg_status_t status) { 9 | switch(status) { 10 | STRINGIFY_ENUM(MSG_CHANNEL_NOTREADY) 11 | STRINGIFY_ENUM(MSG_INVALID) 12 | STRINGIFY_ENUM(MSG_PENDING) 13 | STRINGIFY_ENUM(MSG_NOTFOUND) 14 | STRINGIFY_ENUM(MSG_FOUND) 15 | STRINGIFY_ENUM(MSG_EXPECTED) 16 | STRINGIFY_ENUM(MSG_EXPIRED) 17 | STRINGIFY_ENUM(MSG_ERROR) 18 | } 19 | return "???"; 20 | } 21 | 22 | #if NCHAN_SUBSCRIBER_LEAK_DEBUG 23 | 24 | subscriber_t *subdebug_head = NULL; 25 | 26 | void subscriber_debug_add(subscriber_t *sub) { 27 | if(subdebug_head == NULL) { 28 | sub->dbg_next = NULL; 29 | sub->dbg_prev = NULL; 30 | } 31 | else { 32 | sub->dbg_next = subdebug_head; 33 | sub->dbg_prev = NULL; 34 | assert(subdebug_head->dbg_prev == NULL); 35 | subdebug_head->dbg_prev = sub; 36 | } 37 | if(sub->request) { 38 | sub->lbl = ngx_calloc(sub->request->uri.len+1, ngx_cycle->log); 39 | ngx_memcpy(sub->lbl, sub->request->uri.data, sub->request->uri.len); 40 | } 41 | else { 42 | sub->lbl = NULL; 43 | } 44 | 45 | subdebug_head = sub; 46 | } 47 | void subscriber_debug_remove(subscriber_t *sub) { 48 | subscriber_t *prev, *next; 49 | prev = sub->dbg_prev; 50 | next = sub->dbg_next; 51 | if(subdebug_head == sub) { 52 | assert(sub->dbg_prev == NULL); 53 | if(next) { 54 | next->dbg_prev = NULL; 55 | } 56 | subdebug_head = next; 57 | } 58 | else { 59 | if(prev) { 60 | prev->dbg_next = next; 61 | } 62 | if(next) { 63 | next->dbg_prev = prev; 64 | } 65 | } 66 | 67 | sub->dbg_next = NULL; 68 | sub->dbg_prev = NULL; 69 | ngx_free(sub->lbl); 70 | sub->lbl = NULL; 71 | } 72 | void subscriber_debug_assert_isempty(void) { 73 | if(subdebug_head != NULL) { 74 | subscriber_t *cur; 75 | for(cur = subdebug_head; cur != NULL; cur = cur->dbg_next) { 76 | nchan_log_error(" LEFTOVER: %V sub (req. %p (pool %p) cf %p rsv: %d) lbl %s", cur->name, cur->request, cur->request ? cur->request->pool : NULL, cur->cf, cur->reserved, cur->lbl ? cur->lbl : (u_char *)"nolbl"); 77 | } 78 | raise(SIGABRT); 79 | } 80 | } 81 | #endif 82 | -------------------------------------------------------------------------------- /src/util/nchan_debug.h: -------------------------------------------------------------------------------- 1 | #ifndef NCHAN_DEBUG_H 2 | #define NCHAN_DEBUG_H 3 | #include 4 | 5 | char *nchan_msg_status_to_cstr(nchan_msg_status_t status); 6 | 7 | #if NCHAN_SUBSCRIBER_LEAK_DEBUG 8 | void subscriber_debug_add(subscriber_t *); 9 | void subscriber_debug_remove(subscriber_t *); 10 | void subscriber_debug_assert_isempty(void); 11 | #endif 12 | 13 | #endif //NCHAN_DEBUG_H 14 | -------------------------------------------------------------------------------- /src/util/nchan_fake_request.h: -------------------------------------------------------------------------------- 1 | #ifndef NCHAN_FAKE_REQUEST_H 2 | #define NCHAN_FAKE_REQUEST_H 3 | 4 | #include 5 | #include 6 | 7 | ngx_http_request_t *nchan_create_derivative_fake_request(ngx_connection_t *c, ngx_http_request_t *rsrc); 8 | void nchan_finalize_fake_request(ngx_http_request_t *r, ngx_int_t rc); 9 | void nchan_free_fake_request(ngx_http_request_t *r); 10 | 11 | typedef struct nchan_fakereq_subrequest_data_s nchan_fakereq_subrequest_data_t; 12 | typedef struct nchan_requestmachine_s nchan_requestmachine_t; 13 | 14 | struct nchan_fakereq_subrequest_data_s { 15 | ngx_http_request_t *r; 16 | ngx_http_request_t *sr; 17 | void *pd; 18 | callback_pt cb; 19 | nchan_requestmachine_t *rm; 20 | ngx_event_t cleanup_timer; 21 | unsigned manual_cleanup:1; 22 | unsigned running:1; 23 | unsigned aborted:1; 24 | struct { 25 | nchan_fakereq_subrequest_data_t *prev; 26 | nchan_fakereq_subrequest_data_t *next; 27 | } slist; 28 | };// nchan_fakereq_subrequest_data_t 29 | 30 | struct nchan_requestmachine_s { 31 | ngx_http_request_t *template_request; 32 | nchan_slist_t request_queue; 33 | unsigned shutdown_when_finished; 34 | };// nchan_requestmachine_t; 35 | 36 | typedef struct { 37 | union { 38 | ngx_str_t *str; 39 | ngx_http_complex_value_t *cv; 40 | } url; 41 | ngx_pool_t *pool; 42 | ngx_buf_t *body; 43 | 44 | callback_pt cb; 45 | void *pd; 46 | unsigned manual_cleanup:1; 47 | unsigned response_headers_only:1; 48 | unsigned url_complex:1; 49 | } nchan_requestmachine_request_params_t; 50 | 51 | ngx_int_t nchan_requestmachine_initialize(nchan_requestmachine_t *rm, ngx_http_request_t *template_request); 52 | nchan_fakereq_subrequest_data_t *nchan_requestmachine_request(nchan_requestmachine_t *rm, nchan_requestmachine_request_params_t *params); 53 | ngx_int_t nchan_requestmachine_request_cleanup_manual(nchan_fakereq_subrequest_data_t *d); 54 | ngx_int_t nchan_requestmachine_request_cleanup_on_request_finalize(nchan_fakereq_subrequest_data_t *d, ngx_http_request_t *r); 55 | ngx_int_t nchan_requestmachine_abort(nchan_requestmachine_t *rm); 56 | ngx_int_t nchan_requestmachine_shutdown(nchan_requestmachine_t *rm); 57 | 58 | #endif //NCHAN_FAKE_REQUEST_H 59 | -------------------------------------------------------------------------------- /src/util/nchan_list.h: -------------------------------------------------------------------------------- 1 | #ifndef NCHAN_LIST_H 2 | #define NCHAN_LIST_H 3 | 4 | #define NCHAN_LIST_DEBUG 1 5 | 6 | #include 7 | #include 8 | 9 | typedef struct nchan_list_el_s nchan_list_el_t; 10 | 11 | struct nchan_list_el_s { 12 | nchan_list_el_t *prev; 13 | nchan_list_el_t *next; 14 | }; 15 | 16 | typedef struct { 17 | #if NCHAN_LIST_DEBUG 18 | char *name; 19 | #endif 20 | nchan_list_el_t *head; 21 | nchan_list_el_t *tail; 22 | ngx_uint_t n; 23 | size_t data_sz; 24 | ngx_pool_t *pool; 25 | size_t pool_sz; 26 | } nchan_list_t; 27 | 28 | ngx_int_t nchan_list_init(nchan_list_t *list, size_t data_sz, char *name); 29 | ngx_int_t nchan_list_pool_init(nchan_list_t *list, size_t data_sz, size_t pool_sz, char *name); 30 | ngx_pool_t *nchan_list_get_pool(nchan_list_t *list); 31 | 32 | void *nchan_list_append(nchan_list_t *list); 33 | void *nchan_list_prepend(nchan_list_t *list); 34 | 35 | void *nchan_list_first(nchan_list_t *list); 36 | void *nchan_list_last(nchan_list_t *list); 37 | void *nchan_list_prev(void *data); 38 | void *nchan_list_next(void *data); 39 | 40 | size_t nchan_list_count(nchan_list_t *list); 41 | 42 | void *nchan_list_prepend_sized(nchan_list_t *list, size_t sz); 43 | void *nchan_list_append_sized(nchan_list_t *list, size_t sz); 44 | 45 | ngx_int_t nchan_list_remove(nchan_list_t *list, void *el_data); 46 | ngx_int_t nchan_list_empty(nchan_list_t *list); 47 | ngx_int_t nchan_list_traverse_and_empty(nchan_list_t *list, void (*)(void *data, void *pd), void *pd); 48 | 49 | #define nchan_list_el_from_data(el_data) \ 50 | ((nchan_list_el_t *)el_data - 1) 51 | #define nchan_list_data_from_el(el) \ 52 | ((void *)&el[1]) 53 | 54 | #endif //NCHAN_LIST_H 55 | -------------------------------------------------------------------------------- /src/util/nchan_msg.h: -------------------------------------------------------------------------------- 1 | #ifndef NCHAN_MSG_H 2 | #define NCHAN_MSG_H 3 | ngx_int_t msg_reserve(nchan_msg_t *msg, char *lbl); 4 | ngx_int_t msg_release(nchan_msg_t *msg, char *lbl); 5 | int msg_refcount_valid(nchan_msg_t *msg); 6 | int msg_refcount_invalidate_if_zero(nchan_msg_t *msg); 7 | void msg_refcount_invalidate(nchan_msg_t *msg); 8 | 9 | void nchan_expand_msg_id_multi_tag(nchan_msg_id_t *id, uint8_t in_n, uint8_t out_n, int16_t fill); 10 | ngx_int_t nchan_copy_msg_id(nchan_msg_id_t *dst, nchan_msg_id_t *src, int16_t *largetags); 11 | ngx_int_t nchan_copy_new_msg_id(nchan_msg_id_t *dst, nchan_msg_id_t *src); 12 | ngx_int_t nchan_free_msg_id(nchan_msg_id_t *id); 13 | 14 | ngx_int_t nchan_parse_compound_msgid(nchan_msg_id_t *id, ngx_str_t *str, ngx_int_t expected_tag_count); 15 | void nchan_update_multi_msgid(nchan_msg_id_t *oldid, nchan_msg_id_t *newid, int16_t *largetags); 16 | ngx_int_t update_subscriber_last_msg_id(subscriber_t *sub, nchan_msg_t *msg); 17 | nchan_msg_id_t *nchan_subscriber_get_msg_id(ngx_http_request_t *r); 18 | ngx_int_t nchan_extract_from_multi_msgid(nchan_msg_id_t *src, uint16_t n, nchan_msg_id_t *dst); 19 | 20 | int8_t nchan_compare_msgid_tags(nchan_msg_id_t *id1, nchan_msg_id_t *id2); 21 | int8_t nchan_compare_msgids(nchan_msg_id_t *id1, nchan_msg_id_t *id2); 22 | 23 | int nchan_msgid_tagcount_match(nchan_msg_id_t *id, int count); 24 | 25 | void nchan_expand_tiny_msgid(nchan_msg_tiny_id_t *tinyid, nchan_msg_id_t *id); 26 | void nchan_shrink_normal_msgid(nchan_msg_id_t *id, nchan_msg_tiny_id_t *tinyid); 27 | 28 | 29 | nchan_msg_t *nchan_msg_derive_alloc(nchan_msg_t *parent); 30 | nchan_msg_t *nchan_msg_derive_palloc(nchan_msg_t *parent, ngx_pool_t *pool); 31 | nchan_msg_t *nchan_msg_derive_stack(nchan_msg_t *parent, nchan_msg_t *child, int16_t *largetags); 32 | 33 | 34 | 35 | #endif //NCHAN_MSG_H 36 | -------------------------------------------------------------------------------- /src/util/nchan_output.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void nchan_output_init(void); 5 | void nchan_output_shutdown(void); 6 | 7 | ngx_int_t nchan_output_filter(ngx_http_request_t *r, ngx_chain_t *in); 8 | ngx_int_t nchan_output_msg_filter(ngx_http_request_t *r, nchan_msg_t *msg, ngx_chain_t *in); 9 | 10 | ngx_int_t nchan_respond_status(ngx_http_request_t *r, ngx_int_t status_code, const ngx_str_t *status_line, ngx_chain_t *body, ngx_int_t finalize); 11 | ngx_int_t nchan_respond_string(ngx_http_request_t *r, ngx_int_t status_code, const ngx_str_t *content_type, const ngx_str_t *body, ngx_int_t finalize); 12 | ngx_int_t nchan_respond_sprintf(ngx_http_request_t *r, ngx_int_t status_code, const ngx_str_t *content_type, const ngx_int_t finalize, char *fmt, ...); 13 | ngx_int_t nchan_respond_cstring(ngx_http_request_t *r, ngx_int_t status_code, const ngx_str_t *content_type, char *body, ngx_int_t finalize); 14 | ngx_int_t nchan_respond_membuf(ngx_http_request_t *r, ngx_int_t status_code, const ngx_str_t *content_type, ngx_buf_t *body, ngx_int_t finalize); 15 | ngx_table_elt_t * nchan_add_response_header(ngx_http_request_t *r, const ngx_str_t *header_name, const ngx_str_t *header_value); 16 | ngx_int_t nchan_set_msgid_http_response_headers(ngx_http_request_t *r, nchan_request_ctx_t *ctx, nchan_msg_id_t *msgid); 17 | ngx_int_t nchan_OPTIONS_respond(ngx_http_request_t *r, const ngx_str_t *allowed_headers, const ngx_str_t *allowed_methods); 18 | ngx_int_t nchan_respond_msg(ngx_http_request_t *r, nchan_msg_t *msg, nchan_msg_id_t *msgid, ngx_int_t finalize, char **err); 19 | void nchan_include_access_control_if_needed(ngx_http_request_t *r, nchan_request_ctx_t *ctx); 20 | void nchan_flush_pending_output(ngx_http_request_t *r); 21 | 22 | void nchan_http_finalize_request(ngx_http_request_t *r, ngx_int_t code); 23 | 24 | ngx_fd_t nchan_fdcache_get(ngx_str_t *filename); 25 | 26 | ngx_int_t nchan_msg_buf_open_fd_if_needed(ngx_buf_t *buf, ngx_file_t *file, ngx_http_request_t *r); 27 | 28 | ngx_str_t *msgtag_to_str(nchan_msg_id_t *id); 29 | ngx_str_t *msgid_to_str(nchan_msg_id_t *id); 30 | size_t msgtag_to_strptr(nchan_msg_id_t *id, char *ch); 31 | -------------------------------------------------------------------------------- /src/util/nchan_output_info.h: -------------------------------------------------------------------------------- 1 | ngx_buf_t *nchan_channel_info_buf(ngx_str_t *accept_header, ngx_uint_t messages, ngx_uint_t subscribers, time_t last_seen, nchan_msg_id_t *last_msgid, ngx_str_t **generated_content_type); 2 | 3 | ngx_int_t nchan_channel_info(ngx_http_request_t *r, ngx_int_t status_code, ngx_uint_t messages, ngx_uint_t subscribers, time_t last_seen, nchan_msg_id_t *msgid); 4 | ngx_int_t nchan_group_info(ngx_http_request_t *r, const nchan_group_t *group); 5 | 6 | ngx_int_t nchan_response_channel_ptr_info(nchan_channel_t *channel, ngx_http_request_t *r, ngx_int_t status_code); 7 | -------------------------------------------------------------------------------- /src/util/nchan_rbtree.h: -------------------------------------------------------------------------------- 1 | #ifndef NCHAN_RBTREE_UTIL_HEADER 2 | #define NCHAN_RBTREE_UTIL_HEADER 3 | 4 | #define NCHAN_RBTREE_DBG 0 5 | 6 | typedef struct { 7 | char *name; 8 | ngx_rbtree_t tree; 9 | ngx_rbtree_node_t sentinel; 10 | ngx_uint_t allocd_nodes; 11 | ngx_uint_t active_nodes; 12 | void *(*id)(void *node); 13 | uint32_t (*hash)(void *); 14 | ngx_int_t (*compare)(void *, void *); 15 | #if NCHAN_RBTREE_DBG 16 | //ngx_rbtree_node_t *actives[4096]; //super-heavy debugging 17 | #endif 18 | } rbtree_seed_t; 19 | 20 | 21 | #if NCHAN_RBTREE_DBG 22 | typedef struct ngx_rbtree_debug_node_s ngx_rbtree_debug_node_t; 23 | 24 | typedef struct { 25 | struct ngx_rbtree_debug_node_s *prev; 26 | struct ngx_rbtree_debug_node_s *next; 27 | } ngx_rbtree_debug_node_link_t; 28 | 29 | struct ngx_rbtree_debug_node_s { 30 | ngx_rbtree_node_t node; 31 | ngx_rbtree_debug_node_link_t allocd; 32 | ngx_rbtree_debug_node_link_t active; 33 | }; //ngx_rbtree_debug_node_t; 34 | #endif 35 | 36 | typedef enum {RBTREE_WALK_LEFT, RBTREE_WALK_RIGHT, RBTREE_WALK_LEFT_RIGHT, RBTREE_WALK_STOP} rbtree_walk_direction_t; 37 | 38 | typedef ngx_int_t (*rbtree_walk_callback_pt)(rbtree_seed_t *, void *node_data, void *privdata); 39 | typedef rbtree_walk_direction_t (*rbtree_walk_conditional_callback_pt)(rbtree_seed_t *, void *, void *); 40 | 41 | ngx_int_t rbtree_init(rbtree_seed_t *seed, char *name, void *(*id)(void *), uint32_t (*hash)(void *), ngx_int_t (*compare)(void *, void *)); 42 | unsigned rbtree_empty(rbtree_seed_t *, rbtree_walk_callback_pt, void *data); 43 | 44 | ngx_rbtree_node_t *rbtree_create_node(rbtree_seed_t *, size_t data_size); 45 | ngx_int_t rbtree_insert_node(rbtree_seed_t *, ngx_rbtree_node_t *); 46 | ngx_int_t rbtree_remove_node(rbtree_seed_t *, ngx_rbtree_node_t *); 47 | ngx_int_t rbtree_destroy_node(rbtree_seed_t *, ngx_rbtree_node_t *); 48 | 49 | ngx_rbtree_node_t *rbtree_find_node(rbtree_seed_t *, void *id); 50 | 51 | ngx_int_t rbtree_walk(rbtree_seed_t *seed, rbtree_walk_callback_pt, void *data); 52 | ngx_int_t rbtree_walk_incr(rbtree_seed_t *seed, rbtree_walk_callback_pt callback, void *data); 53 | ngx_int_t rbtree_walk_decr(rbtree_seed_t *seed, rbtree_walk_callback_pt callback, void *data); 54 | ngx_int_t rbtree_walk_writesafe(rbtree_seed_t *seed, int (*include)(void *), rbtree_walk_callback_pt callback, void *data); 55 | 56 | ngx_int_t rbtree_conditional_walk(rbtree_seed_t *seed, rbtree_walk_conditional_callback_pt, void *data); 57 | 58 | ngx_rbtree_node_t *rbtree_node_from_data(void *); 59 | 60 | 61 | #define rbtree_data_from_node(node) ((void *)(&node[1])) 62 | #define rbtree_node_from_data(data) (ngx_rbtree_node_t *)((u_char *)data - sizeof(ngx_rbtree_node_t)) 63 | 64 | #endif /*NCHAN_RBTREE_UTIL_HEADER*/ 65 | -------------------------------------------------------------------------------- /src/util/nchan_reaper.h: -------------------------------------------------------------------------------- 1 | #ifndef NCHAN_REAPER_H 2 | #define NCHAN_REAPER_H 3 | 4 | typedef enum {RESCAN, ROTATE, KEEP_PLACE} nchan_reaper_strategy_t; 5 | 6 | typedef struct { 7 | char *name; 8 | ngx_int_t count; 9 | int next_ptr_offset; 10 | int prev_ptr_offset; 11 | void *last; 12 | void *first; 13 | ngx_int_t (*ready)(void *, uint8_t force); //ready to be reaped? 14 | void (*reap)(void *); //reap it 15 | ngx_event_t timer; 16 | int tick_usec; 17 | nchan_reaper_strategy_t strategy; 18 | float max_notready_ratio; 19 | void *position; 20 | 21 | } nchan_reaper_t; 22 | 23 | ngx_int_t nchan_reaper_start(nchan_reaper_t *rp, char *name, int prev, int next, ngx_int_t (*ready)(void *, uint8_t force), void (*reap)(void *), int tick_sec); 24 | 25 | ngx_int_t nchan_reaper_flush(nchan_reaper_t *rp); 26 | ngx_int_t nchan_reaper_stop(nchan_reaper_t *rp); 27 | void nchan_reaper_each(nchan_reaper_t *rp, void (*cb)(void *thing, void *pd), void *pd); 28 | 29 | 30 | ngx_int_t nchan_reaper_add(nchan_reaper_t *rp, void *thing); 31 | ngx_int_t nchan_reaper_withdraw(nchan_reaper_t *rp, void *thing); 32 | 33 | #endif /*NCHAN_REAPER_H*/ 34 | -------------------------------------------------------------------------------- /src/util/nchan_reuse_queue.h: -------------------------------------------------------------------------------- 1 | #ifndef NCHAN_REUSE_QUEUE_H 2 | #define NCHAN_REUSE_QUEUE_H 3 | 4 | typedef struct { 5 | int size; 6 | int next_ptr_offset; 7 | int prev_ptr_offset; 8 | void *first; 9 | void *last; 10 | void *reserve; 11 | void *(*alloc)(void *privdata); 12 | ngx_int_t (*free)(void *privdata, void *thing); 13 | void *pd; 14 | } nchan_reuse_queue_t; 15 | 16 | ngx_int_t nchan_reuse_queue_init(nchan_reuse_queue_t *rq, int prev, int next, void *(*alloc)(void *), ngx_int_t (*free)(void *, void*), void *privdata); 17 | ngx_int_t nchan_reuse_queue_shutdown(nchan_reuse_queue_t *rq); 18 | ngx_int_t nchan_reuse_queue_flush(nchan_reuse_queue_t *rq); 19 | void nchan_reuse_queue_each(nchan_reuse_queue_t *rq, void (*calback)(void *)); 20 | void *nchan_reuse_queue_first(nchan_reuse_queue_t *rq); 21 | void *nchan_reuse_queue_push(nchan_reuse_queue_t *rq); 22 | ngx_int_t nchan_reuse_queue_pop(nchan_reuse_queue_t *rq); 23 | 24 | #endif /*NCHAN_REUSE_QUEUE_H*/ 25 | -------------------------------------------------------------------------------- /src/util/nchan_slist.h: -------------------------------------------------------------------------------- 1 | #ifndef NCHAN_SLIST_H 2 | #define NCHAN_SLIST_H 3 | 4 | #define NCHAN_SLIST_DEBUG 0 5 | 6 | #include 7 | #include 8 | 9 | typedef struct { 10 | off_t prev; 11 | off_t next; 12 | } nchan_slist_offsets_t; 13 | 14 | typedef struct { 15 | void *head; 16 | void *tail; 17 | ngx_uint_t n; 18 | nchan_slist_offsets_t offset; 19 | } nchan_slist_t; 20 | 21 | 22 | 23 | #define nchan_slist_init(slist, data_type, prev_field, next_field) \ 24 | __nchan_slist_init(slist, offsetof(data_type, prev_field), offsetof(data_type, next_field)) 25 | ngx_int_t __nchan_slist_init(nchan_slist_t *list, off_t offset_prev, off_t offset_next); 26 | void *nchan_slist_first(nchan_slist_t *list); 27 | void *nchan_slist_last(nchan_slist_t *list); 28 | void *nchan_slist_next(nchan_slist_t *list, void *el); 29 | void *nchan_slist_prev(nchan_slist_t *list, void *el); 30 | ngx_int_t nchan_slist_append(nchan_slist_t *list, void *el); 31 | ngx_int_t nchan_slist_prepend(nchan_slist_t *list, void *el); 32 | ngx_int_t nchan_slist_remove(nchan_slist_t *list, void *el); 33 | 34 | ngx_int_t nchan_slist_reset(nchan_slist_t *list); 35 | ngx_int_t nchan_slist_transfer(nchan_slist_t *dst, nchan_slist_t *src); 36 | void *nchan_slist_pop(nchan_slist_t *list); 37 | void *nchan_slist_shift(nchan_slist_t *list); 38 | 39 | int nchan_slist_is_empty(nchan_slist_t *list); 40 | 41 | #endif /*NCHAN_SLIST_H*/ 42 | -------------------------------------------------------------------------------- /src/util/nchan_stats.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | static shmem_t *shm = NULL; 9 | static nchan_stats_t *shstats = NULL; 10 | static int stats_enabled = 0; 11 | 12 | static ngx_int_t initialize_shm(ngx_shm_zone_t *zone, void *data); 13 | 14 | ngx_int_t nchan_stats_init_postconfig(ngx_conf_t *cf, int enable) { 15 | ngx_str_t name = ngx_string("nchan_worker_stats"); 16 | shm = shm_create(&name, cf, sizeof(*shstats)*2, initialize_shm, &ngx_nchan_module); 17 | stats_enabled = enable; 18 | return NGX_OK; 19 | } 20 | 21 | ngx_int_t nchan_stats_init_worker(ngx_cycle_t *cycle) { 22 | nchan_stats_worker_t *wstats = &shstats->worker[ngx_process_slot]; 23 | 24 | ngx_memzero(wstats, sizeof(*wstats)); 25 | 26 | return NGX_OK; 27 | } 28 | 29 | void nchan_stats_exit_worker(ngx_cycle_t *cycle) { 30 | shm_destroy(shm); //just for this worker... 31 | } 32 | 33 | void nchan_stats_exit_master(ngx_cycle_t *cycle) { 34 | shm_destroy(shm); 35 | } 36 | 37 | static ngx_int_t initialize_shm(ngx_shm_zone_t *zone, void *data) { 38 | if(data) { //zone being passed after restart 39 | zone->data = data; 40 | shstats = zone->data; 41 | } 42 | else { 43 | shm_init(shm); 44 | 45 | if((shstats = shm_calloc(shm, sizeof(*shstats), "root shared data")) == NULL) { 46 | return NGX_ERROR; 47 | } 48 | zone->data = shstats; 49 | } 50 | 51 | return NGX_OK; 52 | } 53 | 54 | void __nchan_stats_global_incr(off_t offset, int count) { 55 | if(!stats_enabled || !shstats) { 56 | return; 57 | } 58 | ngx_atomic_fetch_add((ngx_atomic_uint_t *)((char *)&shstats->global + offset), count); 59 | } 60 | void __nchan_stats_worker_incr(off_t offset, int count) { 61 | if(!stats_enabled || !shstats) { 62 | return; 63 | } 64 | ngx_atomic_fetch_add((ngx_atomic_uint_t *)((char *)&shstats->worker[ngx_process_slot] + offset), count); 65 | } 66 | 67 | ngx_int_t nchan_stats_get_all(nchan_stats_worker_t *worker, nchan_stats_global_t *global) { 68 | if(!stats_enabled) { 69 | if(worker) { 70 | ngx_memzero(worker, sizeof(*worker)); 71 | } 72 | if(global) { 73 | ngx_memzero(global, sizeof(*global)); 74 | } 75 | return NGX_OK; 76 | } 77 | 78 | ipc_t *ipc = nchan_memstore_get_ipc(); 79 | if(!ipc) { 80 | return NGX_ERROR; 81 | } 82 | 83 | if(worker) { 84 | ngx_memzero(worker, sizeof(*worker)); 85 | ngx_atomic_uint_t *worker_sum_stats_array = (ngx_atomic_uint_t *)worker; 86 | 87 | const ngx_int_t *slots; 88 | size_t worker_count = ipc_worker_slots(ipc, &slots); 89 | unsigned i; 90 | for(i=0; iworker[slots[i]]; 92 | unsigned j; 93 | for(j=0; jglobal; 101 | } 102 | return NGX_OK; 103 | } 104 | -------------------------------------------------------------------------------- /src/util/nchan_stats.h: -------------------------------------------------------------------------------- 1 | #ifndef NCHAN_STATS_H 2 | #define NCHAN_STATS_H 3 | #include 4 | 5 | #define nchan_stats_global_incr(counter_name, count) \ 6 | __nchan_stats_global_incr(offsetof(nchan_stats_global_t, counter_name), count) 7 | 8 | #define nchan_stats_worker_incr(counter_name, count) \ 9 | __nchan_stats_worker_incr(offsetof(nchan_stats_worker_t, counter_name), count) 10 | 11 | void __nchan_stats_global_incr(off_t offset, int count); 12 | void __nchan_stats_worker_incr(off_t offset, int count); 13 | 14 | typedef struct { 15 | //These must all be ngx_atomic_uint_t 16 | ngx_atomic_uint_t channels; 17 | ngx_atomic_uint_t subscribers; 18 | ngx_atomic_uint_t messages; 19 | ngx_atomic_uint_t redis_pending_commands; 20 | ngx_atomic_uint_t redis_connected_servers; 21 | ngx_atomic_uint_t redis_unhealthy_upstreams; 22 | ngx_atomic_uint_t ipc_queue_size; 23 | } nchan_stats_worker_t; 24 | 25 | typedef struct { 26 | ngx_atomic_uint_t total_published_messages; 27 | ngx_atomic_uint_t total_ipc_alerts_sent; 28 | ngx_atomic_uint_t total_ipc_alerts_received; 29 | ngx_atomic_uint_t total_ipc_send_delay; 30 | ngx_atomic_uint_t total_ipc_receive_delay; 31 | ngx_atomic_uint_t total_redis_commands_sent; 32 | } nchan_stats_global_t; 33 | 34 | typedef struct { 35 | nchan_stats_worker_t worker[NGX_MAX_PROCESSES]; 36 | nchan_stats_global_t global; 37 | } nchan_stats_t; 38 | 39 | ngx_int_t nchan_stats_init_postconfig(ngx_conf_t *cf, int enable); 40 | ngx_int_t nchan_stats_init_worker(ngx_cycle_t *cycle); 41 | void nchan_stats_exit_worker(ngx_cycle_t *cycle); 42 | void nchan_stats_exit_master(ngx_cycle_t *cycle); 43 | 44 | ngx_int_t nchan_stats_get_all(nchan_stats_worker_t *worker, nchan_stats_global_t *global); 45 | 46 | 47 | #endif //NCHAN_STATS_H 48 | 49 | -------------------------------------------------------------------------------- /src/util/nchan_subrequest.h: -------------------------------------------------------------------------------- 1 | ngx_int_t nchan_set_content_length_header(ngx_http_request_t *r, off_t len); 2 | ngx_int_t nchan_adjust_subrequest(ngx_http_request_t *sr, ngx_uint_t method, ngx_str_t *method_name, ngx_http_request_body_t *request_body, size_t content_length_n); 3 | size_t nchan_subrequest_content_length(ngx_http_request_t *sr); 4 | ngx_int_t nchan_recover_x_accel_redirected_request_method(ngx_http_request_t *r); 5 | 6 | ngx_http_request_t *nchan_create_subrequest(ngx_http_request_t *r, ngx_str_t *url, ngx_buf_t *body, ngx_http_post_subrequest_pt cb, void *pd); 7 | -------------------------------------------------------------------------------- /src/util/nchan_thingcache.h: -------------------------------------------------------------------------------- 1 | void *nchan_thingcache_init(char *name, void *(*create)(ngx_str_t *), ngx_int_t(*destroy)(ngx_str_t *, void *), ngx_uint_t ttl); 2 | ngx_int_t nchan_thingcache_shutdown(void *tcv); 3 | void *nchan_thingcache_get(void *tcv, ngx_str_t *id); 4 | void *nchan_thingcache_find(void *tcv, ngx_str_t *id); -------------------------------------------------------------------------------- /src/util/nchan_timequeue.h: -------------------------------------------------------------------------------- 1 | #ifndef NCHAN_TIMEQUEUE_H 2 | #define NCHAN_TIMEQUEUE_H 3 | 4 | #include 5 | #include 6 | 7 | typedef struct { 8 | ngx_msec_t time_start; 9 | int tag; 10 | } nchan_timequeue_time_t; 11 | 12 | struct nchan_timequeue_page_s { 13 | struct nchan_timequeue_page_s *next; 14 | uint16_t start; 15 | uint16_t end; 16 | nchan_timequeue_time_t data[1]; 17 | }; 18 | 19 | typedef struct nchan_timequeue_page_s nchan_timequeue_page_t; 20 | 21 | typedef struct { 22 | size_t items_per_page; 23 | int anytag; 24 | nchan_timequeue_page_t *first; 25 | nchan_timequeue_page_t *last; 26 | nchan_timequeue_page_t *standby; 27 | 28 | } nchan_timequeue_t; 29 | 30 | 31 | 32 | int nchan_timequeue_init(nchan_timequeue_t *pq, size_t items_per_page, int anytag); 33 | int nchan_timequeue_queue(nchan_timequeue_t *pq, int tag); 34 | int nchan_timequeue_dequeue(nchan_timequeue_t *pq, int expected_tag, nchan_timequeue_time_t *dequeued); 35 | void nchan_timequeue_destroy(nchan_timequeue_t *pq); 36 | 37 | #endif //NCHAN_TIMEQUEUE_H 38 | -------------------------------------------------------------------------------- /src/util/ngx_nchan_hacked_slab.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Igor Sysoev 4 | * Copyright (C) Nginx, Inc. 5 | */ 6 | 7 | 8 | #ifndef _NCHAN_HACKED_SLAB_H_INCLUDED_ 9 | #define _NCHAN_HACKED_SLAB_H_INCLUDED_ 10 | 11 | 12 | #include 13 | #include 14 | 15 | 16 | void nchan_slab_init(ngx_slab_pool_t *pool); 17 | void *nchan_slab_alloc(ngx_slab_pool_t *pool, size_t size); 18 | void *nchan_slab_alloc_locked(ngx_slab_pool_t *pool, size_t size); 19 | void *nchan_slab_calloc(ngx_slab_pool_t *pool, size_t size); 20 | void *nchan_slab_calloc_locked(ngx_slab_pool_t *pool, size_t size); 21 | void nchan_slab_free(ngx_slab_pool_t *pool, void *p); 22 | void nchan_slab_free_locked(ngx_slab_pool_t *pool, void *p); 23 | 24 | void nchan_slab_set_reserved_pages_tracker(ngx_slab_pool_t *pool, ngx_atomic_uint_t *ref); 25 | 26 | #endif /* _NCHAN_HACKED_SLAB_H_INCLUDED_ */ 27 | -------------------------------------------------------------------------------- /src/util/shmem.h: -------------------------------------------------------------------------------- 1 | #ifndef NCHAN_SHMEM_H 2 | #define NCHAN_SHMEM_H 3 | typedef struct { 4 | ngx_shm_zone_t *zone; 5 | } shmem_t; 6 | 7 | shmem_t *shm_create(ngx_str_t *name, ngx_conf_t *cf, size_t shm_size, ngx_int_t (*init)(ngx_shm_zone_t *, void *), void *privdata); 8 | ngx_int_t shm_init(shmem_t *shm); 9 | ngx_int_t shm_reinit(shmem_t *shm); 10 | ngx_int_t shm_destroy(shmem_t *shm); 11 | void *shm_alloc(shmem_t *shm, size_t size, const char *label); 12 | void *shm_calloc(shmem_t *shm, size_t size, const char *label); 13 | void shm_free(shmem_t *shm, void *p); 14 | 15 | void *shm_locked_alloc(shmem_t *shm, size_t size, const char *label); 16 | void *shm_locked_calloc(shmem_t *shm, size_t size, const char *label); 17 | void shm_locked_free(shmem_t *shm, void *p); 18 | 19 | void shmtx_lock(shmem_t *shm); 20 | void shmtx_unlock(shmem_t *shm); 21 | 22 | ngx_str_t *shm_copy_immutable_string(shmem_t *shm, ngx_str_t *str); 23 | void shm_free_immutable_string(shmem_t *shm, ngx_str_t *str); 24 | void shm_verify_immutable_string(shmem_t *shm, ngx_str_t *str); 25 | 26 | #if nginx_version <= 1011006 27 | void shm_set_allocd_pages_tracker(shmem_t *shm, ngx_atomic_uint_t *ptr); 28 | #else 29 | ngx_uint_t shm_used_pages(shmem_t *shm); 30 | #endif 31 | 32 | 33 | #endif //NCHAN_SHMEM_H 34 | --------------------------------------------------------------------------------