Merge commit '484a904fa7' as 'nginx'
This commit is contained in:
commit
2b63c55768
528 changed files with 294288 additions and 0 deletions
1676
nginx/src/core/nginx.c
Normal file
1676
nginx/src/core/nginx.c
Normal file
File diff suppressed because it is too large
Load diff
26
nginx/src/core/nginx.h
Normal file
26
nginx/src/core/nginx.h
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGINX_H_INCLUDED_
|
||||
#define _NGINX_H_INCLUDED_
|
||||
|
||||
|
||||
#define nginx_version 1031000
|
||||
#define NGINX_VERSION "1.31.0"
|
||||
#define NGINX_VER "nginx/" NGINX_VERSION
|
||||
|
||||
#ifdef NGX_BUILD
|
||||
#define NGINX_VER_BUILD NGINX_VER " (" NGX_BUILD ")"
|
||||
#else
|
||||
#define NGINX_VER_BUILD NGINX_VER
|
||||
#endif
|
||||
|
||||
#define NGINX_VAR "NGINX"
|
||||
#define NGX_OLDPID_EXT ".oldbin"
|
||||
|
||||
|
||||
#endif /* _NGINX_H_INCLUDED_ */
|
||||
141
nginx/src/core/ngx_array.c
Normal file
141
nginx/src/core/ngx_array.c
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
ngx_array_t *
|
||||
ngx_array_create(ngx_pool_t *p, ngx_uint_t n, size_t size)
|
||||
{
|
||||
ngx_array_t *a;
|
||||
|
||||
a = ngx_palloc(p, sizeof(ngx_array_t));
|
||||
if (a == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ngx_array_init(a, p, n, size) != NGX_OK) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_array_destroy(ngx_array_t *a)
|
||||
{
|
||||
ngx_pool_t *p;
|
||||
|
||||
p = a->pool;
|
||||
|
||||
if ((u_char *) a->elts + a->size * a->nalloc == p->d.last) {
|
||||
p->d.last -= a->size * a->nalloc;
|
||||
}
|
||||
|
||||
if ((u_char *) a + sizeof(ngx_array_t) == p->d.last) {
|
||||
p->d.last = (u_char *) a;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
ngx_array_push(ngx_array_t *a)
|
||||
{
|
||||
void *elt, *new;
|
||||
size_t size;
|
||||
ngx_pool_t *p;
|
||||
|
||||
if (a->nelts == a->nalloc) {
|
||||
|
||||
/* the array is full */
|
||||
|
||||
size = a->size * a->nalloc;
|
||||
|
||||
p = a->pool;
|
||||
|
||||
if ((u_char *) a->elts + size == p->d.last
|
||||
&& p->d.last + a->size <= p->d.end)
|
||||
{
|
||||
/*
|
||||
* the array allocation is the last in the pool
|
||||
* and there is space for new allocation
|
||||
*/
|
||||
|
||||
p->d.last += a->size;
|
||||
a->nalloc++;
|
||||
|
||||
} else {
|
||||
/* allocate a new array */
|
||||
|
||||
new = ngx_palloc(p, 2 * size);
|
||||
if (new == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ngx_memcpy(new, a->elts, size);
|
||||
a->elts = new;
|
||||
a->nalloc *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
elt = (u_char *) a->elts + a->size * a->nelts;
|
||||
a->nelts++;
|
||||
|
||||
return elt;
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
ngx_array_push_n(ngx_array_t *a, ngx_uint_t n)
|
||||
{
|
||||
void *elt, *new;
|
||||
size_t size;
|
||||
ngx_uint_t nalloc;
|
||||
ngx_pool_t *p;
|
||||
|
||||
size = n * a->size;
|
||||
|
||||
if (a->nelts + n > a->nalloc) {
|
||||
|
||||
/* the array is full */
|
||||
|
||||
p = a->pool;
|
||||
|
||||
if ((u_char *) a->elts + a->size * a->nalloc == p->d.last
|
||||
&& p->d.last + size <= p->d.end)
|
||||
{
|
||||
/*
|
||||
* the array allocation is the last in the pool
|
||||
* and there is space for new allocation
|
||||
*/
|
||||
|
||||
p->d.last += size;
|
||||
a->nalloc += n;
|
||||
|
||||
} else {
|
||||
/* allocate a new array */
|
||||
|
||||
nalloc = 2 * ((n >= a->nalloc) ? n : a->nalloc);
|
||||
|
||||
new = ngx_palloc(p, nalloc * a->size);
|
||||
if (new == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ngx_memcpy(new, a->elts, a->nelts * a->size);
|
||||
a->elts = new;
|
||||
a->nalloc = nalloc;
|
||||
}
|
||||
}
|
||||
|
||||
elt = (u_char *) a->elts + a->size * a->nelts;
|
||||
a->nelts += n;
|
||||
|
||||
return elt;
|
||||
}
|
||||
53
nginx/src/core/ngx_array.h
Normal file
53
nginx/src/core/ngx_array.h
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_ARRAY_H_INCLUDED_
|
||||
#define _NGX_ARRAY_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
typedef struct {
|
||||
void *elts;
|
||||
ngx_uint_t nelts;
|
||||
size_t size;
|
||||
ngx_uint_t nalloc;
|
||||
ngx_pool_t *pool;
|
||||
} ngx_array_t;
|
||||
|
||||
|
||||
ngx_array_t *ngx_array_create(ngx_pool_t *p, ngx_uint_t n, size_t size);
|
||||
void ngx_array_destroy(ngx_array_t *a);
|
||||
void *ngx_array_push(ngx_array_t *a);
|
||||
void *ngx_array_push_n(ngx_array_t *a, ngx_uint_t n);
|
||||
|
||||
|
||||
static ngx_inline ngx_int_t
|
||||
ngx_array_init(ngx_array_t *array, ngx_pool_t *pool, ngx_uint_t n, size_t size)
|
||||
{
|
||||
/*
|
||||
* set "array->nelts" before "array->elts", otherwise MSVC thinks
|
||||
* that "array->nelts" may be used without having been initialized
|
||||
*/
|
||||
|
||||
array->nelts = 0;
|
||||
array->size = size;
|
||||
array->nalloc = n;
|
||||
array->pool = pool;
|
||||
|
||||
array->elts = ngx_palloc(pool, n * size);
|
||||
if (array->elts == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
#endif /* _NGX_ARRAY_H_INCLUDED_ */
|
||||
143
nginx/src/core/ngx_bpf.c
Normal file
143
nginx/src/core/ngx_bpf.c
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
#define NGX_BPF_LOGBUF_SIZE (16 * 1024)
|
||||
|
||||
|
||||
static ngx_inline int
|
||||
ngx_bpf(enum bpf_cmd cmd, union bpf_attr *attr, unsigned int size)
|
||||
{
|
||||
return syscall(__NR_bpf, cmd, attr, size);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_bpf_program_link(ngx_bpf_program_t *program, const char *symbol, int fd)
|
||||
{
|
||||
ngx_uint_t i;
|
||||
ngx_bpf_reloc_t *rl;
|
||||
|
||||
rl = program->relocs;
|
||||
|
||||
for (i = 0; i < program->nrelocs; i++) {
|
||||
if (ngx_strcmp(rl[i].name, symbol) == 0) {
|
||||
program->ins[rl[i].offset].src_reg = 1;
|
||||
program->ins[rl[i].offset].imm = fd;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_bpf_load_program(ngx_log_t *log, ngx_bpf_program_t *program)
|
||||
{
|
||||
int fd;
|
||||
union bpf_attr attr;
|
||||
#if (NGX_DEBUG)
|
||||
char buf[NGX_BPF_LOGBUF_SIZE];
|
||||
#endif
|
||||
|
||||
ngx_memzero(&attr, sizeof(union bpf_attr));
|
||||
|
||||
attr.license = (uintptr_t) program->license;
|
||||
attr.prog_type = program->type;
|
||||
attr.insns = (uintptr_t) program->ins;
|
||||
attr.insn_cnt = program->nins;
|
||||
|
||||
#if (NGX_DEBUG)
|
||||
/* for verifier errors */
|
||||
attr.log_buf = (uintptr_t) buf;
|
||||
attr.log_size = NGX_BPF_LOGBUF_SIZE;
|
||||
attr.log_level = 1;
|
||||
#endif
|
||||
|
||||
fd = ngx_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
|
||||
if (fd < 0) {
|
||||
ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
|
||||
"failed to load BPF program");
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0,
|
||||
"bpf verifier: %s", buf);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_bpf_map_create(ngx_log_t *log, enum bpf_map_type type, int key_size,
|
||||
int value_size, int max_entries, uint32_t map_flags)
|
||||
{
|
||||
int fd;
|
||||
union bpf_attr attr;
|
||||
|
||||
ngx_memzero(&attr, sizeof(union bpf_attr));
|
||||
|
||||
attr.map_type = type;
|
||||
attr.key_size = key_size;
|
||||
attr.value_size = value_size;
|
||||
attr.max_entries = max_entries;
|
||||
attr.map_flags = map_flags;
|
||||
|
||||
fd = ngx_bpf(BPF_MAP_CREATE, &attr, sizeof(attr));
|
||||
if (fd < 0) {
|
||||
ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
|
||||
"failed to create BPF map");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_bpf_map_update(int fd, const void *key, const void *value, uint64_t flags)
|
||||
{
|
||||
union bpf_attr attr;
|
||||
|
||||
ngx_memzero(&attr, sizeof(union bpf_attr));
|
||||
|
||||
attr.map_fd = fd;
|
||||
attr.key = (uintptr_t) key;
|
||||
attr.value = (uintptr_t) value;
|
||||
attr.flags = flags;
|
||||
|
||||
return ngx_bpf(BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr));
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_bpf_map_delete(int fd, const void *key)
|
||||
{
|
||||
union bpf_attr attr;
|
||||
|
||||
ngx_memzero(&attr, sizeof(union bpf_attr));
|
||||
|
||||
attr.map_fd = fd;
|
||||
attr.key = (uintptr_t) key;
|
||||
|
||||
return ngx_bpf(BPF_MAP_DELETE_ELEM, &attr, sizeof(attr));
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_bpf_map_lookup(int fd, const void *key, void *value)
|
||||
{
|
||||
union bpf_attr attr;
|
||||
|
||||
ngx_memzero(&attr, sizeof(union bpf_attr));
|
||||
|
||||
attr.map_fd = fd;
|
||||
attr.key = (uintptr_t) key;
|
||||
attr.value = (uintptr_t) value;
|
||||
|
||||
return ngx_bpf(BPF_MAP_LOOKUP_ELEM, &attr, sizeof(attr));
|
||||
}
|
||||
43
nginx/src/core/ngx_bpf.h
Normal file
43
nginx/src/core/ngx_bpf.h
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_BPF_H_INCLUDED_
|
||||
#define _NGX_BPF_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
#include <linux/bpf.h>
|
||||
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
int offset;
|
||||
} ngx_bpf_reloc_t;
|
||||
|
||||
typedef struct {
|
||||
char *license;
|
||||
enum bpf_prog_type type;
|
||||
struct bpf_insn *ins;
|
||||
size_t nins;
|
||||
ngx_bpf_reloc_t *relocs;
|
||||
size_t nrelocs;
|
||||
} ngx_bpf_program_t;
|
||||
|
||||
|
||||
void ngx_bpf_program_link(ngx_bpf_program_t *program, const char *symbol,
|
||||
int fd);
|
||||
int ngx_bpf_load_program(ngx_log_t *log, ngx_bpf_program_t *program);
|
||||
|
||||
int ngx_bpf_map_create(ngx_log_t *log, enum bpf_map_type type, int key_size,
|
||||
int value_size, int max_entries, uint32_t map_flags);
|
||||
int ngx_bpf_map_update(int fd, const void *key, const void *value,
|
||||
uint64_t flags);
|
||||
int ngx_bpf_map_delete(int fd, const void *key);
|
||||
int ngx_bpf_map_lookup(int fd, const void *key, void *value);
|
||||
|
||||
#endif /* _NGX_BPF_H_INCLUDED_ */
|
||||
314
nginx/src/core/ngx_buf.c
Normal file
314
nginx/src/core/ngx_buf.c
Normal file
|
|
@ -0,0 +1,314 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
ngx_buf_t *
|
||||
ngx_create_temp_buf(ngx_pool_t *pool, size_t size)
|
||||
{
|
||||
ngx_buf_t *b;
|
||||
|
||||
b = ngx_calloc_buf(pool);
|
||||
if (b == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
b->start = ngx_palloc(pool, size);
|
||||
if (b->start == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* set by ngx_calloc_buf():
|
||||
*
|
||||
* b->file_pos = 0;
|
||||
* b->file_last = 0;
|
||||
* b->file = NULL;
|
||||
* b->shadow = NULL;
|
||||
* b->tag = 0;
|
||||
* and flags
|
||||
*/
|
||||
|
||||
b->pos = b->start;
|
||||
b->last = b->start;
|
||||
b->end = b->last + size;
|
||||
b->temporary = 1;
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
ngx_chain_t *
|
||||
ngx_alloc_chain_link(ngx_pool_t *pool)
|
||||
{
|
||||
ngx_chain_t *cl;
|
||||
|
||||
cl = pool->chain;
|
||||
|
||||
if (cl) {
|
||||
pool->chain = cl->next;
|
||||
return cl;
|
||||
}
|
||||
|
||||
cl = ngx_palloc(pool, sizeof(ngx_chain_t));
|
||||
if (cl == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return cl;
|
||||
}
|
||||
|
||||
|
||||
ngx_chain_t *
|
||||
ngx_create_chain_of_bufs(ngx_pool_t *pool, ngx_bufs_t *bufs)
|
||||
{
|
||||
u_char *p;
|
||||
ngx_int_t i;
|
||||
ngx_buf_t *b;
|
||||
ngx_chain_t *chain, *cl, **ll;
|
||||
|
||||
p = ngx_palloc(pool, bufs->num * bufs->size);
|
||||
if (p == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ll = &chain;
|
||||
|
||||
for (i = 0; i < bufs->num; i++) {
|
||||
|
||||
b = ngx_calloc_buf(pool);
|
||||
if (b == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* set by ngx_calloc_buf():
|
||||
*
|
||||
* b->file_pos = 0;
|
||||
* b->file_last = 0;
|
||||
* b->file = NULL;
|
||||
* b->shadow = NULL;
|
||||
* b->tag = 0;
|
||||
* and flags
|
||||
*
|
||||
*/
|
||||
|
||||
b->pos = p;
|
||||
b->last = p;
|
||||
b->temporary = 1;
|
||||
|
||||
b->start = p;
|
||||
p += bufs->size;
|
||||
b->end = p;
|
||||
|
||||
cl = ngx_alloc_chain_link(pool);
|
||||
if (cl == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cl->buf = b;
|
||||
*ll = cl;
|
||||
ll = &cl->next;
|
||||
}
|
||||
|
||||
*ll = NULL;
|
||||
|
||||
return chain;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_chain_add_copy(ngx_pool_t *pool, ngx_chain_t **chain, ngx_chain_t *in)
|
||||
{
|
||||
ngx_chain_t *cl, **ll;
|
||||
|
||||
ll = chain;
|
||||
|
||||
for (cl = *chain; cl; cl = cl->next) {
|
||||
ll = &cl->next;
|
||||
}
|
||||
|
||||
while (in) {
|
||||
cl = ngx_alloc_chain_link(pool);
|
||||
if (cl == NULL) {
|
||||
*ll = NULL;
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
cl->buf = in->buf;
|
||||
*ll = cl;
|
||||
ll = &cl->next;
|
||||
in = in->next;
|
||||
}
|
||||
|
||||
*ll = NULL;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
ngx_chain_t *
|
||||
ngx_chain_get_free_buf(ngx_pool_t *p, ngx_chain_t **free)
|
||||
{
|
||||
ngx_chain_t *cl;
|
||||
|
||||
if (*free) {
|
||||
cl = *free;
|
||||
*free = cl->next;
|
||||
cl->next = NULL;
|
||||
return cl;
|
||||
}
|
||||
|
||||
cl = ngx_alloc_chain_link(p);
|
||||
if (cl == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cl->buf = ngx_calloc_buf(p);
|
||||
if (cl->buf == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cl->next = NULL;
|
||||
|
||||
return cl;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_chain_update_chains(ngx_pool_t *p, ngx_chain_t **free, ngx_chain_t **busy,
|
||||
ngx_chain_t **out, ngx_buf_tag_t tag)
|
||||
{
|
||||
ngx_chain_t *cl;
|
||||
|
||||
if (*out) {
|
||||
if (*busy == NULL) {
|
||||
*busy = *out;
|
||||
|
||||
} else {
|
||||
for (cl = *busy; cl->next; cl = cl->next) { /* void */ }
|
||||
|
||||
cl->next = *out;
|
||||
}
|
||||
|
||||
*out = NULL;
|
||||
}
|
||||
|
||||
while (*busy) {
|
||||
cl = *busy;
|
||||
|
||||
if (cl->buf->tag != tag) {
|
||||
*busy = cl->next;
|
||||
ngx_free_chain(p, cl);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ngx_buf_size(cl->buf) != 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
cl->buf->pos = cl->buf->start;
|
||||
cl->buf->last = cl->buf->start;
|
||||
|
||||
*busy = cl->next;
|
||||
cl->next = *free;
|
||||
*free = cl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
off_t
|
||||
ngx_chain_coalesce_file(ngx_chain_t **in, off_t limit)
|
||||
{
|
||||
off_t total, size, aligned, fprev;
|
||||
ngx_fd_t fd;
|
||||
ngx_chain_t *cl;
|
||||
|
||||
total = 0;
|
||||
|
||||
cl = *in;
|
||||
fd = cl->buf->file->fd;
|
||||
|
||||
do {
|
||||
size = cl->buf->file_last - cl->buf->file_pos;
|
||||
|
||||
if (size > limit - total) {
|
||||
size = limit - total;
|
||||
|
||||
aligned = (cl->buf->file_pos + size + ngx_pagesize - 1)
|
||||
& ~((off_t) ngx_pagesize - 1);
|
||||
|
||||
if (aligned <= cl->buf->file_last) {
|
||||
size = aligned - cl->buf->file_pos;
|
||||
}
|
||||
|
||||
total += size;
|
||||
break;
|
||||
}
|
||||
|
||||
total += size;
|
||||
fprev = cl->buf->file_pos + size;
|
||||
cl = cl->next;
|
||||
|
||||
} while (cl
|
||||
&& cl->buf->in_file
|
||||
&& total < limit
|
||||
&& fd == cl->buf->file->fd
|
||||
&& fprev == cl->buf->file_pos);
|
||||
|
||||
*in = cl;
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
|
||||
ngx_chain_t *
|
||||
ngx_chain_update_sent(ngx_chain_t *in, off_t sent)
|
||||
{
|
||||
off_t size;
|
||||
|
||||
for ( /* void */ ; in; in = in->next) {
|
||||
|
||||
if (ngx_buf_special(in->buf)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sent == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
size = ngx_buf_size(in->buf);
|
||||
|
||||
if (sent >= size) {
|
||||
sent -= size;
|
||||
|
||||
if (ngx_buf_in_memory(in->buf)) {
|
||||
in->buf->pos = in->buf->last;
|
||||
}
|
||||
|
||||
if (in->buf->in_file) {
|
||||
in->buf->file_pos = in->buf->file_last;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ngx_buf_in_memory(in->buf)) {
|
||||
in->buf->pos += (size_t) sent;
|
||||
}
|
||||
|
||||
if (in->buf->in_file) {
|
||||
in->buf->file_pos += sent;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return in;
|
||||
}
|
||||
167
nginx/src/core/ngx_buf.h
Normal file
167
nginx/src/core/ngx_buf.h
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_BUF_H_INCLUDED_
|
||||
#define _NGX_BUF_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
typedef void * ngx_buf_tag_t;
|
||||
|
||||
typedef struct ngx_buf_s ngx_buf_t;
|
||||
|
||||
struct ngx_buf_s {
|
||||
u_char *pos;
|
||||
u_char *last;
|
||||
off_t file_pos;
|
||||
off_t file_last;
|
||||
|
||||
u_char *start; /* start of buffer */
|
||||
u_char *end; /* end of buffer */
|
||||
ngx_buf_tag_t tag;
|
||||
ngx_file_t *file;
|
||||
ngx_buf_t *shadow;
|
||||
|
||||
|
||||
/* the buf's content could be changed */
|
||||
unsigned temporary:1;
|
||||
|
||||
/*
|
||||
* the buf's content is in a memory cache or in a read only memory
|
||||
* and must not be changed
|
||||
*/
|
||||
unsigned memory:1;
|
||||
|
||||
/* the buf's content is mmap()ed and must not be changed */
|
||||
unsigned mmap:1;
|
||||
|
||||
unsigned recycled:1;
|
||||
unsigned in_file:1;
|
||||
unsigned flush:1;
|
||||
unsigned sync:1;
|
||||
unsigned last_buf:1;
|
||||
unsigned last_in_chain:1;
|
||||
|
||||
unsigned last_shadow:1;
|
||||
unsigned temp_file:1;
|
||||
|
||||
/* STUB */ int num;
|
||||
};
|
||||
|
||||
|
||||
struct ngx_chain_s {
|
||||
ngx_buf_t *buf;
|
||||
ngx_chain_t *next;
|
||||
};
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_int_t num;
|
||||
size_t size;
|
||||
} ngx_bufs_t;
|
||||
|
||||
|
||||
typedef struct ngx_output_chain_ctx_s ngx_output_chain_ctx_t;
|
||||
|
||||
typedef ngx_int_t (*ngx_output_chain_filter_pt)(void *ctx, ngx_chain_t *in);
|
||||
|
||||
typedef void (*ngx_output_chain_aio_pt)(ngx_output_chain_ctx_t *ctx,
|
||||
ngx_file_t *file);
|
||||
|
||||
struct ngx_output_chain_ctx_s {
|
||||
ngx_buf_t *buf;
|
||||
ngx_chain_t *in;
|
||||
ngx_chain_t *free;
|
||||
ngx_chain_t *busy;
|
||||
|
||||
unsigned sendfile:1;
|
||||
unsigned directio:1;
|
||||
unsigned unaligned:1;
|
||||
unsigned need_in_memory:1;
|
||||
unsigned need_in_temp:1;
|
||||
unsigned aio:1;
|
||||
|
||||
#if (NGX_HAVE_FILE_AIO || NGX_COMPAT)
|
||||
ngx_output_chain_aio_pt aio_handler;
|
||||
#endif
|
||||
|
||||
#if (NGX_THREADS || NGX_COMPAT)
|
||||
ngx_int_t (*thread_handler)(ngx_thread_task_t *task,
|
||||
ngx_file_t *file);
|
||||
ngx_thread_task_t *thread_task;
|
||||
#endif
|
||||
|
||||
off_t alignment;
|
||||
|
||||
ngx_pool_t *pool;
|
||||
ngx_int_t allocated;
|
||||
ngx_bufs_t bufs;
|
||||
ngx_buf_tag_t tag;
|
||||
|
||||
ngx_output_chain_filter_pt output_filter;
|
||||
void *filter_ctx;
|
||||
};
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_chain_t *out;
|
||||
ngx_chain_t **last;
|
||||
ngx_connection_t *connection;
|
||||
ngx_pool_t *pool;
|
||||
off_t limit;
|
||||
} ngx_chain_writer_ctx_t;
|
||||
|
||||
|
||||
#define NGX_CHAIN_ERROR (ngx_chain_t *) NGX_ERROR
|
||||
|
||||
|
||||
#define ngx_buf_in_memory(b) ((b)->temporary || (b)->memory || (b)->mmap)
|
||||
#define ngx_buf_in_memory_only(b) (ngx_buf_in_memory(b) && !(b)->in_file)
|
||||
|
||||
#define ngx_buf_special(b) \
|
||||
(((b)->flush || (b)->last_buf || (b)->sync) \
|
||||
&& !ngx_buf_in_memory(b) && !(b)->in_file)
|
||||
|
||||
#define ngx_buf_sync_only(b) \
|
||||
((b)->sync && !ngx_buf_in_memory(b) \
|
||||
&& !(b)->in_file && !(b)->flush && !(b)->last_buf)
|
||||
|
||||
#define ngx_buf_size(b) \
|
||||
(ngx_buf_in_memory(b) ? (off_t) ((b)->last - (b)->pos): \
|
||||
((b)->file_last - (b)->file_pos))
|
||||
|
||||
ngx_buf_t *ngx_create_temp_buf(ngx_pool_t *pool, size_t size);
|
||||
ngx_chain_t *ngx_create_chain_of_bufs(ngx_pool_t *pool, ngx_bufs_t *bufs);
|
||||
|
||||
|
||||
#define ngx_alloc_buf(pool) ngx_palloc(pool, sizeof(ngx_buf_t))
|
||||
#define ngx_calloc_buf(pool) ngx_pcalloc(pool, sizeof(ngx_buf_t))
|
||||
|
||||
ngx_chain_t *ngx_alloc_chain_link(ngx_pool_t *pool);
|
||||
#define ngx_free_chain(pool, cl) \
|
||||
(cl)->next = (pool)->chain; \
|
||||
(pool)->chain = (cl)
|
||||
|
||||
|
||||
|
||||
ngx_int_t ngx_output_chain(ngx_output_chain_ctx_t *ctx, ngx_chain_t *in);
|
||||
ngx_int_t ngx_chain_writer(void *ctx, ngx_chain_t *in);
|
||||
|
||||
ngx_int_t ngx_chain_add_copy(ngx_pool_t *pool, ngx_chain_t **chain,
|
||||
ngx_chain_t *in);
|
||||
ngx_chain_t *ngx_chain_get_free_buf(ngx_pool_t *p, ngx_chain_t **free);
|
||||
void ngx_chain_update_chains(ngx_pool_t *p, ngx_chain_t **free,
|
||||
ngx_chain_t **busy, ngx_chain_t **out, ngx_buf_tag_t tag);
|
||||
|
||||
off_t ngx_chain_coalesce_file(ngx_chain_t **in, off_t limit);
|
||||
|
||||
ngx_chain_t *ngx_chain_update_sent(ngx_chain_t *in, off_t sent);
|
||||
|
||||
#endif /* _NGX_BUF_H_INCLUDED_ */
|
||||
1486
nginx/src/core/ngx_conf_file.c
Normal file
1486
nginx/src/core/ngx_conf_file.c
Normal file
File diff suppressed because it is too large
Load diff
295
nginx/src/core/ngx_conf_file.h
Normal file
295
nginx/src/core/ngx_conf_file.h
Normal file
|
|
@ -0,0 +1,295 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_CONF_FILE_H_INCLUDED_
|
||||
#define _NGX_CONF_FILE_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
/*
|
||||
* AAAA number of arguments
|
||||
* FF command flags
|
||||
* TT command type, i.e. HTTP "location" or "server" command
|
||||
*/
|
||||
|
||||
#define NGX_CONF_NOARGS 0x00000001
|
||||
#define NGX_CONF_TAKE1 0x00000002
|
||||
#define NGX_CONF_TAKE2 0x00000004
|
||||
#define NGX_CONF_TAKE3 0x00000008
|
||||
#define NGX_CONF_TAKE4 0x00000010
|
||||
#define NGX_CONF_TAKE5 0x00000020
|
||||
#define NGX_CONF_TAKE6 0x00000040
|
||||
#define NGX_CONF_TAKE7 0x00000080
|
||||
|
||||
#define NGX_CONF_MAX_ARGS 8
|
||||
|
||||
#define NGX_CONF_TAKE12 (NGX_CONF_TAKE1|NGX_CONF_TAKE2)
|
||||
#define NGX_CONF_TAKE13 (NGX_CONF_TAKE1|NGX_CONF_TAKE3)
|
||||
|
||||
#define NGX_CONF_TAKE23 (NGX_CONF_TAKE2|NGX_CONF_TAKE3)
|
||||
|
||||
#define NGX_CONF_TAKE123 (NGX_CONF_TAKE1|NGX_CONF_TAKE2|NGX_CONF_TAKE3)
|
||||
#define NGX_CONF_TAKE1234 (NGX_CONF_TAKE1|NGX_CONF_TAKE2|NGX_CONF_TAKE3 \
|
||||
|NGX_CONF_TAKE4)
|
||||
|
||||
#define NGX_CONF_ARGS_NUMBER 0x000000ff
|
||||
#define NGX_CONF_BLOCK 0x00000100
|
||||
#define NGX_CONF_FLAG 0x00000200
|
||||
#define NGX_CONF_ANY 0x00000400
|
||||
#define NGX_CONF_1MORE 0x00000800
|
||||
#define NGX_CONF_2MORE 0x00001000
|
||||
|
||||
#define NGX_DIRECT_CONF 0x00010000
|
||||
|
||||
#define NGX_MAIN_CONF 0x01000000
|
||||
#define NGX_ANY_CONF 0xFF000000
|
||||
|
||||
|
||||
|
||||
#define NGX_CONF_UNSET -1
|
||||
#define NGX_CONF_UNSET_UINT (ngx_uint_t) -1
|
||||
#define NGX_CONF_UNSET_PTR (void *) -1
|
||||
#define NGX_CONF_UNSET_SIZE (size_t) -1
|
||||
#define NGX_CONF_UNSET_MSEC (ngx_msec_t) -1
|
||||
|
||||
|
||||
#define NGX_CONF_OK NULL
|
||||
#define NGX_CONF_ERROR (void *) -1
|
||||
|
||||
#define NGX_CONF_BLOCK_START 1
|
||||
#define NGX_CONF_BLOCK_DONE 2
|
||||
#define NGX_CONF_FILE_DONE 3
|
||||
|
||||
#define NGX_CORE_MODULE 0x45524F43 /* "CORE" */
|
||||
#define NGX_CONF_MODULE 0x464E4F43 /* "CONF" */
|
||||
|
||||
|
||||
#define NGX_MAX_CONF_ERRSTR 1024
|
||||
|
||||
|
||||
struct ngx_command_s {
|
||||
ngx_str_t name;
|
||||
ngx_uint_t type;
|
||||
char *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
|
||||
ngx_uint_t conf;
|
||||
ngx_uint_t offset;
|
||||
void *post;
|
||||
};
|
||||
|
||||
#define ngx_null_command { ngx_null_string, 0, NULL, 0, 0, NULL }
|
||||
|
||||
|
||||
struct ngx_open_file_s {
|
||||
ngx_fd_t fd;
|
||||
ngx_str_t name;
|
||||
|
||||
void (*flush)(ngx_open_file_t *file, ngx_log_t *log);
|
||||
void *data;
|
||||
};
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_file_t file;
|
||||
ngx_buf_t *buffer;
|
||||
ngx_buf_t *dump;
|
||||
ngx_uint_t line;
|
||||
} ngx_conf_file_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_str_t name;
|
||||
ngx_buf_t *buffer;
|
||||
} ngx_conf_dump_t;
|
||||
|
||||
|
||||
typedef char *(*ngx_conf_handler_pt)(ngx_conf_t *cf,
|
||||
ngx_command_t *dummy, void *conf);
|
||||
|
||||
|
||||
struct ngx_conf_s {
|
||||
char *name;
|
||||
ngx_array_t *args;
|
||||
|
||||
ngx_cycle_t *cycle;
|
||||
ngx_pool_t *pool;
|
||||
ngx_pool_t *temp_pool;
|
||||
ngx_conf_file_t *conf_file;
|
||||
ngx_log_t *log;
|
||||
|
||||
void *ctx;
|
||||
ngx_uint_t module_type;
|
||||
ngx_uint_t cmd_type;
|
||||
|
||||
ngx_conf_handler_pt handler;
|
||||
void *handler_conf;
|
||||
};
|
||||
|
||||
|
||||
typedef char *(*ngx_conf_post_handler_pt) (ngx_conf_t *cf,
|
||||
void *data, void *conf);
|
||||
|
||||
typedef struct {
|
||||
ngx_conf_post_handler_pt post_handler;
|
||||
} ngx_conf_post_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_conf_post_handler_pt post_handler;
|
||||
char *old_name;
|
||||
char *new_name;
|
||||
} ngx_conf_deprecated_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_conf_post_handler_pt post_handler;
|
||||
ngx_int_t low;
|
||||
ngx_int_t high;
|
||||
} ngx_conf_num_bounds_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_str_t name;
|
||||
ngx_uint_t value;
|
||||
} ngx_conf_enum_t;
|
||||
|
||||
|
||||
#define NGX_CONF_BITMASK_SET 1
|
||||
|
||||
typedef struct {
|
||||
ngx_str_t name;
|
||||
ngx_uint_t mask;
|
||||
} ngx_conf_bitmask_t;
|
||||
|
||||
|
||||
|
||||
char * ngx_conf_deprecated(ngx_conf_t *cf, void *post, void *data);
|
||||
char *ngx_conf_check_num_bounds(ngx_conf_t *cf, void *post, void *data);
|
||||
|
||||
|
||||
#define ngx_get_conf(conf_ctx, module) conf_ctx[module.index]
|
||||
|
||||
|
||||
|
||||
#define ngx_conf_init_value(conf, default) \
|
||||
if (conf == NGX_CONF_UNSET) { \
|
||||
conf = default; \
|
||||
}
|
||||
|
||||
#define ngx_conf_init_ptr_value(conf, default) \
|
||||
if (conf == NGX_CONF_UNSET_PTR) { \
|
||||
conf = default; \
|
||||
}
|
||||
|
||||
#define ngx_conf_init_uint_value(conf, default) \
|
||||
if (conf == NGX_CONF_UNSET_UINT) { \
|
||||
conf = default; \
|
||||
}
|
||||
|
||||
#define ngx_conf_init_size_value(conf, default) \
|
||||
if (conf == NGX_CONF_UNSET_SIZE) { \
|
||||
conf = default; \
|
||||
}
|
||||
|
||||
#define ngx_conf_init_msec_value(conf, default) \
|
||||
if (conf == NGX_CONF_UNSET_MSEC) { \
|
||||
conf = default; \
|
||||
}
|
||||
|
||||
#define ngx_conf_merge_value(conf, prev, default) \
|
||||
if (conf == NGX_CONF_UNSET) { \
|
||||
conf = (prev == NGX_CONF_UNSET) ? default : prev; \
|
||||
}
|
||||
|
||||
#define ngx_conf_merge_ptr_value(conf, prev, default) \
|
||||
if (conf == NGX_CONF_UNSET_PTR) { \
|
||||
conf = (prev == NGX_CONF_UNSET_PTR) ? default : prev; \
|
||||
}
|
||||
|
||||
#define ngx_conf_merge_uint_value(conf, prev, default) \
|
||||
if (conf == NGX_CONF_UNSET_UINT) { \
|
||||
conf = (prev == NGX_CONF_UNSET_UINT) ? default : prev; \
|
||||
}
|
||||
|
||||
#define ngx_conf_merge_msec_value(conf, prev, default) \
|
||||
if (conf == NGX_CONF_UNSET_MSEC) { \
|
||||
conf = (prev == NGX_CONF_UNSET_MSEC) ? default : prev; \
|
||||
}
|
||||
|
||||
#define ngx_conf_merge_sec_value(conf, prev, default) \
|
||||
if (conf == NGX_CONF_UNSET) { \
|
||||
conf = (prev == NGX_CONF_UNSET) ? default : prev; \
|
||||
}
|
||||
|
||||
#define ngx_conf_merge_size_value(conf, prev, default) \
|
||||
if (conf == NGX_CONF_UNSET_SIZE) { \
|
||||
conf = (prev == NGX_CONF_UNSET_SIZE) ? default : prev; \
|
||||
}
|
||||
|
||||
#define ngx_conf_merge_off_value(conf, prev, default) \
|
||||
if (conf == NGX_CONF_UNSET) { \
|
||||
conf = (prev == NGX_CONF_UNSET) ? default : prev; \
|
||||
}
|
||||
|
||||
#define ngx_conf_merge_str_value(conf, prev, default) \
|
||||
if (conf.data == NULL) { \
|
||||
if (prev.data) { \
|
||||
conf.len = prev.len; \
|
||||
conf.data = prev.data; \
|
||||
} else { \
|
||||
conf.len = sizeof(default) - 1; \
|
||||
conf.data = (u_char *) default; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define ngx_conf_merge_bufs_value(conf, prev, default_num, default_size) \
|
||||
if (conf.num == 0) { \
|
||||
if (prev.num) { \
|
||||
conf.num = prev.num; \
|
||||
conf.size = prev.size; \
|
||||
} else { \
|
||||
conf.num = default_num; \
|
||||
conf.size = default_size; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define ngx_conf_merge_bitmask_value(conf, prev, default) \
|
||||
if (conf == 0) { \
|
||||
conf = (prev == 0) ? default : prev; \
|
||||
}
|
||||
|
||||
|
||||
char *ngx_conf_param(ngx_conf_t *cf);
|
||||
char *ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename);
|
||||
char *ngx_conf_include(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
|
||||
|
||||
|
||||
ngx_int_t ngx_conf_full_name(ngx_cycle_t *cycle, ngx_str_t *name,
|
||||
ngx_uint_t conf_prefix);
|
||||
ngx_open_file_t *ngx_conf_open_file(ngx_cycle_t *cycle, ngx_str_t *name);
|
||||
void ngx_cdecl ngx_conf_log_error(ngx_uint_t level, ngx_conf_t *cf,
|
||||
ngx_err_t err, const char *fmt, ...);
|
||||
|
||||
|
||||
char *ngx_conf_set_flag_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
|
||||
char *ngx_conf_set_str_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
|
||||
char *ngx_conf_set_str_array_slot(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
char *ngx_conf_set_keyval_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
|
||||
char *ngx_conf_set_num_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
|
||||
char *ngx_conf_set_size_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
|
||||
char *ngx_conf_set_off_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
|
||||
char *ngx_conf_set_msec_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
|
||||
char *ngx_conf_set_sec_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
|
||||
char *ngx_conf_set_bufs_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
|
||||
char *ngx_conf_set_enum_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
|
||||
char *ngx_conf_set_bitmask_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
|
||||
|
||||
|
||||
#endif /* _NGX_CONF_FILE_H_INCLUDED_ */
|
||||
145
nginx/src/core/ngx_config.h
Normal file
145
nginx/src/core/ngx_config.h
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_CONFIG_H_INCLUDED_
|
||||
#define _NGX_CONFIG_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_auto_headers.h>
|
||||
|
||||
|
||||
#if defined __DragonFly__ && !defined __FreeBSD__
|
||||
#define __FreeBSD__ 4
|
||||
#define __FreeBSD_version 480101
|
||||
#endif
|
||||
|
||||
|
||||
#if (NGX_FREEBSD)
|
||||
#include <ngx_freebsd_config.h>
|
||||
|
||||
|
||||
#elif (NGX_LINUX)
|
||||
#include <ngx_linux_config.h>
|
||||
|
||||
|
||||
#elif (NGX_SOLARIS)
|
||||
#include <ngx_solaris_config.h>
|
||||
|
||||
|
||||
#elif (NGX_DARWIN)
|
||||
#include <ngx_darwin_config.h>
|
||||
|
||||
|
||||
#elif (NGX_WIN32)
|
||||
#include <ngx_win32_config.h>
|
||||
|
||||
|
||||
#else /* POSIX */
|
||||
#include <ngx_posix_config.h>
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef NGX_HAVE_SO_SNDLOWAT
|
||||
#define NGX_HAVE_SO_SNDLOWAT 1
|
||||
#endif
|
||||
|
||||
|
||||
#if !(NGX_WIN32)
|
||||
|
||||
#define ngx_signal_helper(n) SIG##n
|
||||
#define ngx_signal_value(n) ngx_signal_helper(n)
|
||||
|
||||
#define ngx_random random
|
||||
|
||||
/* TODO: #ifndef */
|
||||
#define NGX_SHUTDOWN_SIGNAL QUIT
|
||||
#define NGX_TERMINATE_SIGNAL TERM
|
||||
#define NGX_NOACCEPT_SIGNAL WINCH
|
||||
#define NGX_RECONFIGURE_SIGNAL HUP
|
||||
|
||||
#if (NGX_LINUXTHREADS)
|
||||
#define NGX_REOPEN_SIGNAL INFO
|
||||
#define NGX_CHANGEBIN_SIGNAL XCPU
|
||||
#else
|
||||
#define NGX_REOPEN_SIGNAL USR1
|
||||
#define NGX_CHANGEBIN_SIGNAL USR2
|
||||
#endif
|
||||
|
||||
#define ngx_cdecl
|
||||
#define ngx_libc_cdecl
|
||||
|
||||
#endif
|
||||
|
||||
typedef intptr_t ngx_int_t;
|
||||
typedef uintptr_t ngx_uint_t;
|
||||
typedef intptr_t ngx_flag_t;
|
||||
|
||||
|
||||
#define NGX_INT32_LEN (sizeof("-2147483648") - 1)
|
||||
#define NGX_INT64_LEN (sizeof("-9223372036854775808") - 1)
|
||||
|
||||
#if (NGX_PTR_SIZE == 4)
|
||||
#define NGX_INT_T_LEN NGX_INT32_LEN
|
||||
#define NGX_MAX_INT_T_VALUE 2147483647
|
||||
|
||||
#else
|
||||
#define NGX_INT_T_LEN NGX_INT64_LEN
|
||||
#define NGX_MAX_INT_T_VALUE 9223372036854775807
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef NGX_ALIGNMENT
|
||||
#define NGX_ALIGNMENT sizeof(uintptr_t) /* platform word */
|
||||
#endif
|
||||
|
||||
#define ngx_align(d, a) (((d) + (a - 1)) & ~(a - 1))
|
||||
#define ngx_align_ptr(p, a) \
|
||||
(u_char *) (((uintptr_t) (p) + ((uintptr_t) a - 1)) & ~((uintptr_t) a - 1))
|
||||
|
||||
|
||||
#define ngx_abort abort
|
||||
|
||||
|
||||
/* TODO: platform specific: array[NGX_INVALID_ARRAY_INDEX] must cause SIGSEGV */
|
||||
#define NGX_INVALID_ARRAY_INDEX 0x80000000
|
||||
|
||||
|
||||
/* TODO: auto_conf: ngx_inline inline __inline __inline__ */
|
||||
#ifndef ngx_inline
|
||||
#define ngx_inline inline
|
||||
#endif
|
||||
|
||||
#ifndef INADDR_NONE /* Solaris */
|
||||
#define INADDR_NONE ((unsigned int) -1)
|
||||
#endif
|
||||
|
||||
#ifdef MAXHOSTNAMELEN
|
||||
#define NGX_MAXHOSTNAMELEN MAXHOSTNAMELEN
|
||||
#else
|
||||
#define NGX_MAXHOSTNAMELEN 256
|
||||
#endif
|
||||
|
||||
|
||||
#define NGX_MAX_UINT32_VALUE (uint32_t) 0xffffffff
|
||||
#define NGX_MAX_INT32_VALUE (uint32_t) 0x7fffffff
|
||||
|
||||
|
||||
#if (NGX_COMPAT)
|
||||
|
||||
#define NGX_COMPAT_BEGIN(slots) uint64_t spare[slots];
|
||||
#define NGX_COMPAT_END
|
||||
|
||||
#else
|
||||
|
||||
#define NGX_COMPAT_BEGIN(slots)
|
||||
#define NGX_COMPAT_END
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* _NGX_CONFIG_H_INCLUDED_ */
|
||||
1657
nginx/src/core/ngx_connection.c
Normal file
1657
nginx/src/core/ngx_connection.c
Normal file
File diff suppressed because it is too large
Load diff
239
nginx/src/core/ngx_connection.h
Normal file
239
nginx/src/core/ngx_connection.h
Normal file
|
|
@ -0,0 +1,239 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_CONNECTION_H_INCLUDED_
|
||||
#define _NGX_CONNECTION_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
typedef struct ngx_listening_s ngx_listening_t;
|
||||
|
||||
struct ngx_listening_s {
|
||||
ngx_socket_t fd;
|
||||
|
||||
struct sockaddr *sockaddr;
|
||||
socklen_t socklen; /* size of sockaddr */
|
||||
size_t addr_text_max_len;
|
||||
ngx_str_t addr_text;
|
||||
|
||||
int type;
|
||||
int protocol;
|
||||
|
||||
int backlog;
|
||||
int rcvbuf;
|
||||
int sndbuf;
|
||||
#if (NGX_HAVE_KEEPALIVE_TUNABLE)
|
||||
int keepidle;
|
||||
int keepintvl;
|
||||
int keepcnt;
|
||||
#endif
|
||||
|
||||
/* handler of accepted connection */
|
||||
ngx_connection_handler_pt handler;
|
||||
|
||||
void *servers; /* array of ngx_http_in_addr_t, for example */
|
||||
|
||||
ngx_log_t log;
|
||||
ngx_log_t *logp;
|
||||
|
||||
size_t pool_size;
|
||||
/* should be here because of the AcceptEx() preread */
|
||||
size_t post_accept_buffer_size;
|
||||
|
||||
ngx_listening_t *previous;
|
||||
ngx_connection_t *connection;
|
||||
|
||||
ngx_rbtree_t rbtree;
|
||||
ngx_rbtree_node_t sentinel;
|
||||
|
||||
ngx_uint_t worker;
|
||||
|
||||
unsigned open:1;
|
||||
unsigned remain:1;
|
||||
unsigned ignore:1;
|
||||
|
||||
unsigned bound:1; /* already bound */
|
||||
unsigned inherited:1; /* inherited from previous process */
|
||||
unsigned nonblocking_accept:1;
|
||||
unsigned listen:1;
|
||||
unsigned nonblocking:1;
|
||||
unsigned shared:1; /* shared between threads or processes */
|
||||
unsigned addr_ntop:1;
|
||||
unsigned wildcard:1;
|
||||
|
||||
#if (NGX_HAVE_INET6)
|
||||
unsigned ipv6only:1;
|
||||
#endif
|
||||
unsigned reuseport:1;
|
||||
unsigned add_reuseport:1;
|
||||
unsigned keepalive:2;
|
||||
unsigned quic:1;
|
||||
|
||||
unsigned change_protocol:1;
|
||||
|
||||
unsigned deferred_accept:1;
|
||||
unsigned delete_deferred:1;
|
||||
unsigned add_deferred:1;
|
||||
#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
|
||||
char *accept_filter;
|
||||
#endif
|
||||
#if (NGX_HAVE_SETFIB)
|
||||
int setfib;
|
||||
#endif
|
||||
|
||||
#if (NGX_HAVE_TCP_FASTOPEN)
|
||||
int fastopen;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
|
||||
typedef enum {
|
||||
NGX_ERROR_ALERT = 0,
|
||||
NGX_ERROR_ERR,
|
||||
NGX_ERROR_INFO,
|
||||
NGX_ERROR_IGNORE_ECONNRESET,
|
||||
NGX_ERROR_IGNORE_EINVAL,
|
||||
NGX_ERROR_IGNORE_EMSGSIZE
|
||||
} ngx_connection_log_error_e;
|
||||
|
||||
|
||||
typedef enum {
|
||||
NGX_TCP_NODELAY_UNSET = 0,
|
||||
NGX_TCP_NODELAY_SET,
|
||||
NGX_TCP_NODELAY_DISABLED
|
||||
} ngx_connection_tcp_nodelay_e;
|
||||
|
||||
|
||||
typedef enum {
|
||||
NGX_TCP_NOPUSH_UNSET = 0,
|
||||
NGX_TCP_NOPUSH_SET,
|
||||
NGX_TCP_NOPUSH_DISABLED
|
||||
} ngx_connection_tcp_nopush_e;
|
||||
|
||||
|
||||
#define NGX_LOWLEVEL_BUFFERED 0x0f
|
||||
#define NGX_SSL_BUFFERED 0x01
|
||||
#define NGX_HTTP_V2_BUFFERED 0x02
|
||||
|
||||
|
||||
struct ngx_connection_s {
|
||||
void *data;
|
||||
ngx_event_t *read;
|
||||
ngx_event_t *write;
|
||||
|
||||
ngx_socket_t fd;
|
||||
|
||||
ngx_recv_pt recv;
|
||||
ngx_send_pt send;
|
||||
ngx_recv_chain_pt recv_chain;
|
||||
ngx_send_chain_pt send_chain;
|
||||
|
||||
ngx_listening_t *listening;
|
||||
|
||||
off_t sent;
|
||||
|
||||
ngx_log_t *log;
|
||||
|
||||
ngx_pool_t *pool;
|
||||
|
||||
int type;
|
||||
|
||||
struct sockaddr *sockaddr;
|
||||
socklen_t socklen;
|
||||
ngx_str_t addr_text;
|
||||
|
||||
ngx_proxy_protocol_t *proxy_protocol;
|
||||
|
||||
#if (NGX_QUIC || NGX_COMPAT)
|
||||
ngx_quic_stream_t *quic;
|
||||
#endif
|
||||
|
||||
#if (NGX_SSL || NGX_COMPAT)
|
||||
ngx_ssl_connection_t *ssl;
|
||||
#endif
|
||||
|
||||
ngx_udp_connection_t *udp;
|
||||
|
||||
struct sockaddr *local_sockaddr;
|
||||
socklen_t local_socklen;
|
||||
|
||||
ngx_buf_t *buffer;
|
||||
|
||||
ngx_queue_t queue;
|
||||
|
||||
ngx_atomic_uint_t number;
|
||||
|
||||
ngx_msec_t start_time;
|
||||
ngx_uint_t requests;
|
||||
|
||||
unsigned buffered:8;
|
||||
|
||||
unsigned log_error:3; /* ngx_connection_log_error_e */
|
||||
|
||||
unsigned timedout:1;
|
||||
unsigned error:1;
|
||||
unsigned destroyed:1;
|
||||
unsigned pipeline:1;
|
||||
|
||||
unsigned idle:1;
|
||||
unsigned reusable:1;
|
||||
unsigned close:1;
|
||||
unsigned shared:1;
|
||||
|
||||
unsigned sendfile:1;
|
||||
unsigned sndlowat:1;
|
||||
unsigned tcp_nodelay:2; /* ngx_connection_tcp_nodelay_e */
|
||||
unsigned tcp_nopush:2; /* ngx_connection_tcp_nopush_e */
|
||||
|
||||
unsigned need_last_buf:1;
|
||||
unsigned need_flush_buf:1;
|
||||
|
||||
#if (NGX_HAVE_SENDFILE_NODISKIO || NGX_COMPAT)
|
||||
unsigned busy_count:2;
|
||||
#endif
|
||||
|
||||
#if (NGX_THREADS || NGX_COMPAT)
|
||||
ngx_thread_task_t *sendfile_task;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
#define ngx_set_connection_log(c, l) \
|
||||
\
|
||||
c->log->file = l->file; \
|
||||
c->log->next = l->next; \
|
||||
c->log->writer = l->writer; \
|
||||
c->log->wdata = l->wdata; \
|
||||
if (!(c->log->log_level & NGX_LOG_DEBUG_CONNECTION)) { \
|
||||
c->log->log_level = l->log_level; \
|
||||
}
|
||||
|
||||
|
||||
ngx_listening_t *ngx_create_listening(ngx_conf_t *cf, struct sockaddr *sockaddr,
|
||||
socklen_t socklen);
|
||||
ngx_int_t ngx_clone_listening(ngx_cycle_t *cycle, ngx_listening_t *ls);
|
||||
ngx_int_t ngx_set_inherited_sockets(ngx_cycle_t *cycle);
|
||||
ngx_int_t ngx_open_listening_sockets(ngx_cycle_t *cycle);
|
||||
void ngx_configure_listening_sockets(ngx_cycle_t *cycle);
|
||||
void ngx_close_listening_sockets(ngx_cycle_t *cycle);
|
||||
void ngx_close_connection(ngx_connection_t *c);
|
||||
void ngx_close_idle_connections(ngx_cycle_t *cycle);
|
||||
ngx_int_t ngx_connection_local_sockaddr(ngx_connection_t *c, ngx_str_t *s,
|
||||
ngx_uint_t port);
|
||||
ngx_int_t ngx_tcp_nodelay(ngx_connection_t *c);
|
||||
ngx_int_t ngx_connection_error(ngx_connection_t *c, ngx_err_t err, char *text);
|
||||
|
||||
ngx_connection_t *ngx_get_connection(ngx_socket_t s, ngx_log_t *log);
|
||||
void ngx_free_connection(ngx_connection_t *c);
|
||||
|
||||
void ngx_reusable_connection(ngx_connection_t *c, ngx_uint_t reusable);
|
||||
|
||||
#endif /* _NGX_CONNECTION_H_INCLUDED_ */
|
||||
121
nginx/src/core/ngx_core.h
Normal file
121
nginx/src/core/ngx_core.h
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_CORE_H_INCLUDED_
|
||||
#define _NGX_CORE_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
|
||||
|
||||
typedef struct ngx_module_s ngx_module_t;
|
||||
typedef struct ngx_conf_s ngx_conf_t;
|
||||
typedef struct ngx_cycle_s ngx_cycle_t;
|
||||
typedef struct ngx_pool_s ngx_pool_t;
|
||||
typedef struct ngx_chain_s ngx_chain_t;
|
||||
typedef struct ngx_log_s ngx_log_t;
|
||||
typedef struct ngx_open_file_s ngx_open_file_t;
|
||||
typedef struct ngx_command_s ngx_command_t;
|
||||
typedef struct ngx_file_s ngx_file_t;
|
||||
typedef struct ngx_event_s ngx_event_t;
|
||||
typedef struct ngx_event_aio_s ngx_event_aio_t;
|
||||
typedef struct ngx_connection_s ngx_connection_t;
|
||||
typedef struct ngx_thread_task_s ngx_thread_task_t;
|
||||
typedef struct ngx_ssl_s ngx_ssl_t;
|
||||
typedef struct ngx_ssl_cache_s ngx_ssl_cache_t;
|
||||
typedef struct ngx_proxy_protocol_s ngx_proxy_protocol_t;
|
||||
typedef struct ngx_quic_stream_s ngx_quic_stream_t;
|
||||
typedef struct ngx_ssl_connection_s ngx_ssl_connection_t;
|
||||
typedef struct ngx_udp_connection_s ngx_udp_connection_t;
|
||||
|
||||
typedef void (*ngx_event_handler_pt)(ngx_event_t *ev);
|
||||
typedef void (*ngx_connection_handler_pt)(ngx_connection_t *c);
|
||||
|
||||
|
||||
#define NGX_OK 0
|
||||
#define NGX_ERROR -1
|
||||
#define NGX_AGAIN -2
|
||||
#define NGX_BUSY -3
|
||||
#define NGX_DONE -4
|
||||
#define NGX_DECLINED -5
|
||||
#define NGX_ABORT -6
|
||||
|
||||
|
||||
#include <ngx_errno.h>
|
||||
#include <ngx_atomic.h>
|
||||
#include <ngx_thread.h>
|
||||
#include <ngx_rbtree.h>
|
||||
#include <ngx_time.h>
|
||||
#include <ngx_socket.h>
|
||||
#include <ngx_string.h>
|
||||
#include <ngx_files.h>
|
||||
#include <ngx_shmem.h>
|
||||
#include <ngx_process.h>
|
||||
#include <ngx_user.h>
|
||||
#include <ngx_dlopen.h>
|
||||
#include <ngx_parse.h>
|
||||
#include <ngx_parse_time.h>
|
||||
#include <ngx_log.h>
|
||||
#include <ngx_alloc.h>
|
||||
#include <ngx_palloc.h>
|
||||
#include <ngx_buf.h>
|
||||
#include <ngx_queue.h>
|
||||
#include <ngx_array.h>
|
||||
#include <ngx_list.h>
|
||||
#include <ngx_hash.h>
|
||||
#include <ngx_file.h>
|
||||
#include <ngx_crc.h>
|
||||
#include <ngx_crc32.h>
|
||||
#include <ngx_murmurhash.h>
|
||||
#if (NGX_PCRE)
|
||||
#include <ngx_regex.h>
|
||||
#endif
|
||||
#include <ngx_radix_tree.h>
|
||||
#include <ngx_times.h>
|
||||
#include <ngx_rwlock.h>
|
||||
#include <ngx_shmtx.h>
|
||||
#include <ngx_slab.h>
|
||||
#include <ngx_inet.h>
|
||||
#include <ngx_cycle.h>
|
||||
#include <ngx_resolver.h>
|
||||
#if (NGX_OPENSSL)
|
||||
#include <ngx_event_openssl.h>
|
||||
#if (NGX_QUIC)
|
||||
#include <ngx_event_quic.h>
|
||||
#endif
|
||||
#endif
|
||||
#include <ngx_process_cycle.h>
|
||||
#include <ngx_conf_file.h>
|
||||
#include <ngx_module.h>
|
||||
#include <ngx_open_file_cache.h>
|
||||
#include <ngx_os.h>
|
||||
#include <ngx_connection.h>
|
||||
#include <ngx_syslog.h>
|
||||
#include <ngx_proxy_protocol.h>
|
||||
#if (NGX_HAVE_BPF)
|
||||
#include <ngx_bpf.h>
|
||||
#endif
|
||||
|
||||
|
||||
#define LF (u_char) '\n'
|
||||
#define CR (u_char) '\r'
|
||||
#define CRLF "\r\n"
|
||||
|
||||
|
||||
#define ngx_abs(value) (((value) >= 0) ? (value) : - (value))
|
||||
#define ngx_max(val1, val2) ((val1 < val2) ? (val2) : (val1))
|
||||
#define ngx_min(val1, val2) ((val1 > val2) ? (val2) : (val1))
|
||||
|
||||
void ngx_cpuinfo(void);
|
||||
|
||||
#if (NGX_HAVE_OPENAT)
|
||||
#define NGX_DISABLE_SYMLINKS_OFF 0
|
||||
#define NGX_DISABLE_SYMLINKS_ON 1
|
||||
#define NGX_DISABLE_SYMLINKS_NOTOWNER 2
|
||||
#endif
|
||||
|
||||
#endif /* _NGX_CORE_H_INCLUDED_ */
|
||||
139
nginx/src/core/ngx_cpuinfo.c
Normal file
139
nginx/src/core/ngx_cpuinfo.c
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
#if (( __i386__ || __amd64__ ) && ( __GNUC__ || __INTEL_COMPILER ))
|
||||
|
||||
|
||||
static ngx_inline void ngx_cpuid(uint32_t i, uint32_t *buf);
|
||||
|
||||
|
||||
#if ( __i386__ )
|
||||
|
||||
static ngx_inline void
|
||||
ngx_cpuid(uint32_t i, uint32_t *buf)
|
||||
{
|
||||
|
||||
/*
|
||||
* we could not use %ebx as output parameter if gcc builds PIC,
|
||||
* and we could not save %ebx on stack, because %esp is used,
|
||||
* when the -fomit-frame-pointer optimization is specified.
|
||||
*/
|
||||
|
||||
__asm__ (
|
||||
|
||||
" mov %%ebx, %%esi; "
|
||||
|
||||
" cpuid; "
|
||||
" mov %%eax, (%1); "
|
||||
" mov %%ebx, 4(%1); "
|
||||
" mov %%edx, 8(%1); "
|
||||
" mov %%ecx, 12(%1); "
|
||||
|
||||
" mov %%esi, %%ebx; "
|
||||
|
||||
: : "a" (i), "D" (buf) : "ecx", "edx", "esi", "memory" );
|
||||
}
|
||||
|
||||
|
||||
#else /* __amd64__ */
|
||||
|
||||
|
||||
static ngx_inline void
|
||||
ngx_cpuid(uint32_t i, uint32_t *buf)
|
||||
{
|
||||
uint32_t eax, ebx, ecx, edx;
|
||||
|
||||
__asm__ (
|
||||
|
||||
"cpuid"
|
||||
|
||||
: "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (i) );
|
||||
|
||||
buf[0] = eax;
|
||||
buf[1] = ebx;
|
||||
buf[2] = edx;
|
||||
buf[3] = ecx;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* auto detect the L2 cache line size of modern and widespread CPUs */
|
||||
|
||||
void
|
||||
ngx_cpuinfo(void)
|
||||
{
|
||||
u_char *vendor;
|
||||
uint32_t vbuf[5], cpu[4], model;
|
||||
|
||||
vbuf[0] = 0;
|
||||
vbuf[1] = 0;
|
||||
vbuf[2] = 0;
|
||||
vbuf[3] = 0;
|
||||
vbuf[4] = 0;
|
||||
|
||||
ngx_cpuid(0, vbuf);
|
||||
|
||||
vendor = (u_char *) &vbuf[1];
|
||||
|
||||
if (vbuf[0] == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_cpuid(1, cpu);
|
||||
|
||||
if (ngx_strcmp(vendor, "GenuineIntel") == 0) {
|
||||
|
||||
switch ((cpu[0] & 0xf00) >> 8) {
|
||||
|
||||
/* Pentium */
|
||||
case 5:
|
||||
ngx_cacheline_size = 32;
|
||||
break;
|
||||
|
||||
/* Pentium Pro, II, III */
|
||||
case 6:
|
||||
ngx_cacheline_size = 32;
|
||||
|
||||
model = ((cpu[0] & 0xf0000) >> 8) | (cpu[0] & 0xf0);
|
||||
|
||||
if (model >= 0xd0) {
|
||||
/* Intel Core, Core 2, Atom */
|
||||
ngx_cacheline_size = 64;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
/*
|
||||
* Pentium 4, although its cache line size is 64 bytes,
|
||||
* it prefetches up to two cache lines during memory read
|
||||
*/
|
||||
case 15:
|
||||
ngx_cacheline_size = 128;
|
||||
break;
|
||||
}
|
||||
|
||||
} else if (ngx_strcmp(vendor, "AuthenticAMD") == 0) {
|
||||
ngx_cacheline_size = 64;
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
|
||||
void
|
||||
ngx_cpuinfo(void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
39
nginx/src/core/ngx_crc.h
Normal file
39
nginx/src/core/ngx_crc.h
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_CRC_H_INCLUDED_
|
||||
#define _NGX_CRC_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
/* 32-bit crc16 */
|
||||
|
||||
static ngx_inline uint32_t
|
||||
ngx_crc(u_char *data, size_t len)
|
||||
{
|
||||
uint32_t sum;
|
||||
|
||||
for (sum = 0; len; len--) {
|
||||
|
||||
/*
|
||||
* gcc 2.95.2 x86 and icc 7.1.006 compile
|
||||
* that operator into the single "rol" opcode,
|
||||
* msvc 6.0sp2 compiles it into four opcodes.
|
||||
*/
|
||||
sum = sum >> 1 | sum << 31;
|
||||
|
||||
sum += *data++;
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
|
||||
#endif /* _NGX_CRC_H_INCLUDED_ */
|
||||
129
nginx/src/core/ngx_crc32.c
Normal file
129
nginx/src/core/ngx_crc32.c
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
/*
|
||||
* The code and lookup tables are based on the algorithm
|
||||
* described at http://www.w3.org/TR/PNG/
|
||||
*
|
||||
* The 256 element lookup table takes 1024 bytes, and it may be completely
|
||||
* cached after processing about 30-60 bytes of data. So for short data
|
||||
* we use the 16 element lookup table that takes only 64 bytes and align it
|
||||
* to CPU cache line size. Of course, the small table adds code inside
|
||||
* CRC32 loop, but the cache misses overhead is bigger than overhead of
|
||||
* the additional code. For example, ngx_crc32_short() of 16 bytes of data
|
||||
* takes half as much CPU clocks than ngx_crc32_long().
|
||||
*/
|
||||
|
||||
|
||||
static uint32_t ngx_crc32_table16[] = {
|
||||
0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
|
||||
0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
|
||||
0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
|
||||
0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
|
||||
};
|
||||
|
||||
|
||||
uint32_t ngx_crc32_table256[] = {
|
||||
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
|
||||
0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
|
||||
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
|
||||
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
|
||||
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
|
||||
0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
|
||||
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
|
||||
0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
|
||||
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
|
||||
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
|
||||
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
|
||||
0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
|
||||
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
|
||||
0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
|
||||
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
|
||||
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
|
||||
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
|
||||
0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
|
||||
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
|
||||
0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
|
||||
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
|
||||
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
|
||||
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
|
||||
0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
|
||||
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
|
||||
0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
|
||||
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
|
||||
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
|
||||
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
|
||||
0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
|
||||
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
|
||||
0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
|
||||
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
|
||||
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
|
||||
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
|
||||
0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
|
||||
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
|
||||
0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
|
||||
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
|
||||
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
|
||||
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
|
||||
0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
|
||||
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
|
||||
0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
|
||||
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
|
||||
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
|
||||
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
|
||||
0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
|
||||
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
|
||||
0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
|
||||
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
|
||||
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
|
||||
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
|
||||
0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
|
||||
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
|
||||
0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
|
||||
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
|
||||
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
|
||||
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
|
||||
0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
|
||||
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
|
||||
0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
|
||||
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
|
||||
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
|
||||
};
|
||||
|
||||
|
||||
uint32_t *ngx_crc32_table_short = ngx_crc32_table16;
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_crc32_table_init(void)
|
||||
{
|
||||
void *p;
|
||||
|
||||
if (((uintptr_t) ngx_crc32_table_short
|
||||
& ~((uintptr_t) ngx_cacheline_size - 1))
|
||||
== (uintptr_t) ngx_crc32_table_short)
|
||||
{
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
p = ngx_alloc(16 * sizeof(uint32_t) + ngx_cacheline_size, ngx_cycle->log);
|
||||
if (p == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
p = ngx_align_ptr(p, ngx_cacheline_size);
|
||||
|
||||
ngx_memcpy(p, ngx_crc32_table16, 16 * sizeof(uint32_t));
|
||||
|
||||
ngx_crc32_table_short = p;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
79
nginx/src/core/ngx_crc32.h
Normal file
79
nginx/src/core/ngx_crc32.h
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_CRC32_H_INCLUDED_
|
||||
#define _NGX_CRC32_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
extern uint32_t *ngx_crc32_table_short;
|
||||
extern uint32_t ngx_crc32_table256[];
|
||||
|
||||
|
||||
static ngx_inline uint32_t
|
||||
ngx_crc32_short(u_char *p, size_t len)
|
||||
{
|
||||
u_char c;
|
||||
uint32_t crc;
|
||||
|
||||
crc = 0xffffffff;
|
||||
|
||||
while (len--) {
|
||||
c = *p++;
|
||||
crc = ngx_crc32_table_short[(crc ^ (c & 0xf)) & 0xf] ^ (crc >> 4);
|
||||
crc = ngx_crc32_table_short[(crc ^ (c >> 4)) & 0xf] ^ (crc >> 4);
|
||||
}
|
||||
|
||||
return crc ^ 0xffffffff;
|
||||
}
|
||||
|
||||
|
||||
static ngx_inline uint32_t
|
||||
ngx_crc32_long(u_char *p, size_t len)
|
||||
{
|
||||
uint32_t crc;
|
||||
|
||||
crc = 0xffffffff;
|
||||
|
||||
while (len--) {
|
||||
crc = ngx_crc32_table256[(crc ^ *p++) & 0xff] ^ (crc >> 8);
|
||||
}
|
||||
|
||||
return crc ^ 0xffffffff;
|
||||
}
|
||||
|
||||
|
||||
#define ngx_crc32_init(crc) \
|
||||
crc = 0xffffffff
|
||||
|
||||
|
||||
static ngx_inline void
|
||||
ngx_crc32_update(uint32_t *crc, u_char *p, size_t len)
|
||||
{
|
||||
uint32_t c;
|
||||
|
||||
c = *crc;
|
||||
|
||||
while (len--) {
|
||||
c = ngx_crc32_table256[(c ^ *p++) & 0xff] ^ (c >> 8);
|
||||
}
|
||||
|
||||
*crc = c;
|
||||
}
|
||||
|
||||
|
||||
#define ngx_crc32_final(crc) \
|
||||
crc ^= 0xffffffff
|
||||
|
||||
|
||||
ngx_int_t ngx_crc32_table_init(void);
|
||||
|
||||
|
||||
#endif /* _NGX_CRC32_H_INCLUDED_ */
|
||||
270
nginx/src/core/ngx_crypt.c
Normal file
270
nginx/src/core/ngx_crypt.c
Normal file
|
|
@ -0,0 +1,270 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Maxim Dounin
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_crypt.h>
|
||||
#include <ngx_md5.h>
|
||||
#include <ngx_sha1.h>
|
||||
|
||||
|
||||
#if (NGX_CRYPT)
|
||||
|
||||
static ngx_int_t ngx_crypt_apr1(ngx_pool_t *pool, u_char *key, u_char *salt,
|
||||
u_char **encrypted);
|
||||
static ngx_int_t ngx_crypt_plain(ngx_pool_t *pool, u_char *key, u_char *salt,
|
||||
u_char **encrypted);
|
||||
static ngx_int_t ngx_crypt_ssha(ngx_pool_t *pool, u_char *key, u_char *salt,
|
||||
u_char **encrypted);
|
||||
static ngx_int_t ngx_crypt_sha(ngx_pool_t *pool, u_char *key, u_char *salt,
|
||||
u_char **encrypted);
|
||||
|
||||
|
||||
static u_char *ngx_crypt_to64(u_char *p, uint32_t v, size_t n);
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_crypt(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
|
||||
{
|
||||
if (ngx_strncmp(salt, "$apr1$", sizeof("$apr1$") - 1) == 0) {
|
||||
return ngx_crypt_apr1(pool, key, salt, encrypted);
|
||||
|
||||
} else if (ngx_strncmp(salt, "{PLAIN}", sizeof("{PLAIN}") - 1) == 0) {
|
||||
return ngx_crypt_plain(pool, key, salt, encrypted);
|
||||
|
||||
} else if (ngx_strncmp(salt, "{SSHA}", sizeof("{SSHA}") - 1) == 0) {
|
||||
return ngx_crypt_ssha(pool, key, salt, encrypted);
|
||||
|
||||
} else if (ngx_strncmp(salt, "{SHA}", sizeof("{SHA}") - 1) == 0) {
|
||||
return ngx_crypt_sha(pool, key, salt, encrypted);
|
||||
}
|
||||
|
||||
/* fallback to libc crypt() */
|
||||
|
||||
return ngx_libc_crypt(pool, key, salt, encrypted);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_crypt_apr1(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
|
||||
{
|
||||
ngx_int_t n;
|
||||
ngx_uint_t i;
|
||||
u_char *p, *last, final[16];
|
||||
size_t saltlen, keylen;
|
||||
ngx_md5_t md5, ctx1;
|
||||
|
||||
/* Apache's apr1 crypt is Poul-Henning Kamp's md5 crypt with $apr1$ magic */
|
||||
|
||||
keylen = ngx_strlen(key);
|
||||
|
||||
/* true salt: no magic, max 8 chars, stop at first $ */
|
||||
|
||||
salt += sizeof("$apr1$") - 1;
|
||||
last = salt + 8;
|
||||
for (p = salt; *p && *p != '$' && p < last; p++) { /* void */ }
|
||||
saltlen = p - salt;
|
||||
|
||||
/* hash key and salt */
|
||||
|
||||
ngx_md5_init(&md5);
|
||||
ngx_md5_update(&md5, key, keylen);
|
||||
ngx_md5_update(&md5, (u_char *) "$apr1$", sizeof("$apr1$") - 1);
|
||||
ngx_md5_update(&md5, salt, saltlen);
|
||||
|
||||
ngx_md5_init(&ctx1);
|
||||
ngx_md5_update(&ctx1, key, keylen);
|
||||
ngx_md5_update(&ctx1, salt, saltlen);
|
||||
ngx_md5_update(&ctx1, key, keylen);
|
||||
ngx_md5_final(final, &ctx1);
|
||||
|
||||
for (n = keylen; n > 0; n -= 16) {
|
||||
ngx_md5_update(&md5, final, n > 16 ? 16 : n);
|
||||
}
|
||||
|
||||
ngx_memzero(final, sizeof(final));
|
||||
|
||||
for (i = keylen; i; i >>= 1) {
|
||||
if (i & 1) {
|
||||
ngx_md5_update(&md5, final, 1);
|
||||
|
||||
} else {
|
||||
ngx_md5_update(&md5, key, 1);
|
||||
}
|
||||
}
|
||||
|
||||
ngx_md5_final(final, &md5);
|
||||
|
||||
for (i = 0; i < 1000; i++) {
|
||||
ngx_md5_init(&ctx1);
|
||||
|
||||
if (i & 1) {
|
||||
ngx_md5_update(&ctx1, key, keylen);
|
||||
|
||||
} else {
|
||||
ngx_md5_update(&ctx1, final, 16);
|
||||
}
|
||||
|
||||
if (i % 3) {
|
||||
ngx_md5_update(&ctx1, salt, saltlen);
|
||||
}
|
||||
|
||||
if (i % 7) {
|
||||
ngx_md5_update(&ctx1, key, keylen);
|
||||
}
|
||||
|
||||
if (i & 1) {
|
||||
ngx_md5_update(&ctx1, final, 16);
|
||||
|
||||
} else {
|
||||
ngx_md5_update(&ctx1, key, keylen);
|
||||
}
|
||||
|
||||
ngx_md5_final(final, &ctx1);
|
||||
}
|
||||
|
||||
/* output */
|
||||
|
||||
*encrypted = ngx_pnalloc(pool, sizeof("$apr1$") - 1 + saltlen + 1 + 22 + 1);
|
||||
if (*encrypted == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
p = ngx_cpymem(*encrypted, "$apr1$", sizeof("$apr1$") - 1);
|
||||
p = ngx_copy(p, salt, saltlen);
|
||||
*p++ = '$';
|
||||
|
||||
p = ngx_crypt_to64(p, (final[ 0]<<16) | (final[ 6]<<8) | final[12], 4);
|
||||
p = ngx_crypt_to64(p, (final[ 1]<<16) | (final[ 7]<<8) | final[13], 4);
|
||||
p = ngx_crypt_to64(p, (final[ 2]<<16) | (final[ 8]<<8) | final[14], 4);
|
||||
p = ngx_crypt_to64(p, (final[ 3]<<16) | (final[ 9]<<8) | final[15], 4);
|
||||
p = ngx_crypt_to64(p, (final[ 4]<<16) | (final[10]<<8) | final[ 5], 4);
|
||||
p = ngx_crypt_to64(p, final[11], 2);
|
||||
*p = '\0';
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static u_char *
|
||||
ngx_crypt_to64(u_char *p, uint32_t v, size_t n)
|
||||
{
|
||||
static u_char itoa64[] =
|
||||
"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
while (n--) {
|
||||
*p++ = itoa64[v & 0x3f];
|
||||
v >>= 6;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_crypt_plain(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
|
||||
{
|
||||
size_t len;
|
||||
u_char *p;
|
||||
|
||||
len = ngx_strlen(key);
|
||||
|
||||
*encrypted = ngx_pnalloc(pool, sizeof("{PLAIN}") - 1 + len + 1);
|
||||
if (*encrypted == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
p = ngx_cpymem(*encrypted, "{PLAIN}", sizeof("{PLAIN}") - 1);
|
||||
ngx_memcpy(p, key, len + 1);
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_crypt_ssha(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
|
||||
{
|
||||
size_t len;
|
||||
ngx_int_t rc;
|
||||
ngx_str_t encoded, decoded;
|
||||
ngx_sha1_t sha1;
|
||||
|
||||
/* "{SSHA}" base64(SHA1(key salt) salt) */
|
||||
|
||||
/* decode base64 salt to find out true salt */
|
||||
|
||||
encoded.data = salt + sizeof("{SSHA}") - 1;
|
||||
encoded.len = ngx_strlen(encoded.data);
|
||||
|
||||
len = ngx_max(ngx_base64_decoded_length(encoded.len), 20);
|
||||
|
||||
decoded.data = ngx_pnalloc(pool, len);
|
||||
if (decoded.data == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
rc = ngx_decode_base64(&decoded, &encoded);
|
||||
|
||||
if (rc != NGX_OK || decoded.len < 20) {
|
||||
decoded.len = 20;
|
||||
}
|
||||
|
||||
/* update SHA1 from key and salt */
|
||||
|
||||
ngx_sha1_init(&sha1);
|
||||
ngx_sha1_update(&sha1, key, ngx_strlen(key));
|
||||
ngx_sha1_update(&sha1, decoded.data + 20, decoded.len - 20);
|
||||
ngx_sha1_final(decoded.data, &sha1);
|
||||
|
||||
/* encode it back to base64 */
|
||||
|
||||
len = sizeof("{SSHA}") - 1 + ngx_base64_encoded_length(decoded.len) + 1;
|
||||
|
||||
*encrypted = ngx_pnalloc(pool, len);
|
||||
if (*encrypted == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
encoded.data = ngx_cpymem(*encrypted, "{SSHA}", sizeof("{SSHA}") - 1);
|
||||
ngx_encode_base64(&encoded, &decoded);
|
||||
encoded.data[encoded.len] = '\0';
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_crypt_sha(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
|
||||
{
|
||||
size_t len;
|
||||
ngx_str_t encoded, decoded;
|
||||
ngx_sha1_t sha1;
|
||||
u_char digest[20];
|
||||
|
||||
/* "{SHA}" base64(SHA1(key)) */
|
||||
|
||||
decoded.len = sizeof(digest);
|
||||
decoded.data = digest;
|
||||
|
||||
ngx_sha1_init(&sha1);
|
||||
ngx_sha1_update(&sha1, key, ngx_strlen(key));
|
||||
ngx_sha1_final(digest, &sha1);
|
||||
|
||||
len = sizeof("{SHA}") - 1 + ngx_base64_encoded_length(decoded.len) + 1;
|
||||
|
||||
*encrypted = ngx_pnalloc(pool, len);
|
||||
if (*encrypted == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
encoded.data = ngx_cpymem(*encrypted, "{SHA}", sizeof("{SHA}") - 1);
|
||||
ngx_encode_base64(&encoded, &decoded);
|
||||
encoded.data[encoded.len] = '\0';
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
#endif /* NGX_CRYPT */
|
||||
20
nginx/src/core/ngx_crypt.h
Normal file
20
nginx/src/core/ngx_crypt.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_CRYPT_H_INCLUDED_
|
||||
#define _NGX_CRYPT_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
ngx_int_t ngx_crypt(ngx_pool_t *pool, u_char *key, u_char *salt,
|
||||
u_char **encrypted);
|
||||
|
||||
|
||||
#endif /* _NGX_CRYPT_H_INCLUDED_ */
|
||||
1484
nginx/src/core/ngx_cycle.c
Normal file
1484
nginx/src/core/ngx_cycle.c
Normal file
File diff suppressed because it is too large
Load diff
149
nginx/src/core/ngx_cycle.h
Normal file
149
nginx/src/core/ngx_cycle.h
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_CYCLE_H_INCLUDED_
|
||||
#define _NGX_CYCLE_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
#ifndef NGX_CYCLE_POOL_SIZE
|
||||
#define NGX_CYCLE_POOL_SIZE NGX_DEFAULT_POOL_SIZE
|
||||
#endif
|
||||
|
||||
|
||||
#define NGX_DEBUG_POINTS_STOP 1
|
||||
#define NGX_DEBUG_POINTS_ABORT 2
|
||||
|
||||
|
||||
typedef struct ngx_shm_zone_s ngx_shm_zone_t;
|
||||
|
||||
typedef ngx_int_t (*ngx_shm_zone_init_pt) (ngx_shm_zone_t *zone, void *data);
|
||||
|
||||
struct ngx_shm_zone_s {
|
||||
void *data;
|
||||
ngx_shm_t shm;
|
||||
ngx_shm_zone_init_pt init;
|
||||
void *tag;
|
||||
void *sync;
|
||||
ngx_uint_t noreuse; /* unsigned noreuse:1; */
|
||||
};
|
||||
|
||||
|
||||
struct ngx_cycle_s {
|
||||
void ****conf_ctx;
|
||||
ngx_pool_t *pool;
|
||||
|
||||
ngx_log_t *log;
|
||||
ngx_log_t new_log;
|
||||
|
||||
ngx_uint_t log_use_stderr; /* unsigned log_use_stderr:1; */
|
||||
|
||||
ngx_connection_t **files;
|
||||
ngx_connection_t *free_connections;
|
||||
ngx_uint_t free_connection_n;
|
||||
|
||||
ngx_module_t **modules;
|
||||
ngx_uint_t modules_n;
|
||||
ngx_uint_t modules_used; /* unsigned modules_used:1; */
|
||||
|
||||
ngx_queue_t reusable_connections_queue;
|
||||
ngx_uint_t reusable_connections_n;
|
||||
time_t connections_reuse_time;
|
||||
|
||||
ngx_array_t listening;
|
||||
ngx_array_t paths;
|
||||
|
||||
ngx_array_t config_dump;
|
||||
ngx_rbtree_t config_dump_rbtree;
|
||||
ngx_rbtree_node_t config_dump_sentinel;
|
||||
|
||||
ngx_list_t open_files;
|
||||
ngx_list_t shared_memory;
|
||||
|
||||
ngx_uint_t connection_n;
|
||||
ngx_uint_t files_n;
|
||||
|
||||
ngx_connection_t *connections;
|
||||
ngx_event_t *read_events;
|
||||
ngx_event_t *write_events;
|
||||
|
||||
ngx_cycle_t *old_cycle;
|
||||
|
||||
ngx_str_t conf_file;
|
||||
ngx_str_t conf_param;
|
||||
ngx_str_t conf_prefix;
|
||||
ngx_str_t prefix;
|
||||
ngx_str_t error_log;
|
||||
ngx_str_t lock_file;
|
||||
ngx_str_t hostname;
|
||||
};
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_flag_t daemon;
|
||||
ngx_flag_t master;
|
||||
|
||||
ngx_msec_t timer_resolution;
|
||||
ngx_msec_t shutdown_timeout;
|
||||
|
||||
ngx_int_t worker_processes;
|
||||
ngx_int_t debug_points;
|
||||
|
||||
ngx_int_t rlimit_nofile;
|
||||
off_t rlimit_core;
|
||||
|
||||
int priority;
|
||||
|
||||
ngx_uint_t cpu_affinity_auto;
|
||||
ngx_uint_t cpu_affinity_n;
|
||||
ngx_cpuset_t *cpu_affinity;
|
||||
|
||||
char *username;
|
||||
ngx_uid_t user;
|
||||
ngx_gid_t group;
|
||||
|
||||
ngx_str_t working_directory;
|
||||
ngx_str_t lock_file;
|
||||
|
||||
ngx_str_t pid;
|
||||
ngx_str_t oldpid;
|
||||
|
||||
ngx_array_t env;
|
||||
char **environment;
|
||||
|
||||
ngx_uint_t transparent; /* unsigned transparent:1; */
|
||||
} ngx_core_conf_t;
|
||||
|
||||
|
||||
#define ngx_is_init_cycle(cycle) (cycle->conf_ctx == NULL)
|
||||
|
||||
|
||||
ngx_cycle_t *ngx_init_cycle(ngx_cycle_t *old_cycle);
|
||||
ngx_int_t ngx_create_pidfile(ngx_str_t *name, ngx_log_t *log);
|
||||
void ngx_delete_pidfile(ngx_cycle_t *cycle);
|
||||
ngx_int_t ngx_signal_process(ngx_cycle_t *cycle, char *sig);
|
||||
void ngx_reopen_files(ngx_cycle_t *cycle, ngx_uid_t user);
|
||||
char **ngx_set_environment(ngx_cycle_t *cycle, ngx_uint_t *last);
|
||||
ngx_pid_t ngx_exec_new_binary(ngx_cycle_t *cycle, char *const *argv);
|
||||
ngx_cpuset_t *ngx_get_cpu_affinity(ngx_uint_t n);
|
||||
ngx_shm_zone_t *ngx_shared_memory_add(ngx_conf_t *cf, ngx_str_t *name,
|
||||
size_t size, void *tag);
|
||||
void ngx_set_shutdown_timer(ngx_cycle_t *cycle);
|
||||
|
||||
|
||||
extern volatile ngx_cycle_t *ngx_cycle;
|
||||
extern ngx_array_t ngx_old_cycles;
|
||||
extern ngx_module_t ngx_core_module;
|
||||
extern ngx_uint_t ngx_test_config;
|
||||
extern ngx_uint_t ngx_dump_config;
|
||||
extern ngx_uint_t ngx_quiet_mode;
|
||||
|
||||
|
||||
#endif /* _NGX_CYCLE_H_INCLUDED_ */
|
||||
1128
nginx/src/core/ngx_file.c
Normal file
1128
nginx/src/core/ngx_file.c
Normal file
File diff suppressed because it is too large
Load diff
164
nginx/src/core/ngx_file.h
Normal file
164
nginx/src/core/ngx_file.h
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_FILE_H_INCLUDED_
|
||||
#define _NGX_FILE_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
struct ngx_file_s {
|
||||
ngx_fd_t fd;
|
||||
ngx_str_t name;
|
||||
ngx_file_info_t info;
|
||||
|
||||
off_t offset;
|
||||
off_t sys_offset;
|
||||
|
||||
ngx_log_t *log;
|
||||
|
||||
#if (NGX_THREADS || NGX_COMPAT)
|
||||
ngx_int_t (*thread_handler)(ngx_thread_task_t *task,
|
||||
ngx_file_t *file);
|
||||
void *thread_ctx;
|
||||
ngx_thread_task_t *thread_task;
|
||||
#endif
|
||||
|
||||
#if (NGX_HAVE_FILE_AIO || NGX_COMPAT)
|
||||
ngx_event_aio_t *aio;
|
||||
#endif
|
||||
|
||||
unsigned valid_info:1;
|
||||
unsigned directio:1;
|
||||
};
|
||||
|
||||
|
||||
#define NGX_MAX_PATH_LEVEL 3
|
||||
|
||||
|
||||
typedef ngx_msec_t (*ngx_path_manager_pt) (void *data);
|
||||
typedef ngx_msec_t (*ngx_path_purger_pt) (void *data);
|
||||
typedef void (*ngx_path_loader_pt) (void *data);
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_str_t name;
|
||||
size_t len;
|
||||
size_t level[NGX_MAX_PATH_LEVEL];
|
||||
|
||||
ngx_path_manager_pt manager;
|
||||
ngx_path_purger_pt purger;
|
||||
ngx_path_loader_pt loader;
|
||||
void *data;
|
||||
|
||||
u_char *conf_file;
|
||||
ngx_uint_t line;
|
||||
} ngx_path_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_str_t name;
|
||||
size_t level[NGX_MAX_PATH_LEVEL];
|
||||
} ngx_path_init_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_file_t file;
|
||||
off_t offset;
|
||||
ngx_path_t *path;
|
||||
ngx_pool_t *pool;
|
||||
char *warn;
|
||||
|
||||
ngx_uint_t access;
|
||||
|
||||
unsigned log_level:8;
|
||||
unsigned persistent:1;
|
||||
unsigned clean:1;
|
||||
unsigned thread_write:1;
|
||||
} ngx_temp_file_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_uint_t access;
|
||||
ngx_uint_t path_access;
|
||||
time_t time;
|
||||
ngx_fd_t fd;
|
||||
|
||||
unsigned create_path:1;
|
||||
unsigned delete_file:1;
|
||||
|
||||
ngx_log_t *log;
|
||||
} ngx_ext_rename_file_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
off_t size;
|
||||
size_t buf_size;
|
||||
|
||||
ngx_uint_t access;
|
||||
time_t time;
|
||||
|
||||
ngx_log_t *log;
|
||||
} ngx_copy_file_t;
|
||||
|
||||
|
||||
typedef struct ngx_tree_ctx_s ngx_tree_ctx_t;
|
||||
|
||||
typedef ngx_int_t (*ngx_tree_init_handler_pt) (void *ctx, void *prev);
|
||||
typedef ngx_int_t (*ngx_tree_handler_pt) (ngx_tree_ctx_t *ctx, ngx_str_t *name);
|
||||
|
||||
struct ngx_tree_ctx_s {
|
||||
off_t size;
|
||||
off_t fs_size;
|
||||
ngx_uint_t access;
|
||||
time_t mtime;
|
||||
|
||||
ngx_tree_init_handler_pt init_handler;
|
||||
ngx_tree_handler_pt file_handler;
|
||||
ngx_tree_handler_pt pre_tree_handler;
|
||||
ngx_tree_handler_pt post_tree_handler;
|
||||
ngx_tree_handler_pt spec_handler;
|
||||
|
||||
void *data;
|
||||
size_t alloc;
|
||||
|
||||
ngx_log_t *log;
|
||||
};
|
||||
|
||||
|
||||
ngx_int_t ngx_get_full_name(ngx_pool_t *pool, ngx_str_t *prefix,
|
||||
ngx_str_t *name);
|
||||
|
||||
ssize_t ngx_write_chain_to_temp_file(ngx_temp_file_t *tf, ngx_chain_t *chain);
|
||||
ngx_int_t ngx_create_temp_file(ngx_file_t *file, ngx_path_t *path,
|
||||
ngx_pool_t *pool, ngx_uint_t persistent, ngx_uint_t clean,
|
||||
ngx_uint_t access);
|
||||
void ngx_create_hashed_filename(ngx_path_t *path, u_char *file, size_t len);
|
||||
ngx_int_t ngx_create_path(ngx_file_t *file, ngx_path_t *path);
|
||||
ngx_err_t ngx_create_full_path(u_char *dir, ngx_uint_t access);
|
||||
ngx_int_t ngx_add_path(ngx_conf_t *cf, ngx_path_t **slot);
|
||||
ngx_int_t ngx_create_paths(ngx_cycle_t *cycle, ngx_uid_t user);
|
||||
ngx_int_t ngx_ext_rename_file(ngx_str_t *src, ngx_str_t *to,
|
||||
ngx_ext_rename_file_t *ext);
|
||||
ngx_int_t ngx_copy_file(u_char *from, u_char *to, ngx_copy_file_t *cf);
|
||||
ngx_int_t ngx_walk_tree(ngx_tree_ctx_t *ctx, ngx_str_t *tree);
|
||||
|
||||
ngx_atomic_uint_t ngx_next_temp_number(ngx_uint_t collision);
|
||||
|
||||
char *ngx_conf_set_path_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
|
||||
char *ngx_conf_merge_path_value(ngx_conf_t *cf, ngx_path_t **path,
|
||||
ngx_path_t *prev, ngx_path_init_t *init);
|
||||
char *ngx_conf_set_access_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
|
||||
|
||||
|
||||
extern ngx_atomic_t *ngx_temp_number;
|
||||
extern ngx_atomic_int_t ngx_random_number;
|
||||
|
||||
|
||||
#endif /* _NGX_FILE_H_INCLUDED_ */
|
||||
1013
nginx/src/core/ngx_hash.c
Normal file
1013
nginx/src/core/ngx_hash.c
Normal file
File diff suppressed because it is too large
Load diff
125
nginx/src/core/ngx_hash.h
Normal file
125
nginx/src/core/ngx_hash.h
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_HASH_H_INCLUDED_
|
||||
#define _NGX_HASH_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
typedef struct {
|
||||
void *value;
|
||||
u_short len;
|
||||
u_char name[1];
|
||||
} ngx_hash_elt_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_hash_elt_t **buckets;
|
||||
ngx_uint_t size;
|
||||
} ngx_hash_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_hash_t hash;
|
||||
void *value;
|
||||
} ngx_hash_wildcard_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_str_t key;
|
||||
ngx_uint_t key_hash;
|
||||
void *value;
|
||||
} ngx_hash_key_t;
|
||||
|
||||
|
||||
typedef ngx_uint_t (*ngx_hash_key_pt) (u_char *data, size_t len);
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_hash_t hash;
|
||||
ngx_hash_wildcard_t *wc_head;
|
||||
ngx_hash_wildcard_t *wc_tail;
|
||||
} ngx_hash_combined_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_hash_t *hash;
|
||||
ngx_hash_key_pt key;
|
||||
|
||||
ngx_uint_t max_size;
|
||||
ngx_uint_t bucket_size;
|
||||
|
||||
char *name;
|
||||
ngx_pool_t *pool;
|
||||
ngx_pool_t *temp_pool;
|
||||
} ngx_hash_init_t;
|
||||
|
||||
|
||||
#define NGX_HASH_SMALL 1
|
||||
#define NGX_HASH_LARGE 2
|
||||
|
||||
#define NGX_HASH_LARGE_ASIZE 16384
|
||||
#define NGX_HASH_LARGE_HSIZE 10007
|
||||
|
||||
#define NGX_HASH_WILDCARD_KEY 1
|
||||
#define NGX_HASH_READONLY_KEY 2
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_uint_t hsize;
|
||||
|
||||
ngx_pool_t *pool;
|
||||
ngx_pool_t *temp_pool;
|
||||
|
||||
ngx_array_t keys;
|
||||
ngx_array_t *keys_hash;
|
||||
|
||||
ngx_array_t dns_wc_head;
|
||||
ngx_array_t *dns_wc_head_hash;
|
||||
|
||||
ngx_array_t dns_wc_tail;
|
||||
ngx_array_t *dns_wc_tail_hash;
|
||||
} ngx_hash_keys_arrays_t;
|
||||
|
||||
|
||||
typedef struct ngx_table_elt_s ngx_table_elt_t;
|
||||
|
||||
struct ngx_table_elt_s {
|
||||
ngx_uint_t hash;
|
||||
ngx_str_t key;
|
||||
ngx_str_t value;
|
||||
u_char *lowcase_key;
|
||||
ngx_table_elt_t *next;
|
||||
};
|
||||
|
||||
|
||||
void *ngx_hash_find(ngx_hash_t *hash, ngx_uint_t key, u_char *name, size_t len);
|
||||
void *ngx_hash_find_wc_head(ngx_hash_wildcard_t *hwc, u_char *name, size_t len);
|
||||
void *ngx_hash_find_wc_tail(ngx_hash_wildcard_t *hwc, u_char *name, size_t len);
|
||||
void *ngx_hash_find_combined(ngx_hash_combined_t *hash, ngx_uint_t key,
|
||||
u_char *name, size_t len);
|
||||
|
||||
ngx_int_t ngx_hash_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names,
|
||||
ngx_uint_t nelts);
|
||||
ngx_int_t ngx_hash_wildcard_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names,
|
||||
ngx_uint_t nelts);
|
||||
|
||||
#define ngx_hash(key, c) ((ngx_uint_t) key * 31 + c)
|
||||
ngx_uint_t ngx_hash_key(u_char *data, size_t len);
|
||||
ngx_uint_t ngx_hash_key_lc(u_char *data, size_t len);
|
||||
ngx_uint_t ngx_hash_strlow(u_char *dst, u_char *src, size_t n);
|
||||
|
||||
|
||||
ngx_int_t ngx_hash_keys_array_init(ngx_hash_keys_arrays_t *ha, ngx_uint_t type);
|
||||
ngx_int_t ngx_hash_add_key(ngx_hash_keys_arrays_t *ha, ngx_str_t *key,
|
||||
void *value, ngx_uint_t flags);
|
||||
|
||||
|
||||
#endif /* _NGX_HASH_H_INCLUDED_ */
|
||||
1499
nginx/src/core/ngx_inet.c
Normal file
1499
nginx/src/core/ngx_inet.c
Normal file
File diff suppressed because it is too large
Load diff
132
nginx/src/core/ngx_inet.h
Normal file
132
nginx/src/core/ngx_inet.h
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_INET_H_INCLUDED_
|
||||
#define _NGX_INET_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
#define NGX_INET_ADDRSTRLEN (sizeof("255.255.255.255") - 1)
|
||||
#define NGX_INET6_ADDRSTRLEN \
|
||||
(sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255") - 1)
|
||||
#define NGX_UNIX_ADDRSTRLEN \
|
||||
(sizeof("unix:") - 1 + \
|
||||
sizeof(struct sockaddr_un) - offsetof(struct sockaddr_un, sun_path))
|
||||
|
||||
#if (NGX_HAVE_UNIX_DOMAIN)
|
||||
#define NGX_SOCKADDR_STRLEN NGX_UNIX_ADDRSTRLEN
|
||||
#elif (NGX_HAVE_INET6)
|
||||
#define NGX_SOCKADDR_STRLEN (NGX_INET6_ADDRSTRLEN + sizeof("[]:65535") - 1)
|
||||
#else
|
||||
#define NGX_SOCKADDR_STRLEN (NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1)
|
||||
#endif
|
||||
|
||||
/* compatibility */
|
||||
#define NGX_SOCKADDRLEN sizeof(ngx_sockaddr_t)
|
||||
|
||||
|
||||
typedef union {
|
||||
struct sockaddr sockaddr;
|
||||
struct sockaddr_in sockaddr_in;
|
||||
#if (NGX_HAVE_INET6)
|
||||
struct sockaddr_in6 sockaddr_in6;
|
||||
#endif
|
||||
#if (NGX_HAVE_UNIX_DOMAIN)
|
||||
struct sockaddr_un sockaddr_un;
|
||||
#endif
|
||||
} ngx_sockaddr_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
in_addr_t addr;
|
||||
in_addr_t mask;
|
||||
} ngx_in_cidr_t;
|
||||
|
||||
|
||||
#if (NGX_HAVE_INET6)
|
||||
|
||||
typedef struct {
|
||||
struct in6_addr addr;
|
||||
struct in6_addr mask;
|
||||
} ngx_in6_cidr_t;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_uint_t family;
|
||||
union {
|
||||
ngx_in_cidr_t in;
|
||||
#if (NGX_HAVE_INET6)
|
||||
ngx_in6_cidr_t in6;
|
||||
#endif
|
||||
} u;
|
||||
} ngx_cidr_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
struct sockaddr *sockaddr;
|
||||
socklen_t socklen;
|
||||
ngx_str_t name;
|
||||
} ngx_addr_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_str_t url;
|
||||
ngx_str_t host;
|
||||
ngx_str_t port_text;
|
||||
ngx_str_t uri;
|
||||
|
||||
in_port_t port;
|
||||
in_port_t default_port;
|
||||
in_port_t last_port;
|
||||
int family;
|
||||
|
||||
unsigned listen:1;
|
||||
unsigned uri_part:1;
|
||||
unsigned no_resolve:1;
|
||||
|
||||
unsigned no_port:1;
|
||||
unsigned wildcard:1;
|
||||
|
||||
socklen_t socklen;
|
||||
ngx_sockaddr_t sockaddr;
|
||||
|
||||
ngx_addr_t *addrs;
|
||||
ngx_uint_t naddrs;
|
||||
|
||||
char *err;
|
||||
} ngx_url_t;
|
||||
|
||||
|
||||
in_addr_t ngx_inet_addr(u_char *text, size_t len);
|
||||
#if (NGX_HAVE_INET6)
|
||||
ngx_int_t ngx_inet6_addr(u_char *p, size_t len, u_char *addr);
|
||||
size_t ngx_inet6_ntop(u_char *p, u_char *text, size_t len);
|
||||
#endif
|
||||
size_t ngx_sock_ntop(struct sockaddr *sa, socklen_t socklen, u_char *text,
|
||||
size_t len, ngx_uint_t port);
|
||||
size_t ngx_inet_ntop(int family, void *addr, u_char *text, size_t len);
|
||||
ngx_int_t ngx_ptocidr(ngx_str_t *text, ngx_cidr_t *cidr);
|
||||
ngx_int_t ngx_cidr_match(struct sockaddr *sa, ngx_array_t *cidrs);
|
||||
ngx_int_t ngx_parse_addr(ngx_pool_t *pool, ngx_addr_t *addr, u_char *text,
|
||||
size_t len);
|
||||
ngx_int_t ngx_parse_addr_port(ngx_pool_t *pool, ngx_addr_t *addr,
|
||||
u_char *text, size_t len);
|
||||
ngx_int_t ngx_parse_url(ngx_pool_t *pool, ngx_url_t *u);
|
||||
ngx_int_t ngx_inet_resolve_host(ngx_pool_t *pool, ngx_url_t *u);
|
||||
ngx_int_t ngx_cmp_sockaddr(struct sockaddr *sa1, socklen_t slen1,
|
||||
struct sockaddr *sa2, socklen_t slen2, ngx_uint_t cmp_port);
|
||||
in_port_t ngx_inet_get_port(struct sockaddr *sa);
|
||||
void ngx_inet_set_port(struct sockaddr *sa, in_port_t port);
|
||||
ngx_uint_t ngx_inet_wildcard(struct sockaddr *sa);
|
||||
|
||||
|
||||
#endif /* _NGX_INET_H_INCLUDED_ */
|
||||
63
nginx/src/core/ngx_list.c
Normal file
63
nginx/src/core/ngx_list.c
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
ngx_list_t *
|
||||
ngx_list_create(ngx_pool_t *pool, ngx_uint_t n, size_t size)
|
||||
{
|
||||
ngx_list_t *list;
|
||||
|
||||
list = ngx_palloc(pool, sizeof(ngx_list_t));
|
||||
if (list == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ngx_list_init(list, pool, n, size) != NGX_OK) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
ngx_list_push(ngx_list_t *l)
|
||||
{
|
||||
void *elt;
|
||||
ngx_list_part_t *last;
|
||||
|
||||
last = l->last;
|
||||
|
||||
if (last->nelts == l->nalloc) {
|
||||
|
||||
/* the last part is full, allocate a new list part */
|
||||
|
||||
last = ngx_palloc(l->pool, sizeof(ngx_list_part_t));
|
||||
if (last == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
last->elts = ngx_palloc(l->pool, l->nalloc * l->size);
|
||||
if (last->elts == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
last->nelts = 0;
|
||||
last->next = NULL;
|
||||
|
||||
l->last->next = last;
|
||||
l->last = last;
|
||||
}
|
||||
|
||||
elt = (char *) last->elts + l->size * last->nelts;
|
||||
last->nelts++;
|
||||
|
||||
return elt;
|
||||
}
|
||||
83
nginx/src/core/ngx_list.h
Normal file
83
nginx/src/core/ngx_list.h
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_LIST_H_INCLUDED_
|
||||
#define _NGX_LIST_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
typedef struct ngx_list_part_s ngx_list_part_t;
|
||||
|
||||
struct ngx_list_part_s {
|
||||
void *elts;
|
||||
ngx_uint_t nelts;
|
||||
ngx_list_part_t *next;
|
||||
};
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_list_part_t *last;
|
||||
ngx_list_part_t part;
|
||||
size_t size;
|
||||
ngx_uint_t nalloc;
|
||||
ngx_pool_t *pool;
|
||||
} ngx_list_t;
|
||||
|
||||
|
||||
ngx_list_t *ngx_list_create(ngx_pool_t *pool, ngx_uint_t n, size_t size);
|
||||
|
||||
static ngx_inline ngx_int_t
|
||||
ngx_list_init(ngx_list_t *list, ngx_pool_t *pool, ngx_uint_t n, size_t size)
|
||||
{
|
||||
list->part.elts = ngx_palloc(pool, n * size);
|
||||
if (list->part.elts == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
list->part.nelts = 0;
|
||||
list->part.next = NULL;
|
||||
list->last = &list->part;
|
||||
list->size = size;
|
||||
list->nalloc = n;
|
||||
list->pool = pool;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* the iteration through the list:
|
||||
*
|
||||
* part = &list.part;
|
||||
* data = part->elts;
|
||||
*
|
||||
* for (i = 0 ;; i++) {
|
||||
*
|
||||
* if (i >= part->nelts) {
|
||||
* if (part->next == NULL) {
|
||||
* break;
|
||||
* }
|
||||
*
|
||||
* part = part->next;
|
||||
* data = part->elts;
|
||||
* i = 0;
|
||||
* }
|
||||
*
|
||||
* ... data[i] ...
|
||||
*
|
||||
* }
|
||||
*/
|
||||
|
||||
|
||||
void *ngx_list_push(ngx_list_t *list);
|
||||
|
||||
|
||||
#endif /* _NGX_LIST_H_INCLUDED_ */
|
||||
752
nginx/src/core/ngx_log.c
Normal file
752
nginx/src/core/ngx_log.c
Normal file
|
|
@ -0,0 +1,752 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
static char *ngx_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
|
||||
static char *ngx_log_set_levels(ngx_conf_t *cf, ngx_log_t *log);
|
||||
static void ngx_log_insert(ngx_log_t *log, ngx_log_t *new_log);
|
||||
|
||||
|
||||
#if (NGX_DEBUG)
|
||||
|
||||
static void ngx_log_memory_writer(ngx_log_t *log, ngx_uint_t level,
|
||||
u_char *buf, size_t len);
|
||||
static void ngx_log_memory_cleanup(void *data);
|
||||
|
||||
|
||||
typedef struct {
|
||||
u_char *start;
|
||||
u_char *end;
|
||||
u_char *pos;
|
||||
ngx_atomic_t written;
|
||||
} ngx_log_memory_buf_t;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
static ngx_command_t ngx_errlog_commands[] = {
|
||||
|
||||
{ ngx_string("error_log"),
|
||||
NGX_MAIN_CONF|NGX_CONF_1MORE,
|
||||
ngx_error_log,
|
||||
0,
|
||||
0,
|
||||
NULL },
|
||||
|
||||
ngx_null_command
|
||||
};
|
||||
|
||||
|
||||
static ngx_core_module_t ngx_errlog_module_ctx = {
|
||||
ngx_string("errlog"),
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
ngx_module_t ngx_errlog_module = {
|
||||
NGX_MODULE_V1,
|
||||
&ngx_errlog_module_ctx, /* module context */
|
||||
ngx_errlog_commands, /* module directives */
|
||||
NGX_CORE_MODULE, /* module type */
|
||||
NULL, /* init master */
|
||||
NULL, /* init module */
|
||||
NULL, /* init process */
|
||||
NULL, /* init thread */
|
||||
NULL, /* exit thread */
|
||||
NULL, /* exit process */
|
||||
NULL, /* exit master */
|
||||
NGX_MODULE_V1_PADDING
|
||||
};
|
||||
|
||||
|
||||
static ngx_log_t ngx_log;
|
||||
static ngx_open_file_t ngx_log_file;
|
||||
ngx_uint_t ngx_use_stderr = 1;
|
||||
|
||||
|
||||
static ngx_str_t err_levels[] = {
|
||||
ngx_null_string,
|
||||
ngx_string("emerg"),
|
||||
ngx_string("alert"),
|
||||
ngx_string("crit"),
|
||||
ngx_string("error"),
|
||||
ngx_string("warn"),
|
||||
ngx_string("notice"),
|
||||
ngx_string("info"),
|
||||
ngx_string("debug")
|
||||
};
|
||||
|
||||
static const char *debug_levels[] = {
|
||||
"debug_core", "debug_alloc", "debug_mutex", "debug_event",
|
||||
"debug_http", "debug_mail", "debug_stream"
|
||||
};
|
||||
|
||||
|
||||
#if (NGX_HAVE_VARIADIC_MACROS)
|
||||
|
||||
void
|
||||
ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,
|
||||
const char *fmt, ...)
|
||||
|
||||
#else
|
||||
|
||||
void
|
||||
ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,
|
||||
const char *fmt, va_list args)
|
||||
|
||||
#endif
|
||||
{
|
||||
#if (NGX_HAVE_VARIADIC_MACROS)
|
||||
va_list args;
|
||||
#endif
|
||||
u_char *p, *last, *msg;
|
||||
ssize_t n;
|
||||
ngx_uint_t wrote_stderr, debug_connection;
|
||||
u_char errstr[NGX_MAX_ERROR_STR];
|
||||
|
||||
last = errstr + NGX_MAX_ERROR_STR;
|
||||
|
||||
p = ngx_cpymem(errstr, ngx_cached_err_log_time.data,
|
||||
ngx_cached_err_log_time.len);
|
||||
|
||||
p = ngx_slprintf(p, last, " [%V] ", &err_levels[level]);
|
||||
|
||||
/* pid#tid */
|
||||
p = ngx_slprintf(p, last, "%P#" NGX_TID_T_FMT ": ",
|
||||
ngx_log_pid, ngx_log_tid);
|
||||
|
||||
if (log->connection) {
|
||||
p = ngx_slprintf(p, last, "*%uA ", log->connection);
|
||||
}
|
||||
|
||||
msg = p;
|
||||
|
||||
#if (NGX_HAVE_VARIADIC_MACROS)
|
||||
|
||||
va_start(args, fmt);
|
||||
p = ngx_vslprintf(p, last, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
#else
|
||||
|
||||
p = ngx_vslprintf(p, last, fmt, args);
|
||||
|
||||
#endif
|
||||
|
||||
if (err) {
|
||||
p = ngx_log_errno(p, last, err);
|
||||
}
|
||||
|
||||
if (level != NGX_LOG_DEBUG && log->handler) {
|
||||
p = log->handler(log, p, last - p);
|
||||
}
|
||||
|
||||
if (p > last - NGX_LINEFEED_SIZE) {
|
||||
p = last - NGX_LINEFEED_SIZE;
|
||||
}
|
||||
|
||||
ngx_linefeed(p);
|
||||
|
||||
wrote_stderr = 0;
|
||||
debug_connection = (log->log_level & NGX_LOG_DEBUG_CONNECTION) != 0;
|
||||
|
||||
while (log) {
|
||||
|
||||
if (log->log_level < level && !debug_connection) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (log->writer) {
|
||||
log->writer(log, level, errstr, p - errstr);
|
||||
goto next;
|
||||
}
|
||||
|
||||
if (ngx_time() == log->disk_full_time) {
|
||||
|
||||
/*
|
||||
* on FreeBSD writing to a full filesystem with enabled softupdates
|
||||
* may block process for much longer time than writing to non-full
|
||||
* filesystem, so we skip writing to a log for one second
|
||||
*/
|
||||
|
||||
goto next;
|
||||
}
|
||||
|
||||
n = ngx_write_fd(log->file->fd, errstr, p - errstr);
|
||||
|
||||
if (n == -1 && ngx_errno == NGX_ENOSPC) {
|
||||
log->disk_full_time = ngx_time();
|
||||
}
|
||||
|
||||
if (log->file->fd == ngx_stderr) {
|
||||
wrote_stderr = 1;
|
||||
}
|
||||
|
||||
next:
|
||||
|
||||
log = log->next;
|
||||
}
|
||||
|
||||
if (!ngx_use_stderr
|
||||
|| level > NGX_LOG_WARN
|
||||
|| wrote_stderr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
msg -= (7 + err_levels[level].len + 3);
|
||||
|
||||
(void) ngx_sprintf(msg, "nginx: [%V] ", &err_levels[level]);
|
||||
|
||||
(void) ngx_write_console(ngx_stderr, msg, p - msg);
|
||||
}
|
||||
|
||||
|
||||
#if !(NGX_HAVE_VARIADIC_MACROS)
|
||||
|
||||
void ngx_cdecl
|
||||
ngx_log_error(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
if (log->log_level >= level) {
|
||||
va_start(args, fmt);
|
||||
ngx_log_error_core(level, log, err, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ngx_cdecl
|
||||
ngx_log_debug_core(ngx_log_t *log, ngx_err_t err, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
ngx_log_error_core(NGX_LOG_DEBUG, log, err, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
void ngx_cdecl
|
||||
ngx_log_abort(ngx_err_t err, const char *fmt, ...)
|
||||
{
|
||||
u_char *p;
|
||||
va_list args;
|
||||
u_char errstr[NGX_MAX_CONF_ERRSTR];
|
||||
|
||||
va_start(args, fmt);
|
||||
p = ngx_vsnprintf(errstr, sizeof(errstr) - 1, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, err,
|
||||
"%*s", p - errstr, errstr);
|
||||
}
|
||||
|
||||
|
||||
void ngx_cdecl
|
||||
ngx_log_stderr(ngx_err_t err, const char *fmt, ...)
|
||||
{
|
||||
u_char *p, *last;
|
||||
va_list args;
|
||||
u_char errstr[NGX_MAX_ERROR_STR];
|
||||
|
||||
last = errstr + NGX_MAX_ERROR_STR;
|
||||
|
||||
p = ngx_cpymem(errstr, "nginx: ", 7);
|
||||
|
||||
va_start(args, fmt);
|
||||
p = ngx_vslprintf(p, last, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
if (err) {
|
||||
p = ngx_log_errno(p, last, err);
|
||||
}
|
||||
|
||||
if (p > last - NGX_LINEFEED_SIZE) {
|
||||
p = last - NGX_LINEFEED_SIZE;
|
||||
}
|
||||
|
||||
ngx_linefeed(p);
|
||||
|
||||
(void) ngx_write_console(ngx_stderr, errstr, p - errstr);
|
||||
}
|
||||
|
||||
|
||||
u_char *
|
||||
ngx_log_errno(u_char *buf, u_char *last, ngx_err_t err)
|
||||
{
|
||||
if (buf > last - 50) {
|
||||
|
||||
/* leave a space for an error code */
|
||||
|
||||
buf = last - 50;
|
||||
*buf++ = '.';
|
||||
*buf++ = '.';
|
||||
*buf++ = '.';
|
||||
}
|
||||
|
||||
#if (NGX_WIN32)
|
||||
buf = ngx_slprintf(buf, last, ((unsigned) err < 0x80000000)
|
||||
? " (%d: " : " (%Xd: ", err);
|
||||
#else
|
||||
buf = ngx_slprintf(buf, last, " (%d: ", err);
|
||||
#endif
|
||||
|
||||
buf = ngx_strerror(err, buf, last - buf);
|
||||
|
||||
if (buf < last) {
|
||||
*buf++ = ')';
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
ngx_log_t *
|
||||
ngx_log_init(u_char *prefix, u_char *error_log)
|
||||
{
|
||||
u_char *p, *name;
|
||||
size_t nlen, plen;
|
||||
|
||||
ngx_log.file = &ngx_log_file;
|
||||
ngx_log.log_level = NGX_LOG_NOTICE;
|
||||
|
||||
if (error_log == NULL) {
|
||||
error_log = (u_char *) NGX_ERROR_LOG_PATH;
|
||||
}
|
||||
|
||||
name = error_log;
|
||||
nlen = ngx_strlen(name);
|
||||
|
||||
if (nlen == 0) {
|
||||
ngx_log_file.fd = ngx_stderr;
|
||||
return &ngx_log;
|
||||
}
|
||||
|
||||
p = NULL;
|
||||
|
||||
#if (NGX_WIN32)
|
||||
if (name[1] != ':') {
|
||||
#else
|
||||
if (name[0] != '/') {
|
||||
#endif
|
||||
|
||||
if (prefix) {
|
||||
plen = ngx_strlen(prefix);
|
||||
|
||||
} else {
|
||||
#ifdef NGX_PREFIX
|
||||
prefix = (u_char *) NGX_PREFIX;
|
||||
plen = ngx_strlen(prefix);
|
||||
#else
|
||||
plen = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (plen) {
|
||||
name = malloc(plen + nlen + 2);
|
||||
if (name == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p = ngx_cpymem(name, prefix, plen);
|
||||
|
||||
if (!ngx_path_separator(*(p - 1))) {
|
||||
*p++ = '/';
|
||||
}
|
||||
|
||||
ngx_cpystrn(p, error_log, nlen + 1);
|
||||
|
||||
p = name;
|
||||
}
|
||||
}
|
||||
|
||||
ngx_log_file.fd = ngx_open_file(name, NGX_FILE_APPEND,
|
||||
NGX_FILE_CREATE_OR_OPEN,
|
||||
NGX_FILE_DEFAULT_ACCESS);
|
||||
|
||||
if (ngx_log_file.fd == NGX_INVALID_FILE) {
|
||||
ngx_log_stderr(ngx_errno,
|
||||
"[alert] could not open error log file: "
|
||||
ngx_open_file_n " \"%s\" failed", name);
|
||||
#if (NGX_WIN32)
|
||||
ngx_event_log(ngx_errno,
|
||||
"could not open error log file: "
|
||||
ngx_open_file_n " \"%s\" failed", name);
|
||||
#endif
|
||||
|
||||
ngx_log_file.fd = ngx_stderr;
|
||||
}
|
||||
|
||||
if (p) {
|
||||
ngx_free(p);
|
||||
}
|
||||
|
||||
return &ngx_log;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_log_open_default(ngx_cycle_t *cycle)
|
||||
{
|
||||
ngx_log_t *log;
|
||||
|
||||
if (ngx_log_get_file_log(&cycle->new_log) != NULL) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
if (cycle->new_log.log_level != 0) {
|
||||
/* there are some error logs, but no files */
|
||||
|
||||
log = ngx_pcalloc(cycle->pool, sizeof(ngx_log_t));
|
||||
if (log == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
} else {
|
||||
/* no error logs at all */
|
||||
log = &cycle->new_log;
|
||||
}
|
||||
|
||||
log->log_level = NGX_LOG_ERR;
|
||||
|
||||
log->file = ngx_conf_open_file(cycle, &cycle->error_log);
|
||||
if (log->file == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (log != &cycle->new_log) {
|
||||
ngx_log_insert(&cycle->new_log, log);
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_log_redirect_stderr(ngx_cycle_t *cycle)
|
||||
{
|
||||
ngx_fd_t fd;
|
||||
|
||||
if (cycle->log_use_stderr) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
/* file log always exists when we are called */
|
||||
fd = ngx_log_get_file_log(cycle->log)->file->fd;
|
||||
|
||||
if (fd != ngx_stderr) {
|
||||
if (ngx_set_stderr(fd) == NGX_FILE_ERROR) {
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
|
||||
ngx_set_stderr_n " failed");
|
||||
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
ngx_log_t *
|
||||
ngx_log_get_file_log(ngx_log_t *head)
|
||||
{
|
||||
ngx_log_t *log;
|
||||
|
||||
for (log = head; log; log = log->next) {
|
||||
if (log->file != NULL) {
|
||||
return log;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
ngx_log_set_levels(ngx_conf_t *cf, ngx_log_t *log)
|
||||
{
|
||||
ngx_uint_t i, n, d, found;
|
||||
ngx_str_t *value;
|
||||
|
||||
if (cf->args->nelts == 2) {
|
||||
log->log_level = NGX_LOG_ERR;
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
value = cf->args->elts;
|
||||
|
||||
for (i = 2; i < cf->args->nelts; i++) {
|
||||
found = 0;
|
||||
|
||||
for (n = 1; n <= NGX_LOG_DEBUG; n++) {
|
||||
if (ngx_strcmp(value[i].data, err_levels[n].data) == 0) {
|
||||
|
||||
if (log->log_level != 0) {
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"duplicate log level \"%V\"",
|
||||
&value[i]);
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
log->log_level = n;
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (n = 0, d = NGX_LOG_DEBUG_FIRST; d <= NGX_LOG_DEBUG_LAST; d <<= 1) {
|
||||
if (ngx_strcmp(value[i].data, debug_levels[n++]) == 0) {
|
||||
if (log->log_level & ~NGX_LOG_DEBUG_ALL) {
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"invalid log level \"%V\"",
|
||||
&value[i]);
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
log->log_level |= d;
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!found) {
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"invalid log level \"%V\"", &value[i]);
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (log->log_level == NGX_LOG_DEBUG) {
|
||||
log->log_level = NGX_LOG_DEBUG_ALL;
|
||||
}
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
ngx_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
||||
{
|
||||
ngx_log_t *dummy;
|
||||
|
||||
dummy = &cf->cycle->new_log;
|
||||
|
||||
return ngx_log_set_log(cf, &dummy);
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
ngx_log_set_log(ngx_conf_t *cf, ngx_log_t **head)
|
||||
{
|
||||
ngx_log_t *new_log;
|
||||
ngx_str_t *value, name;
|
||||
ngx_syslog_peer_t *peer;
|
||||
|
||||
if (*head != NULL && (*head)->log_level == 0) {
|
||||
new_log = *head;
|
||||
|
||||
} else {
|
||||
|
||||
new_log = ngx_pcalloc(cf->pool, sizeof(ngx_log_t));
|
||||
if (new_log == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
if (*head == NULL) {
|
||||
*head = new_log;
|
||||
}
|
||||
}
|
||||
|
||||
value = cf->args->elts;
|
||||
|
||||
if (ngx_strcmp(value[1].data, "stderr") == 0) {
|
||||
ngx_str_null(&name);
|
||||
cf->cycle->log_use_stderr = 1;
|
||||
|
||||
new_log->file = ngx_conf_open_file(cf->cycle, &name);
|
||||
if (new_log->file == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
} else if (ngx_strncmp(value[1].data, "memory:", 7) == 0) {
|
||||
|
||||
#if (NGX_DEBUG)
|
||||
size_t size, needed;
|
||||
ngx_pool_cleanup_t *cln;
|
||||
ngx_log_memory_buf_t *buf;
|
||||
|
||||
value[1].len -= 7;
|
||||
value[1].data += 7;
|
||||
|
||||
needed = sizeof("MEMLOG :" NGX_LINEFEED)
|
||||
+ cf->conf_file->file.name.len
|
||||
+ NGX_SIZE_T_LEN
|
||||
+ NGX_INT_T_LEN
|
||||
+ NGX_MAX_ERROR_STR;
|
||||
|
||||
size = ngx_parse_size(&value[1]);
|
||||
|
||||
if (size == (size_t) NGX_ERROR || size < needed) {
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"invalid buffer size \"%V\"", &value[1]);
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
buf = ngx_pcalloc(cf->pool, sizeof(ngx_log_memory_buf_t));
|
||||
if (buf == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
buf->start = ngx_pnalloc(cf->pool, size);
|
||||
if (buf->start == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
buf->end = buf->start + size;
|
||||
|
||||
buf->pos = ngx_slprintf(buf->start, buf->end, "MEMLOG %uz %V:%ui%N",
|
||||
size, &cf->conf_file->file.name,
|
||||
cf->conf_file->line);
|
||||
|
||||
ngx_memset(buf->pos, ' ', buf->end - buf->pos);
|
||||
|
||||
cln = ngx_pool_cleanup_add(cf->pool, 0);
|
||||
if (cln == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
cln->data = new_log;
|
||||
cln->handler = ngx_log_memory_cleanup;
|
||||
|
||||
new_log->writer = ngx_log_memory_writer;
|
||||
new_log->wdata = buf;
|
||||
|
||||
#else
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"nginx was built without debug support");
|
||||
return NGX_CONF_ERROR;
|
||||
#endif
|
||||
|
||||
} else if (ngx_strncmp(value[1].data, "syslog:", 7) == 0) {
|
||||
peer = ngx_pcalloc(cf->pool, sizeof(ngx_syslog_peer_t));
|
||||
if (peer == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
if (ngx_syslog_process_conf(cf, peer) != NGX_CONF_OK) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
new_log->writer = ngx_syslog_writer;
|
||||
new_log->wdata = peer;
|
||||
|
||||
} else {
|
||||
new_log->file = ngx_conf_open_file(cf->cycle, &value[1]);
|
||||
if (new_log->file == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (ngx_log_set_levels(cf, new_log) != NGX_CONF_OK) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
if (*head != new_log) {
|
||||
ngx_log_insert(*head, new_log);
|
||||
}
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_log_insert(ngx_log_t *log, ngx_log_t *new_log)
|
||||
{
|
||||
ngx_log_t tmp;
|
||||
|
||||
if (new_log->log_level > log->log_level) {
|
||||
|
||||
/*
|
||||
* list head address is permanent, insert new log after
|
||||
* head and swap its contents with head
|
||||
*/
|
||||
|
||||
tmp = *log;
|
||||
*log = *new_log;
|
||||
*new_log = tmp;
|
||||
|
||||
log->next = new_log;
|
||||
return;
|
||||
}
|
||||
|
||||
while (log->next) {
|
||||
if (new_log->log_level > log->next->log_level) {
|
||||
new_log->next = log->next;
|
||||
log->next = new_log;
|
||||
return;
|
||||
}
|
||||
|
||||
log = log->next;
|
||||
}
|
||||
|
||||
log->next = new_log;
|
||||
}
|
||||
|
||||
|
||||
#if (NGX_DEBUG)
|
||||
|
||||
static void
|
||||
ngx_log_memory_writer(ngx_log_t *log, ngx_uint_t level, u_char *buf,
|
||||
size_t len)
|
||||
{
|
||||
u_char *p;
|
||||
size_t avail, written;
|
||||
ngx_log_memory_buf_t *mem;
|
||||
|
||||
mem = log->wdata;
|
||||
|
||||
if (mem == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
written = ngx_atomic_fetch_add(&mem->written, len);
|
||||
|
||||
p = mem->pos + written % (mem->end - mem->pos);
|
||||
|
||||
avail = mem->end - p;
|
||||
|
||||
if (avail >= len) {
|
||||
ngx_memcpy(p, buf, len);
|
||||
|
||||
} else {
|
||||
ngx_memcpy(p, buf, avail);
|
||||
ngx_memcpy(mem->pos, buf + avail, len - avail);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_log_memory_cleanup(void *data)
|
||||
{
|
||||
ngx_log_t *log = data;
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_CORE, log, 0, "destroy memory log buffer");
|
||||
|
||||
log->wdata = NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
271
nginx/src/core/ngx_log.h
Normal file
271
nginx/src/core/ngx_log.h
Normal file
|
|
@ -0,0 +1,271 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_LOG_H_INCLUDED_
|
||||
#define _NGX_LOG_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
#define NGX_LOG_STDERR 0
|
||||
#define NGX_LOG_EMERG 1
|
||||
#define NGX_LOG_ALERT 2
|
||||
#define NGX_LOG_CRIT 3
|
||||
#define NGX_LOG_ERR 4
|
||||
#define NGX_LOG_WARN 5
|
||||
#define NGX_LOG_NOTICE 6
|
||||
#define NGX_LOG_INFO 7
|
||||
#define NGX_LOG_DEBUG 8
|
||||
|
||||
#define NGX_LOG_DEBUG_CORE 0x010
|
||||
#define NGX_LOG_DEBUG_ALLOC 0x020
|
||||
#define NGX_LOG_DEBUG_MUTEX 0x040
|
||||
#define NGX_LOG_DEBUG_EVENT 0x080
|
||||
#define NGX_LOG_DEBUG_HTTP 0x100
|
||||
#define NGX_LOG_DEBUG_MAIL 0x200
|
||||
#define NGX_LOG_DEBUG_STREAM 0x400
|
||||
|
||||
/*
|
||||
* do not forget to update debug_levels[] in src/core/ngx_log.c
|
||||
* after the adding a new debug level
|
||||
*/
|
||||
|
||||
#define NGX_LOG_DEBUG_FIRST NGX_LOG_DEBUG_CORE
|
||||
#define NGX_LOG_DEBUG_LAST NGX_LOG_DEBUG_STREAM
|
||||
#define NGX_LOG_DEBUG_CONNECTION 0x80000000
|
||||
#define NGX_LOG_DEBUG_ALL 0x7ffffff0
|
||||
|
||||
|
||||
typedef u_char *(*ngx_log_handler_pt) (ngx_log_t *log, u_char *buf, size_t len);
|
||||
typedef void (*ngx_log_writer_pt) (ngx_log_t *log, ngx_uint_t level,
|
||||
u_char *buf, size_t len);
|
||||
|
||||
|
||||
struct ngx_log_s {
|
||||
ngx_uint_t log_level;
|
||||
ngx_open_file_t *file;
|
||||
|
||||
ngx_atomic_uint_t connection;
|
||||
|
||||
time_t disk_full_time;
|
||||
|
||||
ngx_log_handler_pt handler;
|
||||
void *data;
|
||||
|
||||
ngx_log_writer_pt writer;
|
||||
void *wdata;
|
||||
|
||||
/*
|
||||
* we declare "action" as "char *" because the actions are usually
|
||||
* the static strings and in the "u_char *" case we have to override
|
||||
* their types all the time
|
||||
*/
|
||||
|
||||
char *action;
|
||||
|
||||
ngx_log_t *next;
|
||||
|
||||
NGX_COMPAT_BEGIN(5)
|
||||
NGX_COMPAT_END
|
||||
};
|
||||
|
||||
|
||||
#define NGX_MAX_ERROR_STR 2048
|
||||
|
||||
|
||||
/*********************************/
|
||||
|
||||
#if (NGX_HAVE_C99_VARIADIC_MACROS)
|
||||
|
||||
#define NGX_HAVE_VARIADIC_MACROS 1
|
||||
|
||||
#define ngx_log_error(level, log, ...) \
|
||||
if ((log)->log_level >= level) ngx_log_error_core(level, log, __VA_ARGS__)
|
||||
|
||||
void ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,
|
||||
const char *fmt, ...);
|
||||
|
||||
#define ngx_log_debug(level, log, ...) \
|
||||
if ((log)->log_level & level) \
|
||||
ngx_log_error_core(NGX_LOG_DEBUG, log, __VA_ARGS__)
|
||||
|
||||
/*********************************/
|
||||
|
||||
#elif (NGX_HAVE_GCC_VARIADIC_MACROS)
|
||||
|
||||
#define NGX_HAVE_VARIADIC_MACROS 1
|
||||
|
||||
#define ngx_log_error(level, log, args...) \
|
||||
if ((log)->log_level >= level) ngx_log_error_core(level, log, args)
|
||||
|
||||
void ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,
|
||||
const char *fmt, ...);
|
||||
|
||||
#define ngx_log_debug(level, log, args...) \
|
||||
if ((log)->log_level & level) \
|
||||
ngx_log_error_core(NGX_LOG_DEBUG, log, args)
|
||||
|
||||
/*********************************/
|
||||
|
||||
#else /* no variadic macros */
|
||||
|
||||
#define NGX_HAVE_VARIADIC_MACROS 0
|
||||
|
||||
void ngx_cdecl ngx_log_error(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,
|
||||
const char *fmt, ...);
|
||||
void ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,
|
||||
const char *fmt, va_list args);
|
||||
void ngx_cdecl ngx_log_debug_core(ngx_log_t *log, ngx_err_t err,
|
||||
const char *fmt, ...);
|
||||
|
||||
|
||||
#endif /* variadic macros */
|
||||
|
||||
|
||||
/*********************************/
|
||||
|
||||
#if (NGX_DEBUG)
|
||||
|
||||
#if (NGX_HAVE_VARIADIC_MACROS)
|
||||
|
||||
#define ngx_log_debug0(level, log, err, fmt) \
|
||||
ngx_log_debug(level, log, err, fmt)
|
||||
|
||||
#define ngx_log_debug1(level, log, err, fmt, arg1) \
|
||||
ngx_log_debug(level, log, err, fmt, arg1)
|
||||
|
||||
#define ngx_log_debug2(level, log, err, fmt, arg1, arg2) \
|
||||
ngx_log_debug(level, log, err, fmt, arg1, arg2)
|
||||
|
||||
#define ngx_log_debug3(level, log, err, fmt, arg1, arg2, arg3) \
|
||||
ngx_log_debug(level, log, err, fmt, arg1, arg2, arg3)
|
||||
|
||||
#define ngx_log_debug4(level, log, err, fmt, arg1, arg2, arg3, arg4) \
|
||||
ngx_log_debug(level, log, err, fmt, arg1, arg2, arg3, arg4)
|
||||
|
||||
#define ngx_log_debug5(level, log, err, fmt, arg1, arg2, arg3, arg4, arg5) \
|
||||
ngx_log_debug(level, log, err, fmt, arg1, arg2, arg3, arg4, arg5)
|
||||
|
||||
#define ngx_log_debug6(level, log, err, fmt, \
|
||||
arg1, arg2, arg3, arg4, arg5, arg6) \
|
||||
ngx_log_debug(level, log, err, fmt, \
|
||||
arg1, arg2, arg3, arg4, arg5, arg6)
|
||||
|
||||
#define ngx_log_debug7(level, log, err, fmt, \
|
||||
arg1, arg2, arg3, arg4, arg5, arg6, arg7) \
|
||||
ngx_log_debug(level, log, err, fmt, \
|
||||
arg1, arg2, arg3, arg4, arg5, arg6, arg7)
|
||||
|
||||
#define ngx_log_debug8(level, log, err, fmt, \
|
||||
arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) \
|
||||
ngx_log_debug(level, log, err, fmt, \
|
||||
arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
|
||||
|
||||
|
||||
#else /* no variadic macros */
|
||||
|
||||
#define ngx_log_debug0(level, log, err, fmt) \
|
||||
if ((log)->log_level & level) \
|
||||
ngx_log_debug_core(log, err, fmt)
|
||||
|
||||
#define ngx_log_debug1(level, log, err, fmt, arg1) \
|
||||
if ((log)->log_level & level) \
|
||||
ngx_log_debug_core(log, err, fmt, arg1)
|
||||
|
||||
#define ngx_log_debug2(level, log, err, fmt, arg1, arg2) \
|
||||
if ((log)->log_level & level) \
|
||||
ngx_log_debug_core(log, err, fmt, arg1, arg2)
|
||||
|
||||
#define ngx_log_debug3(level, log, err, fmt, arg1, arg2, arg3) \
|
||||
if ((log)->log_level & level) \
|
||||
ngx_log_debug_core(log, err, fmt, arg1, arg2, arg3)
|
||||
|
||||
#define ngx_log_debug4(level, log, err, fmt, arg1, arg2, arg3, arg4) \
|
||||
if ((log)->log_level & level) \
|
||||
ngx_log_debug_core(log, err, fmt, arg1, arg2, arg3, arg4)
|
||||
|
||||
#define ngx_log_debug5(level, log, err, fmt, arg1, arg2, arg3, arg4, arg5) \
|
||||
if ((log)->log_level & level) \
|
||||
ngx_log_debug_core(log, err, fmt, arg1, arg2, arg3, arg4, arg5)
|
||||
|
||||
#define ngx_log_debug6(level, log, err, fmt, \
|
||||
arg1, arg2, arg3, arg4, arg5, arg6) \
|
||||
if ((log)->log_level & level) \
|
||||
ngx_log_debug_core(log, err, fmt, arg1, arg2, arg3, arg4, arg5, arg6)
|
||||
|
||||
#define ngx_log_debug7(level, log, err, fmt, \
|
||||
arg1, arg2, arg3, arg4, arg5, arg6, arg7) \
|
||||
if ((log)->log_level & level) \
|
||||
ngx_log_debug_core(log, err, fmt, \
|
||||
arg1, arg2, arg3, arg4, arg5, arg6, arg7)
|
||||
|
||||
#define ngx_log_debug8(level, log, err, fmt, \
|
||||
arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) \
|
||||
if ((log)->log_level & level) \
|
||||
ngx_log_debug_core(log, err, fmt, \
|
||||
arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
|
||||
|
||||
#endif
|
||||
|
||||
#else /* !NGX_DEBUG */
|
||||
|
||||
#define ngx_log_debug0(level, log, err, fmt)
|
||||
#define ngx_log_debug1(level, log, err, fmt, arg1)
|
||||
#define ngx_log_debug2(level, log, err, fmt, arg1, arg2)
|
||||
#define ngx_log_debug3(level, log, err, fmt, arg1, arg2, arg3)
|
||||
#define ngx_log_debug4(level, log, err, fmt, arg1, arg2, arg3, arg4)
|
||||
#define ngx_log_debug5(level, log, err, fmt, arg1, arg2, arg3, arg4, arg5)
|
||||
#define ngx_log_debug6(level, log, err, fmt, arg1, arg2, arg3, arg4, arg5, arg6)
|
||||
#define ngx_log_debug7(level, log, err, fmt, arg1, arg2, arg3, arg4, arg5, \
|
||||
arg6, arg7)
|
||||
#define ngx_log_debug8(level, log, err, fmt, arg1, arg2, arg3, arg4, arg5, \
|
||||
arg6, arg7, arg8)
|
||||
|
||||
#endif
|
||||
|
||||
/*********************************/
|
||||
|
||||
ngx_log_t *ngx_log_init(u_char *prefix, u_char *error_log);
|
||||
void ngx_cdecl ngx_log_abort(ngx_err_t err, const char *fmt, ...);
|
||||
void ngx_cdecl ngx_log_stderr(ngx_err_t err, const char *fmt, ...);
|
||||
u_char *ngx_log_errno(u_char *buf, u_char *last, ngx_err_t err);
|
||||
ngx_int_t ngx_log_open_default(ngx_cycle_t *cycle);
|
||||
ngx_int_t ngx_log_redirect_stderr(ngx_cycle_t *cycle);
|
||||
ngx_log_t *ngx_log_get_file_log(ngx_log_t *head);
|
||||
char *ngx_log_set_log(ngx_conf_t *cf, ngx_log_t **head);
|
||||
|
||||
|
||||
/*
|
||||
* ngx_write_stderr() cannot be implemented as macro, since
|
||||
* MSVC does not allow to use #ifdef inside macro parameters.
|
||||
*
|
||||
* ngx_write_fd() is used instead of ngx_write_console(), since
|
||||
* CharToOemBuff() inside ngx_write_console() cannot be used with
|
||||
* read only buffer as destination and CharToOemBuff() is not needed
|
||||
* for ngx_write_stderr() anyway.
|
||||
*/
|
||||
static ngx_inline void
|
||||
ngx_write_stderr(char *text)
|
||||
{
|
||||
(void) ngx_write_fd(ngx_stderr, text, ngx_strlen(text));
|
||||
}
|
||||
|
||||
|
||||
static ngx_inline void
|
||||
ngx_write_stdout(char *text)
|
||||
{
|
||||
(void) ngx_write_fd(ngx_stdout, text, ngx_strlen(text));
|
||||
}
|
||||
|
||||
|
||||
extern ngx_module_t ngx_errlog_module;
|
||||
extern ngx_uint_t ngx_use_stderr;
|
||||
|
||||
|
||||
#endif /* _NGX_LOG_H_INCLUDED_ */
|
||||
283
nginx/src/core/ngx_md5.c
Normal file
283
nginx/src/core/ngx_md5.c
Normal file
|
|
@ -0,0 +1,283 @@
|
|||
|
||||
/*
|
||||
* An internal implementation, based on Alexander Peslyak's
|
||||
* public domain implementation:
|
||||
* http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_md5.h>
|
||||
|
||||
|
||||
static const u_char *ngx_md5_body(ngx_md5_t *ctx, const u_char *data,
|
||||
size_t size);
|
||||
|
||||
|
||||
void
|
||||
ngx_md5_init(ngx_md5_t *ctx)
|
||||
{
|
||||
ctx->a = 0x67452301;
|
||||
ctx->b = 0xefcdab89;
|
||||
ctx->c = 0x98badcfe;
|
||||
ctx->d = 0x10325476;
|
||||
|
||||
ctx->bytes = 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_md5_update(ngx_md5_t *ctx, const void *data, size_t size)
|
||||
{
|
||||
size_t used, free;
|
||||
|
||||
used = (size_t) (ctx->bytes & 0x3f);
|
||||
ctx->bytes += size;
|
||||
|
||||
if (used) {
|
||||
free = 64 - used;
|
||||
|
||||
if (size < free) {
|
||||
ngx_memcpy(&ctx->buffer[used], data, size);
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_memcpy(&ctx->buffer[used], data, free);
|
||||
data = (u_char *) data + free;
|
||||
size -= free;
|
||||
(void) ngx_md5_body(ctx, ctx->buffer, 64);
|
||||
}
|
||||
|
||||
if (size >= 64) {
|
||||
data = ngx_md5_body(ctx, data, size & ~(size_t) 0x3f);
|
||||
size &= 0x3f;
|
||||
}
|
||||
|
||||
ngx_memcpy(ctx->buffer, data, size);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_md5_final(u_char result[16], ngx_md5_t *ctx)
|
||||
{
|
||||
size_t used, free;
|
||||
|
||||
used = (size_t) (ctx->bytes & 0x3f);
|
||||
|
||||
ctx->buffer[used++] = 0x80;
|
||||
|
||||
free = 64 - used;
|
||||
|
||||
if (free < 8) {
|
||||
ngx_memzero(&ctx->buffer[used], free);
|
||||
(void) ngx_md5_body(ctx, ctx->buffer, 64);
|
||||
used = 0;
|
||||
free = 64;
|
||||
}
|
||||
|
||||
ngx_memzero(&ctx->buffer[used], free - 8);
|
||||
|
||||
ctx->bytes <<= 3;
|
||||
ctx->buffer[56] = (u_char) ctx->bytes;
|
||||
ctx->buffer[57] = (u_char) (ctx->bytes >> 8);
|
||||
ctx->buffer[58] = (u_char) (ctx->bytes >> 16);
|
||||
ctx->buffer[59] = (u_char) (ctx->bytes >> 24);
|
||||
ctx->buffer[60] = (u_char) (ctx->bytes >> 32);
|
||||
ctx->buffer[61] = (u_char) (ctx->bytes >> 40);
|
||||
ctx->buffer[62] = (u_char) (ctx->bytes >> 48);
|
||||
ctx->buffer[63] = (u_char) (ctx->bytes >> 56);
|
||||
|
||||
(void) ngx_md5_body(ctx, ctx->buffer, 64);
|
||||
|
||||
result[0] = (u_char) ctx->a;
|
||||
result[1] = (u_char) (ctx->a >> 8);
|
||||
result[2] = (u_char) (ctx->a >> 16);
|
||||
result[3] = (u_char) (ctx->a >> 24);
|
||||
result[4] = (u_char) ctx->b;
|
||||
result[5] = (u_char) (ctx->b >> 8);
|
||||
result[6] = (u_char) (ctx->b >> 16);
|
||||
result[7] = (u_char) (ctx->b >> 24);
|
||||
result[8] = (u_char) ctx->c;
|
||||
result[9] = (u_char) (ctx->c >> 8);
|
||||
result[10] = (u_char) (ctx->c >> 16);
|
||||
result[11] = (u_char) (ctx->c >> 24);
|
||||
result[12] = (u_char) ctx->d;
|
||||
result[13] = (u_char) (ctx->d >> 8);
|
||||
result[14] = (u_char) (ctx->d >> 16);
|
||||
result[15] = (u_char) (ctx->d >> 24);
|
||||
|
||||
ngx_memzero(ctx, sizeof(*ctx));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The basic MD5 functions.
|
||||
*
|
||||
* F and G are optimized compared to their RFC 1321 definitions for
|
||||
* architectures that lack an AND-NOT instruction, just like in
|
||||
* Colin Plumb's implementation.
|
||||
*/
|
||||
|
||||
#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
|
||||
#define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y))))
|
||||
#define H(x, y, z) ((x) ^ (y) ^ (z))
|
||||
#define I(x, y, z) ((y) ^ ((x) | ~(z)))
|
||||
|
||||
/*
|
||||
* The MD5 transformation for all four rounds.
|
||||
*/
|
||||
|
||||
#define STEP(f, a, b, c, d, x, t, s) \
|
||||
(a) += f((b), (c), (d)) + (x) + (t); \
|
||||
(a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
|
||||
(a) += (b)
|
||||
|
||||
/*
|
||||
* SET() reads 4 input bytes in little-endian byte order and stores them
|
||||
* in a properly aligned word in host byte order.
|
||||
*
|
||||
* The check for little-endian architectures that tolerate unaligned
|
||||
* memory accesses is just an optimization. Nothing will break if it
|
||||
* does not work.
|
||||
*/
|
||||
|
||||
#if (NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED)
|
||||
|
||||
#define SET(n) (*(uint32_t *) &p[n * 4])
|
||||
#define GET(n) (*(uint32_t *) &p[n * 4])
|
||||
|
||||
#else
|
||||
|
||||
#define SET(n) \
|
||||
(block[n] = \
|
||||
(uint32_t) p[n * 4] | \
|
||||
((uint32_t) p[n * 4 + 1] << 8) | \
|
||||
((uint32_t) p[n * 4 + 2] << 16) | \
|
||||
((uint32_t) p[n * 4 + 3] << 24))
|
||||
|
||||
#define GET(n) block[n]
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* This processes one or more 64-byte data blocks, but does not update
|
||||
* the bit counters. There are no alignment requirements.
|
||||
*/
|
||||
|
||||
static const u_char *
|
||||
ngx_md5_body(ngx_md5_t *ctx, const u_char *data, size_t size)
|
||||
{
|
||||
uint32_t a, b, c, d;
|
||||
uint32_t saved_a, saved_b, saved_c, saved_d;
|
||||
const u_char *p;
|
||||
#if !(NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED)
|
||||
uint32_t block[16];
|
||||
#endif
|
||||
|
||||
p = data;
|
||||
|
||||
a = ctx->a;
|
||||
b = ctx->b;
|
||||
c = ctx->c;
|
||||
d = ctx->d;
|
||||
|
||||
do {
|
||||
saved_a = a;
|
||||
saved_b = b;
|
||||
saved_c = c;
|
||||
saved_d = d;
|
||||
|
||||
/* Round 1 */
|
||||
|
||||
STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7);
|
||||
STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12);
|
||||
STEP(F, c, d, a, b, SET(2), 0x242070db, 17);
|
||||
STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22);
|
||||
STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7);
|
||||
STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12);
|
||||
STEP(F, c, d, a, b, SET(6), 0xa8304613, 17);
|
||||
STEP(F, b, c, d, a, SET(7), 0xfd469501, 22);
|
||||
STEP(F, a, b, c, d, SET(8), 0x698098d8, 7);
|
||||
STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12);
|
||||
STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17);
|
||||
STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22);
|
||||
STEP(F, a, b, c, d, SET(12), 0x6b901122, 7);
|
||||
STEP(F, d, a, b, c, SET(13), 0xfd987193, 12);
|
||||
STEP(F, c, d, a, b, SET(14), 0xa679438e, 17);
|
||||
STEP(F, b, c, d, a, SET(15), 0x49b40821, 22);
|
||||
|
||||
/* Round 2 */
|
||||
|
||||
STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5);
|
||||
STEP(G, d, a, b, c, GET(6), 0xc040b340, 9);
|
||||
STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14);
|
||||
STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20);
|
||||
STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5);
|
||||
STEP(G, d, a, b, c, GET(10), 0x02441453, 9);
|
||||
STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14);
|
||||
STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20);
|
||||
STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5);
|
||||
STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9);
|
||||
STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14);
|
||||
STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20);
|
||||
STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5);
|
||||
STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9);
|
||||
STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14);
|
||||
STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20);
|
||||
|
||||
/* Round 3 */
|
||||
|
||||
STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4);
|
||||
STEP(H, d, a, b, c, GET(8), 0x8771f681, 11);
|
||||
STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16);
|
||||
STEP(H, b, c, d, a, GET(14), 0xfde5380c, 23);
|
||||
STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4);
|
||||
STEP(H, d, a, b, c, GET(4), 0x4bdecfa9, 11);
|
||||
STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16);
|
||||
STEP(H, b, c, d, a, GET(10), 0xbebfbc70, 23);
|
||||
STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4);
|
||||
STEP(H, d, a, b, c, GET(0), 0xeaa127fa, 11);
|
||||
STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16);
|
||||
STEP(H, b, c, d, a, GET(6), 0x04881d05, 23);
|
||||
STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4);
|
||||
STEP(H, d, a, b, c, GET(12), 0xe6db99e5, 11);
|
||||
STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16);
|
||||
STEP(H, b, c, d, a, GET(2), 0xc4ac5665, 23);
|
||||
|
||||
/* Round 4 */
|
||||
|
||||
STEP(I, a, b, c, d, GET(0), 0xf4292244, 6);
|
||||
STEP(I, d, a, b, c, GET(7), 0x432aff97, 10);
|
||||
STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15);
|
||||
STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21);
|
||||
STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6);
|
||||
STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10);
|
||||
STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15);
|
||||
STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21);
|
||||
STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6);
|
||||
STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10);
|
||||
STEP(I, c, d, a, b, GET(6), 0xa3014314, 15);
|
||||
STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21);
|
||||
STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6);
|
||||
STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10);
|
||||
STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15);
|
||||
STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21);
|
||||
|
||||
a += saved_a;
|
||||
b += saved_b;
|
||||
c += saved_c;
|
||||
d += saved_d;
|
||||
|
||||
p += 64;
|
||||
|
||||
} while (size -= 64);
|
||||
|
||||
ctx->a = a;
|
||||
ctx->b = b;
|
||||
ctx->c = c;
|
||||
ctx->d = d;
|
||||
|
||||
return p;
|
||||
}
|
||||
28
nginx/src/core/ngx_md5.h
Normal file
28
nginx/src/core/ngx_md5.h
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_MD5_H_INCLUDED_
|
||||
#define _NGX_MD5_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint64_t bytes;
|
||||
uint32_t a, b, c, d;
|
||||
u_char buffer[64];
|
||||
} ngx_md5_t;
|
||||
|
||||
|
||||
void ngx_md5_init(ngx_md5_t *ctx);
|
||||
void ngx_md5_update(ngx_md5_t *ctx, const void *data, size_t size);
|
||||
void ngx_md5_final(u_char result[16], ngx_md5_t *ctx);
|
||||
|
||||
|
||||
#endif /* _NGX_MD5_H_INCLUDED_ */
|
||||
360
nginx/src/core/ngx_module.c
Normal file
360
nginx/src/core/ngx_module.c
Normal file
|
|
@ -0,0 +1,360 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Maxim Dounin
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
#define NGX_MAX_DYNAMIC_MODULES 128
|
||||
|
||||
|
||||
static ngx_uint_t ngx_module_index(ngx_cycle_t *cycle);
|
||||
static ngx_uint_t ngx_module_ctx_index(ngx_cycle_t *cycle, ngx_uint_t type,
|
||||
ngx_uint_t index);
|
||||
|
||||
|
||||
ngx_uint_t ngx_max_module;
|
||||
static ngx_uint_t ngx_modules_n;
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_preinit_modules(void)
|
||||
{
|
||||
ngx_uint_t i;
|
||||
|
||||
for (i = 0; ngx_modules[i]; i++) {
|
||||
ngx_modules[i]->index = i;
|
||||
ngx_modules[i]->name = ngx_module_names[i];
|
||||
}
|
||||
|
||||
ngx_modules_n = i;
|
||||
ngx_max_module = ngx_modules_n + NGX_MAX_DYNAMIC_MODULES;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_cycle_modules(ngx_cycle_t *cycle)
|
||||
{
|
||||
/*
|
||||
* create a list of modules to be used for this cycle,
|
||||
* copy static modules to it
|
||||
*/
|
||||
|
||||
cycle->modules = ngx_pcalloc(cycle->pool, (ngx_max_module + 1)
|
||||
* sizeof(ngx_module_t *));
|
||||
if (cycle->modules == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_memcpy(cycle->modules, ngx_modules,
|
||||
ngx_modules_n * sizeof(ngx_module_t *));
|
||||
|
||||
cycle->modules_n = ngx_modules_n;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_init_modules(ngx_cycle_t *cycle)
|
||||
{
|
||||
ngx_uint_t i;
|
||||
|
||||
for (i = 0; cycle->modules[i]; i++) {
|
||||
if (cycle->modules[i]->init_module) {
|
||||
if (cycle->modules[i]->init_module(cycle) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_count_modules(ngx_cycle_t *cycle, ngx_uint_t type)
|
||||
{
|
||||
ngx_uint_t i, next, max;
|
||||
ngx_module_t *module;
|
||||
|
||||
next = 0;
|
||||
max = 0;
|
||||
|
||||
/* count appropriate modules, set up their indices */
|
||||
|
||||
for (i = 0; cycle->modules[i]; i++) {
|
||||
module = cycle->modules[i];
|
||||
|
||||
if (module->type != type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (module->ctx_index != NGX_MODULE_UNSET_INDEX) {
|
||||
|
||||
/* if ctx_index was assigned, preserve it */
|
||||
|
||||
if (module->ctx_index > max) {
|
||||
max = module->ctx_index;
|
||||
}
|
||||
|
||||
if (module->ctx_index == next) {
|
||||
next++;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* search for some free index */
|
||||
|
||||
module->ctx_index = ngx_module_ctx_index(cycle, type, next);
|
||||
|
||||
if (module->ctx_index > max) {
|
||||
max = module->ctx_index;
|
||||
}
|
||||
|
||||
next = module->ctx_index + 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* make sure the number returned is big enough for previous
|
||||
* cycle as well, else there will be problems if the number
|
||||
* will be stored in a global variable (as it's used to be)
|
||||
* and we'll have to roll back to the previous cycle
|
||||
*/
|
||||
|
||||
if (cycle->old_cycle && cycle->old_cycle->modules) {
|
||||
|
||||
for (i = 0; cycle->old_cycle->modules[i]; i++) {
|
||||
module = cycle->old_cycle->modules[i];
|
||||
|
||||
if (module->type != type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (module->ctx_index > max) {
|
||||
max = module->ctx_index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* prevent loading of additional modules */
|
||||
|
||||
cycle->modules_used = 1;
|
||||
|
||||
return max + 1;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_add_module(ngx_conf_t *cf, ngx_str_t *file, ngx_module_t *module,
|
||||
char **order)
|
||||
{
|
||||
void *rv;
|
||||
ngx_uint_t i, m, before;
|
||||
ngx_core_module_t *core_module;
|
||||
|
||||
if (cf->cycle->modules_n >= ngx_max_module) {
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"too many modules loaded");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (module->version != nginx_version) {
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"module \"%V\" version %ui instead of %ui",
|
||||
file, module->version, (ngx_uint_t) nginx_version);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (ngx_strcmp(module->signature, NGX_MODULE_SIGNATURE) != 0) {
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"module \"%V\" is not binary compatible",
|
||||
file);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
for (m = 0; cf->cycle->modules[m]; m++) {
|
||||
if (ngx_strcmp(cf->cycle->modules[m]->name, module->name) == 0) {
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"module \"%s\" is already loaded",
|
||||
module->name);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* if the module wasn't previously loaded, assign an index
|
||||
*/
|
||||
|
||||
if (module->index == NGX_MODULE_UNSET_INDEX) {
|
||||
module->index = ngx_module_index(cf->cycle);
|
||||
|
||||
if (module->index >= ngx_max_module) {
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"too many modules loaded");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* put the module into the cycle->modules array
|
||||
*/
|
||||
|
||||
before = cf->cycle->modules_n;
|
||||
|
||||
if (order) {
|
||||
for (i = 0; order[i]; i++) {
|
||||
if (ngx_strcmp(order[i], module->name) == 0) {
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for ( /* void */ ; order[i]; i++) {
|
||||
|
||||
#if 0
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_CORE, cf->log, 0,
|
||||
"module: %s before %s",
|
||||
module->name, order[i]);
|
||||
#endif
|
||||
|
||||
for (m = 0; m < before; m++) {
|
||||
if (ngx_strcmp(cf->cycle->modules[m]->name, order[i]) == 0) {
|
||||
|
||||
ngx_log_debug3(NGX_LOG_DEBUG_CORE, cf->log, 0,
|
||||
"module: %s before %s:%i",
|
||||
module->name, order[i], m);
|
||||
|
||||
before = m;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* put the module before modules[before] */
|
||||
|
||||
if (before != cf->cycle->modules_n) {
|
||||
ngx_memmove(&cf->cycle->modules[before + 1],
|
||||
&cf->cycle->modules[before],
|
||||
(cf->cycle->modules_n - before) * sizeof(ngx_module_t *));
|
||||
}
|
||||
|
||||
cf->cycle->modules[before] = module;
|
||||
cf->cycle->modules_n++;
|
||||
|
||||
if (module->type == NGX_CORE_MODULE) {
|
||||
|
||||
/*
|
||||
* we are smart enough to initialize core modules;
|
||||
* other modules are expected to be loaded before
|
||||
* initialization - e.g., http modules must be loaded
|
||||
* before http{} block
|
||||
*/
|
||||
|
||||
core_module = module->ctx;
|
||||
|
||||
if (core_module->create_conf) {
|
||||
rv = core_module->create_conf(cf->cycle);
|
||||
if (rv == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
cf->cycle->conf_ctx[module->index] = rv;
|
||||
}
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_uint_t
|
||||
ngx_module_index(ngx_cycle_t *cycle)
|
||||
{
|
||||
ngx_uint_t i, index;
|
||||
ngx_module_t *module;
|
||||
|
||||
index = 0;
|
||||
|
||||
again:
|
||||
|
||||
/* find an unused index */
|
||||
|
||||
for (i = 0; cycle->modules[i]; i++) {
|
||||
module = cycle->modules[i];
|
||||
|
||||
if (module->index == index) {
|
||||
index++;
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
|
||||
/* check previous cycle */
|
||||
|
||||
if (cycle->old_cycle && cycle->old_cycle->modules) {
|
||||
|
||||
for (i = 0; cycle->old_cycle->modules[i]; i++) {
|
||||
module = cycle->old_cycle->modules[i];
|
||||
|
||||
if (module->index == index) {
|
||||
index++;
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
|
||||
static ngx_uint_t
|
||||
ngx_module_ctx_index(ngx_cycle_t *cycle, ngx_uint_t type, ngx_uint_t index)
|
||||
{
|
||||
ngx_uint_t i;
|
||||
ngx_module_t *module;
|
||||
|
||||
again:
|
||||
|
||||
/* find an unused ctx_index */
|
||||
|
||||
for (i = 0; cycle->modules[i]; i++) {
|
||||
module = cycle->modules[i];
|
||||
|
||||
if (module->type != type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (module->ctx_index == index) {
|
||||
index++;
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
|
||||
/* check previous cycle */
|
||||
|
||||
if (cycle->old_cycle && cycle->old_cycle->modules) {
|
||||
|
||||
for (i = 0; cycle->old_cycle->modules[i]; i++) {
|
||||
module = cycle->old_cycle->modules[i];
|
||||
|
||||
if (module->type != type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (module->ctx_index == index) {
|
||||
index++;
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
288
nginx/src/core/ngx_module.h
Normal file
288
nginx/src/core/ngx_module.h
Normal file
|
|
@ -0,0 +1,288 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Maxim Dounin
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_MODULE_H_INCLUDED_
|
||||
#define _NGX_MODULE_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <nginx.h>
|
||||
|
||||
|
||||
#define NGX_MODULE_UNSET_INDEX (ngx_uint_t) -1
|
||||
|
||||
|
||||
#define NGX_MODULE_SIGNATURE_0 \
|
||||
ngx_value(NGX_PTR_SIZE) "," \
|
||||
ngx_value(NGX_SIG_ATOMIC_T_SIZE) "," \
|
||||
ngx_value(NGX_TIME_T_SIZE) ","
|
||||
|
||||
#if (NGX_HAVE_KQUEUE)
|
||||
#define NGX_MODULE_SIGNATURE_1 "1"
|
||||
#else
|
||||
#define NGX_MODULE_SIGNATURE_1 "0"
|
||||
#endif
|
||||
|
||||
#if (NGX_HAVE_IOCP)
|
||||
#define NGX_MODULE_SIGNATURE_2 "1"
|
||||
#else
|
||||
#define NGX_MODULE_SIGNATURE_2 "0"
|
||||
#endif
|
||||
|
||||
#if (NGX_HAVE_FILE_AIO || NGX_COMPAT)
|
||||
#define NGX_MODULE_SIGNATURE_3 "1"
|
||||
#else
|
||||
#define NGX_MODULE_SIGNATURE_3 "0"
|
||||
#endif
|
||||
|
||||
#if (NGX_HAVE_SENDFILE_NODISKIO || NGX_COMPAT)
|
||||
#define NGX_MODULE_SIGNATURE_4 "1"
|
||||
#else
|
||||
#define NGX_MODULE_SIGNATURE_4 "0"
|
||||
#endif
|
||||
|
||||
#if (NGX_HAVE_EVENTFD)
|
||||
#define NGX_MODULE_SIGNATURE_5 "1"
|
||||
#else
|
||||
#define NGX_MODULE_SIGNATURE_5 "0"
|
||||
#endif
|
||||
|
||||
#if (NGX_HAVE_EPOLL)
|
||||
#define NGX_MODULE_SIGNATURE_6 "1"
|
||||
#else
|
||||
#define NGX_MODULE_SIGNATURE_6 "0"
|
||||
#endif
|
||||
|
||||
#if (NGX_HAVE_KEEPALIVE_TUNABLE)
|
||||
#define NGX_MODULE_SIGNATURE_7 "1"
|
||||
#else
|
||||
#define NGX_MODULE_SIGNATURE_7 "0"
|
||||
#endif
|
||||
|
||||
#if (NGX_HAVE_INET6)
|
||||
#define NGX_MODULE_SIGNATURE_8 "1"
|
||||
#else
|
||||
#define NGX_MODULE_SIGNATURE_8 "0"
|
||||
#endif
|
||||
|
||||
#define NGX_MODULE_SIGNATURE_9 "1"
|
||||
#define NGX_MODULE_SIGNATURE_10 "1"
|
||||
|
||||
#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
|
||||
#define NGX_MODULE_SIGNATURE_11 "1"
|
||||
#else
|
||||
#define NGX_MODULE_SIGNATURE_11 "0"
|
||||
#endif
|
||||
|
||||
#define NGX_MODULE_SIGNATURE_12 "1"
|
||||
|
||||
#if (NGX_HAVE_SETFIB)
|
||||
#define NGX_MODULE_SIGNATURE_13 "1"
|
||||
#else
|
||||
#define NGX_MODULE_SIGNATURE_13 "0"
|
||||
#endif
|
||||
|
||||
#if (NGX_HAVE_TCP_FASTOPEN)
|
||||
#define NGX_MODULE_SIGNATURE_14 "1"
|
||||
#else
|
||||
#define NGX_MODULE_SIGNATURE_14 "0"
|
||||
#endif
|
||||
|
||||
#if (NGX_HAVE_UNIX_DOMAIN)
|
||||
#define NGX_MODULE_SIGNATURE_15 "1"
|
||||
#else
|
||||
#define NGX_MODULE_SIGNATURE_15 "0"
|
||||
#endif
|
||||
|
||||
#if (NGX_HAVE_VARIADIC_MACROS)
|
||||
#define NGX_MODULE_SIGNATURE_16 "1"
|
||||
#else
|
||||
#define NGX_MODULE_SIGNATURE_16 "0"
|
||||
#endif
|
||||
|
||||
#define NGX_MODULE_SIGNATURE_17 "0"
|
||||
|
||||
#if (NGX_QUIC || NGX_COMPAT)
|
||||
#define NGX_MODULE_SIGNATURE_18 "1"
|
||||
#else
|
||||
#define NGX_MODULE_SIGNATURE_18 "0"
|
||||
#endif
|
||||
|
||||
#if (NGX_HAVE_OPENAT)
|
||||
#define NGX_MODULE_SIGNATURE_19 "1"
|
||||
#else
|
||||
#define NGX_MODULE_SIGNATURE_19 "0"
|
||||
#endif
|
||||
|
||||
#if (NGX_HAVE_ATOMIC_OPS)
|
||||
#define NGX_MODULE_SIGNATURE_20 "1"
|
||||
#else
|
||||
#define NGX_MODULE_SIGNATURE_20 "0"
|
||||
#endif
|
||||
|
||||
#if (NGX_HAVE_POSIX_SEM)
|
||||
#define NGX_MODULE_SIGNATURE_21 "1"
|
||||
#else
|
||||
#define NGX_MODULE_SIGNATURE_21 "0"
|
||||
#endif
|
||||
|
||||
#if (NGX_THREADS || NGX_COMPAT)
|
||||
#define NGX_MODULE_SIGNATURE_22 "1"
|
||||
#else
|
||||
#define NGX_MODULE_SIGNATURE_22 "0"
|
||||
#endif
|
||||
|
||||
#if (NGX_PCRE)
|
||||
#define NGX_MODULE_SIGNATURE_23 "1"
|
||||
#else
|
||||
#define NGX_MODULE_SIGNATURE_23 "0"
|
||||
#endif
|
||||
|
||||
#if (NGX_HTTP_SSL || NGX_COMPAT)
|
||||
#define NGX_MODULE_SIGNATURE_24 "1"
|
||||
#else
|
||||
#define NGX_MODULE_SIGNATURE_24 "0"
|
||||
#endif
|
||||
|
||||
#define NGX_MODULE_SIGNATURE_25 "1"
|
||||
|
||||
#if (NGX_HTTP_GZIP)
|
||||
#define NGX_MODULE_SIGNATURE_26 "1"
|
||||
#else
|
||||
#define NGX_MODULE_SIGNATURE_26 "0"
|
||||
#endif
|
||||
|
||||
#define NGX_MODULE_SIGNATURE_27 "1"
|
||||
|
||||
#if (NGX_HTTP_X_FORWARDED_FOR)
|
||||
#define NGX_MODULE_SIGNATURE_28 "1"
|
||||
#else
|
||||
#define NGX_MODULE_SIGNATURE_28 "0"
|
||||
#endif
|
||||
|
||||
#if (NGX_HTTP_REALIP)
|
||||
#define NGX_MODULE_SIGNATURE_29 "1"
|
||||
#else
|
||||
#define NGX_MODULE_SIGNATURE_29 "0"
|
||||
#endif
|
||||
|
||||
#if (NGX_HTTP_HEADERS)
|
||||
#define NGX_MODULE_SIGNATURE_30 "1"
|
||||
#else
|
||||
#define NGX_MODULE_SIGNATURE_30 "0"
|
||||
#endif
|
||||
|
||||
#if (NGX_HTTP_DAV)
|
||||
#define NGX_MODULE_SIGNATURE_31 "1"
|
||||
#else
|
||||
#define NGX_MODULE_SIGNATURE_31 "0"
|
||||
#endif
|
||||
|
||||
#if (NGX_HTTP_CACHE)
|
||||
#define NGX_MODULE_SIGNATURE_32 "1"
|
||||
#else
|
||||
#define NGX_MODULE_SIGNATURE_32 "0"
|
||||
#endif
|
||||
|
||||
#if (NGX_HTTP_UPSTREAM_ZONE)
|
||||
#define NGX_MODULE_SIGNATURE_33 "1"
|
||||
#else
|
||||
#define NGX_MODULE_SIGNATURE_33 "0"
|
||||
#endif
|
||||
|
||||
#if (NGX_COMPAT)
|
||||
#define NGX_MODULE_SIGNATURE_34 "1"
|
||||
#else
|
||||
#define NGX_MODULE_SIGNATURE_34 "0"
|
||||
#endif
|
||||
|
||||
#define NGX_MODULE_SIGNATURE \
|
||||
NGX_MODULE_SIGNATURE_0 NGX_MODULE_SIGNATURE_1 NGX_MODULE_SIGNATURE_2 \
|
||||
NGX_MODULE_SIGNATURE_3 NGX_MODULE_SIGNATURE_4 NGX_MODULE_SIGNATURE_5 \
|
||||
NGX_MODULE_SIGNATURE_6 NGX_MODULE_SIGNATURE_7 NGX_MODULE_SIGNATURE_8 \
|
||||
NGX_MODULE_SIGNATURE_9 NGX_MODULE_SIGNATURE_10 NGX_MODULE_SIGNATURE_11 \
|
||||
NGX_MODULE_SIGNATURE_12 NGX_MODULE_SIGNATURE_13 NGX_MODULE_SIGNATURE_14 \
|
||||
NGX_MODULE_SIGNATURE_15 NGX_MODULE_SIGNATURE_16 NGX_MODULE_SIGNATURE_17 \
|
||||
NGX_MODULE_SIGNATURE_18 NGX_MODULE_SIGNATURE_19 NGX_MODULE_SIGNATURE_20 \
|
||||
NGX_MODULE_SIGNATURE_21 NGX_MODULE_SIGNATURE_22 NGX_MODULE_SIGNATURE_23 \
|
||||
NGX_MODULE_SIGNATURE_24 NGX_MODULE_SIGNATURE_25 NGX_MODULE_SIGNATURE_26 \
|
||||
NGX_MODULE_SIGNATURE_27 NGX_MODULE_SIGNATURE_28 NGX_MODULE_SIGNATURE_29 \
|
||||
NGX_MODULE_SIGNATURE_30 NGX_MODULE_SIGNATURE_31 NGX_MODULE_SIGNATURE_32 \
|
||||
NGX_MODULE_SIGNATURE_33 NGX_MODULE_SIGNATURE_34
|
||||
|
||||
|
||||
#define NGX_MODULE_V1 \
|
||||
NGX_MODULE_UNSET_INDEX, NGX_MODULE_UNSET_INDEX, \
|
||||
NULL, 0, 0, nginx_version, NGX_MODULE_SIGNATURE
|
||||
|
||||
#define NGX_MODULE_V1_PADDING 0, 0, 0, 0, 0, 0, 0, 0
|
||||
|
||||
|
||||
struct ngx_module_s {
|
||||
ngx_uint_t ctx_index;
|
||||
ngx_uint_t index;
|
||||
|
||||
char *name;
|
||||
|
||||
ngx_uint_t spare0;
|
||||
ngx_uint_t spare1;
|
||||
|
||||
ngx_uint_t version;
|
||||
const char *signature;
|
||||
|
||||
void *ctx;
|
||||
ngx_command_t *commands;
|
||||
ngx_uint_t type;
|
||||
|
||||
ngx_int_t (*init_master)(ngx_log_t *log);
|
||||
|
||||
ngx_int_t (*init_module)(ngx_cycle_t *cycle);
|
||||
|
||||
ngx_int_t (*init_process)(ngx_cycle_t *cycle);
|
||||
ngx_int_t (*init_thread)(ngx_cycle_t *cycle);
|
||||
void (*exit_thread)(ngx_cycle_t *cycle);
|
||||
void (*exit_process)(ngx_cycle_t *cycle);
|
||||
|
||||
void (*exit_master)(ngx_cycle_t *cycle);
|
||||
|
||||
uintptr_t spare_hook0;
|
||||
uintptr_t spare_hook1;
|
||||
uintptr_t spare_hook2;
|
||||
uintptr_t spare_hook3;
|
||||
uintptr_t spare_hook4;
|
||||
uintptr_t spare_hook5;
|
||||
uintptr_t spare_hook6;
|
||||
uintptr_t spare_hook7;
|
||||
};
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_str_t name;
|
||||
void *(*create_conf)(ngx_cycle_t *cycle);
|
||||
char *(*init_conf)(ngx_cycle_t *cycle, void *conf);
|
||||
} ngx_core_module_t;
|
||||
|
||||
|
||||
ngx_int_t ngx_preinit_modules(void);
|
||||
ngx_int_t ngx_cycle_modules(ngx_cycle_t *cycle);
|
||||
ngx_int_t ngx_init_modules(ngx_cycle_t *cycle);
|
||||
ngx_int_t ngx_count_modules(ngx_cycle_t *cycle, ngx_uint_t type);
|
||||
|
||||
|
||||
ngx_int_t ngx_add_module(ngx_conf_t *cf, ngx_str_t *file,
|
||||
ngx_module_t *module, char **order);
|
||||
|
||||
|
||||
extern ngx_module_t *ngx_modules[];
|
||||
extern ngx_uint_t ngx_max_module;
|
||||
|
||||
extern char *ngx_module_names[];
|
||||
|
||||
|
||||
#endif /* _NGX_MODULE_H_INCLUDED_ */
|
||||
52
nginx/src/core/ngx_murmurhash.c
Normal file
52
nginx/src/core/ngx_murmurhash.c
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Austin Appleby
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
uint32_t
|
||||
ngx_murmur_hash2(u_char *data, size_t len)
|
||||
{
|
||||
uint32_t h, k;
|
||||
|
||||
h = 0 ^ len;
|
||||
|
||||
while (len >= 4) {
|
||||
k = data[0];
|
||||
k |= data[1] << 8;
|
||||
k |= data[2] << 16;
|
||||
k |= data[3] << 24;
|
||||
|
||||
k *= 0x5bd1e995;
|
||||
k ^= k >> 24;
|
||||
k *= 0x5bd1e995;
|
||||
|
||||
h *= 0x5bd1e995;
|
||||
h ^= k;
|
||||
|
||||
data += 4;
|
||||
len -= 4;
|
||||
}
|
||||
|
||||
switch (len) {
|
||||
case 3:
|
||||
h ^= data[2] << 16;
|
||||
/* fall through */
|
||||
case 2:
|
||||
h ^= data[1] << 8;
|
||||
/* fall through */
|
||||
case 1:
|
||||
h ^= data[0];
|
||||
h *= 0x5bd1e995;
|
||||
}
|
||||
|
||||
h ^= h >> 13;
|
||||
h *= 0x5bd1e995;
|
||||
h ^= h >> 15;
|
||||
|
||||
return h;
|
||||
}
|
||||
19
nginx/src/core/ngx_murmurhash.h
Normal file
19
nginx/src/core/ngx_murmurhash.h
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_MURMURHASH_H_INCLUDED_
|
||||
#define _NGX_MURMURHASH_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
uint32_t ngx_murmur_hash2(u_char *data, size_t len);
|
||||
|
||||
|
||||
#endif /* _NGX_MURMURHASH_H_INCLUDED_ */
|
||||
1253
nginx/src/core/ngx_open_file_cache.c
Normal file
1253
nginx/src/core/ngx_open_file_cache.c
Normal file
File diff suppressed because it is too large
Load diff
129
nginx/src/core/ngx_open_file_cache.h
Normal file
129
nginx/src/core/ngx_open_file_cache.h
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
#ifndef _NGX_OPEN_FILE_CACHE_H_INCLUDED_
|
||||
#define _NGX_OPEN_FILE_CACHE_H_INCLUDED_
|
||||
|
||||
|
||||
#define NGX_OPEN_FILE_DIRECTIO_OFF NGX_MAX_OFF_T_VALUE
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_fd_t fd;
|
||||
ngx_file_uniq_t uniq;
|
||||
time_t mtime;
|
||||
off_t size;
|
||||
off_t fs_size;
|
||||
off_t directio;
|
||||
size_t read_ahead;
|
||||
|
||||
ngx_err_t err;
|
||||
char *failed;
|
||||
|
||||
time_t valid;
|
||||
|
||||
ngx_uint_t min_uses;
|
||||
|
||||
#if (NGX_HAVE_OPENAT)
|
||||
size_t disable_symlinks_from;
|
||||
unsigned disable_symlinks:2;
|
||||
#endif
|
||||
|
||||
unsigned test_dir:1;
|
||||
unsigned test_only:1;
|
||||
unsigned log:1;
|
||||
unsigned errors:1;
|
||||
unsigned events:1;
|
||||
|
||||
unsigned is_dir:1;
|
||||
unsigned is_file:1;
|
||||
unsigned is_link:1;
|
||||
unsigned is_exec:1;
|
||||
unsigned is_directio:1;
|
||||
} ngx_open_file_info_t;
|
||||
|
||||
|
||||
typedef struct ngx_cached_open_file_s ngx_cached_open_file_t;
|
||||
|
||||
struct ngx_cached_open_file_s {
|
||||
ngx_rbtree_node_t node;
|
||||
ngx_queue_t queue;
|
||||
|
||||
u_char *name;
|
||||
time_t created;
|
||||
time_t accessed;
|
||||
|
||||
ngx_fd_t fd;
|
||||
ngx_file_uniq_t uniq;
|
||||
time_t mtime;
|
||||
off_t size;
|
||||
ngx_err_t err;
|
||||
|
||||
uint32_t uses;
|
||||
|
||||
#if (NGX_HAVE_OPENAT)
|
||||
size_t disable_symlinks_from;
|
||||
unsigned disable_symlinks:2;
|
||||
#endif
|
||||
|
||||
unsigned count:24;
|
||||
unsigned close:1;
|
||||
unsigned use_event:1;
|
||||
|
||||
unsigned is_dir:1;
|
||||
unsigned is_file:1;
|
||||
unsigned is_link:1;
|
||||
unsigned is_exec:1;
|
||||
unsigned is_directio:1;
|
||||
|
||||
ngx_event_t *event;
|
||||
};
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_rbtree_t rbtree;
|
||||
ngx_rbtree_node_t sentinel;
|
||||
ngx_queue_t expire_queue;
|
||||
|
||||
ngx_uint_t current;
|
||||
ngx_uint_t max;
|
||||
time_t inactive;
|
||||
} ngx_open_file_cache_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_open_file_cache_t *cache;
|
||||
ngx_cached_open_file_t *file;
|
||||
ngx_uint_t min_uses;
|
||||
ngx_log_t *log;
|
||||
} ngx_open_file_cache_cleanup_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
|
||||
/* ngx_connection_t stub to allow use c->fd as event ident */
|
||||
void *data;
|
||||
ngx_event_t *read;
|
||||
ngx_event_t *write;
|
||||
ngx_fd_t fd;
|
||||
|
||||
ngx_cached_open_file_t *file;
|
||||
ngx_open_file_cache_t *cache;
|
||||
} ngx_open_file_cache_event_t;
|
||||
|
||||
|
||||
ngx_open_file_cache_t *ngx_open_file_cache_init(ngx_pool_t *pool,
|
||||
ngx_uint_t max, time_t inactive);
|
||||
ngx_int_t ngx_open_cached_file(ngx_open_file_cache_t *cache, ngx_str_t *name,
|
||||
ngx_open_file_info_t *of, ngx_pool_t *pool);
|
||||
|
||||
|
||||
#endif /* _NGX_OPEN_FILE_CACHE_H_INCLUDED_ */
|
||||
820
nginx/src/core/ngx_output_chain.c
Normal file
820
nginx/src/core/ngx_output_chain.c
Normal file
|
|
@ -0,0 +1,820 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_event.h>
|
||||
|
||||
|
||||
#if 0
|
||||
#define NGX_SENDFILE_LIMIT 4096
|
||||
#endif
|
||||
|
||||
/*
|
||||
* When DIRECTIO is enabled FreeBSD, Solaris, and MacOSX read directly
|
||||
* to an application memory from a device if parameters are aligned
|
||||
* to device sector boundary (512 bytes). They fallback to usual read
|
||||
* operation if the parameters are not aligned.
|
||||
* Linux allows DIRECTIO only if the parameters are aligned to a filesystem
|
||||
* sector boundary, otherwise it returns EINVAL. The sector size is
|
||||
* usually 512 bytes, however, on XFS it may be 4096 bytes.
|
||||
*/
|
||||
|
||||
#define NGX_NONE 1
|
||||
|
||||
|
||||
static ngx_inline ngx_int_t
|
||||
ngx_output_chain_as_is(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf);
|
||||
static ngx_int_t ngx_output_chain_add_copy(ngx_pool_t *pool,
|
||||
ngx_chain_t **chain, ngx_chain_t *in);
|
||||
static ngx_int_t ngx_output_chain_align_file_buf(ngx_output_chain_ctx_t *ctx,
|
||||
off_t bsize);
|
||||
static ngx_int_t ngx_output_chain_get_buf(ngx_output_chain_ctx_t *ctx,
|
||||
off_t bsize);
|
||||
static ngx_int_t ngx_output_chain_copy_buf(ngx_output_chain_ctx_t *ctx);
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_output_chain(ngx_output_chain_ctx_t *ctx, ngx_chain_t *in)
|
||||
{
|
||||
off_t bsize;
|
||||
ngx_int_t rc, last;
|
||||
ngx_chain_t *cl, *out, **last_out;
|
||||
|
||||
if (ctx->in == NULL && ctx->busy == NULL
|
||||
#if (NGX_HAVE_FILE_AIO || NGX_THREADS)
|
||||
&& !ctx->aio
|
||||
#endif
|
||||
)
|
||||
{
|
||||
/*
|
||||
* the short path for the case when the ctx->in and ctx->busy chains
|
||||
* are empty, the incoming chain is empty too or has the single buf
|
||||
* that does not require the copy
|
||||
*/
|
||||
|
||||
if (in == NULL) {
|
||||
return ctx->output_filter(ctx->filter_ctx, in);
|
||||
}
|
||||
|
||||
if (in->next == NULL
|
||||
#if (NGX_SENDFILE_LIMIT)
|
||||
&& !(in->buf->in_file && in->buf->file_last > NGX_SENDFILE_LIMIT)
|
||||
#endif
|
||||
&& ngx_output_chain_as_is(ctx, in->buf))
|
||||
{
|
||||
return ctx->output_filter(ctx->filter_ctx, in);
|
||||
}
|
||||
}
|
||||
|
||||
/* add the incoming buf to the chain ctx->in */
|
||||
|
||||
if (in) {
|
||||
if (ngx_output_chain_add_copy(ctx->pool, &ctx->in, in) == NGX_ERROR) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
out = NULL;
|
||||
last_out = &out;
|
||||
last = NGX_NONE;
|
||||
|
||||
for ( ;; ) {
|
||||
|
||||
#if (NGX_HAVE_FILE_AIO || NGX_THREADS)
|
||||
if (ctx->aio) {
|
||||
return NGX_AGAIN;
|
||||
}
|
||||
#endif
|
||||
|
||||
while (ctx->in) {
|
||||
|
||||
/*
|
||||
* cycle while there are the ctx->in bufs
|
||||
* and there are the free output bufs to copy in
|
||||
*/
|
||||
|
||||
bsize = ngx_buf_size(ctx->in->buf);
|
||||
|
||||
if (bsize == 0 && !ngx_buf_special(ctx->in->buf)) {
|
||||
|
||||
ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, 0,
|
||||
"zero size buf in output "
|
||||
"t:%d r:%d f:%d %p %p-%p %p %O-%O",
|
||||
ctx->in->buf->temporary,
|
||||
ctx->in->buf->recycled,
|
||||
ctx->in->buf->in_file,
|
||||
ctx->in->buf->start,
|
||||
ctx->in->buf->pos,
|
||||
ctx->in->buf->last,
|
||||
ctx->in->buf->file,
|
||||
ctx->in->buf->file_pos,
|
||||
ctx->in->buf->file_last);
|
||||
|
||||
ngx_debug_point();
|
||||
|
||||
cl = ctx->in;
|
||||
ctx->in = cl->next;
|
||||
|
||||
ngx_free_chain(ctx->pool, cl);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bsize < 0) {
|
||||
|
||||
ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, 0,
|
||||
"negative size buf in output "
|
||||
"t:%d r:%d f:%d %p %p-%p %p %O-%O",
|
||||
ctx->in->buf->temporary,
|
||||
ctx->in->buf->recycled,
|
||||
ctx->in->buf->in_file,
|
||||
ctx->in->buf->start,
|
||||
ctx->in->buf->pos,
|
||||
ctx->in->buf->last,
|
||||
ctx->in->buf->file,
|
||||
ctx->in->buf->file_pos,
|
||||
ctx->in->buf->file_last);
|
||||
|
||||
ngx_debug_point();
|
||||
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (ngx_output_chain_as_is(ctx, ctx->in->buf)) {
|
||||
|
||||
/* move the chain link to the output chain */
|
||||
|
||||
cl = ctx->in;
|
||||
ctx->in = cl->next;
|
||||
|
||||
*last_out = cl;
|
||||
last_out = &cl->next;
|
||||
cl->next = NULL;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ctx->buf == NULL) {
|
||||
|
||||
rc = ngx_output_chain_align_file_buf(ctx, bsize);
|
||||
|
||||
if (rc == NGX_ERROR) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (rc != NGX_OK) {
|
||||
|
||||
if (ctx->free) {
|
||||
|
||||
/* get the free buf */
|
||||
|
||||
cl = ctx->free;
|
||||
ctx->buf = cl->buf;
|
||||
ctx->free = cl->next;
|
||||
|
||||
ngx_free_chain(ctx->pool, cl);
|
||||
|
||||
} else if (out || ctx->allocated == ctx->bufs.num) {
|
||||
|
||||
break;
|
||||
|
||||
} else if (ngx_output_chain_get_buf(ctx, bsize) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rc = ngx_output_chain_copy_buf(ctx);
|
||||
|
||||
if (rc == NGX_ERROR) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (rc == NGX_AGAIN) {
|
||||
if (out) {
|
||||
break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* delete the completed buf from the ctx->in chain */
|
||||
|
||||
if (ngx_buf_size(ctx->in->buf) == 0) {
|
||||
cl = ctx->in;
|
||||
ctx->in = cl->next;
|
||||
|
||||
ngx_free_chain(ctx->pool, cl);
|
||||
}
|
||||
|
||||
cl = ngx_alloc_chain_link(ctx->pool);
|
||||
if (cl == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
cl->buf = ctx->buf;
|
||||
cl->next = NULL;
|
||||
*last_out = cl;
|
||||
last_out = &cl->next;
|
||||
ctx->buf = NULL;
|
||||
}
|
||||
|
||||
if (out == NULL && last != NGX_NONE) {
|
||||
|
||||
if (ctx->in) {
|
||||
return NGX_AGAIN;
|
||||
}
|
||||
|
||||
return last;
|
||||
}
|
||||
|
||||
last = ctx->output_filter(ctx->filter_ctx, out);
|
||||
|
||||
if (last == NGX_ERROR || last == NGX_DONE) {
|
||||
return last;
|
||||
}
|
||||
|
||||
ngx_chain_update_chains(ctx->pool, &ctx->free, &ctx->busy, &out,
|
||||
ctx->tag);
|
||||
last_out = &out;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static ngx_inline ngx_int_t
|
||||
ngx_output_chain_as_is(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf)
|
||||
{
|
||||
ngx_uint_t sendfile;
|
||||
|
||||
if (ngx_buf_special(buf)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if (NGX_THREADS)
|
||||
if (buf->in_file) {
|
||||
buf->file->thread_handler = ctx->thread_handler;
|
||||
buf->file->thread_ctx = ctx->filter_ctx;
|
||||
}
|
||||
#endif
|
||||
|
||||
sendfile = ctx->sendfile;
|
||||
|
||||
#if (NGX_SENDFILE_LIMIT)
|
||||
|
||||
if (buf->in_file && buf->file_pos >= NGX_SENDFILE_LIMIT) {
|
||||
sendfile = 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if !(NGX_HAVE_SENDFILE_NODISKIO)
|
||||
|
||||
/*
|
||||
* With DIRECTIO, disable sendfile() unless sendfile(SF_NOCACHE)
|
||||
* is available.
|
||||
*/
|
||||
|
||||
if (buf->in_file && buf->file->directio) {
|
||||
sendfile = 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if (!sendfile) {
|
||||
|
||||
if (!ngx_buf_in_memory(buf)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
buf->in_file = 0;
|
||||
}
|
||||
|
||||
if (ctx->need_in_memory && !ngx_buf_in_memory(buf)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ctx->need_in_temp && (buf->memory || buf->mmap)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_output_chain_add_copy(ngx_pool_t *pool, ngx_chain_t **chain,
|
||||
ngx_chain_t *in)
|
||||
{
|
||||
ngx_chain_t *cl, **ll;
|
||||
#if (NGX_SENDFILE_LIMIT)
|
||||
ngx_buf_t *b, *buf;
|
||||
#endif
|
||||
|
||||
ll = chain;
|
||||
|
||||
for (cl = *chain; cl; cl = cl->next) {
|
||||
ll = &cl->next;
|
||||
}
|
||||
|
||||
while (in) {
|
||||
|
||||
cl = ngx_alloc_chain_link(pool);
|
||||
if (cl == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
#if (NGX_SENDFILE_LIMIT)
|
||||
|
||||
buf = in->buf;
|
||||
|
||||
if (buf->in_file
|
||||
&& buf->file_pos < NGX_SENDFILE_LIMIT
|
||||
&& buf->file_last > NGX_SENDFILE_LIMIT)
|
||||
{
|
||||
/* split a file buf on two bufs by the sendfile limit */
|
||||
|
||||
b = ngx_calloc_buf(pool);
|
||||
if (b == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_memcpy(b, buf, sizeof(ngx_buf_t));
|
||||
|
||||
if (ngx_buf_in_memory(buf)) {
|
||||
buf->pos += (ssize_t) (NGX_SENDFILE_LIMIT - buf->file_pos);
|
||||
b->last = buf->pos;
|
||||
}
|
||||
|
||||
buf->file_pos = NGX_SENDFILE_LIMIT;
|
||||
b->file_last = NGX_SENDFILE_LIMIT;
|
||||
|
||||
cl->buf = b;
|
||||
|
||||
} else {
|
||||
cl->buf = buf;
|
||||
in = in->next;
|
||||
}
|
||||
|
||||
#else
|
||||
cl->buf = in->buf;
|
||||
in = in->next;
|
||||
|
||||
#endif
|
||||
|
||||
cl->next = NULL;
|
||||
*ll = cl;
|
||||
ll = &cl->next;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_output_chain_align_file_buf(ngx_output_chain_ctx_t *ctx, off_t bsize)
|
||||
{
|
||||
size_t size;
|
||||
ngx_buf_t *in;
|
||||
|
||||
in = ctx->in->buf;
|
||||
|
||||
if (in->file == NULL || !in->file->directio) {
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
ctx->directio = 1;
|
||||
|
||||
size = (size_t) (in->file_pos - (in->file_pos & ~(ctx->alignment - 1)));
|
||||
|
||||
if (size == 0) {
|
||||
|
||||
if (bsize >= (off_t) ctx->bufs.size) {
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
size = (size_t) bsize;
|
||||
|
||||
} else {
|
||||
size = (size_t) ctx->alignment - size;
|
||||
|
||||
if ((off_t) size > bsize) {
|
||||
size = (size_t) bsize;
|
||||
}
|
||||
}
|
||||
|
||||
ctx->buf = ngx_create_temp_buf(ctx->pool, size);
|
||||
if (ctx->buf == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* we do not set ctx->buf->tag, because we do not want
|
||||
* to reuse the buf via ctx->free list
|
||||
*/
|
||||
|
||||
#if (NGX_HAVE_ALIGNED_DIRECTIO)
|
||||
ctx->unaligned = 1;
|
||||
#endif
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_output_chain_get_buf(ngx_output_chain_ctx_t *ctx, off_t bsize)
|
||||
{
|
||||
size_t size;
|
||||
ngx_buf_t *b, *in;
|
||||
ngx_uint_t recycled;
|
||||
|
||||
in = ctx->in->buf;
|
||||
size = ctx->bufs.size;
|
||||
recycled = 1;
|
||||
|
||||
if (in->last_in_chain) {
|
||||
|
||||
if (bsize < (off_t) size) {
|
||||
|
||||
/*
|
||||
* allocate a small temp buf for a small last buf
|
||||
* or its small last part
|
||||
*/
|
||||
|
||||
size = (size_t) bsize;
|
||||
recycled = 0;
|
||||
|
||||
} else if (!ctx->directio
|
||||
&& ctx->bufs.num == 1
|
||||
&& (bsize < (off_t) (size + size / 4)))
|
||||
{
|
||||
/*
|
||||
* allocate a temp buf that equals to a last buf,
|
||||
* if there is no directio, the last buf size is lesser
|
||||
* than 1.25 of bufs.size and the temp buf is single
|
||||
*/
|
||||
|
||||
size = (size_t) bsize;
|
||||
recycled = 0;
|
||||
}
|
||||
}
|
||||
|
||||
b = ngx_calloc_buf(ctx->pool);
|
||||
if (b == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (ctx->directio) {
|
||||
|
||||
/*
|
||||
* allocate block aligned to a disk sector size to enable
|
||||
* userland buffer direct usage conjunctly with directio
|
||||
*/
|
||||
|
||||
b->start = ngx_pmemalign(ctx->pool, size, (size_t) ctx->alignment);
|
||||
if (b->start == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
} else {
|
||||
b->start = ngx_palloc(ctx->pool, size);
|
||||
if (b->start == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
b->pos = b->start;
|
||||
b->last = b->start;
|
||||
b->end = b->last + size;
|
||||
b->temporary = 1;
|
||||
b->tag = ctx->tag;
|
||||
b->recycled = recycled;
|
||||
|
||||
ctx->buf = b;
|
||||
ctx->allocated++;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_output_chain_copy_buf(ngx_output_chain_ctx_t *ctx)
|
||||
{
|
||||
off_t size;
|
||||
ssize_t n;
|
||||
ngx_buf_t *src, *dst;
|
||||
ngx_uint_t sendfile;
|
||||
|
||||
src = ctx->in->buf;
|
||||
dst = ctx->buf;
|
||||
|
||||
size = ngx_buf_size(src);
|
||||
size = ngx_min(size, dst->end - dst->pos);
|
||||
|
||||
sendfile = ctx->sendfile && !ctx->directio;
|
||||
|
||||
#if (NGX_SENDFILE_LIMIT)
|
||||
|
||||
if (src->in_file && src->file_pos >= NGX_SENDFILE_LIMIT) {
|
||||
sendfile = 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if (ngx_buf_in_memory(src)) {
|
||||
ngx_memcpy(dst->pos, src->pos, (size_t) size);
|
||||
src->pos += (size_t) size;
|
||||
dst->last += (size_t) size;
|
||||
|
||||
if (src->in_file) {
|
||||
|
||||
if (sendfile) {
|
||||
dst->in_file = 1;
|
||||
dst->file = src->file;
|
||||
dst->file_pos = src->file_pos;
|
||||
dst->file_last = src->file_pos + size;
|
||||
|
||||
} else {
|
||||
dst->in_file = 0;
|
||||
}
|
||||
|
||||
src->file_pos += size;
|
||||
|
||||
} else {
|
||||
dst->in_file = 0;
|
||||
}
|
||||
|
||||
if (src->pos == src->last) {
|
||||
dst->flush = src->flush;
|
||||
dst->last_buf = src->last_buf;
|
||||
dst->last_in_chain = src->last_in_chain;
|
||||
|
||||
} else {
|
||||
dst->flush = 0;
|
||||
dst->last_buf = 0;
|
||||
dst->last_in_chain = 0;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
#if (NGX_HAVE_ALIGNED_DIRECTIO)
|
||||
|
||||
if (ctx->unaligned) {
|
||||
if (ngx_directio_off(src->file->fd) == NGX_FILE_ERROR) {
|
||||
ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, ngx_errno,
|
||||
ngx_directio_off_n " \"%s\" failed",
|
||||
src->file->name.data);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if (NGX_HAVE_FILE_AIO)
|
||||
if (ctx->aio_handler) {
|
||||
n = ngx_file_aio_read(src->file, dst->pos, (size_t) size,
|
||||
src->file_pos, ctx->pool);
|
||||
if (n == NGX_AGAIN) {
|
||||
ctx->aio_handler(ctx, src->file);
|
||||
return NGX_AGAIN;
|
||||
}
|
||||
|
||||
} else
|
||||
#endif
|
||||
#if (NGX_THREADS)
|
||||
if (ctx->thread_handler) {
|
||||
src->file->thread_task = ctx->thread_task;
|
||||
src->file->thread_handler = ctx->thread_handler;
|
||||
src->file->thread_ctx = ctx->filter_ctx;
|
||||
|
||||
n = ngx_thread_read(src->file, dst->pos, (size_t) size,
|
||||
src->file_pos, ctx->pool);
|
||||
if (n == NGX_AGAIN) {
|
||||
ctx->thread_task = src->file->thread_task;
|
||||
return NGX_AGAIN;
|
||||
}
|
||||
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
n = ngx_read_file(src->file, dst->pos, (size_t) size,
|
||||
src->file_pos);
|
||||
}
|
||||
|
||||
#if (NGX_HAVE_ALIGNED_DIRECTIO)
|
||||
|
||||
if (ctx->unaligned) {
|
||||
ngx_err_t err;
|
||||
|
||||
err = ngx_errno;
|
||||
|
||||
if (ngx_directio_on(src->file->fd) == NGX_FILE_ERROR) {
|
||||
ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, ngx_errno,
|
||||
ngx_directio_on_n " \"%s\" failed",
|
||||
src->file->name.data);
|
||||
}
|
||||
|
||||
ngx_set_errno(err);
|
||||
|
||||
ctx->unaligned = 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if (n == NGX_ERROR) {
|
||||
return (ngx_int_t) n;
|
||||
}
|
||||
|
||||
if (n != size) {
|
||||
ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, 0,
|
||||
ngx_read_file_n " read only %z of %O from \"%s\"",
|
||||
n, size, src->file->name.data);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
dst->last += n;
|
||||
|
||||
if (sendfile) {
|
||||
dst->in_file = 1;
|
||||
dst->file = src->file;
|
||||
dst->file_pos = src->file_pos;
|
||||
dst->file_last = src->file_pos + n;
|
||||
|
||||
} else {
|
||||
dst->in_file = 0;
|
||||
}
|
||||
|
||||
src->file_pos += n;
|
||||
|
||||
if (src->file_pos == src->file_last) {
|
||||
dst->flush = src->flush;
|
||||
dst->last_buf = src->last_buf;
|
||||
dst->last_in_chain = src->last_in_chain;
|
||||
|
||||
} else {
|
||||
dst->flush = 0;
|
||||
dst->last_buf = 0;
|
||||
dst->last_in_chain = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_chain_writer(void *data, ngx_chain_t *in)
|
||||
{
|
||||
ngx_chain_writer_ctx_t *ctx = data;
|
||||
|
||||
off_t size;
|
||||
ngx_chain_t *cl, *ln, *chain;
|
||||
ngx_connection_t *c;
|
||||
|
||||
c = ctx->connection;
|
||||
|
||||
for (size = 0; in; in = in->next) {
|
||||
|
||||
if (ngx_buf_size(in->buf) == 0 && !ngx_buf_special(in->buf)) {
|
||||
|
||||
ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, 0,
|
||||
"zero size buf in chain writer "
|
||||
"t:%d r:%d f:%d %p %p-%p %p %O-%O",
|
||||
in->buf->temporary,
|
||||
in->buf->recycled,
|
||||
in->buf->in_file,
|
||||
in->buf->start,
|
||||
in->buf->pos,
|
||||
in->buf->last,
|
||||
in->buf->file,
|
||||
in->buf->file_pos,
|
||||
in->buf->file_last);
|
||||
|
||||
ngx_debug_point();
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ngx_buf_size(in->buf) < 0) {
|
||||
|
||||
ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, 0,
|
||||
"negative size buf in chain writer "
|
||||
"t:%d r:%d f:%d %p %p-%p %p %O-%O",
|
||||
in->buf->temporary,
|
||||
in->buf->recycled,
|
||||
in->buf->in_file,
|
||||
in->buf->start,
|
||||
in->buf->pos,
|
||||
in->buf->last,
|
||||
in->buf->file,
|
||||
in->buf->file_pos,
|
||||
in->buf->file_last);
|
||||
|
||||
ngx_debug_point();
|
||||
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
size += ngx_buf_size(in->buf);
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_CORE, c->log, 0,
|
||||
"chain writer buf fl:%d s:%uO",
|
||||
in->buf->flush, ngx_buf_size(in->buf));
|
||||
|
||||
cl = ngx_alloc_chain_link(ctx->pool);
|
||||
if (cl == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
cl->buf = in->buf;
|
||||
cl->next = NULL;
|
||||
*ctx->last = cl;
|
||||
ctx->last = &cl->next;
|
||||
}
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0,
|
||||
"chain writer in: %p", ctx->out);
|
||||
|
||||
for (cl = ctx->out; cl; cl = cl->next) {
|
||||
|
||||
if (ngx_buf_size(cl->buf) == 0 && !ngx_buf_special(cl->buf)) {
|
||||
|
||||
ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, 0,
|
||||
"zero size buf in chain writer "
|
||||
"t:%d r:%d f:%d %p %p-%p %p %O-%O",
|
||||
cl->buf->temporary,
|
||||
cl->buf->recycled,
|
||||
cl->buf->in_file,
|
||||
cl->buf->start,
|
||||
cl->buf->pos,
|
||||
cl->buf->last,
|
||||
cl->buf->file,
|
||||
cl->buf->file_pos,
|
||||
cl->buf->file_last);
|
||||
|
||||
ngx_debug_point();
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ngx_buf_size(cl->buf) < 0) {
|
||||
|
||||
ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, 0,
|
||||
"negative size buf in chain writer "
|
||||
"t:%d r:%d f:%d %p %p-%p %p %O-%O",
|
||||
cl->buf->temporary,
|
||||
cl->buf->recycled,
|
||||
cl->buf->in_file,
|
||||
cl->buf->start,
|
||||
cl->buf->pos,
|
||||
cl->buf->last,
|
||||
cl->buf->file,
|
||||
cl->buf->file_pos,
|
||||
cl->buf->file_last);
|
||||
|
||||
ngx_debug_point();
|
||||
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
size += ngx_buf_size(cl->buf);
|
||||
}
|
||||
|
||||
if (size == 0 && !c->buffered) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
chain = c->send_chain(c, ctx->out, ctx->limit);
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0,
|
||||
"chain writer out: %p", chain);
|
||||
|
||||
if (chain == NGX_CHAIN_ERROR) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (chain && c->write->ready) {
|
||||
ngx_post_event(c->write, &ngx_posted_next_events);
|
||||
}
|
||||
|
||||
for (cl = ctx->out; cl && cl != chain; /* void */) {
|
||||
ln = cl;
|
||||
cl = cl->next;
|
||||
ngx_free_chain(ctx->pool, ln);
|
||||
}
|
||||
|
||||
ctx->out = chain;
|
||||
|
||||
if (ctx->out == NULL) {
|
||||
ctx->last = &ctx->out;
|
||||
|
||||
if (!c->buffered) {
|
||||
return NGX_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return NGX_AGAIN;
|
||||
}
|
||||
430
nginx/src/core/ngx_palloc.c
Normal file
430
nginx/src/core/ngx_palloc.c
Normal file
|
|
@ -0,0 +1,430 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
static ngx_inline void *ngx_palloc_small(ngx_pool_t *pool, size_t size,
|
||||
ngx_uint_t align);
|
||||
static void *ngx_palloc_block(ngx_pool_t *pool, size_t size);
|
||||
static void *ngx_palloc_large(ngx_pool_t *pool, size_t size);
|
||||
|
||||
|
||||
ngx_pool_t *
|
||||
ngx_create_pool(size_t size, ngx_log_t *log)
|
||||
{
|
||||
ngx_pool_t *p;
|
||||
|
||||
p = ngx_memalign(NGX_POOL_ALIGNMENT, size, log);
|
||||
if (p == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p->d.last = (u_char *) p + sizeof(ngx_pool_t);
|
||||
p->d.end = (u_char *) p + size;
|
||||
p->d.next = NULL;
|
||||
p->d.failed = 0;
|
||||
|
||||
size = size - sizeof(ngx_pool_t);
|
||||
p->max = (size < NGX_MAX_ALLOC_FROM_POOL) ? size : NGX_MAX_ALLOC_FROM_POOL;
|
||||
|
||||
p->current = p;
|
||||
p->chain = NULL;
|
||||
p->large = NULL;
|
||||
p->cleanup = NULL;
|
||||
p->log = log;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_destroy_pool(ngx_pool_t *pool)
|
||||
{
|
||||
ngx_pool_t *p, *n;
|
||||
ngx_pool_large_t *l;
|
||||
ngx_pool_cleanup_t *c;
|
||||
|
||||
for (c = pool->cleanup; c; c = c->next) {
|
||||
if (c->handler) {
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0,
|
||||
"run cleanup: %p", c);
|
||||
c->handler(c->data);
|
||||
}
|
||||
}
|
||||
|
||||
#if (NGX_DEBUG)
|
||||
|
||||
/*
|
||||
* we could allocate the pool->log from this pool
|
||||
* so we cannot use this log while free()ing the pool
|
||||
*/
|
||||
|
||||
for (l = pool->large; l; l = l->next) {
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0, "free: %p", l->alloc);
|
||||
}
|
||||
|
||||
for (p = pool, n = pool->d.next; /* void */; p = n, n = n->d.next) {
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, pool->log, 0,
|
||||
"free: %p, unused: %uz", p, p->d.end - p->d.last);
|
||||
|
||||
if (n == NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
for (l = pool->large; l; l = l->next) {
|
||||
if (l->alloc) {
|
||||
ngx_free(l->alloc);
|
||||
}
|
||||
}
|
||||
|
||||
for (p = pool, n = pool->d.next; /* void */; p = n, n = n->d.next) {
|
||||
ngx_free(p);
|
||||
|
||||
if (n == NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_reset_pool(ngx_pool_t *pool)
|
||||
{
|
||||
ngx_pool_t *p;
|
||||
ngx_pool_large_t *l;
|
||||
|
||||
for (l = pool->large; l; l = l->next) {
|
||||
if (l->alloc) {
|
||||
ngx_free(l->alloc);
|
||||
}
|
||||
}
|
||||
|
||||
for (p = pool; p; p = p->d.next) {
|
||||
p->d.last = (u_char *) p + sizeof(ngx_pool_t);
|
||||
p->d.failed = 0;
|
||||
}
|
||||
|
||||
pool->current = pool;
|
||||
pool->chain = NULL;
|
||||
pool->large = NULL;
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
ngx_palloc(ngx_pool_t *pool, size_t size)
|
||||
{
|
||||
#if !(NGX_DEBUG_PALLOC)
|
||||
if (size <= pool->max) {
|
||||
return ngx_palloc_small(pool, size, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
return ngx_palloc_large(pool, size);
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
ngx_pnalloc(ngx_pool_t *pool, size_t size)
|
||||
{
|
||||
#if !(NGX_DEBUG_PALLOC)
|
||||
if (size <= pool->max) {
|
||||
return ngx_palloc_small(pool, size, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
return ngx_palloc_large(pool, size);
|
||||
}
|
||||
|
||||
|
||||
static ngx_inline void *
|
||||
ngx_palloc_small(ngx_pool_t *pool, size_t size, ngx_uint_t align)
|
||||
{
|
||||
u_char *m;
|
||||
ngx_pool_t *p;
|
||||
|
||||
p = pool->current;
|
||||
|
||||
do {
|
||||
m = p->d.last;
|
||||
|
||||
if (align) {
|
||||
m = ngx_align_ptr(m, NGX_ALIGNMENT);
|
||||
}
|
||||
|
||||
if ((size_t) (p->d.end - m) >= size) {
|
||||
p->d.last = m + size;
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
p = p->d.next;
|
||||
|
||||
} while (p);
|
||||
|
||||
return ngx_palloc_block(pool, size);
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
ngx_palloc_block(ngx_pool_t *pool, size_t size)
|
||||
{
|
||||
u_char *m;
|
||||
size_t psize;
|
||||
ngx_pool_t *p, *new;
|
||||
|
||||
psize = (size_t) (pool->d.end - (u_char *) pool);
|
||||
|
||||
m = ngx_memalign(NGX_POOL_ALIGNMENT, psize, pool->log);
|
||||
if (m == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
new = (ngx_pool_t *) m;
|
||||
|
||||
new->d.end = m + psize;
|
||||
new->d.next = NULL;
|
||||
new->d.failed = 0;
|
||||
|
||||
m += sizeof(ngx_pool_data_t);
|
||||
m = ngx_align_ptr(m, NGX_ALIGNMENT);
|
||||
new->d.last = m + size;
|
||||
|
||||
for (p = pool->current; p->d.next; p = p->d.next) {
|
||||
if (p->d.failed++ > 4) {
|
||||
pool->current = p->d.next;
|
||||
}
|
||||
}
|
||||
|
||||
p->d.next = new;
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
ngx_palloc_large(ngx_pool_t *pool, size_t size)
|
||||
{
|
||||
void *p;
|
||||
ngx_uint_t n;
|
||||
ngx_pool_large_t *large;
|
||||
|
||||
p = ngx_alloc(size, pool->log);
|
||||
if (p == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
n = 0;
|
||||
|
||||
for (large = pool->large; large; large = large->next) {
|
||||
if (large->alloc == NULL) {
|
||||
large->alloc = p;
|
||||
return p;
|
||||
}
|
||||
|
||||
if (n++ > 3) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
large = ngx_palloc_small(pool, sizeof(ngx_pool_large_t), 1);
|
||||
if (large == NULL) {
|
||||
ngx_free(p);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
large->alloc = p;
|
||||
large->next = pool->large;
|
||||
pool->large = large;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
ngx_pmemalign(ngx_pool_t *pool, size_t size, size_t alignment)
|
||||
{
|
||||
void *p;
|
||||
ngx_pool_large_t *large;
|
||||
|
||||
p = ngx_memalign(alignment, size, pool->log);
|
||||
if (p == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
large = ngx_palloc_small(pool, sizeof(ngx_pool_large_t), 1);
|
||||
if (large == NULL) {
|
||||
ngx_free(p);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
large->alloc = p;
|
||||
large->next = pool->large;
|
||||
pool->large = large;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_pfree(ngx_pool_t *pool, void *p)
|
||||
{
|
||||
ngx_pool_large_t *l;
|
||||
|
||||
for (l = pool->large; l; l = l->next) {
|
||||
if (p == l->alloc) {
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0,
|
||||
"free: %p", l->alloc);
|
||||
ngx_free(l->alloc);
|
||||
l->alloc = NULL;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
ngx_pcalloc(ngx_pool_t *pool, size_t size)
|
||||
{
|
||||
void *p;
|
||||
|
||||
p = ngx_palloc(pool, size);
|
||||
if (p) {
|
||||
ngx_memzero(p, size);
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
ngx_pool_cleanup_t *
|
||||
ngx_pool_cleanup_add(ngx_pool_t *p, size_t size)
|
||||
{
|
||||
ngx_pool_cleanup_t *c;
|
||||
|
||||
c = ngx_palloc(p, sizeof(ngx_pool_cleanup_t));
|
||||
if (c == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (size) {
|
||||
c->data = ngx_palloc(p, size);
|
||||
if (c->data == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
} else {
|
||||
c->data = NULL;
|
||||
}
|
||||
|
||||
c->handler = NULL;
|
||||
c->next = p->cleanup;
|
||||
|
||||
p->cleanup = c;
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, p->log, 0, "add cleanup: %p", c);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_pool_run_cleanup_file(ngx_pool_t *p, ngx_fd_t fd)
|
||||
{
|
||||
ngx_pool_cleanup_t *c;
|
||||
ngx_pool_cleanup_file_t *cf;
|
||||
|
||||
for (c = p->cleanup; c; c = c->next) {
|
||||
if (c->handler == ngx_pool_cleanup_file) {
|
||||
|
||||
cf = c->data;
|
||||
|
||||
if (cf->fd == fd) {
|
||||
c->handler(cf);
|
||||
c->handler = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_pool_cleanup_file(void *data)
|
||||
{
|
||||
ngx_pool_cleanup_file_t *c = data;
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, c->log, 0, "file cleanup: fd:%d",
|
||||
c->fd);
|
||||
|
||||
if (ngx_close_file(c->fd) == NGX_FILE_ERROR) {
|
||||
ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
|
||||
ngx_close_file_n " \"%s\" failed", c->name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_pool_delete_file(void *data)
|
||||
{
|
||||
ngx_pool_cleanup_file_t *c = data;
|
||||
|
||||
ngx_err_t err;
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, c->log, 0, "file cleanup: fd:%d %s",
|
||||
c->fd, c->name);
|
||||
|
||||
if (ngx_delete_file(c->name) == NGX_FILE_ERROR) {
|
||||
err = ngx_errno;
|
||||
|
||||
if (err != NGX_ENOENT) {
|
||||
ngx_log_error(NGX_LOG_CRIT, c->log, err,
|
||||
ngx_delete_file_n " \"%s\" failed", c->name);
|
||||
}
|
||||
}
|
||||
|
||||
if (ngx_close_file(c->fd) == NGX_FILE_ERROR) {
|
||||
ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
|
||||
ngx_close_file_n " \"%s\" failed", c->name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
|
||||
static void *
|
||||
ngx_get_cached_block(size_t size)
|
||||
{
|
||||
void *p;
|
||||
ngx_cached_block_slot_t *slot;
|
||||
|
||||
if (ngx_cycle->cache == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
slot = &ngx_cycle->cache[(size + ngx_pagesize - 1) / ngx_pagesize];
|
||||
|
||||
slot->tries++;
|
||||
|
||||
if (slot->number) {
|
||||
p = slot->block;
|
||||
slot->block = slot->block->next;
|
||||
slot->number--;
|
||||
return p;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
92
nginx/src/core/ngx_palloc.h
Normal file
92
nginx/src/core/ngx_palloc.h
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_PALLOC_H_INCLUDED_
|
||||
#define _NGX_PALLOC_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
/*
|
||||
* NGX_MAX_ALLOC_FROM_POOL should be (ngx_pagesize - 1), i.e. 4095 on x86.
|
||||
* On Windows NT it decreases a number of locked pages in a kernel.
|
||||
*/
|
||||
#define NGX_MAX_ALLOC_FROM_POOL (ngx_pagesize - 1)
|
||||
|
||||
#define NGX_DEFAULT_POOL_SIZE (16 * 1024)
|
||||
|
||||
#define NGX_POOL_ALIGNMENT 16
|
||||
#define NGX_MIN_POOL_SIZE \
|
||||
ngx_align((sizeof(ngx_pool_t) + 2 * sizeof(ngx_pool_large_t)), \
|
||||
NGX_POOL_ALIGNMENT)
|
||||
|
||||
|
||||
typedef void (*ngx_pool_cleanup_pt)(void *data);
|
||||
|
||||
typedef struct ngx_pool_cleanup_s ngx_pool_cleanup_t;
|
||||
|
||||
struct ngx_pool_cleanup_s {
|
||||
ngx_pool_cleanup_pt handler;
|
||||
void *data;
|
||||
ngx_pool_cleanup_t *next;
|
||||
};
|
||||
|
||||
|
||||
typedef struct ngx_pool_large_s ngx_pool_large_t;
|
||||
|
||||
struct ngx_pool_large_s {
|
||||
ngx_pool_large_t *next;
|
||||
void *alloc;
|
||||
};
|
||||
|
||||
|
||||
typedef struct {
|
||||
u_char *last;
|
||||
u_char *end;
|
||||
ngx_pool_t *next;
|
||||
ngx_uint_t failed;
|
||||
} ngx_pool_data_t;
|
||||
|
||||
|
||||
struct ngx_pool_s {
|
||||
ngx_pool_data_t d;
|
||||
size_t max;
|
||||
ngx_pool_t *current;
|
||||
ngx_chain_t *chain;
|
||||
ngx_pool_large_t *large;
|
||||
ngx_pool_cleanup_t *cleanup;
|
||||
ngx_log_t *log;
|
||||
};
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_fd_t fd;
|
||||
u_char *name;
|
||||
ngx_log_t *log;
|
||||
} ngx_pool_cleanup_file_t;
|
||||
|
||||
|
||||
ngx_pool_t *ngx_create_pool(size_t size, ngx_log_t *log);
|
||||
void ngx_destroy_pool(ngx_pool_t *pool);
|
||||
void ngx_reset_pool(ngx_pool_t *pool);
|
||||
|
||||
void *ngx_palloc(ngx_pool_t *pool, size_t size);
|
||||
void *ngx_pnalloc(ngx_pool_t *pool, size_t size);
|
||||
void *ngx_pcalloc(ngx_pool_t *pool, size_t size);
|
||||
void *ngx_pmemalign(ngx_pool_t *pool, size_t size, size_t alignment);
|
||||
ngx_int_t ngx_pfree(ngx_pool_t *pool, void *p);
|
||||
|
||||
|
||||
ngx_pool_cleanup_t *ngx_pool_cleanup_add(ngx_pool_t *p, size_t size);
|
||||
void ngx_pool_run_cleanup_file(ngx_pool_t *p, ngx_fd_t fd);
|
||||
void ngx_pool_cleanup_file(void *data);
|
||||
void ngx_pool_delete_file(void *data);
|
||||
|
||||
|
||||
#endif /* _NGX_PALLOC_H_INCLUDED_ */
|
||||
283
nginx/src/core/ngx_parse.c
Normal file
283
nginx/src/core/ngx_parse.c
Normal file
|
|
@ -0,0 +1,283 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
ssize_t
|
||||
ngx_parse_size(ngx_str_t *line)
|
||||
{
|
||||
u_char unit;
|
||||
size_t len;
|
||||
ssize_t size, scale, max;
|
||||
|
||||
len = line->len;
|
||||
|
||||
if (len == 0) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
unit = line->data[len - 1];
|
||||
|
||||
switch (unit) {
|
||||
case 'K':
|
||||
case 'k':
|
||||
len--;
|
||||
max = NGX_MAX_SIZE_T_VALUE / 1024;
|
||||
scale = 1024;
|
||||
break;
|
||||
|
||||
case 'M':
|
||||
case 'm':
|
||||
len--;
|
||||
max = NGX_MAX_SIZE_T_VALUE / (1024 * 1024);
|
||||
scale = 1024 * 1024;
|
||||
break;
|
||||
|
||||
default:
|
||||
max = NGX_MAX_SIZE_T_VALUE;
|
||||
scale = 1;
|
||||
}
|
||||
|
||||
size = ngx_atosz(line->data, len);
|
||||
if (size == NGX_ERROR || size > max) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
size *= scale;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
off_t
|
||||
ngx_parse_offset(ngx_str_t *line)
|
||||
{
|
||||
u_char unit;
|
||||
off_t offset, scale, max;
|
||||
size_t len;
|
||||
|
||||
len = line->len;
|
||||
|
||||
if (len == 0) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
unit = line->data[len - 1];
|
||||
|
||||
switch (unit) {
|
||||
case 'K':
|
||||
case 'k':
|
||||
len--;
|
||||
max = NGX_MAX_OFF_T_VALUE / 1024;
|
||||
scale = 1024;
|
||||
break;
|
||||
|
||||
case 'M':
|
||||
case 'm':
|
||||
len--;
|
||||
max = NGX_MAX_OFF_T_VALUE / (1024 * 1024);
|
||||
scale = 1024 * 1024;
|
||||
break;
|
||||
|
||||
case 'G':
|
||||
case 'g':
|
||||
len--;
|
||||
max = NGX_MAX_OFF_T_VALUE / (1024 * 1024 * 1024);
|
||||
scale = 1024 * 1024 * 1024;
|
||||
break;
|
||||
|
||||
default:
|
||||
max = NGX_MAX_OFF_T_VALUE;
|
||||
scale = 1;
|
||||
}
|
||||
|
||||
offset = ngx_atoof(line->data, len);
|
||||
if (offset == NGX_ERROR || offset > max) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
offset *= scale;
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_parse_time(ngx_str_t *line, ngx_uint_t is_sec)
|
||||
{
|
||||
u_char *p, *last;
|
||||
ngx_int_t value, total, scale;
|
||||
ngx_int_t max, cutoff, cutlim;
|
||||
ngx_uint_t valid;
|
||||
enum {
|
||||
st_start = 0,
|
||||
st_year,
|
||||
st_month,
|
||||
st_week,
|
||||
st_day,
|
||||
st_hour,
|
||||
st_min,
|
||||
st_sec,
|
||||
st_msec,
|
||||
st_last
|
||||
} step;
|
||||
|
||||
valid = 0;
|
||||
value = 0;
|
||||
total = 0;
|
||||
cutoff = NGX_MAX_INT_T_VALUE / 10;
|
||||
cutlim = NGX_MAX_INT_T_VALUE % 10;
|
||||
step = is_sec ? st_start : st_month;
|
||||
|
||||
p = line->data;
|
||||
last = p + line->len;
|
||||
|
||||
while (p < last) {
|
||||
|
||||
if (*p >= '0' && *p <= '9') {
|
||||
if (value >= cutoff && (value > cutoff || *p - '0' > cutlim)) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
value = value * 10 + (*p++ - '0');
|
||||
valid = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (*p++) {
|
||||
|
||||
case 'y':
|
||||
if (step > st_start) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
step = st_year;
|
||||
max = NGX_MAX_INT_T_VALUE / (60 * 60 * 24 * 365);
|
||||
scale = 60 * 60 * 24 * 365;
|
||||
break;
|
||||
|
||||
case 'M':
|
||||
if (step >= st_month) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
step = st_month;
|
||||
max = NGX_MAX_INT_T_VALUE / (60 * 60 * 24 * 30);
|
||||
scale = 60 * 60 * 24 * 30;
|
||||
break;
|
||||
|
||||
case 'w':
|
||||
if (step >= st_week) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
step = st_week;
|
||||
max = NGX_MAX_INT_T_VALUE / (60 * 60 * 24 * 7);
|
||||
scale = 60 * 60 * 24 * 7;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
if (step >= st_day) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
step = st_day;
|
||||
max = NGX_MAX_INT_T_VALUE / (60 * 60 * 24);
|
||||
scale = 60 * 60 * 24;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
if (step >= st_hour) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
step = st_hour;
|
||||
max = NGX_MAX_INT_T_VALUE / (60 * 60);
|
||||
scale = 60 * 60;
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
if (p < last && *p == 's') {
|
||||
if (is_sec || step >= st_msec) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
p++;
|
||||
step = st_msec;
|
||||
max = NGX_MAX_INT_T_VALUE;
|
||||
scale = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (step >= st_min) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
step = st_min;
|
||||
max = NGX_MAX_INT_T_VALUE / 60;
|
||||
scale = 60;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
if (step >= st_sec) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
step = st_sec;
|
||||
max = NGX_MAX_INT_T_VALUE;
|
||||
scale = 1;
|
||||
break;
|
||||
|
||||
case ' ':
|
||||
if (step >= st_sec) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
step = st_last;
|
||||
max = NGX_MAX_INT_T_VALUE;
|
||||
scale = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (step != st_msec && !is_sec) {
|
||||
scale *= 1000;
|
||||
max /= 1000;
|
||||
}
|
||||
|
||||
if (value > max) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
value *= scale;
|
||||
|
||||
if (total > NGX_MAX_INT_T_VALUE - value) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
total += value;
|
||||
|
||||
value = 0;
|
||||
|
||||
while (p < last && *p == ' ') {
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!valid) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (!is_sec) {
|
||||
if (value > NGX_MAX_INT_T_VALUE / 1000) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
value *= 1000;
|
||||
}
|
||||
|
||||
if (total > NGX_MAX_INT_T_VALUE - value) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
return total + value;
|
||||
}
|
||||
21
nginx/src/core/ngx_parse.h
Normal file
21
nginx/src/core/ngx_parse.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_PARSE_H_INCLUDED_
|
||||
#define _NGX_PARSE_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
ssize_t ngx_parse_size(ngx_str_t *line);
|
||||
off_t ngx_parse_offset(ngx_str_t *line);
|
||||
ngx_int_t ngx_parse_time(ngx_str_t *line, ngx_uint_t is_sec);
|
||||
|
||||
|
||||
#endif /* _NGX_PARSE_H_INCLUDED_ */
|
||||
277
nginx/src/core/ngx_parse_time.c
Normal file
277
nginx/src/core/ngx_parse_time.c
Normal file
|
|
@ -0,0 +1,277 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
static ngx_uint_t mday[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
||||
|
||||
time_t
|
||||
ngx_parse_http_time(u_char *value, size_t len)
|
||||
{
|
||||
u_char *p, *end;
|
||||
ngx_int_t month;
|
||||
ngx_uint_t day, year, hour, min, sec;
|
||||
uint64_t time;
|
||||
enum {
|
||||
no = 0,
|
||||
rfc822, /* Tue, 10 Nov 2002 23:50:13 */
|
||||
rfc850, /* Tuesday, 10-Dec-02 23:50:13 */
|
||||
isoc /* Tue Dec 10 23:50:13 2002 */
|
||||
} fmt;
|
||||
|
||||
fmt = 0;
|
||||
end = value + len;
|
||||
|
||||
#if (NGX_SUPPRESS_WARN)
|
||||
day = 32;
|
||||
year = 2038;
|
||||
#endif
|
||||
|
||||
for (p = value; p < end; p++) {
|
||||
if (*p == ',') {
|
||||
break;
|
||||
}
|
||||
|
||||
if (*p == ' ') {
|
||||
fmt = isoc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (p++; p < end; p++) {
|
||||
if (*p != ' ') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (end - p < 18) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (fmt != isoc) {
|
||||
if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9') {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
day = (*p - '0') * 10 + (*(p + 1) - '0');
|
||||
p += 2;
|
||||
|
||||
if (*p == ' ') {
|
||||
if (end - p < 18) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
fmt = rfc822;
|
||||
|
||||
} else if (*p == '-') {
|
||||
fmt = rfc850;
|
||||
|
||||
} else {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
p++;
|
||||
}
|
||||
|
||||
switch (*p) {
|
||||
|
||||
case 'J':
|
||||
month = *(p + 1) == 'a' ? 0 : *(p + 2) == 'n' ? 5 : 6;
|
||||
break;
|
||||
|
||||
case 'F':
|
||||
month = 1;
|
||||
break;
|
||||
|
||||
case 'M':
|
||||
month = *(p + 2) == 'r' ? 2 : 4;
|
||||
break;
|
||||
|
||||
case 'A':
|
||||
month = *(p + 1) == 'p' ? 3 : 7;
|
||||
break;
|
||||
|
||||
case 'S':
|
||||
month = 8;
|
||||
break;
|
||||
|
||||
case 'O':
|
||||
month = 9;
|
||||
break;
|
||||
|
||||
case 'N':
|
||||
month = 10;
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
month = 11;
|
||||
break;
|
||||
|
||||
default:
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
p += 3;
|
||||
|
||||
if ((fmt == rfc822 && *p != ' ') || (fmt == rfc850 && *p != '-')) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
p++;
|
||||
|
||||
if (fmt == rfc822) {
|
||||
if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9'
|
||||
|| *(p + 2) < '0' || *(p + 2) > '9'
|
||||
|| *(p + 3) < '0' || *(p + 3) > '9')
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
year = (*p - '0') * 1000 + (*(p + 1) - '0') * 100
|
||||
+ (*(p + 2) - '0') * 10 + (*(p + 3) - '0');
|
||||
p += 4;
|
||||
|
||||
} else if (fmt == rfc850) {
|
||||
if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9') {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
year = (*p - '0') * 10 + (*(p + 1) - '0');
|
||||
year += (year < 70) ? 2000 : 1900;
|
||||
p += 2;
|
||||
}
|
||||
|
||||
if (fmt == isoc) {
|
||||
if (*p == ' ') {
|
||||
p++;
|
||||
}
|
||||
|
||||
if (*p < '0' || *p > '9') {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
day = *p++ - '0';
|
||||
|
||||
if (*p != ' ') {
|
||||
if (*p < '0' || *p > '9') {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
day = day * 10 + (*p++ - '0');
|
||||
}
|
||||
|
||||
if (end - p < 14) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (*p++ != ' ') {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9') {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
hour = (*p - '0') * 10 + (*(p + 1) - '0');
|
||||
p += 2;
|
||||
|
||||
if (*p++ != ':') {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9') {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
min = (*p - '0') * 10 + (*(p + 1) - '0');
|
||||
p += 2;
|
||||
|
||||
if (*p++ != ':') {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9') {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
sec = (*p - '0') * 10 + (*(p + 1) - '0');
|
||||
|
||||
if (fmt == isoc) {
|
||||
p += 2;
|
||||
|
||||
if (*p++ != ' ') {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9'
|
||||
|| *(p + 2) < '0' || *(p + 2) > '9'
|
||||
|| *(p + 3) < '0' || *(p + 3) > '9')
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
year = (*p - '0') * 1000 + (*(p + 1) - '0') * 100
|
||||
+ (*(p + 2) - '0') * 10 + (*(p + 3) - '0');
|
||||
}
|
||||
|
||||
if (hour > 23 || min > 59 || sec > 59) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (day == 29 && month == 1) {
|
||||
if ((year & 3) || ((year % 100 == 0) && (year % 400) != 0)) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
} else if (day > mday[month]) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* shift new year to March 1 and start months from 1 (not 0),
|
||||
* it is needed for Gauss' formula
|
||||
*/
|
||||
|
||||
if (--month <= 0) {
|
||||
month += 12;
|
||||
year -= 1;
|
||||
}
|
||||
|
||||
/* Gauss' formula for Gregorian days since March 1, 1 BC */
|
||||
|
||||
time = (uint64_t) (
|
||||
/* days in years including leap years since March 1, 1 BC */
|
||||
|
||||
365 * year + year / 4 - year / 100 + year / 400
|
||||
|
||||
/* days before the month */
|
||||
|
||||
+ 367 * month / 12 - 30
|
||||
|
||||
/* days before the day */
|
||||
|
||||
+ day - 1
|
||||
|
||||
/*
|
||||
* 719527 days were between March 1, 1 BC and March 1, 1970,
|
||||
* 31 and 28 days were in January and February 1970
|
||||
*/
|
||||
|
||||
- 719527 + 31 + 28) * 86400 + hour * 3600 + min * 60 + sec;
|
||||
|
||||
#if (NGX_TIME_T_SIZE <= 4)
|
||||
|
||||
if (time > 0x7fffffff) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return (time_t) time;
|
||||
}
|
||||
22
nginx/src/core/ngx_parse_time.h
Normal file
22
nginx/src/core/ngx_parse_time.h
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_PARSE_TIME_H_INCLUDED_
|
||||
#define _NGX_PARSE_TIME_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
time_t ngx_parse_http_time(u_char *value, size_t len);
|
||||
|
||||
/* compatibility */
|
||||
#define ngx_http_parse_time(value, len) ngx_parse_http_time(value, len)
|
||||
|
||||
|
||||
#endif /* _NGX_PARSE_TIME_H_INCLUDED_ */
|
||||
614
nginx/src/core/ngx_proxy_protocol.c
Normal file
614
nginx/src/core/ngx_proxy_protocol.c
Normal file
|
|
@ -0,0 +1,614 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Roman Arutyunyan
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
#define NGX_PROXY_PROTOCOL_AF_INET 1
|
||||
#define NGX_PROXY_PROTOCOL_AF_INET6 2
|
||||
|
||||
|
||||
#define ngx_proxy_protocol_parse_uint16(p) \
|
||||
( ((uint16_t) (p)[0] << 8) \
|
||||
+ ( (p)[1]) )
|
||||
|
||||
#define ngx_proxy_protocol_parse_uint32(p) \
|
||||
( ((uint32_t) (p)[0] << 24) \
|
||||
+ ( (p)[1] << 16) \
|
||||
+ ( (p)[2] << 8) \
|
||||
+ ( (p)[3]) )
|
||||
|
||||
|
||||
typedef struct {
|
||||
u_char signature[12];
|
||||
u_char version_command;
|
||||
u_char family_transport;
|
||||
u_char len[2];
|
||||
} ngx_proxy_protocol_header_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
u_char src_addr[4];
|
||||
u_char dst_addr[4];
|
||||
u_char src_port[2];
|
||||
u_char dst_port[2];
|
||||
} ngx_proxy_protocol_inet_addrs_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
u_char src_addr[16];
|
||||
u_char dst_addr[16];
|
||||
u_char src_port[2];
|
||||
u_char dst_port[2];
|
||||
} ngx_proxy_protocol_inet6_addrs_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
u_char type;
|
||||
u_char len[2];
|
||||
} ngx_proxy_protocol_tlv_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
u_char client;
|
||||
u_char verify[4];
|
||||
} ngx_proxy_protocol_tlv_ssl_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_str_t name;
|
||||
ngx_uint_t type;
|
||||
} ngx_proxy_protocol_tlv_entry_t;
|
||||
|
||||
|
||||
static u_char *ngx_proxy_protocol_read_addr(ngx_connection_t *c, u_char *p,
|
||||
u_char *last, ngx_str_t *addr);
|
||||
static u_char *ngx_proxy_protocol_read_port(u_char *p, u_char *last,
|
||||
in_port_t *port, u_char sep);
|
||||
static u_char *ngx_proxy_protocol_v2_read(ngx_connection_t *c, u_char *buf,
|
||||
u_char *last);
|
||||
static ngx_int_t ngx_proxy_protocol_lookup_tlv(ngx_connection_t *c,
|
||||
ngx_str_t *tlvs, ngx_uint_t type, ngx_str_t *value);
|
||||
|
||||
|
||||
static ngx_proxy_protocol_tlv_entry_t ngx_proxy_protocol_tlv_entries[] = {
|
||||
{ ngx_string("alpn"), 0x01 },
|
||||
{ ngx_string("authority"), 0x02 },
|
||||
{ ngx_string("unique_id"), 0x05 },
|
||||
{ ngx_string("ssl"), 0x20 },
|
||||
{ ngx_string("netns"), 0x30 },
|
||||
{ ngx_null_string, 0x00 }
|
||||
};
|
||||
|
||||
|
||||
static ngx_proxy_protocol_tlv_entry_t ngx_proxy_protocol_tlv_ssl_entries[] = {
|
||||
{ ngx_string("version"), 0x21 },
|
||||
{ ngx_string("cn"), 0x22 },
|
||||
{ ngx_string("cipher"), 0x23 },
|
||||
{ ngx_string("sig_alg"), 0x24 },
|
||||
{ ngx_string("key_alg"), 0x25 },
|
||||
{ ngx_null_string, 0x00 }
|
||||
};
|
||||
|
||||
|
||||
u_char *
|
||||
ngx_proxy_protocol_read(ngx_connection_t *c, u_char *buf, u_char *last)
|
||||
{
|
||||
size_t len;
|
||||
u_char *p;
|
||||
ngx_proxy_protocol_t *pp;
|
||||
|
||||
static const u_char signature[] = "\r\n\r\n\0\r\nQUIT\n";
|
||||
|
||||
p = buf;
|
||||
len = last - buf;
|
||||
|
||||
if (len >= sizeof(ngx_proxy_protocol_header_t)
|
||||
&& ngx_memcmp(p, signature, sizeof(signature) - 1) == 0)
|
||||
{
|
||||
return ngx_proxy_protocol_v2_read(c, buf, last);
|
||||
}
|
||||
|
||||
if (len < 8 || ngx_strncmp(p, "PROXY ", 6) != 0) {
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
p += 6;
|
||||
len -= 6;
|
||||
|
||||
if (len >= 7 && ngx_strncmp(p, "UNKNOWN", 7) == 0) {
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_CORE, c->log, 0,
|
||||
"PROXY protocol unknown protocol");
|
||||
p += 7;
|
||||
goto skip;
|
||||
}
|
||||
|
||||
if (len < 5 || ngx_strncmp(p, "TCP", 3) != 0
|
||||
|| (p[3] != '4' && p[3] != '6') || p[4] != ' ')
|
||||
{
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
p += 5;
|
||||
|
||||
pp = ngx_pcalloc(c->pool, sizeof(ngx_proxy_protocol_t));
|
||||
if (pp == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p = ngx_proxy_protocol_read_addr(c, p, last, &pp->src_addr);
|
||||
if (p == NULL) {
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
p = ngx_proxy_protocol_read_addr(c, p, last, &pp->dst_addr);
|
||||
if (p == NULL) {
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
p = ngx_proxy_protocol_read_port(p, last, &pp->src_port, ' ');
|
||||
if (p == NULL) {
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
p = ngx_proxy_protocol_read_port(p, last, &pp->dst_port, CR);
|
||||
if (p == NULL) {
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
if (p == last) {
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
if (*p++ != LF) {
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
ngx_log_debug4(NGX_LOG_DEBUG_CORE, c->log, 0,
|
||||
"PROXY protocol src: %V %d, dst: %V %d",
|
||||
&pp->src_addr, pp->src_port, &pp->dst_addr, pp->dst_port);
|
||||
|
||||
c->proxy_protocol = pp;
|
||||
|
||||
return p;
|
||||
|
||||
skip:
|
||||
|
||||
for ( /* void */ ; p < last - 1; p++) {
|
||||
if (p[0] == CR && p[1] == LF) {
|
||||
return p + 2;
|
||||
}
|
||||
}
|
||||
|
||||
invalid:
|
||||
|
||||
for (p = buf; p < last; p++) {
|
||||
if (*p == CR || *p == LF) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ngx_log_error(NGX_LOG_ERR, c->log, 0,
|
||||
"broken header: \"%*s\"", (size_t) (p - buf), buf);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static u_char *
|
||||
ngx_proxy_protocol_read_addr(ngx_connection_t *c, u_char *p, u_char *last,
|
||||
ngx_str_t *addr)
|
||||
{
|
||||
size_t len;
|
||||
u_char ch, *pos;
|
||||
|
||||
pos = p;
|
||||
|
||||
for ( ;; ) {
|
||||
if (p == last) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ch = *p++;
|
||||
|
||||
if (ch == ' ') {
|
||||
break;
|
||||
}
|
||||
|
||||
if (ch != ':' && ch != '.'
|
||||
&& (ch < 'a' || ch > 'f')
|
||||
&& (ch < 'A' || ch > 'F')
|
||||
&& (ch < '0' || ch > '9'))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
len = p - pos - 1;
|
||||
|
||||
addr->data = ngx_pnalloc(c->pool, len);
|
||||
if (addr->data == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ngx_memcpy(addr->data, pos, len);
|
||||
addr->len = len;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
static u_char *
|
||||
ngx_proxy_protocol_read_port(u_char *p, u_char *last, in_port_t *port,
|
||||
u_char sep)
|
||||
{
|
||||
size_t len;
|
||||
u_char *pos;
|
||||
ngx_int_t n;
|
||||
|
||||
pos = p;
|
||||
|
||||
for ( ;; ) {
|
||||
if (p == last) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (*p++ == sep) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
len = p - pos - 1;
|
||||
|
||||
n = ngx_atoi(pos, len);
|
||||
if (n < 0 || n > 65535) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*port = (in_port_t) n;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
u_char *
|
||||
ngx_proxy_protocol_write(ngx_connection_t *c, u_char *buf, u_char *last)
|
||||
{
|
||||
ngx_uint_t port, lport;
|
||||
|
||||
if (last - buf < NGX_PROXY_PROTOCOL_V1_MAX_HEADER) {
|
||||
ngx_log_error(NGX_LOG_ALERT, c->log, 0,
|
||||
"too small buffer for PROXY protocol");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ngx_connection_local_sockaddr(c, NULL, 0) != NGX_OK) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (c->sockaddr->sa_family) {
|
||||
|
||||
case AF_INET:
|
||||
buf = ngx_cpymem(buf, "PROXY TCP4 ", sizeof("PROXY TCP4 ") - 1);
|
||||
break;
|
||||
|
||||
#if (NGX_HAVE_INET6)
|
||||
case AF_INET6:
|
||||
buf = ngx_cpymem(buf, "PROXY TCP6 ", sizeof("PROXY TCP6 ") - 1);
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
return ngx_cpymem(buf, "PROXY UNKNOWN" CRLF,
|
||||
sizeof("PROXY UNKNOWN" CRLF) - 1);
|
||||
}
|
||||
|
||||
buf += ngx_sock_ntop(c->sockaddr, c->socklen, buf, last - buf, 0);
|
||||
|
||||
*buf++ = ' ';
|
||||
|
||||
buf += ngx_sock_ntop(c->local_sockaddr, c->local_socklen, buf, last - buf,
|
||||
0);
|
||||
|
||||
port = ngx_inet_get_port(c->sockaddr);
|
||||
lport = ngx_inet_get_port(c->local_sockaddr);
|
||||
|
||||
return ngx_slprintf(buf, last, " %ui %ui" CRLF, port, lport);
|
||||
}
|
||||
|
||||
|
||||
static u_char *
|
||||
ngx_proxy_protocol_v2_read(ngx_connection_t *c, u_char *buf, u_char *last)
|
||||
{
|
||||
u_char *end;
|
||||
size_t len;
|
||||
socklen_t socklen;
|
||||
ngx_uint_t version, command, family, transport;
|
||||
ngx_sockaddr_t src_sockaddr, dst_sockaddr;
|
||||
ngx_proxy_protocol_t *pp;
|
||||
ngx_proxy_protocol_header_t *header;
|
||||
ngx_proxy_protocol_inet_addrs_t *in;
|
||||
#if (NGX_HAVE_INET6)
|
||||
ngx_proxy_protocol_inet6_addrs_t *in6;
|
||||
#endif
|
||||
|
||||
header = (ngx_proxy_protocol_header_t *) buf;
|
||||
|
||||
buf += sizeof(ngx_proxy_protocol_header_t);
|
||||
|
||||
version = header->version_command >> 4;
|
||||
|
||||
if (version != 2) {
|
||||
ngx_log_error(NGX_LOG_ERR, c->log, 0,
|
||||
"unknown PROXY protocol version: %ui", version);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
len = ngx_proxy_protocol_parse_uint16(header->len);
|
||||
|
||||
if ((size_t) (last - buf) < len) {
|
||||
ngx_log_error(NGX_LOG_ERR, c->log, 0, "header is too large");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
end = buf + len;
|
||||
|
||||
command = header->version_command & 0x0f;
|
||||
|
||||
/* only PROXY is supported */
|
||||
if (command != 1) {
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0,
|
||||
"PROXY protocol v2 unsupported command %ui", command);
|
||||
return end;
|
||||
}
|
||||
|
||||
transport = header->family_transport & 0x0f;
|
||||
|
||||
/* only STREAM is supported */
|
||||
if (transport != 1) {
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0,
|
||||
"PROXY protocol v2 unsupported transport %ui",
|
||||
transport);
|
||||
return end;
|
||||
}
|
||||
|
||||
pp = ngx_pcalloc(c->pool, sizeof(ngx_proxy_protocol_t));
|
||||
if (pp == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
family = header->family_transport >> 4;
|
||||
|
||||
switch (family) {
|
||||
|
||||
case NGX_PROXY_PROTOCOL_AF_INET:
|
||||
|
||||
if ((size_t) (end - buf) < sizeof(ngx_proxy_protocol_inet_addrs_t)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
in = (ngx_proxy_protocol_inet_addrs_t *) buf;
|
||||
|
||||
src_sockaddr.sockaddr_in.sin_family = AF_INET;
|
||||
src_sockaddr.sockaddr_in.sin_port = 0;
|
||||
ngx_memcpy(&src_sockaddr.sockaddr_in.sin_addr, in->src_addr, 4);
|
||||
|
||||
dst_sockaddr.sockaddr_in.sin_family = AF_INET;
|
||||
dst_sockaddr.sockaddr_in.sin_port = 0;
|
||||
ngx_memcpy(&dst_sockaddr.sockaddr_in.sin_addr, in->dst_addr, 4);
|
||||
|
||||
pp->src_port = ngx_proxy_protocol_parse_uint16(in->src_port);
|
||||
pp->dst_port = ngx_proxy_protocol_parse_uint16(in->dst_port);
|
||||
|
||||
socklen = sizeof(struct sockaddr_in);
|
||||
|
||||
buf += sizeof(ngx_proxy_protocol_inet_addrs_t);
|
||||
|
||||
break;
|
||||
|
||||
#if (NGX_HAVE_INET6)
|
||||
|
||||
case NGX_PROXY_PROTOCOL_AF_INET6:
|
||||
|
||||
if ((size_t) (end - buf) < sizeof(ngx_proxy_protocol_inet6_addrs_t)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
in6 = (ngx_proxy_protocol_inet6_addrs_t *) buf;
|
||||
|
||||
src_sockaddr.sockaddr_in6.sin6_family = AF_INET6;
|
||||
src_sockaddr.sockaddr_in6.sin6_port = 0;
|
||||
ngx_memcpy(&src_sockaddr.sockaddr_in6.sin6_addr, in6->src_addr, 16);
|
||||
|
||||
dst_sockaddr.sockaddr_in6.sin6_family = AF_INET6;
|
||||
dst_sockaddr.sockaddr_in6.sin6_port = 0;
|
||||
ngx_memcpy(&dst_sockaddr.sockaddr_in6.sin6_addr, in6->dst_addr, 16);
|
||||
|
||||
pp->src_port = ngx_proxy_protocol_parse_uint16(in6->src_port);
|
||||
pp->dst_port = ngx_proxy_protocol_parse_uint16(in6->dst_port);
|
||||
|
||||
socklen = sizeof(struct sockaddr_in6);
|
||||
|
||||
buf += sizeof(ngx_proxy_protocol_inet6_addrs_t);
|
||||
|
||||
break;
|
||||
|
||||
#endif
|
||||
|
||||
default:
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0,
|
||||
"PROXY protocol v2 unsupported address family %ui",
|
||||
family);
|
||||
return end;
|
||||
}
|
||||
|
||||
pp->src_addr.data = ngx_pnalloc(c->pool, NGX_SOCKADDR_STRLEN);
|
||||
if (pp->src_addr.data == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pp->src_addr.len = ngx_sock_ntop(&src_sockaddr.sockaddr, socklen,
|
||||
pp->src_addr.data, NGX_SOCKADDR_STRLEN, 0);
|
||||
|
||||
pp->dst_addr.data = ngx_pnalloc(c->pool, NGX_SOCKADDR_STRLEN);
|
||||
if (pp->dst_addr.data == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pp->dst_addr.len = ngx_sock_ntop(&dst_sockaddr.sockaddr, socklen,
|
||||
pp->dst_addr.data, NGX_SOCKADDR_STRLEN, 0);
|
||||
|
||||
ngx_log_debug4(NGX_LOG_DEBUG_CORE, c->log, 0,
|
||||
"PROXY protocol v2 src: %V %d, dst: %V %d",
|
||||
&pp->src_addr, pp->src_port, &pp->dst_addr, pp->dst_port);
|
||||
|
||||
if (buf < end) {
|
||||
pp->tlvs.data = ngx_pnalloc(c->pool, end - buf);
|
||||
if (pp->tlvs.data == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ngx_memcpy(pp->tlvs.data, buf, end - buf);
|
||||
pp->tlvs.len = end - buf;
|
||||
}
|
||||
|
||||
c->proxy_protocol = pp;
|
||||
|
||||
return end;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_proxy_protocol_get_tlv(ngx_connection_t *c, ngx_str_t *name,
|
||||
ngx_str_t *value)
|
||||
{
|
||||
u_char *p;
|
||||
size_t n;
|
||||
uint32_t verify;
|
||||
ngx_str_t ssl, *tlvs;
|
||||
ngx_int_t rc, type;
|
||||
ngx_proxy_protocol_tlv_ssl_t *tlv_ssl;
|
||||
ngx_proxy_protocol_tlv_entry_t *te;
|
||||
|
||||
if (c->proxy_protocol == NULL) {
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0,
|
||||
"PROXY protocol v2 get tlv \"%V\"", name);
|
||||
|
||||
te = ngx_proxy_protocol_tlv_entries;
|
||||
tlvs = &c->proxy_protocol->tlvs;
|
||||
|
||||
p = name->data;
|
||||
n = name->len;
|
||||
|
||||
if (n >= 4 && p[0] == 's' && p[1] == 's' && p[2] == 'l' && p[3] == '_') {
|
||||
|
||||
rc = ngx_proxy_protocol_lookup_tlv(c, tlvs, 0x20, &ssl);
|
||||
if (rc != NGX_OK) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (ssl.len < sizeof(ngx_proxy_protocol_tlv_ssl_t)) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
p += 4;
|
||||
n -= 4;
|
||||
|
||||
if (n == 6 && ngx_strncmp(p, "verify", 6) == 0) {
|
||||
|
||||
tlv_ssl = (ngx_proxy_protocol_tlv_ssl_t *) ssl.data;
|
||||
verify = ngx_proxy_protocol_parse_uint32(tlv_ssl->verify);
|
||||
|
||||
value->data = ngx_pnalloc(c->pool, NGX_INT32_LEN);
|
||||
if (value->data == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
value->len = ngx_sprintf(value->data, "%uD", verify)
|
||||
- value->data;
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
ssl.data += sizeof(ngx_proxy_protocol_tlv_ssl_t);
|
||||
ssl.len -= sizeof(ngx_proxy_protocol_tlv_ssl_t);
|
||||
|
||||
te = ngx_proxy_protocol_tlv_ssl_entries;
|
||||
tlvs = &ssl;
|
||||
}
|
||||
|
||||
if (n >= 2 && p[0] == '0' && p[1] == 'x') {
|
||||
|
||||
type = ngx_hextoi(p + 2, n - 2);
|
||||
if (type == NGX_ERROR) {
|
||||
ngx_log_error(NGX_LOG_ERR, c->log, 0,
|
||||
"invalid PROXY protocol TLV \"%V\"", name);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
return ngx_proxy_protocol_lookup_tlv(c, tlvs, type, value);
|
||||
}
|
||||
|
||||
for ( /* void */ ; te->type; te++) {
|
||||
if (te->name.len == n && ngx_strncmp(te->name.data, p, n) == 0) {
|
||||
return ngx_proxy_protocol_lookup_tlv(c, tlvs, te->type, value);
|
||||
}
|
||||
}
|
||||
|
||||
ngx_log_error(NGX_LOG_ERR, c->log, 0,
|
||||
"unknown PROXY protocol TLV \"%V\"", name);
|
||||
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_proxy_protocol_lookup_tlv(ngx_connection_t *c, ngx_str_t *tlvs,
|
||||
ngx_uint_t type, ngx_str_t *value)
|
||||
{
|
||||
u_char *p;
|
||||
size_t n, len;
|
||||
ngx_proxy_protocol_tlv_t *tlv;
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0,
|
||||
"PROXY protocol v2 lookup tlv:%02xi", type);
|
||||
|
||||
p = tlvs->data;
|
||||
n = tlvs->len;
|
||||
|
||||
while (n) {
|
||||
if (n < sizeof(ngx_proxy_protocol_tlv_t)) {
|
||||
ngx_log_error(NGX_LOG_ERR, c->log, 0, "broken PROXY protocol TLV");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
tlv = (ngx_proxy_protocol_tlv_t *) p;
|
||||
len = ngx_proxy_protocol_parse_uint16(tlv->len);
|
||||
|
||||
p += sizeof(ngx_proxy_protocol_tlv_t);
|
||||
n -= sizeof(ngx_proxy_protocol_tlv_t);
|
||||
|
||||
if (n < len) {
|
||||
ngx_log_error(NGX_LOG_ERR, c->log, 0, "broken PROXY protocol TLV");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (tlv->type == type) {
|
||||
value->data = p;
|
||||
value->len = len;
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
p += len;
|
||||
n -= len;
|
||||
}
|
||||
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
37
nginx/src/core/ngx_proxy_protocol.h
Normal file
37
nginx/src/core/ngx_proxy_protocol.h
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Roman Arutyunyan
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_PROXY_PROTOCOL_H_INCLUDED_
|
||||
#define _NGX_PROXY_PROTOCOL_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
#define NGX_PROXY_PROTOCOL_V1_MAX_HEADER 107
|
||||
#define NGX_PROXY_PROTOCOL_MAX_HEADER 4096
|
||||
|
||||
|
||||
struct ngx_proxy_protocol_s {
|
||||
ngx_str_t src_addr;
|
||||
ngx_str_t dst_addr;
|
||||
in_port_t src_port;
|
||||
in_port_t dst_port;
|
||||
ngx_str_t tlvs;
|
||||
};
|
||||
|
||||
|
||||
u_char *ngx_proxy_protocol_read(ngx_connection_t *c, u_char *buf,
|
||||
u_char *last);
|
||||
u_char *ngx_proxy_protocol_write(ngx_connection_t *c, u_char *buf,
|
||||
u_char *last);
|
||||
ngx_int_t ngx_proxy_protocol_get_tlv(ngx_connection_t *c, ngx_str_t *name,
|
||||
ngx_str_t *value);
|
||||
|
||||
|
||||
#endif /* _NGX_PROXY_PROTOCOL_H_INCLUDED_ */
|
||||
106
nginx/src/core/ngx_queue.c
Normal file
106
nginx/src/core/ngx_queue.c
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
static void ngx_queue_merge(ngx_queue_t *queue, ngx_queue_t *tail,
|
||||
ngx_int_t (*cmp)(const ngx_queue_t *, const ngx_queue_t *));
|
||||
|
||||
|
||||
/*
|
||||
* find the middle queue element if the queue has odd number of elements
|
||||
* or the first element of the queue's second part otherwise
|
||||
*/
|
||||
|
||||
ngx_queue_t *
|
||||
ngx_queue_middle(ngx_queue_t *queue)
|
||||
{
|
||||
ngx_queue_t *middle, *next;
|
||||
|
||||
middle = ngx_queue_head(queue);
|
||||
|
||||
if (middle == ngx_queue_last(queue)) {
|
||||
return middle;
|
||||
}
|
||||
|
||||
next = ngx_queue_head(queue);
|
||||
|
||||
for ( ;; ) {
|
||||
middle = ngx_queue_next(middle);
|
||||
|
||||
next = ngx_queue_next(next);
|
||||
|
||||
if (next == ngx_queue_last(queue)) {
|
||||
return middle;
|
||||
}
|
||||
|
||||
next = ngx_queue_next(next);
|
||||
|
||||
if (next == ngx_queue_last(queue)) {
|
||||
return middle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* the stable merge sort */
|
||||
|
||||
void
|
||||
ngx_queue_sort(ngx_queue_t *queue,
|
||||
ngx_int_t (*cmp)(const ngx_queue_t *, const ngx_queue_t *))
|
||||
{
|
||||
ngx_queue_t *q, tail;
|
||||
|
||||
q = ngx_queue_head(queue);
|
||||
|
||||
if (q == ngx_queue_last(queue)) {
|
||||
return;
|
||||
}
|
||||
|
||||
q = ngx_queue_middle(queue);
|
||||
|
||||
ngx_queue_split(queue, q, &tail);
|
||||
|
||||
ngx_queue_sort(queue, cmp);
|
||||
ngx_queue_sort(&tail, cmp);
|
||||
|
||||
ngx_queue_merge(queue, &tail, cmp);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_queue_merge(ngx_queue_t *queue, ngx_queue_t *tail,
|
||||
ngx_int_t (*cmp)(const ngx_queue_t *, const ngx_queue_t *))
|
||||
{
|
||||
ngx_queue_t *q1, *q2;
|
||||
|
||||
q1 = ngx_queue_head(queue);
|
||||
q2 = ngx_queue_head(tail);
|
||||
|
||||
for ( ;; ) {
|
||||
if (q1 == ngx_queue_sentinel(queue)) {
|
||||
ngx_queue_add(queue, tail);
|
||||
break;
|
||||
}
|
||||
|
||||
if (q2 == ngx_queue_sentinel(tail)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (cmp(q1, q2) <= 0) {
|
||||
q1 = ngx_queue_next(q1);
|
||||
continue;
|
||||
}
|
||||
|
||||
ngx_queue_remove(q2);
|
||||
ngx_queue_insert_before(q1, q2);
|
||||
|
||||
q2 = ngx_queue_head(tail);
|
||||
}
|
||||
}
|
||||
115
nginx/src/core/ngx_queue.h
Normal file
115
nginx/src/core/ngx_queue.h
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
#ifndef _NGX_QUEUE_H_INCLUDED_
|
||||
#define _NGX_QUEUE_H_INCLUDED_
|
||||
|
||||
|
||||
typedef struct ngx_queue_s ngx_queue_t;
|
||||
|
||||
struct ngx_queue_s {
|
||||
ngx_queue_t *prev;
|
||||
ngx_queue_t *next;
|
||||
};
|
||||
|
||||
|
||||
#define ngx_queue_init(q) \
|
||||
(q)->prev = q; \
|
||||
(q)->next = q
|
||||
|
||||
|
||||
#define ngx_queue_empty(h) \
|
||||
(h == (h)->prev)
|
||||
|
||||
|
||||
#define ngx_queue_insert_head(h, x) \
|
||||
(x)->next = (h)->next; \
|
||||
(x)->next->prev = x; \
|
||||
(x)->prev = h; \
|
||||
(h)->next = x
|
||||
|
||||
|
||||
#define ngx_queue_insert_after ngx_queue_insert_head
|
||||
|
||||
|
||||
#define ngx_queue_insert_tail(h, x) \
|
||||
(x)->prev = (h)->prev; \
|
||||
(x)->prev->next = x; \
|
||||
(x)->next = h; \
|
||||
(h)->prev = x
|
||||
|
||||
|
||||
#define ngx_queue_insert_before ngx_queue_insert_tail
|
||||
|
||||
|
||||
#define ngx_queue_head(h) \
|
||||
(h)->next
|
||||
|
||||
|
||||
#define ngx_queue_last(h) \
|
||||
(h)->prev
|
||||
|
||||
|
||||
#define ngx_queue_sentinel(h) \
|
||||
(h)
|
||||
|
||||
|
||||
#define ngx_queue_next(q) \
|
||||
(q)->next
|
||||
|
||||
|
||||
#define ngx_queue_prev(q) \
|
||||
(q)->prev
|
||||
|
||||
|
||||
#if (NGX_DEBUG)
|
||||
|
||||
#define ngx_queue_remove(x) \
|
||||
(x)->next->prev = (x)->prev; \
|
||||
(x)->prev->next = (x)->next; \
|
||||
(x)->prev = NULL; \
|
||||
(x)->next = NULL
|
||||
|
||||
#else
|
||||
|
||||
#define ngx_queue_remove(x) \
|
||||
(x)->next->prev = (x)->prev; \
|
||||
(x)->prev->next = (x)->next
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#define ngx_queue_split(h, q, n) \
|
||||
(n)->prev = (h)->prev; \
|
||||
(n)->prev->next = n; \
|
||||
(n)->next = q; \
|
||||
(h)->prev = (q)->prev; \
|
||||
(h)->prev->next = h; \
|
||||
(q)->prev = n;
|
||||
|
||||
|
||||
#define ngx_queue_add(h, n) \
|
||||
(h)->prev->next = (n)->next; \
|
||||
(n)->next->prev = (h)->prev; \
|
||||
(h)->prev = (n)->prev; \
|
||||
(h)->prev->next = h;
|
||||
|
||||
|
||||
#define ngx_queue_data(q, type, link) \
|
||||
(type *) ((u_char *) q - offsetof(type, link))
|
||||
|
||||
|
||||
ngx_queue_t *ngx_queue_middle(ngx_queue_t *queue);
|
||||
void ngx_queue_sort(ngx_queue_t *queue,
|
||||
ngx_int_t (*cmp)(const ngx_queue_t *, const ngx_queue_t *));
|
||||
|
||||
|
||||
#endif /* _NGX_QUEUE_H_INCLUDED_ */
|
||||
488
nginx/src/core/ngx_radix_tree.c
Normal file
488
nginx/src/core/ngx_radix_tree.c
Normal file
|
|
@ -0,0 +1,488 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
static ngx_radix_node_t *ngx_radix_alloc(ngx_radix_tree_t *tree);
|
||||
|
||||
|
||||
ngx_radix_tree_t *
|
||||
ngx_radix_tree_create(ngx_pool_t *pool, ngx_int_t preallocate)
|
||||
{
|
||||
uint32_t key, mask, inc;
|
||||
ngx_radix_tree_t *tree;
|
||||
|
||||
tree = ngx_palloc(pool, sizeof(ngx_radix_tree_t));
|
||||
if (tree == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tree->pool = pool;
|
||||
tree->free = NULL;
|
||||
tree->start = NULL;
|
||||
tree->size = 0;
|
||||
|
||||
tree->root = ngx_radix_alloc(tree);
|
||||
if (tree->root == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tree->root->right = NULL;
|
||||
tree->root->left = NULL;
|
||||
tree->root->parent = NULL;
|
||||
tree->root->value = NGX_RADIX_NO_VALUE;
|
||||
|
||||
if (preallocate == 0) {
|
||||
return tree;
|
||||
}
|
||||
|
||||
/*
|
||||
* Preallocation of first nodes : 0, 1, 00, 01, 10, 11, 000, 001, etc.
|
||||
* increases TLB hits even if for first lookup iterations.
|
||||
* On 32-bit platforms the 7 preallocated bits takes continuous 4K,
|
||||
* 8 - 8K, 9 - 16K, etc. On 64-bit platforms the 6 preallocated bits
|
||||
* takes continuous 4K, 7 - 8K, 8 - 16K, etc. There is no sense to
|
||||
* to preallocate more than one page, because further preallocation
|
||||
* distributes the only bit per page. Instead, a random insertion
|
||||
* may distribute several bits per page.
|
||||
*
|
||||
* Thus, by default we preallocate maximum
|
||||
* 6 bits on amd64 (64-bit platform and 4K pages)
|
||||
* 7 bits on i386 (32-bit platform and 4K pages)
|
||||
* 7 bits on sparc64 in 64-bit mode (8K pages)
|
||||
* 8 bits on sparc64 in 32-bit mode (8K pages)
|
||||
*/
|
||||
|
||||
if (preallocate == -1) {
|
||||
switch (ngx_pagesize / sizeof(ngx_radix_node_t)) {
|
||||
|
||||
/* amd64 */
|
||||
case 128:
|
||||
preallocate = 6;
|
||||
break;
|
||||
|
||||
/* i386, sparc64 */
|
||||
case 256:
|
||||
preallocate = 7;
|
||||
break;
|
||||
|
||||
/* sparc64 in 32-bit mode */
|
||||
default:
|
||||
preallocate = 8;
|
||||
}
|
||||
}
|
||||
|
||||
mask = 0;
|
||||
inc = 0x80000000;
|
||||
|
||||
while (preallocate--) {
|
||||
|
||||
key = 0;
|
||||
mask >>= 1;
|
||||
mask |= 0x80000000;
|
||||
|
||||
do {
|
||||
if (ngx_radix32tree_insert(tree, key, mask, NGX_RADIX_NO_VALUE)
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
key += inc;
|
||||
|
||||
} while (key);
|
||||
|
||||
inc >>= 1;
|
||||
}
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_radix32tree_insert(ngx_radix_tree_t *tree, uint32_t key, uint32_t mask,
|
||||
uintptr_t value)
|
||||
{
|
||||
uint32_t bit;
|
||||
ngx_radix_node_t *node, *next;
|
||||
|
||||
bit = 0x80000000;
|
||||
|
||||
node = tree->root;
|
||||
next = tree->root;
|
||||
|
||||
while (bit & mask) {
|
||||
if (key & bit) {
|
||||
next = node->right;
|
||||
|
||||
} else {
|
||||
next = node->left;
|
||||
}
|
||||
|
||||
if (next == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
bit >>= 1;
|
||||
node = next;
|
||||
}
|
||||
|
||||
if (next) {
|
||||
if (node->value != NGX_RADIX_NO_VALUE) {
|
||||
return NGX_BUSY;
|
||||
}
|
||||
|
||||
node->value = value;
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
while (bit & mask) {
|
||||
next = ngx_radix_alloc(tree);
|
||||
if (next == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
next->right = NULL;
|
||||
next->left = NULL;
|
||||
next->parent = node;
|
||||
next->value = NGX_RADIX_NO_VALUE;
|
||||
|
||||
if (key & bit) {
|
||||
node->right = next;
|
||||
|
||||
} else {
|
||||
node->left = next;
|
||||
}
|
||||
|
||||
bit >>= 1;
|
||||
node = next;
|
||||
}
|
||||
|
||||
node->value = value;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_radix32tree_delete(ngx_radix_tree_t *tree, uint32_t key, uint32_t mask)
|
||||
{
|
||||
uint32_t bit;
|
||||
ngx_radix_node_t *node;
|
||||
|
||||
bit = 0x80000000;
|
||||
node = tree->root;
|
||||
|
||||
while (node && (bit & mask)) {
|
||||
if (key & bit) {
|
||||
node = node->right;
|
||||
|
||||
} else {
|
||||
node = node->left;
|
||||
}
|
||||
|
||||
bit >>= 1;
|
||||
}
|
||||
|
||||
if (node == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (node->right || node->left) {
|
||||
if (node->value != NGX_RADIX_NO_VALUE) {
|
||||
node->value = NGX_RADIX_NO_VALUE;
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
for ( ;; ) {
|
||||
if (node->parent->right == node) {
|
||||
node->parent->right = NULL;
|
||||
|
||||
} else {
|
||||
node->parent->left = NULL;
|
||||
}
|
||||
|
||||
node->right = tree->free;
|
||||
tree->free = node;
|
||||
|
||||
node = node->parent;
|
||||
|
||||
if (node->right || node->left) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (node->value != NGX_RADIX_NO_VALUE) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (node->parent == NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
uintptr_t
|
||||
ngx_radix32tree_find(ngx_radix_tree_t *tree, uint32_t key)
|
||||
{
|
||||
uint32_t bit;
|
||||
uintptr_t value;
|
||||
ngx_radix_node_t *node;
|
||||
|
||||
bit = 0x80000000;
|
||||
value = NGX_RADIX_NO_VALUE;
|
||||
node = tree->root;
|
||||
|
||||
while (node) {
|
||||
if (node->value != NGX_RADIX_NO_VALUE) {
|
||||
value = node->value;
|
||||
}
|
||||
|
||||
if (key & bit) {
|
||||
node = node->right;
|
||||
|
||||
} else {
|
||||
node = node->left;
|
||||
}
|
||||
|
||||
bit >>= 1;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
#if (NGX_HAVE_INET6)
|
||||
|
||||
ngx_int_t
|
||||
ngx_radix128tree_insert(ngx_radix_tree_t *tree, u_char *key, u_char *mask,
|
||||
uintptr_t value)
|
||||
{
|
||||
u_char bit;
|
||||
ngx_uint_t i;
|
||||
ngx_radix_node_t *node, *next;
|
||||
|
||||
i = 0;
|
||||
bit = 0x80;
|
||||
|
||||
node = tree->root;
|
||||
next = tree->root;
|
||||
|
||||
while (bit & mask[i]) {
|
||||
if (key[i] & bit) {
|
||||
next = node->right;
|
||||
|
||||
} else {
|
||||
next = node->left;
|
||||
}
|
||||
|
||||
if (next == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
bit >>= 1;
|
||||
node = next;
|
||||
|
||||
if (bit == 0) {
|
||||
if (++i == 16) {
|
||||
break;
|
||||
}
|
||||
|
||||
bit = 0x80;
|
||||
}
|
||||
}
|
||||
|
||||
if (next) {
|
||||
if (node->value != NGX_RADIX_NO_VALUE) {
|
||||
return NGX_BUSY;
|
||||
}
|
||||
|
||||
node->value = value;
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
while (bit & mask[i]) {
|
||||
next = ngx_radix_alloc(tree);
|
||||
if (next == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
next->right = NULL;
|
||||
next->left = NULL;
|
||||
next->parent = node;
|
||||
next->value = NGX_RADIX_NO_VALUE;
|
||||
|
||||
if (key[i] & bit) {
|
||||
node->right = next;
|
||||
|
||||
} else {
|
||||
node->left = next;
|
||||
}
|
||||
|
||||
bit >>= 1;
|
||||
node = next;
|
||||
|
||||
if (bit == 0) {
|
||||
if (++i == 16) {
|
||||
break;
|
||||
}
|
||||
|
||||
bit = 0x80;
|
||||
}
|
||||
}
|
||||
|
||||
node->value = value;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_radix128tree_delete(ngx_radix_tree_t *tree, u_char *key, u_char *mask)
|
||||
{
|
||||
u_char bit;
|
||||
ngx_uint_t i;
|
||||
ngx_radix_node_t *node;
|
||||
|
||||
i = 0;
|
||||
bit = 0x80;
|
||||
node = tree->root;
|
||||
|
||||
while (node && (bit & mask[i])) {
|
||||
if (key[i] & bit) {
|
||||
node = node->right;
|
||||
|
||||
} else {
|
||||
node = node->left;
|
||||
}
|
||||
|
||||
bit >>= 1;
|
||||
|
||||
if (bit == 0) {
|
||||
if (++i == 16) {
|
||||
break;
|
||||
}
|
||||
|
||||
bit = 0x80;
|
||||
}
|
||||
}
|
||||
|
||||
if (node == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (node->right || node->left) {
|
||||
if (node->value != NGX_RADIX_NO_VALUE) {
|
||||
node->value = NGX_RADIX_NO_VALUE;
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
for ( ;; ) {
|
||||
if (node->parent->right == node) {
|
||||
node->parent->right = NULL;
|
||||
|
||||
} else {
|
||||
node->parent->left = NULL;
|
||||
}
|
||||
|
||||
node->right = tree->free;
|
||||
tree->free = node;
|
||||
|
||||
node = node->parent;
|
||||
|
||||
if (node->right || node->left) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (node->value != NGX_RADIX_NO_VALUE) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (node->parent == NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
uintptr_t
|
||||
ngx_radix128tree_find(ngx_radix_tree_t *tree, u_char *key)
|
||||
{
|
||||
u_char bit;
|
||||
uintptr_t value;
|
||||
ngx_uint_t i;
|
||||
ngx_radix_node_t *node;
|
||||
|
||||
i = 0;
|
||||
bit = 0x80;
|
||||
value = NGX_RADIX_NO_VALUE;
|
||||
node = tree->root;
|
||||
|
||||
while (node) {
|
||||
if (node->value != NGX_RADIX_NO_VALUE) {
|
||||
value = node->value;
|
||||
}
|
||||
|
||||
if (key[i] & bit) {
|
||||
node = node->right;
|
||||
|
||||
} else {
|
||||
node = node->left;
|
||||
}
|
||||
|
||||
bit >>= 1;
|
||||
|
||||
if (bit == 0) {
|
||||
i++;
|
||||
bit = 0x80;
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
static ngx_radix_node_t *
|
||||
ngx_radix_alloc(ngx_radix_tree_t *tree)
|
||||
{
|
||||
ngx_radix_node_t *p;
|
||||
|
||||
if (tree->free) {
|
||||
p = tree->free;
|
||||
tree->free = tree->free->right;
|
||||
return p;
|
||||
}
|
||||
|
||||
if (tree->size < sizeof(ngx_radix_node_t)) {
|
||||
tree->start = ngx_pmemalign(tree->pool, ngx_pagesize, ngx_pagesize);
|
||||
if (tree->start == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tree->size = ngx_pagesize;
|
||||
}
|
||||
|
||||
p = (ngx_radix_node_t *) tree->start;
|
||||
tree->start += sizeof(ngx_radix_node_t);
|
||||
tree->size -= sizeof(ngx_radix_node_t);
|
||||
|
||||
return p;
|
||||
}
|
||||
55
nginx/src/core/ngx_radix_tree.h
Normal file
55
nginx/src/core/ngx_radix_tree.h
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_RADIX_TREE_H_INCLUDED_
|
||||
#define _NGX_RADIX_TREE_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
#define NGX_RADIX_NO_VALUE (uintptr_t) -1
|
||||
|
||||
typedef struct ngx_radix_node_s ngx_radix_node_t;
|
||||
|
||||
struct ngx_radix_node_s {
|
||||
ngx_radix_node_t *right;
|
||||
ngx_radix_node_t *left;
|
||||
ngx_radix_node_t *parent;
|
||||
uintptr_t value;
|
||||
};
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_radix_node_t *root;
|
||||
ngx_pool_t *pool;
|
||||
ngx_radix_node_t *free;
|
||||
char *start;
|
||||
size_t size;
|
||||
} ngx_radix_tree_t;
|
||||
|
||||
|
||||
ngx_radix_tree_t *ngx_radix_tree_create(ngx_pool_t *pool,
|
||||
ngx_int_t preallocate);
|
||||
|
||||
ngx_int_t ngx_radix32tree_insert(ngx_radix_tree_t *tree,
|
||||
uint32_t key, uint32_t mask, uintptr_t value);
|
||||
ngx_int_t ngx_radix32tree_delete(ngx_radix_tree_t *tree,
|
||||
uint32_t key, uint32_t mask);
|
||||
uintptr_t ngx_radix32tree_find(ngx_radix_tree_t *tree, uint32_t key);
|
||||
|
||||
#if (NGX_HAVE_INET6)
|
||||
ngx_int_t ngx_radix128tree_insert(ngx_radix_tree_t *tree,
|
||||
u_char *key, u_char *mask, uintptr_t value);
|
||||
ngx_int_t ngx_radix128tree_delete(ngx_radix_tree_t *tree,
|
||||
u_char *key, u_char *mask);
|
||||
uintptr_t ngx_radix128tree_find(ngx_radix_tree_t *tree, u_char *key);
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* _NGX_RADIX_TREE_H_INCLUDED_ */
|
||||
404
nginx/src/core/ngx_rbtree.c
Normal file
404
nginx/src/core/ngx_rbtree.c
Normal file
|
|
@ -0,0 +1,404 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
/*
|
||||
* The red-black tree code is based on the algorithm described in
|
||||
* the "Introduction to Algorithms" by Cormen, Leiserson and Rivest.
|
||||
*/
|
||||
|
||||
|
||||
static ngx_inline void ngx_rbtree_left_rotate(ngx_rbtree_node_t **root,
|
||||
ngx_rbtree_node_t *sentinel, ngx_rbtree_node_t *node);
|
||||
static ngx_inline void ngx_rbtree_right_rotate(ngx_rbtree_node_t **root,
|
||||
ngx_rbtree_node_t *sentinel, ngx_rbtree_node_t *node);
|
||||
|
||||
|
||||
void
|
||||
ngx_rbtree_insert(ngx_rbtree_t *tree, ngx_rbtree_node_t *node)
|
||||
{
|
||||
ngx_rbtree_node_t **root, *temp, *sentinel;
|
||||
|
||||
/* a binary tree insert */
|
||||
|
||||
root = &tree->root;
|
||||
sentinel = tree->sentinel;
|
||||
|
||||
if (*root == sentinel) {
|
||||
node->parent = NULL;
|
||||
node->left = sentinel;
|
||||
node->right = sentinel;
|
||||
ngx_rbt_black(node);
|
||||
*root = node;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
tree->insert(*root, node, sentinel);
|
||||
|
||||
/* re-balance tree */
|
||||
|
||||
while (node != *root && ngx_rbt_is_red(node->parent)) {
|
||||
|
||||
if (node->parent == node->parent->parent->left) {
|
||||
temp = node->parent->parent->right;
|
||||
|
||||
if (ngx_rbt_is_red(temp)) {
|
||||
ngx_rbt_black(node->parent);
|
||||
ngx_rbt_black(temp);
|
||||
ngx_rbt_red(node->parent->parent);
|
||||
node = node->parent->parent;
|
||||
|
||||
} else {
|
||||
if (node == node->parent->right) {
|
||||
node = node->parent;
|
||||
ngx_rbtree_left_rotate(root, sentinel, node);
|
||||
}
|
||||
|
||||
ngx_rbt_black(node->parent);
|
||||
ngx_rbt_red(node->parent->parent);
|
||||
ngx_rbtree_right_rotate(root, sentinel, node->parent->parent);
|
||||
}
|
||||
|
||||
} else {
|
||||
temp = node->parent->parent->left;
|
||||
|
||||
if (ngx_rbt_is_red(temp)) {
|
||||
ngx_rbt_black(node->parent);
|
||||
ngx_rbt_black(temp);
|
||||
ngx_rbt_red(node->parent->parent);
|
||||
node = node->parent->parent;
|
||||
|
||||
} else {
|
||||
if (node == node->parent->left) {
|
||||
node = node->parent;
|
||||
ngx_rbtree_right_rotate(root, sentinel, node);
|
||||
}
|
||||
|
||||
ngx_rbt_black(node->parent);
|
||||
ngx_rbt_red(node->parent->parent);
|
||||
ngx_rbtree_left_rotate(root, sentinel, node->parent->parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ngx_rbt_black(*root);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_rbtree_insert_value(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node,
|
||||
ngx_rbtree_node_t *sentinel)
|
||||
{
|
||||
ngx_rbtree_node_t **p;
|
||||
|
||||
for ( ;; ) {
|
||||
|
||||
p = (node->key < temp->key) ? &temp->left : &temp->right;
|
||||
|
||||
if (*p == sentinel) {
|
||||
break;
|
||||
}
|
||||
|
||||
temp = *p;
|
||||
}
|
||||
|
||||
*p = node;
|
||||
node->parent = temp;
|
||||
node->left = sentinel;
|
||||
node->right = sentinel;
|
||||
ngx_rbt_red(node);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_rbtree_insert_timer_value(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node,
|
||||
ngx_rbtree_node_t *sentinel)
|
||||
{
|
||||
ngx_rbtree_node_t **p;
|
||||
|
||||
for ( ;; ) {
|
||||
|
||||
/*
|
||||
* Timer values
|
||||
* 1) are spread in small range, usually several minutes,
|
||||
* 2) and overflow each 49 days, if milliseconds are stored in 32 bits.
|
||||
* The comparison takes into account that overflow.
|
||||
*/
|
||||
|
||||
/* node->key < temp->key */
|
||||
|
||||
p = ((ngx_rbtree_key_int_t) (node->key - temp->key) < 0)
|
||||
? &temp->left : &temp->right;
|
||||
|
||||
if (*p == sentinel) {
|
||||
break;
|
||||
}
|
||||
|
||||
temp = *p;
|
||||
}
|
||||
|
||||
*p = node;
|
||||
node->parent = temp;
|
||||
node->left = sentinel;
|
||||
node->right = sentinel;
|
||||
ngx_rbt_red(node);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_rbtree_delete(ngx_rbtree_t *tree, ngx_rbtree_node_t *node)
|
||||
{
|
||||
ngx_uint_t red;
|
||||
ngx_rbtree_node_t **root, *sentinel, *subst, *temp, *w;
|
||||
|
||||
/* a binary tree delete */
|
||||
|
||||
root = &tree->root;
|
||||
sentinel = tree->sentinel;
|
||||
|
||||
if (node->left == sentinel) {
|
||||
temp = node->right;
|
||||
subst = node;
|
||||
|
||||
} else if (node->right == sentinel) {
|
||||
temp = node->left;
|
||||
subst = node;
|
||||
|
||||
} else {
|
||||
subst = ngx_rbtree_min(node->right, sentinel);
|
||||
temp = subst->right;
|
||||
}
|
||||
|
||||
if (subst == *root) {
|
||||
*root = temp;
|
||||
ngx_rbt_black(temp);
|
||||
|
||||
/* DEBUG stuff */
|
||||
node->left = NULL;
|
||||
node->right = NULL;
|
||||
node->parent = NULL;
|
||||
node->key = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
red = ngx_rbt_is_red(subst);
|
||||
|
||||
if (subst == subst->parent->left) {
|
||||
subst->parent->left = temp;
|
||||
|
||||
} else {
|
||||
subst->parent->right = temp;
|
||||
}
|
||||
|
||||
if (subst == node) {
|
||||
|
||||
temp->parent = subst->parent;
|
||||
|
||||
} else {
|
||||
|
||||
if (subst->parent == node) {
|
||||
temp->parent = subst;
|
||||
|
||||
} else {
|
||||
temp->parent = subst->parent;
|
||||
}
|
||||
|
||||
subst->left = node->left;
|
||||
subst->right = node->right;
|
||||
subst->parent = node->parent;
|
||||
ngx_rbt_copy_color(subst, node);
|
||||
|
||||
if (node == *root) {
|
||||
*root = subst;
|
||||
|
||||
} else {
|
||||
if (node == node->parent->left) {
|
||||
node->parent->left = subst;
|
||||
} else {
|
||||
node->parent->right = subst;
|
||||
}
|
||||
}
|
||||
|
||||
if (subst->left != sentinel) {
|
||||
subst->left->parent = subst;
|
||||
}
|
||||
|
||||
if (subst->right != sentinel) {
|
||||
subst->right->parent = subst;
|
||||
}
|
||||
}
|
||||
|
||||
/* DEBUG stuff */
|
||||
node->left = NULL;
|
||||
node->right = NULL;
|
||||
node->parent = NULL;
|
||||
node->key = 0;
|
||||
|
||||
if (red) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* a delete fixup */
|
||||
|
||||
while (temp != *root && ngx_rbt_is_black(temp)) {
|
||||
|
||||
if (temp == temp->parent->left) {
|
||||
w = temp->parent->right;
|
||||
|
||||
if (ngx_rbt_is_red(w)) {
|
||||
ngx_rbt_black(w);
|
||||
ngx_rbt_red(temp->parent);
|
||||
ngx_rbtree_left_rotate(root, sentinel, temp->parent);
|
||||
w = temp->parent->right;
|
||||
}
|
||||
|
||||
if (ngx_rbt_is_black(w->left) && ngx_rbt_is_black(w->right)) {
|
||||
ngx_rbt_red(w);
|
||||
temp = temp->parent;
|
||||
|
||||
} else {
|
||||
if (ngx_rbt_is_black(w->right)) {
|
||||
ngx_rbt_black(w->left);
|
||||
ngx_rbt_red(w);
|
||||
ngx_rbtree_right_rotate(root, sentinel, w);
|
||||
w = temp->parent->right;
|
||||
}
|
||||
|
||||
ngx_rbt_copy_color(w, temp->parent);
|
||||
ngx_rbt_black(temp->parent);
|
||||
ngx_rbt_black(w->right);
|
||||
ngx_rbtree_left_rotate(root, sentinel, temp->parent);
|
||||
temp = *root;
|
||||
}
|
||||
|
||||
} else {
|
||||
w = temp->parent->left;
|
||||
|
||||
if (ngx_rbt_is_red(w)) {
|
||||
ngx_rbt_black(w);
|
||||
ngx_rbt_red(temp->parent);
|
||||
ngx_rbtree_right_rotate(root, sentinel, temp->parent);
|
||||
w = temp->parent->left;
|
||||
}
|
||||
|
||||
if (ngx_rbt_is_black(w->left) && ngx_rbt_is_black(w->right)) {
|
||||
ngx_rbt_red(w);
|
||||
temp = temp->parent;
|
||||
|
||||
} else {
|
||||
if (ngx_rbt_is_black(w->left)) {
|
||||
ngx_rbt_black(w->right);
|
||||
ngx_rbt_red(w);
|
||||
ngx_rbtree_left_rotate(root, sentinel, w);
|
||||
w = temp->parent->left;
|
||||
}
|
||||
|
||||
ngx_rbt_copy_color(w, temp->parent);
|
||||
ngx_rbt_black(temp->parent);
|
||||
ngx_rbt_black(w->left);
|
||||
ngx_rbtree_right_rotate(root, sentinel, temp->parent);
|
||||
temp = *root;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ngx_rbt_black(temp);
|
||||
}
|
||||
|
||||
|
||||
static ngx_inline void
|
||||
ngx_rbtree_left_rotate(ngx_rbtree_node_t **root, ngx_rbtree_node_t *sentinel,
|
||||
ngx_rbtree_node_t *node)
|
||||
{
|
||||
ngx_rbtree_node_t *temp;
|
||||
|
||||
temp = node->right;
|
||||
node->right = temp->left;
|
||||
|
||||
if (temp->left != sentinel) {
|
||||
temp->left->parent = node;
|
||||
}
|
||||
|
||||
temp->parent = node->parent;
|
||||
|
||||
if (node == *root) {
|
||||
*root = temp;
|
||||
|
||||
} else if (node == node->parent->left) {
|
||||
node->parent->left = temp;
|
||||
|
||||
} else {
|
||||
node->parent->right = temp;
|
||||
}
|
||||
|
||||
temp->left = node;
|
||||
node->parent = temp;
|
||||
}
|
||||
|
||||
|
||||
static ngx_inline void
|
||||
ngx_rbtree_right_rotate(ngx_rbtree_node_t **root, ngx_rbtree_node_t *sentinel,
|
||||
ngx_rbtree_node_t *node)
|
||||
{
|
||||
ngx_rbtree_node_t *temp;
|
||||
|
||||
temp = node->left;
|
||||
node->left = temp->right;
|
||||
|
||||
if (temp->right != sentinel) {
|
||||
temp->right->parent = node;
|
||||
}
|
||||
|
||||
temp->parent = node->parent;
|
||||
|
||||
if (node == *root) {
|
||||
*root = temp;
|
||||
|
||||
} else if (node == node->parent->right) {
|
||||
node->parent->right = temp;
|
||||
|
||||
} else {
|
||||
node->parent->left = temp;
|
||||
}
|
||||
|
||||
temp->right = node;
|
||||
node->parent = temp;
|
||||
}
|
||||
|
||||
|
||||
ngx_rbtree_node_t *
|
||||
ngx_rbtree_next(ngx_rbtree_t *tree, ngx_rbtree_node_t *node)
|
||||
{
|
||||
ngx_rbtree_node_t *root, *sentinel, *parent;
|
||||
|
||||
sentinel = tree->sentinel;
|
||||
|
||||
if (node->right != sentinel) {
|
||||
return ngx_rbtree_min(node->right, sentinel);
|
||||
}
|
||||
|
||||
root = tree->root;
|
||||
|
||||
for ( ;; ) {
|
||||
parent = node->parent;
|
||||
|
||||
if (node == root) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (node == parent->left) {
|
||||
return parent;
|
||||
}
|
||||
|
||||
node = parent;
|
||||
}
|
||||
}
|
||||
87
nginx/src/core/ngx_rbtree.h
Normal file
87
nginx/src/core/ngx_rbtree.h
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_RBTREE_H_INCLUDED_
|
||||
#define _NGX_RBTREE_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
typedef ngx_uint_t ngx_rbtree_key_t;
|
||||
typedef ngx_int_t ngx_rbtree_key_int_t;
|
||||
|
||||
|
||||
typedef struct ngx_rbtree_node_s ngx_rbtree_node_t;
|
||||
|
||||
struct ngx_rbtree_node_s {
|
||||
ngx_rbtree_key_t key;
|
||||
ngx_rbtree_node_t *left;
|
||||
ngx_rbtree_node_t *right;
|
||||
ngx_rbtree_node_t *parent;
|
||||
u_char color;
|
||||
u_char data;
|
||||
};
|
||||
|
||||
|
||||
typedef struct ngx_rbtree_s ngx_rbtree_t;
|
||||
|
||||
typedef void (*ngx_rbtree_insert_pt) (ngx_rbtree_node_t *root,
|
||||
ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
|
||||
|
||||
struct ngx_rbtree_s {
|
||||
ngx_rbtree_node_t *root;
|
||||
ngx_rbtree_node_t *sentinel;
|
||||
ngx_rbtree_insert_pt insert;
|
||||
};
|
||||
|
||||
|
||||
#define ngx_rbtree_init(tree, s, i) \
|
||||
ngx_rbtree_sentinel_init(s); \
|
||||
(tree)->root = s; \
|
||||
(tree)->sentinel = s; \
|
||||
(tree)->insert = i
|
||||
|
||||
#define ngx_rbtree_data(node, type, link) \
|
||||
(type *) ((u_char *) (node) - offsetof(type, link))
|
||||
|
||||
|
||||
void ngx_rbtree_insert(ngx_rbtree_t *tree, ngx_rbtree_node_t *node);
|
||||
void ngx_rbtree_delete(ngx_rbtree_t *tree, ngx_rbtree_node_t *node);
|
||||
void ngx_rbtree_insert_value(ngx_rbtree_node_t *root, ngx_rbtree_node_t *node,
|
||||
ngx_rbtree_node_t *sentinel);
|
||||
void ngx_rbtree_insert_timer_value(ngx_rbtree_node_t *root,
|
||||
ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
|
||||
ngx_rbtree_node_t *ngx_rbtree_next(ngx_rbtree_t *tree,
|
||||
ngx_rbtree_node_t *node);
|
||||
|
||||
|
||||
#define ngx_rbt_red(node) ((node)->color = 1)
|
||||
#define ngx_rbt_black(node) ((node)->color = 0)
|
||||
#define ngx_rbt_is_red(node) ((node)->color)
|
||||
#define ngx_rbt_is_black(node) (!ngx_rbt_is_red(node))
|
||||
#define ngx_rbt_copy_color(n1, n2) (n1->color = n2->color)
|
||||
|
||||
|
||||
/* a sentinel must be black */
|
||||
|
||||
#define ngx_rbtree_sentinel_init(node) ngx_rbt_black(node)
|
||||
|
||||
|
||||
static ngx_inline ngx_rbtree_node_t *
|
||||
ngx_rbtree_min(ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
|
||||
{
|
||||
while (node->left != sentinel) {
|
||||
node = node->left;
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
#endif /* _NGX_RBTREE_H_INCLUDED_ */
|
||||
804
nginx/src/core/ngx_regex.c
Normal file
804
nginx/src/core/ngx_regex.c
Normal file
|
|
@ -0,0 +1,804 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_flag_t pcre_jit;
|
||||
ngx_list_t *studies;
|
||||
} ngx_regex_conf_t;
|
||||
|
||||
|
||||
static ngx_inline void ngx_regex_malloc_init(ngx_pool_t *pool);
|
||||
static ngx_inline void ngx_regex_malloc_done(void);
|
||||
|
||||
#if (NGX_PCRE2)
|
||||
static void * ngx_libc_cdecl ngx_regex_malloc(size_t size, void *data);
|
||||
static void ngx_libc_cdecl ngx_regex_free(void *p, void *data);
|
||||
#else
|
||||
static void * ngx_libc_cdecl ngx_regex_malloc(size_t size);
|
||||
static void ngx_libc_cdecl ngx_regex_free(void *p);
|
||||
#endif
|
||||
static void ngx_regex_cleanup(void *data);
|
||||
|
||||
static ngx_int_t ngx_regex_module_init(ngx_cycle_t *cycle);
|
||||
|
||||
static void *ngx_regex_create_conf(ngx_cycle_t *cycle);
|
||||
static char *ngx_regex_init_conf(ngx_cycle_t *cycle, void *conf);
|
||||
|
||||
static char *ngx_regex_pcre_jit(ngx_conf_t *cf, void *post, void *data);
|
||||
static ngx_conf_post_t ngx_regex_pcre_jit_post = { ngx_regex_pcre_jit };
|
||||
|
||||
|
||||
static ngx_command_t ngx_regex_commands[] = {
|
||||
|
||||
{ ngx_string("pcre_jit"),
|
||||
NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_FLAG,
|
||||
ngx_conf_set_flag_slot,
|
||||
0,
|
||||
offsetof(ngx_regex_conf_t, pcre_jit),
|
||||
&ngx_regex_pcre_jit_post },
|
||||
|
||||
ngx_null_command
|
||||
};
|
||||
|
||||
|
||||
static ngx_core_module_t ngx_regex_module_ctx = {
|
||||
ngx_string("regex"),
|
||||
ngx_regex_create_conf,
|
||||
ngx_regex_init_conf
|
||||
};
|
||||
|
||||
|
||||
ngx_module_t ngx_regex_module = {
|
||||
NGX_MODULE_V1,
|
||||
&ngx_regex_module_ctx, /* module context */
|
||||
ngx_regex_commands, /* module directives */
|
||||
NGX_CORE_MODULE, /* module type */
|
||||
NULL, /* init master */
|
||||
ngx_regex_module_init, /* init module */
|
||||
NULL, /* init process */
|
||||
NULL, /* init thread */
|
||||
NULL, /* exit thread */
|
||||
NULL, /* exit process */
|
||||
NULL, /* exit master */
|
||||
NGX_MODULE_V1_PADDING
|
||||
};
|
||||
|
||||
|
||||
static ngx_pool_t *ngx_regex_pool;
|
||||
static ngx_list_t *ngx_regex_studies;
|
||||
static ngx_uint_t ngx_regex_direct_alloc;
|
||||
|
||||
#if (NGX_PCRE2)
|
||||
static pcre2_compile_context *ngx_regex_compile_context;
|
||||
static pcre2_match_data *ngx_regex_match_data;
|
||||
static ngx_uint_t ngx_regex_match_data_size;
|
||||
#endif
|
||||
|
||||
|
||||
void
|
||||
ngx_regex_init(void)
|
||||
{
|
||||
#if !(NGX_PCRE2)
|
||||
pcre_malloc = ngx_regex_malloc;
|
||||
pcre_free = ngx_regex_free;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static ngx_inline void
|
||||
ngx_regex_malloc_init(ngx_pool_t *pool)
|
||||
{
|
||||
ngx_regex_pool = pool;
|
||||
ngx_regex_direct_alloc = (pool == NULL) ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
static ngx_inline void
|
||||
ngx_regex_malloc_done(void)
|
||||
{
|
||||
ngx_regex_pool = NULL;
|
||||
ngx_regex_direct_alloc = 0;
|
||||
}
|
||||
|
||||
|
||||
#if (NGX_PCRE2)
|
||||
|
||||
ngx_int_t
|
||||
ngx_regex_compile(ngx_regex_compile_t *rc)
|
||||
{
|
||||
int n, errcode;
|
||||
char *p;
|
||||
u_char errstr[128];
|
||||
size_t erroff;
|
||||
uint32_t options;
|
||||
pcre2_code *re;
|
||||
ngx_regex_elt_t *elt;
|
||||
pcre2_general_context *gctx;
|
||||
pcre2_compile_context *cctx;
|
||||
|
||||
if (ngx_regex_compile_context == NULL) {
|
||||
/*
|
||||
* Allocate a compile context if not yet allocated. This uses
|
||||
* direct allocations from heap, so the result can be cached
|
||||
* even at runtime.
|
||||
*/
|
||||
|
||||
ngx_regex_malloc_init(NULL);
|
||||
|
||||
gctx = pcre2_general_context_create(ngx_regex_malloc, ngx_regex_free,
|
||||
NULL);
|
||||
if (gctx == NULL) {
|
||||
ngx_regex_malloc_done();
|
||||
goto nomem;
|
||||
}
|
||||
|
||||
cctx = pcre2_compile_context_create(gctx);
|
||||
if (cctx == NULL) {
|
||||
pcre2_general_context_free(gctx);
|
||||
ngx_regex_malloc_done();
|
||||
goto nomem;
|
||||
}
|
||||
|
||||
ngx_regex_compile_context = cctx;
|
||||
|
||||
pcre2_general_context_free(gctx);
|
||||
ngx_regex_malloc_done();
|
||||
}
|
||||
|
||||
options = 0;
|
||||
|
||||
if (rc->options & NGX_REGEX_CASELESS) {
|
||||
options |= PCRE2_CASELESS;
|
||||
}
|
||||
|
||||
if (rc->options & NGX_REGEX_MULTILINE) {
|
||||
options |= PCRE2_MULTILINE;
|
||||
}
|
||||
|
||||
if (rc->options & ~(NGX_REGEX_CASELESS|NGX_REGEX_MULTILINE)) {
|
||||
rc->err.len = ngx_snprintf(rc->err.data, rc->err.len,
|
||||
"regex \"%V\" compilation failed: invalid options",
|
||||
&rc->pattern)
|
||||
- rc->err.data;
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_regex_malloc_init(rc->pool);
|
||||
|
||||
re = pcre2_compile(rc->pattern.data, rc->pattern.len, options,
|
||||
&errcode, &erroff, ngx_regex_compile_context);
|
||||
|
||||
/* ensure that there is no current pool */
|
||||
ngx_regex_malloc_done();
|
||||
|
||||
if (re == NULL) {
|
||||
pcre2_get_error_message(errcode, errstr, 128);
|
||||
|
||||
if ((size_t) erroff == rc->pattern.len) {
|
||||
rc->err.len = ngx_snprintf(rc->err.data, rc->err.len,
|
||||
"pcre2_compile() failed: %s in \"%V\"",
|
||||
errstr, &rc->pattern)
|
||||
- rc->err.data;
|
||||
|
||||
} else {
|
||||
rc->err.len = ngx_snprintf(rc->err.data, rc->err.len,
|
||||
"pcre2_compile() failed: %s in \"%V\" at \"%s\"",
|
||||
errstr, &rc->pattern, rc->pattern.data + erroff)
|
||||
- rc->err.data;
|
||||
}
|
||||
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
rc->regex = re;
|
||||
|
||||
/* do not study at runtime */
|
||||
|
||||
if (ngx_regex_studies != NULL) {
|
||||
elt = ngx_list_push(ngx_regex_studies);
|
||||
if (elt == NULL) {
|
||||
goto nomem;
|
||||
}
|
||||
|
||||
elt->regex = rc->regex;
|
||||
elt->name = rc->pattern.data;
|
||||
}
|
||||
|
||||
n = pcre2_pattern_info(re, PCRE2_INFO_CAPTURECOUNT, &rc->captures);
|
||||
if (n < 0) {
|
||||
p = "pcre2_pattern_info(\"%V\", PCRE2_INFO_CAPTURECOUNT) failed: %d";
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (rc->captures == 0) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
n = pcre2_pattern_info(re, PCRE2_INFO_NAMECOUNT, &rc->named_captures);
|
||||
if (n < 0) {
|
||||
p = "pcre2_pattern_info(\"%V\", PCRE2_INFO_NAMECOUNT) failed: %d";
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (rc->named_captures == 0) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
n = pcre2_pattern_info(re, PCRE2_INFO_NAMEENTRYSIZE, &rc->name_size);
|
||||
if (n < 0) {
|
||||
p = "pcre2_pattern_info(\"%V\", PCRE2_INFO_NAMEENTRYSIZE) failed: %d";
|
||||
goto failed;
|
||||
}
|
||||
|
||||
n = pcre2_pattern_info(re, PCRE2_INFO_NAMETABLE, &rc->names);
|
||||
if (n < 0) {
|
||||
p = "pcre2_pattern_info(\"%V\", PCRE2_INFO_NAMETABLE) failed: %d";
|
||||
goto failed;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
|
||||
failed:
|
||||
|
||||
rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, p, &rc->pattern, n)
|
||||
- rc->err.data;
|
||||
return NGX_ERROR;
|
||||
|
||||
nomem:
|
||||
|
||||
rc->err.len = ngx_snprintf(rc->err.data, rc->err.len,
|
||||
"regex \"%V\" compilation failed: no memory",
|
||||
&rc->pattern)
|
||||
- rc->err.data;
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
ngx_int_t
|
||||
ngx_regex_compile(ngx_regex_compile_t *rc)
|
||||
{
|
||||
int n, erroff;
|
||||
char *p;
|
||||
pcre *re;
|
||||
const char *errstr;
|
||||
ngx_uint_t options;
|
||||
ngx_regex_elt_t *elt;
|
||||
|
||||
options = 0;
|
||||
|
||||
if (rc->options & NGX_REGEX_CASELESS) {
|
||||
options |= PCRE_CASELESS;
|
||||
}
|
||||
|
||||
if (rc->options & NGX_REGEX_MULTILINE) {
|
||||
options |= PCRE_MULTILINE;
|
||||
}
|
||||
|
||||
if (rc->options & ~(NGX_REGEX_CASELESS|NGX_REGEX_MULTILINE)) {
|
||||
rc->err.len = ngx_snprintf(rc->err.data, rc->err.len,
|
||||
"regex \"%V\" compilation failed: invalid options",
|
||||
&rc->pattern)
|
||||
- rc->err.data;
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_regex_malloc_init(rc->pool);
|
||||
|
||||
re = pcre_compile((const char *) rc->pattern.data, (int) options,
|
||||
&errstr, &erroff, NULL);
|
||||
|
||||
/* ensure that there is no current pool */
|
||||
ngx_regex_malloc_done();
|
||||
|
||||
if (re == NULL) {
|
||||
if ((size_t) erroff == rc->pattern.len) {
|
||||
rc->err.len = ngx_snprintf(rc->err.data, rc->err.len,
|
||||
"pcre_compile() failed: %s in \"%V\"",
|
||||
errstr, &rc->pattern)
|
||||
- rc->err.data;
|
||||
|
||||
} else {
|
||||
rc->err.len = ngx_snprintf(rc->err.data, rc->err.len,
|
||||
"pcre_compile() failed: %s in \"%V\" at \"%s\"",
|
||||
errstr, &rc->pattern, rc->pattern.data + erroff)
|
||||
- rc->err.data;
|
||||
}
|
||||
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
rc->regex = ngx_pcalloc(rc->pool, sizeof(ngx_regex_t));
|
||||
if (rc->regex == NULL) {
|
||||
goto nomem;
|
||||
}
|
||||
|
||||
rc->regex->code = re;
|
||||
|
||||
/* do not study at runtime */
|
||||
|
||||
if (ngx_regex_studies != NULL) {
|
||||
elt = ngx_list_push(ngx_regex_studies);
|
||||
if (elt == NULL) {
|
||||
goto nomem;
|
||||
}
|
||||
|
||||
elt->regex = rc->regex;
|
||||
elt->name = rc->pattern.data;
|
||||
}
|
||||
|
||||
n = pcre_fullinfo(re, NULL, PCRE_INFO_CAPTURECOUNT, &rc->captures);
|
||||
if (n < 0) {
|
||||
p = "pcre_fullinfo(\"%V\", PCRE_INFO_CAPTURECOUNT) failed: %d";
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (rc->captures == 0) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
n = pcre_fullinfo(re, NULL, PCRE_INFO_NAMECOUNT, &rc->named_captures);
|
||||
if (n < 0) {
|
||||
p = "pcre_fullinfo(\"%V\", PCRE_INFO_NAMECOUNT) failed: %d";
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (rc->named_captures == 0) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
n = pcre_fullinfo(re, NULL, PCRE_INFO_NAMEENTRYSIZE, &rc->name_size);
|
||||
if (n < 0) {
|
||||
p = "pcre_fullinfo(\"%V\", PCRE_INFO_NAMEENTRYSIZE) failed: %d";
|
||||
goto failed;
|
||||
}
|
||||
|
||||
n = pcre_fullinfo(re, NULL, PCRE_INFO_NAMETABLE, &rc->names);
|
||||
if (n < 0) {
|
||||
p = "pcre_fullinfo(\"%V\", PCRE_INFO_NAMETABLE) failed: %d";
|
||||
goto failed;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
|
||||
failed:
|
||||
|
||||
rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, p, &rc->pattern, n)
|
||||
- rc->err.data;
|
||||
return NGX_ERROR;
|
||||
|
||||
nomem:
|
||||
|
||||
rc->err.len = ngx_snprintf(rc->err.data, rc->err.len,
|
||||
"regex \"%V\" compilation failed: no memory",
|
||||
&rc->pattern)
|
||||
- rc->err.data;
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if (NGX_PCRE2)
|
||||
|
||||
ngx_int_t
|
||||
ngx_regex_exec(ngx_regex_t *re, ngx_str_t *s, int *captures, ngx_uint_t size)
|
||||
{
|
||||
size_t *ov;
|
||||
ngx_int_t rc;
|
||||
ngx_uint_t n, i;
|
||||
|
||||
/*
|
||||
* The pcre2_match() function might allocate memory for backtracking
|
||||
* frames, typical allocations are from 40k and above. So the allocator
|
||||
* is configured to do direct allocations from heap during matching.
|
||||
*/
|
||||
|
||||
ngx_regex_malloc_init(NULL);
|
||||
|
||||
if (ngx_regex_match_data == NULL
|
||||
|| size > ngx_regex_match_data_size)
|
||||
{
|
||||
/*
|
||||
* Allocate a match data if not yet allocated or smaller than
|
||||
* needed.
|
||||
*/
|
||||
|
||||
if (ngx_regex_match_data) {
|
||||
pcre2_match_data_free(ngx_regex_match_data);
|
||||
}
|
||||
|
||||
ngx_regex_match_data_size = size;
|
||||
ngx_regex_match_data = pcre2_match_data_create(size / 3, NULL);
|
||||
|
||||
if (ngx_regex_match_data == NULL) {
|
||||
rc = PCRE2_ERROR_NOMEMORY;
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
|
||||
rc = pcre2_match(re, s->data, s->len, 0, 0, ngx_regex_match_data, NULL);
|
||||
|
||||
if (rc < 0) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
n = pcre2_get_ovector_count(ngx_regex_match_data);
|
||||
ov = pcre2_get_ovector_pointer(ngx_regex_match_data);
|
||||
|
||||
if (n > size / 3) {
|
||||
n = size / 3;
|
||||
}
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
captures[i * 2] = ov[i * 2];
|
||||
captures[i * 2 + 1] = ov[i * 2 + 1];
|
||||
}
|
||||
|
||||
failed:
|
||||
|
||||
ngx_regex_malloc_done();
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
ngx_int_t
|
||||
ngx_regex_exec(ngx_regex_t *re, ngx_str_t *s, int *captures, ngx_uint_t size)
|
||||
{
|
||||
return pcre_exec(re->code, re->extra, (const char *) s->data, s->len,
|
||||
0, 0, captures, size);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_regex_exec_array(ngx_array_t *a, ngx_str_t *s, ngx_log_t *log)
|
||||
{
|
||||
ngx_int_t n;
|
||||
ngx_uint_t i;
|
||||
ngx_regex_elt_t *re;
|
||||
|
||||
re = a->elts;
|
||||
|
||||
for (i = 0; i < a->nelts; i++) {
|
||||
|
||||
n = ngx_regex_exec(re[i].regex, s, NULL, 0);
|
||||
|
||||
if (n == NGX_REGEX_NO_MATCHED) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (n < 0) {
|
||||
ngx_log_error(NGX_LOG_ALERT, log, 0,
|
||||
ngx_regex_exec_n " failed: %i on \"%V\" using \"%s\"",
|
||||
n, s, re[i].name);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
/* match */
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
|
||||
#if (NGX_PCRE2)
|
||||
|
||||
static void * ngx_libc_cdecl
|
||||
ngx_regex_malloc(size_t size, void *data)
|
||||
{
|
||||
if (ngx_regex_pool) {
|
||||
return ngx_palloc(ngx_regex_pool, size);
|
||||
}
|
||||
|
||||
if (ngx_regex_direct_alloc) {
|
||||
return ngx_alloc(size, ngx_cycle->log);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static void ngx_libc_cdecl
|
||||
ngx_regex_free(void *p, void *data)
|
||||
{
|
||||
if (ngx_regex_direct_alloc) {
|
||||
ngx_free(p);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static void * ngx_libc_cdecl
|
||||
ngx_regex_malloc(size_t size)
|
||||
{
|
||||
if (ngx_regex_pool) {
|
||||
return ngx_palloc(ngx_regex_pool, size);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static void ngx_libc_cdecl
|
||||
ngx_regex_free(void *p)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
static void
|
||||
ngx_regex_cleanup(void *data)
|
||||
{
|
||||
#if (NGX_PCRE2 || NGX_HAVE_PCRE_JIT)
|
||||
ngx_regex_conf_t *rcf = data;
|
||||
|
||||
ngx_uint_t i;
|
||||
ngx_list_part_t *part;
|
||||
ngx_regex_elt_t *elts;
|
||||
|
||||
part = &rcf->studies->part;
|
||||
elts = part->elts;
|
||||
|
||||
for (i = 0; /* void */ ; i++) {
|
||||
|
||||
if (i >= part->nelts) {
|
||||
if (part->next == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
part = part->next;
|
||||
elts = part->elts;
|
||||
i = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The PCRE JIT compiler uses mmap for its executable codes, so we
|
||||
* have to explicitly call the pcre_free_study() function to free
|
||||
* this memory. In PCRE2, we call the pcre2_code_free() function
|
||||
* for the same reason.
|
||||
*/
|
||||
|
||||
#if (NGX_PCRE2)
|
||||
pcre2_code_free(elts[i].regex);
|
||||
#else
|
||||
if (elts[i].regex->extra != NULL) {
|
||||
pcre_free_study(elts[i].regex->extra);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* On configuration parsing errors ngx_regex_module_init() will not
|
||||
* be called. Make sure ngx_regex_studies is properly cleared anyway.
|
||||
*/
|
||||
|
||||
ngx_regex_studies = NULL;
|
||||
|
||||
#if (NGX_PCRE2)
|
||||
|
||||
/*
|
||||
* Free compile context and match data. If needed at runtime by
|
||||
* the new cycle, these will be re-allocated.
|
||||
*/
|
||||
|
||||
ngx_regex_malloc_init(NULL);
|
||||
|
||||
if (ngx_regex_compile_context) {
|
||||
pcre2_compile_context_free(ngx_regex_compile_context);
|
||||
ngx_regex_compile_context = NULL;
|
||||
}
|
||||
|
||||
if (ngx_regex_match_data) {
|
||||
pcre2_match_data_free(ngx_regex_match_data);
|
||||
ngx_regex_match_data = NULL;
|
||||
ngx_regex_match_data_size = 0;
|
||||
}
|
||||
|
||||
ngx_regex_malloc_done();
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_regex_module_init(ngx_cycle_t *cycle)
|
||||
{
|
||||
int opt;
|
||||
#if !(NGX_PCRE2)
|
||||
const char *errstr;
|
||||
#endif
|
||||
ngx_uint_t i;
|
||||
ngx_list_part_t *part;
|
||||
ngx_regex_elt_t *elts;
|
||||
ngx_regex_conf_t *rcf;
|
||||
|
||||
opt = 0;
|
||||
|
||||
rcf = (ngx_regex_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_regex_module);
|
||||
|
||||
#if (NGX_PCRE2 || NGX_HAVE_PCRE_JIT)
|
||||
|
||||
if (rcf->pcre_jit) {
|
||||
#if (NGX_PCRE2)
|
||||
opt = 1;
|
||||
#else
|
||||
opt = PCRE_STUDY_JIT_COMPILE;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
ngx_regex_malloc_init(cycle->pool);
|
||||
|
||||
part = &rcf->studies->part;
|
||||
elts = part->elts;
|
||||
|
||||
for (i = 0; /* void */ ; i++) {
|
||||
|
||||
if (i >= part->nelts) {
|
||||
if (part->next == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
part = part->next;
|
||||
elts = part->elts;
|
||||
i = 0;
|
||||
}
|
||||
|
||||
#if (NGX_PCRE2)
|
||||
|
||||
if (opt) {
|
||||
int n;
|
||||
|
||||
n = pcre2_jit_compile(elts[i].regex, PCRE2_JIT_COMPLETE);
|
||||
|
||||
if (n != 0) {
|
||||
ngx_log_error(NGX_LOG_INFO, cycle->log, 0,
|
||||
"pcre2_jit_compile() failed: %d in \"%s\", "
|
||||
"ignored",
|
||||
n, elts[i].name);
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
elts[i].regex->extra = pcre_study(elts[i].regex->code, opt, &errstr);
|
||||
|
||||
if (errstr != NULL) {
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
|
||||
"pcre_study() failed: %s in \"%s\"",
|
||||
errstr, elts[i].name);
|
||||
}
|
||||
|
||||
#if (NGX_HAVE_PCRE_JIT)
|
||||
if (opt & PCRE_STUDY_JIT_COMPILE) {
|
||||
int jit, n;
|
||||
|
||||
jit = 0;
|
||||
n = pcre_fullinfo(elts[i].regex->code, elts[i].regex->extra,
|
||||
PCRE_INFO_JIT, &jit);
|
||||
|
||||
if (n != 0 || jit != 1) {
|
||||
ngx_log_error(NGX_LOG_INFO, cycle->log, 0,
|
||||
"JIT compiler does not support pattern: \"%s\"",
|
||||
elts[i].name);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
ngx_regex_malloc_done();
|
||||
|
||||
ngx_regex_studies = NULL;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
ngx_regex_create_conf(ngx_cycle_t *cycle)
|
||||
{
|
||||
ngx_regex_conf_t *rcf;
|
||||
ngx_pool_cleanup_t *cln;
|
||||
|
||||
rcf = ngx_pcalloc(cycle->pool, sizeof(ngx_regex_conf_t));
|
||||
if (rcf == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rcf->pcre_jit = NGX_CONF_UNSET;
|
||||
|
||||
cln = ngx_pool_cleanup_add(cycle->pool, 0);
|
||||
if (cln == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rcf->studies = ngx_list_create(cycle->pool, 8, sizeof(ngx_regex_elt_t));
|
||||
if (rcf->studies == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cln->handler = ngx_regex_cleanup;
|
||||
cln->data = rcf;
|
||||
|
||||
ngx_regex_studies = rcf->studies;
|
||||
|
||||
return rcf;
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
ngx_regex_init_conf(ngx_cycle_t *cycle, void *conf)
|
||||
{
|
||||
ngx_regex_conf_t *rcf = conf;
|
||||
|
||||
ngx_conf_init_value(rcf->pcre_jit, 0);
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
ngx_regex_pcre_jit(ngx_conf_t *cf, void *post, void *data)
|
||||
{
|
||||
ngx_flag_t *fp = data;
|
||||
|
||||
if (*fp == 0) {
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
#if (NGX_PCRE2)
|
||||
{
|
||||
int r;
|
||||
uint32_t jit;
|
||||
|
||||
jit = 0;
|
||||
r = pcre2_config(PCRE2_CONFIG_JIT, &jit);
|
||||
|
||||
if (r != 0 || jit != 1) {
|
||||
ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
|
||||
"PCRE2 library does not support JIT");
|
||||
*fp = 0;
|
||||
}
|
||||
}
|
||||
#elif (NGX_HAVE_PCRE_JIT)
|
||||
{
|
||||
int jit, r;
|
||||
|
||||
jit = 0;
|
||||
r = pcre_config(PCRE_CONFIG_JIT, &jit);
|
||||
|
||||
if (r != 0 || jit != 1) {
|
||||
ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
|
||||
"PCRE library does not support JIT");
|
||||
*fp = 0;
|
||||
}
|
||||
}
|
||||
#else
|
||||
ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
|
||||
"nginx was built without PCRE JIT support");
|
||||
*fp = 0;
|
||||
#endif
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
78
nginx/src/core/ngx_regex.h
Normal file
78
nginx/src/core/ngx_regex.h
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_REGEX_H_INCLUDED_
|
||||
#define _NGX_REGEX_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
#if (NGX_PCRE2)
|
||||
|
||||
#define PCRE2_CODE_UNIT_WIDTH 8
|
||||
#include <pcre2.h>
|
||||
|
||||
#define NGX_REGEX_NO_MATCHED PCRE2_ERROR_NOMATCH /* -1 */
|
||||
|
||||
typedef pcre2_code ngx_regex_t;
|
||||
|
||||
#else
|
||||
|
||||
#include <pcre.h>
|
||||
|
||||
#define NGX_REGEX_NO_MATCHED PCRE_ERROR_NOMATCH /* -1 */
|
||||
|
||||
typedef struct {
|
||||
pcre *code;
|
||||
pcre_extra *extra;
|
||||
} ngx_regex_t;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#define NGX_REGEX_CASELESS 0x00000001
|
||||
#define NGX_REGEX_MULTILINE 0x00000002
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_str_t pattern;
|
||||
ngx_pool_t *pool;
|
||||
ngx_uint_t options;
|
||||
|
||||
ngx_regex_t *regex;
|
||||
int captures;
|
||||
int named_captures;
|
||||
int name_size;
|
||||
u_char *names;
|
||||
ngx_str_t err;
|
||||
} ngx_regex_compile_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_regex_t *regex;
|
||||
u_char *name;
|
||||
} ngx_regex_elt_t;
|
||||
|
||||
|
||||
void ngx_regex_init(void);
|
||||
ngx_int_t ngx_regex_compile(ngx_regex_compile_t *rc);
|
||||
|
||||
ngx_int_t ngx_regex_exec(ngx_regex_t *re, ngx_str_t *s, int *captures,
|
||||
ngx_uint_t size);
|
||||
|
||||
#if (NGX_PCRE2)
|
||||
#define ngx_regex_exec_n "pcre2_match()"
|
||||
#else
|
||||
#define ngx_regex_exec_n "pcre_exec()"
|
||||
#endif
|
||||
|
||||
ngx_int_t ngx_regex_exec_array(ngx_array_t *a, ngx_str_t *s, ngx_log_t *log);
|
||||
|
||||
|
||||
#endif /* _NGX_REGEX_H_INCLUDED_ */
|
||||
4741
nginx/src/core/ngx_resolver.c
Normal file
4741
nginx/src/core/ngx_resolver.c
Normal file
File diff suppressed because it is too large
Load diff
242
nginx/src/core/ngx_resolver.h
Normal file
242
nginx/src/core/ngx_resolver.h
Normal file
|
|
@ -0,0 +1,242 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
#ifndef _NGX_RESOLVER_H_INCLUDED_
|
||||
#define _NGX_RESOLVER_H_INCLUDED_
|
||||
|
||||
|
||||
#define NGX_RESOLVE_A 1
|
||||
#define NGX_RESOLVE_CNAME 5
|
||||
#define NGX_RESOLVE_PTR 12
|
||||
#define NGX_RESOLVE_MX 15
|
||||
#define NGX_RESOLVE_TXT 16
|
||||
#if (NGX_HAVE_INET6)
|
||||
#define NGX_RESOLVE_AAAA 28
|
||||
#endif
|
||||
#define NGX_RESOLVE_SRV 33
|
||||
#define NGX_RESOLVE_DNAME 39
|
||||
|
||||
#define NGX_RESOLVE_FORMERR 1
|
||||
#define NGX_RESOLVE_SERVFAIL 2
|
||||
#define NGX_RESOLVE_NXDOMAIN 3
|
||||
#define NGX_RESOLVE_NOTIMP 4
|
||||
#define NGX_RESOLVE_REFUSED 5
|
||||
#define NGX_RESOLVE_TIMEDOUT NGX_ETIMEDOUT
|
||||
|
||||
|
||||
#define NGX_NO_RESOLVER (void *) -1
|
||||
|
||||
#define NGX_RESOLVER_MAX_RECURSION 50
|
||||
|
||||
|
||||
typedef struct ngx_resolver_s ngx_resolver_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_connection_t *udp;
|
||||
ngx_connection_t *tcp;
|
||||
struct sockaddr *sockaddr;
|
||||
socklen_t socklen;
|
||||
ngx_str_t server;
|
||||
ngx_log_t log;
|
||||
ngx_buf_t *read_buf;
|
||||
ngx_buf_t *write_buf;
|
||||
ngx_resolver_t *resolver;
|
||||
} ngx_resolver_connection_t;
|
||||
|
||||
|
||||
typedef struct ngx_resolver_ctx_s ngx_resolver_ctx_t;
|
||||
|
||||
typedef void (*ngx_resolver_handler_pt)(ngx_resolver_ctx_t *ctx);
|
||||
|
||||
|
||||
typedef struct {
|
||||
struct sockaddr *sockaddr;
|
||||
socklen_t socklen;
|
||||
ngx_str_t name;
|
||||
u_short priority;
|
||||
u_short weight;
|
||||
} ngx_resolver_addr_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_str_t name;
|
||||
u_short priority;
|
||||
u_short weight;
|
||||
u_short port;
|
||||
} ngx_resolver_srv_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_str_t name;
|
||||
u_short priority;
|
||||
u_short weight;
|
||||
u_short port;
|
||||
|
||||
ngx_resolver_ctx_t *ctx;
|
||||
ngx_int_t state;
|
||||
|
||||
ngx_uint_t naddrs;
|
||||
ngx_addr_t *addrs;
|
||||
} ngx_resolver_srv_name_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_rbtree_node_t node;
|
||||
ngx_queue_t queue;
|
||||
|
||||
/* PTR: resolved name, A: name to resolve */
|
||||
u_char *name;
|
||||
|
||||
#if (NGX_HAVE_INET6)
|
||||
/* PTR: IPv6 address to resolve (IPv4 address is in rbtree node key) */
|
||||
struct in6_addr addr6;
|
||||
#endif
|
||||
|
||||
u_short nlen;
|
||||
u_short qlen;
|
||||
|
||||
u_char *query;
|
||||
#if (NGX_HAVE_INET6)
|
||||
u_char *query6;
|
||||
#endif
|
||||
|
||||
union {
|
||||
in_addr_t addr;
|
||||
in_addr_t *addrs;
|
||||
u_char *cname;
|
||||
ngx_resolver_srv_t *srvs;
|
||||
} u;
|
||||
|
||||
u_char code;
|
||||
u_short naddrs;
|
||||
u_short nsrvs;
|
||||
u_short cnlen;
|
||||
|
||||
#if (NGX_HAVE_INET6)
|
||||
union {
|
||||
struct in6_addr addr6;
|
||||
struct in6_addr *addrs6;
|
||||
} u6;
|
||||
|
||||
u_short naddrs6;
|
||||
#endif
|
||||
|
||||
time_t expire;
|
||||
time_t valid;
|
||||
uint32_t ttl;
|
||||
|
||||
unsigned tcp:1;
|
||||
#if (NGX_HAVE_INET6)
|
||||
unsigned tcp6:1;
|
||||
#endif
|
||||
|
||||
ngx_uint_t last_connection;
|
||||
|
||||
ngx_resolver_ctx_t *waiting;
|
||||
} ngx_resolver_node_t;
|
||||
|
||||
|
||||
struct ngx_resolver_s {
|
||||
/* has to be pointer because of "incomplete type" */
|
||||
ngx_event_t *event;
|
||||
void *dummy;
|
||||
ngx_log_t *log;
|
||||
|
||||
/* event ident must be after 3 pointers as in ngx_connection_t */
|
||||
ngx_int_t ident;
|
||||
|
||||
/* simple round robin DNS peers balancer */
|
||||
ngx_array_t connections;
|
||||
ngx_uint_t last_connection;
|
||||
|
||||
ngx_rbtree_t name_rbtree;
|
||||
ngx_rbtree_node_t name_sentinel;
|
||||
|
||||
ngx_rbtree_t srv_rbtree;
|
||||
ngx_rbtree_node_t srv_sentinel;
|
||||
|
||||
ngx_rbtree_t addr_rbtree;
|
||||
ngx_rbtree_node_t addr_sentinel;
|
||||
|
||||
ngx_queue_t name_resend_queue;
|
||||
ngx_queue_t srv_resend_queue;
|
||||
ngx_queue_t addr_resend_queue;
|
||||
|
||||
ngx_queue_t name_expire_queue;
|
||||
ngx_queue_t srv_expire_queue;
|
||||
ngx_queue_t addr_expire_queue;
|
||||
|
||||
unsigned ipv4:1;
|
||||
|
||||
#if (NGX_HAVE_INET6)
|
||||
unsigned ipv6:1;
|
||||
ngx_rbtree_t addr6_rbtree;
|
||||
ngx_rbtree_node_t addr6_sentinel;
|
||||
ngx_queue_t addr6_resend_queue;
|
||||
ngx_queue_t addr6_expire_queue;
|
||||
#endif
|
||||
|
||||
time_t resend_timeout;
|
||||
time_t tcp_timeout;
|
||||
time_t expire;
|
||||
time_t valid;
|
||||
|
||||
ngx_uint_t log_level;
|
||||
};
|
||||
|
||||
|
||||
struct ngx_resolver_ctx_s {
|
||||
ngx_resolver_ctx_t *next;
|
||||
ngx_resolver_t *resolver;
|
||||
ngx_resolver_node_t *node;
|
||||
|
||||
/* event ident must be after 3 pointers as in ngx_connection_t */
|
||||
ngx_int_t ident;
|
||||
|
||||
ngx_int_t state;
|
||||
ngx_str_t name;
|
||||
ngx_str_t service;
|
||||
|
||||
time_t valid;
|
||||
ngx_uint_t naddrs;
|
||||
ngx_resolver_addr_t *addrs;
|
||||
ngx_resolver_addr_t addr;
|
||||
struct sockaddr_in sin;
|
||||
|
||||
ngx_uint_t count;
|
||||
ngx_uint_t nsrvs;
|
||||
ngx_resolver_srv_name_t *srvs;
|
||||
|
||||
ngx_resolver_handler_pt handler;
|
||||
void *data;
|
||||
ngx_msec_t timeout;
|
||||
|
||||
unsigned quick:1;
|
||||
unsigned async:1;
|
||||
unsigned cancelable:1;
|
||||
ngx_uint_t recursion;
|
||||
ngx_event_t *event;
|
||||
};
|
||||
|
||||
|
||||
ngx_resolver_t *ngx_resolver_create(ngx_conf_t *cf, ngx_str_t *names,
|
||||
ngx_uint_t n);
|
||||
ngx_resolver_ctx_t *ngx_resolve_start(ngx_resolver_t *r,
|
||||
ngx_resolver_ctx_t *temp);
|
||||
ngx_int_t ngx_resolve_name(ngx_resolver_ctx_t *ctx);
|
||||
void ngx_resolve_name_done(ngx_resolver_ctx_t *ctx);
|
||||
ngx_int_t ngx_resolve_addr(ngx_resolver_ctx_t *ctx);
|
||||
void ngx_resolve_addr_done(ngx_resolver_ctx_t *ctx);
|
||||
char *ngx_resolver_strerror(ngx_int_t err);
|
||||
|
||||
|
||||
#endif /* _NGX_RESOLVER_H_INCLUDED_ */
|
||||
117
nginx/src/core/ngx_rwlock.c
Normal file
117
nginx/src/core/ngx_rwlock.c
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Ruslan Ermilov
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
#if (NGX_HAVE_ATOMIC_OPS)
|
||||
|
||||
|
||||
#define NGX_RWLOCK_SPIN 2048
|
||||
#define NGX_RWLOCK_WLOCK ((ngx_atomic_uint_t) -1)
|
||||
|
||||
|
||||
void
|
||||
ngx_rwlock_wlock(ngx_atomic_t *lock)
|
||||
{
|
||||
ngx_uint_t i, n;
|
||||
|
||||
for ( ;; ) {
|
||||
|
||||
if (*lock == 0 && ngx_atomic_cmp_set(lock, 0, NGX_RWLOCK_WLOCK)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ngx_ncpu > 1) {
|
||||
|
||||
for (n = 1; n < NGX_RWLOCK_SPIN; n <<= 1) {
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
ngx_cpu_pause();
|
||||
}
|
||||
|
||||
if (*lock == 0
|
||||
&& ngx_atomic_cmp_set(lock, 0, NGX_RWLOCK_WLOCK))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ngx_sched_yield();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_rwlock_rlock(ngx_atomic_t *lock)
|
||||
{
|
||||
ngx_uint_t i, n;
|
||||
ngx_atomic_uint_t readers;
|
||||
|
||||
for ( ;; ) {
|
||||
readers = *lock;
|
||||
|
||||
if (readers != NGX_RWLOCK_WLOCK
|
||||
&& ngx_atomic_cmp_set(lock, readers, readers + 1))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (ngx_ncpu > 1) {
|
||||
|
||||
for (n = 1; n < NGX_RWLOCK_SPIN; n <<= 1) {
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
ngx_cpu_pause();
|
||||
}
|
||||
|
||||
readers = *lock;
|
||||
|
||||
if (readers != NGX_RWLOCK_WLOCK
|
||||
&& ngx_atomic_cmp_set(lock, readers, readers + 1))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ngx_sched_yield();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_rwlock_unlock(ngx_atomic_t *lock)
|
||||
{
|
||||
if (*lock == NGX_RWLOCK_WLOCK) {
|
||||
(void) ngx_atomic_cmp_set(lock, NGX_RWLOCK_WLOCK, 0);
|
||||
} else {
|
||||
(void) ngx_atomic_fetch_add(lock, -1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_rwlock_downgrade(ngx_atomic_t *lock)
|
||||
{
|
||||
if (*lock == NGX_RWLOCK_WLOCK) {
|
||||
*lock = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
#if (NGX_HTTP_UPSTREAM_ZONE || NGX_STREAM_UPSTREAM_ZONE)
|
||||
|
||||
#error ngx_atomic_cmp_set() is not defined!
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
22
nginx/src/core/ngx_rwlock.h
Normal file
22
nginx/src/core/ngx_rwlock.h
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Ruslan Ermilov
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_RWLOCK_H_INCLUDED_
|
||||
#define _NGX_RWLOCK_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
void ngx_rwlock_wlock(ngx_atomic_t *lock);
|
||||
void ngx_rwlock_rlock(ngx_atomic_t *lock);
|
||||
void ngx_rwlock_unlock(ngx_atomic_t *lock);
|
||||
void ngx_rwlock_downgrade(ngx_atomic_t *lock);
|
||||
|
||||
|
||||
#endif /* _NGX_RWLOCK_H_INCLUDED_ */
|
||||
294
nginx/src/core/ngx_sha1.c
Normal file
294
nginx/src/core/ngx_sha1.c
Normal file
|
|
@ -0,0 +1,294 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Maxim Dounin
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*
|
||||
* An internal SHA1 implementation.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_sha1.h>
|
||||
|
||||
|
||||
static const u_char *ngx_sha1_body(ngx_sha1_t *ctx, const u_char *data,
|
||||
size_t size);
|
||||
|
||||
|
||||
void
|
||||
ngx_sha1_init(ngx_sha1_t *ctx)
|
||||
{
|
||||
ctx->a = 0x67452301;
|
||||
ctx->b = 0xefcdab89;
|
||||
ctx->c = 0x98badcfe;
|
||||
ctx->d = 0x10325476;
|
||||
ctx->e = 0xc3d2e1f0;
|
||||
|
||||
ctx->bytes = 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_sha1_update(ngx_sha1_t *ctx, const void *data, size_t size)
|
||||
{
|
||||
size_t used, free;
|
||||
|
||||
used = (size_t) (ctx->bytes & 0x3f);
|
||||
ctx->bytes += size;
|
||||
|
||||
if (used) {
|
||||
free = 64 - used;
|
||||
|
||||
if (size < free) {
|
||||
ngx_memcpy(&ctx->buffer[used], data, size);
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_memcpy(&ctx->buffer[used], data, free);
|
||||
data = (u_char *) data + free;
|
||||
size -= free;
|
||||
(void) ngx_sha1_body(ctx, ctx->buffer, 64);
|
||||
}
|
||||
|
||||
if (size >= 64) {
|
||||
data = ngx_sha1_body(ctx, data, size & ~(size_t) 0x3f);
|
||||
size &= 0x3f;
|
||||
}
|
||||
|
||||
ngx_memcpy(ctx->buffer, data, size);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_sha1_final(u_char result[20], ngx_sha1_t *ctx)
|
||||
{
|
||||
size_t used, free;
|
||||
|
||||
used = (size_t) (ctx->bytes & 0x3f);
|
||||
|
||||
ctx->buffer[used++] = 0x80;
|
||||
|
||||
free = 64 - used;
|
||||
|
||||
if (free < 8) {
|
||||
ngx_memzero(&ctx->buffer[used], free);
|
||||
(void) ngx_sha1_body(ctx, ctx->buffer, 64);
|
||||
used = 0;
|
||||
free = 64;
|
||||
}
|
||||
|
||||
ngx_memzero(&ctx->buffer[used], free - 8);
|
||||
|
||||
ctx->bytes <<= 3;
|
||||
ctx->buffer[56] = (u_char) (ctx->bytes >> 56);
|
||||
ctx->buffer[57] = (u_char) (ctx->bytes >> 48);
|
||||
ctx->buffer[58] = (u_char) (ctx->bytes >> 40);
|
||||
ctx->buffer[59] = (u_char) (ctx->bytes >> 32);
|
||||
ctx->buffer[60] = (u_char) (ctx->bytes >> 24);
|
||||
ctx->buffer[61] = (u_char) (ctx->bytes >> 16);
|
||||
ctx->buffer[62] = (u_char) (ctx->bytes >> 8);
|
||||
ctx->buffer[63] = (u_char) ctx->bytes;
|
||||
|
||||
(void) ngx_sha1_body(ctx, ctx->buffer, 64);
|
||||
|
||||
result[0] = (u_char) (ctx->a >> 24);
|
||||
result[1] = (u_char) (ctx->a >> 16);
|
||||
result[2] = (u_char) (ctx->a >> 8);
|
||||
result[3] = (u_char) ctx->a;
|
||||
result[4] = (u_char) (ctx->b >> 24);
|
||||
result[5] = (u_char) (ctx->b >> 16);
|
||||
result[6] = (u_char) (ctx->b >> 8);
|
||||
result[7] = (u_char) ctx->b;
|
||||
result[8] = (u_char) (ctx->c >> 24);
|
||||
result[9] = (u_char) (ctx->c >> 16);
|
||||
result[10] = (u_char) (ctx->c >> 8);
|
||||
result[11] = (u_char) ctx->c;
|
||||
result[12] = (u_char) (ctx->d >> 24);
|
||||
result[13] = (u_char) (ctx->d >> 16);
|
||||
result[14] = (u_char) (ctx->d >> 8);
|
||||
result[15] = (u_char) ctx->d;
|
||||
result[16] = (u_char) (ctx->e >> 24);
|
||||
result[17] = (u_char) (ctx->e >> 16);
|
||||
result[18] = (u_char) (ctx->e >> 8);
|
||||
result[19] = (u_char) ctx->e;
|
||||
|
||||
ngx_memzero(ctx, sizeof(*ctx));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Helper functions.
|
||||
*/
|
||||
|
||||
#define ROTATE(bits, word) (((word) << (bits)) | ((word) >> (32 - (bits))))
|
||||
|
||||
#define F1(b, c, d) (((b) & (c)) | ((~(b)) & (d)))
|
||||
#define F2(b, c, d) ((b) ^ (c) ^ (d))
|
||||
#define F3(b, c, d) (((b) & (c)) | ((b) & (d)) | ((c) & (d)))
|
||||
|
||||
#define STEP(f, a, b, c, d, e, w, t) \
|
||||
temp = ROTATE(5, (a)) + f((b), (c), (d)) + (e) + (w) + (t); \
|
||||
(e) = (d); \
|
||||
(d) = (c); \
|
||||
(c) = ROTATE(30, (b)); \
|
||||
(b) = (a); \
|
||||
(a) = temp;
|
||||
|
||||
|
||||
/*
|
||||
* GET() reads 4 input bytes in big-endian byte order and returns
|
||||
* them as uint32_t.
|
||||
*/
|
||||
|
||||
#define GET(n) \
|
||||
((uint32_t) p[n * 4 + 3] | \
|
||||
((uint32_t) p[n * 4 + 2] << 8) | \
|
||||
((uint32_t) p[n * 4 + 1] << 16) | \
|
||||
((uint32_t) p[n * 4] << 24))
|
||||
|
||||
|
||||
/*
|
||||
* This processes one or more 64-byte data blocks, but does not update
|
||||
* the bit counters. There are no alignment requirements.
|
||||
*/
|
||||
|
||||
static const u_char *
|
||||
ngx_sha1_body(ngx_sha1_t *ctx, const u_char *data, size_t size)
|
||||
{
|
||||
uint32_t a, b, c, d, e, temp;
|
||||
uint32_t saved_a, saved_b, saved_c, saved_d, saved_e;
|
||||
uint32_t words[80];
|
||||
ngx_uint_t i;
|
||||
const u_char *p;
|
||||
|
||||
p = data;
|
||||
|
||||
a = ctx->a;
|
||||
b = ctx->b;
|
||||
c = ctx->c;
|
||||
d = ctx->d;
|
||||
e = ctx->e;
|
||||
|
||||
do {
|
||||
saved_a = a;
|
||||
saved_b = b;
|
||||
saved_c = c;
|
||||
saved_d = d;
|
||||
saved_e = e;
|
||||
|
||||
/* Load data block into the words array */
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
words[i] = GET(i);
|
||||
}
|
||||
|
||||
for (i = 16; i < 80; i++) {
|
||||
words[i] = ROTATE(1, words[i - 3] ^ words[i - 8] ^ words[i - 14]
|
||||
^ words[i - 16]);
|
||||
}
|
||||
|
||||
/* Transformations */
|
||||
|
||||
STEP(F1, a, b, c, d, e, words[0], 0x5a827999);
|
||||
STEP(F1, a, b, c, d, e, words[1], 0x5a827999);
|
||||
STEP(F1, a, b, c, d, e, words[2], 0x5a827999);
|
||||
STEP(F1, a, b, c, d, e, words[3], 0x5a827999);
|
||||
STEP(F1, a, b, c, d, e, words[4], 0x5a827999);
|
||||
STEP(F1, a, b, c, d, e, words[5], 0x5a827999);
|
||||
STEP(F1, a, b, c, d, e, words[6], 0x5a827999);
|
||||
STEP(F1, a, b, c, d, e, words[7], 0x5a827999);
|
||||
STEP(F1, a, b, c, d, e, words[8], 0x5a827999);
|
||||
STEP(F1, a, b, c, d, e, words[9], 0x5a827999);
|
||||
STEP(F1, a, b, c, d, e, words[10], 0x5a827999);
|
||||
STEP(F1, a, b, c, d, e, words[11], 0x5a827999);
|
||||
STEP(F1, a, b, c, d, e, words[12], 0x5a827999);
|
||||
STEP(F1, a, b, c, d, e, words[13], 0x5a827999);
|
||||
STEP(F1, a, b, c, d, e, words[14], 0x5a827999);
|
||||
STEP(F1, a, b, c, d, e, words[15], 0x5a827999);
|
||||
STEP(F1, a, b, c, d, e, words[16], 0x5a827999);
|
||||
STEP(F1, a, b, c, d, e, words[17], 0x5a827999);
|
||||
STEP(F1, a, b, c, d, e, words[18], 0x5a827999);
|
||||
STEP(F1, a, b, c, d, e, words[19], 0x5a827999);
|
||||
|
||||
STEP(F2, a, b, c, d, e, words[20], 0x6ed9eba1);
|
||||
STEP(F2, a, b, c, d, e, words[21], 0x6ed9eba1);
|
||||
STEP(F2, a, b, c, d, e, words[22], 0x6ed9eba1);
|
||||
STEP(F2, a, b, c, d, e, words[23], 0x6ed9eba1);
|
||||
STEP(F2, a, b, c, d, e, words[24], 0x6ed9eba1);
|
||||
STEP(F2, a, b, c, d, e, words[25], 0x6ed9eba1);
|
||||
STEP(F2, a, b, c, d, e, words[26], 0x6ed9eba1);
|
||||
STEP(F2, a, b, c, d, e, words[27], 0x6ed9eba1);
|
||||
STEP(F2, a, b, c, d, e, words[28], 0x6ed9eba1);
|
||||
STEP(F2, a, b, c, d, e, words[29], 0x6ed9eba1);
|
||||
STEP(F2, a, b, c, d, e, words[30], 0x6ed9eba1);
|
||||
STEP(F2, a, b, c, d, e, words[31], 0x6ed9eba1);
|
||||
STEP(F2, a, b, c, d, e, words[32], 0x6ed9eba1);
|
||||
STEP(F2, a, b, c, d, e, words[33], 0x6ed9eba1);
|
||||
STEP(F2, a, b, c, d, e, words[34], 0x6ed9eba1);
|
||||
STEP(F2, a, b, c, d, e, words[35], 0x6ed9eba1);
|
||||
STEP(F2, a, b, c, d, e, words[36], 0x6ed9eba1);
|
||||
STEP(F2, a, b, c, d, e, words[37], 0x6ed9eba1);
|
||||
STEP(F2, a, b, c, d, e, words[38], 0x6ed9eba1);
|
||||
STEP(F2, a, b, c, d, e, words[39], 0x6ed9eba1);
|
||||
|
||||
STEP(F3, a, b, c, d, e, words[40], 0x8f1bbcdc);
|
||||
STEP(F3, a, b, c, d, e, words[41], 0x8f1bbcdc);
|
||||
STEP(F3, a, b, c, d, e, words[42], 0x8f1bbcdc);
|
||||
STEP(F3, a, b, c, d, e, words[43], 0x8f1bbcdc);
|
||||
STEP(F3, a, b, c, d, e, words[44], 0x8f1bbcdc);
|
||||
STEP(F3, a, b, c, d, e, words[45], 0x8f1bbcdc);
|
||||
STEP(F3, a, b, c, d, e, words[46], 0x8f1bbcdc);
|
||||
STEP(F3, a, b, c, d, e, words[47], 0x8f1bbcdc);
|
||||
STEP(F3, a, b, c, d, e, words[48], 0x8f1bbcdc);
|
||||
STEP(F3, a, b, c, d, e, words[49], 0x8f1bbcdc);
|
||||
STEP(F3, a, b, c, d, e, words[50], 0x8f1bbcdc);
|
||||
STEP(F3, a, b, c, d, e, words[51], 0x8f1bbcdc);
|
||||
STEP(F3, a, b, c, d, e, words[52], 0x8f1bbcdc);
|
||||
STEP(F3, a, b, c, d, e, words[53], 0x8f1bbcdc);
|
||||
STEP(F3, a, b, c, d, e, words[54], 0x8f1bbcdc);
|
||||
STEP(F3, a, b, c, d, e, words[55], 0x8f1bbcdc);
|
||||
STEP(F3, a, b, c, d, e, words[56], 0x8f1bbcdc);
|
||||
STEP(F3, a, b, c, d, e, words[57], 0x8f1bbcdc);
|
||||
STEP(F3, a, b, c, d, e, words[58], 0x8f1bbcdc);
|
||||
STEP(F3, a, b, c, d, e, words[59], 0x8f1bbcdc);
|
||||
|
||||
STEP(F2, a, b, c, d, e, words[60], 0xca62c1d6);
|
||||
STEP(F2, a, b, c, d, e, words[61], 0xca62c1d6);
|
||||
STEP(F2, a, b, c, d, e, words[62], 0xca62c1d6);
|
||||
STEP(F2, a, b, c, d, e, words[63], 0xca62c1d6);
|
||||
STEP(F2, a, b, c, d, e, words[64], 0xca62c1d6);
|
||||
STEP(F2, a, b, c, d, e, words[65], 0xca62c1d6);
|
||||
STEP(F2, a, b, c, d, e, words[66], 0xca62c1d6);
|
||||
STEP(F2, a, b, c, d, e, words[67], 0xca62c1d6);
|
||||
STEP(F2, a, b, c, d, e, words[68], 0xca62c1d6);
|
||||
STEP(F2, a, b, c, d, e, words[69], 0xca62c1d6);
|
||||
STEP(F2, a, b, c, d, e, words[70], 0xca62c1d6);
|
||||
STEP(F2, a, b, c, d, e, words[71], 0xca62c1d6);
|
||||
STEP(F2, a, b, c, d, e, words[72], 0xca62c1d6);
|
||||
STEP(F2, a, b, c, d, e, words[73], 0xca62c1d6);
|
||||
STEP(F2, a, b, c, d, e, words[74], 0xca62c1d6);
|
||||
STEP(F2, a, b, c, d, e, words[75], 0xca62c1d6);
|
||||
STEP(F2, a, b, c, d, e, words[76], 0xca62c1d6);
|
||||
STEP(F2, a, b, c, d, e, words[77], 0xca62c1d6);
|
||||
STEP(F2, a, b, c, d, e, words[78], 0xca62c1d6);
|
||||
STEP(F2, a, b, c, d, e, words[79], 0xca62c1d6);
|
||||
|
||||
a += saved_a;
|
||||
b += saved_b;
|
||||
c += saved_c;
|
||||
d += saved_d;
|
||||
e += saved_e;
|
||||
|
||||
p += 64;
|
||||
|
||||
} while (size -= 64);
|
||||
|
||||
ctx->a = a;
|
||||
ctx->b = b;
|
||||
ctx->c = c;
|
||||
ctx->d = d;
|
||||
ctx->e = e;
|
||||
|
||||
return p;
|
||||
}
|
||||
28
nginx/src/core/ngx_sha1.h
Normal file
28
nginx/src/core/ngx_sha1.h
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_SHA1_H_INCLUDED_
|
||||
#define _NGX_SHA1_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint64_t bytes;
|
||||
uint32_t a, b, c, d, e, f;
|
||||
u_char buffer[64];
|
||||
} ngx_sha1_t;
|
||||
|
||||
|
||||
void ngx_sha1_init(ngx_sha1_t *ctx);
|
||||
void ngx_sha1_update(ngx_sha1_t *ctx, const void *data, size_t size);
|
||||
void ngx_sha1_final(u_char result[20], ngx_sha1_t *ctx);
|
||||
|
||||
|
||||
#endif /* _NGX_SHA1_H_INCLUDED_ */
|
||||
310
nginx/src/core/ngx_shmtx.c
Normal file
310
nginx/src/core/ngx_shmtx.c
Normal file
|
|
@ -0,0 +1,310 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
#if (NGX_HAVE_ATOMIC_OPS)
|
||||
|
||||
|
||||
static void ngx_shmtx_wakeup(ngx_shmtx_t *mtx);
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_shmtx_create(ngx_shmtx_t *mtx, ngx_shmtx_sh_t *addr, u_char *name)
|
||||
{
|
||||
mtx->lock = &addr->lock;
|
||||
|
||||
if (mtx->spin == (ngx_uint_t) -1) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
mtx->spin = 2048;
|
||||
|
||||
#if (NGX_HAVE_POSIX_SEM)
|
||||
|
||||
mtx->wait = &addr->wait;
|
||||
|
||||
if (sem_init(&mtx->sem, 1, 0) == -1) {
|
||||
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_errno,
|
||||
"sem_init() failed");
|
||||
} else {
|
||||
mtx->semaphore = 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_shmtx_destroy(ngx_shmtx_t *mtx)
|
||||
{
|
||||
#if (NGX_HAVE_POSIX_SEM)
|
||||
|
||||
if (mtx->semaphore) {
|
||||
if (sem_destroy(&mtx->sem) == -1) {
|
||||
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_errno,
|
||||
"sem_destroy() failed");
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
ngx_uint_t
|
||||
ngx_shmtx_trylock(ngx_shmtx_t *mtx)
|
||||
{
|
||||
return (*mtx->lock == 0 && ngx_atomic_cmp_set(mtx->lock, 0, ngx_pid));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_shmtx_lock(ngx_shmtx_t *mtx)
|
||||
{
|
||||
ngx_uint_t i, n;
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, "shmtx lock");
|
||||
|
||||
for ( ;; ) {
|
||||
|
||||
if (*mtx->lock == 0 && ngx_atomic_cmp_set(mtx->lock, 0, ngx_pid)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ngx_ncpu > 1) {
|
||||
|
||||
for (n = 1; n < mtx->spin; n <<= 1) {
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
ngx_cpu_pause();
|
||||
}
|
||||
|
||||
if (*mtx->lock == 0
|
||||
&& ngx_atomic_cmp_set(mtx->lock, 0, ngx_pid))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if (NGX_HAVE_POSIX_SEM)
|
||||
|
||||
if (mtx->semaphore) {
|
||||
(void) ngx_atomic_fetch_add(mtx->wait, 1);
|
||||
|
||||
if (*mtx->lock == 0 && ngx_atomic_cmp_set(mtx->lock, 0, ngx_pid)) {
|
||||
(void) ngx_atomic_fetch_add(mtx->wait, -1);
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
|
||||
"shmtx wait %uA", *mtx->wait);
|
||||
|
||||
while (sem_wait(&mtx->sem) == -1) {
|
||||
ngx_err_t err;
|
||||
|
||||
err = ngx_errno;
|
||||
|
||||
if (err != NGX_EINTR) {
|
||||
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, err,
|
||||
"sem_wait() failed while waiting on shmtx");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
|
||||
"shmtx awoke");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
ngx_sched_yield();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_shmtx_unlock(ngx_shmtx_t *mtx)
|
||||
{
|
||||
if (mtx->spin != (ngx_uint_t) -1) {
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, "shmtx unlock");
|
||||
}
|
||||
|
||||
if (ngx_atomic_cmp_set(mtx->lock, ngx_pid, 0)) {
|
||||
ngx_shmtx_wakeup(mtx);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ngx_uint_t
|
||||
ngx_shmtx_force_unlock(ngx_shmtx_t *mtx, ngx_pid_t pid)
|
||||
{
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
|
||||
"shmtx forced unlock");
|
||||
|
||||
if (ngx_atomic_cmp_set(mtx->lock, pid, 0)) {
|
||||
ngx_shmtx_wakeup(mtx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_shmtx_wakeup(ngx_shmtx_t *mtx)
|
||||
{
|
||||
#if (NGX_HAVE_POSIX_SEM)
|
||||
ngx_atomic_uint_t wait;
|
||||
|
||||
if (!mtx->semaphore) {
|
||||
return;
|
||||
}
|
||||
|
||||
for ( ;; ) {
|
||||
|
||||
wait = *mtx->wait;
|
||||
|
||||
if ((ngx_atomic_int_t) wait <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ngx_atomic_cmp_set(mtx->wait, wait, wait - 1)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
|
||||
"shmtx wake %uA", wait);
|
||||
|
||||
if (sem_post(&mtx->sem) == -1) {
|
||||
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_errno,
|
||||
"sem_post() failed while wake shmtx");
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_shmtx_create(ngx_shmtx_t *mtx, ngx_shmtx_sh_t *addr, u_char *name)
|
||||
{
|
||||
if (mtx->name) {
|
||||
|
||||
if (ngx_strcmp(name, mtx->name) == 0) {
|
||||
mtx->name = name;
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
ngx_shmtx_destroy(mtx);
|
||||
}
|
||||
|
||||
mtx->fd = ngx_open_file(name, NGX_FILE_RDWR, NGX_FILE_CREATE_OR_OPEN,
|
||||
NGX_FILE_DEFAULT_ACCESS);
|
||||
|
||||
if (mtx->fd == NGX_INVALID_FILE) {
|
||||
ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno,
|
||||
ngx_open_file_n " \"%s\" failed", name);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (ngx_delete_file(name) == NGX_FILE_ERROR) {
|
||||
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_errno,
|
||||
ngx_delete_file_n " \"%s\" failed", name);
|
||||
}
|
||||
|
||||
mtx->name = name;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_shmtx_destroy(ngx_shmtx_t *mtx)
|
||||
{
|
||||
if (ngx_close_file(mtx->fd) == NGX_FILE_ERROR) {
|
||||
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_errno,
|
||||
ngx_close_file_n " \"%s\" failed", mtx->name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ngx_uint_t
|
||||
ngx_shmtx_trylock(ngx_shmtx_t *mtx)
|
||||
{
|
||||
ngx_err_t err;
|
||||
|
||||
err = ngx_trylock_fd(mtx->fd);
|
||||
|
||||
if (err == 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (err == NGX_EAGAIN) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if __osf__ /* Tru64 UNIX */
|
||||
|
||||
if (err == NGX_EACCES) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
ngx_log_abort(err, ngx_trylock_fd_n " %s failed", mtx->name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_shmtx_lock(ngx_shmtx_t *mtx)
|
||||
{
|
||||
ngx_err_t err;
|
||||
|
||||
err = ngx_lock_fd(mtx->fd);
|
||||
|
||||
if (err == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_log_abort(err, ngx_lock_fd_n " %s failed", mtx->name);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_shmtx_unlock(ngx_shmtx_t *mtx)
|
||||
{
|
||||
ngx_err_t err;
|
||||
|
||||
err = ngx_unlock_fd(mtx->fd);
|
||||
|
||||
if (err == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_log_abort(err, ngx_unlock_fd_n " %s failed", mtx->name);
|
||||
}
|
||||
|
||||
|
||||
ngx_uint_t
|
||||
ngx_shmtx_force_unlock(ngx_shmtx_t *mtx, ngx_pid_t pid)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
49
nginx/src/core/ngx_shmtx.h
Normal file
49
nginx/src/core/ngx_shmtx.h
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_SHMTX_H_INCLUDED_
|
||||
#define _NGX_SHMTX_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_atomic_t lock;
|
||||
#if (NGX_HAVE_POSIX_SEM)
|
||||
ngx_atomic_t wait;
|
||||
#endif
|
||||
} ngx_shmtx_sh_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
#if (NGX_HAVE_ATOMIC_OPS)
|
||||
ngx_atomic_t *lock;
|
||||
#if (NGX_HAVE_POSIX_SEM)
|
||||
ngx_atomic_t *wait;
|
||||
ngx_uint_t semaphore;
|
||||
sem_t sem;
|
||||
#endif
|
||||
#else
|
||||
ngx_fd_t fd;
|
||||
u_char *name;
|
||||
#endif
|
||||
ngx_uint_t spin;
|
||||
} ngx_shmtx_t;
|
||||
|
||||
|
||||
ngx_int_t ngx_shmtx_create(ngx_shmtx_t *mtx, ngx_shmtx_sh_t *addr,
|
||||
u_char *name);
|
||||
void ngx_shmtx_destroy(ngx_shmtx_t *mtx);
|
||||
ngx_uint_t ngx_shmtx_trylock(ngx_shmtx_t *mtx);
|
||||
void ngx_shmtx_lock(ngx_shmtx_t *mtx);
|
||||
void ngx_shmtx_unlock(ngx_shmtx_t *mtx);
|
||||
ngx_uint_t ngx_shmtx_force_unlock(ngx_shmtx_t *mtx, ngx_pid_t pid);
|
||||
|
||||
|
||||
#endif /* _NGX_SHMTX_H_INCLUDED_ */
|
||||
817
nginx/src/core/ngx_slab.c
Normal file
817
nginx/src/core/ngx_slab.c
Normal file
|
|
@ -0,0 +1,817 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
#define NGX_SLAB_PAGE_MASK 3
|
||||
#define NGX_SLAB_PAGE 0
|
||||
#define NGX_SLAB_BIG 1
|
||||
#define NGX_SLAB_EXACT 2
|
||||
#define NGX_SLAB_SMALL 3
|
||||
|
||||
#if (NGX_PTR_SIZE == 4)
|
||||
|
||||
#define NGX_SLAB_PAGE_FREE 0
|
||||
#define NGX_SLAB_PAGE_BUSY 0xffffffff
|
||||
#define NGX_SLAB_PAGE_START 0x80000000
|
||||
|
||||
#define NGX_SLAB_SHIFT_MASK 0x0000000f
|
||||
#define NGX_SLAB_MAP_MASK 0xffff0000
|
||||
#define NGX_SLAB_MAP_SHIFT 16
|
||||
|
||||
#define NGX_SLAB_BUSY 0xffffffff
|
||||
|
||||
#else /* (NGX_PTR_SIZE == 8) */
|
||||
|
||||
#define NGX_SLAB_PAGE_FREE 0
|
||||
#define NGX_SLAB_PAGE_BUSY 0xffffffffffffffff
|
||||
#define NGX_SLAB_PAGE_START 0x8000000000000000
|
||||
|
||||
#define NGX_SLAB_SHIFT_MASK 0x000000000000000f
|
||||
#define NGX_SLAB_MAP_MASK 0xffffffff00000000
|
||||
#define NGX_SLAB_MAP_SHIFT 32
|
||||
|
||||
#define NGX_SLAB_BUSY 0xffffffffffffffff
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#define ngx_slab_slots(pool) \
|
||||
(ngx_slab_page_t *) ((u_char *) (pool) + sizeof(ngx_slab_pool_t))
|
||||
|
||||
#define ngx_slab_page_type(page) ((page)->prev & NGX_SLAB_PAGE_MASK)
|
||||
|
||||
#define ngx_slab_page_prev(page) \
|
||||
(ngx_slab_page_t *) ((page)->prev & ~NGX_SLAB_PAGE_MASK)
|
||||
|
||||
#define ngx_slab_page_addr(pool, page) \
|
||||
((((page) - (pool)->pages) << ngx_pagesize_shift) \
|
||||
+ (uintptr_t) (pool)->start)
|
||||
|
||||
|
||||
#if (NGX_DEBUG_MALLOC)
|
||||
|
||||
#define ngx_slab_junk(p, size) ngx_memset(p, 0xA5, size)
|
||||
|
||||
#elif (NGX_HAVE_DEBUG_MALLOC)
|
||||
|
||||
#define ngx_slab_junk(p, size) \
|
||||
if (ngx_debug_malloc) ngx_memset(p, 0xA5, size)
|
||||
|
||||
#else
|
||||
|
||||
#define ngx_slab_junk(p, size)
|
||||
|
||||
#endif
|
||||
|
||||
static ngx_slab_page_t *ngx_slab_alloc_pages(ngx_slab_pool_t *pool,
|
||||
ngx_uint_t pages);
|
||||
static void ngx_slab_free_pages(ngx_slab_pool_t *pool, ngx_slab_page_t *page,
|
||||
ngx_uint_t pages);
|
||||
static void ngx_slab_error(ngx_slab_pool_t *pool, ngx_uint_t level,
|
||||
char *text);
|
||||
|
||||
|
||||
static ngx_uint_t ngx_slab_max_size;
|
||||
static ngx_uint_t ngx_slab_exact_size;
|
||||
static ngx_uint_t ngx_slab_exact_shift;
|
||||
|
||||
|
||||
void
|
||||
ngx_slab_sizes_init(void)
|
||||
{
|
||||
ngx_uint_t n;
|
||||
|
||||
ngx_slab_max_size = ngx_pagesize / 2;
|
||||
ngx_slab_exact_size = ngx_pagesize / (8 * sizeof(uintptr_t));
|
||||
for (n = ngx_slab_exact_size; n >>= 1; ngx_slab_exact_shift++) {
|
||||
/* void */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_slab_init(ngx_slab_pool_t *pool)
|
||||
{
|
||||
u_char *p;
|
||||
size_t size;
|
||||
ngx_int_t m;
|
||||
ngx_uint_t i, n, pages;
|
||||
ngx_slab_page_t *slots, *page;
|
||||
|
||||
pool->min_size = (size_t) 1 << pool->min_shift;
|
||||
|
||||
slots = ngx_slab_slots(pool);
|
||||
|
||||
p = (u_char *) slots;
|
||||
size = pool->end - p;
|
||||
|
||||
ngx_slab_junk(p, size);
|
||||
|
||||
n = ngx_pagesize_shift - pool->min_shift;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
/* only "next" is used in list head */
|
||||
slots[i].slab = 0;
|
||||
slots[i].next = &slots[i];
|
||||
slots[i].prev = 0;
|
||||
}
|
||||
|
||||
p += n * sizeof(ngx_slab_page_t);
|
||||
|
||||
pool->stats = (ngx_slab_stat_t *) p;
|
||||
ngx_memzero(pool->stats, n * sizeof(ngx_slab_stat_t));
|
||||
|
||||
p += n * sizeof(ngx_slab_stat_t);
|
||||
|
||||
size -= n * (sizeof(ngx_slab_page_t) + sizeof(ngx_slab_stat_t));
|
||||
|
||||
pages = (ngx_uint_t) (size / (ngx_pagesize + sizeof(ngx_slab_page_t)));
|
||||
|
||||
pool->pages = (ngx_slab_page_t *) p;
|
||||
ngx_memzero(pool->pages, pages * sizeof(ngx_slab_page_t));
|
||||
|
||||
page = pool->pages;
|
||||
|
||||
/* only "next" is used in list head */
|
||||
pool->free.slab = 0;
|
||||
pool->free.next = page;
|
||||
pool->free.prev = 0;
|
||||
|
||||
page->slab = pages;
|
||||
page->next = &pool->free;
|
||||
page->prev = (uintptr_t) &pool->free;
|
||||
|
||||
pool->start = ngx_align_ptr(p + pages * sizeof(ngx_slab_page_t),
|
||||
ngx_pagesize);
|
||||
|
||||
m = pages - (pool->end - pool->start) / ngx_pagesize;
|
||||
if (m > 0) {
|
||||
pages -= m;
|
||||
page->slab = pages;
|
||||
}
|
||||
|
||||
pool->last = pool->pages + pages;
|
||||
pool->pfree = pages;
|
||||
|
||||
pool->log_nomem = 1;
|
||||
pool->log_ctx = &pool->zero;
|
||||
pool->zero = '\0';
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
ngx_slab_alloc(ngx_slab_pool_t *pool, size_t size)
|
||||
{
|
||||
void *p;
|
||||
|
||||
ngx_shmtx_lock(&pool->mutex);
|
||||
|
||||
p = ngx_slab_alloc_locked(pool, size);
|
||||
|
||||
ngx_shmtx_unlock(&pool->mutex);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
ngx_slab_alloc_locked(ngx_slab_pool_t *pool, size_t size)
|
||||
{
|
||||
size_t s;
|
||||
uintptr_t p, m, mask, *bitmap;
|
||||
ngx_uint_t i, n, slot, shift, map;
|
||||
ngx_slab_page_t *page, *prev, *slots;
|
||||
|
||||
if (size > ngx_slab_max_size) {
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, ngx_cycle->log, 0,
|
||||
"slab alloc: %uz", size);
|
||||
|
||||
page = ngx_slab_alloc_pages(pool, (size >> ngx_pagesize_shift)
|
||||
+ ((size % ngx_pagesize) ? 1 : 0));
|
||||
if (page) {
|
||||
p = ngx_slab_page_addr(pool, page);
|
||||
|
||||
} else {
|
||||
p = 0;
|
||||
}
|
||||
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (size > pool->min_size) {
|
||||
shift = 1;
|
||||
for (s = size - 1; s >>= 1; shift++) { /* void */ }
|
||||
slot = shift - pool->min_shift;
|
||||
|
||||
} else {
|
||||
shift = pool->min_shift;
|
||||
slot = 0;
|
||||
}
|
||||
|
||||
pool->stats[slot].reqs++;
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, ngx_cycle->log, 0,
|
||||
"slab alloc: %uz slot: %ui", size, slot);
|
||||
|
||||
slots = ngx_slab_slots(pool);
|
||||
page = slots[slot].next;
|
||||
|
||||
if (page->next != page) {
|
||||
|
||||
if (shift < ngx_slab_exact_shift) {
|
||||
|
||||
bitmap = (uintptr_t *) ngx_slab_page_addr(pool, page);
|
||||
|
||||
map = (ngx_pagesize >> shift) / (8 * sizeof(uintptr_t));
|
||||
|
||||
for (n = 0; n < map; n++) {
|
||||
|
||||
if (bitmap[n] != NGX_SLAB_BUSY) {
|
||||
|
||||
for (m = 1, i = 0; m; m <<= 1, i++) {
|
||||
if (bitmap[n] & m) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bitmap[n] |= m;
|
||||
|
||||
i = (n * 8 * sizeof(uintptr_t) + i) << shift;
|
||||
|
||||
p = (uintptr_t) bitmap + i;
|
||||
|
||||
pool->stats[slot].used++;
|
||||
|
||||
if (bitmap[n] == NGX_SLAB_BUSY) {
|
||||
for (n = n + 1; n < map; n++) {
|
||||
if (bitmap[n] != NGX_SLAB_BUSY) {
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
prev = ngx_slab_page_prev(page);
|
||||
prev->next = page->next;
|
||||
page->next->prev = page->prev;
|
||||
|
||||
page->next = NULL;
|
||||
page->prev = NGX_SLAB_SMALL;
|
||||
}
|
||||
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else if (shift == ngx_slab_exact_shift) {
|
||||
|
||||
for (m = 1, i = 0; m; m <<= 1, i++) {
|
||||
if (page->slab & m) {
|
||||
continue;
|
||||
}
|
||||
|
||||
page->slab |= m;
|
||||
|
||||
if (page->slab == NGX_SLAB_BUSY) {
|
||||
prev = ngx_slab_page_prev(page);
|
||||
prev->next = page->next;
|
||||
page->next->prev = page->prev;
|
||||
|
||||
page->next = NULL;
|
||||
page->prev = NGX_SLAB_EXACT;
|
||||
}
|
||||
|
||||
p = ngx_slab_page_addr(pool, page) + (i << shift);
|
||||
|
||||
pool->stats[slot].used++;
|
||||
|
||||
goto done;
|
||||
}
|
||||
|
||||
} else { /* shift > ngx_slab_exact_shift */
|
||||
|
||||
mask = ((uintptr_t) 1 << (ngx_pagesize >> shift)) - 1;
|
||||
mask <<= NGX_SLAB_MAP_SHIFT;
|
||||
|
||||
for (m = (uintptr_t) 1 << NGX_SLAB_MAP_SHIFT, i = 0;
|
||||
m & mask;
|
||||
m <<= 1, i++)
|
||||
{
|
||||
if (page->slab & m) {
|
||||
continue;
|
||||
}
|
||||
|
||||
page->slab |= m;
|
||||
|
||||
if ((page->slab & NGX_SLAB_MAP_MASK) == mask) {
|
||||
prev = ngx_slab_page_prev(page);
|
||||
prev->next = page->next;
|
||||
page->next->prev = page->prev;
|
||||
|
||||
page->next = NULL;
|
||||
page->prev = NGX_SLAB_BIG;
|
||||
}
|
||||
|
||||
p = ngx_slab_page_addr(pool, page) + (i << shift);
|
||||
|
||||
pool->stats[slot].used++;
|
||||
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
ngx_slab_error(pool, NGX_LOG_ALERT, "ngx_slab_alloc(): page is busy");
|
||||
ngx_debug_point();
|
||||
}
|
||||
|
||||
page = ngx_slab_alloc_pages(pool, 1);
|
||||
|
||||
if (page) {
|
||||
if (shift < ngx_slab_exact_shift) {
|
||||
bitmap = (uintptr_t *) ngx_slab_page_addr(pool, page);
|
||||
|
||||
n = (ngx_pagesize >> shift) / ((1 << shift) * 8);
|
||||
|
||||
if (n == 0) {
|
||||
n = 1;
|
||||
}
|
||||
|
||||
/* "n" elements for bitmap, plus one requested */
|
||||
|
||||
for (i = 0; i < (n + 1) / (8 * sizeof(uintptr_t)); i++) {
|
||||
bitmap[i] = NGX_SLAB_BUSY;
|
||||
}
|
||||
|
||||
m = ((uintptr_t) 1 << ((n + 1) % (8 * sizeof(uintptr_t)))) - 1;
|
||||
bitmap[i] = m;
|
||||
|
||||
map = (ngx_pagesize >> shift) / (8 * sizeof(uintptr_t));
|
||||
|
||||
for (i = i + 1; i < map; i++) {
|
||||
bitmap[i] = 0;
|
||||
}
|
||||
|
||||
page->slab = shift;
|
||||
page->next = &slots[slot];
|
||||
page->prev = (uintptr_t) &slots[slot] | NGX_SLAB_SMALL;
|
||||
|
||||
slots[slot].next = page;
|
||||
|
||||
pool->stats[slot].total += (ngx_pagesize >> shift) - n;
|
||||
|
||||
p = ngx_slab_page_addr(pool, page) + (n << shift);
|
||||
|
||||
pool->stats[slot].used++;
|
||||
|
||||
goto done;
|
||||
|
||||
} else if (shift == ngx_slab_exact_shift) {
|
||||
|
||||
page->slab = 1;
|
||||
page->next = &slots[slot];
|
||||
page->prev = (uintptr_t) &slots[slot] | NGX_SLAB_EXACT;
|
||||
|
||||
slots[slot].next = page;
|
||||
|
||||
pool->stats[slot].total += 8 * sizeof(uintptr_t);
|
||||
|
||||
p = ngx_slab_page_addr(pool, page);
|
||||
|
||||
pool->stats[slot].used++;
|
||||
|
||||
goto done;
|
||||
|
||||
} else { /* shift > ngx_slab_exact_shift */
|
||||
|
||||
page->slab = ((uintptr_t) 1 << NGX_SLAB_MAP_SHIFT) | shift;
|
||||
page->next = &slots[slot];
|
||||
page->prev = (uintptr_t) &slots[slot] | NGX_SLAB_BIG;
|
||||
|
||||
slots[slot].next = page;
|
||||
|
||||
pool->stats[slot].total += ngx_pagesize >> shift;
|
||||
|
||||
p = ngx_slab_page_addr(pool, page);
|
||||
|
||||
pool->stats[slot].used++;
|
||||
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
p = 0;
|
||||
|
||||
pool->stats[slot].fails++;
|
||||
|
||||
done:
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, ngx_cycle->log, 0,
|
||||
"slab alloc: %p", (void *) p);
|
||||
|
||||
return (void *) p;
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
ngx_slab_calloc(ngx_slab_pool_t *pool, size_t size)
|
||||
{
|
||||
void *p;
|
||||
|
||||
ngx_shmtx_lock(&pool->mutex);
|
||||
|
||||
p = ngx_slab_calloc_locked(pool, size);
|
||||
|
||||
ngx_shmtx_unlock(&pool->mutex);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
ngx_slab_calloc_locked(ngx_slab_pool_t *pool, size_t size)
|
||||
{
|
||||
void *p;
|
||||
|
||||
p = ngx_slab_alloc_locked(pool, size);
|
||||
if (p) {
|
||||
ngx_memzero(p, size);
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_slab_free(ngx_slab_pool_t *pool, void *p)
|
||||
{
|
||||
ngx_shmtx_lock(&pool->mutex);
|
||||
|
||||
ngx_slab_free_locked(pool, p);
|
||||
|
||||
ngx_shmtx_unlock(&pool->mutex);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_slab_free_locked(ngx_slab_pool_t *pool, void *p)
|
||||
{
|
||||
size_t size;
|
||||
uintptr_t slab, m, *bitmap;
|
||||
ngx_uint_t i, n, type, slot, shift, map;
|
||||
ngx_slab_page_t *slots, *page;
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, ngx_cycle->log, 0, "slab free: %p", p);
|
||||
|
||||
if ((u_char *) p < pool->start || (u_char *) p > pool->end) {
|
||||
ngx_slab_error(pool, NGX_LOG_ALERT, "ngx_slab_free(): outside of pool");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
n = ((u_char *) p - pool->start) >> ngx_pagesize_shift;
|
||||
page = &pool->pages[n];
|
||||
slab = page->slab;
|
||||
type = ngx_slab_page_type(page);
|
||||
|
||||
switch (type) {
|
||||
|
||||
case NGX_SLAB_SMALL:
|
||||
|
||||
shift = slab & NGX_SLAB_SHIFT_MASK;
|
||||
size = (size_t) 1 << shift;
|
||||
|
||||
if ((uintptr_t) p & (size - 1)) {
|
||||
goto wrong_chunk;
|
||||
}
|
||||
|
||||
n = ((uintptr_t) p & (ngx_pagesize - 1)) >> shift;
|
||||
m = (uintptr_t) 1 << (n % (8 * sizeof(uintptr_t)));
|
||||
n /= 8 * sizeof(uintptr_t);
|
||||
bitmap = (uintptr_t *)
|
||||
((uintptr_t) p & ~((uintptr_t) ngx_pagesize - 1));
|
||||
|
||||
if (bitmap[n] & m) {
|
||||
slot = shift - pool->min_shift;
|
||||
|
||||
if (page->next == NULL) {
|
||||
slots = ngx_slab_slots(pool);
|
||||
|
||||
page->next = slots[slot].next;
|
||||
slots[slot].next = page;
|
||||
|
||||
page->prev = (uintptr_t) &slots[slot] | NGX_SLAB_SMALL;
|
||||
page->next->prev = (uintptr_t) page | NGX_SLAB_SMALL;
|
||||
}
|
||||
|
||||
bitmap[n] &= ~m;
|
||||
|
||||
n = (ngx_pagesize >> shift) / ((1 << shift) * 8);
|
||||
|
||||
if (n == 0) {
|
||||
n = 1;
|
||||
}
|
||||
|
||||
i = n / (8 * sizeof(uintptr_t));
|
||||
m = ((uintptr_t) 1 << (n % (8 * sizeof(uintptr_t)))) - 1;
|
||||
|
||||
if (bitmap[i] & ~m) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
map = (ngx_pagesize >> shift) / (8 * sizeof(uintptr_t));
|
||||
|
||||
for (i = i + 1; i < map; i++) {
|
||||
if (bitmap[i]) {
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
ngx_slab_free_pages(pool, page, 1);
|
||||
|
||||
pool->stats[slot].total -= (ngx_pagesize >> shift) - n;
|
||||
|
||||
goto done;
|
||||
}
|
||||
|
||||
goto chunk_already_free;
|
||||
|
||||
case NGX_SLAB_EXACT:
|
||||
|
||||
m = (uintptr_t) 1 <<
|
||||
(((uintptr_t) p & (ngx_pagesize - 1)) >> ngx_slab_exact_shift);
|
||||
size = ngx_slab_exact_size;
|
||||
|
||||
if ((uintptr_t) p & (size - 1)) {
|
||||
goto wrong_chunk;
|
||||
}
|
||||
|
||||
if (slab & m) {
|
||||
slot = ngx_slab_exact_shift - pool->min_shift;
|
||||
|
||||
if (slab == NGX_SLAB_BUSY) {
|
||||
slots = ngx_slab_slots(pool);
|
||||
|
||||
page->next = slots[slot].next;
|
||||
slots[slot].next = page;
|
||||
|
||||
page->prev = (uintptr_t) &slots[slot] | NGX_SLAB_EXACT;
|
||||
page->next->prev = (uintptr_t) page | NGX_SLAB_EXACT;
|
||||
}
|
||||
|
||||
page->slab &= ~m;
|
||||
|
||||
if (page->slab) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
ngx_slab_free_pages(pool, page, 1);
|
||||
|
||||
pool->stats[slot].total -= 8 * sizeof(uintptr_t);
|
||||
|
||||
goto done;
|
||||
}
|
||||
|
||||
goto chunk_already_free;
|
||||
|
||||
case NGX_SLAB_BIG:
|
||||
|
||||
shift = slab & NGX_SLAB_SHIFT_MASK;
|
||||
size = (size_t) 1 << shift;
|
||||
|
||||
if ((uintptr_t) p & (size - 1)) {
|
||||
goto wrong_chunk;
|
||||
}
|
||||
|
||||
m = (uintptr_t) 1 << ((((uintptr_t) p & (ngx_pagesize - 1)) >> shift)
|
||||
+ NGX_SLAB_MAP_SHIFT);
|
||||
|
||||
if (slab & m) {
|
||||
slot = shift - pool->min_shift;
|
||||
|
||||
if (page->next == NULL) {
|
||||
slots = ngx_slab_slots(pool);
|
||||
|
||||
page->next = slots[slot].next;
|
||||
slots[slot].next = page;
|
||||
|
||||
page->prev = (uintptr_t) &slots[slot] | NGX_SLAB_BIG;
|
||||
page->next->prev = (uintptr_t) page | NGX_SLAB_BIG;
|
||||
}
|
||||
|
||||
page->slab &= ~m;
|
||||
|
||||
if (page->slab & NGX_SLAB_MAP_MASK) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
ngx_slab_free_pages(pool, page, 1);
|
||||
|
||||
pool->stats[slot].total -= ngx_pagesize >> shift;
|
||||
|
||||
goto done;
|
||||
}
|
||||
|
||||
goto chunk_already_free;
|
||||
|
||||
case NGX_SLAB_PAGE:
|
||||
|
||||
if ((uintptr_t) p & (ngx_pagesize - 1)) {
|
||||
goto wrong_chunk;
|
||||
}
|
||||
|
||||
if (!(slab & NGX_SLAB_PAGE_START)) {
|
||||
ngx_slab_error(pool, NGX_LOG_ALERT,
|
||||
"ngx_slab_free(): page is already free");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (slab == NGX_SLAB_PAGE_BUSY) {
|
||||
ngx_slab_error(pool, NGX_LOG_ALERT,
|
||||
"ngx_slab_free(): pointer to wrong page");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
size = slab & ~NGX_SLAB_PAGE_START;
|
||||
|
||||
ngx_slab_free_pages(pool, page, size);
|
||||
|
||||
ngx_slab_junk(p, size << ngx_pagesize_shift);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* not reached */
|
||||
|
||||
return;
|
||||
|
||||
done:
|
||||
|
||||
pool->stats[slot].used--;
|
||||
|
||||
ngx_slab_junk(p, size);
|
||||
|
||||
return;
|
||||
|
||||
wrong_chunk:
|
||||
|
||||
ngx_slab_error(pool, NGX_LOG_ALERT,
|
||||
"ngx_slab_free(): pointer to wrong chunk");
|
||||
|
||||
goto fail;
|
||||
|
||||
chunk_already_free:
|
||||
|
||||
ngx_slab_error(pool, NGX_LOG_ALERT,
|
||||
"ngx_slab_free(): chunk is already free");
|
||||
|
||||
fail:
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
static ngx_slab_page_t *
|
||||
ngx_slab_alloc_pages(ngx_slab_pool_t *pool, ngx_uint_t pages)
|
||||
{
|
||||
ngx_slab_page_t *page, *p;
|
||||
|
||||
for (page = pool->free.next; page != &pool->free; page = page->next) {
|
||||
|
||||
if (page->slab >= pages) {
|
||||
|
||||
if (page->slab > pages) {
|
||||
page[page->slab - 1].prev = (uintptr_t) &page[pages];
|
||||
|
||||
page[pages].slab = page->slab - pages;
|
||||
page[pages].next = page->next;
|
||||
page[pages].prev = page->prev;
|
||||
|
||||
p = (ngx_slab_page_t *) page->prev;
|
||||
p->next = &page[pages];
|
||||
page->next->prev = (uintptr_t) &page[pages];
|
||||
|
||||
} else {
|
||||
p = (ngx_slab_page_t *) page->prev;
|
||||
p->next = page->next;
|
||||
page->next->prev = page->prev;
|
||||
}
|
||||
|
||||
page->slab = pages | NGX_SLAB_PAGE_START;
|
||||
page->next = NULL;
|
||||
page->prev = NGX_SLAB_PAGE;
|
||||
|
||||
pool->pfree -= pages;
|
||||
|
||||
if (--pages == 0) {
|
||||
return page;
|
||||
}
|
||||
|
||||
for (p = page + 1; pages; pages--) {
|
||||
p->slab = NGX_SLAB_PAGE_BUSY;
|
||||
p->next = NULL;
|
||||
p->prev = NGX_SLAB_PAGE;
|
||||
p++;
|
||||
}
|
||||
|
||||
return page;
|
||||
}
|
||||
}
|
||||
|
||||
if (pool->log_nomem) {
|
||||
ngx_slab_error(pool, NGX_LOG_CRIT,
|
||||
"ngx_slab_alloc() failed: no memory");
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_slab_free_pages(ngx_slab_pool_t *pool, ngx_slab_page_t *page,
|
||||
ngx_uint_t pages)
|
||||
{
|
||||
ngx_slab_page_t *prev, *join;
|
||||
|
||||
pool->pfree += pages;
|
||||
|
||||
page->slab = pages--;
|
||||
|
||||
if (pages) {
|
||||
ngx_memzero(&page[1], pages * sizeof(ngx_slab_page_t));
|
||||
}
|
||||
|
||||
if (page->next) {
|
||||
prev = ngx_slab_page_prev(page);
|
||||
prev->next = page->next;
|
||||
page->next->prev = page->prev;
|
||||
}
|
||||
|
||||
join = page + page->slab;
|
||||
|
||||
if (join < pool->last) {
|
||||
|
||||
if (ngx_slab_page_type(join) == NGX_SLAB_PAGE) {
|
||||
|
||||
if (join->next != NULL) {
|
||||
pages += join->slab;
|
||||
page->slab += join->slab;
|
||||
|
||||
prev = ngx_slab_page_prev(join);
|
||||
prev->next = join->next;
|
||||
join->next->prev = join->prev;
|
||||
|
||||
join->slab = NGX_SLAB_PAGE_FREE;
|
||||
join->next = NULL;
|
||||
join->prev = NGX_SLAB_PAGE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (page > pool->pages) {
|
||||
join = page - 1;
|
||||
|
||||
if (ngx_slab_page_type(join) == NGX_SLAB_PAGE) {
|
||||
|
||||
if (join->slab == NGX_SLAB_PAGE_FREE) {
|
||||
join = ngx_slab_page_prev(join);
|
||||
}
|
||||
|
||||
if (join->next != NULL) {
|
||||
pages += join->slab;
|
||||
join->slab += page->slab;
|
||||
|
||||
prev = ngx_slab_page_prev(join);
|
||||
prev->next = join->next;
|
||||
join->next->prev = join->prev;
|
||||
|
||||
page->slab = NGX_SLAB_PAGE_FREE;
|
||||
page->next = NULL;
|
||||
page->prev = NGX_SLAB_PAGE;
|
||||
|
||||
page = join;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pages) {
|
||||
page[pages].prev = (uintptr_t) page;
|
||||
}
|
||||
|
||||
page->prev = (uintptr_t) &pool->free;
|
||||
page->next = pool->free.next;
|
||||
|
||||
page->next->prev = (uintptr_t) page;
|
||||
|
||||
pool->free.next = page;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_slab_error(ngx_slab_pool_t *pool, ngx_uint_t level, char *text)
|
||||
{
|
||||
ngx_log_error(level, ngx_cycle->log, 0, "%s%s", text, pool->log_ctx);
|
||||
}
|
||||
72
nginx/src/core/ngx_slab.h
Normal file
72
nginx/src/core/ngx_slab.h
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_SLAB_H_INCLUDED_
|
||||
#define _NGX_SLAB_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
typedef struct ngx_slab_page_s ngx_slab_page_t;
|
||||
|
||||
struct ngx_slab_page_s {
|
||||
uintptr_t slab;
|
||||
ngx_slab_page_t *next;
|
||||
uintptr_t prev;
|
||||
};
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_uint_t total;
|
||||
ngx_uint_t used;
|
||||
|
||||
ngx_uint_t reqs;
|
||||
ngx_uint_t fails;
|
||||
} ngx_slab_stat_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_shmtx_sh_t lock;
|
||||
|
||||
size_t min_size;
|
||||
size_t min_shift;
|
||||
|
||||
ngx_slab_page_t *pages;
|
||||
ngx_slab_page_t *last;
|
||||
ngx_slab_page_t free;
|
||||
|
||||
ngx_slab_stat_t *stats;
|
||||
ngx_uint_t pfree;
|
||||
|
||||
u_char *start;
|
||||
u_char *end;
|
||||
|
||||
ngx_shmtx_t mutex;
|
||||
|
||||
u_char *log_ctx;
|
||||
u_char zero;
|
||||
|
||||
unsigned log_nomem:1;
|
||||
|
||||
void *data;
|
||||
void *addr;
|
||||
} ngx_slab_pool_t;
|
||||
|
||||
|
||||
void ngx_slab_sizes_init(void);
|
||||
void ngx_slab_init(ngx_slab_pool_t *pool);
|
||||
void *ngx_slab_alloc(ngx_slab_pool_t *pool, size_t size);
|
||||
void *ngx_slab_alloc_locked(ngx_slab_pool_t *pool, size_t size);
|
||||
void *ngx_slab_calloc(ngx_slab_pool_t *pool, size_t size);
|
||||
void *ngx_slab_calloc_locked(ngx_slab_pool_t *pool, size_t size);
|
||||
void ngx_slab_free(ngx_slab_pool_t *pool, void *p);
|
||||
void ngx_slab_free_locked(ngx_slab_pool_t *pool, void *p);
|
||||
|
||||
|
||||
#endif /* _NGX_SLAB_H_INCLUDED_ */
|
||||
53
nginx/src/core/ngx_spinlock.c
Normal file
53
nginx/src/core/ngx_spinlock.c
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
void
|
||||
ngx_spinlock(ngx_atomic_t *lock, ngx_atomic_int_t value, ngx_uint_t spin)
|
||||
{
|
||||
|
||||
#if (NGX_HAVE_ATOMIC_OPS)
|
||||
|
||||
ngx_uint_t i, n;
|
||||
|
||||
for ( ;; ) {
|
||||
|
||||
if (*lock == 0 && ngx_atomic_cmp_set(lock, 0, value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ngx_ncpu > 1) {
|
||||
|
||||
for (n = 1; n < spin; n <<= 1) {
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
ngx_cpu_pause();
|
||||
}
|
||||
|
||||
if (*lock == 0 && ngx_atomic_cmp_set(lock, 0, value)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ngx_sched_yield();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#if (NGX_THREADS)
|
||||
|
||||
#error ngx_spinlock() or ngx_atomic_cmp_set() are not defined !
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
2130
nginx/src/core/ngx_string.c
Normal file
2130
nginx/src/core/ngx_string.c
Normal file
File diff suppressed because it is too large
Load diff
239
nginx/src/core/ngx_string.h
Normal file
239
nginx/src/core/ngx_string.h
Normal file
|
|
@ -0,0 +1,239 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_STRING_H_INCLUDED_
|
||||
#define _NGX_STRING_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
typedef struct {
|
||||
size_t len;
|
||||
u_char *data;
|
||||
} ngx_str_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_str_t key;
|
||||
ngx_str_t value;
|
||||
} ngx_keyval_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
unsigned len:28;
|
||||
|
||||
unsigned valid:1;
|
||||
unsigned no_cacheable:1;
|
||||
unsigned not_found:1;
|
||||
unsigned escape:1;
|
||||
|
||||
u_char *data;
|
||||
} ngx_variable_value_t;
|
||||
|
||||
|
||||
#define ngx_string(str) { sizeof(str) - 1, (u_char *) str }
|
||||
#define ngx_null_string { 0, NULL }
|
||||
#define ngx_str_set(str, text) \
|
||||
(str)->len = sizeof(text) - 1; (str)->data = (u_char *) text
|
||||
#define ngx_str_null(str) (str)->len = 0; (str)->data = NULL
|
||||
|
||||
|
||||
#define ngx_tolower(c) (u_char) ((c >= 'A' && c <= 'Z') ? (c | 0x20) : c)
|
||||
#define ngx_toupper(c) (u_char) ((c >= 'a' && c <= 'z') ? (c & ~0x20) : c)
|
||||
|
||||
void ngx_strlow(u_char *dst, u_char *src, size_t n);
|
||||
|
||||
|
||||
#define ngx_strncmp(s1, s2, n) strncmp((const char *) s1, (const char *) s2, n)
|
||||
|
||||
|
||||
/* msvc and icc7 compile strcmp() to inline loop */
|
||||
#define ngx_strcmp(s1, s2) strcmp((const char *) s1, (const char *) s2)
|
||||
|
||||
|
||||
#define ngx_strstr(s1, s2) strstr((const char *) s1, (const char *) s2)
|
||||
#define ngx_strlen(s) strlen((const char *) s)
|
||||
|
||||
size_t ngx_strnlen(u_char *p, size_t n);
|
||||
|
||||
#define ngx_strchr(s1, c) strchr((const char *) s1, (int) c)
|
||||
|
||||
static ngx_inline u_char *
|
||||
ngx_strlchr(u_char *p, u_char *last, u_char c)
|
||||
{
|
||||
while (p < last) {
|
||||
|
||||
if (*p == c) {
|
||||
return p;
|
||||
}
|
||||
|
||||
p++;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* msvc and icc7 compile memset() to the inline "rep stos"
|
||||
* while ZeroMemory() and bzero() are the calls.
|
||||
* icc7 may also inline several mov's of a zeroed register for small blocks.
|
||||
*/
|
||||
#define ngx_memzero(buf, n) (void) memset(buf, 0, n)
|
||||
#define ngx_memset(buf, c, n) (void) memset(buf, c, n)
|
||||
|
||||
void ngx_explicit_memzero(void *buf, size_t n);
|
||||
|
||||
|
||||
#if (NGX_MEMCPY_LIMIT)
|
||||
|
||||
void *ngx_memcpy(void *dst, const void *src, size_t n);
|
||||
#define ngx_cpymem(dst, src, n) (((u_char *) ngx_memcpy(dst, src, n)) + (n))
|
||||
|
||||
#else
|
||||
|
||||
/*
|
||||
* gcc3, msvc, and icc7 compile memcpy() to the inline "rep movs".
|
||||
* gcc3 compiles memcpy(d, s, 4) to the inline "mov"es.
|
||||
* icc8 compile memcpy(d, s, 4) to the inline "mov"es or XMM moves.
|
||||
*/
|
||||
#define ngx_memcpy(dst, src, n) (void) memcpy(dst, src, n)
|
||||
#define ngx_cpymem(dst, src, n) (((u_char *) memcpy(dst, src, n)) + (n))
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if ( __INTEL_COMPILER >= 800 )
|
||||
|
||||
/*
|
||||
* the simple inline cycle copies the variable length strings up to 16
|
||||
* bytes faster than icc8 autodetecting _intel_fast_memcpy()
|
||||
*/
|
||||
|
||||
static ngx_inline u_char *
|
||||
ngx_copy(u_char *dst, u_char *src, size_t len)
|
||||
{
|
||||
if (len < 17) {
|
||||
|
||||
while (len) {
|
||||
*dst++ = *src++;
|
||||
len--;
|
||||
}
|
||||
|
||||
return dst;
|
||||
|
||||
} else {
|
||||
return ngx_cpymem(dst, src, len);
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define ngx_copy ngx_cpymem
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#define ngx_memmove(dst, src, n) (void) memmove(dst, src, n)
|
||||
#define ngx_movemem(dst, src, n) (((u_char *) memmove(dst, src, n)) + (n))
|
||||
|
||||
|
||||
/* msvc and icc7 compile memcmp() to the inline loop */
|
||||
#define ngx_memcmp(s1, s2, n) memcmp(s1, s2, n)
|
||||
|
||||
|
||||
u_char *ngx_cpystrn(u_char *dst, u_char *src, size_t n);
|
||||
u_char *ngx_pstrdup(ngx_pool_t *pool, ngx_str_t *src);
|
||||
u_char * ngx_cdecl ngx_sprintf(u_char *buf, const char *fmt, ...);
|
||||
u_char * ngx_cdecl ngx_snprintf(u_char *buf, size_t max, const char *fmt, ...);
|
||||
u_char * ngx_cdecl ngx_slprintf(u_char *buf, u_char *last, const char *fmt,
|
||||
...);
|
||||
u_char *ngx_vslprintf(u_char *buf, u_char *last, const char *fmt, va_list args);
|
||||
#define ngx_vsnprintf(buf, max, fmt, args) \
|
||||
ngx_vslprintf(buf, buf + (max), fmt, args)
|
||||
|
||||
ngx_int_t ngx_strcasecmp(u_char *s1, u_char *s2);
|
||||
ngx_int_t ngx_strncasecmp(u_char *s1, u_char *s2, size_t n);
|
||||
|
||||
u_char *ngx_strnstr(u_char *s1, char *s2, size_t n);
|
||||
|
||||
u_char *ngx_strstrn(u_char *s1, char *s2, size_t n);
|
||||
u_char *ngx_strcasestrn(u_char *s1, char *s2, size_t n);
|
||||
u_char *ngx_strlcasestrn(u_char *s1, u_char *last, u_char *s2, size_t n);
|
||||
|
||||
ngx_int_t ngx_rstrncmp(u_char *s1, u_char *s2, size_t n);
|
||||
ngx_int_t ngx_rstrncasecmp(u_char *s1, u_char *s2, size_t n);
|
||||
ngx_int_t ngx_memn2cmp(u_char *s1, u_char *s2, size_t n1, size_t n2);
|
||||
ngx_int_t ngx_dns_strcmp(u_char *s1, u_char *s2);
|
||||
ngx_int_t ngx_filename_cmp(u_char *s1, u_char *s2, size_t n);
|
||||
|
||||
ngx_int_t ngx_atoi(u_char *line, size_t n);
|
||||
ngx_int_t ngx_atofp(u_char *line, size_t n, size_t point);
|
||||
ssize_t ngx_atosz(u_char *line, size_t n);
|
||||
off_t ngx_atoof(u_char *line, size_t n);
|
||||
time_t ngx_atotm(u_char *line, size_t n);
|
||||
ngx_int_t ngx_hextoi(u_char *line, size_t n);
|
||||
|
||||
u_char *ngx_hex_dump(u_char *dst, u_char *src, size_t len);
|
||||
|
||||
|
||||
#define ngx_base64_encoded_length(len) (((len + 2) / 3) * 4)
|
||||
#define ngx_base64_decoded_length(len) (((len + 3) / 4) * 3)
|
||||
|
||||
void ngx_encode_base64(ngx_str_t *dst, ngx_str_t *src);
|
||||
void ngx_encode_base64url(ngx_str_t *dst, ngx_str_t *src);
|
||||
ngx_int_t ngx_decode_base64(ngx_str_t *dst, ngx_str_t *src);
|
||||
ngx_int_t ngx_decode_base64url(ngx_str_t *dst, ngx_str_t *src);
|
||||
|
||||
uint32_t ngx_utf8_decode(u_char **p, size_t n);
|
||||
size_t ngx_utf8_length(u_char *p, size_t n);
|
||||
u_char *ngx_utf8_cpystrn(u_char *dst, u_char *src, size_t n, size_t len);
|
||||
|
||||
|
||||
#define NGX_ESCAPE_URI 0
|
||||
#define NGX_ESCAPE_ARGS 1
|
||||
#define NGX_ESCAPE_URI_COMPONENT 2
|
||||
#define NGX_ESCAPE_HTML 3
|
||||
#define NGX_ESCAPE_REFRESH 4
|
||||
#define NGX_ESCAPE_MEMCACHED 5
|
||||
#define NGX_ESCAPE_MAIL_AUTH 6
|
||||
#define NGX_ESCAPE_MAIL_XTEXT 7
|
||||
|
||||
#define NGX_UNESCAPE_URI 1
|
||||
#define NGX_UNESCAPE_REDIRECT 2
|
||||
|
||||
uintptr_t ngx_escape_uri(u_char *dst, u_char *src, size_t size,
|
||||
ngx_uint_t type);
|
||||
void ngx_unescape_uri(u_char **dst, u_char **src, size_t size, ngx_uint_t type);
|
||||
uintptr_t ngx_escape_html(u_char *dst, u_char *src, size_t size);
|
||||
uintptr_t ngx_escape_json(u_char *dst, u_char *src, size_t size);
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_rbtree_node_t node;
|
||||
ngx_str_t str;
|
||||
} ngx_str_node_t;
|
||||
|
||||
|
||||
void ngx_str_rbtree_insert_value(ngx_rbtree_node_t *temp,
|
||||
ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
|
||||
ngx_str_node_t *ngx_str_rbtree_lookup(ngx_rbtree_t *rbtree, ngx_str_t *name,
|
||||
uint32_t hash);
|
||||
|
||||
|
||||
void ngx_sort(void *base, size_t n, size_t size,
|
||||
ngx_int_t (*cmp)(const void *, const void *));
|
||||
#define ngx_qsort qsort
|
||||
|
||||
|
||||
#define ngx_value_helper(n) #n
|
||||
#define ngx_value(n) ngx_value_helper(n)
|
||||
|
||||
|
||||
#endif /* _NGX_STRING_H_INCLUDED_ */
|
||||
410
nginx/src/core/ngx_syslog.c
Normal file
410
nginx/src/core/ngx_syslog.c
Normal file
|
|
@ -0,0 +1,410 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_event.h>
|
||||
|
||||
|
||||
#define NGX_SYSLOG_MAX_STR \
|
||||
NGX_MAX_ERROR_STR + sizeof("<255>Jan 01 00:00:00 ") - 1 \
|
||||
+ (NGX_MAXHOSTNAMELEN - 1) + 1 /* space */ \
|
||||
+ 32 /* tag */ + 2 /* colon, space */
|
||||
|
||||
|
||||
static char *ngx_syslog_parse_args(ngx_conf_t *cf, ngx_syslog_peer_t *peer);
|
||||
static ngx_int_t ngx_syslog_init_peer(ngx_syslog_peer_t *peer);
|
||||
static void ngx_syslog_cleanup(void *data);
|
||||
static u_char *ngx_syslog_log_error(ngx_log_t *log, u_char *buf, size_t len);
|
||||
|
||||
|
||||
static char *facilities[] = {
|
||||
"kern", "user", "mail", "daemon", "auth", "intern", "lpr", "news", "uucp",
|
||||
"clock", "authpriv", "ftp", "ntp", "audit", "alert", "cron", "local0",
|
||||
"local1", "local2", "local3", "local4", "local5", "local6", "local7",
|
||||
NULL
|
||||
};
|
||||
|
||||
/* note 'error/warn' like in nginx.conf, not 'err/warning' */
|
||||
static char *severities[] = {
|
||||
"emerg", "alert", "crit", "error", "warn", "notice", "info", "debug", NULL
|
||||
};
|
||||
|
||||
static ngx_log_t ngx_syslog_dummy_log;
|
||||
static ngx_event_t ngx_syslog_dummy_event;
|
||||
|
||||
|
||||
char *
|
||||
ngx_syslog_process_conf(ngx_conf_t *cf, ngx_syslog_peer_t *peer)
|
||||
{
|
||||
ngx_pool_cleanup_t *cln;
|
||||
|
||||
peer->facility = NGX_CONF_UNSET_UINT;
|
||||
peer->severity = NGX_CONF_UNSET_UINT;
|
||||
|
||||
if (ngx_syslog_parse_args(cf, peer) != NGX_CONF_OK) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
if (peer->server.sockaddr == NULL) {
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"no syslog server specified");
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
if (peer->facility == NGX_CONF_UNSET_UINT) {
|
||||
peer->facility = 23; /* local7 */
|
||||
}
|
||||
|
||||
if (peer->severity == NGX_CONF_UNSET_UINT) {
|
||||
peer->severity = 6; /* info */
|
||||
}
|
||||
|
||||
if (peer->tag.data == NULL) {
|
||||
ngx_str_set(&peer->tag, "nginx");
|
||||
}
|
||||
|
||||
peer->hostname = &cf->cycle->hostname;
|
||||
peer->logp = &cf->cycle->new_log;
|
||||
|
||||
peer->conn.fd = (ngx_socket_t) -1;
|
||||
|
||||
peer->conn.read = &ngx_syslog_dummy_event;
|
||||
peer->conn.write = &ngx_syslog_dummy_event;
|
||||
|
||||
ngx_syslog_dummy_event.log = &ngx_syslog_dummy_log;
|
||||
|
||||
cln = ngx_pool_cleanup_add(cf->pool, 0);
|
||||
if (cln == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
cln->data = peer;
|
||||
cln->handler = ngx_syslog_cleanup;
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
ngx_syslog_parse_args(ngx_conf_t *cf, ngx_syslog_peer_t *peer)
|
||||
{
|
||||
u_char *p, *comma, c;
|
||||
size_t len;
|
||||
ngx_str_t *value;
|
||||
ngx_url_t u;
|
||||
ngx_uint_t i;
|
||||
|
||||
value = cf->args->elts;
|
||||
|
||||
p = value[1].data + sizeof("syslog:") - 1;
|
||||
|
||||
for ( ;; ) {
|
||||
comma = (u_char *) ngx_strchr(p, ',');
|
||||
|
||||
if (comma != NULL) {
|
||||
len = comma - p;
|
||||
*comma = '\0';
|
||||
|
||||
} else {
|
||||
len = value[1].data + value[1].len - p;
|
||||
}
|
||||
|
||||
if (ngx_strncmp(p, "server=", 7) == 0) {
|
||||
|
||||
if (peer->server.sockaddr != NULL) {
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"duplicate syslog \"server\"");
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
ngx_memzero(&u, sizeof(ngx_url_t));
|
||||
|
||||
u.url.data = p + 7;
|
||||
u.url.len = len - 7;
|
||||
u.default_port = 514;
|
||||
|
||||
if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
|
||||
if (u.err) {
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"%s in syslog server \"%V\"",
|
||||
u.err, &u.url);
|
||||
}
|
||||
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
peer->server = u.addrs[0];
|
||||
|
||||
} else if (ngx_strncmp(p, "facility=", 9) == 0) {
|
||||
|
||||
if (peer->facility != NGX_CONF_UNSET_UINT) {
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"duplicate syslog \"facility\"");
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
for (i = 0; facilities[i] != NULL; i++) {
|
||||
|
||||
if (ngx_strcmp(p + 9, facilities[i]) == 0) {
|
||||
peer->facility = i;
|
||||
goto next;
|
||||
}
|
||||
}
|
||||
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"unknown syslog facility \"%s\"", p + 9);
|
||||
return NGX_CONF_ERROR;
|
||||
|
||||
} else if (ngx_strncmp(p, "severity=", 9) == 0) {
|
||||
|
||||
if (peer->severity != NGX_CONF_UNSET_UINT) {
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"duplicate syslog \"severity\"");
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
for (i = 0; severities[i] != NULL; i++) {
|
||||
|
||||
if (ngx_strcmp(p + 9, severities[i]) == 0) {
|
||||
peer->severity = i;
|
||||
goto next;
|
||||
}
|
||||
}
|
||||
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"unknown syslog severity \"%s\"", p + 9);
|
||||
return NGX_CONF_ERROR;
|
||||
|
||||
} else if (ngx_strncmp(p, "tag=", 4) == 0) {
|
||||
|
||||
if (peer->tag.data != NULL) {
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"duplicate syslog \"tag\"");
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* RFC 3164: the TAG is a string of ABNF alphanumeric characters
|
||||
* that MUST NOT exceed 32 characters.
|
||||
*/
|
||||
if (len - 4 > 32) {
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"syslog tag length exceeds 32");
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
for (i = 4; i < len; i++) {
|
||||
c = ngx_tolower(p[i]);
|
||||
|
||||
if (c < '0' || (c > '9' && c < 'a' && c != '_') || c > 'z') {
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"syslog \"tag\" only allows "
|
||||
"alphanumeric characters "
|
||||
"and underscore");
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
peer->tag.data = p + 4;
|
||||
peer->tag.len = len - 4;
|
||||
|
||||
} else if (len == 10 && ngx_strncmp(p, "nohostname", 10) == 0) {
|
||||
peer->nohostname = 1;
|
||||
|
||||
} else {
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"unknown syslog parameter \"%s\"", p);
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
next:
|
||||
|
||||
if (comma == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
p = comma + 1;
|
||||
}
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
|
||||
u_char *
|
||||
ngx_syslog_add_header(ngx_syslog_peer_t *peer, u_char *buf)
|
||||
{
|
||||
ngx_uint_t pri;
|
||||
|
||||
pri = peer->facility * 8 + peer->severity;
|
||||
|
||||
if (peer->nohostname) {
|
||||
return ngx_sprintf(buf, "<%ui>%V %V: ", pri, &ngx_cached_syslog_time,
|
||||
&peer->tag);
|
||||
}
|
||||
|
||||
return ngx_sprintf(buf, "<%ui>%V %V %V: ", pri, &ngx_cached_syslog_time,
|
||||
peer->hostname, &peer->tag);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_syslog_writer(ngx_log_t *log, ngx_uint_t level, u_char *buf,
|
||||
size_t len)
|
||||
{
|
||||
u_char *p, msg[NGX_SYSLOG_MAX_STR];
|
||||
ngx_uint_t head_len;
|
||||
ngx_syslog_peer_t *peer;
|
||||
|
||||
peer = log->wdata;
|
||||
|
||||
if (peer->busy) {
|
||||
return;
|
||||
}
|
||||
|
||||
peer->busy = 1;
|
||||
peer->severity = level - 1;
|
||||
|
||||
p = ngx_syslog_add_header(peer, msg);
|
||||
head_len = p - msg;
|
||||
|
||||
len -= NGX_LINEFEED_SIZE;
|
||||
|
||||
if (len > NGX_SYSLOG_MAX_STR - head_len) {
|
||||
len = NGX_SYSLOG_MAX_STR - head_len;
|
||||
}
|
||||
|
||||
p = ngx_snprintf(p, len, "%s", buf);
|
||||
|
||||
(void) ngx_syslog_send(peer, msg, p - msg);
|
||||
|
||||
peer->busy = 0;
|
||||
}
|
||||
|
||||
|
||||
ssize_t
|
||||
ngx_syslog_send(ngx_syslog_peer_t *peer, u_char *buf, size_t len)
|
||||
{
|
||||
ssize_t n;
|
||||
|
||||
if (peer->log.handler == NULL) {
|
||||
peer->log = *peer->logp;
|
||||
peer->log.handler = ngx_syslog_log_error;
|
||||
peer->log.data = peer;
|
||||
peer->log.action = "logging to syslog";
|
||||
}
|
||||
|
||||
if (peer->conn.fd == (ngx_socket_t) -1) {
|
||||
if (ngx_syslog_init_peer(peer) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (ngx_send) {
|
||||
n = ngx_send(&peer->conn, buf, len);
|
||||
|
||||
} else {
|
||||
/* event module has not yet set ngx_io */
|
||||
n = ngx_os_io.send(&peer->conn, buf, len);
|
||||
}
|
||||
|
||||
if (n == NGX_ERROR) {
|
||||
|
||||
if (ngx_close_socket(peer->conn.fd) == -1) {
|
||||
ngx_log_error(NGX_LOG_ALERT, &peer->log, ngx_socket_errno,
|
||||
ngx_close_socket_n " failed");
|
||||
}
|
||||
|
||||
peer->conn.fd = (ngx_socket_t) -1;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_syslog_init_peer(ngx_syslog_peer_t *peer)
|
||||
{
|
||||
ngx_socket_t fd;
|
||||
|
||||
fd = ngx_socket(peer->server.sockaddr->sa_family, SOCK_DGRAM, 0);
|
||||
if (fd == (ngx_socket_t) -1) {
|
||||
ngx_log_error(NGX_LOG_ALERT, &peer->log, ngx_socket_errno,
|
||||
ngx_socket_n " failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (ngx_nonblocking(fd) == -1) {
|
||||
ngx_log_error(NGX_LOG_ALERT, &peer->log, ngx_socket_errno,
|
||||
ngx_nonblocking_n " failed");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (connect(fd, peer->server.sockaddr, peer->server.socklen) == -1) {
|
||||
ngx_log_error(NGX_LOG_ALERT, &peer->log, ngx_socket_errno,
|
||||
"connect() failed");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
peer->conn.fd = fd;
|
||||
peer->conn.log = &peer->log;
|
||||
|
||||
/* UDP sockets are always ready to write */
|
||||
peer->conn.write->ready = 1;
|
||||
|
||||
return NGX_OK;
|
||||
|
||||
failed:
|
||||
|
||||
if (ngx_close_socket(fd) == -1) {
|
||||
ngx_log_error(NGX_LOG_ALERT, &peer->log, ngx_socket_errno,
|
||||
ngx_close_socket_n " failed");
|
||||
}
|
||||
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_syslog_cleanup(void *data)
|
||||
{
|
||||
ngx_syslog_peer_t *peer = data;
|
||||
|
||||
/* prevents further use of this peer */
|
||||
peer->busy = 1;
|
||||
|
||||
if (peer->conn.fd == (ngx_socket_t) -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ngx_close_socket(peer->conn.fd) == -1) {
|
||||
ngx_log_error(NGX_LOG_ALERT, &peer->log, ngx_socket_errno,
|
||||
ngx_close_socket_n " failed");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static u_char *
|
||||
ngx_syslog_log_error(ngx_log_t *log, u_char *buf, size_t len)
|
||||
{
|
||||
u_char *p;
|
||||
ngx_syslog_peer_t *peer;
|
||||
|
||||
p = buf;
|
||||
|
||||
if (log->action) {
|
||||
p = ngx_snprintf(buf, len, " while %s", log->action);
|
||||
len -= p - buf;
|
||||
}
|
||||
|
||||
peer = log->data;
|
||||
|
||||
if (peer) {
|
||||
p = ngx_snprintf(p, len, ", server: %V", &peer->server.name);
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
36
nginx/src/core/ngx_syslog.h
Normal file
36
nginx/src/core/ngx_syslog.h
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_SYSLOG_H_INCLUDED_
|
||||
#define _NGX_SYSLOG_H_INCLUDED_
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_uint_t facility;
|
||||
ngx_uint_t severity;
|
||||
ngx_str_t tag;
|
||||
|
||||
ngx_str_t *hostname;
|
||||
|
||||
ngx_addr_t server;
|
||||
ngx_connection_t conn;
|
||||
|
||||
ngx_log_t log;
|
||||
ngx_log_t *logp;
|
||||
|
||||
unsigned busy:1;
|
||||
unsigned nohostname:1;
|
||||
} ngx_syslog_peer_t;
|
||||
|
||||
|
||||
char *ngx_syslog_process_conf(ngx_conf_t *cf, ngx_syslog_peer_t *peer);
|
||||
u_char *ngx_syslog_add_header(ngx_syslog_peer_t *peer, u_char *buf);
|
||||
void ngx_syslog_writer(ngx_log_t *log, ngx_uint_t level, u_char *buf,
|
||||
size_t len);
|
||||
ssize_t ngx_syslog_send(ngx_syslog_peer_t *peer, u_char *buf, size_t len);
|
||||
|
||||
|
||||
#endif /* _NGX_SYSLOG_H_INCLUDED_ */
|
||||
641
nginx/src/core/ngx_thread_pool.c
Normal file
641
nginx/src/core/ngx_thread_pool.c
Normal file
|
|
@ -0,0 +1,641 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Nginx, Inc.
|
||||
* Copyright (C) Valentin V. Bartenev
|
||||
* Copyright (C) Ruslan Ermilov
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_thread_pool.h>
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_array_t pools;
|
||||
} ngx_thread_pool_conf_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_thread_task_t *first;
|
||||
ngx_thread_task_t **last;
|
||||
} ngx_thread_pool_queue_t;
|
||||
|
||||
#define ngx_thread_pool_queue_init(q) \
|
||||
(q)->first = NULL; \
|
||||
(q)->last = &(q)->first
|
||||
|
||||
|
||||
struct ngx_thread_pool_s {
|
||||
ngx_thread_mutex_t mtx;
|
||||
ngx_thread_pool_queue_t queue;
|
||||
ngx_int_t waiting;
|
||||
ngx_thread_cond_t cond;
|
||||
|
||||
ngx_log_t *log;
|
||||
|
||||
ngx_str_t name;
|
||||
ngx_uint_t threads;
|
||||
ngx_int_t max_queue;
|
||||
|
||||
u_char *file;
|
||||
ngx_uint_t line;
|
||||
};
|
||||
|
||||
|
||||
static ngx_int_t ngx_thread_pool_init(ngx_thread_pool_t *tp, ngx_log_t *log,
|
||||
ngx_pool_t *pool);
|
||||
static void ngx_thread_pool_destroy(ngx_thread_pool_t *tp);
|
||||
static void ngx_thread_pool_exit_handler(void *data, ngx_log_t *log);
|
||||
|
||||
static void *ngx_thread_pool_cycle(void *data);
|
||||
static void ngx_thread_pool_handler(ngx_event_t *ev);
|
||||
|
||||
static char *ngx_thread_pool(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
|
||||
|
||||
static void *ngx_thread_pool_create_conf(ngx_cycle_t *cycle);
|
||||
static char *ngx_thread_pool_init_conf(ngx_cycle_t *cycle, void *conf);
|
||||
|
||||
static ngx_int_t ngx_thread_pool_init_worker(ngx_cycle_t *cycle);
|
||||
static void ngx_thread_pool_exit_worker(ngx_cycle_t *cycle);
|
||||
|
||||
|
||||
static ngx_command_t ngx_thread_pool_commands[] = {
|
||||
|
||||
{ ngx_string("thread_pool"),
|
||||
NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE23,
|
||||
ngx_thread_pool,
|
||||
0,
|
||||
0,
|
||||
NULL },
|
||||
|
||||
ngx_null_command
|
||||
};
|
||||
|
||||
|
||||
static ngx_core_module_t ngx_thread_pool_module_ctx = {
|
||||
ngx_string("thread_pool"),
|
||||
ngx_thread_pool_create_conf,
|
||||
ngx_thread_pool_init_conf
|
||||
};
|
||||
|
||||
|
||||
ngx_module_t ngx_thread_pool_module = {
|
||||
NGX_MODULE_V1,
|
||||
&ngx_thread_pool_module_ctx, /* module context */
|
||||
ngx_thread_pool_commands, /* module directives */
|
||||
NGX_CORE_MODULE, /* module type */
|
||||
NULL, /* init master */
|
||||
NULL, /* init module */
|
||||
ngx_thread_pool_init_worker, /* init process */
|
||||
NULL, /* init thread */
|
||||
NULL, /* exit thread */
|
||||
ngx_thread_pool_exit_worker, /* exit process */
|
||||
NULL, /* exit master */
|
||||
NGX_MODULE_V1_PADDING
|
||||
};
|
||||
|
||||
|
||||
static ngx_str_t ngx_thread_pool_default = ngx_string("default");
|
||||
|
||||
static ngx_uint_t ngx_thread_pool_task_id;
|
||||
static ngx_atomic_t ngx_thread_pool_done_lock;
|
||||
static ngx_thread_pool_queue_t ngx_thread_pool_done;
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_thread_pool_init(ngx_thread_pool_t *tp, ngx_log_t *log, ngx_pool_t *pool)
|
||||
{
|
||||
int err;
|
||||
pthread_t tid;
|
||||
ngx_uint_t n;
|
||||
pthread_attr_t attr;
|
||||
|
||||
if (ngx_notify == NULL) {
|
||||
ngx_log_error(NGX_LOG_ALERT, log, 0,
|
||||
"the configured event method cannot be used with thread pools");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_thread_pool_queue_init(&tp->queue);
|
||||
|
||||
if (ngx_thread_mutex_create(&tp->mtx, log) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (ngx_thread_cond_create(&tp->cond, log) != NGX_OK) {
|
||||
(void) ngx_thread_mutex_destroy(&tp->mtx, log);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
tp->log = log;
|
||||
|
||||
err = pthread_attr_init(&attr);
|
||||
if (err) {
|
||||
ngx_log_error(NGX_LOG_ALERT, log, err,
|
||||
"pthread_attr_init() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||
if (err) {
|
||||
ngx_log_error(NGX_LOG_ALERT, log, err,
|
||||
"pthread_attr_setdetachstate() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
#if 0
|
||||
err = pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN);
|
||||
if (err) {
|
||||
ngx_log_error(NGX_LOG_ALERT, log, err,
|
||||
"pthread_attr_setstacksize() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
for (n = 0; n < tp->threads; n++) {
|
||||
err = pthread_create(&tid, &attr, ngx_thread_pool_cycle, tp);
|
||||
if (err) {
|
||||
ngx_log_error(NGX_LOG_ALERT, log, err,
|
||||
"pthread_create() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
(void) pthread_attr_destroy(&attr);
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_thread_pool_destroy(ngx_thread_pool_t *tp)
|
||||
{
|
||||
ngx_uint_t n;
|
||||
ngx_thread_task_t task;
|
||||
volatile ngx_uint_t lock;
|
||||
|
||||
ngx_memzero(&task, sizeof(ngx_thread_task_t));
|
||||
|
||||
task.handler = ngx_thread_pool_exit_handler;
|
||||
task.ctx = (void *) &lock;
|
||||
|
||||
for (n = 0; n < tp->threads; n++) {
|
||||
lock = 1;
|
||||
|
||||
if (ngx_thread_task_post(tp, &task) != NGX_OK) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (lock) {
|
||||
ngx_sched_yield();
|
||||
}
|
||||
|
||||
task.event.active = 0;
|
||||
}
|
||||
|
||||
(void) ngx_thread_cond_destroy(&tp->cond, tp->log);
|
||||
|
||||
(void) ngx_thread_mutex_destroy(&tp->mtx, tp->log);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_thread_pool_exit_handler(void *data, ngx_log_t *log)
|
||||
{
|
||||
ngx_uint_t *lock = data;
|
||||
|
||||
*lock = 0;
|
||||
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
|
||||
ngx_thread_task_t *
|
||||
ngx_thread_task_alloc(ngx_pool_t *pool, size_t size)
|
||||
{
|
||||
ngx_thread_task_t *task;
|
||||
|
||||
task = ngx_pcalloc(pool, sizeof(ngx_thread_task_t) + size);
|
||||
if (task == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
task->ctx = task + 1;
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_thread_task_post(ngx_thread_pool_t *tp, ngx_thread_task_t *task)
|
||||
{
|
||||
if (task->event.active) {
|
||||
ngx_log_error(NGX_LOG_ALERT, tp->log, 0,
|
||||
"task #%ui already active", task->id);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (ngx_thread_mutex_lock(&tp->mtx, tp->log) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (tp->waiting >= tp->max_queue) {
|
||||
(void) ngx_thread_mutex_unlock(&tp->mtx, tp->log);
|
||||
|
||||
ngx_log_error(NGX_LOG_ERR, tp->log, 0,
|
||||
"thread pool \"%V\" queue overflow: %i tasks waiting",
|
||||
&tp->name, tp->waiting);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
task->event.active = 1;
|
||||
|
||||
task->id = ngx_thread_pool_task_id++;
|
||||
task->next = NULL;
|
||||
|
||||
if (ngx_thread_cond_signal(&tp->cond, tp->log) != NGX_OK) {
|
||||
(void) ngx_thread_mutex_unlock(&tp->mtx, tp->log);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
*tp->queue.last = task;
|
||||
tp->queue.last = &task->next;
|
||||
|
||||
tp->waiting++;
|
||||
|
||||
(void) ngx_thread_mutex_unlock(&tp->mtx, tp->log);
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_CORE, tp->log, 0,
|
||||
"task #%ui added to thread pool \"%V\"",
|
||||
task->id, &tp->name);
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
ngx_thread_pool_cycle(void *data)
|
||||
{
|
||||
ngx_thread_pool_t *tp = data;
|
||||
|
||||
int err;
|
||||
sigset_t set;
|
||||
ngx_thread_task_t *task;
|
||||
|
||||
#if 0
|
||||
ngx_time_update();
|
||||
#endif
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_CORE, tp->log, 0,
|
||||
"thread in pool \"%V\" started", &tp->name);
|
||||
|
||||
sigfillset(&set);
|
||||
|
||||
sigdelset(&set, SIGILL);
|
||||
sigdelset(&set, SIGFPE);
|
||||
sigdelset(&set, SIGSEGV);
|
||||
sigdelset(&set, SIGBUS);
|
||||
|
||||
err = pthread_sigmask(SIG_BLOCK, &set, NULL);
|
||||
if (err) {
|
||||
ngx_log_error(NGX_LOG_ALERT, tp->log, err, "pthread_sigmask() failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for ( ;; ) {
|
||||
if (ngx_thread_mutex_lock(&tp->mtx, tp->log) != NGX_OK) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* the number may become negative */
|
||||
tp->waiting--;
|
||||
|
||||
while (tp->queue.first == NULL) {
|
||||
if (ngx_thread_cond_wait(&tp->cond, &tp->mtx, tp->log)
|
||||
!= NGX_OK)
|
||||
{
|
||||
(void) ngx_thread_mutex_unlock(&tp->mtx, tp->log);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
task = tp->queue.first;
|
||||
tp->queue.first = task->next;
|
||||
|
||||
if (tp->queue.first == NULL) {
|
||||
tp->queue.last = &tp->queue.first;
|
||||
}
|
||||
|
||||
if (ngx_thread_mutex_unlock(&tp->mtx, tp->log) != NGX_OK) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if 0
|
||||
ngx_time_update();
|
||||
#endif
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_CORE, tp->log, 0,
|
||||
"run task #%ui in thread pool \"%V\"",
|
||||
task->id, &tp->name);
|
||||
|
||||
task->handler(task->ctx, tp->log);
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_CORE, tp->log, 0,
|
||||
"complete task #%ui in thread pool \"%V\"",
|
||||
task->id, &tp->name);
|
||||
|
||||
task->next = NULL;
|
||||
|
||||
ngx_spinlock(&ngx_thread_pool_done_lock, 1, 2048);
|
||||
|
||||
*ngx_thread_pool_done.last = task;
|
||||
ngx_thread_pool_done.last = &task->next;
|
||||
|
||||
ngx_memory_barrier();
|
||||
|
||||
ngx_unlock(&ngx_thread_pool_done_lock);
|
||||
|
||||
(void) ngx_notify(ngx_thread_pool_handler);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_thread_pool_handler(ngx_event_t *ev)
|
||||
{
|
||||
ngx_event_t *event;
|
||||
ngx_thread_task_t *task;
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_CORE, ev->log, 0, "thread pool handler");
|
||||
|
||||
ngx_spinlock(&ngx_thread_pool_done_lock, 1, 2048);
|
||||
|
||||
task = ngx_thread_pool_done.first;
|
||||
ngx_thread_pool_done.first = NULL;
|
||||
ngx_thread_pool_done.last = &ngx_thread_pool_done.first;
|
||||
|
||||
ngx_memory_barrier();
|
||||
|
||||
ngx_unlock(&ngx_thread_pool_done_lock);
|
||||
|
||||
while (task) {
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_CORE, ev->log, 0,
|
||||
"run completion handler for task #%ui", task->id);
|
||||
|
||||
event = &task->event;
|
||||
task = task->next;
|
||||
|
||||
event->complete = 1;
|
||||
event->active = 0;
|
||||
|
||||
event->handler(event);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
ngx_thread_pool_create_conf(ngx_cycle_t *cycle)
|
||||
{
|
||||
ngx_thread_pool_conf_t *tcf;
|
||||
|
||||
tcf = ngx_pcalloc(cycle->pool, sizeof(ngx_thread_pool_conf_t));
|
||||
if (tcf == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ngx_array_init(&tcf->pools, cycle->pool, 4,
|
||||
sizeof(ngx_thread_pool_t *))
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return tcf;
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
ngx_thread_pool_init_conf(ngx_cycle_t *cycle, void *conf)
|
||||
{
|
||||
ngx_thread_pool_conf_t *tcf = conf;
|
||||
|
||||
ngx_uint_t i;
|
||||
ngx_thread_pool_t **tpp;
|
||||
|
||||
tpp = tcf->pools.elts;
|
||||
|
||||
for (i = 0; i < tcf->pools.nelts; i++) {
|
||||
|
||||
if (tpp[i]->threads) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tpp[i]->name.len == ngx_thread_pool_default.len
|
||||
&& ngx_strncmp(tpp[i]->name.data, ngx_thread_pool_default.data,
|
||||
ngx_thread_pool_default.len)
|
||||
== 0)
|
||||
{
|
||||
tpp[i]->threads = 32;
|
||||
tpp[i]->max_queue = 65536;
|
||||
continue;
|
||||
}
|
||||
|
||||
ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
|
||||
"unknown thread pool \"%V\" in %s:%ui",
|
||||
&tpp[i]->name, tpp[i]->file, tpp[i]->line);
|
||||
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
ngx_thread_pool(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
||||
{
|
||||
ngx_str_t *value;
|
||||
ngx_uint_t i;
|
||||
ngx_thread_pool_t *tp;
|
||||
|
||||
value = cf->args->elts;
|
||||
|
||||
tp = ngx_thread_pool_add(cf, &value[1]);
|
||||
|
||||
if (tp == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
if (tp->threads) {
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"duplicate thread pool \"%V\"", &tp->name);
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
tp->max_queue = 65536;
|
||||
|
||||
for (i = 2; i < cf->args->nelts; i++) {
|
||||
|
||||
if (ngx_strncmp(value[i].data, "threads=", 8) == 0) {
|
||||
|
||||
tp->threads = ngx_atoi(value[i].data + 8, value[i].len - 8);
|
||||
|
||||
if (tp->threads == (ngx_uint_t) NGX_ERROR || tp->threads == 0) {
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"invalid threads value \"%V\"", &value[i]);
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ngx_strncmp(value[i].data, "max_queue=", 10) == 0) {
|
||||
|
||||
tp->max_queue = ngx_atoi(value[i].data + 10, value[i].len - 10);
|
||||
|
||||
if (tp->max_queue == NGX_ERROR) {
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"invalid max_queue value \"%V\"", &value[i]);
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (tp->threads == 0) {
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"\"%V\" must have \"threads\" parameter",
|
||||
&cmd->name);
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
|
||||
ngx_thread_pool_t *
|
||||
ngx_thread_pool_add(ngx_conf_t *cf, ngx_str_t *name)
|
||||
{
|
||||
ngx_thread_pool_t *tp, **tpp;
|
||||
ngx_thread_pool_conf_t *tcf;
|
||||
|
||||
if (name == NULL) {
|
||||
name = &ngx_thread_pool_default;
|
||||
}
|
||||
|
||||
tp = ngx_thread_pool_get(cf->cycle, name);
|
||||
|
||||
if (tp) {
|
||||
return tp;
|
||||
}
|
||||
|
||||
tp = ngx_pcalloc(cf->pool, sizeof(ngx_thread_pool_t));
|
||||
if (tp == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tp->name = *name;
|
||||
tp->file = cf->conf_file->file.name.data;
|
||||
tp->line = cf->conf_file->line;
|
||||
|
||||
tcf = (ngx_thread_pool_conf_t *) ngx_get_conf(cf->cycle->conf_ctx,
|
||||
ngx_thread_pool_module);
|
||||
|
||||
tpp = ngx_array_push(&tcf->pools);
|
||||
if (tpp == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*tpp = tp;
|
||||
|
||||
return tp;
|
||||
}
|
||||
|
||||
|
||||
ngx_thread_pool_t *
|
||||
ngx_thread_pool_get(ngx_cycle_t *cycle, ngx_str_t *name)
|
||||
{
|
||||
ngx_uint_t i;
|
||||
ngx_thread_pool_t **tpp;
|
||||
ngx_thread_pool_conf_t *tcf;
|
||||
|
||||
tcf = (ngx_thread_pool_conf_t *) ngx_get_conf(cycle->conf_ctx,
|
||||
ngx_thread_pool_module);
|
||||
|
||||
tpp = tcf->pools.elts;
|
||||
|
||||
for (i = 0; i < tcf->pools.nelts; i++) {
|
||||
|
||||
if (tpp[i]->name.len == name->len
|
||||
&& ngx_strncmp(tpp[i]->name.data, name->data, name->len) == 0)
|
||||
{
|
||||
return tpp[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_thread_pool_init_worker(ngx_cycle_t *cycle)
|
||||
{
|
||||
ngx_uint_t i;
|
||||
ngx_thread_pool_t **tpp;
|
||||
ngx_thread_pool_conf_t *tcf;
|
||||
|
||||
if (ngx_process != NGX_PROCESS_WORKER
|
||||
&& ngx_process != NGX_PROCESS_SINGLE)
|
||||
{
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
tcf = (ngx_thread_pool_conf_t *) ngx_get_conf(cycle->conf_ctx,
|
||||
ngx_thread_pool_module);
|
||||
|
||||
if (tcf == NULL) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
ngx_thread_pool_queue_init(&ngx_thread_pool_done);
|
||||
|
||||
tpp = tcf->pools.elts;
|
||||
|
||||
for (i = 0; i < tcf->pools.nelts; i++) {
|
||||
if (ngx_thread_pool_init(tpp[i], cycle->log, cycle->pool) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_thread_pool_exit_worker(ngx_cycle_t *cycle)
|
||||
{
|
||||
ngx_uint_t i;
|
||||
ngx_thread_pool_t **tpp;
|
||||
ngx_thread_pool_conf_t *tcf;
|
||||
|
||||
if (ngx_process != NGX_PROCESS_WORKER
|
||||
&& ngx_process != NGX_PROCESS_SINGLE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
tcf = (ngx_thread_pool_conf_t *) ngx_get_conf(cycle->conf_ctx,
|
||||
ngx_thread_pool_module);
|
||||
|
||||
if (tcf == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
tpp = tcf->pools.elts;
|
||||
|
||||
for (i = 0; i < tcf->pools.nelts; i++) {
|
||||
ngx_thread_pool_destroy(tpp[i]);
|
||||
}
|
||||
}
|
||||
36
nginx/src/core/ngx_thread_pool.h
Normal file
36
nginx/src/core/ngx_thread_pool.h
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Nginx, Inc.
|
||||
* Copyright (C) Valentin V. Bartenev
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_THREAD_POOL_H_INCLUDED_
|
||||
#define _NGX_THREAD_POOL_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_event.h>
|
||||
|
||||
|
||||
struct ngx_thread_task_s {
|
||||
ngx_thread_task_t *next;
|
||||
ngx_uint_t id;
|
||||
void *ctx;
|
||||
void (*handler)(void *data, ngx_log_t *log);
|
||||
ngx_event_t event;
|
||||
};
|
||||
|
||||
|
||||
typedef struct ngx_thread_pool_s ngx_thread_pool_t;
|
||||
|
||||
|
||||
ngx_thread_pool_t *ngx_thread_pool_add(ngx_conf_t *cf, ngx_str_t *name);
|
||||
ngx_thread_pool_t *ngx_thread_pool_get(ngx_cycle_t *cycle, ngx_str_t *name);
|
||||
|
||||
ngx_thread_task_t *ngx_thread_task_alloc(ngx_pool_t *pool, size_t size);
|
||||
ngx_int_t ngx_thread_task_post(ngx_thread_pool_t *tp, ngx_thread_task_t *task);
|
||||
|
||||
|
||||
#endif /* _NGX_THREAD_POOL_H_INCLUDED_ */
|
||||
460
nginx/src/core/ngx_times.c
Normal file
460
nginx/src/core/ngx_times.c
Normal file
|
|
@ -0,0 +1,460 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
static ngx_msec_t ngx_monotonic_time(time_t sec, ngx_uint_t msec);
|
||||
|
||||
|
||||
/*
|
||||
* The time may be updated by signal handler or by several threads.
|
||||
* The time update operations are rare and require to hold the ngx_time_lock.
|
||||
* The time read operations are frequent, so they are lock-free and get time
|
||||
* values and strings from the current slot. Thus thread may get the corrupted
|
||||
* values only if it is preempted while copying and then it is not scheduled
|
||||
* to run more than NGX_TIME_SLOTS seconds.
|
||||
*/
|
||||
|
||||
#define NGX_TIME_SLOTS 64
|
||||
|
||||
static ngx_uint_t slot;
|
||||
static ngx_atomic_t ngx_time_lock;
|
||||
|
||||
volatile ngx_msec_t ngx_current_msec;
|
||||
volatile ngx_time_t *ngx_cached_time;
|
||||
volatile ngx_str_t ngx_cached_err_log_time;
|
||||
volatile ngx_str_t ngx_cached_http_time;
|
||||
volatile ngx_str_t ngx_cached_http_log_time;
|
||||
volatile ngx_str_t ngx_cached_http_log_iso8601;
|
||||
volatile ngx_str_t ngx_cached_syslog_time;
|
||||
|
||||
#if !(NGX_WIN32)
|
||||
|
||||
/*
|
||||
* localtime() and localtime_r() are not Async-Signal-Safe functions, therefore,
|
||||
* they must not be called by a signal handler, so we use the cached
|
||||
* GMT offset value. Fortunately the value is changed only two times a year.
|
||||
*/
|
||||
|
||||
static ngx_int_t cached_gmtoff;
|
||||
#endif
|
||||
|
||||
static ngx_time_t cached_time[NGX_TIME_SLOTS];
|
||||
static u_char cached_err_log_time[NGX_TIME_SLOTS]
|
||||
[sizeof("1970/09/28 12:00:00")];
|
||||
static u_char cached_http_time[NGX_TIME_SLOTS]
|
||||
[sizeof("Mon, 28 Sep 1970 06:00:00 GMT")];
|
||||
static u_char cached_http_log_time[NGX_TIME_SLOTS]
|
||||
[sizeof("28/Sep/1970:12:00:00 +0600")];
|
||||
static u_char cached_http_log_iso8601[NGX_TIME_SLOTS]
|
||||
[sizeof("1970-09-28T12:00:00+06:00")];
|
||||
static u_char cached_syslog_time[NGX_TIME_SLOTS]
|
||||
[sizeof("Sep 28 12:00:00")];
|
||||
|
||||
|
||||
static char *week[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
|
||||
static char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
||||
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
|
||||
|
||||
void
|
||||
ngx_time_init(void)
|
||||
{
|
||||
ngx_cached_err_log_time.len = sizeof("1970/09/28 12:00:00") - 1;
|
||||
ngx_cached_http_time.len = sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1;
|
||||
ngx_cached_http_log_time.len = sizeof("28/Sep/1970:12:00:00 +0600") - 1;
|
||||
ngx_cached_http_log_iso8601.len = sizeof("1970-09-28T12:00:00+06:00") - 1;
|
||||
ngx_cached_syslog_time.len = sizeof("Sep 28 12:00:00") - 1;
|
||||
|
||||
ngx_cached_time = &cached_time[0];
|
||||
|
||||
ngx_time_update();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_time_update(void)
|
||||
{
|
||||
u_char *p0, *p1, *p2, *p3, *p4;
|
||||
ngx_tm_t tm, gmt;
|
||||
time_t sec;
|
||||
ngx_uint_t msec;
|
||||
ngx_time_t *tp;
|
||||
struct timeval tv;
|
||||
|
||||
if (!ngx_trylock(&ngx_time_lock)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_gettimeofday(&tv);
|
||||
|
||||
sec = tv.tv_sec;
|
||||
msec = tv.tv_usec / 1000;
|
||||
|
||||
ngx_current_msec = ngx_monotonic_time(sec, msec);
|
||||
|
||||
tp = &cached_time[slot];
|
||||
|
||||
if (tp->sec == sec) {
|
||||
tp->msec = msec;
|
||||
ngx_unlock(&ngx_time_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
if (slot == NGX_TIME_SLOTS - 1) {
|
||||
slot = 0;
|
||||
} else {
|
||||
slot++;
|
||||
}
|
||||
|
||||
tp = &cached_time[slot];
|
||||
|
||||
tp->sec = sec;
|
||||
tp->msec = msec;
|
||||
|
||||
ngx_gmtime(sec, &gmt);
|
||||
|
||||
|
||||
p0 = &cached_http_time[slot][0];
|
||||
|
||||
(void) ngx_sprintf(p0, "%s, %02d %s %4d %02d:%02d:%02d GMT",
|
||||
week[gmt.ngx_tm_wday], gmt.ngx_tm_mday,
|
||||
months[gmt.ngx_tm_mon - 1], gmt.ngx_tm_year,
|
||||
gmt.ngx_tm_hour, gmt.ngx_tm_min, gmt.ngx_tm_sec);
|
||||
|
||||
#if (NGX_HAVE_GETTIMEZONE)
|
||||
|
||||
tp->gmtoff = ngx_gettimezone();
|
||||
ngx_gmtime(sec + tp->gmtoff * 60, &tm);
|
||||
|
||||
#elif (NGX_HAVE_GMTOFF)
|
||||
|
||||
ngx_localtime(sec, &tm);
|
||||
cached_gmtoff = (ngx_int_t) (tm.ngx_tm_gmtoff / 60);
|
||||
tp->gmtoff = cached_gmtoff;
|
||||
|
||||
#else
|
||||
|
||||
ngx_localtime(sec, &tm);
|
||||
cached_gmtoff = ngx_timezone(tm.ngx_tm_isdst);
|
||||
tp->gmtoff = cached_gmtoff;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
p1 = &cached_err_log_time[slot][0];
|
||||
|
||||
(void) ngx_sprintf(p1, "%4d/%02d/%02d %02d:%02d:%02d",
|
||||
tm.ngx_tm_year, tm.ngx_tm_mon,
|
||||
tm.ngx_tm_mday, tm.ngx_tm_hour,
|
||||
tm.ngx_tm_min, tm.ngx_tm_sec);
|
||||
|
||||
|
||||
p2 = &cached_http_log_time[slot][0];
|
||||
|
||||
(void) ngx_sprintf(p2, "%02d/%s/%d:%02d:%02d:%02d %c%02i%02i",
|
||||
tm.ngx_tm_mday, months[tm.ngx_tm_mon - 1],
|
||||
tm.ngx_tm_year, tm.ngx_tm_hour,
|
||||
tm.ngx_tm_min, tm.ngx_tm_sec,
|
||||
tp->gmtoff < 0 ? '-' : '+',
|
||||
ngx_abs(tp->gmtoff / 60), ngx_abs(tp->gmtoff % 60));
|
||||
|
||||
p3 = &cached_http_log_iso8601[slot][0];
|
||||
|
||||
(void) ngx_sprintf(p3, "%4d-%02d-%02dT%02d:%02d:%02d%c%02i:%02i",
|
||||
tm.ngx_tm_year, tm.ngx_tm_mon,
|
||||
tm.ngx_tm_mday, tm.ngx_tm_hour,
|
||||
tm.ngx_tm_min, tm.ngx_tm_sec,
|
||||
tp->gmtoff < 0 ? '-' : '+',
|
||||
ngx_abs(tp->gmtoff / 60), ngx_abs(tp->gmtoff % 60));
|
||||
|
||||
p4 = &cached_syslog_time[slot][0];
|
||||
|
||||
(void) ngx_sprintf(p4, "%s %2d %02d:%02d:%02d",
|
||||
months[tm.ngx_tm_mon - 1], tm.ngx_tm_mday,
|
||||
tm.ngx_tm_hour, tm.ngx_tm_min, tm.ngx_tm_sec);
|
||||
|
||||
ngx_memory_barrier();
|
||||
|
||||
ngx_cached_time = tp;
|
||||
ngx_cached_http_time.data = p0;
|
||||
ngx_cached_err_log_time.data = p1;
|
||||
ngx_cached_http_log_time.data = p2;
|
||||
ngx_cached_http_log_iso8601.data = p3;
|
||||
ngx_cached_syslog_time.data = p4;
|
||||
|
||||
ngx_unlock(&ngx_time_lock);
|
||||
}
|
||||
|
||||
|
||||
static ngx_msec_t
|
||||
ngx_monotonic_time(time_t sec, ngx_uint_t msec)
|
||||
{
|
||||
#if (NGX_HAVE_CLOCK_MONOTONIC)
|
||||
struct timespec ts;
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
|
||||
sec = ts.tv_sec;
|
||||
msec = ts.tv_nsec / 1000000;
|
||||
|
||||
#endif
|
||||
|
||||
return (ngx_msec_t) sec * 1000 + msec;
|
||||
}
|
||||
|
||||
|
||||
#if !(NGX_WIN32)
|
||||
|
||||
void
|
||||
ngx_time_sigsafe_update(void)
|
||||
{
|
||||
u_char *p, *p2;
|
||||
ngx_tm_t tm;
|
||||
time_t sec;
|
||||
ngx_time_t *tp;
|
||||
struct timeval tv;
|
||||
|
||||
if (!ngx_trylock(&ngx_time_lock)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_gettimeofday(&tv);
|
||||
|
||||
sec = tv.tv_sec;
|
||||
|
||||
tp = &cached_time[slot];
|
||||
|
||||
if (tp->sec == sec) {
|
||||
ngx_unlock(&ngx_time_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
if (slot == NGX_TIME_SLOTS - 1) {
|
||||
slot = 0;
|
||||
} else {
|
||||
slot++;
|
||||
}
|
||||
|
||||
tp = &cached_time[slot];
|
||||
|
||||
tp->sec = 0;
|
||||
|
||||
ngx_gmtime(sec + cached_gmtoff * 60, &tm);
|
||||
|
||||
p = &cached_err_log_time[slot][0];
|
||||
|
||||
(void) ngx_sprintf(p, "%4d/%02d/%02d %02d:%02d:%02d",
|
||||
tm.ngx_tm_year, tm.ngx_tm_mon,
|
||||
tm.ngx_tm_mday, tm.ngx_tm_hour,
|
||||
tm.ngx_tm_min, tm.ngx_tm_sec);
|
||||
|
||||
p2 = &cached_syslog_time[slot][0];
|
||||
|
||||
(void) ngx_sprintf(p2, "%s %2d %02d:%02d:%02d",
|
||||
months[tm.ngx_tm_mon - 1], tm.ngx_tm_mday,
|
||||
tm.ngx_tm_hour, tm.ngx_tm_min, tm.ngx_tm_sec);
|
||||
|
||||
ngx_memory_barrier();
|
||||
|
||||
ngx_cached_err_log_time.data = p;
|
||||
ngx_cached_syslog_time.data = p2;
|
||||
|
||||
ngx_unlock(&ngx_time_lock);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
u_char *
|
||||
ngx_http_time(u_char *buf, time_t t)
|
||||
{
|
||||
ngx_tm_t tm;
|
||||
|
||||
ngx_gmtime(t, &tm);
|
||||
|
||||
return ngx_sprintf(buf, "%s, %02d %s %4d %02d:%02d:%02d GMT",
|
||||
week[tm.ngx_tm_wday],
|
||||
tm.ngx_tm_mday,
|
||||
months[tm.ngx_tm_mon - 1],
|
||||
tm.ngx_tm_year,
|
||||
tm.ngx_tm_hour,
|
||||
tm.ngx_tm_min,
|
||||
tm.ngx_tm_sec);
|
||||
}
|
||||
|
||||
|
||||
u_char *
|
||||
ngx_http_cookie_time(u_char *buf, time_t t)
|
||||
{
|
||||
ngx_tm_t tm;
|
||||
|
||||
ngx_gmtime(t, &tm);
|
||||
|
||||
/*
|
||||
* Netscape 3.x does not understand 4-digit years at all and
|
||||
* 2-digit years more than "37"
|
||||
*/
|
||||
|
||||
return ngx_sprintf(buf,
|
||||
(tm.ngx_tm_year > 2037) ?
|
||||
"%s, %02d-%s-%d %02d:%02d:%02d GMT":
|
||||
"%s, %02d-%s-%02d %02d:%02d:%02d GMT",
|
||||
week[tm.ngx_tm_wday],
|
||||
tm.ngx_tm_mday,
|
||||
months[tm.ngx_tm_mon - 1],
|
||||
(tm.ngx_tm_year > 2037) ? tm.ngx_tm_year:
|
||||
tm.ngx_tm_year % 100,
|
||||
tm.ngx_tm_hour,
|
||||
tm.ngx_tm_min,
|
||||
tm.ngx_tm_sec);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_gmtime(time_t t, ngx_tm_t *tp)
|
||||
{
|
||||
ngx_int_t yday;
|
||||
ngx_uint_t sec, min, hour, mday, mon, year, wday, days, leap;
|
||||
|
||||
/* the calculation is valid for positive time_t only */
|
||||
|
||||
if (t < 0) {
|
||||
t = 0;
|
||||
}
|
||||
|
||||
days = t / 86400;
|
||||
sec = t % 86400;
|
||||
|
||||
/*
|
||||
* no more than 4 year digits supported,
|
||||
* truncate to December 31, 9999, 23:59:59
|
||||
*/
|
||||
|
||||
if (days > 2932896) {
|
||||
days = 2932896;
|
||||
sec = 86399;
|
||||
}
|
||||
|
||||
/* January 1, 1970 was Thursday */
|
||||
|
||||
wday = (4 + days) % 7;
|
||||
|
||||
hour = sec / 3600;
|
||||
sec %= 3600;
|
||||
min = sec / 60;
|
||||
sec %= 60;
|
||||
|
||||
/*
|
||||
* the algorithm based on Gauss' formula,
|
||||
* see src/core/ngx_parse_time.c
|
||||
*/
|
||||
|
||||
/* days since March 1, 1 BC */
|
||||
days = days - (31 + 28) + 719527;
|
||||
|
||||
/*
|
||||
* The "days" should be adjusted to 1 only, however, some March 1st's go
|
||||
* to previous year, so we adjust them to 2. This causes also shift of the
|
||||
* last February days to next year, but we catch the case when "yday"
|
||||
* becomes negative.
|
||||
*/
|
||||
|
||||
year = (days + 2) * 400 / (365 * 400 + 100 - 4 + 1);
|
||||
|
||||
yday = days - (365 * year + year / 4 - year / 100 + year / 400);
|
||||
|
||||
if (yday < 0) {
|
||||
leap = (year % 4 == 0) && (year % 100 || (year % 400 == 0));
|
||||
yday = 365 + leap + yday;
|
||||
year--;
|
||||
}
|
||||
|
||||
/*
|
||||
* The empirical formula that maps "yday" to month.
|
||||
* There are at least 10 variants, some of them are:
|
||||
* mon = (yday + 31) * 15 / 459
|
||||
* mon = (yday + 31) * 17 / 520
|
||||
* mon = (yday + 31) * 20 / 612
|
||||
*/
|
||||
|
||||
mon = (yday + 31) * 10 / 306;
|
||||
|
||||
/* the Gauss' formula that evaluates days before the month */
|
||||
|
||||
mday = yday - (367 * mon / 12 - 30) + 1;
|
||||
|
||||
if (yday >= 306) {
|
||||
|
||||
year++;
|
||||
mon -= 10;
|
||||
|
||||
/*
|
||||
* there is no "yday" in Win32 SYSTEMTIME
|
||||
*
|
||||
* yday -= 306;
|
||||
*/
|
||||
|
||||
} else {
|
||||
|
||||
mon += 2;
|
||||
|
||||
/*
|
||||
* there is no "yday" in Win32 SYSTEMTIME
|
||||
*
|
||||
* yday += 31 + 28 + leap;
|
||||
*/
|
||||
}
|
||||
|
||||
tp->ngx_tm_sec = (ngx_tm_sec_t) sec;
|
||||
tp->ngx_tm_min = (ngx_tm_min_t) min;
|
||||
tp->ngx_tm_hour = (ngx_tm_hour_t) hour;
|
||||
tp->ngx_tm_mday = (ngx_tm_mday_t) mday;
|
||||
tp->ngx_tm_mon = (ngx_tm_mon_t) mon;
|
||||
tp->ngx_tm_year = (ngx_tm_year_t) year;
|
||||
tp->ngx_tm_wday = (ngx_tm_wday_t) wday;
|
||||
}
|
||||
|
||||
|
||||
time_t
|
||||
ngx_next_time(time_t when)
|
||||
{
|
||||
time_t now, next;
|
||||
struct tm tm;
|
||||
|
||||
now = ngx_time();
|
||||
|
||||
ngx_libc_localtime(now, &tm);
|
||||
|
||||
tm.tm_hour = (int) (when / 3600);
|
||||
when %= 3600;
|
||||
tm.tm_min = (int) (when / 60);
|
||||
tm.tm_sec = (int) (when % 60);
|
||||
|
||||
next = mktime(&tm);
|
||||
|
||||
if (next == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (next - now > 0) {
|
||||
return next;
|
||||
}
|
||||
|
||||
tm.tm_mday++;
|
||||
|
||||
/* mktime() should normalize a date (Jan 32, etc) */
|
||||
|
||||
next = mktime(&tm);
|
||||
|
||||
if (next != -1) {
|
||||
return next;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
52
nginx/src/core/ngx_times.h
Normal file
52
nginx/src/core/ngx_times.h
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_TIMES_H_INCLUDED_
|
||||
#define _NGX_TIMES_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
typedef struct {
|
||||
time_t sec;
|
||||
ngx_uint_t msec;
|
||||
ngx_int_t gmtoff;
|
||||
} ngx_time_t;
|
||||
|
||||
|
||||
void ngx_time_init(void);
|
||||
void ngx_time_update(void);
|
||||
void ngx_time_sigsafe_update(void);
|
||||
u_char *ngx_http_time(u_char *buf, time_t t);
|
||||
u_char *ngx_http_cookie_time(u_char *buf, time_t t);
|
||||
void ngx_gmtime(time_t t, ngx_tm_t *tp);
|
||||
|
||||
time_t ngx_next_time(time_t when);
|
||||
#define ngx_next_time_n "mktime()"
|
||||
|
||||
|
||||
extern volatile ngx_time_t *ngx_cached_time;
|
||||
|
||||
#define ngx_time() ngx_cached_time->sec
|
||||
#define ngx_timeofday() (ngx_time_t *) ngx_cached_time
|
||||
|
||||
extern volatile ngx_str_t ngx_cached_err_log_time;
|
||||
extern volatile ngx_str_t ngx_cached_http_time;
|
||||
extern volatile ngx_str_t ngx_cached_http_log_time;
|
||||
extern volatile ngx_str_t ngx_cached_http_log_iso8601;
|
||||
extern volatile ngx_str_t ngx_cached_syslog_time;
|
||||
|
||||
/*
|
||||
* milliseconds elapsed since some unspecified point in the past
|
||||
* and truncated to ngx_msec_t, used in event timers
|
||||
*/
|
||||
extern volatile ngx_msec_t ngx_current_msec;
|
||||
|
||||
|
||||
#endif /* _NGX_TIMES_H_INCLUDED_ */
|
||||
561
nginx/src/event/modules/ngx_devpoll_module.c
Normal file
561
nginx/src/event/modules/ngx_devpoll_module.c
Normal file
|
|
@ -0,0 +1,561 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_event.h>
|
||||
|
||||
|
||||
#if (NGX_TEST_BUILD_DEVPOLL)
|
||||
|
||||
/* Solaris declarations */
|
||||
|
||||
#ifndef POLLREMOVE
|
||||
#define POLLREMOVE 0x0800
|
||||
#endif
|
||||
#define DP_POLL 0xD001
|
||||
#define DP_ISPOLLED 0xD002
|
||||
|
||||
struct dvpoll {
|
||||
struct pollfd *dp_fds;
|
||||
int dp_nfds;
|
||||
int dp_timeout;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_uint_t changes;
|
||||
ngx_uint_t events;
|
||||
} ngx_devpoll_conf_t;
|
||||
|
||||
|
||||
static ngx_int_t ngx_devpoll_init(ngx_cycle_t *cycle, ngx_msec_t timer);
|
||||
static void ngx_devpoll_done(ngx_cycle_t *cycle);
|
||||
static ngx_int_t ngx_devpoll_add_event(ngx_event_t *ev, ngx_int_t event,
|
||||
ngx_uint_t flags);
|
||||
static ngx_int_t ngx_devpoll_del_event(ngx_event_t *ev, ngx_int_t event,
|
||||
ngx_uint_t flags);
|
||||
static ngx_int_t ngx_devpoll_set_event(ngx_event_t *ev, ngx_int_t event,
|
||||
ngx_uint_t flags);
|
||||
static ngx_int_t ngx_devpoll_process_events(ngx_cycle_t *cycle,
|
||||
ngx_msec_t timer, ngx_uint_t flags);
|
||||
|
||||
static void *ngx_devpoll_create_conf(ngx_cycle_t *cycle);
|
||||
static char *ngx_devpoll_init_conf(ngx_cycle_t *cycle, void *conf);
|
||||
|
||||
static int dp = -1;
|
||||
static struct pollfd *change_list, *event_list;
|
||||
static ngx_uint_t nchanges, max_changes, nevents;
|
||||
|
||||
static ngx_event_t **change_index;
|
||||
|
||||
|
||||
static ngx_str_t devpoll_name = ngx_string("/dev/poll");
|
||||
|
||||
static ngx_command_t ngx_devpoll_commands[] = {
|
||||
|
||||
{ ngx_string("devpoll_changes"),
|
||||
NGX_EVENT_CONF|NGX_CONF_TAKE1,
|
||||
ngx_conf_set_num_slot,
|
||||
0,
|
||||
offsetof(ngx_devpoll_conf_t, changes),
|
||||
NULL },
|
||||
|
||||
{ ngx_string("devpoll_events"),
|
||||
NGX_EVENT_CONF|NGX_CONF_TAKE1,
|
||||
ngx_conf_set_num_slot,
|
||||
0,
|
||||
offsetof(ngx_devpoll_conf_t, events),
|
||||
NULL },
|
||||
|
||||
ngx_null_command
|
||||
};
|
||||
|
||||
|
||||
static ngx_event_module_t ngx_devpoll_module_ctx = {
|
||||
&devpoll_name,
|
||||
ngx_devpoll_create_conf, /* create configuration */
|
||||
ngx_devpoll_init_conf, /* init configuration */
|
||||
|
||||
{
|
||||
ngx_devpoll_add_event, /* add an event */
|
||||
ngx_devpoll_del_event, /* delete an event */
|
||||
ngx_devpoll_add_event, /* enable an event */
|
||||
ngx_devpoll_del_event, /* disable an event */
|
||||
NULL, /* add an connection */
|
||||
NULL, /* delete an connection */
|
||||
NULL, /* trigger a notify */
|
||||
ngx_devpoll_process_events, /* process the events */
|
||||
ngx_devpoll_init, /* init the events */
|
||||
ngx_devpoll_done, /* done the events */
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
ngx_module_t ngx_devpoll_module = {
|
||||
NGX_MODULE_V1,
|
||||
&ngx_devpoll_module_ctx, /* module context */
|
||||
ngx_devpoll_commands, /* module directives */
|
||||
NGX_EVENT_MODULE, /* module type */
|
||||
NULL, /* init master */
|
||||
NULL, /* init module */
|
||||
NULL, /* init process */
|
||||
NULL, /* init thread */
|
||||
NULL, /* exit thread */
|
||||
NULL, /* exit process */
|
||||
NULL, /* exit master */
|
||||
NGX_MODULE_V1_PADDING
|
||||
};
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_devpoll_init(ngx_cycle_t *cycle, ngx_msec_t timer)
|
||||
{
|
||||
size_t n;
|
||||
ngx_devpoll_conf_t *dpcf;
|
||||
|
||||
dpcf = ngx_event_get_conf(cycle->conf_ctx, ngx_devpoll_module);
|
||||
|
||||
if (dp == -1) {
|
||||
dp = open("/dev/poll", O_RDWR);
|
||||
|
||||
if (dp == -1) {
|
||||
ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
|
||||
"open(/dev/poll) failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (max_changes < dpcf->changes) {
|
||||
if (nchanges) {
|
||||
n = nchanges * sizeof(struct pollfd);
|
||||
if (write(dp, change_list, n) != (ssize_t) n) {
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
|
||||
"write(/dev/poll) failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
nchanges = 0;
|
||||
}
|
||||
|
||||
if (change_list) {
|
||||
ngx_free(change_list);
|
||||
}
|
||||
|
||||
change_list = ngx_alloc(sizeof(struct pollfd) * dpcf->changes,
|
||||
cycle->log);
|
||||
if (change_list == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (change_index) {
|
||||
ngx_free(change_index);
|
||||
}
|
||||
|
||||
change_index = ngx_alloc(sizeof(ngx_event_t *) * dpcf->changes,
|
||||
cycle->log);
|
||||
if (change_index == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
max_changes = dpcf->changes;
|
||||
|
||||
if (nevents < dpcf->events) {
|
||||
if (event_list) {
|
||||
ngx_free(event_list);
|
||||
}
|
||||
|
||||
event_list = ngx_alloc(sizeof(struct pollfd) * dpcf->events,
|
||||
cycle->log);
|
||||
if (event_list == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
nevents = dpcf->events;
|
||||
|
||||
ngx_io = ngx_os_io;
|
||||
|
||||
ngx_event_actions = ngx_devpoll_module_ctx.actions;
|
||||
|
||||
ngx_event_flags = NGX_USE_LEVEL_EVENT|NGX_USE_FD_EVENT;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_devpoll_done(ngx_cycle_t *cycle)
|
||||
{
|
||||
if (close(dp) == -1) {
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
|
||||
"close(/dev/poll) failed");
|
||||
}
|
||||
|
||||
dp = -1;
|
||||
|
||||
ngx_free(change_list);
|
||||
ngx_free(event_list);
|
||||
ngx_free(change_index);
|
||||
|
||||
change_list = NULL;
|
||||
event_list = NULL;
|
||||
change_index = NULL;
|
||||
max_changes = 0;
|
||||
nchanges = 0;
|
||||
nevents = 0;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_devpoll_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
|
||||
{
|
||||
#if (NGX_DEBUG)
|
||||
ngx_connection_t *c;
|
||||
#endif
|
||||
|
||||
#if (NGX_READ_EVENT != POLLIN)
|
||||
event = (event == NGX_READ_EVENT) ? POLLIN : POLLOUT;
|
||||
#endif
|
||||
|
||||
#if (NGX_DEBUG)
|
||||
c = ev->data;
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
|
||||
"devpoll add event: fd:%d ev:%04Xi", c->fd, event);
|
||||
#endif
|
||||
|
||||
ev->active = 1;
|
||||
|
||||
return ngx_devpoll_set_event(ev, event, 0);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_devpoll_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
|
||||
{
|
||||
ngx_event_t *e;
|
||||
ngx_connection_t *c;
|
||||
|
||||
c = ev->data;
|
||||
|
||||
#if (NGX_READ_EVENT != POLLIN)
|
||||
event = (event == NGX_READ_EVENT) ? POLLIN : POLLOUT;
|
||||
#endif
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
|
||||
"devpoll del event: fd:%d ev:%04Xi", c->fd, event);
|
||||
|
||||
if (ngx_devpoll_set_event(ev, POLLREMOVE, flags) == NGX_ERROR) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ev->active = 0;
|
||||
|
||||
if (flags & NGX_CLOSE_EVENT) {
|
||||
e = (event == POLLIN) ? c->write : c->read;
|
||||
|
||||
if (e) {
|
||||
e->active = 0;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
/* restore the pair event if it exists */
|
||||
|
||||
if (event == POLLIN) {
|
||||
e = c->write;
|
||||
event = POLLOUT;
|
||||
|
||||
} else {
|
||||
e = c->read;
|
||||
event = POLLIN;
|
||||
}
|
||||
|
||||
if (e && e->active) {
|
||||
return ngx_devpoll_set_event(e, event, 0);
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_devpoll_set_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
|
||||
{
|
||||
size_t n;
|
||||
ngx_connection_t *c;
|
||||
|
||||
c = ev->data;
|
||||
|
||||
ngx_log_debug3(NGX_LOG_DEBUG_EVENT, ev->log, 0,
|
||||
"devpoll fd:%d ev:%04Xi fl:%04Xi", c->fd, event, flags);
|
||||
|
||||
if (nchanges >= max_changes) {
|
||||
ngx_log_error(NGX_LOG_WARN, ev->log, 0,
|
||||
"/dev/pool change list is filled up");
|
||||
|
||||
n = nchanges * sizeof(struct pollfd);
|
||||
if (write(dp, change_list, n) != (ssize_t) n) {
|
||||
ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
|
||||
"write(/dev/poll) failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
nchanges = 0;
|
||||
}
|
||||
|
||||
change_list[nchanges].fd = c->fd;
|
||||
change_list[nchanges].events = (short) event;
|
||||
change_list[nchanges].revents = 0;
|
||||
|
||||
change_index[nchanges] = ev;
|
||||
ev->index = nchanges;
|
||||
|
||||
nchanges++;
|
||||
|
||||
if (flags & NGX_CLOSE_EVENT) {
|
||||
n = nchanges * sizeof(struct pollfd);
|
||||
if (write(dp, change_list, n) != (ssize_t) n) {
|
||||
ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
|
||||
"write(/dev/poll) failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
nchanges = 0;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_devpoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
|
||||
ngx_uint_t flags)
|
||||
{
|
||||
int events, revents, rc;
|
||||
size_t n;
|
||||
ngx_fd_t fd;
|
||||
ngx_err_t err;
|
||||
ngx_int_t i;
|
||||
ngx_uint_t level, instance;
|
||||
ngx_event_t *rev, *wev;
|
||||
ngx_queue_t *queue;
|
||||
ngx_connection_t *c;
|
||||
struct pollfd pfd;
|
||||
struct dvpoll dvp;
|
||||
|
||||
/* NGX_TIMER_INFINITE == INFTIM */
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
|
||||
"devpoll timer: %M", timer);
|
||||
|
||||
if (nchanges) {
|
||||
n = nchanges * sizeof(struct pollfd);
|
||||
if (write(dp, change_list, n) != (ssize_t) n) {
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
|
||||
"write(/dev/poll) failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
nchanges = 0;
|
||||
}
|
||||
|
||||
dvp.dp_fds = event_list;
|
||||
dvp.dp_nfds = (int) nevents;
|
||||
dvp.dp_timeout = timer;
|
||||
events = ioctl(dp, DP_POLL, &dvp);
|
||||
|
||||
err = (events == -1) ? ngx_errno : 0;
|
||||
|
||||
if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) {
|
||||
ngx_time_update();
|
||||
}
|
||||
|
||||
if (err) {
|
||||
if (err == NGX_EINTR) {
|
||||
|
||||
if (ngx_event_timer_alarm) {
|
||||
ngx_event_timer_alarm = 0;
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
level = NGX_LOG_INFO;
|
||||
|
||||
} else {
|
||||
level = NGX_LOG_ALERT;
|
||||
}
|
||||
|
||||
ngx_log_error(level, cycle->log, err, "ioctl(DP_POLL) failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (events == 0) {
|
||||
if (timer != NGX_TIMER_INFINITE) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
|
||||
"ioctl(DP_POLL) returned no events without timeout");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
for (i = 0; i < events; i++) {
|
||||
|
||||
fd = event_list[i].fd;
|
||||
revents = event_list[i].revents;
|
||||
|
||||
c = ngx_cycle->files[fd];
|
||||
|
||||
if (c == NULL || c->fd == -1) {
|
||||
|
||||
pfd.fd = fd;
|
||||
pfd.events = 0;
|
||||
pfd.revents = 0;
|
||||
|
||||
rc = ioctl(dp, DP_ISPOLLED, &pfd);
|
||||
|
||||
switch (rc) {
|
||||
|
||||
case -1:
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
|
||||
"ioctl(DP_ISPOLLED) failed for socket %d, event %04Xd",
|
||||
fd, revents);
|
||||
break;
|
||||
|
||||
case 0:
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
|
||||
"phantom event %04Xd for closed and removed socket %d",
|
||||
revents, fd);
|
||||
break;
|
||||
|
||||
default:
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
|
||||
"unexpected event %04Xd for closed and removed socket %d, "
|
||||
"ioctl(DP_ISPOLLED) returned rc:%d, fd:%d, event %04Xd",
|
||||
revents, fd, rc, pfd.fd, pfd.revents);
|
||||
|
||||
pfd.fd = fd;
|
||||
pfd.events = POLLREMOVE;
|
||||
pfd.revents = 0;
|
||||
|
||||
if (write(dp, &pfd, sizeof(struct pollfd))
|
||||
!= (ssize_t) sizeof(struct pollfd))
|
||||
{
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
|
||||
"write(/dev/poll) for %d failed", fd);
|
||||
}
|
||||
|
||||
if (close(fd) == -1) {
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
|
||||
"close(%d) failed", fd);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
|
||||
"devpoll: fd:%d, ev:%04Xd, rev:%04Xd",
|
||||
fd, event_list[i].events, revents);
|
||||
|
||||
if (revents & (POLLERR|POLLHUP|POLLNVAL)) {
|
||||
ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
|
||||
"ioctl(DP_POLL) error fd:%d ev:%04Xd rev:%04Xd",
|
||||
fd, event_list[i].events, revents);
|
||||
}
|
||||
|
||||
if (revents & ~(POLLIN|POLLOUT|POLLERR|POLLHUP|POLLNVAL)) {
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
|
||||
"strange ioctl(DP_POLL) events "
|
||||
"fd:%d ev:%04Xd rev:%04Xd",
|
||||
fd, event_list[i].events, revents);
|
||||
}
|
||||
|
||||
if (revents & (POLLERR|POLLHUP|POLLNVAL)) {
|
||||
|
||||
/*
|
||||
* if the error events were returned, add POLLIN and POLLOUT
|
||||
* to handle the events at least in one active handler
|
||||
*/
|
||||
|
||||
revents |= POLLIN|POLLOUT;
|
||||
}
|
||||
|
||||
rev = c->read;
|
||||
|
||||
if ((revents & POLLIN) && rev->active) {
|
||||
rev->ready = 1;
|
||||
rev->available = -1;
|
||||
|
||||
if (flags & NGX_POST_EVENTS) {
|
||||
queue = rev->accept ? &ngx_posted_accept_events
|
||||
: &ngx_posted_events;
|
||||
|
||||
ngx_post_event(rev, queue);
|
||||
|
||||
} else {
|
||||
instance = rev->instance;
|
||||
|
||||
rev->handler(rev);
|
||||
|
||||
if (c->fd == -1 || rev->instance != instance) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wev = c->write;
|
||||
|
||||
if ((revents & POLLOUT) && wev->active) {
|
||||
wev->ready = 1;
|
||||
|
||||
if (flags & NGX_POST_EVENTS) {
|
||||
ngx_post_event(wev, &ngx_posted_events);
|
||||
|
||||
} else {
|
||||
wev->handler(wev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
ngx_devpoll_create_conf(ngx_cycle_t *cycle)
|
||||
{
|
||||
ngx_devpoll_conf_t *dpcf;
|
||||
|
||||
dpcf = ngx_palloc(cycle->pool, sizeof(ngx_devpoll_conf_t));
|
||||
if (dpcf == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dpcf->changes = NGX_CONF_UNSET;
|
||||
dpcf->events = NGX_CONF_UNSET;
|
||||
|
||||
return dpcf;
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
ngx_devpoll_init_conf(ngx_cycle_t *cycle, void *conf)
|
||||
{
|
||||
ngx_devpoll_conf_t *dpcf = conf;
|
||||
|
||||
ngx_conf_init_uint_value(dpcf->changes, 32);
|
||||
ngx_conf_init_uint_value(dpcf->events, 32);
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
1051
nginx/src/event/modules/ngx_epoll_module.c
Normal file
1051
nginx/src/event/modules/ngx_epoll_module.c
Normal file
File diff suppressed because it is too large
Load diff
650
nginx/src/event/modules/ngx_eventport_module.c
Normal file
650
nginx/src/event/modules/ngx_eventport_module.c
Normal file
|
|
@ -0,0 +1,650 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_event.h>
|
||||
|
||||
|
||||
#if (NGX_TEST_BUILD_EVENTPORT)
|
||||
|
||||
#define ushort_t u_short
|
||||
#define uint_t u_int
|
||||
|
||||
#ifndef CLOCK_REALTIME
|
||||
#define CLOCK_REALTIME 0
|
||||
typedef int clockid_t;
|
||||
typedef void * timer_t;
|
||||
#elif (NGX_DARWIN)
|
||||
typedef void * timer_t;
|
||||
#endif
|
||||
|
||||
/* Solaris declarations */
|
||||
|
||||
#define PORT_SOURCE_AIO 1
|
||||
#define PORT_SOURCE_TIMER 2
|
||||
#define PORT_SOURCE_USER 3
|
||||
#define PORT_SOURCE_FD 4
|
||||
#define PORT_SOURCE_ALERT 5
|
||||
#define PORT_SOURCE_MQ 6
|
||||
|
||||
#ifndef ETIME
|
||||
#define ETIME 64
|
||||
#endif
|
||||
|
||||
#define SIGEV_PORT 4
|
||||
|
||||
typedef struct {
|
||||
int portev_events; /* event data is source specific */
|
||||
ushort_t portev_source; /* event source */
|
||||
ushort_t portev_pad; /* port internal use */
|
||||
uintptr_t portev_object; /* source specific object */
|
||||
void *portev_user; /* user cookie */
|
||||
} port_event_t;
|
||||
|
||||
typedef struct port_notify {
|
||||
int portnfy_port; /* bind request(s) to port */
|
||||
void *portnfy_user; /* user defined */
|
||||
} port_notify_t;
|
||||
|
||||
#if (__FreeBSD__ && __FreeBSD_version < 700005) || (NGX_DARWIN)
|
||||
|
||||
typedef struct itimerspec { /* definition per POSIX.4 */
|
||||
struct timespec it_interval;/* timer period */
|
||||
struct timespec it_value; /* timer expiration */
|
||||
} itimerspec_t;
|
||||
|
||||
#endif
|
||||
|
||||
int port_create(void);
|
||||
|
||||
int port_create(void)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int port_associate(int port, int source, uintptr_t object, int events,
|
||||
void *user);
|
||||
|
||||
int port_associate(int port, int source, uintptr_t object, int events,
|
||||
void *user)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int port_dissociate(int port, int source, uintptr_t object);
|
||||
|
||||
int port_dissociate(int port, int source, uintptr_t object)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int port_getn(int port, port_event_t list[], uint_t max, uint_t *nget,
|
||||
struct timespec *timeout);
|
||||
|
||||
int port_getn(int port, port_event_t list[], uint_t max, uint_t *nget,
|
||||
struct timespec *timeout)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int port_send(int port, int events, void *user);
|
||||
|
||||
int port_send(int port, int events, void *user)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int timer_create(clockid_t clock_id, struct sigevent *evp, timer_t *timerid);
|
||||
|
||||
int timer_create(clockid_t clock_id, struct sigevent *evp, timer_t *timerid)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int timer_settime(timer_t timerid, int flags, const struct itimerspec *value,
|
||||
struct itimerspec *ovalue);
|
||||
|
||||
int timer_settime(timer_t timerid, int flags, const struct itimerspec *value,
|
||||
struct itimerspec *ovalue)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int timer_delete(timer_t timerid);
|
||||
|
||||
int timer_delete(timer_t timerid)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_uint_t events;
|
||||
} ngx_eventport_conf_t;
|
||||
|
||||
|
||||
static ngx_int_t ngx_eventport_init(ngx_cycle_t *cycle, ngx_msec_t timer);
|
||||
static void ngx_eventport_done(ngx_cycle_t *cycle);
|
||||
static ngx_int_t ngx_eventport_add_event(ngx_event_t *ev, ngx_int_t event,
|
||||
ngx_uint_t flags);
|
||||
static ngx_int_t ngx_eventport_del_event(ngx_event_t *ev, ngx_int_t event,
|
||||
ngx_uint_t flags);
|
||||
static ngx_int_t ngx_eventport_notify(ngx_event_handler_pt handler);
|
||||
static ngx_int_t ngx_eventport_process_events(ngx_cycle_t *cycle,
|
||||
ngx_msec_t timer, ngx_uint_t flags);
|
||||
|
||||
static void *ngx_eventport_create_conf(ngx_cycle_t *cycle);
|
||||
static char *ngx_eventport_init_conf(ngx_cycle_t *cycle, void *conf);
|
||||
|
||||
static int ep = -1;
|
||||
static port_event_t *event_list;
|
||||
static ngx_uint_t nevents;
|
||||
static timer_t event_timer = (timer_t) -1;
|
||||
static ngx_event_t notify_event;
|
||||
|
||||
static ngx_str_t eventport_name = ngx_string("eventport");
|
||||
|
||||
|
||||
static ngx_command_t ngx_eventport_commands[] = {
|
||||
|
||||
{ ngx_string("eventport_events"),
|
||||
NGX_EVENT_CONF|NGX_CONF_TAKE1,
|
||||
ngx_conf_set_num_slot,
|
||||
0,
|
||||
offsetof(ngx_eventport_conf_t, events),
|
||||
NULL },
|
||||
|
||||
ngx_null_command
|
||||
};
|
||||
|
||||
|
||||
static ngx_event_module_t ngx_eventport_module_ctx = {
|
||||
&eventport_name,
|
||||
ngx_eventport_create_conf, /* create configuration */
|
||||
ngx_eventport_init_conf, /* init configuration */
|
||||
|
||||
{
|
||||
ngx_eventport_add_event, /* add an event */
|
||||
ngx_eventport_del_event, /* delete an event */
|
||||
ngx_eventport_add_event, /* enable an event */
|
||||
ngx_eventport_del_event, /* disable an event */
|
||||
NULL, /* add an connection */
|
||||
NULL, /* delete an connection */
|
||||
ngx_eventport_notify, /* trigger a notify */
|
||||
ngx_eventport_process_events, /* process the events */
|
||||
ngx_eventport_init, /* init the events */
|
||||
ngx_eventport_done, /* done the events */
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
ngx_module_t ngx_eventport_module = {
|
||||
NGX_MODULE_V1,
|
||||
&ngx_eventport_module_ctx, /* module context */
|
||||
ngx_eventport_commands, /* module directives */
|
||||
NGX_EVENT_MODULE, /* module type */
|
||||
NULL, /* init master */
|
||||
NULL, /* init module */
|
||||
NULL, /* init process */
|
||||
NULL, /* init thread */
|
||||
NULL, /* exit thread */
|
||||
NULL, /* exit process */
|
||||
NULL, /* exit master */
|
||||
NGX_MODULE_V1_PADDING
|
||||
};
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_eventport_init(ngx_cycle_t *cycle, ngx_msec_t timer)
|
||||
{
|
||||
port_notify_t pn;
|
||||
struct itimerspec its;
|
||||
struct sigevent sev;
|
||||
ngx_eventport_conf_t *epcf;
|
||||
|
||||
epcf = ngx_event_get_conf(cycle->conf_ctx, ngx_eventport_module);
|
||||
|
||||
if (ep == -1) {
|
||||
ep = port_create();
|
||||
|
||||
if (ep == -1) {
|
||||
ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
|
||||
"port_create() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
notify_event.active = 1;
|
||||
notify_event.log = cycle->log;
|
||||
}
|
||||
|
||||
if (nevents < epcf->events) {
|
||||
if (event_list) {
|
||||
ngx_free(event_list);
|
||||
}
|
||||
|
||||
event_list = ngx_alloc(sizeof(port_event_t) * epcf->events,
|
||||
cycle->log);
|
||||
if (event_list == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
ngx_event_flags = NGX_USE_EVENTPORT_EVENT;
|
||||
|
||||
if (timer) {
|
||||
ngx_memzero(&pn, sizeof(port_notify_t));
|
||||
pn.portnfy_port = ep;
|
||||
|
||||
ngx_memzero(&sev, sizeof(struct sigevent));
|
||||
sev.sigev_notify = SIGEV_PORT;
|
||||
sev.sigev_value.sival_ptr = &pn;
|
||||
|
||||
if (timer_create(CLOCK_REALTIME, &sev, &event_timer) == -1) {
|
||||
ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
|
||||
"timer_create() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
its.it_interval.tv_sec = timer / 1000;
|
||||
its.it_interval.tv_nsec = (timer % 1000) * 1000000;
|
||||
its.it_value.tv_sec = timer / 1000;
|
||||
its.it_value.tv_nsec = (timer % 1000) * 1000000;
|
||||
|
||||
if (timer_settime(event_timer, 0, &its, NULL) == -1) {
|
||||
ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
|
||||
"timer_settime() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_event_flags |= NGX_USE_TIMER_EVENT;
|
||||
}
|
||||
|
||||
nevents = epcf->events;
|
||||
|
||||
ngx_io = ngx_os_io;
|
||||
|
||||
ngx_event_actions = ngx_eventport_module_ctx.actions;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_eventport_done(ngx_cycle_t *cycle)
|
||||
{
|
||||
if (event_timer != (timer_t) -1) {
|
||||
if (timer_delete(event_timer) == -1) {
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
|
||||
"timer_delete() failed");
|
||||
}
|
||||
|
||||
event_timer = (timer_t) -1;
|
||||
}
|
||||
|
||||
if (close(ep) == -1) {
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
|
||||
"close() event port failed");
|
||||
}
|
||||
|
||||
ep = -1;
|
||||
|
||||
ngx_free(event_list);
|
||||
|
||||
event_list = NULL;
|
||||
nevents = 0;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_eventport_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
|
||||
{
|
||||
ngx_int_t events, prev;
|
||||
ngx_event_t *e;
|
||||
ngx_connection_t *c;
|
||||
|
||||
c = ev->data;
|
||||
|
||||
events = event;
|
||||
|
||||
if (event == NGX_READ_EVENT) {
|
||||
e = c->write;
|
||||
prev = POLLOUT;
|
||||
#if (NGX_READ_EVENT != POLLIN)
|
||||
events = POLLIN;
|
||||
#endif
|
||||
|
||||
} else {
|
||||
e = c->read;
|
||||
prev = POLLIN;
|
||||
#if (NGX_WRITE_EVENT != POLLOUT)
|
||||
events = POLLOUT;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (e->oneshot) {
|
||||
events |= prev;
|
||||
}
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
|
||||
"eventport add event: fd:%d ev:%04Xi", c->fd, events);
|
||||
|
||||
if (port_associate(ep, PORT_SOURCE_FD, c->fd, events,
|
||||
(void *) ((uintptr_t) ev | ev->instance))
|
||||
== -1)
|
||||
{
|
||||
ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
|
||||
"port_associate() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ev->active = 1;
|
||||
ev->oneshot = 1;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_eventport_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
|
||||
{
|
||||
ngx_event_t *e;
|
||||
ngx_connection_t *c;
|
||||
|
||||
/*
|
||||
* when the file descriptor is closed, the event port automatically
|
||||
* dissociates it from the port, so we do not need to dissociate explicitly
|
||||
* the event before the closing the file descriptor
|
||||
*/
|
||||
|
||||
if (flags & NGX_CLOSE_EVENT) {
|
||||
ev->active = 0;
|
||||
ev->oneshot = 0;
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
c = ev->data;
|
||||
|
||||
if (event == NGX_READ_EVENT) {
|
||||
e = c->write;
|
||||
event = POLLOUT;
|
||||
|
||||
} else {
|
||||
e = c->read;
|
||||
event = POLLIN;
|
||||
}
|
||||
|
||||
if (e->oneshot) {
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
|
||||
"eventport change event: fd:%d ev:%04Xi", c->fd, event);
|
||||
|
||||
if (port_associate(ep, PORT_SOURCE_FD, c->fd, event,
|
||||
(void *) ((uintptr_t) ev | ev->instance))
|
||||
== -1)
|
||||
{
|
||||
ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
|
||||
"port_associate() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
} else if (ev->active) {
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ev->log, 0,
|
||||
"eventport del event: fd:%d", c->fd);
|
||||
|
||||
if (port_dissociate(ep, PORT_SOURCE_FD, c->fd) == -1) {
|
||||
ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
|
||||
"port_dissociate() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
ev->active = 0;
|
||||
ev->oneshot = 0;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_eventport_notify(ngx_event_handler_pt handler)
|
||||
{
|
||||
notify_event.handler = handler;
|
||||
|
||||
if (port_send(ep, 0, ¬ify_event) != 0) {
|
||||
ngx_log_error(NGX_LOG_ALERT, notify_event.log, ngx_errno,
|
||||
"port_send() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_eventport_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
|
||||
ngx_uint_t flags)
|
||||
{
|
||||
int n, revents;
|
||||
u_int events;
|
||||
ngx_err_t err;
|
||||
ngx_int_t instance;
|
||||
ngx_uint_t i, level;
|
||||
ngx_event_t *ev, *rev, *wev;
|
||||
ngx_queue_t *queue;
|
||||
ngx_connection_t *c;
|
||||
struct timespec ts, *tp;
|
||||
|
||||
if (timer == NGX_TIMER_INFINITE) {
|
||||
tp = NULL;
|
||||
|
||||
} else {
|
||||
ts.tv_sec = timer / 1000;
|
||||
ts.tv_nsec = (timer % 1000) * 1000000;
|
||||
tp = &ts;
|
||||
}
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
|
||||
"eventport timer: %M", timer);
|
||||
|
||||
events = 1;
|
||||
|
||||
n = port_getn(ep, event_list, (u_int) nevents, &events, tp);
|
||||
|
||||
err = ngx_errno;
|
||||
|
||||
if (flags & NGX_UPDATE_TIME) {
|
||||
ngx_time_update();
|
||||
}
|
||||
|
||||
if (n == -1) {
|
||||
if (err == ETIME) {
|
||||
if (timer != NGX_TIMER_INFINITE) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
|
||||
"port_getn() returned no events without timeout");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
level = (err == NGX_EINTR) ? NGX_LOG_INFO : NGX_LOG_ALERT;
|
||||
ngx_log_error(level, cycle->log, err, "port_getn() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (events == 0) {
|
||||
if (timer != NGX_TIMER_INFINITE) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
|
||||
"port_getn() returned no events without timeout");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
for (i = 0; i < events; i++) {
|
||||
|
||||
if (event_list[i].portev_source == PORT_SOURCE_TIMER) {
|
||||
ngx_time_update();
|
||||
continue;
|
||||
}
|
||||
|
||||
ev = event_list[i].portev_user;
|
||||
|
||||
switch (event_list[i].portev_source) {
|
||||
|
||||
case PORT_SOURCE_FD:
|
||||
|
||||
instance = (uintptr_t) ev & 1;
|
||||
ev = (ngx_event_t *) ((uintptr_t) ev & (uintptr_t) ~1);
|
||||
|
||||
if (ev->closed || ev->instance != instance) {
|
||||
|
||||
/*
|
||||
* the stale event from a file descriptor
|
||||
* that was just closed in this iteration
|
||||
*/
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
|
||||
"eventport: stale event %p", ev);
|
||||
continue;
|
||||
}
|
||||
|
||||
revents = event_list[i].portev_events;
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
|
||||
"eventport: fd:%d, ev:%04Xd",
|
||||
(int) event_list[i].portev_object, revents);
|
||||
|
||||
if (revents & (POLLERR|POLLHUP|POLLNVAL)) {
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
|
||||
"port_getn() error fd:%d ev:%04Xd",
|
||||
(int) event_list[i].portev_object, revents);
|
||||
}
|
||||
|
||||
if (revents & ~(POLLIN|POLLOUT|POLLERR|POLLHUP|POLLNVAL)) {
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
|
||||
"strange port_getn() events fd:%d ev:%04Xd",
|
||||
(int) event_list[i].portev_object, revents);
|
||||
}
|
||||
|
||||
if (revents & (POLLERR|POLLHUP|POLLNVAL)) {
|
||||
|
||||
/*
|
||||
* if the error events were returned, add POLLIN and POLLOUT
|
||||
* to handle the events at least in one active handler
|
||||
*/
|
||||
|
||||
revents |= POLLIN|POLLOUT;
|
||||
}
|
||||
|
||||
c = ev->data;
|
||||
rev = c->read;
|
||||
wev = c->write;
|
||||
|
||||
rev->active = 0;
|
||||
wev->active = 0;
|
||||
|
||||
if (revents & POLLIN) {
|
||||
rev->ready = 1;
|
||||
rev->available = -1;
|
||||
|
||||
if (flags & NGX_POST_EVENTS) {
|
||||
queue = rev->accept ? &ngx_posted_accept_events
|
||||
: &ngx_posted_events;
|
||||
|
||||
ngx_post_event(rev, queue);
|
||||
|
||||
} else {
|
||||
rev->handler(rev);
|
||||
|
||||
if (ev->closed || ev->instance != instance) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (rev->accept) {
|
||||
if (ngx_use_accept_mutex) {
|
||||
ngx_accept_events = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (port_associate(ep, PORT_SOURCE_FD, c->fd, POLLIN,
|
||||
(void *) ((uintptr_t) ev | ev->instance))
|
||||
== -1)
|
||||
{
|
||||
ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
|
||||
"port_associate() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (revents & POLLOUT) {
|
||||
wev->ready = 1;
|
||||
|
||||
if (flags & NGX_POST_EVENTS) {
|
||||
ngx_post_event(wev, &ngx_posted_events);
|
||||
|
||||
} else {
|
||||
wev->handler(wev);
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
|
||||
case PORT_SOURCE_USER:
|
||||
|
||||
ev->handler(ev);
|
||||
|
||||
continue;
|
||||
|
||||
default:
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
|
||||
"unexpected eventport object %d",
|
||||
(int) event_list[i].portev_object);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
ngx_eventport_create_conf(ngx_cycle_t *cycle)
|
||||
{
|
||||
ngx_eventport_conf_t *epcf;
|
||||
|
||||
epcf = ngx_palloc(cycle->pool, sizeof(ngx_eventport_conf_t));
|
||||
if (epcf == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
epcf->events = NGX_CONF_UNSET;
|
||||
|
||||
return epcf;
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
ngx_eventport_init_conf(ngx_cycle_t *cycle, void *conf)
|
||||
{
|
||||
ngx_eventport_conf_t *epcf = conf;
|
||||
|
||||
ngx_conf_init_uint_value(epcf->events, 32);
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
379
nginx/src/event/modules/ngx_iocp_module.c
Normal file
379
nginx/src/event/modules/ngx_iocp_module.c
Normal file
|
|
@ -0,0 +1,379 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_event.h>
|
||||
#include <ngx_iocp_module.h>
|
||||
|
||||
|
||||
static ngx_int_t ngx_iocp_init(ngx_cycle_t *cycle, ngx_msec_t timer);
|
||||
static ngx_thread_value_t __stdcall ngx_iocp_timer(void *data);
|
||||
static void ngx_iocp_done(ngx_cycle_t *cycle);
|
||||
static ngx_int_t ngx_iocp_add_event(ngx_event_t *ev, ngx_int_t event,
|
||||
ngx_uint_t key);
|
||||
static ngx_int_t ngx_iocp_del_connection(ngx_connection_t *c, ngx_uint_t flags);
|
||||
static ngx_int_t ngx_iocp_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
|
||||
ngx_uint_t flags);
|
||||
static void *ngx_iocp_create_conf(ngx_cycle_t *cycle);
|
||||
static char *ngx_iocp_init_conf(ngx_cycle_t *cycle, void *conf);
|
||||
|
||||
|
||||
static ngx_str_t iocp_name = ngx_string("iocp");
|
||||
|
||||
static ngx_command_t ngx_iocp_commands[] = {
|
||||
|
||||
{ ngx_string("iocp_threads"),
|
||||
NGX_EVENT_CONF|NGX_CONF_TAKE1,
|
||||
ngx_conf_set_num_slot,
|
||||
0,
|
||||
offsetof(ngx_iocp_conf_t, threads),
|
||||
NULL },
|
||||
|
||||
{ ngx_string("post_acceptex"),
|
||||
NGX_EVENT_CONF|NGX_CONF_TAKE1,
|
||||
ngx_conf_set_num_slot,
|
||||
0,
|
||||
offsetof(ngx_iocp_conf_t, post_acceptex),
|
||||
NULL },
|
||||
|
||||
{ ngx_string("acceptex_read"),
|
||||
NGX_EVENT_CONF|NGX_CONF_FLAG,
|
||||
ngx_conf_set_flag_slot,
|
||||
0,
|
||||
offsetof(ngx_iocp_conf_t, acceptex_read),
|
||||
NULL },
|
||||
|
||||
ngx_null_command
|
||||
};
|
||||
|
||||
|
||||
static ngx_event_module_t ngx_iocp_module_ctx = {
|
||||
&iocp_name,
|
||||
ngx_iocp_create_conf, /* create configuration */
|
||||
ngx_iocp_init_conf, /* init configuration */
|
||||
|
||||
{
|
||||
ngx_iocp_add_event, /* add an event */
|
||||
NULL, /* delete an event */
|
||||
NULL, /* enable an event */
|
||||
NULL, /* disable an event */
|
||||
NULL, /* add an connection */
|
||||
ngx_iocp_del_connection, /* delete an connection */
|
||||
NULL, /* trigger a notify */
|
||||
ngx_iocp_process_events, /* process the events */
|
||||
ngx_iocp_init, /* init the events */
|
||||
ngx_iocp_done /* done the events */
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
ngx_module_t ngx_iocp_module = {
|
||||
NGX_MODULE_V1,
|
||||
&ngx_iocp_module_ctx, /* module context */
|
||||
ngx_iocp_commands, /* module directives */
|
||||
NGX_EVENT_MODULE, /* module type */
|
||||
NULL, /* init master */
|
||||
NULL, /* init module */
|
||||
NULL, /* init process */
|
||||
NULL, /* init thread */
|
||||
NULL, /* exit thread */
|
||||
NULL, /* exit process */
|
||||
NULL, /* exit master */
|
||||
NGX_MODULE_V1_PADDING
|
||||
};
|
||||
|
||||
|
||||
ngx_os_io_t ngx_iocp_io = {
|
||||
ngx_overlapped_wsarecv,
|
||||
NULL,
|
||||
ngx_udp_overlapped_wsarecv,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
ngx_overlapped_wsasend_chain,
|
||||
0
|
||||
};
|
||||
|
||||
|
||||
static HANDLE iocp;
|
||||
static ngx_tid_t timer_thread;
|
||||
static ngx_msec_t msec;
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_iocp_init(ngx_cycle_t *cycle, ngx_msec_t timer)
|
||||
{
|
||||
ngx_iocp_conf_t *cf;
|
||||
|
||||
cf = ngx_event_get_conf(cycle->conf_ctx, ngx_iocp_module);
|
||||
|
||||
if (iocp == NULL) {
|
||||
iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0,
|
||||
cf->threads);
|
||||
}
|
||||
|
||||
if (iocp == NULL) {
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
|
||||
"CreateIoCompletionPort() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_io = ngx_iocp_io;
|
||||
|
||||
ngx_event_actions = ngx_iocp_module_ctx.actions;
|
||||
|
||||
ngx_event_flags = NGX_USE_IOCP_EVENT;
|
||||
|
||||
if (timer == 0) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* The waitable timer could not be used, because
|
||||
* GetQueuedCompletionStatus() does not set a thread to alertable state
|
||||
*/
|
||||
|
||||
if (timer_thread == NULL) {
|
||||
|
||||
msec = timer;
|
||||
|
||||
if (ngx_create_thread(&timer_thread, ngx_iocp_timer, &msec, cycle->log)
|
||||
!= 0)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
ngx_event_flags |= NGX_USE_TIMER_EVENT;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_thread_value_t __stdcall
|
||||
ngx_iocp_timer(void *data)
|
||||
{
|
||||
ngx_msec_t timer = *(ngx_msec_t *) data;
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0,
|
||||
"THREAD %p %p", &msec, data);
|
||||
|
||||
for ( ;; ) {
|
||||
Sleep(timer);
|
||||
|
||||
ngx_time_update();
|
||||
#if 1
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0, "timer");
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(__WATCOMC__) || defined(__GNUC__)
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_iocp_done(ngx_cycle_t *cycle)
|
||||
{
|
||||
if (CloseHandle(iocp) == -1) {
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
|
||||
"iocp CloseHandle() failed");
|
||||
}
|
||||
|
||||
iocp = NULL;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_iocp_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t key)
|
||||
{
|
||||
ngx_connection_t *c;
|
||||
|
||||
c = (ngx_connection_t *) ev->data;
|
||||
|
||||
c->read->active = 1;
|
||||
c->write->active = 1;
|
||||
|
||||
ngx_log_debug3(NGX_LOG_DEBUG_EVENT, ev->log, 0,
|
||||
"iocp add: fd:%d k:%ui ov:%p", c->fd, key, &ev->ovlp);
|
||||
|
||||
if (CreateIoCompletionPort((HANDLE) c->fd, iocp, key, 0) == NULL) {
|
||||
ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
|
||||
"CreateIoCompletionPort() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_iocp_del_connection(ngx_connection_t *c, ngx_uint_t flags)
|
||||
{
|
||||
#if 0
|
||||
if (flags & NGX_CLOSE_EVENT) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
if (CancelIo((HANDLE) c->fd) == 0) {
|
||||
ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno, "CancelIo() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_iocp_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags)
|
||||
{
|
||||
int rc;
|
||||
u_int key;
|
||||
u_long bytes;
|
||||
ngx_err_t err;
|
||||
ngx_msec_t delta;
|
||||
ngx_event_t *ev;
|
||||
ngx_event_ovlp_t *ovlp;
|
||||
|
||||
if (timer == NGX_TIMER_INFINITE) {
|
||||
timer = INFINITE;
|
||||
}
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "iocp timer: %M", timer);
|
||||
|
||||
rc = GetQueuedCompletionStatus(iocp, &bytes, (PULONG_PTR) &key,
|
||||
(LPOVERLAPPED *) &ovlp, (u_long) timer);
|
||||
|
||||
if (rc == 0) {
|
||||
err = ngx_errno;
|
||||
} else {
|
||||
err = 0;
|
||||
}
|
||||
|
||||
delta = ngx_current_msec;
|
||||
|
||||
if (flags & NGX_UPDATE_TIME) {
|
||||
ngx_time_update();
|
||||
}
|
||||
|
||||
ngx_log_debug4(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
|
||||
"iocp: %d b:%d k:%d ov:%p", rc, bytes, key, ovlp);
|
||||
|
||||
if (timer != INFINITE) {
|
||||
delta = ngx_current_msec - delta;
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
|
||||
"iocp timer: %M, delta: %M", timer, delta);
|
||||
}
|
||||
|
||||
if (err) {
|
||||
if (ovlp == NULL) {
|
||||
if (err != WAIT_TIMEOUT) {
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, err,
|
||||
"GetQueuedCompletionStatus() failed");
|
||||
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
ovlp->error = err;
|
||||
}
|
||||
|
||||
if (ovlp == NULL) {
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
|
||||
"GetQueuedCompletionStatus() returned no operation");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
|
||||
ev = ovlp->event;
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, err, "iocp event:%p", ev);
|
||||
|
||||
|
||||
if (err == ERROR_NETNAME_DELETED /* the socket was closed */
|
||||
|| err == ERROR_OPERATION_ABORTED /* the operation was canceled */)
|
||||
{
|
||||
|
||||
/*
|
||||
* the WSA_OPERATION_ABORTED completion notification
|
||||
* for a file descriptor that was closed
|
||||
*/
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, err,
|
||||
"iocp: aborted event %p", ev);
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
if (err) {
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, err,
|
||||
"GetQueuedCompletionStatus() returned operation error");
|
||||
}
|
||||
|
||||
switch (key) {
|
||||
|
||||
case NGX_IOCP_ACCEPT:
|
||||
if (bytes) {
|
||||
ev->ready = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case NGX_IOCP_IO:
|
||||
ev->complete = 1;
|
||||
ev->ready = 1;
|
||||
break;
|
||||
|
||||
case NGX_IOCP_CONNECT:
|
||||
ev->ready = 1;
|
||||
}
|
||||
|
||||
ev->available = bytes;
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
|
||||
"iocp event handler: %p", ev->handler);
|
||||
|
||||
ev->handler(ev);
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
ngx_iocp_create_conf(ngx_cycle_t *cycle)
|
||||
{
|
||||
ngx_iocp_conf_t *cf;
|
||||
|
||||
cf = ngx_palloc(cycle->pool, sizeof(ngx_iocp_conf_t));
|
||||
if (cf == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cf->threads = NGX_CONF_UNSET;
|
||||
cf->post_acceptex = NGX_CONF_UNSET;
|
||||
cf->acceptex_read = NGX_CONF_UNSET;
|
||||
|
||||
return cf;
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
ngx_iocp_init_conf(ngx_cycle_t *cycle, void *conf)
|
||||
{
|
||||
ngx_iocp_conf_t *cf = conf;
|
||||
|
||||
ngx_conf_init_value(cf->threads, 0);
|
||||
ngx_conf_init_value(cf->post_acceptex, 10);
|
||||
ngx_conf_init_value(cf->acceptex_read, 1);
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
22
nginx/src/event/modules/ngx_iocp_module.h
Normal file
22
nginx/src/event/modules/ngx_iocp_module.h
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_IOCP_MODULE_H_INCLUDED_
|
||||
#define _NGX_IOCP_MODULE_H_INCLUDED_
|
||||
|
||||
|
||||
typedef struct {
|
||||
int threads;
|
||||
int post_acceptex;
|
||||
int acceptex_read;
|
||||
} ngx_iocp_conf_t;
|
||||
|
||||
|
||||
extern ngx_module_t ngx_iocp_module;
|
||||
|
||||
|
||||
#endif /* _NGX_IOCP_MODULE_H_INCLUDED_ */
|
||||
731
nginx/src/event/modules/ngx_kqueue_module.c
Normal file
731
nginx/src/event/modules/ngx_kqueue_module.c
Normal file
|
|
@ -0,0 +1,731 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_event.h>
|
||||
|
||||
|
||||
/* NetBSD up to 10.0 incompatibly defines kevent.udata as "intptr_t" */
|
||||
|
||||
#if (__NetBSD__ && __NetBSD_Version__ < 1000000000)
|
||||
#define NGX_KQUEUE_UDATA_T
|
||||
#else
|
||||
#define NGX_KQUEUE_UDATA_T (void *)
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_uint_t changes;
|
||||
ngx_uint_t events;
|
||||
} ngx_kqueue_conf_t;
|
||||
|
||||
|
||||
static ngx_int_t ngx_kqueue_init(ngx_cycle_t *cycle, ngx_msec_t timer);
|
||||
#ifdef EVFILT_USER
|
||||
static ngx_int_t ngx_kqueue_notify_init(ngx_log_t *log);
|
||||
#endif
|
||||
static void ngx_kqueue_done(ngx_cycle_t *cycle);
|
||||
static ngx_int_t ngx_kqueue_add_event(ngx_event_t *ev, ngx_int_t event,
|
||||
ngx_uint_t flags);
|
||||
static ngx_int_t ngx_kqueue_del_event(ngx_event_t *ev, ngx_int_t event,
|
||||
ngx_uint_t flags);
|
||||
static ngx_int_t ngx_kqueue_set_event(ngx_event_t *ev, ngx_int_t filter,
|
||||
ngx_uint_t flags);
|
||||
#ifdef EVFILT_USER
|
||||
static ngx_int_t ngx_kqueue_notify(ngx_event_handler_pt handler);
|
||||
#endif
|
||||
static ngx_int_t ngx_kqueue_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
|
||||
ngx_uint_t flags);
|
||||
static ngx_inline void ngx_kqueue_dump_event(ngx_log_t *log,
|
||||
struct kevent *kev);
|
||||
|
||||
static void *ngx_kqueue_create_conf(ngx_cycle_t *cycle);
|
||||
static char *ngx_kqueue_init_conf(ngx_cycle_t *cycle, void *conf);
|
||||
|
||||
|
||||
int ngx_kqueue = -1;
|
||||
|
||||
static struct kevent *change_list;
|
||||
static struct kevent *event_list;
|
||||
static ngx_uint_t max_changes, nchanges, nevents;
|
||||
|
||||
#ifdef EVFILT_USER
|
||||
static ngx_event_t notify_event;
|
||||
static struct kevent notify_kev;
|
||||
#endif
|
||||
|
||||
|
||||
static ngx_str_t kqueue_name = ngx_string("kqueue");
|
||||
|
||||
static ngx_command_t ngx_kqueue_commands[] = {
|
||||
|
||||
{ ngx_string("kqueue_changes"),
|
||||
NGX_EVENT_CONF|NGX_CONF_TAKE1,
|
||||
ngx_conf_set_num_slot,
|
||||
0,
|
||||
offsetof(ngx_kqueue_conf_t, changes),
|
||||
NULL },
|
||||
|
||||
{ ngx_string("kqueue_events"),
|
||||
NGX_EVENT_CONF|NGX_CONF_TAKE1,
|
||||
ngx_conf_set_num_slot,
|
||||
0,
|
||||
offsetof(ngx_kqueue_conf_t, events),
|
||||
NULL },
|
||||
|
||||
ngx_null_command
|
||||
};
|
||||
|
||||
|
||||
static ngx_event_module_t ngx_kqueue_module_ctx = {
|
||||
&kqueue_name,
|
||||
ngx_kqueue_create_conf, /* create configuration */
|
||||
ngx_kqueue_init_conf, /* init configuration */
|
||||
|
||||
{
|
||||
ngx_kqueue_add_event, /* add an event */
|
||||
ngx_kqueue_del_event, /* delete an event */
|
||||
ngx_kqueue_add_event, /* enable an event */
|
||||
ngx_kqueue_del_event, /* disable an event */
|
||||
NULL, /* add an connection */
|
||||
NULL, /* delete an connection */
|
||||
#ifdef EVFILT_USER
|
||||
ngx_kqueue_notify, /* trigger a notify */
|
||||
#else
|
||||
NULL, /* trigger a notify */
|
||||
#endif
|
||||
ngx_kqueue_process_events, /* process the events */
|
||||
ngx_kqueue_init, /* init the events */
|
||||
ngx_kqueue_done /* done the events */
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
ngx_module_t ngx_kqueue_module = {
|
||||
NGX_MODULE_V1,
|
||||
&ngx_kqueue_module_ctx, /* module context */
|
||||
ngx_kqueue_commands, /* module directives */
|
||||
NGX_EVENT_MODULE, /* module type */
|
||||
NULL, /* init master */
|
||||
NULL, /* init module */
|
||||
NULL, /* init process */
|
||||
NULL, /* init thread */
|
||||
NULL, /* exit thread */
|
||||
NULL, /* exit process */
|
||||
NULL, /* exit master */
|
||||
NGX_MODULE_V1_PADDING
|
||||
};
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_kqueue_init(ngx_cycle_t *cycle, ngx_msec_t timer)
|
||||
{
|
||||
ngx_kqueue_conf_t *kcf;
|
||||
struct timespec ts;
|
||||
#if (NGX_HAVE_TIMER_EVENT)
|
||||
struct kevent kev;
|
||||
#endif
|
||||
|
||||
kcf = ngx_event_get_conf(cycle->conf_ctx, ngx_kqueue_module);
|
||||
|
||||
if (ngx_kqueue == -1) {
|
||||
ngx_kqueue = kqueue();
|
||||
|
||||
if (ngx_kqueue == -1) {
|
||||
ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
|
||||
"kqueue() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
#ifdef EVFILT_USER
|
||||
if (ngx_kqueue_notify_init(cycle->log) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (max_changes < kcf->changes) {
|
||||
if (nchanges) {
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 0;
|
||||
|
||||
if (kevent(ngx_kqueue, change_list, (int) nchanges, NULL, 0, &ts)
|
||||
== -1)
|
||||
{
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
|
||||
"kevent() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
nchanges = 0;
|
||||
}
|
||||
|
||||
if (change_list) {
|
||||
ngx_free(change_list);
|
||||
}
|
||||
|
||||
change_list = ngx_alloc(kcf->changes * sizeof(struct kevent),
|
||||
cycle->log);
|
||||
if (change_list == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
max_changes = kcf->changes;
|
||||
|
||||
if (nevents < kcf->events) {
|
||||
if (event_list) {
|
||||
ngx_free(event_list);
|
||||
}
|
||||
|
||||
event_list = ngx_alloc(kcf->events * sizeof(struct kevent), cycle->log);
|
||||
if (event_list == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
ngx_event_flags = NGX_USE_ONESHOT_EVENT
|
||||
|NGX_USE_KQUEUE_EVENT
|
||||
|NGX_USE_VNODE_EVENT;
|
||||
|
||||
#if (NGX_HAVE_TIMER_EVENT)
|
||||
|
||||
if (timer) {
|
||||
kev.ident = 0;
|
||||
kev.filter = EVFILT_TIMER;
|
||||
kev.flags = EV_ADD|EV_ENABLE;
|
||||
kev.fflags = 0;
|
||||
kev.data = timer;
|
||||
kev.udata = NGX_KQUEUE_UDATA_T (uintptr_t) 0;
|
||||
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 0;
|
||||
|
||||
if (kevent(ngx_kqueue, &kev, 1, NULL, 0, &ts) == -1) {
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
|
||||
"kevent(EVFILT_TIMER) failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_event_flags |= NGX_USE_TIMER_EVENT;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if (NGX_HAVE_CLEAR_EVENT)
|
||||
ngx_event_flags |= NGX_USE_CLEAR_EVENT;
|
||||
#else
|
||||
ngx_event_flags |= NGX_USE_LEVEL_EVENT;
|
||||
#endif
|
||||
|
||||
#if (NGX_HAVE_LOWAT_EVENT)
|
||||
ngx_event_flags |= NGX_USE_LOWAT_EVENT;
|
||||
#endif
|
||||
|
||||
nevents = kcf->events;
|
||||
|
||||
ngx_io = ngx_os_io;
|
||||
|
||||
ngx_event_actions = ngx_kqueue_module_ctx.actions;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
#ifdef EVFILT_USER
|
||||
|
||||
static ngx_int_t
|
||||
ngx_kqueue_notify_init(ngx_log_t *log)
|
||||
{
|
||||
notify_kev.ident = 0;
|
||||
notify_kev.filter = EVFILT_USER;
|
||||
notify_kev.data = 0;
|
||||
notify_kev.flags = EV_ADD|EV_CLEAR;
|
||||
notify_kev.fflags = 0;
|
||||
notify_kev.udata = NGX_KQUEUE_UDATA_T (uintptr_t) 0;
|
||||
|
||||
if (kevent(ngx_kqueue, ¬ify_kev, 1, NULL, 0, NULL) == -1) {
|
||||
ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
|
||||
"kevent(EVFILT_USER, EV_ADD) failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
notify_event.active = 1;
|
||||
notify_event.log = log;
|
||||
|
||||
notify_kev.flags = 0;
|
||||
notify_kev.fflags = NOTE_TRIGGER;
|
||||
notify_kev.udata = NGX_KQUEUE_UDATA_T ((uintptr_t) ¬ify_event);
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
static void
|
||||
ngx_kqueue_done(ngx_cycle_t *cycle)
|
||||
{
|
||||
if (close(ngx_kqueue) == -1) {
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
|
||||
"kqueue close() failed");
|
||||
}
|
||||
|
||||
ngx_kqueue = -1;
|
||||
|
||||
ngx_free(change_list);
|
||||
ngx_free(event_list);
|
||||
|
||||
change_list = NULL;
|
||||
event_list = NULL;
|
||||
max_changes = 0;
|
||||
nchanges = 0;
|
||||
nevents = 0;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_kqueue_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
|
||||
{
|
||||
ngx_int_t rc;
|
||||
#if 0
|
||||
ngx_event_t *e;
|
||||
ngx_connection_t *c;
|
||||
#endif
|
||||
|
||||
ev->active = 1;
|
||||
ev->disabled = 0;
|
||||
ev->oneshot = (flags & NGX_ONESHOT_EVENT) ? 1 : 0;
|
||||
|
||||
#if 0
|
||||
|
||||
if (ev->index < nchanges
|
||||
&& ((uintptr_t) change_list[ev->index].udata & (uintptr_t) ~1)
|
||||
== (uintptr_t) ev)
|
||||
{
|
||||
if (change_list[ev->index].flags == EV_DISABLE) {
|
||||
|
||||
/*
|
||||
* if the EV_DISABLE is still not passed to a kernel
|
||||
* we will not pass it
|
||||
*/
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
|
||||
"kevent activated: %d: ft:%i",
|
||||
ngx_event_ident(ev->data), event);
|
||||
|
||||
if (ev->index < --nchanges) {
|
||||
e = (ngx_event_t *)
|
||||
((uintptr_t) change_list[nchanges].udata & (uintptr_t) ~1);
|
||||
change_list[ev->index] = change_list[nchanges];
|
||||
e->index = ev->index;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
c = ev->data;
|
||||
|
||||
ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
|
||||
"previous event on #%d were not passed in kernel", c->fd);
|
||||
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
rc = ngx_kqueue_set_event(ev, event, EV_ADD|EV_ENABLE|flags);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_kqueue_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
|
||||
{
|
||||
ngx_int_t rc;
|
||||
ngx_event_t *e;
|
||||
|
||||
ev->active = 0;
|
||||
ev->disabled = 0;
|
||||
|
||||
if (ev->index < nchanges
|
||||
&& ((uintptr_t) change_list[ev->index].udata & (uintptr_t) ~1)
|
||||
== (uintptr_t) ev)
|
||||
{
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
|
||||
"kevent deleted: %d: ft:%i",
|
||||
ngx_event_ident(ev->data), event);
|
||||
|
||||
/* if the event is still not passed to a kernel we will not pass it */
|
||||
|
||||
nchanges--;
|
||||
|
||||
if (ev->index < nchanges) {
|
||||
e = (ngx_event_t *)
|
||||
((uintptr_t) change_list[nchanges].udata & (uintptr_t) ~1);
|
||||
change_list[ev->index] = change_list[nchanges];
|
||||
e->index = ev->index;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* when the file descriptor is closed the kqueue automatically deletes
|
||||
* its filters so we do not need to delete explicitly the event
|
||||
* before the closing the file descriptor.
|
||||
*/
|
||||
|
||||
if (flags & NGX_CLOSE_EVENT) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
if (flags & NGX_DISABLE_EVENT) {
|
||||
ev->disabled = 1;
|
||||
|
||||
} else {
|
||||
flags |= EV_DELETE;
|
||||
}
|
||||
|
||||
rc = ngx_kqueue_set_event(ev, event, flags);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_kqueue_set_event(ngx_event_t *ev, ngx_int_t filter, ngx_uint_t flags)
|
||||
{
|
||||
struct kevent *kev;
|
||||
struct timespec ts;
|
||||
ngx_connection_t *c;
|
||||
|
||||
c = ev->data;
|
||||
|
||||
ngx_log_debug3(NGX_LOG_DEBUG_EVENT, ev->log, 0,
|
||||
"kevent set event: %d: ft:%i fl:%04Xi",
|
||||
c->fd, filter, flags);
|
||||
|
||||
if (nchanges >= max_changes) {
|
||||
ngx_log_error(NGX_LOG_WARN, ev->log, 0,
|
||||
"kqueue change list is filled up");
|
||||
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 0;
|
||||
|
||||
if (kevent(ngx_kqueue, change_list, (int) nchanges, NULL, 0, &ts)
|
||||
== -1)
|
||||
{
|
||||
ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno, "kevent() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
nchanges = 0;
|
||||
}
|
||||
|
||||
kev = &change_list[nchanges];
|
||||
|
||||
kev->ident = c->fd;
|
||||
kev->filter = (short) filter;
|
||||
kev->flags = (u_short) flags;
|
||||
kev->udata = NGX_KQUEUE_UDATA_T ((uintptr_t) ev | ev->instance);
|
||||
|
||||
if (filter == EVFILT_VNODE) {
|
||||
kev->fflags = NOTE_DELETE|NOTE_WRITE|NOTE_EXTEND
|
||||
|NOTE_ATTRIB|NOTE_RENAME
|
||||
#if (__FreeBSD__ == 4 && __FreeBSD_version >= 430000) \
|
||||
|| __FreeBSD_version >= 500018
|
||||
|NOTE_REVOKE
|
||||
#endif
|
||||
;
|
||||
kev->data = 0;
|
||||
|
||||
} else {
|
||||
#if (NGX_HAVE_LOWAT_EVENT)
|
||||
if (flags & NGX_LOWAT_EVENT) {
|
||||
kev->fflags = NOTE_LOWAT;
|
||||
kev->data = ev->available;
|
||||
|
||||
} else {
|
||||
kev->fflags = 0;
|
||||
kev->data = 0;
|
||||
}
|
||||
#else
|
||||
kev->fflags = 0;
|
||||
kev->data = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
ev->index = nchanges;
|
||||
nchanges++;
|
||||
|
||||
if (flags & NGX_FLUSH_EVENT) {
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 0;
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0, "kevent flush");
|
||||
|
||||
if (kevent(ngx_kqueue, change_list, (int) nchanges, NULL, 0, &ts)
|
||||
== -1)
|
||||
{
|
||||
ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno, "kevent() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
nchanges = 0;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
#ifdef EVFILT_USER
|
||||
|
||||
static ngx_int_t
|
||||
ngx_kqueue_notify(ngx_event_handler_pt handler)
|
||||
{
|
||||
notify_event.handler = handler;
|
||||
|
||||
if (kevent(ngx_kqueue, ¬ify_kev, 1, NULL, 0, NULL) == -1) {
|
||||
ngx_log_error(NGX_LOG_ALERT, notify_event.log, ngx_errno,
|
||||
"kevent(EVFILT_USER, NOTE_TRIGGER) failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_kqueue_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
|
||||
ngx_uint_t flags)
|
||||
{
|
||||
int events, n;
|
||||
ngx_int_t i, instance;
|
||||
ngx_uint_t level;
|
||||
ngx_err_t err;
|
||||
ngx_event_t *ev;
|
||||
ngx_queue_t *queue;
|
||||
struct timespec ts, *tp;
|
||||
|
||||
n = (int) nchanges;
|
||||
nchanges = 0;
|
||||
|
||||
if (timer == NGX_TIMER_INFINITE) {
|
||||
tp = NULL;
|
||||
|
||||
} else {
|
||||
|
||||
ts.tv_sec = timer / 1000;
|
||||
ts.tv_nsec = (timer % 1000) * 1000000;
|
||||
|
||||
/*
|
||||
* 64-bit Darwin kernel has the bug: kernel level ts.tv_nsec is
|
||||
* the int32_t while user level ts.tv_nsec is the long (64-bit),
|
||||
* so on the big endian PowerPC all nanoseconds are lost.
|
||||
*/
|
||||
|
||||
#if (NGX_DARWIN_KEVENT_BUG)
|
||||
ts.tv_nsec <<= 32;
|
||||
#endif
|
||||
|
||||
tp = &ts;
|
||||
}
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
|
||||
"kevent timer: %M, changes: %d", timer, n);
|
||||
|
||||
events = kevent(ngx_kqueue, change_list, n, event_list, (int) nevents, tp);
|
||||
|
||||
err = (events == -1) ? ngx_errno : 0;
|
||||
|
||||
if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) {
|
||||
ngx_time_update();
|
||||
}
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
|
||||
"kevent events: %d", events);
|
||||
|
||||
if (err) {
|
||||
if (err == NGX_EINTR) {
|
||||
|
||||
if (ngx_event_timer_alarm) {
|
||||
ngx_event_timer_alarm = 0;
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
level = NGX_LOG_INFO;
|
||||
|
||||
} else {
|
||||
level = NGX_LOG_ALERT;
|
||||
}
|
||||
|
||||
ngx_log_error(level, cycle->log, err, "kevent() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (events == 0) {
|
||||
if (timer != NGX_TIMER_INFINITE) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
|
||||
"kevent() returned no events without timeout");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
for (i = 0; i < events; i++) {
|
||||
|
||||
ngx_kqueue_dump_event(cycle->log, &event_list[i]);
|
||||
|
||||
if (event_list[i].flags & EV_ERROR) {
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, event_list[i].data,
|
||||
"kevent() error on %d filter:%d flags:%04Xd",
|
||||
(int) event_list[i].ident, event_list[i].filter,
|
||||
event_list[i].flags);
|
||||
continue;
|
||||
}
|
||||
|
||||
#if (NGX_HAVE_TIMER_EVENT)
|
||||
|
||||
if (event_list[i].filter == EVFILT_TIMER) {
|
||||
ngx_time_update();
|
||||
continue;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
ev = (ngx_event_t *) event_list[i].udata;
|
||||
|
||||
switch (event_list[i].filter) {
|
||||
|
||||
case EVFILT_READ:
|
||||
case EVFILT_WRITE:
|
||||
|
||||
instance = (uintptr_t) ev & 1;
|
||||
ev = (ngx_event_t *) ((uintptr_t) ev & (uintptr_t) ~1);
|
||||
|
||||
if (ev->closed || ev->instance != instance) {
|
||||
|
||||
/*
|
||||
* the stale event from a file descriptor
|
||||
* that was just closed in this iteration
|
||||
*/
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
|
||||
"kevent: stale event %p", ev);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ev->log && (ev->log->log_level & NGX_LOG_DEBUG_CONNECTION)) {
|
||||
ngx_kqueue_dump_event(ev->log, &event_list[i]);
|
||||
}
|
||||
|
||||
if (ev->oneshot) {
|
||||
ev->active = 0;
|
||||
}
|
||||
|
||||
ev->available = event_list[i].data;
|
||||
|
||||
if (event_list[i].flags & EV_EOF) {
|
||||
ev->pending_eof = 1;
|
||||
ev->kq_errno = event_list[i].fflags;
|
||||
}
|
||||
|
||||
ev->ready = 1;
|
||||
|
||||
break;
|
||||
|
||||
case EVFILT_VNODE:
|
||||
ev->kq_vnode = 1;
|
||||
|
||||
break;
|
||||
|
||||
case EVFILT_AIO:
|
||||
ev->complete = 1;
|
||||
ev->ready = 1;
|
||||
|
||||
break;
|
||||
|
||||
#ifdef EVFILT_USER
|
||||
case EVFILT_USER:
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
|
||||
"unexpected kevent() filter %d",
|
||||
event_list[i].filter);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (flags & NGX_POST_EVENTS) {
|
||||
queue = ev->accept ? &ngx_posted_accept_events
|
||||
: &ngx_posted_events;
|
||||
|
||||
ngx_post_event(ev, queue);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
ev->handler(ev);
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_inline void
|
||||
ngx_kqueue_dump_event(ngx_log_t *log, struct kevent *kev)
|
||||
{
|
||||
if (kev->ident > 0x8000000 && kev->ident != (unsigned) -1) {
|
||||
ngx_log_debug6(NGX_LOG_DEBUG_EVENT, log, 0,
|
||||
"kevent: %p: ft:%d fl:%04Xd ff:%08Xd d:%d ud:%p",
|
||||
(void *) kev->ident, kev->filter,
|
||||
kev->flags, kev->fflags,
|
||||
(int) kev->data, kev->udata);
|
||||
|
||||
} else {
|
||||
ngx_log_debug6(NGX_LOG_DEBUG_EVENT, log, 0,
|
||||
"kevent: %d: ft:%d fl:%04Xd ff:%08Xd d:%d ud:%p",
|
||||
(int) kev->ident, kev->filter,
|
||||
kev->flags, kev->fflags,
|
||||
(int) kev->data, kev->udata);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
ngx_kqueue_create_conf(ngx_cycle_t *cycle)
|
||||
{
|
||||
ngx_kqueue_conf_t *kcf;
|
||||
|
||||
kcf = ngx_palloc(cycle->pool, sizeof(ngx_kqueue_conf_t));
|
||||
if (kcf == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
kcf->changes = NGX_CONF_UNSET;
|
||||
kcf->events = NGX_CONF_UNSET;
|
||||
|
||||
return kcf;
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
ngx_kqueue_init_conf(ngx_cycle_t *cycle, void *conf)
|
||||
{
|
||||
ngx_kqueue_conf_t *kcf = conf;
|
||||
|
||||
ngx_conf_init_uint_value(kcf->changes, 512);
|
||||
ngx_conf_init_uint_value(kcf->events, 512);
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
416
nginx/src/event/modules/ngx_poll_module.c
Normal file
416
nginx/src/event/modules/ngx_poll_module.c
Normal file
|
|
@ -0,0 +1,416 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_event.h>
|
||||
|
||||
|
||||
static ngx_int_t ngx_poll_init(ngx_cycle_t *cycle, ngx_msec_t timer);
|
||||
static void ngx_poll_done(ngx_cycle_t *cycle);
|
||||
static ngx_int_t ngx_poll_add_event(ngx_event_t *ev, ngx_int_t event,
|
||||
ngx_uint_t flags);
|
||||
static ngx_int_t ngx_poll_del_event(ngx_event_t *ev, ngx_int_t event,
|
||||
ngx_uint_t flags);
|
||||
static ngx_int_t ngx_poll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
|
||||
ngx_uint_t flags);
|
||||
static char *ngx_poll_init_conf(ngx_cycle_t *cycle, void *conf);
|
||||
|
||||
|
||||
static struct pollfd *event_list;
|
||||
static ngx_uint_t nevents;
|
||||
|
||||
|
||||
static ngx_str_t poll_name = ngx_string("poll");
|
||||
|
||||
static ngx_event_module_t ngx_poll_module_ctx = {
|
||||
&poll_name,
|
||||
NULL, /* create configuration */
|
||||
ngx_poll_init_conf, /* init configuration */
|
||||
|
||||
{
|
||||
ngx_poll_add_event, /* add an event */
|
||||
ngx_poll_del_event, /* delete an event */
|
||||
ngx_poll_add_event, /* enable an event */
|
||||
ngx_poll_del_event, /* disable an event */
|
||||
NULL, /* add an connection */
|
||||
NULL, /* delete an connection */
|
||||
NULL, /* trigger a notify */
|
||||
ngx_poll_process_events, /* process the events */
|
||||
ngx_poll_init, /* init the events */
|
||||
ngx_poll_done /* done the events */
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
ngx_module_t ngx_poll_module = {
|
||||
NGX_MODULE_V1,
|
||||
&ngx_poll_module_ctx, /* module context */
|
||||
NULL, /* module directives */
|
||||
NGX_EVENT_MODULE, /* module type */
|
||||
NULL, /* init master */
|
||||
NULL, /* init module */
|
||||
NULL, /* init process */
|
||||
NULL, /* init thread */
|
||||
NULL, /* exit thread */
|
||||
NULL, /* exit process */
|
||||
NULL, /* exit master */
|
||||
NGX_MODULE_V1_PADDING
|
||||
};
|
||||
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_poll_init(ngx_cycle_t *cycle, ngx_msec_t timer)
|
||||
{
|
||||
struct pollfd *list;
|
||||
|
||||
if (event_list == NULL) {
|
||||
nevents = 0;
|
||||
}
|
||||
|
||||
if (ngx_process >= NGX_PROCESS_WORKER
|
||||
|| cycle->old_cycle == NULL
|
||||
|| cycle->old_cycle->connection_n < cycle->connection_n)
|
||||
{
|
||||
list = ngx_alloc(sizeof(struct pollfd) * cycle->connection_n,
|
||||
cycle->log);
|
||||
if (list == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (event_list) {
|
||||
ngx_memcpy(list, event_list, sizeof(struct pollfd) * nevents);
|
||||
ngx_free(event_list);
|
||||
}
|
||||
|
||||
event_list = list;
|
||||
}
|
||||
|
||||
ngx_io = ngx_os_io;
|
||||
|
||||
ngx_event_actions = ngx_poll_module_ctx.actions;
|
||||
|
||||
ngx_event_flags = NGX_USE_LEVEL_EVENT|NGX_USE_FD_EVENT;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_poll_done(ngx_cycle_t *cycle)
|
||||
{
|
||||
ngx_free(event_list);
|
||||
|
||||
event_list = NULL;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_poll_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
|
||||
{
|
||||
ngx_event_t *e;
|
||||
ngx_connection_t *c;
|
||||
|
||||
c = ev->data;
|
||||
|
||||
ev->active = 1;
|
||||
|
||||
if (ev->index != NGX_INVALID_INDEX) {
|
||||
ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
|
||||
"poll event fd:%d ev:%i is already set", c->fd, event);
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
if (event == NGX_READ_EVENT) {
|
||||
e = c->write;
|
||||
#if (NGX_READ_EVENT != POLLIN)
|
||||
event = POLLIN;
|
||||
#endif
|
||||
|
||||
} else {
|
||||
e = c->read;
|
||||
#if (NGX_WRITE_EVENT != POLLOUT)
|
||||
event = POLLOUT;
|
||||
#endif
|
||||
}
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
|
||||
"poll add event: fd:%d ev:%i", c->fd, event);
|
||||
|
||||
if (e == NULL || e->index == NGX_INVALID_INDEX) {
|
||||
event_list[nevents].fd = c->fd;
|
||||
event_list[nevents].events = (short) event;
|
||||
event_list[nevents].revents = 0;
|
||||
|
||||
ev->index = nevents;
|
||||
nevents++;
|
||||
|
||||
} else {
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ev->log, 0,
|
||||
"poll add index: %i", e->index);
|
||||
|
||||
event_list[e->index].events |= (short) event;
|
||||
ev->index = e->index;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_poll_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
|
||||
{
|
||||
ngx_event_t *e;
|
||||
ngx_connection_t *c;
|
||||
|
||||
c = ev->data;
|
||||
|
||||
ev->active = 0;
|
||||
|
||||
if (ev->index == NGX_INVALID_INDEX) {
|
||||
ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
|
||||
"poll event fd:%d ev:%i is already deleted",
|
||||
c->fd, event);
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
if (event == NGX_READ_EVENT) {
|
||||
e = c->write;
|
||||
#if (NGX_READ_EVENT != POLLIN)
|
||||
event = POLLIN;
|
||||
#endif
|
||||
|
||||
} else {
|
||||
e = c->read;
|
||||
#if (NGX_WRITE_EVENT != POLLOUT)
|
||||
event = POLLOUT;
|
||||
#endif
|
||||
}
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
|
||||
"poll del event: fd:%d ev:%i", c->fd, event);
|
||||
|
||||
if (e == NULL || e->index == NGX_INVALID_INDEX) {
|
||||
nevents--;
|
||||
|
||||
if (ev->index < nevents) {
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
|
||||
"index: copy event %ui to %i", nevents, ev->index);
|
||||
|
||||
event_list[ev->index] = event_list[nevents];
|
||||
|
||||
c = ngx_cycle->files[event_list[nevents].fd];
|
||||
|
||||
if (c->fd == -1) {
|
||||
ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
|
||||
"unexpected last event");
|
||||
|
||||
} else {
|
||||
if (c->read->index == nevents) {
|
||||
c->read->index = ev->index;
|
||||
}
|
||||
|
||||
if (c->write->index == nevents) {
|
||||
c->write->index = ev->index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ev->log, 0,
|
||||
"poll del index: %i", e->index);
|
||||
|
||||
event_list[e->index].events &= (short) ~event;
|
||||
}
|
||||
|
||||
ev->index = NGX_INVALID_INDEX;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_poll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags)
|
||||
{
|
||||
int ready, revents;
|
||||
ngx_err_t err;
|
||||
ngx_uint_t i, found, level;
|
||||
ngx_event_t *ev;
|
||||
ngx_queue_t *queue;
|
||||
ngx_connection_t *c;
|
||||
|
||||
/* NGX_TIMER_INFINITE == INFTIM */
|
||||
|
||||
#if (NGX_DEBUG0)
|
||||
if (cycle->log->log_level & NGX_LOG_DEBUG_ALL) {
|
||||
for (i = 0; i < nevents; i++) {
|
||||
ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
|
||||
"poll: %ui: fd:%d ev:%04Xd",
|
||||
i, event_list[i].fd, event_list[i].events);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "poll timer: %M", timer);
|
||||
|
||||
ready = poll(event_list, (u_int) nevents, (int) timer);
|
||||
|
||||
err = (ready == -1) ? ngx_errno : 0;
|
||||
|
||||
if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) {
|
||||
ngx_time_update();
|
||||
}
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
|
||||
"poll ready %d of %ui", ready, nevents);
|
||||
|
||||
if (err) {
|
||||
if (err == NGX_EINTR) {
|
||||
|
||||
if (ngx_event_timer_alarm) {
|
||||
ngx_event_timer_alarm = 0;
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
level = NGX_LOG_INFO;
|
||||
|
||||
} else {
|
||||
level = NGX_LOG_ALERT;
|
||||
}
|
||||
|
||||
ngx_log_error(level, cycle->log, err, "poll() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (ready == 0) {
|
||||
if (timer != NGX_TIMER_INFINITE) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
|
||||
"poll() returned no events without timeout");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
for (i = 0; i < nevents && ready; i++) {
|
||||
|
||||
revents = event_list[i].revents;
|
||||
|
||||
#if 1
|
||||
ngx_log_debug4(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
|
||||
"poll: %ui: fd:%d ev:%04Xd rev:%04Xd",
|
||||
i, event_list[i].fd, event_list[i].events, revents);
|
||||
#else
|
||||
if (revents) {
|
||||
ngx_log_debug4(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
|
||||
"poll: %ui: fd:%d ev:%04Xd rev:%04Xd",
|
||||
i, event_list[i].fd, event_list[i].events, revents);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (revents & POLLNVAL) {
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
|
||||
"poll() error fd:%d ev:%04Xd rev:%04Xd",
|
||||
event_list[i].fd, event_list[i].events, revents);
|
||||
}
|
||||
|
||||
if (revents & ~(POLLIN|POLLOUT|POLLERR|POLLHUP|POLLNVAL)) {
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
|
||||
"strange poll() events fd:%d ev:%04Xd rev:%04Xd",
|
||||
event_list[i].fd, event_list[i].events, revents);
|
||||
}
|
||||
|
||||
if (event_list[i].fd == -1) {
|
||||
/*
|
||||
* the disabled event, a workaround for our possible bug,
|
||||
* see the comment below
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
|
||||
c = ngx_cycle->files[event_list[i].fd];
|
||||
|
||||
if (c->fd == -1) {
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "unexpected event");
|
||||
|
||||
/*
|
||||
* it is certainly our fault and it should be investigated,
|
||||
* in the meantime we disable this event to avoid a CPU spinning
|
||||
*/
|
||||
|
||||
if (i == nevents - 1) {
|
||||
nevents--;
|
||||
} else {
|
||||
event_list[i].fd = -1;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (revents & (POLLERR|POLLHUP|POLLNVAL)) {
|
||||
|
||||
/*
|
||||
* if the error events were returned, add POLLIN and POLLOUT
|
||||
* to handle the events at least in one active handler
|
||||
*/
|
||||
|
||||
revents |= POLLIN|POLLOUT;
|
||||
}
|
||||
|
||||
found = 0;
|
||||
|
||||
if ((revents & POLLIN) && c->read->active) {
|
||||
found = 1;
|
||||
|
||||
ev = c->read;
|
||||
ev->ready = 1;
|
||||
ev->available = -1;
|
||||
|
||||
queue = ev->accept ? &ngx_posted_accept_events
|
||||
: &ngx_posted_events;
|
||||
|
||||
ngx_post_event(ev, queue);
|
||||
}
|
||||
|
||||
if ((revents & POLLOUT) && c->write->active) {
|
||||
found = 1;
|
||||
|
||||
ev = c->write;
|
||||
ev->ready = 1;
|
||||
|
||||
ngx_post_event(ev, &ngx_posted_events);
|
||||
}
|
||||
|
||||
if (found) {
|
||||
ready--;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (ready != 0) {
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "poll ready != events");
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
ngx_poll_init_conf(ngx_cycle_t *cycle, void *conf)
|
||||
{
|
||||
ngx_event_conf_t *ecf;
|
||||
|
||||
ecf = ngx_event_get_conf(cycle->conf_ctx, ngx_event_core_module);
|
||||
|
||||
if (ecf->use != ngx_poll_module.ctx_index) {
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
424
nginx/src/event/modules/ngx_select_module.c
Normal file
424
nginx/src/event/modules/ngx_select_module.c
Normal file
|
|
@ -0,0 +1,424 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_event.h>
|
||||
|
||||
|
||||
static ngx_int_t ngx_select_init(ngx_cycle_t *cycle, ngx_msec_t timer);
|
||||
static void ngx_select_done(ngx_cycle_t *cycle);
|
||||
static ngx_int_t ngx_select_add_event(ngx_event_t *ev, ngx_int_t event,
|
||||
ngx_uint_t flags);
|
||||
static ngx_int_t ngx_select_del_event(ngx_event_t *ev, ngx_int_t event,
|
||||
ngx_uint_t flags);
|
||||
static ngx_int_t ngx_select_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
|
||||
ngx_uint_t flags);
|
||||
static void ngx_select_repair_fd_sets(ngx_cycle_t *cycle);
|
||||
static char *ngx_select_init_conf(ngx_cycle_t *cycle, void *conf);
|
||||
|
||||
|
||||
static fd_set master_read_fd_set;
|
||||
static fd_set master_write_fd_set;
|
||||
static fd_set work_read_fd_set;
|
||||
static fd_set work_write_fd_set;
|
||||
|
||||
static ngx_int_t max_fd;
|
||||
static ngx_uint_t nevents;
|
||||
|
||||
static ngx_event_t **event_index;
|
||||
|
||||
|
||||
static ngx_str_t select_name = ngx_string("select");
|
||||
|
||||
static ngx_event_module_t ngx_select_module_ctx = {
|
||||
&select_name,
|
||||
NULL, /* create configuration */
|
||||
ngx_select_init_conf, /* init configuration */
|
||||
|
||||
{
|
||||
ngx_select_add_event, /* add an event */
|
||||
ngx_select_del_event, /* delete an event */
|
||||
ngx_select_add_event, /* enable an event */
|
||||
ngx_select_del_event, /* disable an event */
|
||||
NULL, /* add an connection */
|
||||
NULL, /* delete an connection */
|
||||
NULL, /* trigger a notify */
|
||||
ngx_select_process_events, /* process the events */
|
||||
ngx_select_init, /* init the events */
|
||||
ngx_select_done /* done the events */
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
ngx_module_t ngx_select_module = {
|
||||
NGX_MODULE_V1,
|
||||
&ngx_select_module_ctx, /* module context */
|
||||
NULL, /* module directives */
|
||||
NGX_EVENT_MODULE, /* module type */
|
||||
NULL, /* init master */
|
||||
NULL, /* init module */
|
||||
NULL, /* init process */
|
||||
NULL, /* init thread */
|
||||
NULL, /* exit thread */
|
||||
NULL, /* exit process */
|
||||
NULL, /* exit master */
|
||||
NGX_MODULE_V1_PADDING
|
||||
};
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_select_init(ngx_cycle_t *cycle, ngx_msec_t timer)
|
||||
{
|
||||
ngx_event_t **index;
|
||||
|
||||
if (event_index == NULL) {
|
||||
FD_ZERO(&master_read_fd_set);
|
||||
FD_ZERO(&master_write_fd_set);
|
||||
nevents = 0;
|
||||
}
|
||||
|
||||
if (ngx_process >= NGX_PROCESS_WORKER
|
||||
|| cycle->old_cycle == NULL
|
||||
|| cycle->old_cycle->connection_n < cycle->connection_n)
|
||||
{
|
||||
index = ngx_alloc(sizeof(ngx_event_t *) * 2 * cycle->connection_n,
|
||||
cycle->log);
|
||||
if (index == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (event_index) {
|
||||
ngx_memcpy(index, event_index, sizeof(ngx_event_t *) * nevents);
|
||||
ngx_free(event_index);
|
||||
}
|
||||
|
||||
event_index = index;
|
||||
}
|
||||
|
||||
ngx_io = ngx_os_io;
|
||||
|
||||
ngx_event_actions = ngx_select_module_ctx.actions;
|
||||
|
||||
ngx_event_flags = NGX_USE_LEVEL_EVENT;
|
||||
|
||||
max_fd = -1;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_select_done(ngx_cycle_t *cycle)
|
||||
{
|
||||
ngx_free(event_index);
|
||||
|
||||
event_index = NULL;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_select_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
|
||||
{
|
||||
ngx_connection_t *c;
|
||||
|
||||
c = ev->data;
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
|
||||
"select add event fd:%d ev:%i", c->fd, event);
|
||||
|
||||
if (ev->index != NGX_INVALID_INDEX) {
|
||||
ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
|
||||
"select event fd:%d ev:%i is already set", c->fd, event);
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
if ((event == NGX_READ_EVENT && ev->write)
|
||||
|| (event == NGX_WRITE_EVENT && !ev->write))
|
||||
{
|
||||
ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
|
||||
"invalid select %s event fd:%d ev:%i",
|
||||
ev->write ? "write" : "read", c->fd, event);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (event == NGX_READ_EVENT) {
|
||||
FD_SET(c->fd, &master_read_fd_set);
|
||||
|
||||
} else if (event == NGX_WRITE_EVENT) {
|
||||
FD_SET(c->fd, &master_write_fd_set);
|
||||
}
|
||||
|
||||
if (max_fd != -1 && max_fd < c->fd) {
|
||||
max_fd = c->fd;
|
||||
}
|
||||
|
||||
ev->active = 1;
|
||||
|
||||
event_index[nevents] = ev;
|
||||
ev->index = nevents;
|
||||
nevents++;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_select_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
|
||||
{
|
||||
ngx_event_t *e;
|
||||
ngx_connection_t *c;
|
||||
|
||||
c = ev->data;
|
||||
|
||||
ev->active = 0;
|
||||
|
||||
if (ev->index == NGX_INVALID_INDEX) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
|
||||
"select del event fd:%d ev:%i", c->fd, event);
|
||||
|
||||
if (event == NGX_READ_EVENT) {
|
||||
FD_CLR(c->fd, &master_read_fd_set);
|
||||
|
||||
} else if (event == NGX_WRITE_EVENT) {
|
||||
FD_CLR(c->fd, &master_write_fd_set);
|
||||
}
|
||||
|
||||
if (max_fd == c->fd) {
|
||||
max_fd = -1;
|
||||
}
|
||||
|
||||
if (ev->index < --nevents) {
|
||||
e = event_index[nevents];
|
||||
event_index[ev->index] = e;
|
||||
e->index = ev->index;
|
||||
}
|
||||
|
||||
ev->index = NGX_INVALID_INDEX;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_select_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
|
||||
ngx_uint_t flags)
|
||||
{
|
||||
int ready, nready;
|
||||
ngx_err_t err;
|
||||
ngx_uint_t i, found;
|
||||
ngx_event_t *ev;
|
||||
ngx_queue_t *queue;
|
||||
struct timeval tv, *tp;
|
||||
ngx_connection_t *c;
|
||||
|
||||
if (max_fd == -1) {
|
||||
for (i = 0; i < nevents; i++) {
|
||||
c = event_index[i]->data;
|
||||
if (max_fd < c->fd) {
|
||||
max_fd = c->fd;
|
||||
}
|
||||
}
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
|
||||
"change max_fd: %i", max_fd);
|
||||
}
|
||||
|
||||
#if (NGX_DEBUG)
|
||||
if (cycle->log->log_level & NGX_LOG_DEBUG_ALL) {
|
||||
for (i = 0; i < nevents; i++) {
|
||||
ev = event_index[i];
|
||||
c = ev->data;
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
|
||||
"select event: fd:%d wr:%d", c->fd, ev->write);
|
||||
}
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
|
||||
"max_fd: %i", max_fd);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (timer == NGX_TIMER_INFINITE) {
|
||||
tp = NULL;
|
||||
|
||||
} else {
|
||||
tv.tv_sec = (long) (timer / 1000);
|
||||
tv.tv_usec = (long) ((timer % 1000) * 1000);
|
||||
tp = &tv;
|
||||
}
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
|
||||
"select timer: %M", timer);
|
||||
|
||||
work_read_fd_set = master_read_fd_set;
|
||||
work_write_fd_set = master_write_fd_set;
|
||||
|
||||
ready = select(max_fd + 1, &work_read_fd_set, &work_write_fd_set, NULL, tp);
|
||||
|
||||
err = (ready == -1) ? ngx_errno : 0;
|
||||
|
||||
if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) {
|
||||
ngx_time_update();
|
||||
}
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
|
||||
"select ready %d", ready);
|
||||
|
||||
if (err) {
|
||||
ngx_uint_t level;
|
||||
|
||||
if (err == NGX_EINTR) {
|
||||
|
||||
if (ngx_event_timer_alarm) {
|
||||
ngx_event_timer_alarm = 0;
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
level = NGX_LOG_INFO;
|
||||
|
||||
} else {
|
||||
level = NGX_LOG_ALERT;
|
||||
}
|
||||
|
||||
ngx_log_error(level, cycle->log, err, "select() failed");
|
||||
|
||||
if (err == NGX_EBADF) {
|
||||
ngx_select_repair_fd_sets(cycle);
|
||||
}
|
||||
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (ready == 0) {
|
||||
if (timer != NGX_TIMER_INFINITE) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
|
||||
"select() returned no events without timeout");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
nready = 0;
|
||||
|
||||
for (i = 0; i < nevents; i++) {
|
||||
ev = event_index[i];
|
||||
c = ev->data;
|
||||
found = 0;
|
||||
|
||||
if (ev->write) {
|
||||
if (FD_ISSET(c->fd, &work_write_fd_set)) {
|
||||
found = 1;
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
|
||||
"select write %d", c->fd);
|
||||
}
|
||||
|
||||
} else {
|
||||
if (FD_ISSET(c->fd, &work_read_fd_set)) {
|
||||
found = 1;
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
|
||||
"select read %d", c->fd);
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
ev->ready = 1;
|
||||
ev->available = -1;
|
||||
|
||||
queue = ev->accept ? &ngx_posted_accept_events
|
||||
: &ngx_posted_events;
|
||||
|
||||
ngx_post_event(ev, queue);
|
||||
|
||||
nready++;
|
||||
}
|
||||
}
|
||||
|
||||
if (ready != nready) {
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
|
||||
"select ready != events: %d:%d", ready, nready);
|
||||
|
||||
ngx_select_repair_fd_sets(cycle);
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_select_repair_fd_sets(ngx_cycle_t *cycle)
|
||||
{
|
||||
int n;
|
||||
socklen_t len;
|
||||
ngx_err_t err;
|
||||
ngx_socket_t s;
|
||||
|
||||
for (s = 0; s <= max_fd; s++) {
|
||||
|
||||
if (FD_ISSET(s, &master_read_fd_set) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
len = sizeof(int);
|
||||
|
||||
if (getsockopt(s, SOL_SOCKET, SO_TYPE, &n, &len) == -1) {
|
||||
err = ngx_socket_errno;
|
||||
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, err,
|
||||
"invalid descriptor #%d in read fd_set", s);
|
||||
|
||||
FD_CLR(s, &master_read_fd_set);
|
||||
}
|
||||
}
|
||||
|
||||
for (s = 0; s <= max_fd; s++) {
|
||||
|
||||
if (FD_ISSET(s, &master_write_fd_set) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
len = sizeof(int);
|
||||
|
||||
if (getsockopt(s, SOL_SOCKET, SO_TYPE, &n, &len) == -1) {
|
||||
err = ngx_socket_errno;
|
||||
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, err,
|
||||
"invalid descriptor #%d in write fd_set", s);
|
||||
|
||||
FD_CLR(s, &master_write_fd_set);
|
||||
}
|
||||
}
|
||||
|
||||
max_fd = -1;
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
ngx_select_init_conf(ngx_cycle_t *cycle, void *conf)
|
||||
{
|
||||
ngx_event_conf_t *ecf;
|
||||
|
||||
ecf = ngx_event_get_conf(cycle->conf_ctx, ngx_event_core_module);
|
||||
|
||||
if (ecf->use != ngx_select_module.ctx_index) {
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
/* disable warning: the default FD_SETSIZE is 1024U in FreeBSD 5.x */
|
||||
|
||||
if (cycle->connection_n > FD_SETSIZE) {
|
||||
ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
|
||||
"the maximum number of files "
|
||||
"supported by select() is %ud", FD_SETSIZE);
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
436
nginx/src/event/modules/ngx_win32_poll_module.c
Normal file
436
nginx/src/event/modules/ngx_win32_poll_module.c
Normal file
|
|
@ -0,0 +1,436 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Maxim Dounin
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_event.h>
|
||||
|
||||
|
||||
static ngx_int_t ngx_poll_init(ngx_cycle_t *cycle, ngx_msec_t timer);
|
||||
static void ngx_poll_done(ngx_cycle_t *cycle);
|
||||
static ngx_int_t ngx_poll_add_event(ngx_event_t *ev, ngx_int_t event,
|
||||
ngx_uint_t flags);
|
||||
static ngx_int_t ngx_poll_del_event(ngx_event_t *ev, ngx_int_t event,
|
||||
ngx_uint_t flags);
|
||||
static ngx_int_t ngx_poll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
|
||||
ngx_uint_t flags);
|
||||
static char *ngx_poll_init_conf(ngx_cycle_t *cycle, void *conf);
|
||||
|
||||
|
||||
static struct pollfd *event_list;
|
||||
static ngx_connection_t **event_index;
|
||||
static ngx_uint_t nevents;
|
||||
|
||||
|
||||
static ngx_str_t poll_name = ngx_string("poll");
|
||||
|
||||
static ngx_event_module_t ngx_poll_module_ctx = {
|
||||
&poll_name,
|
||||
NULL, /* create configuration */
|
||||
ngx_poll_init_conf, /* init configuration */
|
||||
|
||||
{
|
||||
ngx_poll_add_event, /* add an event */
|
||||
ngx_poll_del_event, /* delete an event */
|
||||
ngx_poll_add_event, /* enable an event */
|
||||
ngx_poll_del_event, /* disable an event */
|
||||
NULL, /* add an connection */
|
||||
NULL, /* delete an connection */
|
||||
NULL, /* trigger a notify */
|
||||
ngx_poll_process_events, /* process the events */
|
||||
ngx_poll_init, /* init the events */
|
||||
ngx_poll_done /* done the events */
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
ngx_module_t ngx_poll_module = {
|
||||
NGX_MODULE_V1,
|
||||
&ngx_poll_module_ctx, /* module context */
|
||||
NULL, /* module directives */
|
||||
NGX_EVENT_MODULE, /* module type */
|
||||
NULL, /* init master */
|
||||
NULL, /* init module */
|
||||
NULL, /* init process */
|
||||
NULL, /* init thread */
|
||||
NULL, /* exit thread */
|
||||
NULL, /* exit process */
|
||||
NULL, /* exit master */
|
||||
NGX_MODULE_V1_PADDING
|
||||
};
|
||||
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_poll_init(ngx_cycle_t *cycle, ngx_msec_t timer)
|
||||
{
|
||||
struct pollfd *list;
|
||||
ngx_connection_t **index;
|
||||
|
||||
if (event_list == NULL) {
|
||||
nevents = 0;
|
||||
}
|
||||
|
||||
if (ngx_process >= NGX_PROCESS_WORKER
|
||||
|| cycle->old_cycle == NULL
|
||||
|| cycle->old_cycle->connection_n < cycle->connection_n)
|
||||
{
|
||||
list = ngx_alloc(sizeof(struct pollfd) * cycle->connection_n,
|
||||
cycle->log);
|
||||
if (list == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (event_list) {
|
||||
ngx_memcpy(list, event_list, sizeof(struct pollfd) * nevents);
|
||||
ngx_free(event_list);
|
||||
}
|
||||
|
||||
event_list = list;
|
||||
|
||||
index = ngx_alloc(sizeof(ngx_connection_t *) * cycle->connection_n,
|
||||
cycle->log);
|
||||
if (index == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (event_index) {
|
||||
ngx_memcpy(index, event_index,
|
||||
sizeof(ngx_connection_t *) * nevents);
|
||||
ngx_free(event_index);
|
||||
}
|
||||
|
||||
event_index = index;
|
||||
}
|
||||
|
||||
ngx_io = ngx_os_io;
|
||||
|
||||
ngx_event_actions = ngx_poll_module_ctx.actions;
|
||||
|
||||
ngx_event_flags = NGX_USE_LEVEL_EVENT;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_poll_done(ngx_cycle_t *cycle)
|
||||
{
|
||||
ngx_free(event_list);
|
||||
ngx_free(event_index);
|
||||
|
||||
event_list = NULL;
|
||||
event_index = NULL;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_poll_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
|
||||
{
|
||||
ngx_event_t *e;
|
||||
ngx_connection_t *c;
|
||||
|
||||
c = ev->data;
|
||||
|
||||
ev->active = 1;
|
||||
|
||||
if (ev->index != NGX_INVALID_INDEX) {
|
||||
ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
|
||||
"poll event fd:%d ev:%i is already set", c->fd, event);
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
if (event == NGX_READ_EVENT) {
|
||||
e = c->write;
|
||||
#if (NGX_READ_EVENT != POLLIN)
|
||||
event = POLLIN;
|
||||
#endif
|
||||
|
||||
} else {
|
||||
e = c->read;
|
||||
#if (NGX_WRITE_EVENT != POLLOUT)
|
||||
event = POLLOUT;
|
||||
#endif
|
||||
}
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
|
||||
"poll add event: fd:%d ev:%i", c->fd, event);
|
||||
|
||||
if (e == NULL || e->index == NGX_INVALID_INDEX) {
|
||||
|
||||
event_list[nevents].fd = c->fd;
|
||||
event_list[nevents].events = (short) event;
|
||||
event_list[nevents].revents = 0;
|
||||
|
||||
event_index[nevents] = c;
|
||||
|
||||
ev->index = nevents;
|
||||
nevents++;
|
||||
|
||||
} else {
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ev->log, 0,
|
||||
"poll add index: %i", e->index);
|
||||
|
||||
event_list[e->index].events |= (short) event;
|
||||
ev->index = e->index;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_poll_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
|
||||
{
|
||||
ngx_event_t *e;
|
||||
ngx_connection_t *c;
|
||||
|
||||
c = ev->data;
|
||||
|
||||
ev->active = 0;
|
||||
|
||||
if (ev->index == NGX_INVALID_INDEX) {
|
||||
ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
|
||||
"poll event fd:%d ev:%i is already deleted",
|
||||
c->fd, event);
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
if (event == NGX_READ_EVENT) {
|
||||
e = c->write;
|
||||
#if (NGX_READ_EVENT != POLLIN)
|
||||
event = POLLIN;
|
||||
#endif
|
||||
|
||||
} else {
|
||||
e = c->read;
|
||||
#if (NGX_WRITE_EVENT != POLLOUT)
|
||||
event = POLLOUT;
|
||||
#endif
|
||||
}
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
|
||||
"poll del event: fd:%d ev:%i", c->fd, event);
|
||||
|
||||
if (e == NULL || e->index == NGX_INVALID_INDEX) {
|
||||
nevents--;
|
||||
|
||||
if (ev->index < nevents) {
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
|
||||
"index: copy event %ui to %i", nevents, ev->index);
|
||||
|
||||
event_list[ev->index] = event_list[nevents];
|
||||
event_index[ev->index] = event_index[nevents];
|
||||
|
||||
c = event_index[ev->index];
|
||||
|
||||
if (c->fd == (ngx_socket_t) -1) {
|
||||
ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
|
||||
"unexpected last event");
|
||||
|
||||
} else {
|
||||
if (c->read->index == nevents) {
|
||||
c->read->index = ev->index;
|
||||
}
|
||||
|
||||
if (c->write->index == nevents) {
|
||||
c->write->index = ev->index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ev->log, 0,
|
||||
"poll del index: %i", e->index);
|
||||
|
||||
event_list[e->index].events &= (short) ~event;
|
||||
}
|
||||
|
||||
ev->index = NGX_INVALID_INDEX;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_poll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags)
|
||||
{
|
||||
int ready, revents;
|
||||
ngx_err_t err;
|
||||
ngx_uint_t i, found;
|
||||
ngx_event_t *ev;
|
||||
ngx_queue_t *queue;
|
||||
ngx_connection_t *c;
|
||||
|
||||
/* NGX_TIMER_INFINITE == INFTIM */
|
||||
|
||||
#if (NGX_DEBUG0)
|
||||
if (cycle->log->log_level & NGX_LOG_DEBUG_ALL) {
|
||||
for (i = 0; i < nevents; i++) {
|
||||
ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
|
||||
"poll: %ui: fd:%d ev:%04Xd",
|
||||
i, event_list[i].fd, event_list[i].events);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "poll timer: %M", timer);
|
||||
|
||||
ready = WSAPoll(event_list, (u_int) nevents, (int) timer);
|
||||
|
||||
err = (ready == -1) ? ngx_errno : 0;
|
||||
|
||||
if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) {
|
||||
ngx_time_update();
|
||||
}
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
|
||||
"poll ready %d of %ui", ready, nevents);
|
||||
|
||||
if (err) {
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, err, "WSAPoll() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (ready == 0) {
|
||||
if (timer != NGX_TIMER_INFINITE) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
|
||||
"WSAPoll() returned no events without timeout");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
for (i = 0; i < nevents && ready; i++) {
|
||||
|
||||
revents = event_list[i].revents;
|
||||
|
||||
#if 1
|
||||
ngx_log_debug4(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
|
||||
"poll: %ui: fd:%d ev:%04Xd rev:%04Xd",
|
||||
i, event_list[i].fd, event_list[i].events, revents);
|
||||
#else
|
||||
if (revents) {
|
||||
ngx_log_debug4(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
|
||||
"poll: %ui: fd:%d ev:%04Xd rev:%04Xd",
|
||||
i, event_list[i].fd, event_list[i].events, revents);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (revents & POLLNVAL) {
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
|
||||
"poll() error fd:%d ev:%04Xd rev:%04Xd",
|
||||
event_list[i].fd, event_list[i].events, revents);
|
||||
}
|
||||
|
||||
if (revents & ~(POLLIN|POLLOUT|POLLERR|POLLHUP|POLLNVAL)) {
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
|
||||
"strange poll() events fd:%d ev:%04Xd rev:%04Xd",
|
||||
event_list[i].fd, event_list[i].events, revents);
|
||||
}
|
||||
|
||||
if (event_list[i].fd == (ngx_socket_t) -1) {
|
||||
/*
|
||||
* the disabled event, a workaround for our possible bug,
|
||||
* see the comment below
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
|
||||
c = event_index[i];
|
||||
|
||||
if (c->fd == (ngx_socket_t) -1) {
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "unexpected event");
|
||||
|
||||
/*
|
||||
* it is certainly our fault and it should be investigated,
|
||||
* in the meantime we disable this event to avoid a CPU spinning
|
||||
*/
|
||||
|
||||
if (i == nevents - 1) {
|
||||
nevents--;
|
||||
} else {
|
||||
event_list[i].fd = (ngx_socket_t) -1;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (revents & (POLLERR|POLLHUP|POLLNVAL)) {
|
||||
|
||||
/*
|
||||
* if the error events were returned, add POLLIN and POLLOUT
|
||||
* to handle the events at least in one active handler
|
||||
*/
|
||||
|
||||
revents |= POLLIN|POLLOUT;
|
||||
}
|
||||
|
||||
found = 0;
|
||||
|
||||
if ((revents & POLLIN) && c->read->active) {
|
||||
found = 1;
|
||||
|
||||
ev = c->read;
|
||||
ev->ready = 1;
|
||||
ev->available = -1;
|
||||
|
||||
queue = ev->accept ? &ngx_posted_accept_events
|
||||
: &ngx_posted_events;
|
||||
|
||||
ngx_post_event(ev, queue);
|
||||
}
|
||||
|
||||
if ((revents & POLLOUT) && c->write->active) {
|
||||
found = 1;
|
||||
|
||||
ev = c->write;
|
||||
ev->ready = 1;
|
||||
|
||||
ngx_post_event(ev, &ngx_posted_events);
|
||||
}
|
||||
|
||||
if (found) {
|
||||
ready--;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (ready != 0) {
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "poll ready != events");
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
ngx_poll_init_conf(ngx_cycle_t *cycle, void *conf)
|
||||
{
|
||||
ngx_event_conf_t *ecf;
|
||||
|
||||
ecf = ngx_event_get_conf(cycle->conf_ctx, ngx_event_core_module);
|
||||
|
||||
if (ecf->use != ngx_poll_module.ctx_index) {
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
#if (NGX_LOAD_WSAPOLL)
|
||||
|
||||
if (!ngx_have_wsapoll) {
|
||||
ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
|
||||
"poll is not available on this platform");
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
408
nginx/src/event/modules/ngx_win32_select_module.c
Normal file
408
nginx/src/event/modules/ngx_win32_select_module.c
Normal file
|
|
@ -0,0 +1,408 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_event.h>
|
||||
|
||||
|
||||
static ngx_int_t ngx_select_init(ngx_cycle_t *cycle, ngx_msec_t timer);
|
||||
static void ngx_select_done(ngx_cycle_t *cycle);
|
||||
static ngx_int_t ngx_select_add_event(ngx_event_t *ev, ngx_int_t event,
|
||||
ngx_uint_t flags);
|
||||
static ngx_int_t ngx_select_del_event(ngx_event_t *ev, ngx_int_t event,
|
||||
ngx_uint_t flags);
|
||||
static ngx_int_t ngx_select_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
|
||||
ngx_uint_t flags);
|
||||
static void ngx_select_repair_fd_sets(ngx_cycle_t *cycle);
|
||||
static char *ngx_select_init_conf(ngx_cycle_t *cycle, void *conf);
|
||||
|
||||
|
||||
static fd_set master_read_fd_set;
|
||||
static fd_set master_write_fd_set;
|
||||
static fd_set work_read_fd_set;
|
||||
static fd_set work_write_fd_set;
|
||||
static fd_set work_except_fd_set;
|
||||
|
||||
static ngx_uint_t max_read;
|
||||
static ngx_uint_t max_write;
|
||||
static ngx_uint_t nevents;
|
||||
|
||||
static ngx_event_t **event_index;
|
||||
|
||||
|
||||
static ngx_str_t select_name = ngx_string("select");
|
||||
|
||||
static ngx_event_module_t ngx_select_module_ctx = {
|
||||
&select_name,
|
||||
NULL, /* create configuration */
|
||||
ngx_select_init_conf, /* init configuration */
|
||||
|
||||
{
|
||||
ngx_select_add_event, /* add an event */
|
||||
ngx_select_del_event, /* delete an event */
|
||||
ngx_select_add_event, /* enable an event */
|
||||
ngx_select_del_event, /* disable an event */
|
||||
NULL, /* add an connection */
|
||||
NULL, /* delete an connection */
|
||||
NULL, /* trigger a notify */
|
||||
ngx_select_process_events, /* process the events */
|
||||
ngx_select_init, /* init the events */
|
||||
ngx_select_done /* done the events */
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
ngx_module_t ngx_select_module = {
|
||||
NGX_MODULE_V1,
|
||||
&ngx_select_module_ctx, /* module context */
|
||||
NULL, /* module directives */
|
||||
NGX_EVENT_MODULE, /* module type */
|
||||
NULL, /* init master */
|
||||
NULL, /* init module */
|
||||
NULL, /* init process */
|
||||
NULL, /* init thread */
|
||||
NULL, /* exit thread */
|
||||
NULL, /* exit process */
|
||||
NULL, /* exit master */
|
||||
NGX_MODULE_V1_PADDING
|
||||
};
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_select_init(ngx_cycle_t *cycle, ngx_msec_t timer)
|
||||
{
|
||||
ngx_event_t **index;
|
||||
|
||||
if (event_index == NULL) {
|
||||
FD_ZERO(&master_read_fd_set);
|
||||
FD_ZERO(&master_write_fd_set);
|
||||
nevents = 0;
|
||||
}
|
||||
|
||||
if (ngx_process >= NGX_PROCESS_WORKER
|
||||
|| cycle->old_cycle == NULL
|
||||
|| cycle->old_cycle->connection_n < cycle->connection_n)
|
||||
{
|
||||
index = ngx_alloc(sizeof(ngx_event_t *) * 2 * cycle->connection_n,
|
||||
cycle->log);
|
||||
if (index == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (event_index) {
|
||||
ngx_memcpy(index, event_index, sizeof(ngx_event_t *) * nevents);
|
||||
ngx_free(event_index);
|
||||
}
|
||||
|
||||
event_index = index;
|
||||
}
|
||||
|
||||
ngx_io = ngx_os_io;
|
||||
|
||||
ngx_event_actions = ngx_select_module_ctx.actions;
|
||||
|
||||
ngx_event_flags = NGX_USE_LEVEL_EVENT;
|
||||
|
||||
max_read = 0;
|
||||
max_write = 0;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_select_done(ngx_cycle_t *cycle)
|
||||
{
|
||||
ngx_free(event_index);
|
||||
|
||||
event_index = NULL;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_select_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
|
||||
{
|
||||
ngx_connection_t *c;
|
||||
|
||||
c = ev->data;
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
|
||||
"select add event fd:%d ev:%i", c->fd, event);
|
||||
|
||||
if (ev->index != NGX_INVALID_INDEX) {
|
||||
ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
|
||||
"select event fd:%d ev:%i is already set", c->fd, event);
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
if ((event == NGX_READ_EVENT && ev->write)
|
||||
|| (event == NGX_WRITE_EVENT && !ev->write))
|
||||
{
|
||||
ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
|
||||
"invalid select %s event fd:%d ev:%i",
|
||||
ev->write ? "write" : "read", c->fd, event);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if ((event == NGX_READ_EVENT && max_read >= FD_SETSIZE)
|
||||
|| (event == NGX_WRITE_EVENT && max_write >= FD_SETSIZE))
|
||||
{
|
||||
ngx_log_error(NGX_LOG_ERR, ev->log, 0,
|
||||
"maximum number of descriptors "
|
||||
"supported by select() is %d", FD_SETSIZE);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (event == NGX_READ_EVENT) {
|
||||
FD_SET(c->fd, &master_read_fd_set);
|
||||
max_read++;
|
||||
|
||||
} else if (event == NGX_WRITE_EVENT) {
|
||||
FD_SET(c->fd, &master_write_fd_set);
|
||||
max_write++;
|
||||
}
|
||||
|
||||
ev->active = 1;
|
||||
|
||||
event_index[nevents] = ev;
|
||||
ev->index = nevents;
|
||||
nevents++;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_select_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
|
||||
{
|
||||
ngx_event_t *e;
|
||||
ngx_connection_t *c;
|
||||
|
||||
c = ev->data;
|
||||
|
||||
ev->active = 0;
|
||||
|
||||
if (ev->index == NGX_INVALID_INDEX) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
|
||||
"select del event fd:%d ev:%i", c->fd, event);
|
||||
|
||||
if (event == NGX_READ_EVENT) {
|
||||
FD_CLR(c->fd, &master_read_fd_set);
|
||||
max_read--;
|
||||
|
||||
} else if (event == NGX_WRITE_EVENT) {
|
||||
FD_CLR(c->fd, &master_write_fd_set);
|
||||
max_write--;
|
||||
}
|
||||
|
||||
if (ev->index < --nevents) {
|
||||
e = event_index[nevents];
|
||||
event_index[ev->index] = e;
|
||||
e->index = ev->index;
|
||||
}
|
||||
|
||||
ev->index = NGX_INVALID_INDEX;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_select_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
|
||||
ngx_uint_t flags)
|
||||
{
|
||||
int ready, nready;
|
||||
ngx_err_t err;
|
||||
ngx_uint_t i, found;
|
||||
ngx_event_t *ev;
|
||||
ngx_queue_t *queue;
|
||||
struct timeval tv, *tp;
|
||||
ngx_connection_t *c;
|
||||
|
||||
#if (NGX_DEBUG)
|
||||
if (cycle->log->log_level & NGX_LOG_DEBUG_ALL) {
|
||||
for (i = 0; i < nevents; i++) {
|
||||
ev = event_index[i];
|
||||
c = ev->data;
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
|
||||
"select event: fd:%d wr:%d", c->fd, ev->write);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (timer == NGX_TIMER_INFINITE) {
|
||||
tp = NULL;
|
||||
|
||||
} else {
|
||||
tv.tv_sec = (long) (timer / 1000);
|
||||
tv.tv_usec = (long) ((timer % 1000) * 1000);
|
||||
tp = &tv;
|
||||
}
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
|
||||
"select timer: %M", timer);
|
||||
|
||||
work_read_fd_set = master_read_fd_set;
|
||||
work_write_fd_set = master_write_fd_set;
|
||||
work_except_fd_set = master_write_fd_set;
|
||||
|
||||
if (max_read || max_write) {
|
||||
ready = select(0, &work_read_fd_set, &work_write_fd_set,
|
||||
&work_except_fd_set, tp);
|
||||
|
||||
} else {
|
||||
|
||||
/*
|
||||
* Winsock select() requires that at least one descriptor set must be
|
||||
* be non-null, and any non-null descriptor set must contain at least
|
||||
* one handle to a socket. Otherwise select() returns WSAEINVAL.
|
||||
*/
|
||||
|
||||
ngx_msleep(timer);
|
||||
|
||||
ready = 0;
|
||||
}
|
||||
|
||||
err = (ready == -1) ? ngx_socket_errno : 0;
|
||||
|
||||
if (flags & NGX_UPDATE_TIME) {
|
||||
ngx_time_update();
|
||||
}
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
|
||||
"select ready %d", ready);
|
||||
|
||||
if (err) {
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, err, "select() failed");
|
||||
|
||||
if (err == WSAENOTSOCK) {
|
||||
ngx_select_repair_fd_sets(cycle);
|
||||
}
|
||||
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (ready == 0) {
|
||||
if (timer != NGX_TIMER_INFINITE) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
|
||||
"select() returned no events without timeout");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
nready = 0;
|
||||
|
||||
for (i = 0; i < nevents; i++) {
|
||||
ev = event_index[i];
|
||||
c = ev->data;
|
||||
found = 0;
|
||||
|
||||
if (ev->write) {
|
||||
if (FD_ISSET(c->fd, &work_write_fd_set)) {
|
||||
found++;
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
|
||||
"select write %d", c->fd);
|
||||
}
|
||||
|
||||
if (FD_ISSET(c->fd, &work_except_fd_set)) {
|
||||
found++;
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
|
||||
"select except %d", c->fd);
|
||||
}
|
||||
|
||||
} else {
|
||||
if (FD_ISSET(c->fd, &work_read_fd_set)) {
|
||||
found++;
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
|
||||
"select read %d", c->fd);
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
ev->ready = 1;
|
||||
ev->available = -1;
|
||||
|
||||
queue = ev->accept ? &ngx_posted_accept_events
|
||||
: &ngx_posted_events;
|
||||
|
||||
ngx_post_event(ev, queue);
|
||||
|
||||
nready += found;
|
||||
}
|
||||
}
|
||||
|
||||
if (ready != nready) {
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
|
||||
"select ready != events: %d:%d", ready, nready);
|
||||
|
||||
ngx_select_repair_fd_sets(cycle);
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_select_repair_fd_sets(ngx_cycle_t *cycle)
|
||||
{
|
||||
int n;
|
||||
u_int i;
|
||||
socklen_t len;
|
||||
ngx_err_t err;
|
||||
ngx_socket_t s;
|
||||
|
||||
for (i = 0; i < master_read_fd_set.fd_count; i++) {
|
||||
|
||||
s = master_read_fd_set.fd_array[i];
|
||||
len = sizeof(int);
|
||||
|
||||
if (getsockopt(s, SOL_SOCKET, SO_TYPE, (char *) &n, &len) == -1) {
|
||||
err = ngx_socket_errno;
|
||||
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, err,
|
||||
"invalid descriptor #%d in read fd_set", s);
|
||||
|
||||
FD_CLR(s, &master_read_fd_set);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < master_write_fd_set.fd_count; i++) {
|
||||
|
||||
s = master_write_fd_set.fd_array[i];
|
||||
len = sizeof(int);
|
||||
|
||||
if (getsockopt(s, SOL_SOCKET, SO_TYPE, (char *) &n, &len) == -1) {
|
||||
err = ngx_socket_errno;
|
||||
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, err,
|
||||
"invalid descriptor #%d in write fd_set", s);
|
||||
|
||||
FD_CLR(s, &master_write_fd_set);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
ngx_select_init_conf(ngx_cycle_t *cycle, void *conf)
|
||||
{
|
||||
ngx_event_conf_t *ecf;
|
||||
|
||||
ecf = ngx_event_get_conf(cycle->conf_ctx, ngx_event_core_module);
|
||||
|
||||
if (ecf->use != ngx_select_module.ctx_index) {
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
1373
nginx/src/event/ngx_event.c
Normal file
1373
nginx/src/event/ngx_event.c
Normal file
File diff suppressed because it is too large
Load diff
533
nginx/src/event/ngx_event.h
Normal file
533
nginx/src/event/ngx_event.h
Normal file
|
|
@ -0,0 +1,533 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_EVENT_H_INCLUDED_
|
||||
#define _NGX_EVENT_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
#define NGX_INVALID_INDEX 0xd0d0d0d0
|
||||
|
||||
|
||||
#if (NGX_HAVE_IOCP)
|
||||
|
||||
typedef struct {
|
||||
WSAOVERLAPPED ovlp;
|
||||
ngx_event_t *event;
|
||||
int error;
|
||||
} ngx_event_ovlp_t;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
struct ngx_event_s {
|
||||
void *data;
|
||||
|
||||
unsigned write:1;
|
||||
|
||||
unsigned accept:1;
|
||||
|
||||
/* used to detect the stale events in kqueue and epoll */
|
||||
unsigned instance:1;
|
||||
|
||||
/*
|
||||
* the event was passed or would be passed to a kernel;
|
||||
* in aio mode - operation was posted.
|
||||
*/
|
||||
unsigned active:1;
|
||||
|
||||
unsigned disabled:1;
|
||||
|
||||
/* the ready event; in aio mode 0 means that no operation can be posted */
|
||||
unsigned ready:1;
|
||||
|
||||
unsigned oneshot:1;
|
||||
|
||||
/* aio operation is complete */
|
||||
unsigned complete:1;
|
||||
|
||||
unsigned eof:1;
|
||||
unsigned error:1;
|
||||
|
||||
unsigned timedout:1;
|
||||
unsigned timer_set:1;
|
||||
|
||||
unsigned delayed:1;
|
||||
|
||||
unsigned deferred_accept:1;
|
||||
|
||||
/* the pending eof reported by kqueue, epoll or in aio chain operation */
|
||||
unsigned pending_eof:1;
|
||||
|
||||
unsigned posted:1;
|
||||
|
||||
unsigned closed:1;
|
||||
|
||||
/* to test on worker exit */
|
||||
unsigned channel:1;
|
||||
unsigned resolver:1;
|
||||
|
||||
unsigned cancelable:1;
|
||||
|
||||
#if (NGX_HAVE_KQUEUE)
|
||||
unsigned kq_vnode:1;
|
||||
|
||||
/* the pending errno reported by kqueue */
|
||||
int kq_errno;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* kqueue only:
|
||||
* accept: number of sockets that wait to be accepted
|
||||
* read: bytes to read when event is ready
|
||||
* or lowat when event is set with NGX_LOWAT_EVENT flag
|
||||
* write: available space in buffer when event is ready
|
||||
* or lowat when event is set with NGX_LOWAT_EVENT flag
|
||||
*
|
||||
* iocp: TODO
|
||||
*
|
||||
* otherwise:
|
||||
* accept: 1 if accept many, 0 otherwise
|
||||
* read: bytes to read when event is ready, -1 if not known
|
||||
*/
|
||||
|
||||
int available;
|
||||
|
||||
ngx_event_handler_pt handler;
|
||||
|
||||
|
||||
#if (NGX_HAVE_IOCP)
|
||||
ngx_event_ovlp_t ovlp;
|
||||
#endif
|
||||
|
||||
ngx_uint_t index;
|
||||
|
||||
ngx_log_t *log;
|
||||
|
||||
ngx_rbtree_node_t timer;
|
||||
|
||||
/* the posted queue */
|
||||
ngx_queue_t queue;
|
||||
|
||||
#if 0
|
||||
|
||||
/* the threads support */
|
||||
|
||||
/*
|
||||
* the event thread context, we store it here
|
||||
* if $(CC) does not understand __thread declaration
|
||||
* and pthread_getspecific() is too costly
|
||||
*/
|
||||
|
||||
void *thr_ctx;
|
||||
|
||||
#if (NGX_EVENT_T_PADDING)
|
||||
|
||||
/* event should not cross cache line in SMP */
|
||||
|
||||
uint32_t padding[NGX_EVENT_T_PADDING];
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
#if (NGX_HAVE_FILE_AIO)
|
||||
|
||||
struct ngx_event_aio_s {
|
||||
void *data;
|
||||
ngx_event_handler_pt handler;
|
||||
ngx_file_t *file;
|
||||
|
||||
ngx_fd_t fd;
|
||||
|
||||
#if (NGX_HAVE_EVENTFD)
|
||||
int64_t res;
|
||||
#endif
|
||||
|
||||
#if !(NGX_HAVE_EVENTFD) || (NGX_TEST_BUILD_EPOLL)
|
||||
ngx_err_t err;
|
||||
size_t nbytes;
|
||||
#endif
|
||||
|
||||
ngx_aiocb_t aiocb;
|
||||
ngx_event_t event;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_int_t (*add)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);
|
||||
ngx_int_t (*del)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);
|
||||
|
||||
ngx_int_t (*enable)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);
|
||||
ngx_int_t (*disable)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);
|
||||
|
||||
ngx_int_t (*add_conn)(ngx_connection_t *c);
|
||||
ngx_int_t (*del_conn)(ngx_connection_t *c, ngx_uint_t flags);
|
||||
|
||||
ngx_int_t (*notify)(ngx_event_handler_pt handler);
|
||||
|
||||
ngx_int_t (*process_events)(ngx_cycle_t *cycle, ngx_msec_t timer,
|
||||
ngx_uint_t flags);
|
||||
|
||||
ngx_int_t (*init)(ngx_cycle_t *cycle, ngx_msec_t timer);
|
||||
void (*done)(ngx_cycle_t *cycle);
|
||||
} ngx_event_actions_t;
|
||||
|
||||
|
||||
extern ngx_event_actions_t ngx_event_actions;
|
||||
#if (NGX_HAVE_EPOLLRDHUP)
|
||||
extern ngx_uint_t ngx_use_epoll_rdhup;
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* The event filter requires to read/write the whole data:
|
||||
* select, poll, /dev/poll, kqueue, epoll.
|
||||
*/
|
||||
#define NGX_USE_LEVEL_EVENT 0x00000001
|
||||
|
||||
/*
|
||||
* The event filter is deleted after a notification without an additional
|
||||
* syscall: kqueue, epoll.
|
||||
*/
|
||||
#define NGX_USE_ONESHOT_EVENT 0x00000002
|
||||
|
||||
/*
|
||||
* The event filter notifies only the changes and an initial level:
|
||||
* kqueue, epoll.
|
||||
*/
|
||||
#define NGX_USE_CLEAR_EVENT 0x00000004
|
||||
|
||||
/*
|
||||
* The event filter has kqueue features: the eof flag, errno,
|
||||
* available data, etc.
|
||||
*/
|
||||
#define NGX_USE_KQUEUE_EVENT 0x00000008
|
||||
|
||||
/*
|
||||
* The event filter supports low water mark: kqueue's NOTE_LOWAT.
|
||||
* kqueue in FreeBSD 4.1-4.2 has no NOTE_LOWAT so we need a separate flag.
|
||||
*/
|
||||
#define NGX_USE_LOWAT_EVENT 0x00000010
|
||||
|
||||
/*
|
||||
* The event filter requires to do i/o operation until EAGAIN: epoll.
|
||||
*/
|
||||
#define NGX_USE_GREEDY_EVENT 0x00000020
|
||||
|
||||
/*
|
||||
* The event filter is epoll.
|
||||
*/
|
||||
#define NGX_USE_EPOLL_EVENT 0x00000040
|
||||
|
||||
/*
|
||||
* Obsolete.
|
||||
*/
|
||||
#define NGX_USE_RTSIG_EVENT 0x00000080
|
||||
|
||||
/*
|
||||
* Obsolete.
|
||||
*/
|
||||
#define NGX_USE_AIO_EVENT 0x00000100
|
||||
|
||||
/*
|
||||
* Need to add socket or handle only once: i/o completion port.
|
||||
*/
|
||||
#define NGX_USE_IOCP_EVENT 0x00000200
|
||||
|
||||
/*
|
||||
* The event filter has no opaque data and requires file descriptors table:
|
||||
* poll, /dev/poll.
|
||||
*/
|
||||
#define NGX_USE_FD_EVENT 0x00000400
|
||||
|
||||
/*
|
||||
* The event module handles periodic or absolute timer event by itself:
|
||||
* kqueue in FreeBSD 4.4, NetBSD 2.0, and MacOSX 10.4, Solaris 10's event ports.
|
||||
*/
|
||||
#define NGX_USE_TIMER_EVENT 0x00000800
|
||||
|
||||
/*
|
||||
* All event filters on file descriptor are deleted after a notification:
|
||||
* Solaris 10's event ports.
|
||||
*/
|
||||
#define NGX_USE_EVENTPORT_EVENT 0x00001000
|
||||
|
||||
/*
|
||||
* The event filter support vnode notifications: kqueue.
|
||||
*/
|
||||
#define NGX_USE_VNODE_EVENT 0x00002000
|
||||
|
||||
|
||||
/*
|
||||
* The event filter is deleted just before the closing file.
|
||||
* Has no meaning for select and poll.
|
||||
* kqueue, epoll, eventport: allows to avoid explicit delete,
|
||||
* because filter automatically is deleted
|
||||
* on file close,
|
||||
*
|
||||
* /dev/poll: we need to flush POLLREMOVE event
|
||||
* before closing file.
|
||||
*/
|
||||
#define NGX_CLOSE_EVENT 1
|
||||
|
||||
/*
|
||||
* disable temporarily event filter, this may avoid locks
|
||||
* in kernel malloc()/free(): kqueue.
|
||||
*/
|
||||
#define NGX_DISABLE_EVENT 2
|
||||
|
||||
/*
|
||||
* event must be passed to kernel right now, do not wait until batch processing.
|
||||
*/
|
||||
#define NGX_FLUSH_EVENT 4
|
||||
|
||||
|
||||
/* these flags have a meaning only for kqueue */
|
||||
#define NGX_LOWAT_EVENT 0
|
||||
#define NGX_VNODE_EVENT 0
|
||||
|
||||
|
||||
#if (NGX_HAVE_EPOLL) && !(NGX_HAVE_EPOLLRDHUP)
|
||||
#define EPOLLRDHUP 0
|
||||
#endif
|
||||
|
||||
|
||||
#if (NGX_HAVE_KQUEUE)
|
||||
|
||||
#define NGX_READ_EVENT EVFILT_READ
|
||||
#define NGX_WRITE_EVENT EVFILT_WRITE
|
||||
|
||||
#undef NGX_VNODE_EVENT
|
||||
#define NGX_VNODE_EVENT EVFILT_VNODE
|
||||
|
||||
/*
|
||||
* NGX_CLOSE_EVENT, NGX_LOWAT_EVENT, and NGX_FLUSH_EVENT are the module flags
|
||||
* and they must not go into a kernel so we need to choose the value
|
||||
* that must not interfere with any existent and future kqueue flags.
|
||||
* kqueue has such values - EV_FLAG1, EV_EOF, and EV_ERROR:
|
||||
* they are reserved and cleared on a kernel entrance.
|
||||
*/
|
||||
#undef NGX_CLOSE_EVENT
|
||||
#define NGX_CLOSE_EVENT EV_EOF
|
||||
|
||||
#undef NGX_LOWAT_EVENT
|
||||
#define NGX_LOWAT_EVENT EV_FLAG1
|
||||
|
||||
#undef NGX_FLUSH_EVENT
|
||||
#define NGX_FLUSH_EVENT EV_ERROR
|
||||
|
||||
#define NGX_LEVEL_EVENT 0
|
||||
#define NGX_ONESHOT_EVENT EV_ONESHOT
|
||||
#define NGX_CLEAR_EVENT EV_CLEAR
|
||||
|
||||
#undef NGX_DISABLE_EVENT
|
||||
#define NGX_DISABLE_EVENT EV_DISABLE
|
||||
|
||||
|
||||
#elif (NGX_HAVE_DEVPOLL && !(NGX_TEST_BUILD_DEVPOLL)) \
|
||||
|| (NGX_HAVE_EVENTPORT && !(NGX_TEST_BUILD_EVENTPORT))
|
||||
|
||||
#define NGX_READ_EVENT POLLIN
|
||||
#define NGX_WRITE_EVENT POLLOUT
|
||||
|
||||
#define NGX_LEVEL_EVENT 0
|
||||
#define NGX_ONESHOT_EVENT 1
|
||||
|
||||
|
||||
#elif (NGX_HAVE_EPOLL) && !(NGX_TEST_BUILD_EPOLL)
|
||||
|
||||
#define NGX_READ_EVENT (EPOLLIN|EPOLLRDHUP)
|
||||
#define NGX_WRITE_EVENT EPOLLOUT
|
||||
|
||||
#define NGX_LEVEL_EVENT 0
|
||||
#define NGX_CLEAR_EVENT EPOLLET
|
||||
#define NGX_ONESHOT_EVENT 0x70000000
|
||||
#if 0
|
||||
#define NGX_ONESHOT_EVENT EPOLLONESHOT
|
||||
#endif
|
||||
|
||||
#if (NGX_HAVE_EPOLLEXCLUSIVE)
|
||||
#define NGX_EXCLUSIVE_EVENT EPOLLEXCLUSIVE
|
||||
#endif
|
||||
|
||||
#elif (NGX_HAVE_POLL)
|
||||
|
||||
#define NGX_READ_EVENT POLLIN
|
||||
#define NGX_WRITE_EVENT POLLOUT
|
||||
|
||||
#define NGX_LEVEL_EVENT 0
|
||||
#define NGX_ONESHOT_EVENT 1
|
||||
|
||||
|
||||
#else /* select */
|
||||
|
||||
#define NGX_READ_EVENT 0
|
||||
#define NGX_WRITE_EVENT 1
|
||||
|
||||
#define NGX_LEVEL_EVENT 0
|
||||
#define NGX_ONESHOT_EVENT 1
|
||||
|
||||
#endif /* NGX_HAVE_KQUEUE */
|
||||
|
||||
|
||||
#if (NGX_HAVE_IOCP)
|
||||
#define NGX_IOCP_ACCEPT 0
|
||||
#define NGX_IOCP_IO 1
|
||||
#define NGX_IOCP_CONNECT 2
|
||||
#endif
|
||||
|
||||
|
||||
#if (NGX_TEST_BUILD_EPOLL)
|
||||
#define NGX_EXCLUSIVE_EVENT 0
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef NGX_CLEAR_EVENT
|
||||
#define NGX_CLEAR_EVENT 0 /* dummy declaration */
|
||||
#endif
|
||||
|
||||
|
||||
#define ngx_process_events ngx_event_actions.process_events
|
||||
#define ngx_done_events ngx_event_actions.done
|
||||
|
||||
#define ngx_add_event ngx_event_actions.add
|
||||
#define ngx_del_event ngx_event_actions.del
|
||||
#define ngx_add_conn ngx_event_actions.add_conn
|
||||
#define ngx_del_conn ngx_event_actions.del_conn
|
||||
|
||||
#define ngx_notify ngx_event_actions.notify
|
||||
|
||||
#define ngx_add_timer ngx_event_add_timer
|
||||
#define ngx_del_timer ngx_event_del_timer
|
||||
|
||||
|
||||
extern ngx_os_io_t ngx_io;
|
||||
|
||||
#define ngx_recv ngx_io.recv
|
||||
#define ngx_recv_chain ngx_io.recv_chain
|
||||
#define ngx_udp_recv ngx_io.udp_recv
|
||||
#define ngx_send ngx_io.send
|
||||
#define ngx_send_chain ngx_io.send_chain
|
||||
#define ngx_udp_send ngx_io.udp_send
|
||||
#define ngx_udp_send_chain ngx_io.udp_send_chain
|
||||
|
||||
|
||||
#define NGX_EVENT_MODULE 0x544E5645 /* "EVNT" */
|
||||
#define NGX_EVENT_CONF 0x02000000
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_uint_t connections;
|
||||
ngx_uint_t use;
|
||||
|
||||
ngx_flag_t multi_accept;
|
||||
ngx_flag_t accept_mutex;
|
||||
|
||||
ngx_msec_t accept_mutex_delay;
|
||||
|
||||
u_char *name;
|
||||
|
||||
#if (NGX_DEBUG)
|
||||
ngx_array_t debug_connection;
|
||||
#endif
|
||||
} ngx_event_conf_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_str_t *name;
|
||||
|
||||
void *(*create_conf)(ngx_cycle_t *cycle);
|
||||
char *(*init_conf)(ngx_cycle_t *cycle, void *conf);
|
||||
|
||||
ngx_event_actions_t actions;
|
||||
} ngx_event_module_t;
|
||||
|
||||
|
||||
extern ngx_atomic_t *ngx_connection_counter;
|
||||
|
||||
extern ngx_atomic_t *ngx_accept_mutex_ptr;
|
||||
extern ngx_shmtx_t ngx_accept_mutex;
|
||||
extern ngx_uint_t ngx_use_accept_mutex;
|
||||
extern ngx_uint_t ngx_accept_events;
|
||||
extern ngx_uint_t ngx_accept_mutex_held;
|
||||
extern ngx_msec_t ngx_accept_mutex_delay;
|
||||
extern ngx_int_t ngx_accept_disabled;
|
||||
extern ngx_uint_t ngx_use_exclusive_accept;
|
||||
|
||||
|
||||
#if (NGX_STAT_STUB)
|
||||
|
||||
extern ngx_atomic_t *ngx_stat_accepted;
|
||||
extern ngx_atomic_t *ngx_stat_handled;
|
||||
extern ngx_atomic_t *ngx_stat_requests;
|
||||
extern ngx_atomic_t *ngx_stat_active;
|
||||
extern ngx_atomic_t *ngx_stat_reading;
|
||||
extern ngx_atomic_t *ngx_stat_writing;
|
||||
extern ngx_atomic_t *ngx_stat_waiting;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#define NGX_UPDATE_TIME 1
|
||||
#define NGX_POST_EVENTS 2
|
||||
|
||||
|
||||
extern sig_atomic_t ngx_event_timer_alarm;
|
||||
extern ngx_uint_t ngx_event_flags;
|
||||
extern ngx_module_t ngx_events_module;
|
||||
extern ngx_module_t ngx_event_core_module;
|
||||
|
||||
|
||||
#define ngx_event_get_conf(conf_ctx, module) \
|
||||
(*(ngx_get_conf(conf_ctx, ngx_events_module))) [module.ctx_index]
|
||||
|
||||
|
||||
|
||||
void ngx_event_accept(ngx_event_t *ev);
|
||||
ngx_int_t ngx_trylock_accept_mutex(ngx_cycle_t *cycle);
|
||||
ngx_int_t ngx_enable_accept_events(ngx_cycle_t *cycle);
|
||||
u_char *ngx_accept_log_error(ngx_log_t *log, u_char *buf, size_t len);
|
||||
#if (NGX_DEBUG)
|
||||
void ngx_debug_accepted_connection(ngx_event_conf_t *ecf, ngx_connection_t *c);
|
||||
#endif
|
||||
|
||||
|
||||
void ngx_process_events_and_timers(ngx_cycle_t *cycle);
|
||||
ngx_int_t ngx_handle_read_event(ngx_event_t *rev, ngx_uint_t flags);
|
||||
ngx_int_t ngx_handle_write_event(ngx_event_t *wev, size_t lowat);
|
||||
|
||||
|
||||
#if (NGX_WIN32)
|
||||
void ngx_event_acceptex(ngx_event_t *ev);
|
||||
ngx_int_t ngx_event_post_acceptex(ngx_listening_t *ls, ngx_uint_t n);
|
||||
u_char *ngx_acceptex_log_error(ngx_log_t *log, u_char *buf, size_t len);
|
||||
#endif
|
||||
|
||||
|
||||
ngx_int_t ngx_send_lowat(ngx_connection_t *c, size_t lowat);
|
||||
|
||||
|
||||
/* used in ngx_log_debugX() */
|
||||
#define ngx_event_ident(p) ((ngx_connection_t *) (p))->fd
|
||||
|
||||
|
||||
#include <ngx_event_timer.h>
|
||||
#include <ngx_event_posted.h>
|
||||
#include <ngx_event_udp.h>
|
||||
|
||||
#if (NGX_WIN32)
|
||||
#include <ngx_iocp_module.h>
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* _NGX_EVENT_H_INCLUDED_ */
|
||||
589
nginx/src/event/ngx_event_accept.c
Normal file
589
nginx/src/event/ngx_event_accept.c
Normal file
|
|
@ -0,0 +1,589 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_event.h>
|
||||
|
||||
|
||||
static ngx_int_t ngx_disable_accept_events(ngx_cycle_t *cycle, ngx_uint_t all);
|
||||
#if (NGX_HAVE_EPOLLEXCLUSIVE)
|
||||
static void ngx_reorder_accept_events(ngx_listening_t *ls);
|
||||
#endif
|
||||
static void ngx_close_accepted_connection(ngx_connection_t *c);
|
||||
|
||||
|
||||
void
|
||||
ngx_event_accept(ngx_event_t *ev)
|
||||
{
|
||||
socklen_t socklen;
|
||||
ngx_err_t err;
|
||||
ngx_log_t *log;
|
||||
ngx_uint_t level;
|
||||
ngx_socket_t s;
|
||||
ngx_event_t *rev, *wev;
|
||||
ngx_sockaddr_t sa;
|
||||
ngx_listening_t *ls;
|
||||
ngx_connection_t *c, *lc;
|
||||
ngx_event_conf_t *ecf;
|
||||
#if (NGX_HAVE_ACCEPT4)
|
||||
static ngx_uint_t use_accept4 = 1;
|
||||
#endif
|
||||
|
||||
if (ev->timedout) {
|
||||
if (ngx_enable_accept_events((ngx_cycle_t *) ngx_cycle) != NGX_OK) {
|
||||
return;
|
||||
}
|
||||
|
||||
ev->timedout = 0;
|
||||
}
|
||||
|
||||
ecf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_event_core_module);
|
||||
|
||||
if (!(ngx_event_flags & NGX_USE_KQUEUE_EVENT)) {
|
||||
ev->available = ecf->multi_accept;
|
||||
}
|
||||
|
||||
lc = ev->data;
|
||||
ls = lc->listening;
|
||||
ev->ready = 0;
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
|
||||
"accept on %V, ready: %d", &ls->addr_text, ev->available);
|
||||
|
||||
do {
|
||||
socklen = sizeof(ngx_sockaddr_t);
|
||||
|
||||
#if (NGX_HAVE_ACCEPT4)
|
||||
if (use_accept4) {
|
||||
s = accept4(lc->fd, &sa.sockaddr, &socklen, SOCK_NONBLOCK);
|
||||
} else {
|
||||
s = accept(lc->fd, &sa.sockaddr, &socklen);
|
||||
}
|
||||
#else
|
||||
s = accept(lc->fd, &sa.sockaddr, &socklen);
|
||||
#endif
|
||||
|
||||
if (s == (ngx_socket_t) -1) {
|
||||
err = ngx_socket_errno;
|
||||
|
||||
if (err == NGX_EAGAIN) {
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, err,
|
||||
"accept() not ready");
|
||||
return;
|
||||
}
|
||||
|
||||
level = NGX_LOG_ALERT;
|
||||
|
||||
if (err == NGX_ECONNABORTED) {
|
||||
level = NGX_LOG_ERR;
|
||||
|
||||
} else if (err == NGX_EMFILE || err == NGX_ENFILE) {
|
||||
level = NGX_LOG_CRIT;
|
||||
}
|
||||
|
||||
#if (NGX_HAVE_ACCEPT4)
|
||||
ngx_log_error(level, ev->log, err,
|
||||
use_accept4 ? "accept4() failed" : "accept() failed");
|
||||
|
||||
if (use_accept4 && err == NGX_ENOSYS) {
|
||||
use_accept4 = 0;
|
||||
ngx_inherited_nonblocking = 0;
|
||||
continue;
|
||||
}
|
||||
#else
|
||||
ngx_log_error(level, ev->log, err, "accept() failed");
|
||||
#endif
|
||||
|
||||
if (err == NGX_ECONNABORTED) {
|
||||
if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
|
||||
ev->available--;
|
||||
}
|
||||
|
||||
if (ev->available) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (err == NGX_EMFILE || err == NGX_ENFILE) {
|
||||
if (ngx_disable_accept_events((ngx_cycle_t *) ngx_cycle, 1)
|
||||
!= NGX_OK)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (ngx_use_accept_mutex) {
|
||||
if (ngx_accept_mutex_held) {
|
||||
ngx_shmtx_unlock(&ngx_accept_mutex);
|
||||
ngx_accept_mutex_held = 0;
|
||||
}
|
||||
|
||||
ngx_accept_disabled = 1;
|
||||
|
||||
} else {
|
||||
ngx_add_timer(ev, ecf->accept_mutex_delay);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#if (NGX_STAT_STUB)
|
||||
(void) ngx_atomic_fetch_add(ngx_stat_accepted, 1);
|
||||
#endif
|
||||
|
||||
ngx_accept_disabled = ngx_cycle->connection_n / 8
|
||||
- ngx_cycle->free_connection_n;
|
||||
|
||||
c = ngx_get_connection(s, ev->log);
|
||||
|
||||
if (c == NULL) {
|
||||
if (ngx_close_socket(s) == -1) {
|
||||
ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
|
||||
ngx_close_socket_n " failed");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
c->type = SOCK_STREAM;
|
||||
|
||||
#if (NGX_STAT_STUB)
|
||||
(void) ngx_atomic_fetch_add(ngx_stat_active, 1);
|
||||
#endif
|
||||
|
||||
c->pool = ngx_create_pool(ls->pool_size, ev->log);
|
||||
if (c->pool == NULL) {
|
||||
ngx_close_accepted_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
if (socklen > (socklen_t) sizeof(ngx_sockaddr_t)) {
|
||||
socklen = sizeof(ngx_sockaddr_t);
|
||||
}
|
||||
|
||||
c->sockaddr = ngx_palloc(c->pool, socklen);
|
||||
if (c->sockaddr == NULL) {
|
||||
ngx_close_accepted_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_memcpy(c->sockaddr, &sa, socklen);
|
||||
|
||||
log = ngx_palloc(c->pool, sizeof(ngx_log_t));
|
||||
if (log == NULL) {
|
||||
ngx_close_accepted_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
/* set a blocking mode for iocp and non-blocking mode for others */
|
||||
|
||||
if (ngx_inherited_nonblocking) {
|
||||
if (ngx_event_flags & NGX_USE_IOCP_EVENT) {
|
||||
if (ngx_blocking(s) == -1) {
|
||||
ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
|
||||
ngx_blocking_n " failed");
|
||||
ngx_close_accepted_connection(c);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
if (!(ngx_event_flags & NGX_USE_IOCP_EVENT)) {
|
||||
if (ngx_nonblocking(s) == -1) {
|
||||
ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
|
||||
ngx_nonblocking_n " failed");
|
||||
ngx_close_accepted_connection(c);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if (NGX_HAVE_KEEPALIVE_TUNABLE && NGX_DARWIN)
|
||||
|
||||
/* Darwin doesn't inherit TCP_KEEPALIVE from a listening socket */
|
||||
|
||||
if (ls->keepidle) {
|
||||
if (setsockopt(s, IPPROTO_TCP, TCP_KEEPALIVE,
|
||||
(const void *) &ls->keepidle, sizeof(int))
|
||||
== -1)
|
||||
{
|
||||
ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
|
||||
"setsockopt(TCP_KEEPALIVE, %d) failed, ignored",
|
||||
ls->keepidle);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
*log = ls->log;
|
||||
|
||||
c->recv = ngx_recv;
|
||||
c->send = ngx_send;
|
||||
c->recv_chain = ngx_recv_chain;
|
||||
c->send_chain = ngx_send_chain;
|
||||
|
||||
c->log = log;
|
||||
c->pool->log = log;
|
||||
|
||||
c->socklen = socklen;
|
||||
c->listening = ls;
|
||||
c->local_sockaddr = ls->sockaddr;
|
||||
c->local_socklen = ls->socklen;
|
||||
|
||||
#if (NGX_HAVE_UNIX_DOMAIN)
|
||||
if (c->sockaddr->sa_family == AF_UNIX) {
|
||||
c->tcp_nopush = NGX_TCP_NOPUSH_DISABLED;
|
||||
c->tcp_nodelay = NGX_TCP_NODELAY_DISABLED;
|
||||
#if (NGX_SOLARIS)
|
||||
/* Solaris's sendfilev() supports AF_NCA, AF_INET, and AF_INET6 */
|
||||
c->sendfile = 0;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
rev = c->read;
|
||||
wev = c->write;
|
||||
|
||||
wev->ready = 1;
|
||||
|
||||
if (ngx_event_flags & NGX_USE_IOCP_EVENT) {
|
||||
rev->ready = 1;
|
||||
}
|
||||
|
||||
if (ev->deferred_accept) {
|
||||
rev->ready = 1;
|
||||
#if (NGX_HAVE_KQUEUE || NGX_HAVE_EPOLLRDHUP)
|
||||
rev->available = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
rev->log = log;
|
||||
wev->log = log;
|
||||
|
||||
/*
|
||||
* TODO: MT: - ngx_atomic_fetch_add()
|
||||
* or protection by critical section or light mutex
|
||||
*
|
||||
* TODO: MP: - allocated in a shared memory
|
||||
* - ngx_atomic_fetch_add()
|
||||
* or protection by critical section or light mutex
|
||||
*/
|
||||
|
||||
c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1);
|
||||
|
||||
c->start_time = ngx_current_msec;
|
||||
|
||||
#if (NGX_STAT_STUB)
|
||||
(void) ngx_atomic_fetch_add(ngx_stat_handled, 1);
|
||||
#endif
|
||||
|
||||
if (ls->addr_ntop) {
|
||||
c->addr_text.data = ngx_pnalloc(c->pool, ls->addr_text_max_len);
|
||||
if (c->addr_text.data == NULL) {
|
||||
ngx_close_accepted_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
c->addr_text.len = ngx_sock_ntop(c->sockaddr, c->socklen,
|
||||
c->addr_text.data,
|
||||
ls->addr_text_max_len, 0);
|
||||
if (c->addr_text.len == 0) {
|
||||
ngx_close_accepted_connection(c);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#if (NGX_DEBUG)
|
||||
{
|
||||
ngx_str_t addr;
|
||||
u_char text[NGX_SOCKADDR_STRLEN];
|
||||
|
||||
ngx_debug_accepted_connection(ecf, c);
|
||||
|
||||
if (log->log_level & NGX_LOG_DEBUG_EVENT) {
|
||||
addr.data = text;
|
||||
addr.len = ngx_sock_ntop(c->sockaddr, c->socklen, text,
|
||||
NGX_SOCKADDR_STRLEN, 1);
|
||||
|
||||
ngx_log_debug3(NGX_LOG_DEBUG_EVENT, log, 0,
|
||||
"*%uA accept: %V fd:%d", c->number, &addr, s);
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ngx_add_conn && (ngx_event_flags & NGX_USE_EPOLL_EVENT) == 0) {
|
||||
if (ngx_add_conn(c) == NGX_ERROR) {
|
||||
ngx_close_accepted_connection(c);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
log->data = NULL;
|
||||
log->handler = NULL;
|
||||
|
||||
ls->handler(c);
|
||||
|
||||
if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
|
||||
ev->available--;
|
||||
}
|
||||
|
||||
} while (ev->available);
|
||||
|
||||
#if (NGX_HAVE_EPOLLEXCLUSIVE)
|
||||
ngx_reorder_accept_events(ls);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_trylock_accept_mutex(ngx_cycle_t *cycle)
|
||||
{
|
||||
if (ngx_shmtx_trylock(&ngx_accept_mutex)) {
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
|
||||
"accept mutex locked");
|
||||
|
||||
if (ngx_accept_mutex_held && ngx_accept_events == 0) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
if (ngx_enable_accept_events(cycle) == NGX_ERROR) {
|
||||
ngx_shmtx_unlock(&ngx_accept_mutex);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_accept_events = 0;
|
||||
ngx_accept_mutex_held = 1;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
|
||||
"accept mutex lock failed: %ui", ngx_accept_mutex_held);
|
||||
|
||||
if (ngx_accept_mutex_held) {
|
||||
if (ngx_disable_accept_events(cycle, 0) == NGX_ERROR) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_accept_mutex_held = 0;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_enable_accept_events(ngx_cycle_t *cycle)
|
||||
{
|
||||
ngx_uint_t i;
|
||||
ngx_listening_t *ls;
|
||||
ngx_connection_t *c;
|
||||
|
||||
ls = cycle->listening.elts;
|
||||
for (i = 0; i < cycle->listening.nelts; i++) {
|
||||
|
||||
c = ls[i].connection;
|
||||
|
||||
if (c == NULL || c->read->active) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ngx_add_event(c->read, NGX_READ_EVENT, 0) == NGX_ERROR) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_disable_accept_events(ngx_cycle_t *cycle, ngx_uint_t all)
|
||||
{
|
||||
ngx_uint_t i;
|
||||
ngx_listening_t *ls;
|
||||
ngx_connection_t *c;
|
||||
|
||||
ls = cycle->listening.elts;
|
||||
for (i = 0; i < cycle->listening.nelts; i++) {
|
||||
|
||||
c = ls[i].connection;
|
||||
|
||||
if (c == NULL || !c->read->active) {
|
||||
continue;
|
||||
}
|
||||
|
||||
#if (NGX_HAVE_REUSEPORT)
|
||||
|
||||
/*
|
||||
* do not disable accept on worker's own sockets
|
||||
* when disabling accept events due to accept mutex
|
||||
*/
|
||||
|
||||
if (ls[i].reuseport && !all) {
|
||||
continue;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if (ngx_del_event(c->read, NGX_READ_EVENT, NGX_DISABLE_EVENT)
|
||||
== NGX_ERROR)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
#if (NGX_HAVE_EPOLLEXCLUSIVE)
|
||||
|
||||
static void
|
||||
ngx_reorder_accept_events(ngx_listening_t *ls)
|
||||
{
|
||||
ngx_connection_t *c;
|
||||
|
||||
/*
|
||||
* Linux with EPOLLEXCLUSIVE usually notifies only the process which
|
||||
* was first to add the listening socket to the epoll instance. As
|
||||
* a result most of the connections are handled by the first worker
|
||||
* process. To fix this, we re-add the socket periodically, so other
|
||||
* workers will get a chance to accept connections.
|
||||
*/
|
||||
|
||||
if (!ngx_use_exclusive_accept) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if (NGX_HAVE_REUSEPORT)
|
||||
|
||||
if (ls->reuseport) {
|
||||
return;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
c = ls->connection;
|
||||
|
||||
if (c->requests++ % 16 != 0
|
||||
&& ngx_accept_disabled <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (ngx_del_event(c->read, NGX_READ_EVENT, NGX_DISABLE_EVENT)
|
||||
== NGX_ERROR)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (ngx_add_event(c->read, NGX_READ_EVENT, NGX_EXCLUSIVE_EVENT)
|
||||
== NGX_ERROR)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
static void
|
||||
ngx_close_accepted_connection(ngx_connection_t *c)
|
||||
{
|
||||
ngx_socket_t fd;
|
||||
|
||||
ngx_free_connection(c);
|
||||
|
||||
fd = c->fd;
|
||||
c->fd = (ngx_socket_t) -1;
|
||||
|
||||
if (ngx_close_socket(fd) == -1) {
|
||||
ngx_log_error(NGX_LOG_ALERT, c->log, ngx_socket_errno,
|
||||
ngx_close_socket_n " failed");
|
||||
}
|
||||
|
||||
if (c->pool) {
|
||||
ngx_destroy_pool(c->pool);
|
||||
}
|
||||
|
||||
#if (NGX_STAT_STUB)
|
||||
(void) ngx_atomic_fetch_add(ngx_stat_active, -1);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
u_char *
|
||||
ngx_accept_log_error(ngx_log_t *log, u_char *buf, size_t len)
|
||||
{
|
||||
return ngx_snprintf(buf, len, " while accepting new connection on %V",
|
||||
log->data);
|
||||
}
|
||||
|
||||
|
||||
#if (NGX_DEBUG)
|
||||
|
||||
void
|
||||
ngx_debug_accepted_connection(ngx_event_conf_t *ecf, ngx_connection_t *c)
|
||||
{
|
||||
struct sockaddr_in *sin;
|
||||
ngx_cidr_t *cidr;
|
||||
ngx_uint_t i;
|
||||
#if (NGX_HAVE_INET6)
|
||||
struct sockaddr_in6 *sin6;
|
||||
ngx_uint_t n;
|
||||
#endif
|
||||
|
||||
cidr = ecf->debug_connection.elts;
|
||||
for (i = 0; i < ecf->debug_connection.nelts; i++) {
|
||||
if (cidr[i].family != (ngx_uint_t) c->sockaddr->sa_family) {
|
||||
goto next;
|
||||
}
|
||||
|
||||
switch (cidr[i].family) {
|
||||
|
||||
#if (NGX_HAVE_INET6)
|
||||
case AF_INET6:
|
||||
sin6 = (struct sockaddr_in6 *) c->sockaddr;
|
||||
for (n = 0; n < 16; n++) {
|
||||
if ((sin6->sin6_addr.s6_addr[n]
|
||||
& cidr[i].u.in6.mask.s6_addr[n])
|
||||
!= cidr[i].u.in6.addr.s6_addr[n])
|
||||
{
|
||||
goto next;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if (NGX_HAVE_UNIX_DOMAIN)
|
||||
case AF_UNIX:
|
||||
break;
|
||||
#endif
|
||||
|
||||
default: /* AF_INET */
|
||||
sin = (struct sockaddr_in *) c->sockaddr;
|
||||
if ((sin->sin_addr.s_addr & cidr[i].u.in.mask)
|
||||
!= cidr[i].u.in.addr)
|
||||
{
|
||||
goto next;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
c->log->log_level = NGX_LOG_DEBUG_CONNECTION|NGX_LOG_DEBUG_ALL;
|
||||
break;
|
||||
|
||||
next:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
229
nginx/src/event/ngx_event_acceptex.c
Normal file
229
nginx/src/event/ngx_event_acceptex.c
Normal file
|
|
@ -0,0 +1,229 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_event.h>
|
||||
|
||||
|
||||
static void ngx_close_posted_connection(ngx_connection_t *c);
|
||||
|
||||
|
||||
void
|
||||
ngx_event_acceptex(ngx_event_t *rev)
|
||||
{
|
||||
ngx_listening_t *ls;
|
||||
ngx_connection_t *c;
|
||||
|
||||
c = rev->data;
|
||||
ls = c->listening;
|
||||
|
||||
c->log->handler = ngx_accept_log_error;
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "AcceptEx: %d", c->fd);
|
||||
|
||||
if (rev->ovlp.error) {
|
||||
ngx_log_error(NGX_LOG_CRIT, c->log, rev->ovlp.error,
|
||||
"AcceptEx() %V failed", &ls->addr_text);
|
||||
return;
|
||||
}
|
||||
|
||||
/* SO_UPDATE_ACCEPT_CONTEXT is required for shutdown() to work */
|
||||
|
||||
if (setsockopt(c->fd, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
|
||||
(char *) &ls->fd, sizeof(ngx_socket_t))
|
||||
== -1)
|
||||
{
|
||||
ngx_log_error(NGX_LOG_CRIT, c->log, ngx_socket_errno,
|
||||
"setsockopt(SO_UPDATE_ACCEPT_CONTEXT) failed for %V",
|
||||
&c->addr_text);
|
||||
/* TODO: close socket */
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_getacceptexsockaddrs(c->buffer->pos,
|
||||
ls->post_accept_buffer_size,
|
||||
ls->socklen + 16,
|
||||
ls->socklen + 16,
|
||||
&c->local_sockaddr, &c->local_socklen,
|
||||
&c->sockaddr, &c->socklen);
|
||||
|
||||
if (ls->post_accept_buffer_size) {
|
||||
c->buffer->last += rev->available;
|
||||
c->buffer->end = c->buffer->start + ls->post_accept_buffer_size;
|
||||
|
||||
} else {
|
||||
c->buffer = NULL;
|
||||
}
|
||||
|
||||
if (ls->addr_ntop) {
|
||||
c->addr_text.data = ngx_pnalloc(c->pool, ls->addr_text_max_len);
|
||||
if (c->addr_text.data == NULL) {
|
||||
/* TODO: close socket */
|
||||
return;
|
||||
}
|
||||
|
||||
c->addr_text.len = ngx_sock_ntop(c->sockaddr, c->socklen,
|
||||
c->addr_text.data,
|
||||
ls->addr_text_max_len, 0);
|
||||
if (c->addr_text.len == 0) {
|
||||
/* TODO: close socket */
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ngx_event_post_acceptex(ls, 1);
|
||||
|
||||
c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1);
|
||||
|
||||
c->start_time = ngx_current_msec;
|
||||
|
||||
ls->handler(c);
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_event_post_acceptex(ngx_listening_t *ls, ngx_uint_t n)
|
||||
{
|
||||
u_long rcvd;
|
||||
ngx_err_t err;
|
||||
ngx_log_t *log;
|
||||
ngx_uint_t i;
|
||||
ngx_event_t *rev, *wev;
|
||||
ngx_socket_t s;
|
||||
ngx_connection_t *c;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
|
||||
/* TODO: look up reused sockets */
|
||||
|
||||
s = ngx_socket(ls->sockaddr->sa_family, ls->type, 0);
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, &ls->log, 0,
|
||||
ngx_socket_n " s:%d", s);
|
||||
|
||||
if (s == (ngx_socket_t) -1) {
|
||||
ngx_log_error(NGX_LOG_ALERT, &ls->log, ngx_socket_errno,
|
||||
ngx_socket_n " failed");
|
||||
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
c = ngx_get_connection(s, &ls->log);
|
||||
|
||||
if (c == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
c->pool = ngx_create_pool(ls->pool_size, &ls->log);
|
||||
if (c->pool == NULL) {
|
||||
ngx_close_posted_connection(c);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
log = ngx_palloc(c->pool, sizeof(ngx_log_t));
|
||||
if (log == NULL) {
|
||||
ngx_close_posted_connection(c);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
c->buffer = ngx_create_temp_buf(c->pool, ls->post_accept_buffer_size
|
||||
+ 2 * (ls->socklen + 16));
|
||||
if (c->buffer == NULL) {
|
||||
ngx_close_posted_connection(c);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
c->local_sockaddr = ngx_palloc(c->pool, ls->socklen);
|
||||
if (c->local_sockaddr == NULL) {
|
||||
ngx_close_posted_connection(c);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
c->sockaddr = ngx_palloc(c->pool, ls->socklen);
|
||||
if (c->sockaddr == NULL) {
|
||||
ngx_close_posted_connection(c);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
*log = ls->log;
|
||||
c->log = log;
|
||||
|
||||
c->recv = ngx_recv;
|
||||
c->send = ngx_send;
|
||||
c->recv_chain = ngx_recv_chain;
|
||||
c->send_chain = ngx_send_chain;
|
||||
|
||||
c->listening = ls;
|
||||
|
||||
rev = c->read;
|
||||
wev = c->write;
|
||||
|
||||
rev->ovlp.event = rev;
|
||||
wev->ovlp.event = wev;
|
||||
rev->handler = ngx_event_acceptex;
|
||||
|
||||
rev->ready = 1;
|
||||
wev->ready = 1;
|
||||
|
||||
rev->log = c->log;
|
||||
wev->log = c->log;
|
||||
|
||||
if (ngx_add_event(rev, 0, NGX_IOCP_IO) == NGX_ERROR) {
|
||||
ngx_close_posted_connection(c);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (ngx_acceptex(ls->fd, s, c->buffer->pos, ls->post_accept_buffer_size,
|
||||
ls->socklen + 16, ls->socklen + 16,
|
||||
&rcvd, (LPOVERLAPPED) &rev->ovlp)
|
||||
== 0)
|
||||
{
|
||||
err = ngx_socket_errno;
|
||||
if (err != WSA_IO_PENDING) {
|
||||
ngx_log_error(NGX_LOG_ALERT, &ls->log, err,
|
||||
"AcceptEx() %V failed", &ls->addr_text);
|
||||
|
||||
ngx_close_posted_connection(c);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_close_posted_connection(ngx_connection_t *c)
|
||||
{
|
||||
ngx_socket_t fd;
|
||||
|
||||
ngx_free_connection(c);
|
||||
|
||||
fd = c->fd;
|
||||
c->fd = (ngx_socket_t) -1;
|
||||
|
||||
if (ngx_close_socket(fd) == -1) {
|
||||
ngx_log_error(NGX_LOG_ALERT, c->log, ngx_socket_errno,
|
||||
ngx_close_socket_n " failed");
|
||||
}
|
||||
|
||||
if (c->pool) {
|
||||
ngx_destroy_pool(c->pool);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
u_char *
|
||||
ngx_acceptex_log_error(ngx_log_t *log, u_char *buf, size_t len)
|
||||
{
|
||||
return ngx_snprintf(buf, len, " while posting AcceptEx() on %V", log->data);
|
||||
}
|
||||
435
nginx/src/event/ngx_event_connect.c
Normal file
435
nginx/src/event/ngx_event_connect.c
Normal file
|
|
@ -0,0 +1,435 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_event.h>
|
||||
#include <ngx_event_connect.h>
|
||||
|
||||
|
||||
#if (NGX_HAVE_TRANSPARENT_PROXY)
|
||||
static ngx_int_t ngx_event_connect_set_transparent(ngx_peer_connection_t *pc,
|
||||
ngx_socket_t s);
|
||||
#endif
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_event_connect_peer(ngx_peer_connection_t *pc)
|
||||
{
|
||||
int rc, type, value;
|
||||
#if (NGX_HAVE_IP_BIND_ADDRESS_NO_PORT || NGX_LINUX)
|
||||
in_port_t port;
|
||||
#endif
|
||||
ngx_int_t event;
|
||||
ngx_err_t err;
|
||||
ngx_uint_t level;
|
||||
ngx_socket_t s;
|
||||
ngx_event_t *rev, *wev;
|
||||
ngx_connection_t *c;
|
||||
|
||||
rc = pc->get(pc, pc->data);
|
||||
if (rc != NGX_OK) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
type = (pc->type ? pc->type : SOCK_STREAM);
|
||||
|
||||
s = ngx_socket(pc->sockaddr->sa_family, type, 0);
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, pc->log, 0, "%s socket %d",
|
||||
(type == SOCK_STREAM) ? "stream" : "dgram", s);
|
||||
|
||||
if (s == (ngx_socket_t) -1) {
|
||||
ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
|
||||
ngx_socket_n " failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
|
||||
c = ngx_get_connection(s, pc->log);
|
||||
|
||||
if (c == NULL) {
|
||||
if (ngx_close_socket(s) == -1) {
|
||||
ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
|
||||
ngx_close_socket_n " failed");
|
||||
}
|
||||
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
c->type = type;
|
||||
|
||||
if (pc->rcvbuf) {
|
||||
if (setsockopt(s, SOL_SOCKET, SO_RCVBUF,
|
||||
(const void *) &pc->rcvbuf, sizeof(int)) == -1)
|
||||
{
|
||||
ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
|
||||
"setsockopt(SO_RCVBUF) failed");
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
|
||||
if (pc->so_keepalive) {
|
||||
value = 1;
|
||||
|
||||
if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE,
|
||||
(const void *) &value, sizeof(int))
|
||||
== -1)
|
||||
{
|
||||
ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
|
||||
"setsockopt(SO_KEEPALIVE) failed, ignored");
|
||||
}
|
||||
}
|
||||
|
||||
if (ngx_nonblocking(s) == -1) {
|
||||
ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
|
||||
ngx_nonblocking_n " failed");
|
||||
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (pc->local) {
|
||||
|
||||
#if (NGX_HAVE_TRANSPARENT_PROXY)
|
||||
if (pc->transparent) {
|
||||
if (ngx_event_connect_set_transparent(pc, s) != NGX_OK) {
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (NGX_HAVE_IP_BIND_ADDRESS_NO_PORT || NGX_LINUX)
|
||||
port = ngx_inet_get_port(pc->local->sockaddr);
|
||||
#endif
|
||||
|
||||
#if (NGX_HAVE_IP_BIND_ADDRESS_NO_PORT)
|
||||
|
||||
if (pc->sockaddr->sa_family != AF_UNIX && port == 0) {
|
||||
static int bind_address_no_port = 1;
|
||||
|
||||
if (bind_address_no_port) {
|
||||
if (setsockopt(s, IPPROTO_IP, IP_BIND_ADDRESS_NO_PORT,
|
||||
(const void *) &bind_address_no_port,
|
||||
sizeof(int)) == -1)
|
||||
{
|
||||
err = ngx_socket_errno;
|
||||
|
||||
if (err != NGX_EOPNOTSUPP && err != NGX_ENOPROTOOPT) {
|
||||
ngx_log_error(NGX_LOG_ALERT, pc->log, err,
|
||||
"setsockopt(IP_BIND_ADDRESS_NO_PORT) "
|
||||
"failed, ignored");
|
||||
|
||||
} else {
|
||||
bind_address_no_port = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if (NGX_LINUX)
|
||||
|
||||
if (pc->type == SOCK_DGRAM && port != 0) {
|
||||
int reuse_addr = 1;
|
||||
|
||||
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
|
||||
(const void *) &reuse_addr, sizeof(int))
|
||||
== -1)
|
||||
{
|
||||
ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
|
||||
"setsockopt(SO_REUSEADDR) failed");
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if (bind(s, pc->local->sockaddr, pc->local->socklen) == -1) {
|
||||
ngx_log_error(NGX_LOG_CRIT, pc->log, ngx_socket_errno,
|
||||
"bind(%V) failed", &pc->local->name);
|
||||
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
|
||||
if (type == SOCK_STREAM) {
|
||||
c->recv = ngx_recv;
|
||||
c->send = ngx_send;
|
||||
c->recv_chain = ngx_recv_chain;
|
||||
c->send_chain = ngx_send_chain;
|
||||
|
||||
c->sendfile = 1;
|
||||
|
||||
if (pc->sockaddr->sa_family == AF_UNIX) {
|
||||
c->tcp_nopush = NGX_TCP_NOPUSH_DISABLED;
|
||||
c->tcp_nodelay = NGX_TCP_NODELAY_DISABLED;
|
||||
|
||||
#if (NGX_SOLARIS)
|
||||
/* Solaris's sendfilev() supports AF_NCA, AF_INET, and AF_INET6 */
|
||||
c->sendfile = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
} else { /* type == SOCK_DGRAM */
|
||||
c->recv = ngx_udp_recv;
|
||||
c->send = ngx_send;
|
||||
c->send_chain = ngx_udp_send_chain;
|
||||
|
||||
c->need_flush_buf = 1;
|
||||
}
|
||||
|
||||
c->log_error = pc->log_error;
|
||||
|
||||
rev = c->read;
|
||||
wev = c->write;
|
||||
|
||||
rev->log = pc->log;
|
||||
wev->log = pc->log;
|
||||
|
||||
pc->connection = c;
|
||||
|
||||
c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1);
|
||||
|
||||
c->start_time = ngx_current_msec;
|
||||
|
||||
if (ngx_add_conn) {
|
||||
if (ngx_add_conn(c) == NGX_ERROR) {
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
|
||||
ngx_log_debug3(NGX_LOG_DEBUG_EVENT, pc->log, 0,
|
||||
"connect to %V, fd:%d #%uA", pc->name, s, c->number);
|
||||
|
||||
rc = connect(s, pc->sockaddr, pc->socklen);
|
||||
|
||||
if (rc == -1) {
|
||||
err = ngx_socket_errno;
|
||||
|
||||
|
||||
if (err != NGX_EINPROGRESS
|
||||
#if (NGX_WIN32)
|
||||
/* Winsock returns WSAEWOULDBLOCK (NGX_EAGAIN) */
|
||||
&& err != NGX_EAGAIN
|
||||
#endif
|
||||
)
|
||||
{
|
||||
if (err == NGX_ECONNREFUSED
|
||||
#if (NGX_LINUX)
|
||||
/*
|
||||
* Linux returns EAGAIN instead of ECONNREFUSED
|
||||
* for unix sockets if listen queue is full
|
||||
*/
|
||||
|| err == NGX_EAGAIN
|
||||
#endif
|
||||
|| err == NGX_ECONNRESET
|
||||
|| err == NGX_ENETDOWN
|
||||
|| err == NGX_ENETUNREACH
|
||||
|| err == NGX_EHOSTDOWN
|
||||
|| err == NGX_EHOSTUNREACH)
|
||||
{
|
||||
level = NGX_LOG_ERR;
|
||||
|
||||
} else {
|
||||
level = NGX_LOG_CRIT;
|
||||
}
|
||||
|
||||
ngx_log_error(level, c->log, err, "connect() to %V failed",
|
||||
pc->name);
|
||||
|
||||
ngx_close_connection(c);
|
||||
pc->connection = NULL;
|
||||
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
}
|
||||
|
||||
if (ngx_add_conn) {
|
||||
if (rc == -1) {
|
||||
|
||||
/* NGX_EINPROGRESS */
|
||||
|
||||
return NGX_AGAIN;
|
||||
}
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, pc->log, 0, "connected");
|
||||
|
||||
wev->ready = 1;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
if (ngx_event_flags & NGX_USE_IOCP_EVENT) {
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pc->log, ngx_socket_errno,
|
||||
"connect(): %d", rc);
|
||||
|
||||
if (ngx_blocking(s) == -1) {
|
||||
ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
|
||||
ngx_blocking_n " failed");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/*
|
||||
* FreeBSD's aio allows to post an operation on non-connected socket.
|
||||
* NT does not support it.
|
||||
*
|
||||
* TODO: check in Win32, etc. As workaround we can use NGX_ONESHOT_EVENT
|
||||
*/
|
||||
|
||||
rev->ready = 1;
|
||||
wev->ready = 1;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
if (ngx_event_flags & NGX_USE_CLEAR_EVENT) {
|
||||
|
||||
/* kqueue */
|
||||
|
||||
event = NGX_CLEAR_EVENT;
|
||||
|
||||
} else {
|
||||
|
||||
/* select, poll, /dev/poll */
|
||||
|
||||
event = NGX_LEVEL_EVENT;
|
||||
}
|
||||
|
||||
if (ngx_add_event(rev, NGX_READ_EVENT, event) != NGX_OK) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (rc == -1) {
|
||||
|
||||
/* NGX_EINPROGRESS */
|
||||
|
||||
if (ngx_add_event(wev, NGX_WRITE_EVENT, event) != NGX_OK) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
return NGX_AGAIN;
|
||||
}
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, pc->log, 0, "connected");
|
||||
|
||||
wev->ready = 1;
|
||||
|
||||
return NGX_OK;
|
||||
|
||||
failed:
|
||||
|
||||
ngx_close_connection(c);
|
||||
pc->connection = NULL;
|
||||
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
|
||||
#if (NGX_HAVE_TRANSPARENT_PROXY)
|
||||
|
||||
static ngx_int_t
|
||||
ngx_event_connect_set_transparent(ngx_peer_connection_t *pc, ngx_socket_t s)
|
||||
{
|
||||
int value;
|
||||
|
||||
value = 1;
|
||||
|
||||
#if defined(SO_BINDANY)
|
||||
|
||||
if (setsockopt(s, SOL_SOCKET, SO_BINDANY,
|
||||
(const void *) &value, sizeof(int)) == -1)
|
||||
{
|
||||
ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
|
||||
"setsockopt(SO_BINDANY) failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
switch (pc->local->sockaddr->sa_family) {
|
||||
|
||||
case AF_INET:
|
||||
|
||||
#if defined(IP_TRANSPARENT)
|
||||
|
||||
if (setsockopt(s, IPPROTO_IP, IP_TRANSPARENT,
|
||||
(const void *) &value, sizeof(int)) == -1)
|
||||
{
|
||||
ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
|
||||
"setsockopt(IP_TRANSPARENT) failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
#elif defined(IP_BINDANY)
|
||||
|
||||
if (setsockopt(s, IPPROTO_IP, IP_BINDANY,
|
||||
(const void *) &value, sizeof(int)) == -1)
|
||||
{
|
||||
ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
|
||||
"setsockopt(IP_BINDANY) failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
break;
|
||||
|
||||
#if (NGX_HAVE_INET6)
|
||||
|
||||
case AF_INET6:
|
||||
|
||||
#if defined(IPV6_TRANSPARENT)
|
||||
|
||||
if (setsockopt(s, IPPROTO_IPV6, IPV6_TRANSPARENT,
|
||||
(const void *) &value, sizeof(int)) == -1)
|
||||
{
|
||||
ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
|
||||
"setsockopt(IPV6_TRANSPARENT) failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
#elif defined(IPV6_BINDANY)
|
||||
|
||||
if (setsockopt(s, IPPROTO_IPV6, IPV6_BINDANY,
|
||||
(const void *) &value, sizeof(int)) == -1)
|
||||
{
|
||||
ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
|
||||
"setsockopt(IPV6_BINDANY) failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
ngx_log_error(NGX_LOG_ALERT, pc->log, 0,
|
||||
"could not enable transparent proxying for IPv6 "
|
||||
"on this platform");
|
||||
|
||||
return NGX_ERROR;
|
||||
|
||||
#endif
|
||||
|
||||
break;
|
||||
|
||||
#endif /* NGX_HAVE_INET6 */
|
||||
|
||||
}
|
||||
|
||||
#endif /* SO_BINDANY */
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_event_get_peer(ngx_peer_connection_t *pc, void *data)
|
||||
{
|
||||
return NGX_OK;
|
||||
}
|
||||
85
nginx/src/event/ngx_event_connect.h
Normal file
85
nginx/src/event/ngx_event_connect.h
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_EVENT_CONNECT_H_INCLUDED_
|
||||
#define _NGX_EVENT_CONNECT_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_event.h>
|
||||
|
||||
|
||||
#define NGX_PEER_KEEPALIVE 1
|
||||
#define NGX_PEER_NEXT 2
|
||||
#define NGX_PEER_FAILED 4
|
||||
|
||||
|
||||
typedef struct ngx_peer_connection_s ngx_peer_connection_t;
|
||||
|
||||
typedef ngx_int_t (*ngx_event_get_peer_pt)(ngx_peer_connection_t *pc,
|
||||
void *data);
|
||||
typedef void (*ngx_event_free_peer_pt)(ngx_peer_connection_t *pc, void *data,
|
||||
ngx_uint_t state);
|
||||
typedef void (*ngx_event_notify_peer_pt)(ngx_peer_connection_t *pc,
|
||||
void *data, ngx_uint_t type);
|
||||
typedef ngx_int_t (*ngx_event_set_peer_session_pt)(ngx_peer_connection_t *pc,
|
||||
void *data);
|
||||
typedef void (*ngx_event_save_peer_session_pt)(ngx_peer_connection_t *pc,
|
||||
void *data);
|
||||
|
||||
|
||||
struct ngx_peer_connection_s {
|
||||
ngx_connection_t *connection;
|
||||
|
||||
struct sockaddr *sockaddr;
|
||||
socklen_t socklen;
|
||||
ngx_str_t *name;
|
||||
|
||||
ngx_uint_t tries;
|
||||
ngx_msec_t start_time;
|
||||
|
||||
ngx_event_get_peer_pt get;
|
||||
ngx_event_free_peer_pt free;
|
||||
ngx_event_notify_peer_pt notify;
|
||||
void *data;
|
||||
|
||||
#if (NGX_SSL || NGX_COMPAT)
|
||||
ngx_event_set_peer_session_pt set_session;
|
||||
ngx_event_save_peer_session_pt save_session;
|
||||
#endif
|
||||
|
||||
ngx_addr_t *local;
|
||||
|
||||
int type;
|
||||
int rcvbuf;
|
||||
|
||||
ngx_log_t *log;
|
||||
|
||||
#if (NGX_HTTP_UPSTREAM_SID || NGX_COMPAT)
|
||||
ngx_str_t *hint;
|
||||
ngx_str_t *sid;
|
||||
#endif
|
||||
|
||||
unsigned cached:1;
|
||||
unsigned transparent:1;
|
||||
unsigned so_keepalive:1;
|
||||
unsigned down:1;
|
||||
|
||||
/* ngx_connection_log_error_e */
|
||||
unsigned log_error:2;
|
||||
|
||||
NGX_COMPAT_BEGIN(1)
|
||||
NGX_COMPAT_END
|
||||
};
|
||||
|
||||
|
||||
ngx_int_t ngx_event_connect_peer(ngx_peer_connection_t *pc);
|
||||
ngx_int_t ngx_event_get_peer(ngx_peer_connection_t *pc, void *data);
|
||||
|
||||
|
||||
#endif /* _NGX_EVENT_CONNECT_H_INCLUDED_ */
|
||||
206
nginx/src/event/ngx_event_connectex.c
Normal file
206
nginx/src/event/ngx_event_connectex.c
Normal file
|
|
@ -0,0 +1,206 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_event.h>
|
||||
|
||||
|
||||
#define NGX_MAX_PENDING_CONN 10
|
||||
|
||||
|
||||
static CRITICAL_SECTION connect_lock;
|
||||
static int nconnects;
|
||||
static ngx_connection_t pending_connects[NGX_MAX_PENDING_CONN];
|
||||
|
||||
static HANDLE pending_connect_event;
|
||||
|
||||
__declspec(thread) int nevents = 0;
|
||||
__declspec(thread) WSAEVENT events[WSA_MAXIMUM_WAIT_EVENTS + 1];
|
||||
__declspec(thread) ngx_connection_t *conn[WSA_MAXIMUM_WAIT_EVENTS + 1];
|
||||
|
||||
|
||||
|
||||
int ngx_iocp_wait_connect(ngx_connection_t *c)
|
||||
{
|
||||
for ( ;; ) {
|
||||
EnterCriticalSection(&connect_lock);
|
||||
|
||||
if (nconnects < NGX_MAX_PENDING_CONN) {
|
||||
pending_connects[--nconnects] = c;
|
||||
LeaveCriticalSection(&connect_lock);
|
||||
|
||||
if (SetEvent(pending_connect_event) == 0) {
|
||||
ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
|
||||
"SetEvent() failed");
|
||||
return NGX_ERROR;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&connect_lock);
|
||||
ngx_log_error(NGX_LOG_NOTICE, c->log, 0,
|
||||
"max number of pending connect()s is %d",
|
||||
NGX_MAX_PENDING_CONN);
|
||||
msleep(100);
|
||||
}
|
||||
|
||||
if (!started) {
|
||||
if (ngx_iocp_new_thread(1) == NGX_ERROR) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
started = 1;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
int ngx_iocp_new_thread(int main)
|
||||
{
|
||||
u_int id;
|
||||
|
||||
if (main) {
|
||||
pending_connect_event = CreateEvent(NULL, 0, 1, NULL);
|
||||
if (pending_connect_event == INVALID_HANDLE_VALUE) {
|
||||
ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
|
||||
"CreateThread() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (CreateThread(NULL, 0, ngx_iocp_wait_events, main, 0, &id)
|
||||
== INVALID_HANDLE_VALUE)
|
||||
{
|
||||
ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
|
||||
"CreateThread() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
SetEvent(event) {
|
||||
ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
|
||||
"SetEvent() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
int ngx_iocp_new_connect()
|
||||
{
|
||||
EnterCriticalSection(&connect_lock);
|
||||
c = pending_connects[--nconnects];
|
||||
LeaveCriticalSection(&connect_lock);
|
||||
|
||||
conn[nevents] = c;
|
||||
|
||||
events[nevents] = WSACreateEvent();
|
||||
if (events[nevents] == INVALID_HANDLE_VALUE) {
|
||||
ngx_log_error(NGX_LOG_ALERT, c->log, ngx_socket_errno,
|
||||
"WSACreateEvent() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (WSAEventSelect(c->fd, events[nevents], FD_CONNECT) == -1)
|
||||
ngx_log_error(NGX_LOG_ALERT, c->log, ngx_socket_errno,
|
||||
"WSAEventSelect() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
nevents++;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
void ngx_iocp_wait_events(int main)
|
||||
{
|
||||
WSANETWORKEVENTS ne;
|
||||
|
||||
nevents = 1;
|
||||
events[0] = pending_connect_event;
|
||||
conn[0] = NULL;
|
||||
|
||||
for ( ;; ) {
|
||||
offset = (nevents == WSA_MAXIMUM_WAIT_EVENTS + 1) ? 1 : 0;
|
||||
timeout = (nevents == 1 && !first) ? 60000 : INFINITE;
|
||||
|
||||
n = WSAWaitForMultipleEvents(nevents - offset, events[offset],
|
||||
0, timeout, 0);
|
||||
if (n == WAIT_FAILED) {
|
||||
ngx_log_error(NGX_LOG_ALERT, log, ngx_socket_errno,
|
||||
"WSAWaitForMultipleEvents() failed");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (n == WAIT_TIMEOUT) {
|
||||
if (nevents == 2 && !main) {
|
||||
ExitThread(0);
|
||||
}
|
||||
|
||||
ngx_log_error(NGX_LOG_ALERT, log, 0,
|
||||
"WSAWaitForMultipleEvents() "
|
||||
"returned unexpected WAIT_TIMEOUT");
|
||||
continue;
|
||||
}
|
||||
|
||||
n -= WSA_WAIT_EVENT_0;
|
||||
|
||||
if (events[n] == NULL) {
|
||||
|
||||
/* the pending_connect_event */
|
||||
|
||||
if (nevents == WSA_MAXIMUM_WAIT_EVENTS) {
|
||||
ngx_iocp_new_thread(0);
|
||||
} else {
|
||||
ngx_iocp_new_connect();
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (WSAEnumNetworkEvents(c[n].fd, events[n], &ne) == -1) {
|
||||
ngx_log_error(NGX_LOG_ALERT, log, ngx_socket_errno,
|
||||
"WSAEnumNetworkEvents() failed");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ne.lNetworkEvents & FD_CONNECT) {
|
||||
conn[n].write->ovlp.error = ne.iErrorCode[FD_CONNECT_BIT];
|
||||
|
||||
if (PostQueuedCompletionStatus(iocp, 0, NGX_IOCP_CONNECT,
|
||||
&conn[n].write->ovlp) == 0)
|
||||
{
|
||||
ngx_log_error(NGX_LOG_ALERT, log, ngx_socket_errno,
|
||||
"PostQueuedCompletionStatus() failed");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (n < nevents) {
|
||||
conn[n] = conn[nevents];
|
||||
events[n] = events[nevents];
|
||||
}
|
||||
|
||||
nevents--;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ne.lNetworkEvents & FD_ACCEPT) {
|
||||
|
||||
/* CHECK ERROR ??? */
|
||||
|
||||
ngx_event_post_acceptex(conn[n].listening, 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
ngx_log_error(NGX_LOG_ALERT, c[n].log, 0,
|
||||
"WSAWaitForMultipleEvents() "
|
||||
"returned unexpected network event %ul",
|
||||
ne.lNetworkEvents);
|
||||
}
|
||||
}
|
||||
6609
nginx/src/event/ngx_event_openssl.c
Normal file
6609
nginx/src/event/ngx_event_openssl.c
Normal file
File diff suppressed because it is too large
Load diff
416
nginx/src/event/ngx_event_openssl.h
Normal file
416
nginx/src/event/ngx_event_openssl.h
Normal file
|
|
@ -0,0 +1,416 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_EVENT_OPENSSL_H_INCLUDED_
|
||||
#define _NGX_EVENT_OPENSSL_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
#define OPENSSL_SUPPRESS_DEPRECATED
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/conf.h>
|
||||
#include <openssl/crypto.h>
|
||||
#ifndef OPENSSL_NO_DH
|
||||
#include <openssl/dh.h>
|
||||
#endif
|
||||
#ifndef OPENSSL_NO_ENGINE
|
||||
#include <openssl/engine.h>
|
||||
#endif
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/hmac.h>
|
||||
#ifndef OPENSSL_NO_OCSP
|
||||
#include <openssl/ocsp.h>
|
||||
#endif
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/x509v3.h>
|
||||
|
||||
#define NGX_SSL_NAME "OpenSSL"
|
||||
|
||||
|
||||
#if (defined LIBRESSL_VERSION_NUMBER && OPENSSL_VERSION_NUMBER == 0x20000000L)
|
||||
#undef OPENSSL_VERSION_NUMBER
|
||||
#if (LIBRESSL_VERSION_NUMBER >= 0x3050000fL)
|
||||
#define OPENSSL_VERSION_NUMBER 0x1010000fL
|
||||
#else
|
||||
#define OPENSSL_VERSION_NUMBER 0x1000107fL
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x10100001L)
|
||||
|
||||
#define ngx_ssl_version() OpenSSL_version(OPENSSL_VERSION)
|
||||
|
||||
#else
|
||||
|
||||
#define ngx_ssl_version() SSLeay_version(SSLEAY_VERSION)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#define ngx_ssl_session_t SSL_SESSION
|
||||
#define ngx_ssl_conn_t SSL
|
||||
|
||||
|
||||
#if (OPENSSL_VERSION_NUMBER < 0x10002000L)
|
||||
#define SSL_is_server(s) (s)->server
|
||||
#endif
|
||||
|
||||
|
||||
#if (OPENSSL_VERSION_NUMBER < 0x1010000fL)
|
||||
#define ASN1_STRING_get0_data(x) (x)->data
|
||||
#endif
|
||||
|
||||
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x30000000L && !defined SSL_get_peer_certificate)
|
||||
#define SSL_get_peer_certificate(s) SSL_get1_peer_certificate(s)
|
||||
#endif
|
||||
|
||||
|
||||
#if (OPENSSL_VERSION_NUMBER < 0x30000000L && !defined ERR_peek_error_data)
|
||||
#define ERR_peek_error_data(d, f) ERR_peek_error_line_data(NULL, NULL, d, f)
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef OPENSSL_NO_DEPRECATED_3_4
|
||||
#define SSL_SESSION_get_time(s) SSL_SESSION_get_time_ex(s)
|
||||
#define SSL_SESSION_set_time(s, t) SSL_SESSION_set_time_ex(s, t)
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef OPENSSL_NO_DEPRECATED_3_0
|
||||
#define EVP_CIPHER_CTX_cipher(c) EVP_CIPHER_CTX_get0_cipher(c)
|
||||
#endif
|
||||
|
||||
|
||||
#if (OPENSSL_VERSION_NUMBER < 0x30000000L)
|
||||
#define SSL_group_to_name(s, nid) NULL
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct ngx_ssl_ocsp_s ngx_ssl_ocsp_t;
|
||||
|
||||
|
||||
struct ngx_ssl_s {
|
||||
SSL_CTX *ctx;
|
||||
ngx_log_t *log;
|
||||
size_t buffer_size;
|
||||
|
||||
ngx_array_t certs;
|
||||
|
||||
ngx_rbtree_t staple_rbtree;
|
||||
ngx_rbtree_node_t staple_sentinel;
|
||||
};
|
||||
|
||||
|
||||
struct ngx_ssl_connection_s {
|
||||
ngx_ssl_conn_t *connection;
|
||||
SSL_CTX *session_ctx;
|
||||
|
||||
ngx_int_t last;
|
||||
ngx_buf_t *buf;
|
||||
size_t buffer_size;
|
||||
|
||||
ngx_connection_handler_pt handler;
|
||||
|
||||
ngx_ssl_session_t *session;
|
||||
ngx_connection_handler_pt save_session;
|
||||
|
||||
ngx_event_handler_pt saved_read_handler;
|
||||
ngx_event_handler_pt saved_write_handler;
|
||||
|
||||
ngx_ssl_ocsp_t *ocsp;
|
||||
|
||||
u_char early_buf;
|
||||
|
||||
unsigned handshaked:1;
|
||||
unsigned handshake_rejected:1;
|
||||
unsigned renegotiation:1;
|
||||
unsigned buffer:1;
|
||||
unsigned sendfile:1;
|
||||
unsigned no_wait_shutdown:1;
|
||||
unsigned no_send_shutdown:1;
|
||||
unsigned shutdown_without_free:1;
|
||||
unsigned handshake_buffer_set:1;
|
||||
unsigned session_timeout_set:1;
|
||||
unsigned try_early_data:1;
|
||||
unsigned in_early:1;
|
||||
unsigned in_ocsp:1;
|
||||
unsigned early_preread:1;
|
||||
unsigned write_blocked:1;
|
||||
unsigned sni_accepted:1;
|
||||
};
|
||||
|
||||
|
||||
#define NGX_SSL_NO_SCACHE -2
|
||||
#define NGX_SSL_NONE_SCACHE -3
|
||||
#define NGX_SSL_NO_BUILTIN_SCACHE -4
|
||||
#define NGX_SSL_DFLT_BUILTIN_SCACHE -5
|
||||
|
||||
|
||||
#define NGX_SSL_MAX_SESSION_SIZE 8192
|
||||
|
||||
typedef struct ngx_ssl_sess_id_s ngx_ssl_sess_id_t;
|
||||
|
||||
struct ngx_ssl_sess_id_s {
|
||||
ngx_rbtree_node_t node;
|
||||
size_t len;
|
||||
ngx_queue_t queue;
|
||||
time_t expire;
|
||||
u_char id[32];
|
||||
#if (NGX_PTR_SIZE == 8)
|
||||
u_char *session;
|
||||
#else
|
||||
u_char session[1];
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
typedef struct {
|
||||
u_char name[16];
|
||||
u_char hmac_key[32];
|
||||
u_char aes_key[32];
|
||||
time_t expire;
|
||||
unsigned size:8;
|
||||
unsigned shared:1;
|
||||
} ngx_ssl_ticket_key_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_rbtree_t session_rbtree;
|
||||
ngx_rbtree_node_t sentinel;
|
||||
ngx_queue_t expire_queue;
|
||||
ngx_ssl_ticket_key_t ticket_keys[3];
|
||||
time_t fail_time;
|
||||
} ngx_ssl_session_cache_t;
|
||||
|
||||
|
||||
typedef int (*ngx_ssl_servername_pt)(ngx_ssl_conn_t *, int *, void *);
|
||||
|
||||
typedef struct {
|
||||
ngx_ssl_servername_pt servername;
|
||||
} ngx_ssl_client_hello_arg;
|
||||
|
||||
|
||||
#define NGX_SSL_SSLv2 0x0002
|
||||
#define NGX_SSL_SSLv3 0x0004
|
||||
#define NGX_SSL_TLSv1 0x0008
|
||||
#define NGX_SSL_TLSv1_1 0x0010
|
||||
#define NGX_SSL_TLSv1_2 0x0020
|
||||
#define NGX_SSL_TLSv1_3 0x0040
|
||||
|
||||
|
||||
#if (defined SSL_OP_NO_TLSv1_2 || defined SSL_OP_NO_TLSv1_3)
|
||||
#define NGX_SSL_DEFAULT_PROTOCOLS (NGX_SSL_TLSv1_2|NGX_SSL_TLSv1_3)
|
||||
#else
|
||||
#define NGX_SSL_DEFAULT_PROTOCOLS (NGX_SSL_TLSv1|NGX_SSL_TLSv1_1)
|
||||
#endif
|
||||
|
||||
|
||||
#define NGX_SSL_BUFFER 1
|
||||
#define NGX_SSL_CLIENT 2
|
||||
|
||||
#define NGX_SSL_BUFSIZE 16384
|
||||
|
||||
|
||||
#define NGX_SSL_CACHE_CERT 0
|
||||
#define NGX_SSL_CACHE_PKEY 1
|
||||
#define NGX_SSL_CACHE_CRL 2
|
||||
#define NGX_SSL_CACHE_CA 3
|
||||
|
||||
#define NGX_SSL_CACHE_INVALIDATE 0x80000000
|
||||
|
||||
|
||||
ngx_int_t ngx_ssl_init(ngx_log_t *log);
|
||||
ngx_int_t ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data);
|
||||
|
||||
ngx_int_t ngx_ssl_certificates(ngx_conf_t *cf, ngx_ssl_t *ssl,
|
||||
ngx_array_t *certs, ngx_array_t *keys, ngx_array_t *passwords);
|
||||
ngx_int_t ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl,
|
||||
ngx_str_t *cert, ngx_str_t *key, ngx_array_t *passwords);
|
||||
ngx_int_t ngx_ssl_connection_certificate(ngx_connection_t *c, ngx_pool_t *pool,
|
||||
ngx_str_t *cert, ngx_str_t *key, ngx_ssl_cache_t *cache,
|
||||
ngx_array_t *passwords);
|
||||
ngx_int_t ngx_ssl_certificate_compression(ngx_conf_t *cf, ngx_ssl_t *ssl,
|
||||
ngx_uint_t enable);
|
||||
|
||||
ngx_int_t ngx_ssl_ciphers(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *ciphers,
|
||||
ngx_uint_t prefer_server_ciphers);
|
||||
ngx_int_t ngx_ssl_client_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl,
|
||||
ngx_str_t *cert, ngx_int_t depth);
|
||||
ngx_int_t ngx_ssl_trusted_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl,
|
||||
ngx_str_t *cert, ngx_int_t depth);
|
||||
ngx_int_t ngx_ssl_crl(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *crl);
|
||||
ngx_int_t ngx_ssl_stapling(ngx_conf_t *cf, ngx_ssl_t *ssl,
|
||||
ngx_str_t *file, ngx_str_t *responder, ngx_uint_t verify);
|
||||
ngx_int_t ngx_ssl_stapling_resolver(ngx_conf_t *cf, ngx_ssl_t *ssl,
|
||||
ngx_resolver_t *resolver, ngx_msec_t resolver_timeout);
|
||||
ngx_int_t ngx_ssl_ocsp(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *responder,
|
||||
ngx_uint_t depth, ngx_shm_zone_t *shm_zone);
|
||||
ngx_int_t ngx_ssl_ocsp_resolver(ngx_conf_t *cf, ngx_ssl_t *ssl,
|
||||
ngx_resolver_t *resolver, ngx_msec_t resolver_timeout);
|
||||
|
||||
ngx_int_t ngx_ssl_ocsp_validate(ngx_connection_t *c);
|
||||
ngx_int_t ngx_ssl_ocsp_get_status(ngx_connection_t *c, const char **s);
|
||||
void ngx_ssl_ocsp_cleanup(ngx_connection_t *c);
|
||||
ngx_int_t ngx_ssl_ocsp_cache_init(ngx_shm_zone_t *shm_zone, void *data);
|
||||
|
||||
ngx_ssl_cache_t *ngx_ssl_cache_init(ngx_pool_t *pool, ngx_uint_t max,
|
||||
time_t valid, time_t inactive);
|
||||
void *ngx_ssl_cache_fetch(ngx_conf_t *cf, ngx_uint_t index, char **err,
|
||||
ngx_str_t *path, void *data);
|
||||
void *ngx_ssl_cache_connection_fetch(ngx_ssl_cache_t *cache, ngx_pool_t *pool,
|
||||
ngx_uint_t index, char **err, ngx_str_t *path, void *data);
|
||||
|
||||
ngx_array_t *ngx_ssl_read_password_file(ngx_conf_t *cf, ngx_str_t *file);
|
||||
ngx_array_t *ngx_ssl_preserve_passwords(ngx_conf_t *cf,
|
||||
ngx_array_t *passwords);
|
||||
ngx_int_t ngx_ssl_dhparam(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file);
|
||||
ngx_int_t ngx_ssl_ech_files(ngx_conf_t *cf, ngx_ssl_t *ssl,
|
||||
ngx_array_t *filename);
|
||||
ngx_int_t ngx_ssl_ecdh_curve(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *name);
|
||||
ngx_int_t ngx_ssl_early_data(ngx_conf_t *cf, ngx_ssl_t *ssl,
|
||||
ngx_uint_t enable);
|
||||
ngx_int_t ngx_ssl_conf_commands(ngx_conf_t *cf, ngx_ssl_t *ssl,
|
||||
ngx_array_t *commands);
|
||||
|
||||
ngx_int_t ngx_ssl_client_session_cache(ngx_conf_t *cf, ngx_ssl_t *ssl,
|
||||
ngx_uint_t enable);
|
||||
ngx_int_t ngx_ssl_session_cache(ngx_ssl_t *ssl, ngx_str_t *sess_ctx,
|
||||
ngx_array_t *certificates, ssize_t builtin_session_cache,
|
||||
ngx_shm_zone_t *shm_zone, time_t timeout);
|
||||
ngx_int_t ngx_ssl_session_ticket_keys(ngx_conf_t *cf, ngx_ssl_t *ssl,
|
||||
ngx_array_t *paths);
|
||||
ngx_int_t ngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone, void *data);
|
||||
|
||||
ngx_int_t ngx_ssl_set_client_hello_callback(ngx_ssl_t *ssl,
|
||||
ngx_ssl_client_hello_arg *cb);
|
||||
#ifdef SSL_CLIENT_HELLO_SUCCESS
|
||||
int ngx_ssl_client_hello_callback(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg);
|
||||
#elif defined OPENSSL_IS_BORINGSSL
|
||||
enum ssl_select_cert_result_t ngx_ssl_select_certificate(
|
||||
const SSL_CLIENT_HELLO *client_hello);
|
||||
#endif
|
||||
|
||||
ngx_int_t ngx_ssl_create_connection(ngx_ssl_t *ssl, ngx_connection_t *c,
|
||||
ngx_uint_t flags);
|
||||
|
||||
void ngx_ssl_remove_cached_session(SSL_CTX *ssl, ngx_ssl_session_t *sess);
|
||||
ngx_int_t ngx_ssl_set_session(ngx_connection_t *c, ngx_ssl_session_t *session);
|
||||
ngx_ssl_session_t *ngx_ssl_get_session(ngx_connection_t *c);
|
||||
ngx_ssl_session_t *ngx_ssl_get0_session(ngx_connection_t *c);
|
||||
#define ngx_ssl_free_session SSL_SESSION_free
|
||||
#define ngx_ssl_get_connection(ssl_conn) \
|
||||
SSL_get_ex_data(ssl_conn, ngx_ssl_connection_index)
|
||||
#define ngx_ssl_get_server_conf(ssl_ctx) \
|
||||
SSL_CTX_get_ex_data(ssl_ctx, ngx_ssl_server_conf_index)
|
||||
|
||||
#define ngx_ssl_verify_error_optional(n) \
|
||||
(n == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT \
|
||||
|| n == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN \
|
||||
|| n == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY \
|
||||
|| n == X509_V_ERR_CERT_UNTRUSTED \
|
||||
|| n == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE)
|
||||
|
||||
ngx_int_t ngx_ssl_check_host(ngx_connection_t *c, ngx_str_t *name);
|
||||
|
||||
|
||||
ngx_int_t ngx_ssl_get_protocol(ngx_connection_t *c, ngx_pool_t *pool,
|
||||
ngx_str_t *s);
|
||||
ngx_int_t ngx_ssl_get_cipher_name(ngx_connection_t *c, ngx_pool_t *pool,
|
||||
ngx_str_t *s);
|
||||
ngx_int_t ngx_ssl_get_ciphers(ngx_connection_t *c, ngx_pool_t *pool,
|
||||
ngx_str_t *s);
|
||||
ngx_int_t ngx_ssl_get_curve(ngx_connection_t *c, ngx_pool_t *pool,
|
||||
ngx_str_t *s);
|
||||
ngx_int_t ngx_ssl_get_curves(ngx_connection_t *c, ngx_pool_t *pool,
|
||||
ngx_str_t *s);
|
||||
ngx_int_t ngx_ssl_get_sigalg(ngx_connection_t *c, ngx_pool_t *pool,
|
||||
ngx_str_t *s);
|
||||
ngx_int_t ngx_ssl_get_session_id(ngx_connection_t *c, ngx_pool_t *pool,
|
||||
ngx_str_t *s);
|
||||
ngx_int_t ngx_ssl_get_session_reused(ngx_connection_t *c, ngx_pool_t *pool,
|
||||
ngx_str_t *s);
|
||||
ngx_int_t ngx_ssl_get_early_data(ngx_connection_t *c, ngx_pool_t *pool,
|
||||
ngx_str_t *s);
|
||||
ngx_int_t ngx_ssl_get_server_name(ngx_connection_t *c, ngx_pool_t *pool,
|
||||
ngx_str_t *s);
|
||||
ngx_int_t ngx_ssl_get_ech_status(ngx_connection_t *c, ngx_pool_t *pool,
|
||||
ngx_str_t *s);
|
||||
ngx_int_t ngx_ssl_get_ech_outer_server_name(ngx_connection_t *c,
|
||||
ngx_pool_t *pool, ngx_str_t *s);
|
||||
ngx_int_t ngx_ssl_get_alpn_protocol(ngx_connection_t *c, ngx_pool_t *pool,
|
||||
ngx_str_t *s);
|
||||
ngx_int_t ngx_ssl_get_raw_certificate(ngx_connection_t *c, ngx_pool_t *pool,
|
||||
ngx_str_t *s);
|
||||
ngx_int_t ngx_ssl_get_certificate(ngx_connection_t *c, ngx_pool_t *pool,
|
||||
ngx_str_t *s);
|
||||
ngx_int_t ngx_ssl_get_escaped_certificate(ngx_connection_t *c, ngx_pool_t *pool,
|
||||
ngx_str_t *s);
|
||||
ngx_int_t ngx_ssl_get_subject_dn(ngx_connection_t *c, ngx_pool_t *pool,
|
||||
ngx_str_t *s);
|
||||
ngx_int_t ngx_ssl_get_issuer_dn(ngx_connection_t *c, ngx_pool_t *pool,
|
||||
ngx_str_t *s);
|
||||
ngx_int_t ngx_ssl_get_subject_dn_legacy(ngx_connection_t *c, ngx_pool_t *pool,
|
||||
ngx_str_t *s);
|
||||
ngx_int_t ngx_ssl_get_issuer_dn_legacy(ngx_connection_t *c, ngx_pool_t *pool,
|
||||
ngx_str_t *s);
|
||||
ngx_int_t ngx_ssl_get_serial_number(ngx_connection_t *c, ngx_pool_t *pool,
|
||||
ngx_str_t *s);
|
||||
ngx_int_t ngx_ssl_get_fingerprint(ngx_connection_t *c, ngx_pool_t *pool,
|
||||
ngx_str_t *s);
|
||||
ngx_int_t ngx_ssl_get_client_verify(ngx_connection_t *c, ngx_pool_t *pool,
|
||||
ngx_str_t *s);
|
||||
ngx_int_t ngx_ssl_get_client_v_start(ngx_connection_t *c, ngx_pool_t *pool,
|
||||
ngx_str_t *s);
|
||||
ngx_int_t ngx_ssl_get_client_v_end(ngx_connection_t *c, ngx_pool_t *pool,
|
||||
ngx_str_t *s);
|
||||
ngx_int_t ngx_ssl_get_client_v_remain(ngx_connection_t *c, ngx_pool_t *pool,
|
||||
ngx_str_t *s);
|
||||
ngx_int_t ngx_ssl_get_client_sigalg(ngx_connection_t *c, ngx_pool_t *pool,
|
||||
ngx_str_t *s);
|
||||
|
||||
|
||||
ngx_int_t ngx_ssl_handshake(ngx_connection_t *c);
|
||||
#if (NGX_DEBUG)
|
||||
void ngx_ssl_handshake_log(ngx_connection_t *c);
|
||||
#endif
|
||||
ssize_t ngx_ssl_recv(ngx_connection_t *c, u_char *buf, size_t size);
|
||||
ssize_t ngx_ssl_write(ngx_connection_t *c, u_char *data, size_t size);
|
||||
ssize_t ngx_ssl_recv_chain(ngx_connection_t *c, ngx_chain_t *cl, off_t limit);
|
||||
ngx_chain_t *ngx_ssl_send_chain(ngx_connection_t *c, ngx_chain_t *in,
|
||||
off_t limit);
|
||||
void ngx_ssl_free_buffer(ngx_connection_t *c);
|
||||
ngx_int_t ngx_ssl_shutdown(ngx_connection_t *c);
|
||||
void ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err,
|
||||
char *text);
|
||||
void ngx_cdecl ngx_ssl_error(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,
|
||||
char *fmt, ...);
|
||||
void ngx_ssl_cleanup_ctx(void *data);
|
||||
|
||||
|
||||
extern int ngx_ssl_connection_index;
|
||||
extern int ngx_ssl_server_conf_index;
|
||||
extern int ngx_ssl_session_cache_index;
|
||||
extern int ngx_ssl_ticket_keys_index;
|
||||
extern int ngx_ssl_ocsp_index;
|
||||
extern int ngx_ssl_index;
|
||||
extern int ngx_ssl_certificate_name_index;
|
||||
extern int ngx_ssl_certificate_comp_index;
|
||||
extern int ngx_ssl_client_hello_arg_index;
|
||||
|
||||
|
||||
extern u_char ngx_ssl_session_buffer[NGX_SSL_MAX_SESSION_SIZE];
|
||||
|
||||
|
||||
#endif /* _NGX_EVENT_OPENSSL_H_INCLUDED_ */
|
||||
1267
nginx/src/event/ngx_event_openssl_cache.c
Normal file
1267
nginx/src/event/ngx_event_openssl_cache.c
Normal file
File diff suppressed because it is too large
Load diff
2819
nginx/src/event/ngx_event_openssl_stapling.c
Normal file
2819
nginx/src/event/ngx_event_openssl_stapling.c
Normal file
File diff suppressed because it is too large
Load diff
1146
nginx/src/event/ngx_event_pipe.c
Normal file
1146
nginx/src/event/ngx_event_pipe.c
Normal file
File diff suppressed because it is too large
Load diff
107
nginx/src/event/ngx_event_pipe.h
Normal file
107
nginx/src/event/ngx_event_pipe.h
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_EVENT_PIPE_H_INCLUDED_
|
||||
#define _NGX_EVENT_PIPE_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_event.h>
|
||||
|
||||
|
||||
typedef struct ngx_event_pipe_s ngx_event_pipe_t;
|
||||
|
||||
typedef ngx_int_t (*ngx_event_pipe_input_filter_pt)(ngx_event_pipe_t *p,
|
||||
ngx_buf_t *buf);
|
||||
typedef ngx_int_t (*ngx_event_pipe_output_filter_pt)(void *data,
|
||||
ngx_chain_t *chain);
|
||||
|
||||
|
||||
struct ngx_event_pipe_s {
|
||||
ngx_connection_t *upstream;
|
||||
ngx_connection_t *downstream;
|
||||
|
||||
ngx_chain_t *free_raw_bufs;
|
||||
ngx_chain_t *in;
|
||||
ngx_chain_t **last_in;
|
||||
|
||||
ngx_chain_t *writing;
|
||||
|
||||
ngx_chain_t *out;
|
||||
ngx_chain_t *free;
|
||||
ngx_chain_t *busy;
|
||||
|
||||
/*
|
||||
* the input filter i.e. that moves HTTP/1.1 chunks
|
||||
* from the raw bufs to an incoming chain
|
||||
*/
|
||||
|
||||
ngx_event_pipe_input_filter_pt input_filter;
|
||||
void *input_ctx;
|
||||
|
||||
ngx_event_pipe_output_filter_pt output_filter;
|
||||
void *output_ctx;
|
||||
|
||||
#if (NGX_THREADS || NGX_COMPAT)
|
||||
ngx_int_t (*thread_handler)(ngx_thread_task_t *task,
|
||||
ngx_file_t *file);
|
||||
void *thread_ctx;
|
||||
ngx_thread_task_t *thread_task;
|
||||
#endif
|
||||
|
||||
unsigned read:1;
|
||||
unsigned cacheable:1;
|
||||
unsigned single_buf:1;
|
||||
unsigned free_bufs:1;
|
||||
unsigned upstream_done:1;
|
||||
unsigned upstream_error:1;
|
||||
unsigned upstream_eof:1;
|
||||
unsigned upstream_blocked:1;
|
||||
unsigned downstream_done:1;
|
||||
unsigned downstream_error:1;
|
||||
unsigned cyclic_temp_file:1;
|
||||
unsigned aio:1;
|
||||
|
||||
ngx_int_t allocated;
|
||||
ngx_bufs_t bufs;
|
||||
ngx_buf_tag_t tag;
|
||||
|
||||
ssize_t busy_size;
|
||||
|
||||
off_t read_length;
|
||||
off_t length;
|
||||
|
||||
off_t max_temp_file_size;
|
||||
ssize_t temp_file_write_size;
|
||||
|
||||
ngx_msec_t read_timeout;
|
||||
ngx_msec_t send_timeout;
|
||||
ssize_t send_lowat;
|
||||
|
||||
ngx_pool_t *pool;
|
||||
ngx_log_t *log;
|
||||
|
||||
ngx_chain_t *preread_bufs;
|
||||
size_t preread_size;
|
||||
ngx_buf_t *buf_to_file;
|
||||
|
||||
size_t limit_rate;
|
||||
time_t start_sec;
|
||||
|
||||
ngx_temp_file_t *temp_file;
|
||||
|
||||
/* STUB */ int num;
|
||||
};
|
||||
|
||||
|
||||
ngx_int_t ngx_event_pipe(ngx_event_pipe_t *p, ngx_int_t do_write);
|
||||
ngx_int_t ngx_event_pipe_copy_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf);
|
||||
ngx_int_t ngx_event_pipe_add_free_buf(ngx_event_pipe_t *p, ngx_buf_t *b);
|
||||
|
||||
|
||||
#endif /* _NGX_EVENT_PIPE_H_INCLUDED_ */
|
||||
60
nginx/src/event/ngx_event_posted.c
Normal file
60
nginx/src/event/ngx_event_posted.c
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_event.h>
|
||||
|
||||
|
||||
ngx_queue_t ngx_posted_accept_events;
|
||||
ngx_queue_t ngx_posted_next_events;
|
||||
ngx_queue_t ngx_posted_events;
|
||||
|
||||
|
||||
void
|
||||
ngx_event_process_posted(ngx_cycle_t *cycle, ngx_queue_t *posted)
|
||||
{
|
||||
ngx_queue_t *q;
|
||||
ngx_event_t *ev;
|
||||
|
||||
while (!ngx_queue_empty(posted)) {
|
||||
|
||||
q = ngx_queue_head(posted);
|
||||
ev = ngx_queue_data(q, ngx_event_t, queue);
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
|
||||
"posted event %p", ev);
|
||||
|
||||
ngx_delete_posted_event(ev);
|
||||
|
||||
ev->handler(ev);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_event_move_posted_next(ngx_cycle_t *cycle)
|
||||
{
|
||||
ngx_queue_t *q;
|
||||
ngx_event_t *ev;
|
||||
|
||||
for (q = ngx_queue_head(&ngx_posted_next_events);
|
||||
q != ngx_queue_sentinel(&ngx_posted_next_events);
|
||||
q = ngx_queue_next(q))
|
||||
{
|
||||
ev = ngx_queue_data(q, ngx_event_t, queue);
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
|
||||
"posted next event %p", ev);
|
||||
|
||||
ev->ready = 1;
|
||||
ev->available = -1;
|
||||
}
|
||||
|
||||
ngx_queue_add(&ngx_posted_events, &ngx_posted_next_events);
|
||||
ngx_queue_init(&ngx_posted_next_events);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue