Merge commit '484a904fa7' as 'nginx'

This commit is contained in:
Ava Apples Affine 2026-04-30 00:59:20 +00:00
commit 2b63c55768
528 changed files with 294288 additions and 0 deletions

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
View 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
View 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;
}

View 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
View 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
View 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
View 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
View 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_ */

File diff suppressed because it is too large Load diff

View 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
View 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_ */

File diff suppressed because it is too large Load diff

View 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
View 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_ */

View 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
View 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
View 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;
}

View 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
View 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 */

View 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

File diff suppressed because it is too large Load diff

149
nginx/src/core/ngx_cycle.h Normal file
View 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

File diff suppressed because it is too large Load diff

164
nginx/src/core/ngx_file.h Normal file
View 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

File diff suppressed because it is too large Load diff

125
nginx/src/core/ngx_hash.h Normal file
View 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

File diff suppressed because it is too large Load diff

132
nginx/src/core/ngx_inet.h Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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_ */

View 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;
}

View 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_ */

File diff suppressed because it is too large Load diff

View 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_ */

View 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
View 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

View 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
View 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;
}

View 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_ */

View 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;
}

View 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_ */

View 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;
}

View 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
View 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
View 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_ */

View 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;
}

View 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
View 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;
}
}

View 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
View 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;
}

View 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_ */

File diff suppressed because it is too large Load diff

View 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
View 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

View 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
View 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
View 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
View 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

View 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
View 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
View 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_ */

View 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

File diff suppressed because it is too large Load diff

239
nginx/src/core/ngx_string.h Normal file
View 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
View 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;
}

View 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_ */

View 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]);
}
}

View 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
View 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;
}

View 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_ */

View 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;
}

File diff suppressed because it is too large Load diff

View 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, &notify_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;
}

View 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;
}

View 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_ */

View 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, &notify_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) &notify_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, &notify_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;
}

View 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;
}

View 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;
}

View 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;
}

View 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

File diff suppressed because it is too large Load diff

533
nginx/src/event/ngx_event.h Normal file
View 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_ */

View 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

View 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);
}

View 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;
}

View 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_ */

View 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);
}
}

File diff suppressed because it is too large Load diff

View 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_ */

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View 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_ */

View 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