src/stream/ngx_stream_split_clients_module.c - nginx source code

Global variables defined

Data types defined

Functions defined

Source code


  1. /*
  2. * Copyright (C) Igor Sysoev
  3. * Copyright (C) Nginx, Inc.
  4. */


  5. #include <ngx_config.h>
  6. #include <ngx_core.h>
  7. #include <ngx_stream.h>


  8. typedef struct {
  9.     uint32_t                      percent;
  10.     ngx_stream_variable_value_t   value;
  11. } ngx_stream_split_clients_part_t;


  12. typedef struct {
  13.     ngx_stream_complex_value_t    value;
  14.     ngx_array_t                   parts;
  15. } ngx_stream_split_clients_ctx_t;


  16. static char *ngx_conf_split_clients_block(ngx_conf_t *cf, ngx_command_t *cmd,
  17.     void *conf);
  18. static char *ngx_stream_split_clients(ngx_conf_t *cf, ngx_command_t *dummy,
  19.     void *conf);

  20. static ngx_command_t  ngx_stream_split_clients_commands[] = {

  21.     { ngx_string("split_clients"),
  22.       NGX_STREAM_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE2,
  23.       ngx_conf_split_clients_block,
  24.       NGX_STREAM_MAIN_CONF_OFFSET,
  25.       0,
  26.       NULL },

  27.       ngx_null_command
  28. };


  29. static ngx_stream_module_t  ngx_stream_split_clients_module_ctx = {
  30.     NULL,                                  /* preconfiguration */
  31.     NULL,                                  /* postconfiguration */

  32.     NULL,                                  /* create main configuration */
  33.     NULL,                                  /* init main configuration */

  34.     NULL,                                  /* create server configuration */
  35.     NULL                                   /* merge server configuration */
  36. };


  37. ngx_module_t  ngx_stream_split_clients_module = {
  38.     NGX_MODULE_V1,
  39.     &ngx_stream_split_clients_module_ctx/* module context */
  40.     ngx_stream_split_clients_commands,     /* module directives */
  41.     NGX_STREAM_MODULE,                     /* module type */
  42.     NULL,                                  /* init master */
  43.     NULL,                                  /* init module */
  44.     NULL,                                  /* init process */
  45.     NULL,                                  /* init thread */
  46.     NULL,                                  /* exit thread */
  47.     NULL,                                  /* exit process */
  48.     NULL,                                  /* exit master */
  49.     NGX_MODULE_V1_PADDING
  50. };


  51. static ngx_int_t
  52. ngx_stream_split_clients_variable(ngx_stream_session_t *s,
  53.     ngx_stream_variable_value_t *v, uintptr_t data)
  54. {
  55.     ngx_stream_split_clients_ctx_t *ctx =
  56.                                        (ngx_stream_split_clients_ctx_t *) data;

  57.     uint32_t                          hash;
  58.     ngx_str_t                         val;
  59.     ngx_uint_t                        i;
  60.     ngx_stream_split_clients_part_t  *part;

  61.     *v = ngx_stream_variable_null_value;

  62.     if (ngx_stream_complex_value(s, &ctx->value, &val) != NGX_OK) {
  63.         return NGX_OK;
  64.     }

  65.     hash = ngx_murmur_hash2(val.data, val.len);

  66.     part = ctx->parts.elts;

  67.     for (i = 0; i < ctx->parts.nelts; i++) {

  68.         ngx_log_debug2(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
  69.                        "stream split: %uD %uD", hash, part[i].percent);

  70.         if (hash < part[i].percent || part[i].percent == 0) {
  71.             *v = part[i].value;
  72.             return NGX_OK;
  73.         }
  74.     }

  75.     return NGX_OK;
  76. }


  77. static char *
  78. ngx_conf_split_clients_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  79. {
  80.     char                                *rv;
  81.     uint32_t                             sum, last;
  82.     ngx_str_t                           *value, name;
  83.     ngx_uint_t                           i;
  84.     ngx_conf_t                           save;
  85.     ngx_stream_variable_t               *var;
  86.     ngx_stream_split_clients_ctx_t      *ctx;
  87.     ngx_stream_split_clients_part_t     *part;
  88.     ngx_stream_compile_complex_value_t   ccv;

  89.     ctx = ngx_pcalloc(cf->pool, sizeof(ngx_stream_split_clients_ctx_t));
  90.     if (ctx == NULL) {
  91.         return NGX_CONF_ERROR;
  92.     }

  93.     value = cf->args->elts;

  94.     ngx_memzero(&ccv, sizeof(ngx_stream_compile_complex_value_t));

  95.     ccv.cf = cf;
  96.     ccv.value = &value[1];
  97.     ccv.complex_value = &ctx->value;

  98.     if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) {
  99.         return NGX_CONF_ERROR;
  100.     }

  101.     name = value[2];

  102.     if (name.data[0] != '$') {
  103.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  104.                            "invalid variable name \"%V\"", &name);
  105.         return NGX_CONF_ERROR;
  106.     }

  107.     name.len--;
  108.     name.data++;

  109.     var = ngx_stream_add_variable(cf, &name, NGX_STREAM_VAR_CHANGEABLE);
  110.     if (var == NULL) {
  111.         return NGX_CONF_ERROR;
  112.     }

  113.     var->get_handler = ngx_stream_split_clients_variable;
  114.     var->data = (uintptr_t) ctx;

  115.     if (ngx_array_init(&ctx->parts, cf->pool, 2,
  116.                        sizeof(ngx_stream_split_clients_part_t))
  117.         != NGX_OK)
  118.     {
  119.         return NGX_CONF_ERROR;
  120.     }

  121.     save = *cf;
  122.     cf->ctx = ctx;
  123.     cf->handler = ngx_stream_split_clients;
  124.     cf->handler_conf = conf;

  125.     rv = ngx_conf_parse(cf, NULL);

  126.     *cf = save;

  127.     if (rv != NGX_CONF_OK) {
  128.         return rv;
  129.     }

  130.     sum = 0;
  131.     last = 0;
  132.     part = ctx->parts.elts;

  133.     for (i = 0; i < ctx->parts.nelts; i++) {
  134.         sum = part[i].percent ? sum + part[i].percent : 10000;
  135.         if (sum > 10000) {
  136.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  137.                                "percent total is greater than 100%%");
  138.             return NGX_CONF_ERROR;
  139.         }

  140.         if (part[i].percent) {
  141.             last += part[i].percent * (uint64_t) 0xffffffff / 10000;
  142.             part[i].percent = last;
  143.         }
  144.     }

  145.     return rv;
  146. }


  147. static char *
  148. ngx_stream_split_clients(ngx_conf_t *cf, ngx_command_t *dummy, void *conf)
  149. {
  150.     ngx_int_t                         n;
  151.     ngx_str_t                        *value;
  152.     ngx_stream_split_clients_ctx_t   *ctx;
  153.     ngx_stream_split_clients_part_t  *part;

  154.     ctx = cf->ctx;
  155.     value = cf->args->elts;

  156.     part = ngx_array_push(&ctx->parts);
  157.     if (part == NULL) {
  158.         return NGX_CONF_ERROR;
  159.     }

  160.     if (value[0].len == 1 && value[0].data[0] == '*') {
  161.         part->percent = 0;

  162.     } else {
  163.         if (value[0].len == 0 || value[0].data[value[0].len - 1] != '%') {
  164.             goto invalid;
  165.         }

  166.         n = ngx_atofp(value[0].data, value[0].len - 1, 2);
  167.         if (n == NGX_ERROR || n == 0) {
  168.             goto invalid;
  169.         }

  170.         part->percent = (uint32_t) n;
  171.     }

  172.     part->value.len = value[1].len;
  173.     part->value.valid = 1;
  174.     part->value.no_cacheable = 0;
  175.     part->value.not_found = 0;
  176.     part->value.data = value[1].data;

  177.     return NGX_CONF_OK;

  178. invalid:

  179.     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  180.                        "invalid percent value \"%V\"", &value[0]);
  181.     return NGX_CONF_ERROR;
  182. }