Initial Commit
This commit is contained in:
1574
src/core/nginx.c
Normal file
1574
src/core/nginx.c
Normal file
File diff suppressed because it is too large
Load Diff
26
src/core/nginx.h
Normal file
26
src/core/nginx.h
Normal file
@@ -0,0 +1,26 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGINX_H_INCLUDED_
|
||||
#define _NGINX_H_INCLUDED_
|
||||
|
||||
|
||||
#define nginx_version 1011009
|
||||
#define NGINX_VERSION "1.11.9"
|
||||
#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
src/core/ngx_array.c
Normal file
141
src/core/ngx_array.c
Normal file
@@ -0,0 +1,141 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
ngx_array_t *
|
||||
ngx_array_create(ngx_pool_t *p, ngx_uint_t n, size_t size)
|
||||
{
|
||||
ngx_array_t *a;
|
||||
|
||||
a = ngx_palloc(p, sizeof(ngx_array_t));
|
||||
if (a == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ngx_array_init(a, p, n, size) != NGX_OK) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_array_destroy(ngx_array_t *a)
|
||||
{
|
||||
ngx_pool_t *p;
|
||||
|
||||
p = a->pool;
|
||||
|
||||
if ((u_char *) a->elts + a->size * a->nalloc == p->d.last) {
|
||||
p->d.last -= a->size * a->nalloc;
|
||||
}
|
||||
|
||||
if ((u_char *) a + sizeof(ngx_array_t) == p->d.last) {
|
||||
p->d.last = (u_char *) a;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
ngx_array_push(ngx_array_t *a)
|
||||
{
|
||||
void *elt, *new;
|
||||
size_t size;
|
||||
ngx_pool_t *p;
|
||||
|
||||
if (a->nelts == a->nalloc) {
|
||||
|
||||
/* the array is full */
|
||||
|
||||
size = a->size * a->nalloc;
|
||||
|
||||
p = a->pool;
|
||||
|
||||
if ((u_char *) a->elts + size == p->d.last
|
||||
&& p->d.last + a->size <= p->d.end)
|
||||
{
|
||||
/*
|
||||
* the array allocation is the last in the pool
|
||||
* and there is space for new allocation
|
||||
*/
|
||||
|
||||
p->d.last += a->size;
|
||||
a->nalloc++;
|
||||
|
||||
} else {
|
||||
/* allocate a new array */
|
||||
|
||||
new = ngx_palloc(p, 2 * size);
|
||||
if (new == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ngx_memcpy(new, a->elts, size);
|
||||
a->elts = new;
|
||||
a->nalloc *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
elt = (u_char *) a->elts + a->size * a->nelts;
|
||||
a->nelts++;
|
||||
|
||||
return elt;
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
ngx_array_push_n(ngx_array_t *a, ngx_uint_t n)
|
||||
{
|
||||
void *elt, *new;
|
||||
size_t size;
|
||||
ngx_uint_t nalloc;
|
||||
ngx_pool_t *p;
|
||||
|
||||
size = n * a->size;
|
||||
|
||||
if (a->nelts + n > a->nalloc) {
|
||||
|
||||
/* the array is full */
|
||||
|
||||
p = a->pool;
|
||||
|
||||
if ((u_char *) a->elts + a->size * a->nalloc == p->d.last
|
||||
&& p->d.last + size <= p->d.end)
|
||||
{
|
||||
/*
|
||||
* the array allocation is the last in the pool
|
||||
* and there is space for new allocation
|
||||
*/
|
||||
|
||||
p->d.last += size;
|
||||
a->nalloc += n;
|
||||
|
||||
} else {
|
||||
/* allocate a new array */
|
||||
|
||||
nalloc = 2 * ((n >= a->nalloc) ? n : a->nalloc);
|
||||
|
||||
new = ngx_palloc(p, nalloc * a->size);
|
||||
if (new == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ngx_memcpy(new, a->elts, a->nelts * a->size);
|
||||
a->elts = new;
|
||||
a->nalloc = nalloc;
|
||||
}
|
||||
}
|
||||
|
||||
elt = (u_char *) a->elts + a->size * a->nelts;
|
||||
a->nelts += n;
|
||||
|
||||
return elt;
|
||||
}
|
||||
53
src/core/ngx_array.h
Normal file
53
src/core/ngx_array.h
Normal file
@@ -0,0 +1,53 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_ARRAY_H_INCLUDED_
|
||||
#define _NGX_ARRAY_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
typedef struct {
|
||||
void *elts;
|
||||
ngx_uint_t nelts;
|
||||
size_t size;
|
||||
ngx_uint_t nalloc;
|
||||
ngx_pool_t *pool;
|
||||
} ngx_array_t;
|
||||
|
||||
|
||||
ngx_array_t *ngx_array_create(ngx_pool_t *p, ngx_uint_t n, size_t size);
|
||||
void ngx_array_destroy(ngx_array_t *a);
|
||||
void *ngx_array_push(ngx_array_t *a);
|
||||
void *ngx_array_push_n(ngx_array_t *a, ngx_uint_t n);
|
||||
|
||||
|
||||
static ngx_inline ngx_int_t
|
||||
ngx_array_init(ngx_array_t *array, ngx_pool_t *pool, ngx_uint_t n, size_t size)
|
||||
{
|
||||
/*
|
||||
* set "array->nelts" before "array->elts", otherwise MSVC thinks
|
||||
* that "array->nelts" may be used without having been initialized
|
||||
*/
|
||||
|
||||
array->nelts = 0;
|
||||
array->size = size;
|
||||
array->nalloc = n;
|
||||
array->pool = pool;
|
||||
|
||||
array->elts = ngx_palloc(pool, n * size);
|
||||
if (array->elts == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
#endif /* _NGX_ARRAY_H_INCLUDED_ */
|
||||
313
src/core/ngx_buf.c
Normal file
313
src/core/ngx_buf.c
Normal file
@@ -0,0 +1,313 @@
|
||||
|
||||
/*
|
||||
* 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) {
|
||||
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 (ngx_buf_size(cl->buf) != 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (cl->buf->tag != tag) {
|
||||
*busy = cl->next;
|
||||
ngx_free_chain(p, cl);
|
||||
continue;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
170
src/core/ngx_buf.h
Normal file
170
src/core/ngx_buf.h
Normal file
@@ -0,0 +1,170 @@
|
||||
|
||||
/*
|
||||
* 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;
|
||||
#if (NGX_HAVE_AIO_SENDFILE || NGX_COMPAT)
|
||||
ssize_t (*aio_preload)(ngx_buf_t *file);
|
||||
#endif
|
||||
#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_ */
|
||||
1479
src/core/ngx_conf_file.c
Normal file
1479
src/core/ngx_conf_file.c
Normal file
File diff suppressed because it is too large
Load Diff
295
src/core/ngx_conf_file.h
Normal file
295
src/core/ngx_conf_file.h
Normal file
@@ -0,0 +1,295 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_CONF_FILE_H_INCLUDED_
|
||||
#define _NGX_CONF_FILE_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
/*
|
||||
* AAAA number of arguments
|
||||
* FF command flags
|
||||
* TT command type, i.e. HTTP "location" or "server" command
|
||||
*/
|
||||
|
||||
#define NGX_CONF_NOARGS 0x00000001
|
||||
#define NGX_CONF_TAKE1 0x00000002
|
||||
#define NGX_CONF_TAKE2 0x00000004
|
||||
#define NGX_CONF_TAKE3 0x00000008
|
||||
#define NGX_CONF_TAKE4 0x00000010
|
||||
#define NGX_CONF_TAKE5 0x00000020
|
||||
#define NGX_CONF_TAKE6 0x00000040
|
||||
#define NGX_CONF_TAKE7 0x00000080
|
||||
|
||||
#define NGX_CONF_MAX_ARGS 8
|
||||
|
||||
#define NGX_CONF_TAKE12 (NGX_CONF_TAKE1|NGX_CONF_TAKE2)
|
||||
#define NGX_CONF_TAKE13 (NGX_CONF_TAKE1|NGX_CONF_TAKE3)
|
||||
|
||||
#define NGX_CONF_TAKE23 (NGX_CONF_TAKE2|NGX_CONF_TAKE3)
|
||||
|
||||
#define NGX_CONF_TAKE123 (NGX_CONF_TAKE1|NGX_CONF_TAKE2|NGX_CONF_TAKE3)
|
||||
#define NGX_CONF_TAKE1234 (NGX_CONF_TAKE1|NGX_CONF_TAKE2|NGX_CONF_TAKE3 \
|
||||
|NGX_CONF_TAKE4)
|
||||
|
||||
#define NGX_CONF_ARGS_NUMBER 0x000000ff
|
||||
#define NGX_CONF_BLOCK 0x00000100
|
||||
#define NGX_CONF_FLAG 0x00000200
|
||||
#define NGX_CONF_ANY 0x00000400
|
||||
#define NGX_CONF_1MORE 0x00000800
|
||||
#define NGX_CONF_2MORE 0x00001000
|
||||
|
||||
#define NGX_DIRECT_CONF 0x00010000
|
||||
|
||||
#define NGX_MAIN_CONF 0x01000000
|
||||
#define NGX_ANY_CONF 0x1F000000
|
||||
|
||||
|
||||
|
||||
#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;
|
||||
char *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
src/core/ngx_config.h
Normal file
145
src/core/ngx_config.h
Normal file
@@ -0,0 +1,145 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_CONFIG_H_INCLUDED_
|
||||
#define _NGX_CONFIG_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_auto_headers.h>
|
||||
|
||||
|
||||
#if defined __DragonFly__ && !defined __FreeBSD__
|
||||
#define __FreeBSD__ 4
|
||||
#define __FreeBSD_version 480101
|
||||
#endif
|
||||
|
||||
|
||||
#if (NGX_FREEBSD)
|
||||
#include <ngx_freebsd_config.h>
|
||||
|
||||
|
||||
#elif (NGX_LINUX)
|
||||
#include <ngx_linux_config.h>
|
||||
|
||||
|
||||
#elif (NGX_SOLARIS)
|
||||
#include <ngx_solaris_config.h>
|
||||
|
||||
|
||||
#elif (NGX_DARWIN)
|
||||
#include <ngx_darwin_config.h>
|
||||
|
||||
|
||||
#elif (NGX_WIN32)
|
||||
#include <ngx_win32_config.h>
|
||||
|
||||
|
||||
#else /* POSIX */
|
||||
#include <ngx_posix_config.h>
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef NGX_HAVE_SO_SNDLOWAT
|
||||
#define NGX_HAVE_SO_SNDLOWAT 1
|
||||
#endif
|
||||
|
||||
|
||||
#if !(NGX_WIN32)
|
||||
|
||||
#define ngx_signal_helper(n) SIG##n
|
||||
#define ngx_signal_value(n) ngx_signal_helper(n)
|
||||
|
||||
#define ngx_random random
|
||||
|
||||
/* TODO: #ifndef */
|
||||
#define NGX_SHUTDOWN_SIGNAL QUIT
|
||||
#define NGX_TERMINATE_SIGNAL TERM
|
||||
#define NGX_NOACCEPT_SIGNAL WINCH
|
||||
#define NGX_RECONFIGURE_SIGNAL HUP
|
||||
|
||||
#if (NGX_LINUXTHREADS)
|
||||
#define NGX_REOPEN_SIGNAL INFO
|
||||
#define NGX_CHANGEBIN_SIGNAL XCPU
|
||||
#else
|
||||
#define NGX_REOPEN_SIGNAL USR1
|
||||
#define NGX_CHANGEBIN_SIGNAL USR2
|
||||
#endif
|
||||
|
||||
#define ngx_cdecl
|
||||
#define ngx_libc_cdecl
|
||||
|
||||
#endif
|
||||
|
||||
typedef intptr_t ngx_int_t;
|
||||
typedef uintptr_t ngx_uint_t;
|
||||
typedef intptr_t ngx_flag_t;
|
||||
|
||||
|
||||
#define NGX_INT32_LEN (sizeof("-2147483648") - 1)
|
||||
#define NGX_INT64_LEN (sizeof("-9223372036854775808") - 1)
|
||||
|
||||
#if (NGX_PTR_SIZE == 4)
|
||||
#define NGX_INT_T_LEN NGX_INT32_LEN
|
||||
#define NGX_MAX_INT_T_VALUE 2147483647
|
||||
|
||||
#else
|
||||
#define NGX_INT_T_LEN NGX_INT64_LEN
|
||||
#define NGX_MAX_INT_T_VALUE 9223372036854775807
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef NGX_ALIGNMENT
|
||||
#define NGX_ALIGNMENT sizeof(unsigned long) /* 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_ */
|
||||
1404
src/core/ngx_connection.c
Normal file
1404
src/core/ngx_connection.c
Normal file
File diff suppressed because it is too large
Load Diff
224
src/core/ngx_connection.h
Normal file
224
src/core/ngx_connection.h
Normal file
@@ -0,0 +1,224 @@
|
||||
|
||||
/*
|
||||
* 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 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;
|
||||
/* should be here because of the deferred accept */
|
||||
ngx_msec_t post_accept_timeout;
|
||||
|
||||
ngx_listening_t *previous;
|
||||
ngx_connection_t *connection;
|
||||
|
||||
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 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_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_str_t proxy_protocol_addr;
|
||||
in_port_t proxy_protocol_port;
|
||||
|
||||
#if (NGX_SSL || NGX_COMPAT)
|
||||
ngx_ssl_connection_t *ssl;
|
||||
#endif
|
||||
|
||||
struct sockaddr *local_sockaddr;
|
||||
socklen_t local_socklen;
|
||||
|
||||
ngx_buf_t *buffer;
|
||||
|
||||
ngx_queue_t queue;
|
||||
|
||||
ngx_atomic_uint_t number;
|
||||
|
||||
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 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;
|
||||
|
||||
#if (NGX_HAVE_AIO_SENDFILE || 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_conf_t *cf, 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_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_ */
|
||||
111
src/core/ngx_core.h
Normal file
111
src/core/ngx_core.h
Normal file
@@ -0,0 +1,111 @@
|
||||
|
||||
/*
|
||||
* 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_connection_s ngx_ssl_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>
|
||||
#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>
|
||||
|
||||
|
||||
#define LF (u_char) '\n'
|
||||
#define CR (u_char) '\r'
|
||||
#define CRLF "\r\n"
|
||||
|
||||
|
||||
#define ngx_abs(value) (((value) >= 0) ? (value) : - (value))
|
||||
#define ngx_max(val1, val2) ((val1 < val2) ? (val2) : (val1))
|
||||
#define ngx_min(val1, val2) ((val1 > val2) ? (val2) : (val1))
|
||||
|
||||
void ngx_cpuinfo(void);
|
||||
|
||||
#if (NGX_HAVE_OPENAT)
|
||||
#define NGX_DISABLE_SYMLINKS_OFF 0
|
||||
#define NGX_DISABLE_SYMLINKS_ON 1
|
||||
#define NGX_DISABLE_SYMLINKS_NOTOWNER 2
|
||||
#endif
|
||||
|
||||
#endif /* _NGX_CORE_H_INCLUDED_ */
|
||||
139
src/core/ngx_cpuinfo.c
Normal file
139
src/core/ngx_cpuinfo.c
Normal file
@@ -0,0 +1,139 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
#if (( __i386__ || __amd64__ ) && ( __GNUC__ || __INTEL_COMPILER ))
|
||||
|
||||
|
||||
static ngx_inline void ngx_cpuid(uint32_t i, uint32_t *buf);
|
||||
|
||||
|
||||
#if ( __i386__ )
|
||||
|
||||
static ngx_inline void
|
||||
ngx_cpuid(uint32_t i, uint32_t *buf)
|
||||
{
|
||||
|
||||
/*
|
||||
* we could not use %ebx as output parameter if gcc builds PIC,
|
||||
* and we could not save %ebx on stack, because %esp is used,
|
||||
* when the -fomit-frame-pointer optimization is specified.
|
||||
*/
|
||||
|
||||
__asm__ (
|
||||
|
||||
" mov %%ebx, %%esi; "
|
||||
|
||||
" cpuid; "
|
||||
" mov %%eax, (%1); "
|
||||
" mov %%ebx, 4(%1); "
|
||||
" mov %%edx, 8(%1); "
|
||||
" mov %%ecx, 12(%1); "
|
||||
|
||||
" mov %%esi, %%ebx; "
|
||||
|
||||
: : "a" (i), "D" (buf) : "ecx", "edx", "esi", "memory" );
|
||||
}
|
||||
|
||||
|
||||
#else /* __amd64__ */
|
||||
|
||||
|
||||
static ngx_inline void
|
||||
ngx_cpuid(uint32_t i, uint32_t *buf)
|
||||
{
|
||||
uint32_t eax, ebx, ecx, edx;
|
||||
|
||||
__asm__ (
|
||||
|
||||
"cpuid"
|
||||
|
||||
: "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (i) );
|
||||
|
||||
buf[0] = eax;
|
||||
buf[1] = ebx;
|
||||
buf[2] = edx;
|
||||
buf[3] = ecx;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* auto detect the L2 cache line size of modern and widespread CPUs */
|
||||
|
||||
void
|
||||
ngx_cpuinfo(void)
|
||||
{
|
||||
u_char *vendor;
|
||||
uint32_t vbuf[5], cpu[4], model;
|
||||
|
||||
vbuf[0] = 0;
|
||||
vbuf[1] = 0;
|
||||
vbuf[2] = 0;
|
||||
vbuf[3] = 0;
|
||||
vbuf[4] = 0;
|
||||
|
||||
ngx_cpuid(0, vbuf);
|
||||
|
||||
vendor = (u_char *) &vbuf[1];
|
||||
|
||||
if (vbuf[0] == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_cpuid(1, cpu);
|
||||
|
||||
if (ngx_strcmp(vendor, "GenuineIntel") == 0) {
|
||||
|
||||
switch ((cpu[0] & 0xf00) >> 8) {
|
||||
|
||||
/* Pentium */
|
||||
case 5:
|
||||
ngx_cacheline_size = 32;
|
||||
break;
|
||||
|
||||
/* Pentium Pro, II, III */
|
||||
case 6:
|
||||
ngx_cacheline_size = 32;
|
||||
|
||||
model = ((cpu[0] & 0xf0000) >> 8) | (cpu[0] & 0xf0);
|
||||
|
||||
if (model >= 0xd0) {
|
||||
/* Intel Core, Core 2, Atom */
|
||||
ngx_cacheline_size = 64;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
/*
|
||||
* Pentium 4, although its cache line size is 64 bytes,
|
||||
* it prefetches up to two cache lines during memory read
|
||||
*/
|
||||
case 15:
|
||||
ngx_cacheline_size = 128;
|
||||
break;
|
||||
}
|
||||
|
||||
} else if (ngx_strcmp(vendor, "AuthenticAMD") == 0) {
|
||||
ngx_cacheline_size = 64;
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
|
||||
void
|
||||
ngx_cpuinfo(void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
39
src/core/ngx_crc.h
Normal file
39
src/core/ngx_crc.h
Normal file
@@ -0,0 +1,39 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_CRC_H_INCLUDED_
|
||||
#define _NGX_CRC_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
/* 32-bit crc16 */
|
||||
|
||||
static ngx_inline uint32_t
|
||||
ngx_crc(u_char *data, size_t len)
|
||||
{
|
||||
uint32_t sum;
|
||||
|
||||
for (sum = 0; len; len--) {
|
||||
|
||||
/*
|
||||
* gcc 2.95.2 x86 and icc 7.1.006 compile
|
||||
* that operator into the single "rol" opcode,
|
||||
* msvc 6.0sp2 compiles it into four opcodes.
|
||||
*/
|
||||
sum = sum >> 1 | sum << 31;
|
||||
|
||||
sum += *data++;
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
|
||||
#endif /* _NGX_CRC_H_INCLUDED_ */
|
||||
129
src/core/ngx_crc32.c
Normal file
129
src/core/ngx_crc32.c
Normal file
@@ -0,0 +1,129 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
/*
|
||||
* The code and lookup tables are based on the algorithm
|
||||
* described at http://www.w3.org/TR/PNG/
|
||||
*
|
||||
* The 256 element lookup table takes 1024 bytes, and it may be completely
|
||||
* cached after processing about 30-60 bytes of data. So for short data
|
||||
* we use the 16 element lookup table that takes only 64 bytes and align it
|
||||
* to CPU cache line size. Of course, the small table adds code inside
|
||||
* CRC32 loop, but the cache misses overhead is bigger than overhead of
|
||||
* the additional code. For example, ngx_crc32_short() of 16 bytes of data
|
||||
* takes half as much CPU clocks than ngx_crc32_long().
|
||||
*/
|
||||
|
||||
|
||||
static uint32_t ngx_crc32_table16[] = {
|
||||
0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
|
||||
0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
|
||||
0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
|
||||
0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
|
||||
};
|
||||
|
||||
|
||||
uint32_t ngx_crc32_table256[] = {
|
||||
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
|
||||
0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
|
||||
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
|
||||
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
|
||||
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
|
||||
0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
|
||||
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
|
||||
0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
|
||||
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
|
||||
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
|
||||
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
|
||||
0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
|
||||
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
|
||||
0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
|
||||
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
|
||||
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
|
||||
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
|
||||
0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
|
||||
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
|
||||
0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
|
||||
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
|
||||
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
|
||||
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
|
||||
0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
|
||||
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
|
||||
0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
|
||||
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
|
||||
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
|
||||
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
|
||||
0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
|
||||
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
|
||||
0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
|
||||
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
|
||||
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
|
||||
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
|
||||
0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
|
||||
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
|
||||
0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
|
||||
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
|
||||
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
|
||||
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
|
||||
0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
|
||||
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
|
||||
0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
|
||||
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
|
||||
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
|
||||
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
|
||||
0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
|
||||
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
|
||||
0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
|
||||
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
|
||||
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
|
||||
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
|
||||
0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
|
||||
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
|
||||
0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
|
||||
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
|
||||
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
|
||||
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
|
||||
0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
|
||||
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
|
||||
0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
|
||||
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
|
||||
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
|
||||
};
|
||||
|
||||
|
||||
uint32_t *ngx_crc32_table_short = ngx_crc32_table16;
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_crc32_table_init(void)
|
||||
{
|
||||
void *p;
|
||||
|
||||
if (((uintptr_t) ngx_crc32_table_short
|
||||
& ~((uintptr_t) ngx_cacheline_size - 1))
|
||||
== (uintptr_t) ngx_crc32_table_short)
|
||||
{
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
p = ngx_alloc(16 * sizeof(uint32_t) + ngx_cacheline_size, ngx_cycle->log);
|
||||
if (p == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
p = ngx_align_ptr(p, ngx_cacheline_size);
|
||||
|
||||
ngx_memcpy(p, ngx_crc32_table16, 16 * sizeof(uint32_t));
|
||||
|
||||
ngx_crc32_table_short = p;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
79
src/core/ngx_crc32.h
Normal file
79
src/core/ngx_crc32.h
Normal file
@@ -0,0 +1,79 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_CRC32_H_INCLUDED_
|
||||
#define _NGX_CRC32_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
extern uint32_t *ngx_crc32_table_short;
|
||||
extern uint32_t ngx_crc32_table256[];
|
||||
|
||||
|
||||
static ngx_inline uint32_t
|
||||
ngx_crc32_short(u_char *p, size_t len)
|
||||
{
|
||||
u_char c;
|
||||
uint32_t crc;
|
||||
|
||||
crc = 0xffffffff;
|
||||
|
||||
while (len--) {
|
||||
c = *p++;
|
||||
crc = ngx_crc32_table_short[(crc ^ (c & 0xf)) & 0xf] ^ (crc >> 4);
|
||||
crc = ngx_crc32_table_short[(crc ^ (c >> 4)) & 0xf] ^ (crc >> 4);
|
||||
}
|
||||
|
||||
return crc ^ 0xffffffff;
|
||||
}
|
||||
|
||||
|
||||
static ngx_inline uint32_t
|
||||
ngx_crc32_long(u_char *p, size_t len)
|
||||
{
|
||||
uint32_t crc;
|
||||
|
||||
crc = 0xffffffff;
|
||||
|
||||
while (len--) {
|
||||
crc = ngx_crc32_table256[(crc ^ *p++) & 0xff] ^ (crc >> 8);
|
||||
}
|
||||
|
||||
return crc ^ 0xffffffff;
|
||||
}
|
||||
|
||||
|
||||
#define ngx_crc32_init(crc) \
|
||||
crc = 0xffffffff
|
||||
|
||||
|
||||
static ngx_inline void
|
||||
ngx_crc32_update(uint32_t *crc, u_char *p, size_t len)
|
||||
{
|
||||
uint32_t c;
|
||||
|
||||
c = *crc;
|
||||
|
||||
while (len--) {
|
||||
c = ngx_crc32_table256[(c ^ *p++) & 0xff] ^ (c >> 8);
|
||||
}
|
||||
|
||||
*crc = c;
|
||||
}
|
||||
|
||||
|
||||
#define ngx_crc32_final(crc) \
|
||||
crc ^= 0xffffffff
|
||||
|
||||
|
||||
ngx_int_t ngx_crc32_table_init(void);
|
||||
|
||||
|
||||
#endif /* _NGX_CRC32_H_INCLUDED_ */
|
||||
270
src/core/ngx_crypt.c
Normal file
270
src/core/ngx_crypt.c
Normal file
@@ -0,0 +1,270 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Maxim Dounin
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_crypt.h>
|
||||
#include <ngx_md5.h>
|
||||
#include <ngx_sha1.h>
|
||||
|
||||
|
||||
#if (NGX_CRYPT)
|
||||
|
||||
static ngx_int_t ngx_crypt_apr1(ngx_pool_t *pool, u_char *key, u_char *salt,
|
||||
u_char **encrypted);
|
||||
static ngx_int_t ngx_crypt_plain(ngx_pool_t *pool, u_char *key, u_char *salt,
|
||||
u_char **encrypted);
|
||||
static ngx_int_t ngx_crypt_ssha(ngx_pool_t *pool, u_char *key, u_char *salt,
|
||||
u_char **encrypted);
|
||||
static ngx_int_t ngx_crypt_sha(ngx_pool_t *pool, u_char *key, u_char *salt,
|
||||
u_char **encrypted);
|
||||
|
||||
|
||||
static u_char *ngx_crypt_to64(u_char *p, uint32_t v, size_t n);
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_crypt(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
|
||||
{
|
||||
if (ngx_strncmp(salt, "$apr1$", sizeof("$apr1$") - 1) == 0) {
|
||||
return ngx_crypt_apr1(pool, key, salt, encrypted);
|
||||
|
||||
} else if (ngx_strncmp(salt, "{PLAIN}", sizeof("{PLAIN}") - 1) == 0) {
|
||||
return ngx_crypt_plain(pool, key, salt, encrypted);
|
||||
|
||||
} else if (ngx_strncmp(salt, "{SSHA}", sizeof("{SSHA}") - 1) == 0) {
|
||||
return ngx_crypt_ssha(pool, key, salt, encrypted);
|
||||
|
||||
} else if (ngx_strncmp(salt, "{SHA}", sizeof("{SHA}") - 1) == 0) {
|
||||
return ngx_crypt_sha(pool, key, salt, encrypted);
|
||||
}
|
||||
|
||||
/* fallback to libc crypt() */
|
||||
|
||||
return ngx_libc_crypt(pool, key, salt, encrypted);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_crypt_apr1(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
|
||||
{
|
||||
ngx_int_t n;
|
||||
ngx_uint_t i;
|
||||
u_char *p, *last, final[16];
|
||||
size_t saltlen, keylen;
|
||||
ngx_md5_t md5, ctx1;
|
||||
|
||||
/* Apache's apr1 crypt is Poul-Henning Kamp's md5 crypt with $apr1$ magic */
|
||||
|
||||
keylen = ngx_strlen(key);
|
||||
|
||||
/* true salt: no magic, max 8 chars, stop at first $ */
|
||||
|
||||
salt += sizeof("$apr1$") - 1;
|
||||
last = salt + 8;
|
||||
for (p = salt; *p && *p != '$' && p < last; p++) { /* void */ }
|
||||
saltlen = p - salt;
|
||||
|
||||
/* hash key and salt */
|
||||
|
||||
ngx_md5_init(&md5);
|
||||
ngx_md5_update(&md5, key, keylen);
|
||||
ngx_md5_update(&md5, (u_char *) "$apr1$", sizeof("$apr1$") - 1);
|
||||
ngx_md5_update(&md5, salt, saltlen);
|
||||
|
||||
ngx_md5_init(&ctx1);
|
||||
ngx_md5_update(&ctx1, key, keylen);
|
||||
ngx_md5_update(&ctx1, salt, saltlen);
|
||||
ngx_md5_update(&ctx1, key, keylen);
|
||||
ngx_md5_final(final, &ctx1);
|
||||
|
||||
for (n = keylen; n > 0; n -= 16) {
|
||||
ngx_md5_update(&md5, final, n > 16 ? 16 : n);
|
||||
}
|
||||
|
||||
ngx_memzero(final, sizeof(final));
|
||||
|
||||
for (i = keylen; i; i >>= 1) {
|
||||
if (i & 1) {
|
||||
ngx_md5_update(&md5, final, 1);
|
||||
|
||||
} else {
|
||||
ngx_md5_update(&md5, key, 1);
|
||||
}
|
||||
}
|
||||
|
||||
ngx_md5_final(final, &md5);
|
||||
|
||||
for (i = 0; i < 1000; i++) {
|
||||
ngx_md5_init(&ctx1);
|
||||
|
||||
if (i & 1) {
|
||||
ngx_md5_update(&ctx1, key, keylen);
|
||||
|
||||
} else {
|
||||
ngx_md5_update(&ctx1, final, 16);
|
||||
}
|
||||
|
||||
if (i % 3) {
|
||||
ngx_md5_update(&ctx1, salt, saltlen);
|
||||
}
|
||||
|
||||
if (i % 7) {
|
||||
ngx_md5_update(&ctx1, key, keylen);
|
||||
}
|
||||
|
||||
if (i & 1) {
|
||||
ngx_md5_update(&ctx1, final, 16);
|
||||
|
||||
} else {
|
||||
ngx_md5_update(&ctx1, key, keylen);
|
||||
}
|
||||
|
||||
ngx_md5_final(final, &ctx1);
|
||||
}
|
||||
|
||||
/* output */
|
||||
|
||||
*encrypted = ngx_pnalloc(pool, sizeof("$apr1$") - 1 + saltlen + 1 + 22 + 1);
|
||||
if (*encrypted == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
p = ngx_cpymem(*encrypted, "$apr1$", sizeof("$apr1$") - 1);
|
||||
p = ngx_copy(p, salt, saltlen);
|
||||
*p++ = '$';
|
||||
|
||||
p = ngx_crypt_to64(p, (final[ 0]<<16) | (final[ 6]<<8) | final[12], 4);
|
||||
p = ngx_crypt_to64(p, (final[ 1]<<16) | (final[ 7]<<8) | final[13], 4);
|
||||
p = ngx_crypt_to64(p, (final[ 2]<<16) | (final[ 8]<<8) | final[14], 4);
|
||||
p = ngx_crypt_to64(p, (final[ 3]<<16) | (final[ 9]<<8) | final[15], 4);
|
||||
p = ngx_crypt_to64(p, (final[ 4]<<16) | (final[10]<<8) | final[ 5], 4);
|
||||
p = ngx_crypt_to64(p, final[11], 2);
|
||||
*p = '\0';
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static u_char *
|
||||
ngx_crypt_to64(u_char *p, uint32_t v, size_t n)
|
||||
{
|
||||
static u_char itoa64[] =
|
||||
"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
while (n--) {
|
||||
*p++ = itoa64[v & 0x3f];
|
||||
v >>= 6;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_crypt_plain(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
|
||||
{
|
||||
size_t len;
|
||||
u_char *p;
|
||||
|
||||
len = ngx_strlen(key);
|
||||
|
||||
*encrypted = ngx_pnalloc(pool, sizeof("{PLAIN}") - 1 + len + 1);
|
||||
if (*encrypted == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
p = ngx_cpymem(*encrypted, "{PLAIN}", sizeof("{PLAIN}") - 1);
|
||||
ngx_memcpy(p, key, len + 1);
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_crypt_ssha(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
|
||||
{
|
||||
size_t len;
|
||||
ngx_int_t rc;
|
||||
ngx_str_t encoded, decoded;
|
||||
ngx_sha1_t sha1;
|
||||
|
||||
/* "{SSHA}" base64(SHA1(key salt) salt) */
|
||||
|
||||
/* decode base64 salt to find out true salt */
|
||||
|
||||
encoded.data = salt + sizeof("{SSHA}") - 1;
|
||||
encoded.len = ngx_strlen(encoded.data);
|
||||
|
||||
len = ngx_max(ngx_base64_decoded_length(encoded.len), 20);
|
||||
|
||||
decoded.data = ngx_pnalloc(pool, len);
|
||||
if (decoded.data == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
rc = ngx_decode_base64(&decoded, &encoded);
|
||||
|
||||
if (rc != NGX_OK || decoded.len < 20) {
|
||||
decoded.len = 20;
|
||||
}
|
||||
|
||||
/* update SHA1 from key and salt */
|
||||
|
||||
ngx_sha1_init(&sha1);
|
||||
ngx_sha1_update(&sha1, key, ngx_strlen(key));
|
||||
ngx_sha1_update(&sha1, decoded.data + 20, decoded.len - 20);
|
||||
ngx_sha1_final(decoded.data, &sha1);
|
||||
|
||||
/* encode it back to base64 */
|
||||
|
||||
len = sizeof("{SSHA}") - 1 + ngx_base64_encoded_length(decoded.len) + 1;
|
||||
|
||||
*encrypted = ngx_pnalloc(pool, len);
|
||||
if (*encrypted == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
encoded.data = ngx_cpymem(*encrypted, "{SSHA}", sizeof("{SSHA}") - 1);
|
||||
ngx_encode_base64(&encoded, &decoded);
|
||||
encoded.data[encoded.len] = '\0';
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_crypt_sha(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
|
||||
{
|
||||
size_t len;
|
||||
ngx_str_t encoded, decoded;
|
||||
ngx_sha1_t sha1;
|
||||
u_char digest[20];
|
||||
|
||||
/* "{SHA}" base64(SHA1(key)) */
|
||||
|
||||
decoded.len = sizeof(digest);
|
||||
decoded.data = digest;
|
||||
|
||||
ngx_sha1_init(&sha1);
|
||||
ngx_sha1_update(&sha1, key, ngx_strlen(key));
|
||||
ngx_sha1_final(digest, &sha1);
|
||||
|
||||
len = sizeof("{SHA}") - 1 + ngx_base64_encoded_length(decoded.len) + 1;
|
||||
|
||||
*encrypted = ngx_pnalloc(pool, len);
|
||||
if (*encrypted == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
encoded.data = ngx_cpymem(*encrypted, "{SHA}", sizeof("{SHA}") - 1);
|
||||
ngx_encode_base64(&encoded, &decoded);
|
||||
encoded.data[encoded.len] = '\0';
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
#endif /* NGX_CRYPT */
|
||||
20
src/core/ngx_crypt.h
Normal file
20
src/core/ngx_crypt.h
Normal file
@@ -0,0 +1,20 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_CRYPT_H_INCLUDED_
|
||||
#define _NGX_CRYPT_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
ngx_int_t ngx_crypt(ngx_pool_t *pool, u_char *key, u_char *salt,
|
||||
u_char **encrypted);
|
||||
|
||||
|
||||
#endif /* _NGX_CRYPT_H_INCLUDED_ */
|
||||
1335
src/core/ngx_cycle.c
Normal file
1335
src/core/ngx_cycle.c
Normal file
File diff suppressed because it is too large
Load Diff
142
src/core/ngx_cycle.h
Normal file
142
src/core/ngx_cycle.h
Normal file
@@ -0,0 +1,142 @@
|
||||
|
||||
/*
|
||||
* 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;
|
||||
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;
|
||||
|
||||
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 lock_file;
|
||||
ngx_str_t hostname;
|
||||
};
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_flag_t daemon;
|
||||
ngx_flag_t master;
|
||||
|
||||
ngx_msec_t timer_resolution;
|
||||
|
||||
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_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);
|
||||
|
||||
|
||||
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_ */
|
||||
1127
src/core/ngx_file.c
Normal file
1127
src/core/ngx_file.c
Normal file
File diff suppressed because it is too large
Load Diff
164
src/core/ngx_file.h
Normal file
164
src/core/ngx_file.h
Normal file
@@ -0,0 +1,164 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_FILE_H_INCLUDED_
|
||||
#define _NGX_FILE_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
struct ngx_file_s {
|
||||
ngx_fd_t fd;
|
||||
ngx_str_t name;
|
||||
ngx_file_info_t info;
|
||||
|
||||
off_t offset;
|
||||
off_t sys_offset;
|
||||
|
||||
ngx_log_t *log;
|
||||
|
||||
#if (NGX_THREADS || NGX_COMPAT)
|
||||
ngx_int_t (*thread_handler)(ngx_thread_task_t *task,
|
||||
ngx_file_t *file);
|
||||
void *thread_ctx;
|
||||
ngx_thread_task_t *thread_task;
|
||||
#endif
|
||||
|
||||
#if (NGX_HAVE_FILE_AIO || NGX_COMPAT)
|
||||
ngx_event_aio_t *aio;
|
||||
#endif
|
||||
|
||||
unsigned valid_info:1;
|
||||
unsigned directio:1;
|
||||
};
|
||||
|
||||
|
||||
#define NGX_MAX_PATH_LEVEL 3
|
||||
|
||||
|
||||
typedef ngx_msec_t (*ngx_path_manager_pt) (void *data);
|
||||
typedef ngx_msec_t (*ngx_path_purger_pt) (void *data);
|
||||
typedef void (*ngx_path_loader_pt) (void *data);
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_str_t name;
|
||||
size_t len;
|
||||
size_t level[NGX_MAX_PATH_LEVEL];
|
||||
|
||||
ngx_path_manager_pt manager;
|
||||
ngx_path_purger_pt purger;
|
||||
ngx_path_loader_pt loader;
|
||||
void *data;
|
||||
|
||||
u_char *conf_file;
|
||||
ngx_uint_t line;
|
||||
} ngx_path_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_str_t name;
|
||||
size_t level[NGX_MAX_PATH_LEVEL];
|
||||
} ngx_path_init_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_file_t file;
|
||||
off_t offset;
|
||||
ngx_path_t *path;
|
||||
ngx_pool_t *pool;
|
||||
char *warn;
|
||||
|
||||
ngx_uint_t access;
|
||||
|
||||
unsigned log_level:8;
|
||||
unsigned persistent:1;
|
||||
unsigned clean:1;
|
||||
unsigned thread_write:1;
|
||||
} ngx_temp_file_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_uint_t access;
|
||||
ngx_uint_t path_access;
|
||||
time_t time;
|
||||
ngx_fd_t fd;
|
||||
|
||||
unsigned create_path:1;
|
||||
unsigned delete_file:1;
|
||||
|
||||
ngx_log_t *log;
|
||||
} ngx_ext_rename_file_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
off_t size;
|
||||
size_t buf_size;
|
||||
|
||||
ngx_uint_t access;
|
||||
time_t time;
|
||||
|
||||
ngx_log_t *log;
|
||||
} ngx_copy_file_t;
|
||||
|
||||
|
||||
typedef struct ngx_tree_ctx_s ngx_tree_ctx_t;
|
||||
|
||||
typedef ngx_int_t (*ngx_tree_init_handler_pt) (void *ctx, void *prev);
|
||||
typedef ngx_int_t (*ngx_tree_handler_pt) (ngx_tree_ctx_t *ctx, ngx_str_t *name);
|
||||
|
||||
struct ngx_tree_ctx_s {
|
||||
off_t size;
|
||||
off_t fs_size;
|
||||
ngx_uint_t access;
|
||||
time_t mtime;
|
||||
|
||||
ngx_tree_init_handler_pt init_handler;
|
||||
ngx_tree_handler_pt file_handler;
|
||||
ngx_tree_handler_pt pre_tree_handler;
|
||||
ngx_tree_handler_pt post_tree_handler;
|
||||
ngx_tree_handler_pt spec_handler;
|
||||
|
||||
void *data;
|
||||
size_t alloc;
|
||||
|
||||
ngx_log_t *log;
|
||||
};
|
||||
|
||||
|
||||
ngx_int_t ngx_get_full_name(ngx_pool_t *pool, ngx_str_t *prefix,
|
||||
ngx_str_t *name);
|
||||
|
||||
ssize_t ngx_write_chain_to_temp_file(ngx_temp_file_t *tf, ngx_chain_t *chain);
|
||||
ngx_int_t ngx_create_temp_file(ngx_file_t *file, ngx_path_t *path,
|
||||
ngx_pool_t *pool, ngx_uint_t persistent, ngx_uint_t clean,
|
||||
ngx_uint_t access);
|
||||
void ngx_create_hashed_filename(ngx_path_t *path, u_char *file, size_t len);
|
||||
ngx_int_t ngx_create_path(ngx_file_t *file, ngx_path_t *path);
|
||||
ngx_err_t ngx_create_full_path(u_char *dir, ngx_uint_t access);
|
||||
ngx_int_t ngx_add_path(ngx_conf_t *cf, ngx_path_t **slot);
|
||||
ngx_int_t ngx_create_paths(ngx_cycle_t *cycle, ngx_uid_t user);
|
||||
ngx_int_t ngx_ext_rename_file(ngx_str_t *src, ngx_str_t *to,
|
||||
ngx_ext_rename_file_t *ext);
|
||||
ngx_int_t ngx_copy_file(u_char *from, u_char *to, ngx_copy_file_t *cf);
|
||||
ngx_int_t ngx_walk_tree(ngx_tree_ctx_t *ctx, ngx_str_t *tree);
|
||||
|
||||
ngx_atomic_uint_t ngx_next_temp_number(ngx_uint_t collision);
|
||||
|
||||
char *ngx_conf_set_path_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
|
||||
char *ngx_conf_merge_path_value(ngx_conf_t *cf, ngx_path_t **path,
|
||||
ngx_path_t *prev, ngx_path_init_t *init);
|
||||
char *ngx_conf_set_access_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
|
||||
|
||||
|
||||
extern ngx_atomic_t *ngx_temp_number;
|
||||
extern ngx_atomic_int_t ngx_random_number;
|
||||
|
||||
|
||||
#endif /* _NGX_FILE_H_INCLUDED_ */
|
||||
988
src/core/ngx_hash.c
Normal file
988
src/core/ngx_hash.c
Normal file
@@ -0,0 +1,988 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
void *
|
||||
ngx_hash_find(ngx_hash_t *hash, ngx_uint_t key, u_char *name, size_t len)
|
||||
{
|
||||
ngx_uint_t i;
|
||||
ngx_hash_elt_t *elt;
|
||||
|
||||
#if 0
|
||||
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "hf:\"%*s\"", len, name);
|
||||
#endif
|
||||
|
||||
elt = hash->buckets[key % hash->size];
|
||||
|
||||
if (elt == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (elt->value) {
|
||||
if (len != (size_t) elt->len) {
|
||||
goto next;
|
||||
}
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (name[i] != elt->name[i]) {
|
||||
goto next;
|
||||
}
|
||||
}
|
||||
|
||||
return elt->value;
|
||||
|
||||
next:
|
||||
|
||||
elt = (ngx_hash_elt_t *) ngx_align_ptr(&elt->name[0] + elt->len,
|
||||
sizeof(void *));
|
||||
continue;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
ngx_hash_find_wc_head(ngx_hash_wildcard_t *hwc, u_char *name, size_t len)
|
||||
{
|
||||
void *value;
|
||||
ngx_uint_t i, n, key;
|
||||
|
||||
#if 0
|
||||
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "wch:\"%*s\"", len, name);
|
||||
#endif
|
||||
|
||||
n = len;
|
||||
|
||||
while (n) {
|
||||
if (name[n - 1] == '.') {
|
||||
break;
|
||||
}
|
||||
|
||||
n--;
|
||||
}
|
||||
|
||||
key = 0;
|
||||
|
||||
for (i = n; i < len; i++) {
|
||||
key = ngx_hash(key, name[i]);
|
||||
}
|
||||
|
||||
#if 0
|
||||
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "key:\"%ui\"", key);
|
||||
#endif
|
||||
|
||||
value = ngx_hash_find(&hwc->hash, key, &name[n], len - n);
|
||||
|
||||
#if 0
|
||||
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "value:\"%p\"", value);
|
||||
#endif
|
||||
|
||||
if (value) {
|
||||
|
||||
/*
|
||||
* the 2 low bits of value have the special meaning:
|
||||
* 00 - value is data pointer for both "example.com"
|
||||
* and "*.example.com";
|
||||
* 01 - value is data pointer for "*.example.com" only;
|
||||
* 10 - value is pointer to wildcard hash allowing
|
||||
* both "example.com" and "*.example.com";
|
||||
* 11 - value is pointer to wildcard hash allowing
|
||||
* "*.example.com" only.
|
||||
*/
|
||||
|
||||
if ((uintptr_t) value & 2) {
|
||||
|
||||
if (n == 0) {
|
||||
|
||||
/* "example.com" */
|
||||
|
||||
if ((uintptr_t) value & 1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hwc = (ngx_hash_wildcard_t *)
|
||||
((uintptr_t) value & (uintptr_t) ~3);
|
||||
return hwc->value;
|
||||
}
|
||||
|
||||
hwc = (ngx_hash_wildcard_t *) ((uintptr_t) value & (uintptr_t) ~3);
|
||||
|
||||
value = ngx_hash_find_wc_head(hwc, name, n - 1);
|
||||
|
||||
if (value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return hwc->value;
|
||||
}
|
||||
|
||||
if ((uintptr_t) value & 1) {
|
||||
|
||||
if (n == 0) {
|
||||
|
||||
/* "example.com" */
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (void *) ((uintptr_t) value & (uintptr_t) ~3);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
return hwc->value;
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
ngx_hash_find_wc_tail(ngx_hash_wildcard_t *hwc, u_char *name, size_t len)
|
||||
{
|
||||
void *value;
|
||||
ngx_uint_t i, key;
|
||||
|
||||
#if 0
|
||||
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "wct:\"%*s\"", len, name);
|
||||
#endif
|
||||
|
||||
key = 0;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (name[i] == '.') {
|
||||
break;
|
||||
}
|
||||
|
||||
key = ngx_hash(key, name[i]);
|
||||
}
|
||||
|
||||
if (i == len) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if 0
|
||||
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "key:\"%ui\"", key);
|
||||
#endif
|
||||
|
||||
value = ngx_hash_find(&hwc->hash, key, name, i);
|
||||
|
||||
#if 0
|
||||
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "value:\"%p\"", value);
|
||||
#endif
|
||||
|
||||
if (value) {
|
||||
|
||||
/*
|
||||
* the 2 low bits of value have the special meaning:
|
||||
* 00 - value is data pointer;
|
||||
* 11 - value is pointer to wildcard hash allowing "example.*".
|
||||
*/
|
||||
|
||||
if ((uintptr_t) value & 2) {
|
||||
|
||||
i++;
|
||||
|
||||
hwc = (ngx_hash_wildcard_t *) ((uintptr_t) value & (uintptr_t) ~3);
|
||||
|
||||
value = ngx_hash_find_wc_tail(hwc, &name[i], len - i);
|
||||
|
||||
if (value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return hwc->value;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
return hwc->value;
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
ngx_hash_find_combined(ngx_hash_combined_t *hash, ngx_uint_t key, u_char *name,
|
||||
size_t len)
|
||||
{
|
||||
void *value;
|
||||
|
||||
if (hash->hash.buckets) {
|
||||
value = ngx_hash_find(&hash->hash, key, name, len);
|
||||
|
||||
if (value) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
if (len == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (hash->wc_head && hash->wc_head->hash.buckets) {
|
||||
value = ngx_hash_find_wc_head(hash->wc_head, name, len);
|
||||
|
||||
if (value) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
if (hash->wc_tail && hash->wc_tail->hash.buckets) {
|
||||
value = ngx_hash_find_wc_tail(hash->wc_tail, name, len);
|
||||
|
||||
if (value) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
#define NGX_HASH_ELT_SIZE(name) \
|
||||
(sizeof(void *) + ngx_align((name)->key.len + 2, sizeof(void *)))
|
||||
|
||||
ngx_int_t
|
||||
ngx_hash_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names, ngx_uint_t nelts)
|
||||
{
|
||||
u_char *elts;
|
||||
size_t len;
|
||||
u_short *test;
|
||||
ngx_uint_t i, n, key, size, start, bucket_size;
|
||||
ngx_hash_elt_t *elt, **buckets;
|
||||
|
||||
if (hinit->max_size == 0) {
|
||||
ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0,
|
||||
"could not build %s, you should "
|
||||
"increase %s_max_size: %i",
|
||||
hinit->name, hinit->name, hinit->max_size);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
for (n = 0; n < nelts; n++) {
|
||||
if (hinit->bucket_size < NGX_HASH_ELT_SIZE(&names[n]) + sizeof(void *))
|
||||
{
|
||||
ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0,
|
||||
"could not build %s, you should "
|
||||
"increase %s_bucket_size: %i",
|
||||
hinit->name, hinit->name, hinit->bucket_size);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
test = ngx_alloc(hinit->max_size * sizeof(u_short), hinit->pool->log);
|
||||
if (test == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
bucket_size = hinit->bucket_size - sizeof(void *);
|
||||
|
||||
start = nelts / (bucket_size / (2 * sizeof(void *)));
|
||||
start = start ? start : 1;
|
||||
|
||||
if (hinit->max_size > 10000 && nelts && hinit->max_size / nelts < 100) {
|
||||
start = hinit->max_size - 1000;
|
||||
}
|
||||
|
||||
for (size = start; size <= hinit->max_size; size++) {
|
||||
|
||||
ngx_memzero(test, size * sizeof(u_short));
|
||||
|
||||
for (n = 0; n < nelts; n++) {
|
||||
if (names[n].key.data == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
key = names[n].key_hash % size;
|
||||
test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n]));
|
||||
|
||||
#if 0
|
||||
ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
|
||||
"%ui: %ui %ui \"%V\"",
|
||||
size, key, test[key], &names[n].key);
|
||||
#endif
|
||||
|
||||
if (test[key] > (u_short) bucket_size) {
|
||||
goto next;
|
||||
}
|
||||
}
|
||||
|
||||
goto found;
|
||||
|
||||
next:
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
size = hinit->max_size;
|
||||
|
||||
ngx_log_error(NGX_LOG_WARN, hinit->pool->log, 0,
|
||||
"could not build optimal %s, you should increase "
|
||||
"either %s_max_size: %i or %s_bucket_size: %i; "
|
||||
"ignoring %s_bucket_size",
|
||||
hinit->name, hinit->name, hinit->max_size,
|
||||
hinit->name, hinit->bucket_size, hinit->name);
|
||||
|
||||
found:
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
test[i] = sizeof(void *);
|
||||
}
|
||||
|
||||
for (n = 0; n < nelts; n++) {
|
||||
if (names[n].key.data == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
key = names[n].key_hash % size;
|
||||
test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n]));
|
||||
}
|
||||
|
||||
len = 0;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
if (test[i] == sizeof(void *)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
test[i] = (u_short) (ngx_align(test[i], ngx_cacheline_size));
|
||||
|
||||
len += test[i];
|
||||
}
|
||||
|
||||
if (hinit->hash == NULL) {
|
||||
hinit->hash = ngx_pcalloc(hinit->pool, sizeof(ngx_hash_wildcard_t)
|
||||
+ size * sizeof(ngx_hash_elt_t *));
|
||||
if (hinit->hash == NULL) {
|
||||
ngx_free(test);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
buckets = (ngx_hash_elt_t **)
|
||||
((u_char *) hinit->hash + sizeof(ngx_hash_wildcard_t));
|
||||
|
||||
} else {
|
||||
buckets = ngx_pcalloc(hinit->pool, size * sizeof(ngx_hash_elt_t *));
|
||||
if (buckets == NULL) {
|
||||
ngx_free(test);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
elts = ngx_palloc(hinit->pool, len + ngx_cacheline_size);
|
||||
if (elts == NULL) {
|
||||
ngx_free(test);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
elts = ngx_align_ptr(elts, ngx_cacheline_size);
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
if (test[i] == sizeof(void *)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
buckets[i] = (ngx_hash_elt_t *) elts;
|
||||
elts += test[i];
|
||||
}
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
test[i] = 0;
|
||||
}
|
||||
|
||||
for (n = 0; n < nelts; n++) {
|
||||
if (names[n].key.data == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
key = names[n].key_hash % size;
|
||||
elt = (ngx_hash_elt_t *) ((u_char *) buckets[key] + test[key]);
|
||||
|
||||
elt->value = names[n].value;
|
||||
elt->len = (u_short) names[n].key.len;
|
||||
|
||||
ngx_strlow(elt->name, names[n].key.data, names[n].key.len);
|
||||
|
||||
test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n]));
|
||||
}
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
if (buckets[i] == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
elt = (ngx_hash_elt_t *) ((u_char *) buckets[i] + test[i]);
|
||||
|
||||
elt->value = NULL;
|
||||
}
|
||||
|
||||
ngx_free(test);
|
||||
|
||||
hinit->hash->buckets = buckets;
|
||||
hinit->hash->size = size;
|
||||
|
||||
#if 0
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
ngx_str_t val;
|
||||
ngx_uint_t key;
|
||||
|
||||
elt = buckets[i];
|
||||
|
||||
if (elt == NULL) {
|
||||
ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
|
||||
"%ui: NULL", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
while (elt->value) {
|
||||
val.len = elt->len;
|
||||
val.data = &elt->name[0];
|
||||
|
||||
key = hinit->key(val.data, val.len);
|
||||
|
||||
ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
|
||||
"%ui: %p \"%V\" %ui", i, elt, &val, key);
|
||||
|
||||
elt = (ngx_hash_elt_t *) ngx_align_ptr(&elt->name[0] + elt->len,
|
||||
sizeof(void *));
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_hash_wildcard_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names,
|
||||
ngx_uint_t nelts)
|
||||
{
|
||||
size_t len, dot_len;
|
||||
ngx_uint_t i, n, dot;
|
||||
ngx_array_t curr_names, next_names;
|
||||
ngx_hash_key_t *name, *next_name;
|
||||
ngx_hash_init_t h;
|
||||
ngx_hash_wildcard_t *wdc;
|
||||
|
||||
if (ngx_array_init(&curr_names, hinit->temp_pool, nelts,
|
||||
sizeof(ngx_hash_key_t))
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (ngx_array_init(&next_names, hinit->temp_pool, nelts,
|
||||
sizeof(ngx_hash_key_t))
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
for (n = 0; n < nelts; n = i) {
|
||||
|
||||
#if 0
|
||||
ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
|
||||
"wc0: \"%V\"", &names[n].key);
|
||||
#endif
|
||||
|
||||
dot = 0;
|
||||
|
||||
for (len = 0; len < names[n].key.len; len++) {
|
||||
if (names[n].key.data[len] == '.') {
|
||||
dot = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
name = ngx_array_push(&curr_names);
|
||||
if (name == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
name->key.len = len;
|
||||
name->key.data = names[n].key.data;
|
||||
name->key_hash = hinit->key(name->key.data, name->key.len);
|
||||
name->value = names[n].value;
|
||||
|
||||
#if 0
|
||||
ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
|
||||
"wc1: \"%V\" %ui", &name->key, dot);
|
||||
#endif
|
||||
|
||||
dot_len = len + 1;
|
||||
|
||||
if (dot) {
|
||||
len++;
|
||||
}
|
||||
|
||||
next_names.nelts = 0;
|
||||
|
||||
if (names[n].key.len != len) {
|
||||
next_name = ngx_array_push(&next_names);
|
||||
if (next_name == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
next_name->key.len = names[n].key.len - len;
|
||||
next_name->key.data = names[n].key.data + len;
|
||||
next_name->key_hash = 0;
|
||||
next_name->value = names[n].value;
|
||||
|
||||
#if 0
|
||||
ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
|
||||
"wc2: \"%V\"", &next_name->key);
|
||||
#endif
|
||||
}
|
||||
|
||||
for (i = n + 1; i < nelts; i++) {
|
||||
if (ngx_strncmp(names[n].key.data, names[i].key.data, len) != 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!dot
|
||||
&& names[i].key.len > len
|
||||
&& names[i].key.data[len] != '.')
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
next_name = ngx_array_push(&next_names);
|
||||
if (next_name == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
next_name->key.len = names[i].key.len - dot_len;
|
||||
next_name->key.data = names[i].key.data + dot_len;
|
||||
next_name->key_hash = 0;
|
||||
next_name->value = names[i].value;
|
||||
|
||||
#if 0
|
||||
ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
|
||||
"wc3: \"%V\"", &next_name->key);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (next_names.nelts) {
|
||||
|
||||
h = *hinit;
|
||||
h.hash = NULL;
|
||||
|
||||
if (ngx_hash_wildcard_init(&h, (ngx_hash_key_t *) next_names.elts,
|
||||
next_names.nelts)
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
wdc = (ngx_hash_wildcard_t *) h.hash;
|
||||
|
||||
if (names[n].key.len == len) {
|
||||
wdc->value = names[n].value;
|
||||
}
|
||||
|
||||
name->value = (void *) ((uintptr_t) wdc | (dot ? 3 : 2));
|
||||
|
||||
} else if (dot) {
|
||||
name->value = (void *) ((uintptr_t) name->value | 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (ngx_hash_init(hinit, (ngx_hash_key_t *) curr_names.elts,
|
||||
curr_names.nelts)
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
ngx_uint_t
|
||||
ngx_hash_key(u_char *data, size_t len)
|
||||
{
|
||||
ngx_uint_t i, key;
|
||||
|
||||
key = 0;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
key = ngx_hash(key, data[i]);
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
|
||||
ngx_uint_t
|
||||
ngx_hash_key_lc(u_char *data, size_t len)
|
||||
{
|
||||
ngx_uint_t i, key;
|
||||
|
||||
key = 0;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
key = ngx_hash(key, ngx_tolower(data[i]));
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
|
||||
ngx_uint_t
|
||||
ngx_hash_strlow(u_char *dst, u_char *src, size_t n)
|
||||
{
|
||||
ngx_uint_t key;
|
||||
|
||||
key = 0;
|
||||
|
||||
while (n--) {
|
||||
*dst = ngx_tolower(*src);
|
||||
key = ngx_hash(key, *dst);
|
||||
dst++;
|
||||
src++;
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_hash_keys_array_init(ngx_hash_keys_arrays_t *ha, ngx_uint_t type)
|
||||
{
|
||||
ngx_uint_t asize;
|
||||
|
||||
if (type == NGX_HASH_SMALL) {
|
||||
asize = 4;
|
||||
ha->hsize = 107;
|
||||
|
||||
} else {
|
||||
asize = NGX_HASH_LARGE_ASIZE;
|
||||
ha->hsize = NGX_HASH_LARGE_HSIZE;
|
||||
}
|
||||
|
||||
if (ngx_array_init(&ha->keys, ha->temp_pool, asize, sizeof(ngx_hash_key_t))
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (ngx_array_init(&ha->dns_wc_head, ha->temp_pool, asize,
|
||||
sizeof(ngx_hash_key_t))
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (ngx_array_init(&ha->dns_wc_tail, ha->temp_pool, asize,
|
||||
sizeof(ngx_hash_key_t))
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ha->keys_hash = ngx_pcalloc(ha->temp_pool, sizeof(ngx_array_t) * ha->hsize);
|
||||
if (ha->keys_hash == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ha->dns_wc_head_hash = ngx_pcalloc(ha->temp_pool,
|
||||
sizeof(ngx_array_t) * ha->hsize);
|
||||
if (ha->dns_wc_head_hash == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ha->dns_wc_tail_hash = ngx_pcalloc(ha->temp_pool,
|
||||
sizeof(ngx_array_t) * ha->hsize);
|
||||
if (ha->dns_wc_tail_hash == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_hash_add_key(ngx_hash_keys_arrays_t *ha, ngx_str_t *key, void *value,
|
||||
ngx_uint_t flags)
|
||||
{
|
||||
size_t len;
|
||||
u_char *p;
|
||||
ngx_str_t *name;
|
||||
ngx_uint_t i, k, n, skip, last;
|
||||
ngx_array_t *keys, *hwc;
|
||||
ngx_hash_key_t *hk;
|
||||
|
||||
last = key->len;
|
||||
|
||||
if (flags & NGX_HASH_WILDCARD_KEY) {
|
||||
|
||||
/*
|
||||
* supported wildcards:
|
||||
* "*.example.com", ".example.com", and "www.example.*"
|
||||
*/
|
||||
|
||||
n = 0;
|
||||
|
||||
for (i = 0; i < key->len; i++) {
|
||||
|
||||
if (key->data[i] == '*') {
|
||||
if (++n > 1) {
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
}
|
||||
|
||||
if (key->data[i] == '.' && key->data[i + 1] == '.') {
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
if (key->data[i] == '\0') {
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
}
|
||||
|
||||
if (key->len > 1 && key->data[0] == '.') {
|
||||
skip = 1;
|
||||
goto wildcard;
|
||||
}
|
||||
|
||||
if (key->len > 2) {
|
||||
|
||||
if (key->data[0] == '*' && key->data[1] == '.') {
|
||||
skip = 2;
|
||||
goto wildcard;
|
||||
}
|
||||
|
||||
if (key->data[i - 2] == '.' && key->data[i - 1] == '*') {
|
||||
skip = 0;
|
||||
last -= 2;
|
||||
goto wildcard;
|
||||
}
|
||||
}
|
||||
|
||||
if (n) {
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
}
|
||||
|
||||
/* exact hash */
|
||||
|
||||
k = 0;
|
||||
|
||||
for (i = 0; i < last; i++) {
|
||||
if (!(flags & NGX_HASH_READONLY_KEY)) {
|
||||
key->data[i] = ngx_tolower(key->data[i]);
|
||||
}
|
||||
k = ngx_hash(k, key->data[i]);
|
||||
}
|
||||
|
||||
k %= ha->hsize;
|
||||
|
||||
/* check conflicts in exact hash */
|
||||
|
||||
name = ha->keys_hash[k].elts;
|
||||
|
||||
if (name) {
|
||||
for (i = 0; i < ha->keys_hash[k].nelts; i++) {
|
||||
if (last != name[i].len) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ngx_strncmp(key->data, name[i].data, last) == 0) {
|
||||
return NGX_BUSY;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
if (ngx_array_init(&ha->keys_hash[k], ha->temp_pool, 4,
|
||||
sizeof(ngx_str_t))
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
name = ngx_array_push(&ha->keys_hash[k]);
|
||||
if (name == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
*name = *key;
|
||||
|
||||
hk = ngx_array_push(&ha->keys);
|
||||
if (hk == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
hk->key = *key;
|
||||
hk->key_hash = ngx_hash_key(key->data, last);
|
||||
hk->value = value;
|
||||
|
||||
return NGX_OK;
|
||||
|
||||
|
||||
wildcard:
|
||||
|
||||
/* wildcard hash */
|
||||
|
||||
k = ngx_hash_strlow(&key->data[skip], &key->data[skip], last - skip);
|
||||
|
||||
k %= ha->hsize;
|
||||
|
||||
if (skip == 1) {
|
||||
|
||||
/* check conflicts in exact hash for ".example.com" */
|
||||
|
||||
name = ha->keys_hash[k].elts;
|
||||
|
||||
if (name) {
|
||||
len = last - skip;
|
||||
|
||||
for (i = 0; i < ha->keys_hash[k].nelts; i++) {
|
||||
if (len != name[i].len) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ngx_strncmp(&key->data[1], name[i].data, len) == 0) {
|
||||
return NGX_BUSY;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
if (ngx_array_init(&ha->keys_hash[k], ha->temp_pool, 4,
|
||||
sizeof(ngx_str_t))
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
name = ngx_array_push(&ha->keys_hash[k]);
|
||||
if (name == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
name->len = last - 1;
|
||||
name->data = ngx_pnalloc(ha->temp_pool, name->len);
|
||||
if (name->data == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_memcpy(name->data, &key->data[1], name->len);
|
||||
}
|
||||
|
||||
|
||||
if (skip) {
|
||||
|
||||
/*
|
||||
* convert "*.example.com" to "com.example.\0"
|
||||
* and ".example.com" to "com.example\0"
|
||||
*/
|
||||
|
||||
p = ngx_pnalloc(ha->temp_pool, last);
|
||||
if (p == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
len = 0;
|
||||
n = 0;
|
||||
|
||||
for (i = last - 1; i; i--) {
|
||||
if (key->data[i] == '.') {
|
||||
ngx_memcpy(&p[n], &key->data[i + 1], len);
|
||||
n += len;
|
||||
p[n++] = '.';
|
||||
len = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
len++;
|
||||
}
|
||||
|
||||
if (len) {
|
||||
ngx_memcpy(&p[n], &key->data[1], len);
|
||||
n += len;
|
||||
}
|
||||
|
||||
p[n] = '\0';
|
||||
|
||||
hwc = &ha->dns_wc_head;
|
||||
keys = &ha->dns_wc_head_hash[k];
|
||||
|
||||
} else {
|
||||
|
||||
/* convert "www.example.*" to "www.example\0" */
|
||||
|
||||
last++;
|
||||
|
||||
p = ngx_pnalloc(ha->temp_pool, last);
|
||||
if (p == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_cpystrn(p, key->data, last);
|
||||
|
||||
hwc = &ha->dns_wc_tail;
|
||||
keys = &ha->dns_wc_tail_hash[k];
|
||||
}
|
||||
|
||||
|
||||
/* check conflicts in wildcard hash */
|
||||
|
||||
name = keys->elts;
|
||||
|
||||
if (name) {
|
||||
len = last - skip;
|
||||
|
||||
for (i = 0; i < keys->nelts; i++) {
|
||||
if (len != name[i].len) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ngx_strncmp(key->data + skip, name[i].data, len) == 0) {
|
||||
return NGX_BUSY;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
if (ngx_array_init(keys, ha->temp_pool, 4, sizeof(ngx_str_t)) != NGX_OK)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
name = ngx_array_push(keys);
|
||||
if (name == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
name->len = last - skip;
|
||||
name->data = ngx_pnalloc(ha->temp_pool, name->len);
|
||||
if (name->data == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_memcpy(name->data, key->data + skip, name->len);
|
||||
|
||||
|
||||
/* add to wildcard hash */
|
||||
|
||||
hk = ngx_array_push(hwc);
|
||||
if (hk == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
hk->key.len = last - 1;
|
||||
hk->key.data = p;
|
||||
hk->key_hash = 0;
|
||||
hk->value = value;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
122
src/core/ngx_hash.h
Normal file
122
src/core/ngx_hash.h
Normal file
@@ -0,0 +1,122 @@
|
||||
|
||||
/*
|
||||
* 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_uint_t hash;
|
||||
ngx_str_t key;
|
||||
ngx_str_t value;
|
||||
u_char *lowcase_key;
|
||||
} ngx_table_elt_t;
|
||||
|
||||
|
||||
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_ */
|
||||
1493
src/core/ngx_inet.c
Normal file
1493
src/core/ngx_inet.c
Normal file
File diff suppressed because it is too large
Load Diff
129
src/core/ngx_inet.h
Normal file
129
src/core/ngx_inet.h
Normal file
@@ -0,0 +1,129 @@
|
||||
|
||||
/*
|
||||
* 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(struct sockaddr_un) - offsetof(struct sockaddr_un, sun_path))
|
||||
|
||||
#if (NGX_HAVE_UNIX_DOMAIN)
|
||||
#define NGX_SOCKADDR_STRLEN (sizeof("unix:") - 1 + 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;
|
||||
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);
|
||||
|
||||
|
||||
#endif /* _NGX_INET_H_INCLUDED_ */
|
||||
63
src/core/ngx_list.c
Normal file
63
src/core/ngx_list.c
Normal file
@@ -0,0 +1,63 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
ngx_list_t *
|
||||
ngx_list_create(ngx_pool_t *pool, ngx_uint_t n, size_t size)
|
||||
{
|
||||
ngx_list_t *list;
|
||||
|
||||
list = ngx_palloc(pool, sizeof(ngx_list_t));
|
||||
if (list == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ngx_list_init(list, pool, n, size) != NGX_OK) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
ngx_list_push(ngx_list_t *l)
|
||||
{
|
||||
void *elt;
|
||||
ngx_list_part_t *last;
|
||||
|
||||
last = l->last;
|
||||
|
||||
if (last->nelts == l->nalloc) {
|
||||
|
||||
/* the last part is full, allocate a new list part */
|
||||
|
||||
last = ngx_palloc(l->pool, sizeof(ngx_list_part_t));
|
||||
if (last == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
last->elts = ngx_palloc(l->pool, l->nalloc * l->size);
|
||||
if (last->elts == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
last->nelts = 0;
|
||||
last->next = NULL;
|
||||
|
||||
l->last->next = last;
|
||||
l->last = last;
|
||||
}
|
||||
|
||||
elt = (char *) last->elts + l->size * last->nelts;
|
||||
last->nelts++;
|
||||
|
||||
return elt;
|
||||
}
|
||||
83
src/core/ngx_list.h
Normal file
83
src/core/ngx_list.h
Normal file
@@ -0,0 +1,83 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_LIST_H_INCLUDED_
|
||||
#define _NGX_LIST_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
typedef struct ngx_list_part_s ngx_list_part_t;
|
||||
|
||||
struct ngx_list_part_s {
|
||||
void *elts;
|
||||
ngx_uint_t nelts;
|
||||
ngx_list_part_t *next;
|
||||
};
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_list_part_t *last;
|
||||
ngx_list_part_t part;
|
||||
size_t size;
|
||||
ngx_uint_t nalloc;
|
||||
ngx_pool_t *pool;
|
||||
} ngx_list_t;
|
||||
|
||||
|
||||
ngx_list_t *ngx_list_create(ngx_pool_t *pool, ngx_uint_t n, size_t size);
|
||||
|
||||
static ngx_inline ngx_int_t
|
||||
ngx_list_init(ngx_list_t *list, ngx_pool_t *pool, ngx_uint_t n, size_t size)
|
||||
{
|
||||
list->part.elts = ngx_palloc(pool, n * size);
|
||||
if (list->part.elts == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
list->part.nelts = 0;
|
||||
list->part.next = NULL;
|
||||
list->last = &list->part;
|
||||
list->size = size;
|
||||
list->nalloc = n;
|
||||
list->pool = pool;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* the iteration through the list:
|
||||
*
|
||||
* part = &list.part;
|
||||
* data = part->elts;
|
||||
*
|
||||
* for (i = 0 ;; i++) {
|
||||
*
|
||||
* if (i >= part->nelts) {
|
||||
* if (part->next == NULL) {
|
||||
* break;
|
||||
* }
|
||||
*
|
||||
* part = part->next;
|
||||
* data = part->elts;
|
||||
* i = 0;
|
||||
* }
|
||||
*
|
||||
* ... data[i] ...
|
||||
*
|
||||
* }
|
||||
*/
|
||||
|
||||
|
||||
void *ngx_list_push(ngx_list_t *list);
|
||||
|
||||
|
||||
#endif /* _NGX_LIST_H_INCLUDED_ */
|
||||
755
src/core/ngx_log.c
Normal file
755
src/core/ngx_log.c
Normal file
@@ -0,0 +1,755 @@
|
||||
|
||||
/*
|
||||
* 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 *p, *name;
|
||||
size_t nlen, plen;
|
||||
|
||||
ngx_log.file = &ngx_log_file;
|
||||
ngx_log.log_level = NGX_LOG_NOTICE;
|
||||
|
||||
name = (u_char *) NGX_ERROR_LOG_PATH;
|
||||
|
||||
/*
|
||||
* we use ngx_strlen() here since BCC warns about
|
||||
* condition is always false and unreachable code
|
||||
*/
|
||||
|
||||
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, (u_char *) NGX_ERROR_LOG_PATH, 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;
|
||||
static ngx_str_t error_log = ngx_string(NGX_ERROR_LOG_PATH);
|
||||
|
||||
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, &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
|
||||
268
src/core/ngx_log.h
Normal file
268
src/core/ngx_log.h
Normal file
@@ -0,0 +1,268 @@
|
||||
|
||||
/*
|
||||
* 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;
|
||||
};
|
||||
|
||||
|
||||
#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);
|
||||
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
src/core/ngx_md5.c
Normal file
283
src/core/ngx_md5.c
Normal file
@@ -0,0 +1,283 @@
|
||||
|
||||
/*
|
||||
* An internal implementation, based on Alexander Peslyak's
|
||||
* public domain implementation:
|
||||
* http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_md5.h>
|
||||
|
||||
|
||||
static const u_char *ngx_md5_body(ngx_md5_t *ctx, const u_char *data,
|
||||
size_t size);
|
||||
|
||||
|
||||
void
|
||||
ngx_md5_init(ngx_md5_t *ctx)
|
||||
{
|
||||
ctx->a = 0x67452301;
|
||||
ctx->b = 0xefcdab89;
|
||||
ctx->c = 0x98badcfe;
|
||||
ctx->d = 0x10325476;
|
||||
|
||||
ctx->bytes = 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_md5_update(ngx_md5_t *ctx, const void *data, size_t size)
|
||||
{
|
||||
size_t used, free;
|
||||
|
||||
used = (size_t) (ctx->bytes & 0x3f);
|
||||
ctx->bytes += size;
|
||||
|
||||
if (used) {
|
||||
free = 64 - used;
|
||||
|
||||
if (size < free) {
|
||||
ngx_memcpy(&ctx->buffer[used], data, size);
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_memcpy(&ctx->buffer[used], data, free);
|
||||
data = (u_char *) data + free;
|
||||
size -= free;
|
||||
(void) ngx_md5_body(ctx, ctx->buffer, 64);
|
||||
}
|
||||
|
||||
if (size >= 64) {
|
||||
data = ngx_md5_body(ctx, data, size & ~(size_t) 0x3f);
|
||||
size &= 0x3f;
|
||||
}
|
||||
|
||||
ngx_memcpy(ctx->buffer, data, size);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_md5_final(u_char result[16], ngx_md5_t *ctx)
|
||||
{
|
||||
size_t used, free;
|
||||
|
||||
used = (size_t) (ctx->bytes & 0x3f);
|
||||
|
||||
ctx->buffer[used++] = 0x80;
|
||||
|
||||
free = 64 - used;
|
||||
|
||||
if (free < 8) {
|
||||
ngx_memzero(&ctx->buffer[used], free);
|
||||
(void) ngx_md5_body(ctx, ctx->buffer, 64);
|
||||
used = 0;
|
||||
free = 64;
|
||||
}
|
||||
|
||||
ngx_memzero(&ctx->buffer[used], free - 8);
|
||||
|
||||
ctx->bytes <<= 3;
|
||||
ctx->buffer[56] = (u_char) ctx->bytes;
|
||||
ctx->buffer[57] = (u_char) (ctx->bytes >> 8);
|
||||
ctx->buffer[58] = (u_char) (ctx->bytes >> 16);
|
||||
ctx->buffer[59] = (u_char) (ctx->bytes >> 24);
|
||||
ctx->buffer[60] = (u_char) (ctx->bytes >> 32);
|
||||
ctx->buffer[61] = (u_char) (ctx->bytes >> 40);
|
||||
ctx->buffer[62] = (u_char) (ctx->bytes >> 48);
|
||||
ctx->buffer[63] = (u_char) (ctx->bytes >> 56);
|
||||
|
||||
(void) ngx_md5_body(ctx, ctx->buffer, 64);
|
||||
|
||||
result[0] = (u_char) ctx->a;
|
||||
result[1] = (u_char) (ctx->a >> 8);
|
||||
result[2] = (u_char) (ctx->a >> 16);
|
||||
result[3] = (u_char) (ctx->a >> 24);
|
||||
result[4] = (u_char) ctx->b;
|
||||
result[5] = (u_char) (ctx->b >> 8);
|
||||
result[6] = (u_char) (ctx->b >> 16);
|
||||
result[7] = (u_char) (ctx->b >> 24);
|
||||
result[8] = (u_char) ctx->c;
|
||||
result[9] = (u_char) (ctx->c >> 8);
|
||||
result[10] = (u_char) (ctx->c >> 16);
|
||||
result[11] = (u_char) (ctx->c >> 24);
|
||||
result[12] = (u_char) ctx->d;
|
||||
result[13] = (u_char) (ctx->d >> 8);
|
||||
result[14] = (u_char) (ctx->d >> 16);
|
||||
result[15] = (u_char) (ctx->d >> 24);
|
||||
|
||||
ngx_memzero(ctx, sizeof(*ctx));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The basic MD5 functions.
|
||||
*
|
||||
* F and G are optimized compared to their RFC 1321 definitions for
|
||||
* architectures that lack an AND-NOT instruction, just like in
|
||||
* Colin Plumb's implementation.
|
||||
*/
|
||||
|
||||
#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
|
||||
#define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y))))
|
||||
#define H(x, y, z) ((x) ^ (y) ^ (z))
|
||||
#define I(x, y, z) ((y) ^ ((x) | ~(z)))
|
||||
|
||||
/*
|
||||
* The MD5 transformation for all four rounds.
|
||||
*/
|
||||
|
||||
#define STEP(f, a, b, c, d, x, t, s) \
|
||||
(a) += f((b), (c), (d)) + (x) + (t); \
|
||||
(a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
|
||||
(a) += (b)
|
||||
|
||||
/*
|
||||
* SET() reads 4 input bytes in little-endian byte order and stores them
|
||||
* in a properly aligned word in host byte order.
|
||||
*
|
||||
* The check for little-endian architectures that tolerate unaligned
|
||||
* memory accesses is just an optimization. Nothing will break if it
|
||||
* does not work.
|
||||
*/
|
||||
|
||||
#if (NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED)
|
||||
|
||||
#define SET(n) (*(uint32_t *) &p[n * 4])
|
||||
#define GET(n) (*(uint32_t *) &p[n * 4])
|
||||
|
||||
#else
|
||||
|
||||
#define SET(n) \
|
||||
(block[n] = \
|
||||
(uint32_t) p[n * 4] | \
|
||||
((uint32_t) p[n * 4 + 1] << 8) | \
|
||||
((uint32_t) p[n * 4 + 2] << 16) | \
|
||||
((uint32_t) p[n * 4 + 3] << 24))
|
||||
|
||||
#define GET(n) block[n]
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* This processes one or more 64-byte data blocks, but does not update
|
||||
* the bit counters. There are no alignment requirements.
|
||||
*/
|
||||
|
||||
static const u_char *
|
||||
ngx_md5_body(ngx_md5_t *ctx, const u_char *data, size_t size)
|
||||
{
|
||||
uint32_t a, b, c, d;
|
||||
uint32_t saved_a, saved_b, saved_c, saved_d;
|
||||
const u_char *p;
|
||||
#if !(NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED)
|
||||
uint32_t block[16];
|
||||
#endif
|
||||
|
||||
p = data;
|
||||
|
||||
a = ctx->a;
|
||||
b = ctx->b;
|
||||
c = ctx->c;
|
||||
d = ctx->d;
|
||||
|
||||
do {
|
||||
saved_a = a;
|
||||
saved_b = b;
|
||||
saved_c = c;
|
||||
saved_d = d;
|
||||
|
||||
/* Round 1 */
|
||||
|
||||
STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7);
|
||||
STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12);
|
||||
STEP(F, c, d, a, b, SET(2), 0x242070db, 17);
|
||||
STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22);
|
||||
STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7);
|
||||
STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12);
|
||||
STEP(F, c, d, a, b, SET(6), 0xa8304613, 17);
|
||||
STEP(F, b, c, d, a, SET(7), 0xfd469501, 22);
|
||||
STEP(F, a, b, c, d, SET(8), 0x698098d8, 7);
|
||||
STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12);
|
||||
STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17);
|
||||
STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22);
|
||||
STEP(F, a, b, c, d, SET(12), 0x6b901122, 7);
|
||||
STEP(F, d, a, b, c, SET(13), 0xfd987193, 12);
|
||||
STEP(F, c, d, a, b, SET(14), 0xa679438e, 17);
|
||||
STEP(F, b, c, d, a, SET(15), 0x49b40821, 22);
|
||||
|
||||
/* Round 2 */
|
||||
|
||||
STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5);
|
||||
STEP(G, d, a, b, c, GET(6), 0xc040b340, 9);
|
||||
STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14);
|
||||
STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20);
|
||||
STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5);
|
||||
STEP(G, d, a, b, c, GET(10), 0x02441453, 9);
|
||||
STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14);
|
||||
STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20);
|
||||
STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5);
|
||||
STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9);
|
||||
STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14);
|
||||
STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20);
|
||||
STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5);
|
||||
STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9);
|
||||
STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14);
|
||||
STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20);
|
||||
|
||||
/* Round 3 */
|
||||
|
||||
STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4);
|
||||
STEP(H, d, a, b, c, GET(8), 0x8771f681, 11);
|
||||
STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16);
|
||||
STEP(H, b, c, d, a, GET(14), 0xfde5380c, 23);
|
||||
STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4);
|
||||
STEP(H, d, a, b, c, GET(4), 0x4bdecfa9, 11);
|
||||
STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16);
|
||||
STEP(H, b, c, d, a, GET(10), 0xbebfbc70, 23);
|
||||
STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4);
|
||||
STEP(H, d, a, b, c, GET(0), 0xeaa127fa, 11);
|
||||
STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16);
|
||||
STEP(H, b, c, d, a, GET(6), 0x04881d05, 23);
|
||||
STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4);
|
||||
STEP(H, d, a, b, c, GET(12), 0xe6db99e5, 11);
|
||||
STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16);
|
||||
STEP(H, b, c, d, a, GET(2), 0xc4ac5665, 23);
|
||||
|
||||
/* Round 4 */
|
||||
|
||||
STEP(I, a, b, c, d, GET(0), 0xf4292244, 6);
|
||||
STEP(I, d, a, b, c, GET(7), 0x432aff97, 10);
|
||||
STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15);
|
||||
STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21);
|
||||
STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6);
|
||||
STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10);
|
||||
STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15);
|
||||
STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21);
|
||||
STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6);
|
||||
STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10);
|
||||
STEP(I, c, d, a, b, GET(6), 0xa3014314, 15);
|
||||
STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21);
|
||||
STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6);
|
||||
STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10);
|
||||
STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15);
|
||||
STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21);
|
||||
|
||||
a += saved_a;
|
||||
b += saved_b;
|
||||
c += saved_c;
|
||||
d += saved_d;
|
||||
|
||||
p += 64;
|
||||
|
||||
} while (size -= 64);
|
||||
|
||||
ctx->a = a;
|
||||
ctx->b = b;
|
||||
ctx->c = c;
|
||||
ctx->d = d;
|
||||
|
||||
return p;
|
||||
}
|
||||
28
src/core/ngx_md5.h
Normal file
28
src/core/ngx_md5.h
Normal file
@@ -0,0 +1,28 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_MD5_H_INCLUDED_
|
||||
#define _NGX_MD5_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint64_t bytes;
|
||||
uint32_t a, b, c, d;
|
||||
u_char buffer[64];
|
||||
} ngx_md5_t;
|
||||
|
||||
|
||||
void ngx_md5_init(ngx_md5_t *ctx);
|
||||
void ngx_md5_update(ngx_md5_t *ctx, const void *data, size_t size);
|
||||
void ngx_md5_final(u_char result[16], ngx_md5_t *ctx);
|
||||
|
||||
|
||||
#endif /* _NGX_MD5_H_INCLUDED_ */
|
||||
360
src/core/ngx_module.c
Normal file
360
src/core/ngx_module.c
Normal file
@@ -0,0 +1,360 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Maxim Dounin
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
#define NGX_MAX_DYNAMIC_MODULES 128
|
||||
|
||||
|
||||
static ngx_uint_t ngx_module_index(ngx_cycle_t *cycle);
|
||||
static ngx_uint_t ngx_module_ctx_index(ngx_cycle_t *cycle, ngx_uint_t type,
|
||||
ngx_uint_t index);
|
||||
|
||||
|
||||
ngx_uint_t ngx_max_module;
|
||||
static ngx_uint_t ngx_modules_n;
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_preinit_modules(void)
|
||||
{
|
||||
ngx_uint_t i;
|
||||
|
||||
for (i = 0; ngx_modules[i]; i++) {
|
||||
ngx_modules[i]->index = i;
|
||||
ngx_modules[i]->name = ngx_module_names[i];
|
||||
}
|
||||
|
||||
ngx_modules_n = i;
|
||||
ngx_max_module = ngx_modules_n + NGX_MAX_DYNAMIC_MODULES;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_cycle_modules(ngx_cycle_t *cycle)
|
||||
{
|
||||
/*
|
||||
* create a list of modules to be used for this cycle,
|
||||
* copy static modules to it
|
||||
*/
|
||||
|
||||
cycle->modules = ngx_pcalloc(cycle->pool, (ngx_max_module + 1)
|
||||
* sizeof(ngx_module_t *));
|
||||
if (cycle->modules == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_memcpy(cycle->modules, ngx_modules,
|
||||
ngx_modules_n * sizeof(ngx_module_t *));
|
||||
|
||||
cycle->modules_n = ngx_modules_n;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_init_modules(ngx_cycle_t *cycle)
|
||||
{
|
||||
ngx_uint_t i;
|
||||
|
||||
for (i = 0; cycle->modules[i]; i++) {
|
||||
if (cycle->modules[i]->init_module) {
|
||||
if (cycle->modules[i]->init_module(cycle) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_count_modules(ngx_cycle_t *cycle, ngx_uint_t type)
|
||||
{
|
||||
ngx_uint_t i, next, max;
|
||||
ngx_module_t *module;
|
||||
|
||||
next = 0;
|
||||
max = 0;
|
||||
|
||||
/* count appropriate modules, set up their indices */
|
||||
|
||||
for (i = 0; cycle->modules[i]; i++) {
|
||||
module = cycle->modules[i];
|
||||
|
||||
if (module->type != type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (module->ctx_index != NGX_MODULE_UNSET_INDEX) {
|
||||
|
||||
/* if ctx_index was assigned, preserve it */
|
||||
|
||||
if (module->ctx_index > max) {
|
||||
max = module->ctx_index;
|
||||
}
|
||||
|
||||
if (module->ctx_index == next) {
|
||||
next++;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* search for some free index */
|
||||
|
||||
module->ctx_index = ngx_module_ctx_index(cycle, type, next);
|
||||
|
||||
if (module->ctx_index > max) {
|
||||
max = module->ctx_index;
|
||||
}
|
||||
|
||||
next = module->ctx_index + 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* make sure the number returned is big enough for previous
|
||||
* cycle as well, else there will be problems if the number
|
||||
* will be stored in a global variable (as it's used to be)
|
||||
* and we'll have to roll back to the previous cycle
|
||||
*/
|
||||
|
||||
if (cycle->old_cycle && cycle->old_cycle->modules) {
|
||||
|
||||
for (i = 0; cycle->old_cycle->modules[i]; i++) {
|
||||
module = cycle->old_cycle->modules[i];
|
||||
|
||||
if (module->type != type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (module->ctx_index > max) {
|
||||
max = module->ctx_index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* prevent loading of additional modules */
|
||||
|
||||
cycle->modules_used = 1;
|
||||
|
||||
return max + 1;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_add_module(ngx_conf_t *cf, ngx_str_t *file, ngx_module_t *module,
|
||||
char **order)
|
||||
{
|
||||
void *rv;
|
||||
ngx_uint_t i, m, before;
|
||||
ngx_core_module_t *core_module;
|
||||
|
||||
if (cf->cycle->modules_n >= ngx_max_module) {
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"too many modules loaded");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (module->version != nginx_version) {
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"module \"%V\" version %ui instead of %ui",
|
||||
file, module->version, (ngx_uint_t) nginx_version);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (ngx_strcmp(module->signature, NGX_MODULE_SIGNATURE) != 0) {
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"module \"%V\" is not binary compatible",
|
||||
file);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
for (m = 0; cf->cycle->modules[m]; m++) {
|
||||
if (ngx_strcmp(cf->cycle->modules[m]->name, module->name) == 0) {
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"module \"%s\" is already loaded",
|
||||
module->name);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* if the module wasn't previously loaded, assign an index
|
||||
*/
|
||||
|
||||
if (module->index == NGX_MODULE_UNSET_INDEX) {
|
||||
module->index = ngx_module_index(cf->cycle);
|
||||
|
||||
if (module->index >= ngx_max_module) {
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"too many modules loaded");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* put the module into the cycle->modules array
|
||||
*/
|
||||
|
||||
before = cf->cycle->modules_n;
|
||||
|
||||
if (order) {
|
||||
for (i = 0; order[i]; i++) {
|
||||
if (ngx_strcmp(order[i], module->name) == 0) {
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for ( /* void */ ; order[i]; i++) {
|
||||
|
||||
#if 0
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_CORE, cf->log, 0,
|
||||
"module: %s before %s",
|
||||
module->name, order[i]);
|
||||
#endif
|
||||
|
||||
for (m = 0; m < before; m++) {
|
||||
if (ngx_strcmp(cf->cycle->modules[m]->name, order[i]) == 0) {
|
||||
|
||||
ngx_log_debug3(NGX_LOG_DEBUG_CORE, cf->log, 0,
|
||||
"module: %s before %s:%i",
|
||||
module->name, order[i], m);
|
||||
|
||||
before = m;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* put the module before modules[before] */
|
||||
|
||||
if (before != cf->cycle->modules_n) {
|
||||
ngx_memmove(&cf->cycle->modules[before + 1],
|
||||
&cf->cycle->modules[before],
|
||||
(cf->cycle->modules_n - before) * sizeof(ngx_module_t *));
|
||||
}
|
||||
|
||||
cf->cycle->modules[before] = module;
|
||||
cf->cycle->modules_n++;
|
||||
|
||||
if (module->type == NGX_CORE_MODULE) {
|
||||
|
||||
/*
|
||||
* we are smart enough to initialize core modules;
|
||||
* other modules are expected to be loaded before
|
||||
* initialization - e.g., http modules must be loaded
|
||||
* before http{} block
|
||||
*/
|
||||
|
||||
core_module = module->ctx;
|
||||
|
||||
if (core_module->create_conf) {
|
||||
rv = core_module->create_conf(cf->cycle);
|
||||
if (rv == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
cf->cycle->conf_ctx[module->index] = rv;
|
||||
}
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_uint_t
|
||||
ngx_module_index(ngx_cycle_t *cycle)
|
||||
{
|
||||
ngx_uint_t i, index;
|
||||
ngx_module_t *module;
|
||||
|
||||
index = 0;
|
||||
|
||||
again:
|
||||
|
||||
/* find an unused index */
|
||||
|
||||
for (i = 0; cycle->modules[i]; i++) {
|
||||
module = cycle->modules[i];
|
||||
|
||||
if (module->index == index) {
|
||||
index++;
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
|
||||
/* check previous cycle */
|
||||
|
||||
if (cycle->old_cycle && cycle->old_cycle->modules) {
|
||||
|
||||
for (i = 0; cycle->old_cycle->modules[i]; i++) {
|
||||
module = cycle->old_cycle->modules[i];
|
||||
|
||||
if (module->index == index) {
|
||||
index++;
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
|
||||
static ngx_uint_t
|
||||
ngx_module_ctx_index(ngx_cycle_t *cycle, ngx_uint_t type, ngx_uint_t index)
|
||||
{
|
||||
ngx_uint_t i;
|
||||
ngx_module_t *module;
|
||||
|
||||
again:
|
||||
|
||||
/* find an unused ctx_index */
|
||||
|
||||
for (i = 0; cycle->modules[i]; i++) {
|
||||
module = cycle->modules[i];
|
||||
|
||||
if (module->type != type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (module->ctx_index == index) {
|
||||
index++;
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
|
||||
/* check previous cycle */
|
||||
|
||||
if (cycle->old_cycle && cycle->old_cycle->modules) {
|
||||
|
||||
for (i = 0; cycle->old_cycle->modules[i]; i++) {
|
||||
module = cycle->old_cycle->modules[i];
|
||||
|
||||
if (module->type != type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (module->ctx_index == index) {
|
||||
index++;
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
283
src/core/ngx_module.h
Normal file
283
src/core/ngx_module.h
Normal file
@@ -0,0 +1,283 @@
|
||||
|
||||
/*
|
||||
* 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_AIO_SENDFILE || 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"
|
||||
#define NGX_MODULE_SIGNATURE_18 "0"
|
||||
|
||||
#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_ */
|
||||
50
src/core/ngx_murmurhash.c
Normal file
50
src/core/ngx_murmurhash.c
Normal file
@@ -0,0 +1,50 @@
|
||||
|
||||
/*
|
||||
* 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;
|
||||
case 2:
|
||||
h ^= data[1] << 8;
|
||||
case 1:
|
||||
h ^= data[0];
|
||||
h *= 0x5bd1e995;
|
||||
}
|
||||
|
||||
h ^= h >> 13;
|
||||
h *= 0x5bd1e995;
|
||||
h ^= h >> 15;
|
||||
|
||||
return h;
|
||||
}
|
||||
19
src/core/ngx_murmurhash.h
Normal file
19
src/core/ngx_murmurhash.h
Normal file
@@ -0,0 +1,19 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_MURMURHASH_H_INCLUDED_
|
||||
#define _NGX_MURMURHASH_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
uint32_t ngx_murmur_hash2(u_char *data, size_t len);
|
||||
|
||||
|
||||
#endif /* _NGX_MURMURHASH_H_INCLUDED_ */
|
||||
1253
src/core/ngx_open_file_cache.c
Normal file
1253
src/core/ngx_open_file_cache.c
Normal file
File diff suppressed because it is too large
Load Diff
129
src/core/ngx_open_file_cache.h
Normal file
129
src/core/ngx_open_file_cache.h
Normal file
@@ -0,0 +1,129 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
#ifndef _NGX_OPEN_FILE_CACHE_H_INCLUDED_
|
||||
#define _NGX_OPEN_FILE_CACHE_H_INCLUDED_
|
||||
|
||||
|
||||
#define NGX_OPEN_FILE_DIRECTIO_OFF NGX_MAX_OFF_T_VALUE
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_fd_t fd;
|
||||
ngx_file_uniq_t uniq;
|
||||
time_t mtime;
|
||||
off_t size;
|
||||
off_t fs_size;
|
||||
off_t directio;
|
||||
size_t read_ahead;
|
||||
|
||||
ngx_err_t err;
|
||||
char *failed;
|
||||
|
||||
time_t valid;
|
||||
|
||||
ngx_uint_t min_uses;
|
||||
|
||||
#if (NGX_HAVE_OPENAT)
|
||||
size_t disable_symlinks_from;
|
||||
unsigned disable_symlinks:2;
|
||||
#endif
|
||||
|
||||
unsigned test_dir:1;
|
||||
unsigned test_only:1;
|
||||
unsigned log:1;
|
||||
unsigned errors:1;
|
||||
unsigned events:1;
|
||||
|
||||
unsigned is_dir:1;
|
||||
unsigned is_file:1;
|
||||
unsigned is_link:1;
|
||||
unsigned is_exec:1;
|
||||
unsigned is_directio:1;
|
||||
} ngx_open_file_info_t;
|
||||
|
||||
|
||||
typedef struct ngx_cached_open_file_s ngx_cached_open_file_t;
|
||||
|
||||
struct ngx_cached_open_file_s {
|
||||
ngx_rbtree_node_t node;
|
||||
ngx_queue_t queue;
|
||||
|
||||
u_char *name;
|
||||
time_t created;
|
||||
time_t accessed;
|
||||
|
||||
ngx_fd_t fd;
|
||||
ngx_file_uniq_t uniq;
|
||||
time_t mtime;
|
||||
off_t size;
|
||||
ngx_err_t err;
|
||||
|
||||
uint32_t uses;
|
||||
|
||||
#if (NGX_HAVE_OPENAT)
|
||||
size_t disable_symlinks_from;
|
||||
unsigned disable_symlinks:2;
|
||||
#endif
|
||||
|
||||
unsigned count:24;
|
||||
unsigned close:1;
|
||||
unsigned use_event:1;
|
||||
|
||||
unsigned is_dir:1;
|
||||
unsigned is_file:1;
|
||||
unsigned is_link:1;
|
||||
unsigned is_exec:1;
|
||||
unsigned is_directio:1;
|
||||
|
||||
ngx_event_t *event;
|
||||
};
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_rbtree_t rbtree;
|
||||
ngx_rbtree_node_t sentinel;
|
||||
ngx_queue_t expire_queue;
|
||||
|
||||
ngx_uint_t current;
|
||||
ngx_uint_t max;
|
||||
time_t inactive;
|
||||
} ngx_open_file_cache_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_open_file_cache_t *cache;
|
||||
ngx_cached_open_file_t *file;
|
||||
ngx_uint_t min_uses;
|
||||
ngx_log_t *log;
|
||||
} ngx_open_file_cache_cleanup_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
|
||||
/* ngx_connection_t stub to allow use c->fd as event ident */
|
||||
void *data;
|
||||
ngx_event_t *read;
|
||||
ngx_event_t *write;
|
||||
ngx_fd_t fd;
|
||||
|
||||
ngx_cached_open_file_t *file;
|
||||
ngx_open_file_cache_t *cache;
|
||||
} ngx_open_file_cache_event_t;
|
||||
|
||||
|
||||
ngx_open_file_cache_t *ngx_open_file_cache_init(ngx_pool_t *pool,
|
||||
ngx_uint_t max, time_t inactive);
|
||||
ngx_int_t ngx_open_cached_file(ngx_open_file_cache_t *cache, ngx_str_t *name,
|
||||
ngx_open_file_info_t *of, ngx_pool_t *pool);
|
||||
|
||||
|
||||
#endif /* _NGX_OPEN_FILE_CACHE_H_INCLUDED_ */
|
||||
767
src/core/ngx_output_chain.c
Normal file
767
src/core/ngx_output_chain.c
Normal file
@@ -0,0 +1,767 @@
|
||||
|
||||
/*
|
||||
* 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);
|
||||
#if (NGX_HAVE_AIO_SENDFILE)
|
||||
static ngx_int_t ngx_output_chain_aio_setup(ngx_output_chain_ctx_t *ctx,
|
||||
ngx_file_t *file);
|
||||
#endif
|
||||
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();
|
||||
|
||||
ctx->in = ctx->in->next;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
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) {
|
||||
ctx->in = ctx->in->next;
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
if (buf->in_file && buf->file->directio) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
sendfile = ctx->sendfile;
|
||||
|
||||
#if (NGX_SENDFILE_LIMIT)
|
||||
|
||||
if (buf->in_file && buf->file_pos >= NGX_SENDFILE_LIMIT) {
|
||||
sendfile = 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if (!sendfile) {
|
||||
|
||||
if (!ngx_buf_in_memory(buf)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
buf->in_file = 0;
|
||||
}
|
||||
|
||||
#if (NGX_HAVE_AIO_SENDFILE)
|
||||
if (ctx->aio_preload && buf->in_file) {
|
||||
(void) ngx_output_chain_aio_setup(ctx, buf->file);
|
||||
}
|
||||
#endif
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
#if (NGX_HAVE_AIO_SENDFILE)
|
||||
|
||||
static ngx_int_t
|
||||
ngx_output_chain_aio_setup(ngx_output_chain_ctx_t *ctx, ngx_file_t *file)
|
||||
{
|
||||
ngx_event_aio_t *aio;
|
||||
|
||||
if (file->aio == NULL && ngx_file_aio_init(file, ctx->pool) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
aio = file->aio;
|
||||
|
||||
aio->data = ctx->filter_ctx;
|
||||
aio->preload_handler = ctx->aio_preload;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
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 {
|
||||
|
||||
#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;
|
||||
}
|
||||
}
|
||||
|
||||
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 1
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
|
||||
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 1
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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
src/core/ngx_palloc.c
Normal file
430
src/core/ngx_palloc.c
Normal file
@@ -0,0 +1,430 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
static ngx_inline void *ngx_palloc_small(ngx_pool_t *pool, size_t size,
|
||||
ngx_uint_t align);
|
||||
static void *ngx_palloc_block(ngx_pool_t *pool, size_t size);
|
||||
static void *ngx_palloc_large(ngx_pool_t *pool, size_t size);
|
||||
|
||||
|
||||
ngx_pool_t *
|
||||
ngx_create_pool(size_t size, ngx_log_t *log)
|
||||
{
|
||||
ngx_pool_t *p;
|
||||
|
||||
p = ngx_memalign(NGX_POOL_ALIGNMENT, size, log);
|
||||
if (p == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p->d.last = (u_char *) p + sizeof(ngx_pool_t);
|
||||
p->d.end = (u_char *) p + size;
|
||||
p->d.next = NULL;
|
||||
p->d.failed = 0;
|
||||
|
||||
size = size - sizeof(ngx_pool_t);
|
||||
p->max = (size < NGX_MAX_ALLOC_FROM_POOL) ? size : NGX_MAX_ALLOC_FROM_POOL;
|
||||
|
||||
p->current = p;
|
||||
p->chain = NULL;
|
||||
p->large = NULL;
|
||||
p->cleanup = NULL;
|
||||
p->log = log;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_destroy_pool(ngx_pool_t *pool)
|
||||
{
|
||||
ngx_pool_t *p, *n;
|
||||
ngx_pool_large_t *l;
|
||||
ngx_pool_cleanup_t *c;
|
||||
|
||||
for (c = pool->cleanup; c; c = c->next) {
|
||||
if (c->handler) {
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0,
|
||||
"run cleanup: %p", c);
|
||||
c->handler(c->data);
|
||||
}
|
||||
}
|
||||
|
||||
#if (NGX_DEBUG)
|
||||
|
||||
/*
|
||||
* we could allocate the pool->log from this pool
|
||||
* so we cannot use this log while free()ing the pool
|
||||
*/
|
||||
|
||||
for (l = pool->large; l; l = l->next) {
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0, "free: %p", l->alloc);
|
||||
}
|
||||
|
||||
for (p = pool, n = pool->d.next; /* void */; p = n, n = n->d.next) {
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, pool->log, 0,
|
||||
"free: %p, unused: %uz", p, p->d.end - p->d.last);
|
||||
|
||||
if (n == NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
for (l = pool->large; l; l = l->next) {
|
||||
if (l->alloc) {
|
||||
ngx_free(l->alloc);
|
||||
}
|
||||
}
|
||||
|
||||
for (p = pool, n = pool->d.next; /* void */; p = n, n = n->d.next) {
|
||||
ngx_free(p);
|
||||
|
||||
if (n == NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_reset_pool(ngx_pool_t *pool)
|
||||
{
|
||||
ngx_pool_t *p;
|
||||
ngx_pool_large_t *l;
|
||||
|
||||
for (l = pool->large; l; l = l->next) {
|
||||
if (l->alloc) {
|
||||
ngx_free(l->alloc);
|
||||
}
|
||||
}
|
||||
|
||||
for (p = pool; p; p = p->d.next) {
|
||||
p->d.last = (u_char *) p + sizeof(ngx_pool_t);
|
||||
p->d.failed = 0;
|
||||
}
|
||||
|
||||
pool->current = pool;
|
||||
pool->chain = NULL;
|
||||
pool->large = NULL;
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
ngx_palloc(ngx_pool_t *pool, size_t size)
|
||||
{
|
||||
#if !(NGX_DEBUG_PALLOC)
|
||||
if (size <= pool->max) {
|
||||
return ngx_palloc_small(pool, size, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
return ngx_palloc_large(pool, size);
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
ngx_pnalloc(ngx_pool_t *pool, size_t size)
|
||||
{
|
||||
#if !(NGX_DEBUG_PALLOC)
|
||||
if (size <= pool->max) {
|
||||
return ngx_palloc_small(pool, size, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
return ngx_palloc_large(pool, size);
|
||||
}
|
||||
|
||||
|
||||
static ngx_inline void *
|
||||
ngx_palloc_small(ngx_pool_t *pool, size_t size, ngx_uint_t align)
|
||||
{
|
||||
u_char *m;
|
||||
ngx_pool_t *p;
|
||||
|
||||
p = pool->current;
|
||||
|
||||
do {
|
||||
m = p->d.last;
|
||||
|
||||
if (align) {
|
||||
m = ngx_align_ptr(m, NGX_ALIGNMENT);
|
||||
}
|
||||
|
||||
if ((size_t) (p->d.end - m) >= size) {
|
||||
p->d.last = m + size;
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
p = p->d.next;
|
||||
|
||||
} while (p);
|
||||
|
||||
return ngx_palloc_block(pool, size);
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
ngx_palloc_block(ngx_pool_t *pool, size_t size)
|
||||
{
|
||||
u_char *m;
|
||||
size_t psize;
|
||||
ngx_pool_t *p, *new;
|
||||
|
||||
psize = (size_t) (pool->d.end - (u_char *) pool);
|
||||
|
||||
m = ngx_memalign(NGX_POOL_ALIGNMENT, psize, pool->log);
|
||||
if (m == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
new = (ngx_pool_t *) m;
|
||||
|
||||
new->d.end = m + psize;
|
||||
new->d.next = NULL;
|
||||
new->d.failed = 0;
|
||||
|
||||
m += sizeof(ngx_pool_data_t);
|
||||
m = ngx_align_ptr(m, NGX_ALIGNMENT);
|
||||
new->d.last = m + size;
|
||||
|
||||
for (p = pool->current; p->d.next; p = p->d.next) {
|
||||
if (p->d.failed++ > 4) {
|
||||
pool->current = p->d.next;
|
||||
}
|
||||
}
|
||||
|
||||
p->d.next = new;
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
ngx_palloc_large(ngx_pool_t *pool, size_t size)
|
||||
{
|
||||
void *p;
|
||||
ngx_uint_t n;
|
||||
ngx_pool_large_t *large;
|
||||
|
||||
p = ngx_alloc(size, pool->log);
|
||||
if (p == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
n = 0;
|
||||
|
||||
for (large = pool->large; large; large = large->next) {
|
||||
if (large->alloc == NULL) {
|
||||
large->alloc = p;
|
||||
return p;
|
||||
}
|
||||
|
||||
if (n++ > 3) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
large = ngx_palloc_small(pool, sizeof(ngx_pool_large_t), 1);
|
||||
if (large == NULL) {
|
||||
ngx_free(p);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
large->alloc = p;
|
||||
large->next = pool->large;
|
||||
pool->large = large;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
ngx_pmemalign(ngx_pool_t *pool, size_t size, size_t alignment)
|
||||
{
|
||||
void *p;
|
||||
ngx_pool_large_t *large;
|
||||
|
||||
p = ngx_memalign(alignment, size, pool->log);
|
||||
if (p == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
large = ngx_palloc_small(pool, sizeof(ngx_pool_large_t), 1);
|
||||
if (large == NULL) {
|
||||
ngx_free(p);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
large->alloc = p;
|
||||
large->next = pool->large;
|
||||
pool->large = large;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_pfree(ngx_pool_t *pool, void *p)
|
||||
{
|
||||
ngx_pool_large_t *l;
|
||||
|
||||
for (l = pool->large; l; l = l->next) {
|
||||
if (p == l->alloc) {
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0,
|
||||
"free: %p", l->alloc);
|
||||
ngx_free(l->alloc);
|
||||
l->alloc = NULL;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
ngx_pcalloc(ngx_pool_t *pool, size_t size)
|
||||
{
|
||||
void *p;
|
||||
|
||||
p = ngx_palloc(pool, size);
|
||||
if (p) {
|
||||
ngx_memzero(p, size);
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
ngx_pool_cleanup_t *
|
||||
ngx_pool_cleanup_add(ngx_pool_t *p, size_t size)
|
||||
{
|
||||
ngx_pool_cleanup_t *c;
|
||||
|
||||
c = ngx_palloc(p, sizeof(ngx_pool_cleanup_t));
|
||||
if (c == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (size) {
|
||||
c->data = ngx_palloc(p, size);
|
||||
if (c->data == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
} else {
|
||||
c->data = NULL;
|
||||
}
|
||||
|
||||
c->handler = NULL;
|
||||
c->next = p->cleanup;
|
||||
|
||||
p->cleanup = c;
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, p->log, 0, "add cleanup: %p", c);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_pool_run_cleanup_file(ngx_pool_t *p, ngx_fd_t fd)
|
||||
{
|
||||
ngx_pool_cleanup_t *c;
|
||||
ngx_pool_cleanup_file_t *cf;
|
||||
|
||||
for (c = p->cleanup; c; c = c->next) {
|
||||
if (c->handler == ngx_pool_cleanup_file) {
|
||||
|
||||
cf = c->data;
|
||||
|
||||
if (cf->fd == fd) {
|
||||
c->handler(cf);
|
||||
c->handler = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_pool_cleanup_file(void *data)
|
||||
{
|
||||
ngx_pool_cleanup_file_t *c = data;
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, c->log, 0, "file cleanup: fd:%d",
|
||||
c->fd);
|
||||
|
||||
if (ngx_close_file(c->fd) == NGX_FILE_ERROR) {
|
||||
ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
|
||||
ngx_close_file_n " \"%s\" failed", c->name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_pool_delete_file(void *data)
|
||||
{
|
||||
ngx_pool_cleanup_file_t *c = data;
|
||||
|
||||
ngx_err_t err;
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, c->log, 0, "file cleanup: fd:%d %s",
|
||||
c->fd, c->name);
|
||||
|
||||
if (ngx_delete_file(c->name) == NGX_FILE_ERROR) {
|
||||
err = ngx_errno;
|
||||
|
||||
if (err != NGX_ENOENT) {
|
||||
ngx_log_error(NGX_LOG_CRIT, c->log, err,
|
||||
ngx_delete_file_n " \"%s\" failed", c->name);
|
||||
}
|
||||
}
|
||||
|
||||
if (ngx_close_file(c->fd) == NGX_FILE_ERROR) {
|
||||
ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
|
||||
ngx_close_file_n " \"%s\" failed", c->name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
|
||||
static void *
|
||||
ngx_get_cached_block(size_t size)
|
||||
{
|
||||
void *p;
|
||||
ngx_cached_block_slot_t *slot;
|
||||
|
||||
if (ngx_cycle->cache == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
slot = &ngx_cycle->cache[(size + ngx_pagesize - 1) / ngx_pagesize];
|
||||
|
||||
slot->tries++;
|
||||
|
||||
if (slot->number) {
|
||||
p = slot->block;
|
||||
slot->block = slot->block->next;
|
||||
slot->number--;
|
||||
return p;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
95
src/core/ngx_palloc.h
Normal file
95
src/core/ngx_palloc.h
Normal file
@@ -0,0 +1,95 @@
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
|
||||
void *ngx_alloc(size_t size, ngx_log_t *log);
|
||||
void *ngx_calloc(size_t size, ngx_log_t *log);
|
||||
|
||||
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_ */
|
||||
273
src/core/ngx_parse.c
Normal file
273
src/core/ngx_parse.c
Normal file
@@ -0,0 +1,273 @@
|
||||
|
||||
/*
|
||||
* 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;
|
||||
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;
|
||||
unit = line->data[len - 1];
|
||||
|
||||
switch (unit) {
|
||||
case 'K':
|
||||
case 'k':
|
||||
len--;
|
||||
max = NGX_MAX_OFF_T_VALUE / 1024;
|
||||
scale = 1024;
|
||||
break;
|
||||
|
||||
case 'M':
|
||||
case 'm':
|
||||
len--;
|
||||
max = NGX_MAX_OFF_T_VALUE / (1024 * 1024);
|
||||
scale = 1024 * 1024;
|
||||
break;
|
||||
|
||||
case 'G':
|
||||
case 'g':
|
||||
len--;
|
||||
max = NGX_MAX_OFF_T_VALUE / (1024 * 1024 * 1024);
|
||||
scale = 1024 * 1024 * 1024;
|
||||
break;
|
||||
|
||||
default:
|
||||
max = NGX_MAX_OFF_T_VALUE;
|
||||
scale = 1;
|
||||
}
|
||||
|
||||
offset = ngx_atoof(line->data, len);
|
||||
if (offset == NGX_ERROR || offset > max) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
offset *= scale;
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_parse_time(ngx_str_t *line, ngx_uint_t is_sec)
|
||||
{
|
||||
u_char *p, *last;
|
||||
ngx_int_t value, total, scale;
|
||||
ngx_int_t max, cutoff, cutlim;
|
||||
ngx_uint_t valid;
|
||||
enum {
|
||||
st_start = 0,
|
||||
st_year,
|
||||
st_month,
|
||||
st_week,
|
||||
st_day,
|
||||
st_hour,
|
||||
st_min,
|
||||
st_sec,
|
||||
st_msec,
|
||||
st_last
|
||||
} step;
|
||||
|
||||
valid = 0;
|
||||
value = 0;
|
||||
total = 0;
|
||||
cutoff = NGX_MAX_INT_T_VALUE / 10;
|
||||
cutlim = NGX_MAX_INT_T_VALUE % 10;
|
||||
step = is_sec ? st_start : st_month;
|
||||
|
||||
p = line->data;
|
||||
last = p + line->len;
|
||||
|
||||
while (p < last) {
|
||||
|
||||
if (*p >= '0' && *p <= '9') {
|
||||
if (value >= cutoff && (value > cutoff || *p - '0' > cutlim)) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
value = value * 10 + (*p++ - '0');
|
||||
valid = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (*p++) {
|
||||
|
||||
case 'y':
|
||||
if (step > st_start) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
step = st_year;
|
||||
max = NGX_MAX_INT_T_VALUE / (60 * 60 * 24 * 365);
|
||||
scale = 60 * 60 * 24 * 365;
|
||||
break;
|
||||
|
||||
case 'M':
|
||||
if (step >= st_month) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
step = st_month;
|
||||
max = NGX_MAX_INT_T_VALUE / (60 * 60 * 24 * 30);
|
||||
scale = 60 * 60 * 24 * 30;
|
||||
break;
|
||||
|
||||
case 'w':
|
||||
if (step >= st_week) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
step = st_week;
|
||||
max = NGX_MAX_INT_T_VALUE / (60 * 60 * 24 * 7);
|
||||
scale = 60 * 60 * 24 * 7;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
if (step >= st_day) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
step = st_day;
|
||||
max = NGX_MAX_INT_T_VALUE / (60 * 60 * 24);
|
||||
scale = 60 * 60 * 24;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
if (step >= st_hour) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
step = st_hour;
|
||||
max = NGX_MAX_INT_T_VALUE / (60 * 60);
|
||||
scale = 60 * 60;
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
if (p < last && *p == 's') {
|
||||
if (is_sec || step >= st_msec) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
p++;
|
||||
step = st_msec;
|
||||
max = NGX_MAX_INT_T_VALUE;
|
||||
scale = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (step >= st_min) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
step = st_min;
|
||||
max = NGX_MAX_INT_T_VALUE / 60;
|
||||
scale = 60;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
if (step >= st_sec) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
step = st_sec;
|
||||
max = NGX_MAX_INT_T_VALUE;
|
||||
scale = 1;
|
||||
break;
|
||||
|
||||
case ' ':
|
||||
if (step >= st_sec) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
step = st_last;
|
||||
max = NGX_MAX_INT_T_VALUE;
|
||||
scale = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (step != st_msec && !is_sec) {
|
||||
scale *= 1000;
|
||||
max /= 1000;
|
||||
}
|
||||
|
||||
if (value > max) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
value *= scale;
|
||||
|
||||
if (total > NGX_MAX_INT_T_VALUE - value) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
total += value;
|
||||
|
||||
value = 0;
|
||||
|
||||
while (p < last && *p == ' ') {
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!valid) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (!is_sec) {
|
||||
if (value > NGX_MAX_INT_T_VALUE / 1000) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
value *= 1000;
|
||||
}
|
||||
|
||||
if (total > NGX_MAX_INT_T_VALUE - value) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
return total + value;
|
||||
}
|
||||
21
src/core/ngx_parse.h
Normal file
21
src/core/ngx_parse.h
Normal file
@@ -0,0 +1,21 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_PARSE_H_INCLUDED_
|
||||
#define _NGX_PARSE_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
ssize_t ngx_parse_size(ngx_str_t *line);
|
||||
off_t ngx_parse_offset(ngx_str_t *line);
|
||||
ngx_int_t ngx_parse_time(ngx_str_t *line, ngx_uint_t is_sec);
|
||||
|
||||
|
||||
#endif /* _NGX_PARSE_H_INCLUDED_ */
|
||||
276
src/core/ngx_parse_time.c
Normal file
276
src/core/ngx_parse_time.c
Normal file
@@ -0,0 +1,276 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
static ngx_uint_t mday[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
||||
|
||||
time_t
|
||||
ngx_parse_http_time(u_char *value, size_t len)
|
||||
{
|
||||
u_char *p, *end;
|
||||
ngx_int_t month;
|
||||
ngx_uint_t day, year, hour, min, sec;
|
||||
uint64_t time;
|
||||
enum {
|
||||
no = 0,
|
||||
rfc822, /* Tue, 10 Nov 2002 23:50:13 */
|
||||
rfc850, /* Tuesday, 10-Dec-02 23:50:13 */
|
||||
isoc /* Tue Dec 10 23:50:13 2002 */
|
||||
} fmt;
|
||||
|
||||
fmt = 0;
|
||||
end = value + len;
|
||||
|
||||
#if (NGX_SUPPRESS_WARN)
|
||||
day = 32;
|
||||
year = 2038;
|
||||
#endif
|
||||
|
||||
for (p = value; p < end; p++) {
|
||||
if (*p == ',') {
|
||||
break;
|
||||
}
|
||||
|
||||
if (*p == ' ') {
|
||||
fmt = isoc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (p++; p < end; p++)
|
||||
if (*p != ' ') {
|
||||
break;
|
||||
}
|
||||
|
||||
if (end - p < 18) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (fmt != isoc) {
|
||||
if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9') {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
day = (*p - '0') * 10 + *(p + 1) - '0';
|
||||
p += 2;
|
||||
|
||||
if (*p == ' ') {
|
||||
if (end - p < 18) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
fmt = rfc822;
|
||||
|
||||
} else if (*p == '-') {
|
||||
fmt = rfc850;
|
||||
|
||||
} else {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
p++;
|
||||
}
|
||||
|
||||
switch (*p) {
|
||||
|
||||
case 'J':
|
||||
month = *(p + 1) == 'a' ? 0 : *(p + 2) == 'n' ? 5 : 6;
|
||||
break;
|
||||
|
||||
case 'F':
|
||||
month = 1;
|
||||
break;
|
||||
|
||||
case 'M':
|
||||
month = *(p + 2) == 'r' ? 2 : 4;
|
||||
break;
|
||||
|
||||
case 'A':
|
||||
month = *(p + 1) == 'p' ? 3 : 7;
|
||||
break;
|
||||
|
||||
case 'S':
|
||||
month = 8;
|
||||
break;
|
||||
|
||||
case 'O':
|
||||
month = 9;
|
||||
break;
|
||||
|
||||
case 'N':
|
||||
month = 10;
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
month = 11;
|
||||
break;
|
||||
|
||||
default:
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
p += 3;
|
||||
|
||||
if ((fmt == rfc822 && *p != ' ') || (fmt == rfc850 && *p != '-')) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
p++;
|
||||
|
||||
if (fmt == rfc822) {
|
||||
if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9'
|
||||
|| *(p + 2) < '0' || *(p + 2) > '9'
|
||||
|| *(p + 3) < '0' || *(p + 3) > '9')
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
year = (*p - '0') * 1000 + (*(p + 1) - '0') * 100
|
||||
+ (*(p + 2) - '0') * 10 + *(p + 3) - '0';
|
||||
p += 4;
|
||||
|
||||
} else if (fmt == rfc850) {
|
||||
if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9') {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
year = (*p - '0') * 10 + *(p + 1) - '0';
|
||||
year += (year < 70) ? 2000 : 1900;
|
||||
p += 2;
|
||||
}
|
||||
|
||||
if (fmt == isoc) {
|
||||
if (*p == ' ') {
|
||||
p++;
|
||||
}
|
||||
|
||||
if (*p < '0' || *p > '9') {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
day = *p++ - '0';
|
||||
|
||||
if (*p != ' ') {
|
||||
if (*p < '0' || *p > '9') {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
day = day * 10 + *p++ - '0';
|
||||
}
|
||||
|
||||
if (end - p < 14) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (*p++ != ' ') {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9') {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
hour = (*p - '0') * 10 + *(p + 1) - '0';
|
||||
p += 2;
|
||||
|
||||
if (*p++ != ':') {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9') {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
min = (*p - '0') * 10 + *(p + 1) - '0';
|
||||
p += 2;
|
||||
|
||||
if (*p++ != ':') {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9') {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
sec = (*p - '0') * 10 + *(p + 1) - '0';
|
||||
|
||||
if (fmt == isoc) {
|
||||
p += 2;
|
||||
|
||||
if (*p++ != ' ') {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9'
|
||||
|| *(p + 2) < '0' || *(p + 2) > '9'
|
||||
|| *(p + 3) < '0' || *(p + 3) > '9')
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
year = (*p - '0') * 1000 + (*(p + 1) - '0') * 100
|
||||
+ (*(p + 2) - '0') * 10 + *(p + 3) - '0';
|
||||
}
|
||||
|
||||
if (hour > 23 || min > 59 || sec > 59) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (day == 29 && month == 1) {
|
||||
if ((year & 3) || ((year % 100 == 0) && (year % 400) != 0)) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
} else if (day > mday[month]) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* shift new year to March 1 and start months from 1 (not 0),
|
||||
* it is needed for Gauss' formula
|
||||
*/
|
||||
|
||||
if (--month <= 0) {
|
||||
month += 12;
|
||||
year -= 1;
|
||||
}
|
||||
|
||||
/* Gauss' formula for Gregorian days since March 1, 1 BC */
|
||||
|
||||
time = (uint64_t) (
|
||||
/* days in years including leap years since March 1, 1 BC */
|
||||
|
||||
365 * year + year / 4 - year / 100 + year / 400
|
||||
|
||||
/* days before the month */
|
||||
|
||||
+ 367 * month / 12 - 30
|
||||
|
||||
/* days before the day */
|
||||
|
||||
+ day - 1
|
||||
|
||||
/*
|
||||
* 719527 days were between March 1, 1 BC and March 1, 1970,
|
||||
* 31 and 28 days were in January and February 1970
|
||||
*/
|
||||
|
||||
- 719527 + 31 + 28) * 86400 + hour * 3600 + min * 60 + sec;
|
||||
|
||||
#if (NGX_TIME_T_SIZE <= 4)
|
||||
|
||||
if (time > 0x7fffffff) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return (time_t) time;
|
||||
}
|
||||
22
src/core/ngx_parse_time.h
Normal file
22
src/core/ngx_parse_time.h
Normal file
@@ -0,0 +1,22 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_PARSE_TIME_H_INCLUDED_
|
||||
#define _NGX_PARSE_TIME_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
time_t ngx_parse_http_time(u_char *value, size_t len);
|
||||
|
||||
/* compatibility */
|
||||
#define ngx_http_parse_time(value, len) ngx_parse_http_time(value, len)
|
||||
|
||||
|
||||
#endif /* _NGX_PARSE_TIME_H_INCLUDED_ */
|
||||
168
src/core/ngx_proxy_protocol.c
Normal file
168
src/core/ngx_proxy_protocol.c
Normal file
@@ -0,0 +1,168 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Roman Arutyunyan
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
u_char *
|
||||
ngx_proxy_protocol_read(ngx_connection_t *c, u_char *buf, u_char *last)
|
||||
{
|
||||
size_t len;
|
||||
u_char ch, *p, *addr, *port;
|
||||
ngx_int_t n;
|
||||
|
||||
p = buf;
|
||||
len = last - buf;
|
||||
|
||||
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;
|
||||
addr = p;
|
||||
|
||||
for ( ;; ) {
|
||||
if (p == last) {
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
ch = *p++;
|
||||
|
||||
if (ch == ' ') {
|
||||
break;
|
||||
}
|
||||
|
||||
if (ch != ':' && ch != '.'
|
||||
&& (ch < 'a' || ch > 'f')
|
||||
&& (ch < 'A' || ch > 'F')
|
||||
&& (ch < '0' || ch > '9'))
|
||||
{
|
||||
goto invalid;
|
||||
}
|
||||
}
|
||||
|
||||
len = p - addr - 1;
|
||||
c->proxy_protocol_addr.data = ngx_pnalloc(c->pool, len);
|
||||
|
||||
if (c->proxy_protocol_addr.data == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ngx_memcpy(c->proxy_protocol_addr.data, addr, len);
|
||||
c->proxy_protocol_addr.len = len;
|
||||
|
||||
for ( ;; ) {
|
||||
if (p == last) {
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
if (*p++ == ' ') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
port = p;
|
||||
|
||||
for ( ;; ) {
|
||||
if (p == last) {
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
if (*p++ == ' ') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
len = p - port - 1;
|
||||
|
||||
n = ngx_atoi(port, len);
|
||||
|
||||
if (n < 0 || n > 65535) {
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
c->proxy_protocol_port = (in_port_t) n;
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_CORE, c->log, 0,
|
||||
"PROXY protocol address: %V %i", &c->proxy_protocol_addr, n);
|
||||
|
||||
skip:
|
||||
|
||||
for ( /* void */ ; p < last - 1; p++) {
|
||||
if (p[0] == CR && p[1] == LF) {
|
||||
return p + 2;
|
||||
}
|
||||
}
|
||||
|
||||
invalid:
|
||||
|
||||
ngx_log_error(NGX_LOG_ERR, c->log, 0,
|
||||
"broken header: \"%*s\"", (size_t) (last - buf), buf);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
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_MAX_HEADER) {
|
||||
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);
|
||||
}
|
||||
25
src/core/ngx_proxy_protocol.h
Normal file
25
src/core/ngx_proxy_protocol.h
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
/*
|
||||
* 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_MAX_HEADER 107
|
||||
|
||||
|
||||
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);
|
||||
|
||||
|
||||
#endif /* _NGX_PROXY_PROTOCOL_H_INCLUDED_ */
|
||||
80
src/core/ngx_queue.c
Normal file
80
src/core/ngx_queue.c
Normal file
@@ -0,0 +1,80 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
/*
|
||||
* 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 insertion 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, *prev, *next;
|
||||
|
||||
q = ngx_queue_head(queue);
|
||||
|
||||
if (q == ngx_queue_last(queue)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (q = ngx_queue_next(q); q != ngx_queue_sentinel(queue); q = next) {
|
||||
|
||||
prev = ngx_queue_prev(q);
|
||||
next = ngx_queue_next(q);
|
||||
|
||||
ngx_queue_remove(q);
|
||||
|
||||
do {
|
||||
if (cmp(prev, q) <= 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
prev = ngx_queue_prev(prev);
|
||||
|
||||
} while (prev != ngx_queue_sentinel(queue));
|
||||
|
||||
ngx_queue_insert_after(prev, q);
|
||||
}
|
||||
}
|
||||
112
src/core/ngx_queue.h
Normal file
112
src/core/ngx_queue.h
Normal file
@@ -0,0 +1,112 @@
|
||||
|
||||
/*
|
||||
* 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_head(h) \
|
||||
(h)->next
|
||||
|
||||
|
||||
#define ngx_queue_last(h) \
|
||||
(h)->prev
|
||||
|
||||
|
||||
#define ngx_queue_sentinel(h) \
|
||||
(h)
|
||||
|
||||
|
||||
#define ngx_queue_next(q) \
|
||||
(q)->next
|
||||
|
||||
|
||||
#define ngx_queue_prev(q) \
|
||||
(q)->prev
|
||||
|
||||
|
||||
#if (NGX_DEBUG)
|
||||
|
||||
#define ngx_queue_remove(x) \
|
||||
(x)->next->prev = (x)->prev; \
|
||||
(x)->prev->next = (x)->next; \
|
||||
(x)->prev = NULL; \
|
||||
(x)->next = NULL
|
||||
|
||||
#else
|
||||
|
||||
#define ngx_queue_remove(x) \
|
||||
(x)->next->prev = (x)->prev; \
|
||||
(x)->prev->next = (x)->next
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#define ngx_queue_split(h, q, n) \
|
||||
(n)->prev = (h)->prev; \
|
||||
(n)->prev->next = n; \
|
||||
(n)->next = q; \
|
||||
(h)->prev = (q)->prev; \
|
||||
(h)->prev->next = h; \
|
||||
(q)->prev = n;
|
||||
|
||||
|
||||
#define ngx_queue_add(h, n) \
|
||||
(h)->prev->next = (n)->next; \
|
||||
(n)->next->prev = (h)->prev; \
|
||||
(h)->prev = (n)->prev; \
|
||||
(h)->prev->next = h;
|
||||
|
||||
|
||||
#define ngx_queue_data(q, type, link) \
|
||||
(type *) ((u_char *) q - offsetof(type, link))
|
||||
|
||||
|
||||
ngx_queue_t *ngx_queue_middle(ngx_queue_t *queue);
|
||||
void ngx_queue_sort(ngx_queue_t *queue,
|
||||
ngx_int_t (*cmp)(const ngx_queue_t *, const ngx_queue_t *));
|
||||
|
||||
|
||||
#endif /* _NGX_QUEUE_H_INCLUDED_ */
|
||||
488
src/core/ngx_radix_tree.c
Normal file
488
src/core/ngx_radix_tree.c
Normal file
@@ -0,0 +1,488 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
static ngx_radix_node_t *ngx_radix_alloc(ngx_radix_tree_t *tree);
|
||||
|
||||
|
||||
ngx_radix_tree_t *
|
||||
ngx_radix_tree_create(ngx_pool_t *pool, ngx_int_t preallocate)
|
||||
{
|
||||
uint32_t key, mask, inc;
|
||||
ngx_radix_tree_t *tree;
|
||||
|
||||
tree = ngx_palloc(pool, sizeof(ngx_radix_tree_t));
|
||||
if (tree == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tree->pool = pool;
|
||||
tree->free = NULL;
|
||||
tree->start = NULL;
|
||||
tree->size = 0;
|
||||
|
||||
tree->root = ngx_radix_alloc(tree);
|
||||
if (tree->root == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tree->root->right = NULL;
|
||||
tree->root->left = NULL;
|
||||
tree->root->parent = NULL;
|
||||
tree->root->value = NGX_RADIX_NO_VALUE;
|
||||
|
||||
if (preallocate == 0) {
|
||||
return tree;
|
||||
}
|
||||
|
||||
/*
|
||||
* Preallocation of first nodes : 0, 1, 00, 01, 10, 11, 000, 001, etc.
|
||||
* increases TLB hits even if for first lookup iterations.
|
||||
* On 32-bit platforms the 7 preallocated bits takes continuous 4K,
|
||||
* 8 - 8K, 9 - 16K, etc. On 64-bit platforms the 6 preallocated bits
|
||||
* takes continuous 4K, 7 - 8K, 8 - 16K, etc. There is no sense to
|
||||
* to preallocate more than one page, because further preallocation
|
||||
* distributes the only bit per page. Instead, a random insertion
|
||||
* may distribute several bits per page.
|
||||
*
|
||||
* Thus, by default we preallocate maximum
|
||||
* 6 bits on amd64 (64-bit platform and 4K pages)
|
||||
* 7 bits on i386 (32-bit platform and 4K pages)
|
||||
* 7 bits on sparc64 in 64-bit mode (8K pages)
|
||||
* 8 bits on sparc64 in 32-bit mode (8K pages)
|
||||
*/
|
||||
|
||||
if (preallocate == -1) {
|
||||
switch (ngx_pagesize / sizeof(ngx_radix_node_t)) {
|
||||
|
||||
/* amd64 */
|
||||
case 128:
|
||||
preallocate = 6;
|
||||
break;
|
||||
|
||||
/* i386, sparc64 */
|
||||
case 256:
|
||||
preallocate = 7;
|
||||
break;
|
||||
|
||||
/* sparc64 in 32-bit mode */
|
||||
default:
|
||||
preallocate = 8;
|
||||
}
|
||||
}
|
||||
|
||||
mask = 0;
|
||||
inc = 0x80000000;
|
||||
|
||||
while (preallocate--) {
|
||||
|
||||
key = 0;
|
||||
mask >>= 1;
|
||||
mask |= 0x80000000;
|
||||
|
||||
do {
|
||||
if (ngx_radix32tree_insert(tree, key, mask, NGX_RADIX_NO_VALUE)
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
key += inc;
|
||||
|
||||
} while (key);
|
||||
|
||||
inc >>= 1;
|
||||
}
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_radix32tree_insert(ngx_radix_tree_t *tree, uint32_t key, uint32_t mask,
|
||||
uintptr_t value)
|
||||
{
|
||||
uint32_t bit;
|
||||
ngx_radix_node_t *node, *next;
|
||||
|
||||
bit = 0x80000000;
|
||||
|
||||
node = tree->root;
|
||||
next = tree->root;
|
||||
|
||||
while (bit & mask) {
|
||||
if (key & bit) {
|
||||
next = node->right;
|
||||
|
||||
} else {
|
||||
next = node->left;
|
||||
}
|
||||
|
||||
if (next == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
bit >>= 1;
|
||||
node = next;
|
||||
}
|
||||
|
||||
if (next) {
|
||||
if (node->value != NGX_RADIX_NO_VALUE) {
|
||||
return NGX_BUSY;
|
||||
}
|
||||
|
||||
node->value = value;
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
while (bit & mask) {
|
||||
next = ngx_radix_alloc(tree);
|
||||
if (next == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
next->right = NULL;
|
||||
next->left = NULL;
|
||||
next->parent = node;
|
||||
next->value = NGX_RADIX_NO_VALUE;
|
||||
|
||||
if (key & bit) {
|
||||
node->right = next;
|
||||
|
||||
} else {
|
||||
node->left = next;
|
||||
}
|
||||
|
||||
bit >>= 1;
|
||||
node = next;
|
||||
}
|
||||
|
||||
node->value = value;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_radix32tree_delete(ngx_radix_tree_t *tree, uint32_t key, uint32_t mask)
|
||||
{
|
||||
uint32_t bit;
|
||||
ngx_radix_node_t *node;
|
||||
|
||||
bit = 0x80000000;
|
||||
node = tree->root;
|
||||
|
||||
while (node && (bit & mask)) {
|
||||
if (key & bit) {
|
||||
node = node->right;
|
||||
|
||||
} else {
|
||||
node = node->left;
|
||||
}
|
||||
|
||||
bit >>= 1;
|
||||
}
|
||||
|
||||
if (node == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (node->right || node->left) {
|
||||
if (node->value != NGX_RADIX_NO_VALUE) {
|
||||
node->value = NGX_RADIX_NO_VALUE;
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
for ( ;; ) {
|
||||
if (node->parent->right == node) {
|
||||
node->parent->right = NULL;
|
||||
|
||||
} else {
|
||||
node->parent->left = NULL;
|
||||
}
|
||||
|
||||
node->right = tree->free;
|
||||
tree->free = node;
|
||||
|
||||
node = node->parent;
|
||||
|
||||
if (node->right || node->left) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (node->value != NGX_RADIX_NO_VALUE) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (node->parent == NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
uintptr_t
|
||||
ngx_radix32tree_find(ngx_radix_tree_t *tree, uint32_t key)
|
||||
{
|
||||
uint32_t bit;
|
||||
uintptr_t value;
|
||||
ngx_radix_node_t *node;
|
||||
|
||||
bit = 0x80000000;
|
||||
value = NGX_RADIX_NO_VALUE;
|
||||
node = tree->root;
|
||||
|
||||
while (node) {
|
||||
if (node->value != NGX_RADIX_NO_VALUE) {
|
||||
value = node->value;
|
||||
}
|
||||
|
||||
if (key & bit) {
|
||||
node = node->right;
|
||||
|
||||
} else {
|
||||
node = node->left;
|
||||
}
|
||||
|
||||
bit >>= 1;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
#if (NGX_HAVE_INET6)
|
||||
|
||||
ngx_int_t
|
||||
ngx_radix128tree_insert(ngx_radix_tree_t *tree, u_char *key, u_char *mask,
|
||||
uintptr_t value)
|
||||
{
|
||||
u_char bit;
|
||||
ngx_uint_t i;
|
||||
ngx_radix_node_t *node, *next;
|
||||
|
||||
i = 0;
|
||||
bit = 0x80;
|
||||
|
||||
node = tree->root;
|
||||
next = tree->root;
|
||||
|
||||
while (bit & mask[i]) {
|
||||
if (key[i] & bit) {
|
||||
next = node->right;
|
||||
|
||||
} else {
|
||||
next = node->left;
|
||||
}
|
||||
|
||||
if (next == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
bit >>= 1;
|
||||
node = next;
|
||||
|
||||
if (bit == 0) {
|
||||
if (++i == 16) {
|
||||
break;
|
||||
}
|
||||
|
||||
bit = 0x80;
|
||||
}
|
||||
}
|
||||
|
||||
if (next) {
|
||||
if (node->value != NGX_RADIX_NO_VALUE) {
|
||||
return NGX_BUSY;
|
||||
}
|
||||
|
||||
node->value = value;
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
while (bit & mask[i]) {
|
||||
next = ngx_radix_alloc(tree);
|
||||
if (next == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
next->right = NULL;
|
||||
next->left = NULL;
|
||||
next->parent = node;
|
||||
next->value = NGX_RADIX_NO_VALUE;
|
||||
|
||||
if (key[i] & bit) {
|
||||
node->right = next;
|
||||
|
||||
} else {
|
||||
node->left = next;
|
||||
}
|
||||
|
||||
bit >>= 1;
|
||||
node = next;
|
||||
|
||||
if (bit == 0) {
|
||||
if (++i == 16) {
|
||||
break;
|
||||
}
|
||||
|
||||
bit = 0x80;
|
||||
}
|
||||
}
|
||||
|
||||
node->value = value;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_radix128tree_delete(ngx_radix_tree_t *tree, u_char *key, u_char *mask)
|
||||
{
|
||||
u_char bit;
|
||||
ngx_uint_t i;
|
||||
ngx_radix_node_t *node;
|
||||
|
||||
i = 0;
|
||||
bit = 0x80;
|
||||
node = tree->root;
|
||||
|
||||
while (node && (bit & mask[i])) {
|
||||
if (key[i] & bit) {
|
||||
node = node->right;
|
||||
|
||||
} else {
|
||||
node = node->left;
|
||||
}
|
||||
|
||||
bit >>= 1;
|
||||
|
||||
if (bit == 0) {
|
||||
if (++i == 16) {
|
||||
break;
|
||||
}
|
||||
|
||||
bit = 0x80;
|
||||
}
|
||||
}
|
||||
|
||||
if (node == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (node->right || node->left) {
|
||||
if (node->value != NGX_RADIX_NO_VALUE) {
|
||||
node->value = NGX_RADIX_NO_VALUE;
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
for ( ;; ) {
|
||||
if (node->parent->right == node) {
|
||||
node->parent->right = NULL;
|
||||
|
||||
} else {
|
||||
node->parent->left = NULL;
|
||||
}
|
||||
|
||||
node->right = tree->free;
|
||||
tree->free = node;
|
||||
|
||||
node = node->parent;
|
||||
|
||||
if (node->right || node->left) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (node->value != NGX_RADIX_NO_VALUE) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (node->parent == NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
uintptr_t
|
||||
ngx_radix128tree_find(ngx_radix_tree_t *tree, u_char *key)
|
||||
{
|
||||
u_char bit;
|
||||
uintptr_t value;
|
||||
ngx_uint_t i;
|
||||
ngx_radix_node_t *node;
|
||||
|
||||
i = 0;
|
||||
bit = 0x80;
|
||||
value = NGX_RADIX_NO_VALUE;
|
||||
node = tree->root;
|
||||
|
||||
while (node) {
|
||||
if (node->value != NGX_RADIX_NO_VALUE) {
|
||||
value = node->value;
|
||||
}
|
||||
|
||||
if (key[i] & bit) {
|
||||
node = node->right;
|
||||
|
||||
} else {
|
||||
node = node->left;
|
||||
}
|
||||
|
||||
bit >>= 1;
|
||||
|
||||
if (bit == 0) {
|
||||
i++;
|
||||
bit = 0x80;
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
static ngx_radix_node_t *
|
||||
ngx_radix_alloc(ngx_radix_tree_t *tree)
|
||||
{
|
||||
ngx_radix_node_t *p;
|
||||
|
||||
if (tree->free) {
|
||||
p = tree->free;
|
||||
tree->free = tree->free->right;
|
||||
return p;
|
||||
}
|
||||
|
||||
if (tree->size < sizeof(ngx_radix_node_t)) {
|
||||
tree->start = ngx_pmemalign(tree->pool, ngx_pagesize, ngx_pagesize);
|
||||
if (tree->start == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tree->size = ngx_pagesize;
|
||||
}
|
||||
|
||||
p = (ngx_radix_node_t *) tree->start;
|
||||
tree->start += sizeof(ngx_radix_node_t);
|
||||
tree->size -= sizeof(ngx_radix_node_t);
|
||||
|
||||
return p;
|
||||
}
|
||||
55
src/core/ngx_radix_tree.h
Normal file
55
src/core/ngx_radix_tree.h
Normal file
@@ -0,0 +1,55 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_RADIX_TREE_H_INCLUDED_
|
||||
#define _NGX_RADIX_TREE_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
#define NGX_RADIX_NO_VALUE (uintptr_t) -1
|
||||
|
||||
typedef struct ngx_radix_node_s ngx_radix_node_t;
|
||||
|
||||
struct ngx_radix_node_s {
|
||||
ngx_radix_node_t *right;
|
||||
ngx_radix_node_t *left;
|
||||
ngx_radix_node_t *parent;
|
||||
uintptr_t value;
|
||||
};
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_radix_node_t *root;
|
||||
ngx_pool_t *pool;
|
||||
ngx_radix_node_t *free;
|
||||
char *start;
|
||||
size_t size;
|
||||
} ngx_radix_tree_t;
|
||||
|
||||
|
||||
ngx_radix_tree_t *ngx_radix_tree_create(ngx_pool_t *pool,
|
||||
ngx_int_t preallocate);
|
||||
|
||||
ngx_int_t ngx_radix32tree_insert(ngx_radix_tree_t *tree,
|
||||
uint32_t key, uint32_t mask, uintptr_t value);
|
||||
ngx_int_t ngx_radix32tree_delete(ngx_radix_tree_t *tree,
|
||||
uint32_t key, uint32_t mask);
|
||||
uintptr_t ngx_radix32tree_find(ngx_radix_tree_t *tree, uint32_t key);
|
||||
|
||||
#if (NGX_HAVE_INET6)
|
||||
ngx_int_t ngx_radix128tree_insert(ngx_radix_tree_t *tree,
|
||||
u_char *key, u_char *mask, uintptr_t value);
|
||||
ngx_int_t ngx_radix128tree_delete(ngx_radix_tree_t *tree,
|
||||
u_char *key, u_char *mask);
|
||||
uintptr_t ngx_radix128tree_find(ngx_radix_tree_t *tree, u_char *key);
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* _NGX_RADIX_TREE_H_INCLUDED_ */
|
||||
380
src/core/ngx_rbtree.c
Normal file
380
src/core/ngx_rbtree.c
Normal file
@@ -0,0 +1,380 @@
|
||||
|
||||
/*
|
||||
* 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 = (ngx_rbtree_node_t **) &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 = (ngx_rbtree_node_t **) &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);
|
||||
|
||||
if (subst->left != sentinel) {
|
||||
temp = subst->left;
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
82
src/core/ngx_rbtree.h
Normal file
82
src/core/ngx_rbtree.h
Normal file
@@ -0,0 +1,82 @@
|
||||
|
||||
/*
|
||||
* 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
|
||||
|
||||
|
||||
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);
|
||||
|
||||
|
||||
#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_ */
|
||||
435
src/core/ngx_regex.c
Normal file
435
src/core/ngx_regex.c
Normal file
@@ -0,0 +1,435 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_flag_t pcre_jit;
|
||||
} ngx_regex_conf_t;
|
||||
|
||||
|
||||
static void * ngx_libc_cdecl ngx_regex_malloc(size_t size);
|
||||
static void ngx_libc_cdecl ngx_regex_free(void *p);
|
||||
#if (NGX_HAVE_PCRE_JIT)
|
||||
static void ngx_pcre_free_studies(void *data);
|
||||
#endif
|
||||
|
||||
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_pcre_pool;
|
||||
static ngx_list_t *ngx_pcre_studies;
|
||||
|
||||
|
||||
void
|
||||
ngx_regex_init(void)
|
||||
{
|
||||
pcre_malloc = ngx_regex_malloc;
|
||||
pcre_free = ngx_regex_free;
|
||||
}
|
||||
|
||||
|
||||
static ngx_inline void
|
||||
ngx_regex_malloc_init(ngx_pool_t *pool)
|
||||
{
|
||||
ngx_pcre_pool = pool;
|
||||
}
|
||||
|
||||
|
||||
static ngx_inline void
|
||||
ngx_regex_malloc_done(void)
|
||||
{
|
||||
ngx_pcre_pool = NULL;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_regex_compile(ngx_regex_compile_t *rc)
|
||||
{
|
||||
int n, erroff;
|
||||
char *p;
|
||||
pcre *re;
|
||||
const char *errstr;
|
||||
ngx_regex_elt_t *elt;
|
||||
|
||||
ngx_regex_malloc_init(rc->pool);
|
||||
|
||||
re = pcre_compile((const char *) rc->pattern.data, (int) rc->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_pcre_studies != NULL) {
|
||||
elt = ngx_list_push(ngx_pcre_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;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
static void * ngx_libc_cdecl
|
||||
ngx_regex_malloc(size_t size)
|
||||
{
|
||||
ngx_pool_t *pool;
|
||||
pool = ngx_pcre_pool;
|
||||
|
||||
if (pool) {
|
||||
return ngx_palloc(pool, size);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static void ngx_libc_cdecl
|
||||
ngx_regex_free(void *p)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
#if (NGX_HAVE_PCRE_JIT)
|
||||
|
||||
static void
|
||||
ngx_pcre_free_studies(void *data)
|
||||
{
|
||||
ngx_list_t *studies = data;
|
||||
|
||||
ngx_uint_t i;
|
||||
ngx_list_part_t *part;
|
||||
ngx_regex_elt_t *elts;
|
||||
|
||||
part = &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 (elts[i].regex->extra != NULL) {
|
||||
pcre_free_study(elts[i].regex->extra);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_regex_module_init(ngx_cycle_t *cycle)
|
||||
{
|
||||
int opt;
|
||||
const char *errstr;
|
||||
ngx_uint_t i;
|
||||
ngx_list_part_t *part;
|
||||
ngx_regex_elt_t *elts;
|
||||
|
||||
opt = 0;
|
||||
|
||||
#if (NGX_HAVE_PCRE_JIT)
|
||||
{
|
||||
ngx_regex_conf_t *rcf;
|
||||
ngx_pool_cleanup_t *cln;
|
||||
|
||||
rcf = (ngx_regex_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_regex_module);
|
||||
|
||||
if (rcf->pcre_jit) {
|
||||
opt = PCRE_STUDY_JIT_COMPILE;
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
cln = ngx_pool_cleanup_add(cycle->pool, 0);
|
||||
if (cln == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
cln->handler = ngx_pcre_free_studies;
|
||||
cln->data = ngx_pcre_studies;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
ngx_regex_malloc_init(cycle->pool);
|
||||
|
||||
part = &ngx_pcre_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;
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
ngx_regex_malloc_done();
|
||||
|
||||
ngx_pcre_studies = NULL;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
ngx_regex_create_conf(ngx_cycle_t *cycle)
|
||||
{
|
||||
ngx_regex_conf_t *rcf;
|
||||
|
||||
rcf = ngx_pcalloc(cycle->pool, sizeof(ngx_regex_conf_t));
|
||||
if (rcf == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rcf->pcre_jit = NGX_CONF_UNSET;
|
||||
|
||||
ngx_pcre_studies = ngx_list_create(cycle->pool, 8, sizeof(ngx_regex_elt_t));
|
||||
if (ngx_pcre_studies == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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_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;
|
||||
}
|
||||
60
src/core/ngx_regex.h
Normal file
60
src/core/ngx_regex.h
Normal file
@@ -0,0 +1,60 @@
|
||||
|
||||
/*
|
||||
* 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>
|
||||
|
||||
#include <pcre.h>
|
||||
|
||||
|
||||
#define NGX_REGEX_NO_MATCHED PCRE_ERROR_NOMATCH /* -1 */
|
||||
|
||||
#define NGX_REGEX_CASELESS PCRE_CASELESS
|
||||
|
||||
|
||||
typedef struct {
|
||||
pcre *code;
|
||||
pcre_extra *extra;
|
||||
} ngx_regex_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_str_t pattern;
|
||||
ngx_pool_t *pool;
|
||||
ngx_int_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);
|
||||
|
||||
#define ngx_regex_exec(re, s, captures, size) \
|
||||
pcre_exec(re->code, re->extra, (const char *) (s)->data, (s)->len, 0, 0, \
|
||||
captures, size)
|
||||
#define ngx_regex_exec_n "pcre_exec()"
|
||||
|
||||
ngx_int_t ngx_regex_exec_array(ngx_array_t *a, ngx_str_t *s, ngx_log_t *log);
|
||||
|
||||
|
||||
#endif /* _NGX_REGEX_H_INCLUDED_ */
|
||||
4662
src/core/ngx_resolver.c
Normal file
4662
src/core/ngx_resolver.c
Normal file
File diff suppressed because it is too large
Load Diff
238
src/core/ngx_resolver.h
Normal file
238
src/core/ngx_resolver.h
Normal file
@@ -0,0 +1,238 @@
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
#if (NGX_HAVE_INET6)
|
||||
ngx_uint_t ipv6; /* 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;
|
||||
|
||||
ngx_uint_t quick; /* unsigned quick: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_ */
|
||||
120
src/core/ngx_rwlock.c
Normal file
120
src/core/ngx_rwlock.c
Normal file
@@ -0,0 +1,120 @@
|
||||
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
ngx_atomic_uint_t readers;
|
||||
|
||||
readers = *lock;
|
||||
|
||||
if (readers == NGX_RWLOCK_WLOCK) {
|
||||
*lock = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
for ( ;; ) {
|
||||
|
||||
if (ngx_atomic_cmp_set(lock, readers, readers - 1)) {
|
||||
return;
|
||||
}
|
||||
|
||||
readers = *lock;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
#if (NGX_HTTP_UPSTREAM_ZONE || NGX_STREAM_UPSTREAM_ZONE)
|
||||
|
||||
#error ngx_atomic_cmp_set() is not defined!
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
21
src/core/ngx_rwlock.h
Normal file
21
src/core/ngx_rwlock.h
Normal file
@@ -0,0 +1,21 @@
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
|
||||
#endif /* _NGX_RWLOCK_H_INCLUDED_ */
|
||||
294
src/core/ngx_sha1.c
Normal file
294
src/core/ngx_sha1.c
Normal file
@@ -0,0 +1,294 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Maxim Dounin
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*
|
||||
* An internal SHA1 implementation.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_sha1.h>
|
||||
|
||||
|
||||
static const u_char *ngx_sha1_body(ngx_sha1_t *ctx, const u_char *data,
|
||||
size_t size);
|
||||
|
||||
|
||||
void
|
||||
ngx_sha1_init(ngx_sha1_t *ctx)
|
||||
{
|
||||
ctx->a = 0x67452301;
|
||||
ctx->b = 0xefcdab89;
|
||||
ctx->c = 0x98badcfe;
|
||||
ctx->d = 0x10325476;
|
||||
ctx->e = 0xc3d2e1f0;
|
||||
|
||||
ctx->bytes = 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_sha1_update(ngx_sha1_t *ctx, const void *data, size_t size)
|
||||
{
|
||||
size_t used, free;
|
||||
|
||||
used = (size_t) (ctx->bytes & 0x3f);
|
||||
ctx->bytes += size;
|
||||
|
||||
if (used) {
|
||||
free = 64 - used;
|
||||
|
||||
if (size < free) {
|
||||
ngx_memcpy(&ctx->buffer[used], data, size);
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_memcpy(&ctx->buffer[used], data, free);
|
||||
data = (u_char *) data + free;
|
||||
size -= free;
|
||||
(void) ngx_sha1_body(ctx, ctx->buffer, 64);
|
||||
}
|
||||
|
||||
if (size >= 64) {
|
||||
data = ngx_sha1_body(ctx, data, size & ~(size_t) 0x3f);
|
||||
size &= 0x3f;
|
||||
}
|
||||
|
||||
ngx_memcpy(ctx->buffer, data, size);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_sha1_final(u_char result[20], ngx_sha1_t *ctx)
|
||||
{
|
||||
size_t used, free;
|
||||
|
||||
used = (size_t) (ctx->bytes & 0x3f);
|
||||
|
||||
ctx->buffer[used++] = 0x80;
|
||||
|
||||
free = 64 - used;
|
||||
|
||||
if (free < 8) {
|
||||
ngx_memzero(&ctx->buffer[used], free);
|
||||
(void) ngx_sha1_body(ctx, ctx->buffer, 64);
|
||||
used = 0;
|
||||
free = 64;
|
||||
}
|
||||
|
||||
ngx_memzero(&ctx->buffer[used], free - 8);
|
||||
|
||||
ctx->bytes <<= 3;
|
||||
ctx->buffer[56] = (u_char) (ctx->bytes >> 56);
|
||||
ctx->buffer[57] = (u_char) (ctx->bytes >> 48);
|
||||
ctx->buffer[58] = (u_char) (ctx->bytes >> 40);
|
||||
ctx->buffer[59] = (u_char) (ctx->bytes >> 32);
|
||||
ctx->buffer[60] = (u_char) (ctx->bytes >> 24);
|
||||
ctx->buffer[61] = (u_char) (ctx->bytes >> 16);
|
||||
ctx->buffer[62] = (u_char) (ctx->bytes >> 8);
|
||||
ctx->buffer[63] = (u_char) ctx->bytes;
|
||||
|
||||
(void) ngx_sha1_body(ctx, ctx->buffer, 64);
|
||||
|
||||
result[0] = (u_char) (ctx->a >> 24);
|
||||
result[1] = (u_char) (ctx->a >> 16);
|
||||
result[2] = (u_char) (ctx->a >> 8);
|
||||
result[3] = (u_char) ctx->a;
|
||||
result[4] = (u_char) (ctx->b >> 24);
|
||||
result[5] = (u_char) (ctx->b >> 16);
|
||||
result[6] = (u_char) (ctx->b >> 8);
|
||||
result[7] = (u_char) ctx->b;
|
||||
result[8] = (u_char) (ctx->c >> 24);
|
||||
result[9] = (u_char) (ctx->c >> 16);
|
||||
result[10] = (u_char) (ctx->c >> 8);
|
||||
result[11] = (u_char) ctx->c;
|
||||
result[12] = (u_char) (ctx->d >> 24);
|
||||
result[13] = (u_char) (ctx->d >> 16);
|
||||
result[14] = (u_char) (ctx->d >> 8);
|
||||
result[15] = (u_char) ctx->d;
|
||||
result[16] = (u_char) (ctx->e >> 24);
|
||||
result[17] = (u_char) (ctx->e >> 16);
|
||||
result[18] = (u_char) (ctx->e >> 8);
|
||||
result[19] = (u_char) ctx->e;
|
||||
|
||||
ngx_memzero(ctx, sizeof(*ctx));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Helper functions.
|
||||
*/
|
||||
|
||||
#define ROTATE(bits, word) (((word) << (bits)) | ((word) >> (32 - (bits))))
|
||||
|
||||
#define F1(b, c, d) (((b) & (c)) | ((~(b)) & (d)))
|
||||
#define F2(b, c, d) ((b) ^ (c) ^ (d))
|
||||
#define F3(b, c, d) (((b) & (c)) | ((b) & (d)) | ((c) & (d)))
|
||||
|
||||
#define STEP(f, a, b, c, d, e, w, t) \
|
||||
temp = ROTATE(5, (a)) + f((b), (c), (d)) + (e) + (w) + (t); \
|
||||
(e) = (d); \
|
||||
(d) = (c); \
|
||||
(c) = ROTATE(30, (b)); \
|
||||
(b) = (a); \
|
||||
(a) = temp;
|
||||
|
||||
|
||||
/*
|
||||
* GET() reads 4 input bytes in big-endian byte order and returns
|
||||
* them as uint32_t.
|
||||
*/
|
||||
|
||||
#define GET(n) \
|
||||
((uint32_t) p[n * 4 + 3] | \
|
||||
((uint32_t) p[n * 4 + 2] << 8) | \
|
||||
((uint32_t) p[n * 4 + 1] << 16) | \
|
||||
((uint32_t) p[n * 4] << 24))
|
||||
|
||||
|
||||
/*
|
||||
* This processes one or more 64-byte data blocks, but does not update
|
||||
* the bit counters. There are no alignment requirements.
|
||||
*/
|
||||
|
||||
static const u_char *
|
||||
ngx_sha1_body(ngx_sha1_t *ctx, const u_char *data, size_t size)
|
||||
{
|
||||
uint32_t a, b, c, d, e, temp;
|
||||
uint32_t saved_a, saved_b, saved_c, saved_d, saved_e;
|
||||
uint32_t words[80];
|
||||
ngx_uint_t i;
|
||||
const u_char *p;
|
||||
|
||||
p = data;
|
||||
|
||||
a = ctx->a;
|
||||
b = ctx->b;
|
||||
c = ctx->c;
|
||||
d = ctx->d;
|
||||
e = ctx->e;
|
||||
|
||||
do {
|
||||
saved_a = a;
|
||||
saved_b = b;
|
||||
saved_c = c;
|
||||
saved_d = d;
|
||||
saved_e = e;
|
||||
|
||||
/* Load data block into the words array */
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
words[i] = GET(i);
|
||||
}
|
||||
|
||||
for (i = 16; i < 80; i++) {
|
||||
words[i] = ROTATE(1, words[i - 3] ^ words[i - 8] ^ words[i - 14]
|
||||
^ words[i - 16]);
|
||||
}
|
||||
|
||||
/* Transformations */
|
||||
|
||||
STEP(F1, a, b, c, d, e, words[0], 0x5a827999);
|
||||
STEP(F1, a, b, c, d, e, words[1], 0x5a827999);
|
||||
STEP(F1, a, b, c, d, e, words[2], 0x5a827999);
|
||||
STEP(F1, a, b, c, d, e, words[3], 0x5a827999);
|
||||
STEP(F1, a, b, c, d, e, words[4], 0x5a827999);
|
||||
STEP(F1, a, b, c, d, e, words[5], 0x5a827999);
|
||||
STEP(F1, a, b, c, d, e, words[6], 0x5a827999);
|
||||
STEP(F1, a, b, c, d, e, words[7], 0x5a827999);
|
||||
STEP(F1, a, b, c, d, e, words[8], 0x5a827999);
|
||||
STEP(F1, a, b, c, d, e, words[9], 0x5a827999);
|
||||
STEP(F1, a, b, c, d, e, words[10], 0x5a827999);
|
||||
STEP(F1, a, b, c, d, e, words[11], 0x5a827999);
|
||||
STEP(F1, a, b, c, d, e, words[12], 0x5a827999);
|
||||
STEP(F1, a, b, c, d, e, words[13], 0x5a827999);
|
||||
STEP(F1, a, b, c, d, e, words[14], 0x5a827999);
|
||||
STEP(F1, a, b, c, d, e, words[15], 0x5a827999);
|
||||
STEP(F1, a, b, c, d, e, words[16], 0x5a827999);
|
||||
STEP(F1, a, b, c, d, e, words[17], 0x5a827999);
|
||||
STEP(F1, a, b, c, d, e, words[18], 0x5a827999);
|
||||
STEP(F1, a, b, c, d, e, words[19], 0x5a827999);
|
||||
|
||||
STEP(F2, a, b, c, d, e, words[20], 0x6ed9eba1);
|
||||
STEP(F2, a, b, c, d, e, words[21], 0x6ed9eba1);
|
||||
STEP(F2, a, b, c, d, e, words[22], 0x6ed9eba1);
|
||||
STEP(F2, a, b, c, d, e, words[23], 0x6ed9eba1);
|
||||
STEP(F2, a, b, c, d, e, words[24], 0x6ed9eba1);
|
||||
STEP(F2, a, b, c, d, e, words[25], 0x6ed9eba1);
|
||||
STEP(F2, a, b, c, d, e, words[26], 0x6ed9eba1);
|
||||
STEP(F2, a, b, c, d, e, words[27], 0x6ed9eba1);
|
||||
STEP(F2, a, b, c, d, e, words[28], 0x6ed9eba1);
|
||||
STEP(F2, a, b, c, d, e, words[29], 0x6ed9eba1);
|
||||
STEP(F2, a, b, c, d, e, words[30], 0x6ed9eba1);
|
||||
STEP(F2, a, b, c, d, e, words[31], 0x6ed9eba1);
|
||||
STEP(F2, a, b, c, d, e, words[32], 0x6ed9eba1);
|
||||
STEP(F2, a, b, c, d, e, words[33], 0x6ed9eba1);
|
||||
STEP(F2, a, b, c, d, e, words[34], 0x6ed9eba1);
|
||||
STEP(F2, a, b, c, d, e, words[35], 0x6ed9eba1);
|
||||
STEP(F2, a, b, c, d, e, words[36], 0x6ed9eba1);
|
||||
STEP(F2, a, b, c, d, e, words[37], 0x6ed9eba1);
|
||||
STEP(F2, a, b, c, d, e, words[38], 0x6ed9eba1);
|
||||
STEP(F2, a, b, c, d, e, words[39], 0x6ed9eba1);
|
||||
|
||||
STEP(F3, a, b, c, d, e, words[40], 0x8f1bbcdc);
|
||||
STEP(F3, a, b, c, d, e, words[41], 0x8f1bbcdc);
|
||||
STEP(F3, a, b, c, d, e, words[42], 0x8f1bbcdc);
|
||||
STEP(F3, a, b, c, d, e, words[43], 0x8f1bbcdc);
|
||||
STEP(F3, a, b, c, d, e, words[44], 0x8f1bbcdc);
|
||||
STEP(F3, a, b, c, d, e, words[45], 0x8f1bbcdc);
|
||||
STEP(F3, a, b, c, d, e, words[46], 0x8f1bbcdc);
|
||||
STEP(F3, a, b, c, d, e, words[47], 0x8f1bbcdc);
|
||||
STEP(F3, a, b, c, d, e, words[48], 0x8f1bbcdc);
|
||||
STEP(F3, a, b, c, d, e, words[49], 0x8f1bbcdc);
|
||||
STEP(F3, a, b, c, d, e, words[50], 0x8f1bbcdc);
|
||||
STEP(F3, a, b, c, d, e, words[51], 0x8f1bbcdc);
|
||||
STEP(F3, a, b, c, d, e, words[52], 0x8f1bbcdc);
|
||||
STEP(F3, a, b, c, d, e, words[53], 0x8f1bbcdc);
|
||||
STEP(F3, a, b, c, d, e, words[54], 0x8f1bbcdc);
|
||||
STEP(F3, a, b, c, d, e, words[55], 0x8f1bbcdc);
|
||||
STEP(F3, a, b, c, d, e, words[56], 0x8f1bbcdc);
|
||||
STEP(F3, a, b, c, d, e, words[57], 0x8f1bbcdc);
|
||||
STEP(F3, a, b, c, d, e, words[58], 0x8f1bbcdc);
|
||||
STEP(F3, a, b, c, d, e, words[59], 0x8f1bbcdc);
|
||||
|
||||
STEP(F2, a, b, c, d, e, words[60], 0xca62c1d6);
|
||||
STEP(F2, a, b, c, d, e, words[61], 0xca62c1d6);
|
||||
STEP(F2, a, b, c, d, e, words[62], 0xca62c1d6);
|
||||
STEP(F2, a, b, c, d, e, words[63], 0xca62c1d6);
|
||||
STEP(F2, a, b, c, d, e, words[64], 0xca62c1d6);
|
||||
STEP(F2, a, b, c, d, e, words[65], 0xca62c1d6);
|
||||
STEP(F2, a, b, c, d, e, words[66], 0xca62c1d6);
|
||||
STEP(F2, a, b, c, d, e, words[67], 0xca62c1d6);
|
||||
STEP(F2, a, b, c, d, e, words[68], 0xca62c1d6);
|
||||
STEP(F2, a, b, c, d, e, words[69], 0xca62c1d6);
|
||||
STEP(F2, a, b, c, d, e, words[70], 0xca62c1d6);
|
||||
STEP(F2, a, b, c, d, e, words[71], 0xca62c1d6);
|
||||
STEP(F2, a, b, c, d, e, words[72], 0xca62c1d6);
|
||||
STEP(F2, a, b, c, d, e, words[73], 0xca62c1d6);
|
||||
STEP(F2, a, b, c, d, e, words[74], 0xca62c1d6);
|
||||
STEP(F2, a, b, c, d, e, words[75], 0xca62c1d6);
|
||||
STEP(F2, a, b, c, d, e, words[76], 0xca62c1d6);
|
||||
STEP(F2, a, b, c, d, e, words[77], 0xca62c1d6);
|
||||
STEP(F2, a, b, c, d, e, words[78], 0xca62c1d6);
|
||||
STEP(F2, a, b, c, d, e, words[79], 0xca62c1d6);
|
||||
|
||||
a += saved_a;
|
||||
b += saved_b;
|
||||
c += saved_c;
|
||||
d += saved_d;
|
||||
e += saved_e;
|
||||
|
||||
p += 64;
|
||||
|
||||
} while (size -= 64);
|
||||
|
||||
ctx->a = a;
|
||||
ctx->b = b;
|
||||
ctx->c = c;
|
||||
ctx->d = d;
|
||||
ctx->e = e;
|
||||
|
||||
return p;
|
||||
}
|
||||
28
src/core/ngx_sha1.h
Normal file
28
src/core/ngx_sha1.h
Normal file
@@ -0,0 +1,28 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_SHA1_H_INCLUDED_
|
||||
#define _NGX_SHA1_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint64_t bytes;
|
||||
uint32_t a, b, c, d, e, f;
|
||||
u_char buffer[64];
|
||||
} ngx_sha1_t;
|
||||
|
||||
|
||||
void ngx_sha1_init(ngx_sha1_t *ctx);
|
||||
void ngx_sha1_update(ngx_sha1_t *ctx, const void *data, size_t size);
|
||||
void ngx_sha1_final(u_char result[20], ngx_sha1_t *ctx);
|
||||
|
||||
|
||||
#endif /* _NGX_SHA1_H_INCLUDED_ */
|
||||
310
src/core/ngx_shmtx.c
Normal file
310
src/core/ngx_shmtx.c
Normal file
@@ -0,0 +1,310 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
#if (NGX_HAVE_ATOMIC_OPS)
|
||||
|
||||
|
||||
static void ngx_shmtx_wakeup(ngx_shmtx_t *mtx);
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_shmtx_create(ngx_shmtx_t *mtx, ngx_shmtx_sh_t *addr, u_char *name)
|
||||
{
|
||||
mtx->lock = &addr->lock;
|
||||
|
||||
if (mtx->spin == (ngx_uint_t) -1) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
mtx->spin = 2048;
|
||||
|
||||
#if (NGX_HAVE_POSIX_SEM)
|
||||
|
||||
mtx->wait = &addr->wait;
|
||||
|
||||
if (sem_init(&mtx->sem, 1, 0) == -1) {
|
||||
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_errno,
|
||||
"sem_init() failed");
|
||||
} else {
|
||||
mtx->semaphore = 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_shmtx_destroy(ngx_shmtx_t *mtx)
|
||||
{
|
||||
#if (NGX_HAVE_POSIX_SEM)
|
||||
|
||||
if (mtx->semaphore) {
|
||||
if (sem_destroy(&mtx->sem) == -1) {
|
||||
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_errno,
|
||||
"sem_destroy() failed");
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
ngx_uint_t
|
||||
ngx_shmtx_trylock(ngx_shmtx_t *mtx)
|
||||
{
|
||||
return (*mtx->lock == 0 && ngx_atomic_cmp_set(mtx->lock, 0, ngx_pid));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_shmtx_lock(ngx_shmtx_t *mtx)
|
||||
{
|
||||
ngx_uint_t i, n;
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, "shmtx lock");
|
||||
|
||||
for ( ;; ) {
|
||||
|
||||
if (*mtx->lock == 0 && ngx_atomic_cmp_set(mtx->lock, 0, ngx_pid)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ngx_ncpu > 1) {
|
||||
|
||||
for (n = 1; n < mtx->spin; n <<= 1) {
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
ngx_cpu_pause();
|
||||
}
|
||||
|
||||
if (*mtx->lock == 0
|
||||
&& ngx_atomic_cmp_set(mtx->lock, 0, ngx_pid))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if (NGX_HAVE_POSIX_SEM)
|
||||
|
||||
if (mtx->semaphore) {
|
||||
(void) ngx_atomic_fetch_add(mtx->wait, 1);
|
||||
|
||||
if (*mtx->lock == 0 && ngx_atomic_cmp_set(mtx->lock, 0, ngx_pid)) {
|
||||
(void) ngx_atomic_fetch_add(mtx->wait, -1);
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
|
||||
"shmtx wait %uA", *mtx->wait);
|
||||
|
||||
while (sem_wait(&mtx->sem) == -1) {
|
||||
ngx_err_t err;
|
||||
|
||||
err = ngx_errno;
|
||||
|
||||
if (err != NGX_EINTR) {
|
||||
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, err,
|
||||
"sem_wait() failed while waiting on shmtx");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
|
||||
"shmtx awoke");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
ngx_sched_yield();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_shmtx_unlock(ngx_shmtx_t *mtx)
|
||||
{
|
||||
if (mtx->spin != (ngx_uint_t) -1) {
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, "shmtx unlock");
|
||||
}
|
||||
|
||||
if (ngx_atomic_cmp_set(mtx->lock, ngx_pid, 0)) {
|
||||
ngx_shmtx_wakeup(mtx);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ngx_uint_t
|
||||
ngx_shmtx_force_unlock(ngx_shmtx_t *mtx, ngx_pid_t pid)
|
||||
{
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
|
||||
"shmtx forced unlock");
|
||||
|
||||
if (ngx_atomic_cmp_set(mtx->lock, pid, 0)) {
|
||||
ngx_shmtx_wakeup(mtx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_shmtx_wakeup(ngx_shmtx_t *mtx)
|
||||
{
|
||||
#if (NGX_HAVE_POSIX_SEM)
|
||||
ngx_atomic_uint_t wait;
|
||||
|
||||
if (!mtx->semaphore) {
|
||||
return;
|
||||
}
|
||||
|
||||
for ( ;; ) {
|
||||
|
||||
wait = *mtx->wait;
|
||||
|
||||
if ((ngx_atomic_int_t) wait <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ngx_atomic_cmp_set(mtx->wait, wait, wait - 1)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
|
||||
"shmtx wake %uA", wait);
|
||||
|
||||
if (sem_post(&mtx->sem) == -1) {
|
||||
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_errno,
|
||||
"sem_post() failed while wake shmtx");
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_shmtx_create(ngx_shmtx_t *mtx, ngx_shmtx_sh_t *addr, u_char *name)
|
||||
{
|
||||
if (mtx->name) {
|
||||
|
||||
if (ngx_strcmp(name, mtx->name) == 0) {
|
||||
mtx->name = name;
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
ngx_shmtx_destroy(mtx);
|
||||
}
|
||||
|
||||
mtx->fd = ngx_open_file(name, NGX_FILE_RDWR, NGX_FILE_CREATE_OR_OPEN,
|
||||
NGX_FILE_DEFAULT_ACCESS);
|
||||
|
||||
if (mtx->fd == NGX_INVALID_FILE) {
|
||||
ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno,
|
||||
ngx_open_file_n " \"%s\" failed", name);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (ngx_delete_file(name) == NGX_FILE_ERROR) {
|
||||
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_errno,
|
||||
ngx_delete_file_n " \"%s\" failed", name);
|
||||
}
|
||||
|
||||
mtx->name = name;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_shmtx_destroy(ngx_shmtx_t *mtx)
|
||||
{
|
||||
if (ngx_close_file(mtx->fd) == NGX_FILE_ERROR) {
|
||||
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_errno,
|
||||
ngx_close_file_n " \"%s\" failed", mtx->name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ngx_uint_t
|
||||
ngx_shmtx_trylock(ngx_shmtx_t *mtx)
|
||||
{
|
||||
ngx_err_t err;
|
||||
|
||||
err = ngx_trylock_fd(mtx->fd);
|
||||
|
||||
if (err == 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (err == NGX_EAGAIN) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if __osf__ /* Tru64 UNIX */
|
||||
|
||||
if (err == NGX_EACCES) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
ngx_log_abort(err, ngx_trylock_fd_n " %s failed", mtx->name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_shmtx_lock(ngx_shmtx_t *mtx)
|
||||
{
|
||||
ngx_err_t err;
|
||||
|
||||
err = ngx_lock_fd(mtx->fd);
|
||||
|
||||
if (err == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_log_abort(err, ngx_lock_fd_n " %s failed", mtx->name);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_shmtx_unlock(ngx_shmtx_t *mtx)
|
||||
{
|
||||
ngx_err_t err;
|
||||
|
||||
err = ngx_unlock_fd(mtx->fd);
|
||||
|
||||
if (err == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_log_abort(err, ngx_unlock_fd_n " %s failed", mtx->name);
|
||||
}
|
||||
|
||||
|
||||
ngx_uint_t
|
||||
ngx_shmtx_force_unlock(ngx_shmtx_t *mtx, ngx_pid_t pid)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
49
src/core/ngx_shmtx.h
Normal file
49
src/core/ngx_shmtx.h
Normal file
@@ -0,0 +1,49 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_SHMTX_H_INCLUDED_
|
||||
#define _NGX_SHMTX_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_atomic_t lock;
|
||||
#if (NGX_HAVE_POSIX_SEM)
|
||||
ngx_atomic_t wait;
|
||||
#endif
|
||||
} ngx_shmtx_sh_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
#if (NGX_HAVE_ATOMIC_OPS)
|
||||
ngx_atomic_t *lock;
|
||||
#if (NGX_HAVE_POSIX_SEM)
|
||||
ngx_atomic_t *wait;
|
||||
ngx_uint_t semaphore;
|
||||
sem_t sem;
|
||||
#endif
|
||||
#else
|
||||
ngx_fd_t fd;
|
||||
u_char *name;
|
||||
#endif
|
||||
ngx_uint_t spin;
|
||||
} ngx_shmtx_t;
|
||||
|
||||
|
||||
ngx_int_t ngx_shmtx_create(ngx_shmtx_t *mtx, ngx_shmtx_sh_t *addr,
|
||||
u_char *name);
|
||||
void ngx_shmtx_destroy(ngx_shmtx_t *mtx);
|
||||
ngx_uint_t ngx_shmtx_trylock(ngx_shmtx_t *mtx);
|
||||
void ngx_shmtx_lock(ngx_shmtx_t *mtx);
|
||||
void ngx_shmtx_unlock(ngx_shmtx_t *mtx);
|
||||
ngx_uint_t ngx_shmtx_force_unlock(ngx_shmtx_t *mtx, ngx_pid_t pid);
|
||||
|
||||
|
||||
#endif /* _NGX_SHMTX_H_INCLUDED_ */
|
||||
806
src/core/ngx_slab.c
Normal file
806
src/core/ngx_slab.c
Normal file
@@ -0,0 +1,806 @@
|
||||
|
||||
/*
|
||||
* 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_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;
|
||||
|
||||
/* STUB */
|
||||
if (ngx_slab_max_size == 0) {
|
||||
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 */
|
||||
}
|
||||
}
|
||||
/**/
|
||||
|
||||
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, n, m, mask, *bitmap;
|
||||
ngx_uint_t i, 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) / (sizeof(uintptr_t) * 8);
|
||||
|
||||
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 * sizeof(uintptr_t) * 8 + 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 */
|
||||
bitmap[0] = ((uintptr_t) 2 << n) - 1;
|
||||
|
||||
map = (ngx_pagesize >> shift) / (sizeof(uintptr_t) * 8);
|
||||
|
||||
for (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 += sizeof(uintptr_t) * 8;
|
||||
|
||||
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 % (sizeof(uintptr_t) * 8));
|
||||
n /= sizeof(uintptr_t) * 8;
|
||||
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;
|
||||
}
|
||||
|
||||
if (bitmap[0] & ~(((uintptr_t) 1 << n) - 1)) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
map = (ngx_pagesize >> shift) / (sizeof(uintptr_t) * 8);
|
||||
|
||||
for (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 -= sizeof(uintptr_t) * 8;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
n = ((u_char *) p - pool->start) >> ngx_pagesize_shift;
|
||||
size = slab & ~NGX_SLAB_PAGE_START;
|
||||
|
||||
ngx_slab_free_pages(pool, &pool->pages[n], 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);
|
||||
}
|
||||
71
src/core/ngx_slab.h
Normal file
71
src/core/ngx_slab.h
Normal file
@@ -0,0 +1,71 @@
|
||||
|
||||
/*
|
||||
* 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_init(ngx_slab_pool_t *pool);
|
||||
void *ngx_slab_alloc(ngx_slab_pool_t *pool, size_t size);
|
||||
void *ngx_slab_alloc_locked(ngx_slab_pool_t *pool, size_t size);
|
||||
void *ngx_slab_calloc(ngx_slab_pool_t *pool, size_t size);
|
||||
void *ngx_slab_calloc_locked(ngx_slab_pool_t *pool, size_t size);
|
||||
void ngx_slab_free(ngx_slab_pool_t *pool, void *p);
|
||||
void ngx_slab_free_locked(ngx_slab_pool_t *pool, void *p);
|
||||
|
||||
|
||||
#endif /* _NGX_SLAB_H_INCLUDED_ */
|
||||
53
src/core/ngx_spinlock.c
Normal file
53
src/core/ngx_spinlock.c
Normal file
@@ -0,0 +1,53 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
void
|
||||
ngx_spinlock(ngx_atomic_t *lock, ngx_atomic_int_t value, ngx_uint_t spin)
|
||||
{
|
||||
|
||||
#if (NGX_HAVE_ATOMIC_OPS)
|
||||
|
||||
ngx_uint_t i, n;
|
||||
|
||||
for ( ;; ) {
|
||||
|
||||
if (*lock == 0 && ngx_atomic_cmp_set(lock, 0, value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ngx_ncpu > 1) {
|
||||
|
||||
for (n = 1; n < spin; n <<= 1) {
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
ngx_cpu_pause();
|
||||
}
|
||||
|
||||
if (*lock == 0 && ngx_atomic_cmp_set(lock, 0, value)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ngx_sched_yield();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#if (NGX_THREADS)
|
||||
|
||||
#error ngx_spinlock() or ngx_atomic_cmp_set() are not defined !
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
1976
src/core/ngx_string.c
Normal file
1976
src/core/ngx_string.c
Normal file
File diff suppressed because it is too large
Load Diff
234
src/core/ngx_string.h
Normal file
234
src/core/ngx_string.h
Normal file
@@ -0,0 +1,234 @@
|
||||
|
||||
/*
|
||||
* 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)
|
||||
|
||||
#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)
|
||||
|
||||
|
||||
#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((const char *) s1, (const char *) 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_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_ */
|
||||
382
src/core/ngx_syslog.c
Normal file
382
src/core/ngx_syslog.c
Normal file
@@ -0,0 +1,382 @@
|
||||
|
||||
/*
|
||||
* 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 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)
|
||||
{
|
||||
peer->pool = cf->pool;
|
||||
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->conn.fd = (ngx_socket_t) -1;
|
||||
|
||||
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,
|
||||
&ngx_cycle->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->conn.fd == (ngx_socket_t) -1) {
|
||||
if (ngx_syslog_init_peer(peer) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* log syslog socket events with valid log */
|
||||
peer->conn.log = ngx_cycle->log;
|
||||
|
||||
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 (NGX_HAVE_UNIX_DOMAIN)
|
||||
|
||||
if (n == NGX_ERROR && peer->server.sockaddr->sa_family == AF_UNIX) {
|
||||
|
||||
if (ngx_close_socket(peer->conn.fd) == -1) {
|
||||
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno,
|
||||
ngx_close_socket_n " failed");
|
||||
}
|
||||
|
||||
peer->conn.fd = (ngx_socket_t) -1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_syslog_init_peer(ngx_syslog_peer_t *peer)
|
||||
{
|
||||
ngx_socket_t fd;
|
||||
ngx_pool_cleanup_t *cln;
|
||||
|
||||
peer->conn.read = &ngx_syslog_dummy_event;
|
||||
peer->conn.write = &ngx_syslog_dummy_event;
|
||||
|
||||
ngx_syslog_dummy_event.log = &ngx_syslog_dummy_log;
|
||||
|
||||
fd = ngx_socket(peer->server.sockaddr->sa_family, SOCK_DGRAM, 0);
|
||||
if (fd == (ngx_socket_t) -1) {
|
||||
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno,
|
||||
ngx_socket_n " failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (ngx_nonblocking(fd) == -1) {
|
||||
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->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, ngx_cycle->log, ngx_socket_errno,
|
||||
"connect() failed");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
cln = ngx_pool_cleanup_add(peer->pool, 0);
|
||||
if (cln == NULL) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
cln->data = peer;
|
||||
cln->handler = ngx_syslog_cleanup;
|
||||
|
||||
peer->conn.fd = fd;
|
||||
|
||||
/* 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, ngx_cycle->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, ngx_cycle->log, ngx_socket_errno,
|
||||
ngx_close_socket_n " failed");
|
||||
}
|
||||
}
|
||||
31
src/core/ngx_syslog.h
Normal file
31
src/core/ngx_syslog.h
Normal file
@@ -0,0 +1,31 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_SYSLOG_H_INCLUDED_
|
||||
#define _NGX_SYSLOG_H_INCLUDED_
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_pool_t *pool;
|
||||
ngx_uint_t facility;
|
||||
ngx_uint_t severity;
|
||||
ngx_str_t tag;
|
||||
|
||||
ngx_addr_t server;
|
||||
ngx_connection_t conn;
|
||||
unsigned busy:1;
|
||||
unsigned nohostname:1;
|
||||
} ngx_syslog_peer_t;
|
||||
|
||||
|
||||
char *ngx_syslog_process_conf(ngx_conf_t *cf, ngx_syslog_peer_t *peer);
|
||||
u_char *ngx_syslog_add_header(ngx_syslog_peer_t *peer, u_char *buf);
|
||||
void ngx_syslog_writer(ngx_log_t *log, ngx_uint_t level, u_char *buf,
|
||||
size_t len);
|
||||
ssize_t ngx_syslog_send(ngx_syslog_peer_t *peer, u_char *buf, size_t len);
|
||||
|
||||
|
||||
#endif /* _NGX_SYSLOG_H_INCLUDED_ */
|
||||
641
src/core/ngx_thread_pool.c
Normal file
641
src/core/ngx_thread_pool.c
Normal file
@@ -0,0 +1,641 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Nginx, Inc.
|
||||
* Copyright (C) Valentin V. Bartenev
|
||||
* Copyright (C) Ruslan Ermilov
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_thread_pool.h>
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_array_t pools;
|
||||
} ngx_thread_pool_conf_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_thread_task_t *first;
|
||||
ngx_thread_task_t **last;
|
||||
} ngx_thread_pool_queue_t;
|
||||
|
||||
#define ngx_thread_pool_queue_init(q) \
|
||||
(q)->first = NULL; \
|
||||
(q)->last = &(q)->first
|
||||
|
||||
|
||||
struct ngx_thread_pool_s {
|
||||
ngx_thread_mutex_t mtx;
|
||||
ngx_thread_pool_queue_t queue;
|
||||
ngx_int_t waiting;
|
||||
ngx_thread_cond_t cond;
|
||||
|
||||
ngx_log_t *log;
|
||||
|
||||
ngx_str_t name;
|
||||
ngx_uint_t threads;
|
||||
ngx_int_t max_queue;
|
||||
|
||||
u_char *file;
|
||||
ngx_uint_t line;
|
||||
};
|
||||
|
||||
|
||||
static ngx_int_t ngx_thread_pool_init(ngx_thread_pool_t *tp, ngx_log_t *log,
|
||||
ngx_pool_t *pool);
|
||||
static void ngx_thread_pool_destroy(ngx_thread_pool_t *tp);
|
||||
static void ngx_thread_pool_exit_handler(void *data, ngx_log_t *log);
|
||||
|
||||
static void *ngx_thread_pool_cycle(void *data);
|
||||
static void ngx_thread_pool_handler(ngx_event_t *ev);
|
||||
|
||||
static char *ngx_thread_pool(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
|
||||
|
||||
static void *ngx_thread_pool_create_conf(ngx_cycle_t *cycle);
|
||||
static char *ngx_thread_pool_init_conf(ngx_cycle_t *cycle, void *conf);
|
||||
|
||||
static ngx_int_t ngx_thread_pool_init_worker(ngx_cycle_t *cycle);
|
||||
static void ngx_thread_pool_exit_worker(ngx_cycle_t *cycle);
|
||||
|
||||
|
||||
static ngx_command_t ngx_thread_pool_commands[] = {
|
||||
|
||||
{ ngx_string("thread_pool"),
|
||||
NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE23,
|
||||
ngx_thread_pool,
|
||||
0,
|
||||
0,
|
||||
NULL },
|
||||
|
||||
ngx_null_command
|
||||
};
|
||||
|
||||
|
||||
static ngx_core_module_t ngx_thread_pool_module_ctx = {
|
||||
ngx_string("thread_pool"),
|
||||
ngx_thread_pool_create_conf,
|
||||
ngx_thread_pool_init_conf
|
||||
};
|
||||
|
||||
|
||||
ngx_module_t ngx_thread_pool_module = {
|
||||
NGX_MODULE_V1,
|
||||
&ngx_thread_pool_module_ctx, /* module context */
|
||||
ngx_thread_pool_commands, /* module directives */
|
||||
NGX_CORE_MODULE, /* module type */
|
||||
NULL, /* init master */
|
||||
NULL, /* init module */
|
||||
ngx_thread_pool_init_worker, /* init process */
|
||||
NULL, /* init thread */
|
||||
NULL, /* exit thread */
|
||||
ngx_thread_pool_exit_worker, /* exit process */
|
||||
NULL, /* exit master */
|
||||
NGX_MODULE_V1_PADDING
|
||||
};
|
||||
|
||||
|
||||
static ngx_str_t ngx_thread_pool_default = ngx_string("default");
|
||||
|
||||
static ngx_uint_t ngx_thread_pool_task_id;
|
||||
static ngx_atomic_t ngx_thread_pool_done_lock;
|
||||
static ngx_thread_pool_queue_t ngx_thread_pool_done;
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_thread_pool_init(ngx_thread_pool_t *tp, ngx_log_t *log, ngx_pool_t *pool)
|
||||
{
|
||||
int err;
|
||||
pthread_t tid;
|
||||
ngx_uint_t n;
|
||||
pthread_attr_t attr;
|
||||
|
||||
if (ngx_notify == NULL) {
|
||||
ngx_log_error(NGX_LOG_ALERT, log, 0,
|
||||
"the configured event method cannot be used with thread pools");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_thread_pool_queue_init(&tp->queue);
|
||||
|
||||
if (ngx_thread_mutex_create(&tp->mtx, log) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (ngx_thread_cond_create(&tp->cond, log) != NGX_OK) {
|
||||
(void) ngx_thread_mutex_destroy(&tp->mtx, log);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
tp->log = log;
|
||||
|
||||
err = pthread_attr_init(&attr);
|
||||
if (err) {
|
||||
ngx_log_error(NGX_LOG_ALERT, log, err,
|
||||
"pthread_attr_init() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||
if (err) {
|
||||
ngx_log_error(NGX_LOG_ALERT, log, err,
|
||||
"pthread_attr_setdetachstate() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
#if 0
|
||||
err = pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN);
|
||||
if (err) {
|
||||
ngx_log_error(NGX_LOG_ALERT, log, err,
|
||||
"pthread_attr_setstacksize() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
for (n = 0; n < tp->threads; n++) {
|
||||
err = pthread_create(&tid, &attr, ngx_thread_pool_cycle, tp);
|
||||
if (err) {
|
||||
ngx_log_error(NGX_LOG_ALERT, log, err,
|
||||
"pthread_create() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
(void) pthread_attr_destroy(&attr);
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_thread_pool_destroy(ngx_thread_pool_t *tp)
|
||||
{
|
||||
ngx_uint_t n;
|
||||
ngx_thread_task_t task;
|
||||
volatile ngx_uint_t lock;
|
||||
|
||||
ngx_memzero(&task, sizeof(ngx_thread_task_t));
|
||||
|
||||
task.handler = ngx_thread_pool_exit_handler;
|
||||
task.ctx = (void *) &lock;
|
||||
|
||||
for (n = 0; n < tp->threads; n++) {
|
||||
lock = 1;
|
||||
|
||||
if (ngx_thread_task_post(tp, &task) != NGX_OK) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (lock) {
|
||||
ngx_sched_yield();
|
||||
}
|
||||
|
||||
task.event.active = 0;
|
||||
}
|
||||
|
||||
(void) ngx_thread_cond_destroy(&tp->cond, tp->log);
|
||||
|
||||
(void) ngx_thread_mutex_destroy(&tp->mtx, tp->log);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_thread_pool_exit_handler(void *data, ngx_log_t *log)
|
||||
{
|
||||
ngx_uint_t *lock = data;
|
||||
|
||||
*lock = 0;
|
||||
|
||||
pthread_exit(0);
|
||||
}
|
||||
|
||||
|
||||
ngx_thread_task_t *
|
||||
ngx_thread_task_alloc(ngx_pool_t *pool, size_t size)
|
||||
{
|
||||
ngx_thread_task_t *task;
|
||||
|
||||
task = ngx_pcalloc(pool, sizeof(ngx_thread_task_t) + size);
|
||||
if (task == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
task->ctx = task + 1;
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_thread_task_post(ngx_thread_pool_t *tp, ngx_thread_task_t *task)
|
||||
{
|
||||
if (task->event.active) {
|
||||
ngx_log_error(NGX_LOG_ALERT, tp->log, 0,
|
||||
"task #%ui already active", task->id);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (ngx_thread_mutex_lock(&tp->mtx, tp->log) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (tp->waiting >= tp->max_queue) {
|
||||
(void) ngx_thread_mutex_unlock(&tp->mtx, tp->log);
|
||||
|
||||
ngx_log_error(NGX_LOG_ERR, tp->log, 0,
|
||||
"thread pool \"%V\" queue overflow: %i tasks waiting",
|
||||
&tp->name, tp->waiting);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
task->event.active = 1;
|
||||
|
||||
task->id = ngx_thread_pool_task_id++;
|
||||
task->next = NULL;
|
||||
|
||||
if (ngx_thread_cond_signal(&tp->cond, tp->log) != NGX_OK) {
|
||||
(void) ngx_thread_mutex_unlock(&tp->mtx, tp->log);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
*tp->queue.last = task;
|
||||
tp->queue.last = &task->next;
|
||||
|
||||
tp->waiting++;
|
||||
|
||||
(void) ngx_thread_mutex_unlock(&tp->mtx, tp->log);
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_CORE, tp->log, 0,
|
||||
"task #%ui added to thread pool \"%V\"",
|
||||
task->id, &tp->name);
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
ngx_thread_pool_cycle(void *data)
|
||||
{
|
||||
ngx_thread_pool_t *tp = data;
|
||||
|
||||
int err;
|
||||
sigset_t set;
|
||||
ngx_thread_task_t *task;
|
||||
|
||||
#if 0
|
||||
ngx_time_update();
|
||||
#endif
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_CORE, tp->log, 0,
|
||||
"thread in pool \"%V\" started", &tp->name);
|
||||
|
||||
sigfillset(&set);
|
||||
|
||||
sigdelset(&set, SIGILL);
|
||||
sigdelset(&set, SIGFPE);
|
||||
sigdelset(&set, SIGSEGV);
|
||||
sigdelset(&set, SIGBUS);
|
||||
|
||||
err = pthread_sigmask(SIG_BLOCK, &set, NULL);
|
||||
if (err) {
|
||||
ngx_log_error(NGX_LOG_ALERT, tp->log, err, "pthread_sigmask() failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for ( ;; ) {
|
||||
if (ngx_thread_mutex_lock(&tp->mtx, tp->log) != NGX_OK) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* the number may become negative */
|
||||
tp->waiting--;
|
||||
|
||||
while (tp->queue.first == NULL) {
|
||||
if (ngx_thread_cond_wait(&tp->cond, &tp->mtx, tp->log)
|
||||
!= NGX_OK)
|
||||
{
|
||||
(void) ngx_thread_mutex_unlock(&tp->mtx, tp->log);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
task = tp->queue.first;
|
||||
tp->queue.first = task->next;
|
||||
|
||||
if (tp->queue.first == NULL) {
|
||||
tp->queue.last = &tp->queue.first;
|
||||
}
|
||||
|
||||
if (ngx_thread_mutex_unlock(&tp->mtx, tp->log) != NGX_OK) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if 0
|
||||
ngx_time_update();
|
||||
#endif
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_CORE, tp->log, 0,
|
||||
"run task #%ui in thread pool \"%V\"",
|
||||
task->id, &tp->name);
|
||||
|
||||
task->handler(task->ctx, tp->log);
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_CORE, tp->log, 0,
|
||||
"complete task #%ui in thread pool \"%V\"",
|
||||
task->id, &tp->name);
|
||||
|
||||
task->next = NULL;
|
||||
|
||||
ngx_spinlock(&ngx_thread_pool_done_lock, 1, 2048);
|
||||
|
||||
*ngx_thread_pool_done.last = task;
|
||||
ngx_thread_pool_done.last = &task->next;
|
||||
|
||||
ngx_memory_barrier();
|
||||
|
||||
ngx_unlock(&ngx_thread_pool_done_lock);
|
||||
|
||||
(void) ngx_notify(ngx_thread_pool_handler);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_thread_pool_handler(ngx_event_t *ev)
|
||||
{
|
||||
ngx_event_t *event;
|
||||
ngx_thread_task_t *task;
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_CORE, ev->log, 0, "thread pool handler");
|
||||
|
||||
ngx_spinlock(&ngx_thread_pool_done_lock, 1, 2048);
|
||||
|
||||
task = ngx_thread_pool_done.first;
|
||||
ngx_thread_pool_done.first = NULL;
|
||||
ngx_thread_pool_done.last = &ngx_thread_pool_done.first;
|
||||
|
||||
ngx_memory_barrier();
|
||||
|
||||
ngx_unlock(&ngx_thread_pool_done_lock);
|
||||
|
||||
while (task) {
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_CORE, ev->log, 0,
|
||||
"run completion handler for task #%ui", task->id);
|
||||
|
||||
event = &task->event;
|
||||
task = task->next;
|
||||
|
||||
event->complete = 1;
|
||||
event->active = 0;
|
||||
|
||||
event->handler(event);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
ngx_thread_pool_create_conf(ngx_cycle_t *cycle)
|
||||
{
|
||||
ngx_thread_pool_conf_t *tcf;
|
||||
|
||||
tcf = ngx_pcalloc(cycle->pool, sizeof(ngx_thread_pool_conf_t));
|
||||
if (tcf == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ngx_array_init(&tcf->pools, cycle->pool, 4,
|
||||
sizeof(ngx_thread_pool_t *))
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return tcf;
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
ngx_thread_pool_init_conf(ngx_cycle_t *cycle, void *conf)
|
||||
{
|
||||
ngx_thread_pool_conf_t *tcf = conf;
|
||||
|
||||
ngx_uint_t i;
|
||||
ngx_thread_pool_t **tpp;
|
||||
|
||||
tpp = tcf->pools.elts;
|
||||
|
||||
for (i = 0; i < tcf->pools.nelts; i++) {
|
||||
|
||||
if (tpp[i]->threads) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tpp[i]->name.len == ngx_thread_pool_default.len
|
||||
&& ngx_strncmp(tpp[i]->name.data, ngx_thread_pool_default.data,
|
||||
ngx_thread_pool_default.len)
|
||||
== 0)
|
||||
{
|
||||
tpp[i]->threads = 32;
|
||||
tpp[i]->max_queue = 65536;
|
||||
continue;
|
||||
}
|
||||
|
||||
ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
|
||||
"unknown thread pool \"%V\" in %s:%ui",
|
||||
&tpp[i]->name, tpp[i]->file, tpp[i]->line);
|
||||
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
ngx_thread_pool(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
||||
{
|
||||
ngx_str_t *value;
|
||||
ngx_uint_t i;
|
||||
ngx_thread_pool_t *tp;
|
||||
|
||||
value = cf->args->elts;
|
||||
|
||||
tp = ngx_thread_pool_add(cf, &value[1]);
|
||||
|
||||
if (tp == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
if (tp->threads) {
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"duplicate thread pool \"%V\"", &tp->name);
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
tp->max_queue = 65536;
|
||||
|
||||
for (i = 2; i < cf->args->nelts; i++) {
|
||||
|
||||
if (ngx_strncmp(value[i].data, "threads=", 8) == 0) {
|
||||
|
||||
tp->threads = ngx_atoi(value[i].data + 8, value[i].len - 8);
|
||||
|
||||
if (tp->threads == (ngx_uint_t) NGX_ERROR || tp->threads == 0) {
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"invalid threads value \"%V\"", &value[i]);
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ngx_strncmp(value[i].data, "max_queue=", 10) == 0) {
|
||||
|
||||
tp->max_queue = ngx_atoi(value[i].data + 10, value[i].len - 10);
|
||||
|
||||
if (tp->max_queue == NGX_ERROR) {
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"invalid max_queue value \"%V\"", &value[i]);
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (tp->threads == 0) {
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"\"%V\" must have \"threads\" parameter",
|
||||
&cmd->name);
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
|
||||
ngx_thread_pool_t *
|
||||
ngx_thread_pool_add(ngx_conf_t *cf, ngx_str_t *name)
|
||||
{
|
||||
ngx_thread_pool_t *tp, **tpp;
|
||||
ngx_thread_pool_conf_t *tcf;
|
||||
|
||||
if (name == NULL) {
|
||||
name = &ngx_thread_pool_default;
|
||||
}
|
||||
|
||||
tp = ngx_thread_pool_get(cf->cycle, name);
|
||||
|
||||
if (tp) {
|
||||
return tp;
|
||||
}
|
||||
|
||||
tp = ngx_pcalloc(cf->pool, sizeof(ngx_thread_pool_t));
|
||||
if (tp == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tp->name = *name;
|
||||
tp->file = cf->conf_file->file.name.data;
|
||||
tp->line = cf->conf_file->line;
|
||||
|
||||
tcf = (ngx_thread_pool_conf_t *) ngx_get_conf(cf->cycle->conf_ctx,
|
||||
ngx_thread_pool_module);
|
||||
|
||||
tpp = ngx_array_push(&tcf->pools);
|
||||
if (tpp == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*tpp = tp;
|
||||
|
||||
return tp;
|
||||
}
|
||||
|
||||
|
||||
ngx_thread_pool_t *
|
||||
ngx_thread_pool_get(ngx_cycle_t *cycle, ngx_str_t *name)
|
||||
{
|
||||
ngx_uint_t i;
|
||||
ngx_thread_pool_t **tpp;
|
||||
ngx_thread_pool_conf_t *tcf;
|
||||
|
||||
tcf = (ngx_thread_pool_conf_t *) ngx_get_conf(cycle->conf_ctx,
|
||||
ngx_thread_pool_module);
|
||||
|
||||
tpp = tcf->pools.elts;
|
||||
|
||||
for (i = 0; i < tcf->pools.nelts; i++) {
|
||||
|
||||
if (tpp[i]->name.len == name->len
|
||||
&& ngx_strncmp(tpp[i]->name.data, name->data, name->len) == 0)
|
||||
{
|
||||
return tpp[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_thread_pool_init_worker(ngx_cycle_t *cycle)
|
||||
{
|
||||
ngx_uint_t i;
|
||||
ngx_thread_pool_t **tpp;
|
||||
ngx_thread_pool_conf_t *tcf;
|
||||
|
||||
if (ngx_process != NGX_PROCESS_WORKER
|
||||
&& ngx_process != NGX_PROCESS_SINGLE)
|
||||
{
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
tcf = (ngx_thread_pool_conf_t *) ngx_get_conf(cycle->conf_ctx,
|
||||
ngx_thread_pool_module);
|
||||
|
||||
if (tcf == NULL) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
ngx_thread_pool_queue_init(&ngx_thread_pool_done);
|
||||
|
||||
tpp = tcf->pools.elts;
|
||||
|
||||
for (i = 0; i < tcf->pools.nelts; i++) {
|
||||
if (ngx_thread_pool_init(tpp[i], cycle->log, cycle->pool) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_thread_pool_exit_worker(ngx_cycle_t *cycle)
|
||||
{
|
||||
ngx_uint_t i;
|
||||
ngx_thread_pool_t **tpp;
|
||||
ngx_thread_pool_conf_t *tcf;
|
||||
|
||||
if (ngx_process != NGX_PROCESS_WORKER
|
||||
&& ngx_process != NGX_PROCESS_SINGLE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
tcf = (ngx_thread_pool_conf_t *) ngx_get_conf(cycle->conf_ctx,
|
||||
ngx_thread_pool_module);
|
||||
|
||||
if (tcf == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
tpp = tcf->pools.elts;
|
||||
|
||||
for (i = 0; i < tcf->pools.nelts; i++) {
|
||||
ngx_thread_pool_destroy(tpp[i]);
|
||||
}
|
||||
}
|
||||
36
src/core/ngx_thread_pool.h
Normal file
36
src/core/ngx_thread_pool.h
Normal file
@@ -0,0 +1,36 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Nginx, Inc.
|
||||
* Copyright (C) Valentin V. Bartenev
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_THREAD_POOL_H_INCLUDED_
|
||||
#define _NGX_THREAD_POOL_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_event.h>
|
||||
|
||||
|
||||
struct ngx_thread_task_s {
|
||||
ngx_thread_task_t *next;
|
||||
ngx_uint_t id;
|
||||
void *ctx;
|
||||
void (*handler)(void *data, ngx_log_t *log);
|
||||
ngx_event_t event;
|
||||
};
|
||||
|
||||
|
||||
typedef struct ngx_thread_pool_s ngx_thread_pool_t;
|
||||
|
||||
|
||||
ngx_thread_pool_t *ngx_thread_pool_add(ngx_conf_t *cf, ngx_str_t *name);
|
||||
ngx_thread_pool_t *ngx_thread_pool_get(ngx_cycle_t *cycle, ngx_str_t *name);
|
||||
|
||||
ngx_thread_task_t *ngx_thread_task_alloc(ngx_pool_t *pool, size_t size);
|
||||
ngx_int_t ngx_thread_task_post(ngx_thread_pool_t *tp, ngx_thread_task_t *task);
|
||||
|
||||
|
||||
#endif /* _NGX_THREAD_POOL_H_INCLUDED_ */
|
||||
428
src/core/ngx_times.c
Normal file
428
src/core/ngx_times.c
Normal file
@@ -0,0 +1,428 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
/*
|
||||
* 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_msec_t) sec * 1000 + 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);
|
||||
}
|
||||
|
||||
|
||||
#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 n, sec, min, hour, mday, mon, year, wday, days, leap;
|
||||
|
||||
/* the calculation is valid for positive time_t only */
|
||||
|
||||
n = (ngx_uint_t) t;
|
||||
|
||||
days = n / 86400;
|
||||
|
||||
/* January 1, 1970 was Thursday */
|
||||
|
||||
wday = (4 + days) % 7;
|
||||
|
||||
n %= 86400;
|
||||
hour = n / 3600;
|
||||
n %= 3600;
|
||||
min = n / 60;
|
||||
sec = n % 60;
|
||||
|
||||
/*
|
||||
* the algorithm based on Gauss' formula,
|
||||
* see src/http/ngx_http_parse_time.c
|
||||
*/
|
||||
|
||||
/* days since March 1, 1 BC */
|
||||
days = days - (31 + 28) + 719527;
|
||||
|
||||
/*
|
||||
* The "days" should be adjusted to 1 only, however, some March 1st's go
|
||||
* to previous year, so we adjust them to 2. This causes also shift of the
|
||||
* last February days to next year, but we catch the case when "yday"
|
||||
* becomes negative.
|
||||
*/
|
||||
|
||||
year = (days + 2) * 400 / (365 * 400 + 100 - 4 + 1);
|
||||
|
||||
yday = days - (365 * year + year / 4 - year / 100 + year / 400);
|
||||
|
||||
if (yday < 0) {
|
||||
leap = (year % 4 == 0) && (year % 100 || (year % 400 == 0));
|
||||
yday = 365 + leap + yday;
|
||||
year--;
|
||||
}
|
||||
|
||||
/*
|
||||
* The empirical formula that maps "yday" to month.
|
||||
* There are at least 10 variants, some of them are:
|
||||
* mon = (yday + 31) * 15 / 459
|
||||
* mon = (yday + 31) * 17 / 520
|
||||
* mon = (yday + 31) * 20 / 612
|
||||
*/
|
||||
|
||||
mon = (yday + 31) * 10 / 306;
|
||||
|
||||
/* the Gauss' formula that evaluates days before the month */
|
||||
|
||||
mday = yday - (367 * mon / 12 - 30) + 1;
|
||||
|
||||
if (yday >= 306) {
|
||||
|
||||
year++;
|
||||
mon -= 10;
|
||||
|
||||
/*
|
||||
* there is no "yday" in Win32 SYSTEMTIME
|
||||
*
|
||||
* yday -= 306;
|
||||
*/
|
||||
|
||||
} else {
|
||||
|
||||
mon += 2;
|
||||
|
||||
/*
|
||||
* there is no "yday" in Win32 SYSTEMTIME
|
||||
*
|
||||
* yday += 31 + 28 + leap;
|
||||
*/
|
||||
}
|
||||
|
||||
tp->ngx_tm_sec = (ngx_tm_sec_t) sec;
|
||||
tp->ngx_tm_min = (ngx_tm_min_t) min;
|
||||
tp->ngx_tm_hour = (ngx_tm_hour_t) hour;
|
||||
tp->ngx_tm_mday = (ngx_tm_mday_t) mday;
|
||||
tp->ngx_tm_mon = (ngx_tm_mon_t) mon;
|
||||
tp->ngx_tm_year = (ngx_tm_year_t) year;
|
||||
tp->ngx_tm_wday = (ngx_tm_wday_t) wday;
|
||||
}
|
||||
|
||||
|
||||
time_t
|
||||
ngx_next_time(time_t when)
|
||||
{
|
||||
time_t now, next;
|
||||
struct tm tm;
|
||||
|
||||
now = ngx_time();
|
||||
|
||||
ngx_libc_localtime(now, &tm);
|
||||
|
||||
tm.tm_hour = (int) (when / 3600);
|
||||
when %= 3600;
|
||||
tm.tm_min = (int) (when / 60);
|
||||
tm.tm_sec = (int) (when % 60);
|
||||
|
||||
next = mktime(&tm);
|
||||
|
||||
if (next == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (next - now > 0) {
|
||||
return next;
|
||||
}
|
||||
|
||||
tm.tm_mday++;
|
||||
|
||||
/* mktime() should normalize a date (Jan 32, etc) */
|
||||
|
||||
next = mktime(&tm);
|
||||
|
||||
if (next != -1) {
|
||||
return next;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
52
src/core/ngx_times.h
Normal file
52
src/core/ngx_times.h
Normal file
@@ -0,0 +1,52 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_TIMES_H_INCLUDED_
|
||||
#define _NGX_TIMES_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
typedef struct {
|
||||
time_t sec;
|
||||
ngx_uint_t msec;
|
||||
ngx_int_t gmtoff;
|
||||
} ngx_time_t;
|
||||
|
||||
|
||||
void ngx_time_init(void);
|
||||
void ngx_time_update(void);
|
||||
void ngx_time_sigsafe_update(void);
|
||||
u_char *ngx_http_time(u_char *buf, time_t t);
|
||||
u_char *ngx_http_cookie_time(u_char *buf, time_t t);
|
||||
void ngx_gmtime(time_t t, ngx_tm_t *tp);
|
||||
|
||||
time_t ngx_next_time(time_t when);
|
||||
#define ngx_next_time_n "mktime()"
|
||||
|
||||
|
||||
extern volatile ngx_time_t *ngx_cached_time;
|
||||
|
||||
#define ngx_time() ngx_cached_time->sec
|
||||
#define ngx_timeofday() (ngx_time_t *) ngx_cached_time
|
||||
|
||||
extern volatile ngx_str_t ngx_cached_err_log_time;
|
||||
extern volatile ngx_str_t ngx_cached_http_time;
|
||||
extern volatile ngx_str_t ngx_cached_http_log_time;
|
||||
extern volatile ngx_str_t ngx_cached_http_log_iso8601;
|
||||
extern volatile ngx_str_t ngx_cached_syslog_time;
|
||||
|
||||
/*
|
||||
* milliseconds elapsed since epoch and truncated to ngx_msec_t,
|
||||
* used in event timers
|
||||
*/
|
||||
extern volatile ngx_msec_t ngx_current_msec;
|
||||
|
||||
|
||||
#endif /* _NGX_TIMES_H_INCLUDED_ */
|
||||
560
src/event/modules/ngx_devpoll_module.c
Normal file
560
src/event/modules/ngx_devpoll_module.c
Normal file
@@ -0,0 +1,560 @@
|
||||
|
||||
/*
|
||||
* 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
|
||||
};
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
1052
src/event/modules/ngx_epoll_module.c
Normal file
1052
src/event/modules/ngx_epoll_module.c
Normal file
File diff suppressed because it is too large
Load Diff
649
src/event/modules/ngx_eventport_module.c
Normal file
649
src/event/modules/ngx_eventport_module.c
Normal file
@@ -0,0 +1,649 @@
|
||||
|
||||
/*
|
||||
* 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;
|
||||
#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
|
||||
};
|
||||
|
||||
|
||||
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;
|
||||
#if !(NGX_TEST_BUILD_EVENTPORT)
|
||||
sev.sigev_value.sival_ptr = &pn;
|
||||
#endif
|
||||
|
||||
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 {
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ev->log, 0,
|
||||
"eventport del event: fd:%d", c->fd);
|
||||
|
||||
if (port_dissociate(ep, PORT_SOURCE_FD, c->fd) == -1) {
|
||||
ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
|
||||
"port_dissociate() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
ev->active = 0;
|
||||
ev->oneshot = 0;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_eventport_notify(ngx_event_handler_pt handler)
|
||||
{
|
||||
notify_event.handler = handler;
|
||||
|
||||
if (port_send(ep, 0, ¬ify_event) != 0) {
|
||||
ngx_log_error(NGX_LOG_ALERT, notify_event.log, ngx_errno,
|
||||
"port_send() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
722
src/event/modules/ngx_kqueue_module.c
Normal file
722
src/event/modules/ngx_kqueue_module.c
Normal file
@@ -0,0 +1,722 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_event.h>
|
||||
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
|
||||
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 = 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 = 0;
|
||||
|
||||
if (kevent(ngx_kqueue, ¬ify_kev, 1, NULL, 0, NULL) == -1) {
|
||||
ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
|
||||
"kevent(EVFILT_USER, EV_ADD) failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
notify_event.active = 1;
|
||||
notify_event.log = log;
|
||||
|
||||
notify_kev.flags = 0;
|
||||
notify_kev.fflags = NOTE_TRIGGER;
|
||||
notify_kev.udata = NGX_KQUEUE_UDATA_T ((uintptr_t) ¬ify_event);
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
static void
|
||||
ngx_kqueue_done(ngx_cycle_t *cycle)
|
||||
{
|
||||
if (close(ngx_kqueue) == -1) {
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
|
||||
"kqueue close() failed");
|
||||
}
|
||||
|
||||
ngx_kqueue = -1;
|
||||
|
||||
ngx_free(change_list);
|
||||
ngx_free(event_list);
|
||||
|
||||
change_list = NULL;
|
||||
event_list = NULL;
|
||||
max_changes = 0;
|
||||
nchanges = 0;
|
||||
nevents = 0;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_kqueue_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
|
||||
{
|
||||
ngx_int_t rc;
|
||||
#if 0
|
||||
ngx_event_t *e;
|
||||
ngx_connection_t *c;
|
||||
#endif
|
||||
|
||||
ev->active = 1;
|
||||
ev->disabled = 0;
|
||||
ev->oneshot = (flags & NGX_ONESHOT_EVENT) ? 1 : 0;
|
||||
|
||||
#if 0
|
||||
|
||||
if (ev->index < nchanges
|
||||
&& ((uintptr_t) change_list[ev->index].udata & (uintptr_t) ~1)
|
||||
== (uintptr_t) ev)
|
||||
{
|
||||
if (change_list[ev->index].flags == EV_DISABLE) {
|
||||
|
||||
/*
|
||||
* if the EV_DISABLE is still not passed to a kernel
|
||||
* we will not pass it
|
||||
*/
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
|
||||
"kevent activated: %d: ft:%i",
|
||||
ngx_event_ident(ev->data), event);
|
||||
|
||||
if (ev->index < --nchanges) {
|
||||
e = (ngx_event_t *)
|
||||
((uintptr_t) change_list[nchanges].udata & (uintptr_t) ~1);
|
||||
change_list[ev->index] = change_list[nchanges];
|
||||
e->index = ev->index;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
c = ev->data;
|
||||
|
||||
ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
|
||||
"previous event on #%d were not passed in kernel", c->fd);
|
||||
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
rc = ngx_kqueue_set_event(ev, event, EV_ADD|EV_ENABLE|flags);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_kqueue_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
|
||||
{
|
||||
ngx_int_t rc;
|
||||
ngx_event_t *e;
|
||||
|
||||
ev->active = 0;
|
||||
ev->disabled = 0;
|
||||
|
||||
if (ev->index < nchanges
|
||||
&& ((uintptr_t) change_list[ev->index].udata & (uintptr_t) ~1)
|
||||
== (uintptr_t) ev)
|
||||
{
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
|
||||
"kevent deleted: %d: ft:%i",
|
||||
ngx_event_ident(ev->data), event);
|
||||
|
||||
/* if the event is still not passed to a kernel we will not pass it */
|
||||
|
||||
nchanges--;
|
||||
|
||||
if (ev->index < nchanges) {
|
||||
e = (ngx_event_t *)
|
||||
((uintptr_t) change_list[nchanges].udata & (uintptr_t) ~1);
|
||||
change_list[ev->index] = change_list[nchanges];
|
||||
e->index = ev->index;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* when the file descriptor is closed the kqueue automatically deletes
|
||||
* its filters so we do not need to delete explicitly the event
|
||||
* before the closing the file descriptor.
|
||||
*/
|
||||
|
||||
if (flags & NGX_CLOSE_EVENT) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
if (flags & NGX_DISABLE_EVENT) {
|
||||
ev->disabled = 1;
|
||||
|
||||
} else {
|
||||
flags |= EV_DELETE;
|
||||
}
|
||||
|
||||
rc = ngx_kqueue_set_event(ev, event, flags);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_kqueue_set_event(ngx_event_t *ev, ngx_int_t filter, ngx_uint_t flags)
|
||||
{
|
||||
struct kevent *kev;
|
||||
struct timespec ts;
|
||||
ngx_connection_t *c;
|
||||
|
||||
c = ev->data;
|
||||
|
||||
ngx_log_debug3(NGX_LOG_DEBUG_EVENT, ev->log, 0,
|
||||
"kevent set event: %d: ft:%i fl:%04Xi",
|
||||
c->fd, filter, flags);
|
||||
|
||||
if (nchanges >= max_changes) {
|
||||
ngx_log_error(NGX_LOG_WARN, ev->log, 0,
|
||||
"kqueue change list is filled up");
|
||||
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 0;
|
||||
|
||||
if (kevent(ngx_kqueue, change_list, (int) nchanges, NULL, 0, &ts)
|
||||
== -1)
|
||||
{
|
||||
ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno, "kevent() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
nchanges = 0;
|
||||
}
|
||||
|
||||
kev = &change_list[nchanges];
|
||||
|
||||
kev->ident = c->fd;
|
||||
kev->filter = (short) filter;
|
||||
kev->flags = (u_short) flags;
|
||||
kev->udata = NGX_KQUEUE_UDATA_T ((uintptr_t) ev | ev->instance);
|
||||
|
||||
if (filter == EVFILT_VNODE) {
|
||||
kev->fflags = NOTE_DELETE|NOTE_WRITE|NOTE_EXTEND
|
||||
|NOTE_ATTRIB|NOTE_RENAME
|
||||
#if (__FreeBSD__ == 4 && __FreeBSD_version >= 430000) \
|
||||
|| __FreeBSD_version >= 500018
|
||||
|NOTE_REVOKE
|
||||
#endif
|
||||
;
|
||||
kev->data = 0;
|
||||
|
||||
} else {
|
||||
#if (NGX_HAVE_LOWAT_EVENT)
|
||||
if (flags & NGX_LOWAT_EVENT) {
|
||||
kev->fflags = NOTE_LOWAT;
|
||||
kev->data = ev->available;
|
||||
|
||||
} else {
|
||||
kev->fflags = 0;
|
||||
kev->data = 0;
|
||||
}
|
||||
#else
|
||||
kev->fflags = 0;
|
||||
kev->data = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
ev->index = nchanges;
|
||||
nchanges++;
|
||||
|
||||
if (flags & NGX_FLUSH_EVENT) {
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 0;
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0, "kevent flush");
|
||||
|
||||
if (kevent(ngx_kqueue, change_list, (int) nchanges, NULL, 0, &ts)
|
||||
== -1)
|
||||
{
|
||||
ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno, "kevent() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
nchanges = 0;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
#ifdef EVFILT_USER
|
||||
|
||||
static ngx_int_t
|
||||
ngx_kqueue_notify(ngx_event_handler_pt handler)
|
||||
{
|
||||
notify_event.handler = handler;
|
||||
|
||||
if (kevent(ngx_kqueue, ¬ify_kev, 1, NULL, 0, NULL) == -1) {
|
||||
ngx_log_error(NGX_LOG_ALERT, notify_event.log, ngx_errno,
|
||||
"kevent(EVFILT_USER, NOTE_TRIGGER) failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_kqueue_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
|
||||
ngx_uint_t flags)
|
||||
{
|
||||
int events, n;
|
||||
ngx_int_t i, instance;
|
||||
ngx_uint_t level;
|
||||
ngx_err_t err;
|
||||
ngx_event_t *ev;
|
||||
ngx_queue_t *queue;
|
||||
struct timespec ts, *tp;
|
||||
|
||||
n = (int) nchanges;
|
||||
nchanges = 0;
|
||||
|
||||
if (timer == NGX_TIMER_INFINITE) {
|
||||
tp = NULL;
|
||||
|
||||
} else {
|
||||
|
||||
ts.tv_sec = timer / 1000;
|
||||
ts.tv_nsec = (timer % 1000) * 1000000;
|
||||
|
||||
/*
|
||||
* 64-bit Darwin kernel has the bug: kernel level ts.tv_nsec is
|
||||
* the int32_t while user level ts.tv_nsec is the long (64-bit),
|
||||
* so on the big endian PowerPC all nanoseconds are lost.
|
||||
*/
|
||||
|
||||
#if (NGX_DARWIN_KEVENT_BUG)
|
||||
ts.tv_nsec <<= 32;
|
||||
#endif
|
||||
|
||||
tp = &ts;
|
||||
}
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
|
||||
"kevent timer: %M, changes: %d", timer, n);
|
||||
|
||||
events = kevent(ngx_kqueue, change_list, n, event_list, (int) nevents, tp);
|
||||
|
||||
err = (events == -1) ? ngx_errno : 0;
|
||||
|
||||
if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) {
|
||||
ngx_time_update();
|
||||
}
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
|
||||
"kevent events: %d", events);
|
||||
|
||||
if (err) {
|
||||
if (err == NGX_EINTR) {
|
||||
|
||||
if (ngx_event_timer_alarm) {
|
||||
ngx_event_timer_alarm = 0;
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
level = NGX_LOG_INFO;
|
||||
|
||||
} else {
|
||||
level = NGX_LOG_ALERT;
|
||||
}
|
||||
|
||||
ngx_log_error(level, cycle->log, err, "kevent() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (events == 0) {
|
||||
if (timer != NGX_TIMER_INFINITE) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
|
||||
"kevent() returned no events without timeout");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
for (i = 0; i < events; i++) {
|
||||
|
||||
ngx_kqueue_dump_event(cycle->log, &event_list[i]);
|
||||
|
||||
if (event_list[i].flags & EV_ERROR) {
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, event_list[i].data,
|
||||
"kevent() error on %d filter:%d flags:%04Xd",
|
||||
(int) event_list[i].ident, event_list[i].filter,
|
||||
event_list[i].flags);
|
||||
continue;
|
||||
}
|
||||
|
||||
#if (NGX_HAVE_TIMER_EVENT)
|
||||
|
||||
if (event_list[i].filter == EVFILT_TIMER) {
|
||||
ngx_time_update();
|
||||
continue;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
ev = (ngx_event_t *) event_list[i].udata;
|
||||
|
||||
switch (event_list[i].filter) {
|
||||
|
||||
case EVFILT_READ:
|
||||
case EVFILT_WRITE:
|
||||
|
||||
instance = (uintptr_t) ev & 1;
|
||||
ev = (ngx_event_t *) ((uintptr_t) ev & (uintptr_t) ~1);
|
||||
|
||||
if (ev->closed || ev->instance != instance) {
|
||||
|
||||
/*
|
||||
* the stale event from a file descriptor
|
||||
* that was just closed in this iteration
|
||||
*/
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
|
||||
"kevent: stale event %p", ev);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ev->log && (ev->log->log_level & NGX_LOG_DEBUG_CONNECTION)) {
|
||||
ngx_kqueue_dump_event(ev->log, &event_list[i]);
|
||||
}
|
||||
|
||||
if (ev->oneshot) {
|
||||
ev->active = 0;
|
||||
}
|
||||
|
||||
ev->available = event_list[i].data;
|
||||
|
||||
if (event_list[i].flags & EV_EOF) {
|
||||
ev->pending_eof = 1;
|
||||
ev->kq_errno = event_list[i].fflags;
|
||||
}
|
||||
|
||||
ev->ready = 1;
|
||||
|
||||
break;
|
||||
|
||||
case EVFILT_VNODE:
|
||||
ev->kq_vnode = 1;
|
||||
|
||||
break;
|
||||
|
||||
case EVFILT_AIO:
|
||||
ev->complete = 1;
|
||||
ev->ready = 1;
|
||||
|
||||
break;
|
||||
|
||||
#ifdef EVFILT_USER
|
||||
case EVFILT_USER:
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
|
||||
"unexpected kevent() filter %d",
|
||||
event_list[i].filter);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (flags & NGX_POST_EVENTS) {
|
||||
queue = ev->accept ? &ngx_posted_accept_events
|
||||
: &ngx_posted_events;
|
||||
|
||||
ngx_post_event(ev, queue);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
ev->handler(ev);
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_inline void
|
||||
ngx_kqueue_dump_event(ngx_log_t *log, struct kevent *kev)
|
||||
{
|
||||
if (kev->ident > 0x8000000 && kev->ident != (unsigned) -1) {
|
||||
ngx_log_debug6(NGX_LOG_DEBUG_EVENT, log, 0,
|
||||
"kevent: %p: ft:%d fl:%04Xd ff:%08Xd d:%d ud:%p",
|
||||
(void *) kev->ident, kev->filter,
|
||||
kev->flags, kev->fflags,
|
||||
(int) kev->data, kev->udata);
|
||||
|
||||
} else {
|
||||
ngx_log_debug6(NGX_LOG_DEBUG_EVENT, log, 0,
|
||||
"kevent: %d: ft:%d fl:%04Xd ff:%08Xd d:%d ud:%p",
|
||||
(int) kev->ident, kev->filter,
|
||||
kev->flags, kev->fflags,
|
||||
(int) kev->data, kev->udata);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
ngx_kqueue_create_conf(ngx_cycle_t *cycle)
|
||||
{
|
||||
ngx_kqueue_conf_t *kcf;
|
||||
|
||||
kcf = ngx_palloc(cycle->pool, sizeof(ngx_kqueue_conf_t));
|
||||
if (kcf == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
kcf->changes = NGX_CONF_UNSET;
|
||||
kcf->events = NGX_CONF_UNSET;
|
||||
|
||||
return kcf;
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
ngx_kqueue_init_conf(ngx_cycle_t *cycle, void *conf)
|
||||
{
|
||||
ngx_kqueue_conf_t *kcf = conf;
|
||||
|
||||
ngx_conf_init_uint_value(kcf->changes, 512);
|
||||
ngx_conf_init_uint_value(kcf->events, 512);
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
415
src/event/modules/ngx_poll_module.c
Normal file
415
src/event/modules/ngx_poll_module.c
Normal file
@@ -0,0 +1,415 @@
|
||||
|
||||
/*
|
||||
* 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");
|
||||
|
||||
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(ngx_event_t *) * 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;
|
||||
|
||||
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;
|
||||
}
|
||||
423
src/event/modules/ngx_select_module.c
Normal file
423
src/event/modules/ngx_select_module.c
Normal file
@@ -0,0 +1,423 @@
|
||||
|
||||
/*
|
||||
* 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");
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
398
src/event/modules/ngx_win32_select_module.c
Normal file
398
src/event/modules/ngx_win32_select_module.c
Normal file
@@ -0,0 +1,398 @@
|
||||
|
||||
/*
|
||||
* 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_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");
|
||||
|
||||
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;
|
||||
|
||||
if (max_read || max_write) {
|
||||
ready = select(0, &work_read_fd_set, &work_write_fd_set, NULL, 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 = 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;
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
1291
src/event/ngx_event.c
Normal file
1291
src/event/ngx_event.c
Normal file
File diff suppressed because it is too large
Load Diff
541
src/event/ngx_event.h
Normal file
541
src/event/ngx_event.h
Normal file
@@ -0,0 +1,541 @@
|
||||
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* epoll with EPOLLRDHUP:
|
||||
* accept: 1 if accept many, 0 otherwise
|
||||
* read: 1 if there can be data to read, 0 otherwise
|
||||
*
|
||||
* iocp: TODO
|
||||
*
|
||||
* otherwise:
|
||||
* accept: 1 if accept many, 0 otherwise
|
||||
*/
|
||||
|
||||
#if (NGX_HAVE_KQUEUE) || (NGX_HAVE_IOCP)
|
||||
int available;
|
||||
#else
|
||||
unsigned available:1;
|
||||
#endif
|
||||
|
||||
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;
|
||||
|
||||
#if (NGX_HAVE_AIO_SENDFILE || NGX_COMPAT)
|
||||
ssize_t (*preload_handler)(ngx_buf_t *file);
|
||||
#endif
|
||||
|
||||
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;
|
||||
|
||||
|
||||
#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);
|
||||
#if !(NGX_WIN32)
|
||||
void ngx_event_recvmsg(ngx_event_t *ev);
|
||||
#endif
|
||||
ngx_int_t ngx_trylock_accept_mutex(ngx_cycle_t *cycle);
|
||||
u_char *ngx_accept_log_error(ngx_log_t *log, u_char *buf, size_t len);
|
||||
|
||||
|
||||
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>
|
||||
|
||||
#if (NGX_WIN32)
|
||||
#include <ngx_iocp_module.h>
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* _NGX_EVENT_H_INCLUDED_ */
|
||||
832
src/event/ngx_event_accept.c
Normal file
832
src/event/ngx_event_accept.c
Normal file
@@ -0,0 +1,832 @@
|
||||
|
||||
/*
|
||||
* 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_enable_accept_events(ngx_cycle_t *cycle);
|
||||
static ngx_int_t ngx_disable_accept_events(ngx_cycle_t *cycle, ngx_uint_t all);
|
||||
static void ngx_close_accepted_connection(ngx_connection_t *c);
|
||||
#if (NGX_DEBUG)
|
||||
static void ngx_debug_accepted_connection(ngx_event_conf_t *ecf,
|
||||
ngx_connection_t *c);
|
||||
#endif
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*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)
|
||||
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);
|
||||
|
||||
#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_WIN32)
|
||||
|
||||
void
|
||||
ngx_event_recvmsg(ngx_event_t *ev)
|
||||
{
|
||||
ssize_t n;
|
||||
ngx_log_t *log;
|
||||
ngx_err_t err;
|
||||
ngx_event_t *rev, *wev;
|
||||
struct iovec iov[1];
|
||||
struct msghdr msg;
|
||||
ngx_sockaddr_t sa;
|
||||
ngx_listening_t *ls;
|
||||
ngx_event_conf_t *ecf;
|
||||
ngx_connection_t *c, *lc;
|
||||
static u_char buffer[65535];
|
||||
|
||||
#if (NGX_HAVE_MSGHDR_MSG_CONTROL)
|
||||
|
||||
#if (NGX_HAVE_IP_RECVDSTADDR)
|
||||
u_char msg_control[CMSG_SPACE(sizeof(struct in_addr))];
|
||||
#elif (NGX_HAVE_IP_PKTINFO)
|
||||
u_char msg_control[CMSG_SPACE(sizeof(struct in_pktinfo))];
|
||||
#endif
|
||||
|
||||
#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO)
|
||||
u_char msg_control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
|
||||
#endif
|
||||
|
||||
#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,
|
||||
"recvmsg on %V, ready: %d", &ls->addr_text, ev->available);
|
||||
|
||||
do {
|
||||
ngx_memzero(&msg, sizeof(struct msghdr));
|
||||
|
||||
iov[0].iov_base = (void *) buffer;
|
||||
iov[0].iov_len = sizeof(buffer);
|
||||
|
||||
msg.msg_name = &sa;
|
||||
msg.msg_namelen = sizeof(ngx_sockaddr_t);
|
||||
msg.msg_iov = iov;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
#if (NGX_HAVE_MSGHDR_MSG_CONTROL)
|
||||
|
||||
if (ls->wildcard) {
|
||||
|
||||
#if (NGX_HAVE_IP_RECVDSTADDR || NGX_HAVE_IP_PKTINFO)
|
||||
if (ls->sockaddr->sa_family == AF_INET) {
|
||||
msg.msg_control = &msg_control;
|
||||
msg.msg_controllen = sizeof(msg_control);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO)
|
||||
if (ls->sockaddr->sa_family == AF_INET6) {
|
||||
msg.msg_control = &msg_control6;
|
||||
msg.msg_controllen = sizeof(msg_control6);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
n = recvmsg(lc->fd, &msg, 0);
|
||||
|
||||
if (n == -1) {
|
||||
err = ngx_socket_errno;
|
||||
|
||||
if (err == NGX_EAGAIN) {
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, err,
|
||||
"recvmsg() not ready");
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_log_error(NGX_LOG_ALERT, ev->log, err, "recvmsg() failed");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#if (NGX_STAT_STUB)
|
||||
(void) ngx_atomic_fetch_add(ngx_stat_accepted, 1);
|
||||
#endif
|
||||
|
||||
#if (NGX_HAVE_MSGHDR_MSG_CONTROL)
|
||||
if (msg.msg_flags & (MSG_TRUNC|MSG_CTRUNC)) {
|
||||
ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
|
||||
"recvmsg() truncated data");
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
ngx_accept_disabled = ngx_cycle->connection_n / 8
|
||||
- ngx_cycle->free_connection_n;
|
||||
|
||||
c = ngx_get_connection(lc->fd, ev->log);
|
||||
if (c == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
c->shared = 1;
|
||||
c->type = SOCK_DGRAM;
|
||||
c->socklen = msg.msg_namelen;
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
c->sockaddr = ngx_palloc(c->pool, c->socklen);
|
||||
if (c->sockaddr == NULL) {
|
||||
ngx_close_accepted_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_memcpy(c->sockaddr, msg.msg_name, c->socklen);
|
||||
|
||||
log = ngx_palloc(c->pool, sizeof(ngx_log_t));
|
||||
if (log == NULL) {
|
||||
ngx_close_accepted_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
*log = ls->log;
|
||||
|
||||
c->send = ngx_udp_send;
|
||||
c->send_chain = ngx_udp_send_chain;
|
||||
|
||||
c->log = log;
|
||||
c->pool->log = log;
|
||||
|
||||
c->listening = ls;
|
||||
c->local_sockaddr = ls->sockaddr;
|
||||
c->local_socklen = ls->socklen;
|
||||
|
||||
#if (NGX_HAVE_MSGHDR_MSG_CONTROL)
|
||||
|
||||
if (ls->wildcard) {
|
||||
struct cmsghdr *cmsg;
|
||||
struct sockaddr *sockaddr;
|
||||
|
||||
sockaddr = ngx_palloc(c->pool, c->local_socklen);
|
||||
if (sockaddr == NULL) {
|
||||
ngx_close_accepted_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_memcpy(sockaddr, c->local_sockaddr, c->local_socklen);
|
||||
c->local_sockaddr = sockaddr;
|
||||
|
||||
for (cmsg = CMSG_FIRSTHDR(&msg);
|
||||
cmsg != NULL;
|
||||
cmsg = CMSG_NXTHDR(&msg, cmsg))
|
||||
{
|
||||
|
||||
#if (NGX_HAVE_IP_RECVDSTADDR)
|
||||
|
||||
if (cmsg->cmsg_level == IPPROTO_IP
|
||||
&& cmsg->cmsg_type == IP_RECVDSTADDR
|
||||
&& sockaddr->sa_family == AF_INET)
|
||||
{
|
||||
struct in_addr *addr;
|
||||
struct sockaddr_in *sin;
|
||||
|
||||
addr = (struct in_addr *) CMSG_DATA(cmsg);
|
||||
sin = (struct sockaddr_in *) sockaddr;
|
||||
sin->sin_addr = *addr;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
#elif (NGX_HAVE_IP_PKTINFO)
|
||||
|
||||
if (cmsg->cmsg_level == IPPROTO_IP
|
||||
&& cmsg->cmsg_type == IP_PKTINFO
|
||||
&& sockaddr->sa_family == AF_INET)
|
||||
{
|
||||
struct in_pktinfo *pkt;
|
||||
struct sockaddr_in *sin;
|
||||
|
||||
pkt = (struct in_pktinfo *) CMSG_DATA(cmsg);
|
||||
sin = (struct sockaddr_in *) sockaddr;
|
||||
sin->sin_addr = pkt->ipi_addr;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO)
|
||||
|
||||
if (cmsg->cmsg_level == IPPROTO_IPV6
|
||||
&& cmsg->cmsg_type == IPV6_PKTINFO
|
||||
&& sockaddr->sa_family == AF_INET6)
|
||||
{
|
||||
struct in6_pktinfo *pkt6;
|
||||
struct sockaddr_in6 *sin6;
|
||||
|
||||
pkt6 = (struct in6_pktinfo *) CMSG_DATA(cmsg);
|
||||
sin6 = (struct sockaddr_in6 *) sockaddr;
|
||||
sin6->sin6_addr = pkt6->ipi6_addr;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
c->buffer = ngx_create_temp_buf(c->pool, n);
|
||||
if (c->buffer == NULL) {
|
||||
ngx_close_accepted_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
c->buffer->last = ngx_cpymem(c->buffer->last, buffer, n);
|
||||
|
||||
rev = c->read;
|
||||
wev = c->write;
|
||||
|
||||
wev->ready = 1;
|
||||
|
||||
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);
|
||||
|
||||
#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_debug4(NGX_LOG_DEBUG_EVENT, log, 0,
|
||||
"*%uA recvmsg: %V fd:%d n:%z",
|
||||
c->number, &addr, c->fd, n);
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
log->data = NULL;
|
||||
log->handler = NULL;
|
||||
|
||||
ls->handler(c);
|
||||
|
||||
if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
|
||||
ev->available -= n;
|
||||
}
|
||||
|
||||
} while (ev->available);
|
||||
}
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
|
||||
static 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;
|
||||
}
|
||||
|
||||
|
||||
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 (!c->shared && 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)
|
||||
|
||||
static 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
|
||||
410
src/event/ngx_event_connect.c
Normal file
410
src/event/ngx_event_connect.c
Normal file
@@ -0,0 +1,410 @@
|
||||
|
||||
/*
|
||||
* 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;
|
||||
#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 (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->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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#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;
|
||||
}
|
||||
78
src/event/ngx_event_connect.h
Normal file
78
src/event/ngx_event_connect.h
Normal file
@@ -0,0 +1,78 @@
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
unsigned cached:1;
|
||||
unsigned transparent:1;
|
||||
|
||||
/* ngx_connection_log_error_e */
|
||||
unsigned log_error:2;
|
||||
|
||||
NGX_COMPAT_BEGIN(2)
|
||||
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_ */
|
||||
4191
src/event/ngx_event_openssl.c
Normal file
4191
src/event/ngx_event_openssl.c
Normal file
File diff suppressed because it is too large
Load Diff
254
src/event/ngx_event_openssl.h
Normal file
254
src/event/ngx_event_openssl.h
Normal file
@@ -0,0 +1,254 @@
|
||||
|
||||
/*
|
||||
* 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>
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/conf.h>
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/dh.h>
|
||||
#ifndef OPENSSL_NO_ENGINE
|
||||
#include <openssl/engine.h>
|
||||
#endif
|
||||
#include <openssl/evp.h>
|
||||
#ifndef OPENSSL_NO_OCSP
|
||||
#include <openssl/ocsp.h>
|
||||
#endif
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/rsa.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
|
||||
#define OPENSSL_VERSION_NUMBER 0x1000107fL
|
||||
#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
|
||||
|
||||
|
||||
struct ngx_ssl_s {
|
||||
SSL_CTX *ctx;
|
||||
ngx_log_t *log;
|
||||
size_t buffer_size;
|
||||
};
|
||||
|
||||
|
||||
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_event_handler_pt saved_read_handler;
|
||||
ngx_event_handler_pt saved_write_handler;
|
||||
|
||||
unsigned handshaked:1;
|
||||
unsigned renegotiation:1;
|
||||
unsigned buffer:1;
|
||||
unsigned no_wait_shutdown:1;
|
||||
unsigned no_send_shutdown:1;
|
||||
unsigned handshake_buffer_set: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 4096
|
||||
|
||||
typedef struct ngx_ssl_sess_id_s ngx_ssl_sess_id_t;
|
||||
|
||||
struct ngx_ssl_sess_id_s {
|
||||
ngx_rbtree_node_t node;
|
||||
u_char *id;
|
||||
size_t len;
|
||||
u_char *session;
|
||||
ngx_queue_t queue;
|
||||
time_t expire;
|
||||
#if (NGX_PTR_SIZE == 8)
|
||||
void *stub;
|
||||
u_char sess_id[32];
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_rbtree_t session_rbtree;
|
||||
ngx_rbtree_node_t sentinel;
|
||||
ngx_queue_t expire_queue;
|
||||
} ngx_ssl_session_cache_t;
|
||||
|
||||
|
||||
#ifdef SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB
|
||||
|
||||
typedef struct {
|
||||
size_t size;
|
||||
u_char name[16];
|
||||
u_char hmac_key[32];
|
||||
u_char aes_key[32];
|
||||
} ngx_ssl_session_ticket_key_t;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#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_BUFFER 1
|
||||
#define NGX_SSL_CLIENT 2
|
||||
|
||||
#define NGX_SSL_BUFSIZE 16384
|
||||
|
||||
|
||||
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_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);
|
||||
RSA *ngx_ssl_rsa512_key_callback(ngx_ssl_conn_t *ssl_conn, int is_export,
|
||||
int key_length);
|
||||
ngx_array_t *ngx_ssl_read_password_file(ngx_conf_t *cf, ngx_str_t *file);
|
||||
ngx_int_t ngx_ssl_dhparam(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file);
|
||||
ngx_int_t ngx_ssl_ecdh_curve(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *name);
|
||||
ngx_int_t ngx_ssl_session_cache(ngx_ssl_t *ssl, ngx_str_t *sess_ctx,
|
||||
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_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);
|
||||
#define ngx_ssl_get_session(c) SSL_get1_session(c->ssl->connection)
|
||||
#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_curves(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_server_name(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_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_handshake(ngx_connection_t *c);
|
||||
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_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_session_ticket_keys_index;
|
||||
extern int ngx_ssl_certificate_index;
|
||||
extern int ngx_ssl_next_certificate_index;
|
||||
extern int ngx_ssl_certificate_name_index;
|
||||
extern int ngx_ssl_stapling_index;
|
||||
|
||||
|
||||
#endif /* _NGX_EVENT_OPENSSL_H_INCLUDED_ */
|
||||
1892
src/event/ngx_event_openssl_stapling.c
Normal file
1892
src/event/ngx_event_openssl_stapling.c
Normal file
File diff suppressed because it is too large
Load Diff
1110
src/event/ngx_event_pipe.c
Normal file
1110
src/event/ngx_event_pipe.c
Normal file
File diff suppressed because it is too large
Load Diff
107
src/event/ngx_event_pipe.h
Normal file
107
src/event/ngx_event_pipe.h
Normal file
@@ -0,0 +1,107 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_EVENT_PIPE_H_INCLUDED_
|
||||
#define _NGX_EVENT_PIPE_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_event.h>
|
||||
|
||||
|
||||
typedef struct ngx_event_pipe_s ngx_event_pipe_t;
|
||||
|
||||
typedef ngx_int_t (*ngx_event_pipe_input_filter_pt)(ngx_event_pipe_t *p,
|
||||
ngx_buf_t *buf);
|
||||
typedef ngx_int_t (*ngx_event_pipe_output_filter_pt)(void *data,
|
||||
ngx_chain_t *chain);
|
||||
|
||||
|
||||
struct ngx_event_pipe_s {
|
||||
ngx_connection_t *upstream;
|
||||
ngx_connection_t *downstream;
|
||||
|
||||
ngx_chain_t *free_raw_bufs;
|
||||
ngx_chain_t *in;
|
||||
ngx_chain_t **last_in;
|
||||
|
||||
ngx_chain_t *writing;
|
||||
|
||||
ngx_chain_t *out;
|
||||
ngx_chain_t *free;
|
||||
ngx_chain_t *busy;
|
||||
|
||||
/*
|
||||
* the input filter i.e. that moves HTTP/1.1 chunks
|
||||
* from the raw bufs to an incoming chain
|
||||
*/
|
||||
|
||||
ngx_event_pipe_input_filter_pt input_filter;
|
||||
void *input_ctx;
|
||||
|
||||
ngx_event_pipe_output_filter_pt output_filter;
|
||||
void *output_ctx;
|
||||
|
||||
#if (NGX_THREADS || NGX_COMPAT)
|
||||
ngx_int_t (*thread_handler)(ngx_thread_task_t *task,
|
||||
ngx_file_t *file);
|
||||
void *thread_ctx;
|
||||
ngx_thread_task_t *thread_task;
|
||||
#endif
|
||||
|
||||
unsigned read:1;
|
||||
unsigned cacheable:1;
|
||||
unsigned single_buf:1;
|
||||
unsigned free_bufs:1;
|
||||
unsigned upstream_done:1;
|
||||
unsigned upstream_error:1;
|
||||
unsigned upstream_eof:1;
|
||||
unsigned upstream_blocked:1;
|
||||
unsigned downstream_done:1;
|
||||
unsigned downstream_error:1;
|
||||
unsigned cyclic_temp_file:1;
|
||||
unsigned aio:1;
|
||||
|
||||
ngx_int_t allocated;
|
||||
ngx_bufs_t bufs;
|
||||
ngx_buf_tag_t tag;
|
||||
|
||||
ssize_t busy_size;
|
||||
|
||||
off_t read_length;
|
||||
off_t length;
|
||||
|
||||
off_t max_temp_file_size;
|
||||
ssize_t temp_file_write_size;
|
||||
|
||||
ngx_msec_t read_timeout;
|
||||
ngx_msec_t send_timeout;
|
||||
ssize_t send_lowat;
|
||||
|
||||
ngx_pool_t *pool;
|
||||
ngx_log_t *log;
|
||||
|
||||
ngx_chain_t *preread_bufs;
|
||||
size_t preread_size;
|
||||
ngx_buf_t *buf_to_file;
|
||||
|
||||
size_t limit_rate;
|
||||
time_t start_sec;
|
||||
|
||||
ngx_temp_file_t *temp_file;
|
||||
|
||||
/* STUB */ int num;
|
||||
};
|
||||
|
||||
|
||||
ngx_int_t ngx_event_pipe(ngx_event_pipe_t *p, ngx_int_t do_write);
|
||||
ngx_int_t ngx_event_pipe_copy_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf);
|
||||
ngx_int_t ngx_event_pipe_add_free_buf(ngx_event_pipe_t *p, ngx_buf_t *b);
|
||||
|
||||
|
||||
#endif /* _NGX_EVENT_PIPE_H_INCLUDED_ */
|
||||
35
src/event/ngx_event_posted.c
Normal file
35
src/event/ngx_event_posted.c
Normal file
@@ -0,0 +1,35 @@
|
||||
|
||||
/*
|
||||
* 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_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);
|
||||
}
|
||||
}
|
||||
48
src/event/ngx_event_posted.h
Normal file
48
src/event/ngx_event_posted.h
Normal file
@@ -0,0 +1,48 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_EVENT_POSTED_H_INCLUDED_
|
||||
#define _NGX_EVENT_POSTED_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_event.h>
|
||||
|
||||
|
||||
#define ngx_post_event(ev, q) \
|
||||
\
|
||||
if (!(ev)->posted) { \
|
||||
(ev)->posted = 1; \
|
||||
ngx_queue_insert_tail(q, &(ev)->queue); \
|
||||
\
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_CORE, (ev)->log, 0, "post event %p", ev);\
|
||||
\
|
||||
} else { \
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_CORE, (ev)->log, 0, \
|
||||
"update posted event %p", ev); \
|
||||
}
|
||||
|
||||
|
||||
#define ngx_delete_posted_event(ev) \
|
||||
\
|
||||
(ev)->posted = 0; \
|
||||
ngx_queue_remove(&(ev)->queue); \
|
||||
\
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_CORE, (ev)->log, 0, \
|
||||
"delete posted event %p", ev);
|
||||
|
||||
|
||||
|
||||
void ngx_event_process_posted(ngx_cycle_t *cycle, ngx_queue_t *posted);
|
||||
|
||||
|
||||
extern ngx_queue_t ngx_posted_accept_events;
|
||||
extern ngx_queue_t ngx_posted_events;
|
||||
|
||||
|
||||
#endif /* _NGX_EVENT_POSTED_H_INCLUDED_ */
|
||||
138
src/event/ngx_event_timer.c
Normal file
138
src/event/ngx_event_timer.c
Normal file
@@ -0,0 +1,138 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_event.h>
|
||||
|
||||
|
||||
ngx_rbtree_t ngx_event_timer_rbtree;
|
||||
static ngx_rbtree_node_t ngx_event_timer_sentinel;
|
||||
|
||||
/*
|
||||
* the event timer rbtree may contain the duplicate keys, however,
|
||||
* it should not be a problem, because we use the rbtree to find
|
||||
* a minimum timer value only
|
||||
*/
|
||||
|
||||
ngx_int_t
|
||||
ngx_event_timer_init(ngx_log_t *log)
|
||||
{
|
||||
ngx_rbtree_init(&ngx_event_timer_rbtree, &ngx_event_timer_sentinel,
|
||||
ngx_rbtree_insert_timer_value);
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
ngx_msec_t
|
||||
ngx_event_find_timer(void)
|
||||
{
|
||||
ngx_msec_int_t timer;
|
||||
ngx_rbtree_node_t *node, *root, *sentinel;
|
||||
|
||||
if (ngx_event_timer_rbtree.root == &ngx_event_timer_sentinel) {
|
||||
return NGX_TIMER_INFINITE;
|
||||
}
|
||||
|
||||
root = ngx_event_timer_rbtree.root;
|
||||
sentinel = ngx_event_timer_rbtree.sentinel;
|
||||
|
||||
node = ngx_rbtree_min(root, sentinel);
|
||||
|
||||
timer = (ngx_msec_int_t) (node->key - ngx_current_msec);
|
||||
|
||||
return (ngx_msec_t) (timer > 0 ? timer : 0);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_event_expire_timers(void)
|
||||
{
|
||||
ngx_event_t *ev;
|
||||
ngx_rbtree_node_t *node, *root, *sentinel;
|
||||
|
||||
sentinel = ngx_event_timer_rbtree.sentinel;
|
||||
|
||||
for ( ;; ) {
|
||||
root = ngx_event_timer_rbtree.root;
|
||||
|
||||
if (root == sentinel) {
|
||||
return;
|
||||
}
|
||||
|
||||
node = ngx_rbtree_min(root, sentinel);
|
||||
|
||||
/* node->key > ngx_current_time */
|
||||
|
||||
if ((ngx_msec_int_t) (node->key - ngx_current_msec) > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
ev = (ngx_event_t *) ((char *) node - offsetof(ngx_event_t, timer));
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
|
||||
"event timer del: %d: %M",
|
||||
ngx_event_ident(ev->data), ev->timer.key);
|
||||
|
||||
ngx_rbtree_delete(&ngx_event_timer_rbtree, &ev->timer);
|
||||
|
||||
#if (NGX_DEBUG)
|
||||
ev->timer.left = NULL;
|
||||
ev->timer.right = NULL;
|
||||
ev->timer.parent = NULL;
|
||||
#endif
|
||||
|
||||
ev->timer_set = 0;
|
||||
|
||||
ev->timedout = 1;
|
||||
|
||||
ev->handler(ev);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_event_cancel_timers(void)
|
||||
{
|
||||
ngx_event_t *ev;
|
||||
ngx_rbtree_node_t *node, *root, *sentinel;
|
||||
|
||||
sentinel = ngx_event_timer_rbtree.sentinel;
|
||||
|
||||
for ( ;; ) {
|
||||
root = ngx_event_timer_rbtree.root;
|
||||
|
||||
if (root == sentinel) {
|
||||
return;
|
||||
}
|
||||
|
||||
node = ngx_rbtree_min(root, sentinel);
|
||||
|
||||
ev = (ngx_event_t *) ((char *) node - offsetof(ngx_event_t, timer));
|
||||
|
||||
if (!ev->cancelable) {
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
|
||||
"event timer cancel: %d: %M",
|
||||
ngx_event_ident(ev->data), ev->timer.key);
|
||||
|
||||
ngx_rbtree_delete(&ngx_event_timer_rbtree, &ev->timer);
|
||||
|
||||
#if (NGX_DEBUG)
|
||||
ev->timer.left = NULL;
|
||||
ev->timer.right = NULL;
|
||||
ev->timer.parent = NULL;
|
||||
#endif
|
||||
|
||||
ev->timer_set = 0;
|
||||
|
||||
ev->handler(ev);
|
||||
}
|
||||
}
|
||||
90
src/event/ngx_event_timer.h
Normal file
90
src/event/ngx_event_timer.h
Normal file
@@ -0,0 +1,90 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_EVENT_TIMER_H_INCLUDED_
|
||||
#define _NGX_EVENT_TIMER_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_event.h>
|
||||
|
||||
|
||||
#define NGX_TIMER_INFINITE (ngx_msec_t) -1
|
||||
|
||||
#define NGX_TIMER_LAZY_DELAY 300
|
||||
|
||||
|
||||
ngx_int_t ngx_event_timer_init(ngx_log_t *log);
|
||||
ngx_msec_t ngx_event_find_timer(void);
|
||||
void ngx_event_expire_timers(void);
|
||||
void ngx_event_cancel_timers(void);
|
||||
|
||||
|
||||
extern ngx_rbtree_t ngx_event_timer_rbtree;
|
||||
|
||||
|
||||
static ngx_inline void
|
||||
ngx_event_del_timer(ngx_event_t *ev)
|
||||
{
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
|
||||
"event timer del: %d: %M",
|
||||
ngx_event_ident(ev->data), ev->timer.key);
|
||||
|
||||
ngx_rbtree_delete(&ngx_event_timer_rbtree, &ev->timer);
|
||||
|
||||
#if (NGX_DEBUG)
|
||||
ev->timer.left = NULL;
|
||||
ev->timer.right = NULL;
|
||||
ev->timer.parent = NULL;
|
||||
#endif
|
||||
|
||||
ev->timer_set = 0;
|
||||
}
|
||||
|
||||
|
||||
static ngx_inline void
|
||||
ngx_event_add_timer(ngx_event_t *ev, ngx_msec_t timer)
|
||||
{
|
||||
ngx_msec_t key;
|
||||
ngx_msec_int_t diff;
|
||||
|
||||
key = ngx_current_msec + timer;
|
||||
|
||||
if (ev->timer_set) {
|
||||
|
||||
/*
|
||||
* Use a previous timer value if difference between it and a new
|
||||
* value is less than NGX_TIMER_LAZY_DELAY milliseconds: this allows
|
||||
* to minimize the rbtree operations for fast connections.
|
||||
*/
|
||||
|
||||
diff = (ngx_msec_int_t) (key - ev->timer.key);
|
||||
|
||||
if (ngx_abs(diff) < NGX_TIMER_LAZY_DELAY) {
|
||||
ngx_log_debug3(NGX_LOG_DEBUG_EVENT, ev->log, 0,
|
||||
"event timer: %d, old: %M, new: %M",
|
||||
ngx_event_ident(ev->data), ev->timer.key, key);
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_del_timer(ev);
|
||||
}
|
||||
|
||||
ev->timer.key = key;
|
||||
|
||||
ngx_log_debug3(NGX_LOG_DEBUG_EVENT, ev->log, 0,
|
||||
"event timer add: %d: %M:%M",
|
||||
ngx_event_ident(ev->data), timer, ev->timer.key);
|
||||
|
||||
ngx_rbtree_insert(&ngx_event_timer_rbtree, &ev->timer);
|
||||
|
||||
ev->timer_set = 1;
|
||||
}
|
||||
|
||||
|
||||
#endif /* _NGX_EVENT_TIMER_H_INCLUDED_ */
|
||||
469
src/http/modules/ngx_http_access_module.c
Normal file
469
src/http/modules/ngx_http_access_module.c
Normal file
@@ -0,0 +1,469 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_http.h>
|
||||
|
||||
|
||||
typedef struct {
|
||||
in_addr_t mask;
|
||||
in_addr_t addr;
|
||||
ngx_uint_t deny; /* unsigned deny:1; */
|
||||
} ngx_http_access_rule_t;
|
||||
|
||||
#if (NGX_HAVE_INET6)
|
||||
|
||||
typedef struct {
|
||||
struct in6_addr addr;
|
||||
struct in6_addr mask;
|
||||
ngx_uint_t deny; /* unsigned deny:1; */
|
||||
} ngx_http_access_rule6_t;
|
||||
|
||||
#endif
|
||||
|
||||
#if (NGX_HAVE_UNIX_DOMAIN)
|
||||
|
||||
typedef struct {
|
||||
ngx_uint_t deny; /* unsigned deny:1; */
|
||||
} ngx_http_access_rule_un_t;
|
||||
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
ngx_array_t *rules; /* array of ngx_http_access_rule_t */
|
||||
#if (NGX_HAVE_INET6)
|
||||
ngx_array_t *rules6; /* array of ngx_http_access_rule6_t */
|
||||
#endif
|
||||
#if (NGX_HAVE_UNIX_DOMAIN)
|
||||
ngx_array_t *rules_un; /* array of ngx_http_access_rule_un_t */
|
||||
#endif
|
||||
} ngx_http_access_loc_conf_t;
|
||||
|
||||
|
||||
static ngx_int_t ngx_http_access_handler(ngx_http_request_t *r);
|
||||
static ngx_int_t ngx_http_access_inet(ngx_http_request_t *r,
|
||||
ngx_http_access_loc_conf_t *alcf, in_addr_t addr);
|
||||
#if (NGX_HAVE_INET6)
|
||||
static ngx_int_t ngx_http_access_inet6(ngx_http_request_t *r,
|
||||
ngx_http_access_loc_conf_t *alcf, u_char *p);
|
||||
#endif
|
||||
#if (NGX_HAVE_UNIX_DOMAIN)
|
||||
static ngx_int_t ngx_http_access_unix(ngx_http_request_t *r,
|
||||
ngx_http_access_loc_conf_t *alcf);
|
||||
#endif
|
||||
static ngx_int_t ngx_http_access_found(ngx_http_request_t *r, ngx_uint_t deny);
|
||||
static char *ngx_http_access_rule(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
static void *ngx_http_access_create_loc_conf(ngx_conf_t *cf);
|
||||
static char *ngx_http_access_merge_loc_conf(ngx_conf_t *cf,
|
||||
void *parent, void *child);
|
||||
static ngx_int_t ngx_http_access_init(ngx_conf_t *cf);
|
||||
|
||||
|
||||
static ngx_command_t ngx_http_access_commands[] = {
|
||||
|
||||
{ ngx_string("allow"),
|
||||
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF
|
||||
|NGX_CONF_TAKE1,
|
||||
ngx_http_access_rule,
|
||||
NGX_HTTP_LOC_CONF_OFFSET,
|
||||
0,
|
||||
NULL },
|
||||
|
||||
{ ngx_string("deny"),
|
||||
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF
|
||||
|NGX_CONF_TAKE1,
|
||||
ngx_http_access_rule,
|
||||
NGX_HTTP_LOC_CONF_OFFSET,
|
||||
0,
|
||||
NULL },
|
||||
|
||||
ngx_null_command
|
||||
};
|
||||
|
||||
|
||||
|
||||
static ngx_http_module_t ngx_http_access_module_ctx = {
|
||||
NULL, /* preconfiguration */
|
||||
ngx_http_access_init, /* postconfiguration */
|
||||
|
||||
NULL, /* create main configuration */
|
||||
NULL, /* init main configuration */
|
||||
|
||||
NULL, /* create server configuration */
|
||||
NULL, /* merge server configuration */
|
||||
|
||||
ngx_http_access_create_loc_conf, /* create location configuration */
|
||||
ngx_http_access_merge_loc_conf /* merge location configuration */
|
||||
};
|
||||
|
||||
|
||||
ngx_module_t ngx_http_access_module = {
|
||||
NGX_MODULE_V1,
|
||||
&ngx_http_access_module_ctx, /* module context */
|
||||
ngx_http_access_commands, /* module directives */
|
||||
NGX_HTTP_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_http_access_handler(ngx_http_request_t *r)
|
||||
{
|
||||
struct sockaddr_in *sin;
|
||||
ngx_http_access_loc_conf_t *alcf;
|
||||
#if (NGX_HAVE_INET6)
|
||||
u_char *p;
|
||||
in_addr_t addr;
|
||||
struct sockaddr_in6 *sin6;
|
||||
#endif
|
||||
|
||||
alcf = ngx_http_get_module_loc_conf(r, ngx_http_access_module);
|
||||
|
||||
switch (r->connection->sockaddr->sa_family) {
|
||||
|
||||
case AF_INET:
|
||||
if (alcf->rules) {
|
||||
sin = (struct sockaddr_in *) r->connection->sockaddr;
|
||||
return ngx_http_access_inet(r, alcf, sin->sin_addr.s_addr);
|
||||
}
|
||||
break;
|
||||
|
||||
#if (NGX_HAVE_INET6)
|
||||
|
||||
case AF_INET6:
|
||||
sin6 = (struct sockaddr_in6 *) r->connection->sockaddr;
|
||||
p = sin6->sin6_addr.s6_addr;
|
||||
|
||||
if (alcf->rules && IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
|
||||
addr = p[12] << 24;
|
||||
addr += p[13] << 16;
|
||||
addr += p[14] << 8;
|
||||
addr += p[15];
|
||||
return ngx_http_access_inet(r, alcf, htonl(addr));
|
||||
}
|
||||
|
||||
if (alcf->rules6) {
|
||||
return ngx_http_access_inet6(r, alcf, p);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
#endif
|
||||
|
||||
#if (NGX_HAVE_UNIX_DOMAIN)
|
||||
|
||||
case AF_UNIX:
|
||||
if (alcf->rules_un) {
|
||||
return ngx_http_access_unix(r, alcf);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_access_inet(ngx_http_request_t *r, ngx_http_access_loc_conf_t *alcf,
|
||||
in_addr_t addr)
|
||||
{
|
||||
ngx_uint_t i;
|
||||
ngx_http_access_rule_t *rule;
|
||||
|
||||
rule = alcf->rules->elts;
|
||||
for (i = 0; i < alcf->rules->nelts; i++) {
|
||||
|
||||
ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"access: %08XD %08XD %08XD",
|
||||
addr, rule[i].mask, rule[i].addr);
|
||||
|
||||
if ((addr & rule[i].mask) == rule[i].addr) {
|
||||
return ngx_http_access_found(r, rule[i].deny);
|
||||
}
|
||||
}
|
||||
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
|
||||
#if (NGX_HAVE_INET6)
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_access_inet6(ngx_http_request_t *r, ngx_http_access_loc_conf_t *alcf,
|
||||
u_char *p)
|
||||
{
|
||||
ngx_uint_t n;
|
||||
ngx_uint_t i;
|
||||
ngx_http_access_rule6_t *rule6;
|
||||
|
||||
rule6 = alcf->rules6->elts;
|
||||
for (i = 0; i < alcf->rules6->nelts; i++) {
|
||||
|
||||
#if (NGX_DEBUG)
|
||||
{
|
||||
size_t cl, ml, al;
|
||||
u_char ct[NGX_INET6_ADDRSTRLEN];
|
||||
u_char mt[NGX_INET6_ADDRSTRLEN];
|
||||
u_char at[NGX_INET6_ADDRSTRLEN];
|
||||
|
||||
cl = ngx_inet6_ntop(p, ct, NGX_INET6_ADDRSTRLEN);
|
||||
ml = ngx_inet6_ntop(rule6[i].mask.s6_addr, mt, NGX_INET6_ADDRSTRLEN);
|
||||
al = ngx_inet6_ntop(rule6[i].addr.s6_addr, at, NGX_INET6_ADDRSTRLEN);
|
||||
|
||||
ngx_log_debug6(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"access: %*s %*s %*s", cl, ct, ml, mt, al, at);
|
||||
}
|
||||
#endif
|
||||
|
||||
for (n = 0; n < 16; n++) {
|
||||
if ((p[n] & rule6[i].mask.s6_addr[n]) != rule6[i].addr.s6_addr[n]) {
|
||||
goto next;
|
||||
}
|
||||
}
|
||||
|
||||
return ngx_http_access_found(r, rule6[i].deny);
|
||||
|
||||
next:
|
||||
continue;
|
||||
}
|
||||
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if (NGX_HAVE_UNIX_DOMAIN)
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_access_unix(ngx_http_request_t *r, ngx_http_access_loc_conf_t *alcf)
|
||||
{
|
||||
ngx_uint_t i;
|
||||
ngx_http_access_rule_un_t *rule_un;
|
||||
|
||||
rule_un = alcf->rules_un->elts;
|
||||
for (i = 0; i < alcf->rules_un->nelts; i++) {
|
||||
|
||||
/* TODO: check path */
|
||||
if (1) {
|
||||
return ngx_http_access_found(r, rule_un[i].deny);
|
||||
}
|
||||
}
|
||||
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_access_found(ngx_http_request_t *r, ngx_uint_t deny)
|
||||
{
|
||||
ngx_http_core_loc_conf_t *clcf;
|
||||
|
||||
if (deny) {
|
||||
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
|
||||
|
||||
if (clcf->satisfy == NGX_HTTP_SATISFY_ALL) {
|
||||
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
|
||||
"access forbidden by rule");
|
||||
}
|
||||
|
||||
return NGX_HTTP_FORBIDDEN;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
ngx_http_access_rule(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
||||
{
|
||||
ngx_http_access_loc_conf_t *alcf = conf;
|
||||
|
||||
ngx_int_t rc;
|
||||
ngx_uint_t all;
|
||||
ngx_str_t *value;
|
||||
ngx_cidr_t cidr;
|
||||
ngx_http_access_rule_t *rule;
|
||||
#if (NGX_HAVE_INET6)
|
||||
ngx_http_access_rule6_t *rule6;
|
||||
#endif
|
||||
#if (NGX_HAVE_UNIX_DOMAIN)
|
||||
ngx_http_access_rule_un_t *rule_un;
|
||||
#endif
|
||||
|
||||
ngx_memzero(&cidr, sizeof(ngx_cidr_t));
|
||||
|
||||
value = cf->args->elts;
|
||||
|
||||
all = (value[1].len == 3 && ngx_strcmp(value[1].data, "all") == 0);
|
||||
|
||||
if (!all) {
|
||||
|
||||
#if (NGX_HAVE_UNIX_DOMAIN)
|
||||
|
||||
if (value[1].len == 5 && ngx_strcmp(value[1].data, "unix:") == 0) {
|
||||
cidr.family = AF_UNIX;
|
||||
rc = NGX_OK;
|
||||
|
||||
} else {
|
||||
rc = ngx_ptocidr(&value[1], &cidr);
|
||||
}
|
||||
|
||||
#else
|
||||
rc = ngx_ptocidr(&value[1], &cidr);
|
||||
#endif
|
||||
|
||||
if (rc == NGX_ERROR) {
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"invalid parameter \"%V\"", &value[1]);
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
if (rc == NGX_DONE) {
|
||||
ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
|
||||
"low address bits of %V are meaningless", &value[1]);
|
||||
}
|
||||
}
|
||||
|
||||
if (cidr.family == AF_INET || all) {
|
||||
|
||||
if (alcf->rules == NULL) {
|
||||
alcf->rules = ngx_array_create(cf->pool, 4,
|
||||
sizeof(ngx_http_access_rule_t));
|
||||
if (alcf->rules == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
rule = ngx_array_push(alcf->rules);
|
||||
if (rule == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
rule->mask = cidr.u.in.mask;
|
||||
rule->addr = cidr.u.in.addr;
|
||||
rule->deny = (value[0].data[0] == 'd') ? 1 : 0;
|
||||
}
|
||||
|
||||
#if (NGX_HAVE_INET6)
|
||||
if (cidr.family == AF_INET6 || all) {
|
||||
|
||||
if (alcf->rules6 == NULL) {
|
||||
alcf->rules6 = ngx_array_create(cf->pool, 4,
|
||||
sizeof(ngx_http_access_rule6_t));
|
||||
if (alcf->rules6 == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
rule6 = ngx_array_push(alcf->rules6);
|
||||
if (rule6 == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
rule6->mask = cidr.u.in6.mask;
|
||||
rule6->addr = cidr.u.in6.addr;
|
||||
rule6->deny = (value[0].data[0] == 'd') ? 1 : 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (NGX_HAVE_UNIX_DOMAIN)
|
||||
if (cidr.family == AF_UNIX || all) {
|
||||
|
||||
if (alcf->rules_un == NULL) {
|
||||
alcf->rules_un = ngx_array_create(cf->pool, 1,
|
||||
sizeof(ngx_http_access_rule_un_t));
|
||||
if (alcf->rules_un == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
rule_un = ngx_array_push(alcf->rules_un);
|
||||
if (rule_un == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
rule_un->deny = (value[0].data[0] == 'd') ? 1 : 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
ngx_http_access_create_loc_conf(ngx_conf_t *cf)
|
||||
{
|
||||
ngx_http_access_loc_conf_t *conf;
|
||||
|
||||
conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_access_loc_conf_t));
|
||||
if (conf == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return conf;
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
ngx_http_access_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
|
||||
{
|
||||
ngx_http_access_loc_conf_t *prev = parent;
|
||||
ngx_http_access_loc_conf_t *conf = child;
|
||||
|
||||
if (conf->rules == NULL
|
||||
#if (NGX_HAVE_INET6)
|
||||
&& conf->rules6 == NULL
|
||||
#endif
|
||||
#if (NGX_HAVE_UNIX_DOMAIN)
|
||||
&& conf->rules_un == NULL
|
||||
#endif
|
||||
) {
|
||||
conf->rules = prev->rules;
|
||||
#if (NGX_HAVE_INET6)
|
||||
conf->rules6 = prev->rules6;
|
||||
#endif
|
||||
#if (NGX_HAVE_UNIX_DOMAIN)
|
||||
conf->rules_un = prev->rules_un;
|
||||
#endif
|
||||
}
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_access_init(ngx_conf_t *cf)
|
||||
{
|
||||
ngx_http_handler_pt *h;
|
||||
ngx_http_core_main_conf_t *cmcf;
|
||||
|
||||
cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
|
||||
|
||||
h = ngx_array_push(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers);
|
||||
if (h == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
*h = ngx_http_access_handler;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
252
src/http/modules/ngx_http_addition_filter_module.c
Normal file
252
src/http/modules/ngx_http_addition_filter_module.c
Normal file
@@ -0,0 +1,252 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_http.h>
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_str_t before_body;
|
||||
ngx_str_t after_body;
|
||||
|
||||
ngx_hash_t types;
|
||||
ngx_array_t *types_keys;
|
||||
} ngx_http_addition_conf_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_uint_t before_body_sent;
|
||||
} ngx_http_addition_ctx_t;
|
||||
|
||||
|
||||
static void *ngx_http_addition_create_conf(ngx_conf_t *cf);
|
||||
static char *ngx_http_addition_merge_conf(ngx_conf_t *cf, void *parent,
|
||||
void *child);
|
||||
static ngx_int_t ngx_http_addition_filter_init(ngx_conf_t *cf);
|
||||
|
||||
|
||||
static ngx_command_t ngx_http_addition_commands[] = {
|
||||
|
||||
{ ngx_string("add_before_body"),
|
||||
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
|
||||
ngx_conf_set_str_slot,
|
||||
NGX_HTTP_LOC_CONF_OFFSET,
|
||||
offsetof(ngx_http_addition_conf_t, before_body),
|
||||
NULL },
|
||||
|
||||
{ ngx_string("add_after_body"),
|
||||
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
|
||||
ngx_conf_set_str_slot,
|
||||
NGX_HTTP_LOC_CONF_OFFSET,
|
||||
offsetof(ngx_http_addition_conf_t, after_body),
|
||||
NULL },
|
||||
|
||||
{ ngx_string("addition_types"),
|
||||
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
|
||||
ngx_http_types_slot,
|
||||
NGX_HTTP_LOC_CONF_OFFSET,
|
||||
offsetof(ngx_http_addition_conf_t, types_keys),
|
||||
&ngx_http_html_default_types[0] },
|
||||
|
||||
ngx_null_command
|
||||
};
|
||||
|
||||
|
||||
static ngx_http_module_t ngx_http_addition_filter_module_ctx = {
|
||||
NULL, /* preconfiguration */
|
||||
ngx_http_addition_filter_init, /* postconfiguration */
|
||||
|
||||
NULL, /* create main configuration */
|
||||
NULL, /* init main configuration */
|
||||
|
||||
NULL, /* create server configuration */
|
||||
NULL, /* merge server configuration */
|
||||
|
||||
ngx_http_addition_create_conf, /* create location configuration */
|
||||
ngx_http_addition_merge_conf /* merge location configuration */
|
||||
};
|
||||
|
||||
|
||||
ngx_module_t ngx_http_addition_filter_module = {
|
||||
NGX_MODULE_V1,
|
||||
&ngx_http_addition_filter_module_ctx, /* module context */
|
||||
ngx_http_addition_commands, /* module directives */
|
||||
NGX_HTTP_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_http_output_header_filter_pt ngx_http_next_header_filter;
|
||||
static ngx_http_output_body_filter_pt ngx_http_next_body_filter;
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_addition_header_filter(ngx_http_request_t *r)
|
||||
{
|
||||
ngx_http_addition_ctx_t *ctx;
|
||||
ngx_http_addition_conf_t *conf;
|
||||
|
||||
if (r->headers_out.status != NGX_HTTP_OK || r != r->main) {
|
||||
return ngx_http_next_header_filter(r);
|
||||
}
|
||||
|
||||
conf = ngx_http_get_module_loc_conf(r, ngx_http_addition_filter_module);
|
||||
|
||||
if (conf->before_body.len == 0 && conf->after_body.len == 0) {
|
||||
return ngx_http_next_header_filter(r);
|
||||
}
|
||||
|
||||
if (ngx_http_test_content_type(r, &conf->types) == NULL) {
|
||||
return ngx_http_next_header_filter(r);
|
||||
}
|
||||
|
||||
ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_addition_ctx_t));
|
||||
if (ctx == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_http_set_ctx(r, ctx, ngx_http_addition_filter_module);
|
||||
|
||||
ngx_http_clear_content_length(r);
|
||||
ngx_http_clear_accept_ranges(r);
|
||||
ngx_http_weak_etag(r);
|
||||
|
||||
return ngx_http_next_header_filter(r);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_addition_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
|
||||
{
|
||||
ngx_int_t rc;
|
||||
ngx_uint_t last;
|
||||
ngx_chain_t *cl;
|
||||
ngx_http_request_t *sr;
|
||||
ngx_http_addition_ctx_t *ctx;
|
||||
ngx_http_addition_conf_t *conf;
|
||||
|
||||
if (in == NULL || r->header_only) {
|
||||
return ngx_http_next_body_filter(r, in);
|
||||
}
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_addition_filter_module);
|
||||
|
||||
if (ctx == NULL) {
|
||||
return ngx_http_next_body_filter(r, in);
|
||||
}
|
||||
|
||||
conf = ngx_http_get_module_loc_conf(r, ngx_http_addition_filter_module);
|
||||
|
||||
if (!ctx->before_body_sent) {
|
||||
ctx->before_body_sent = 1;
|
||||
|
||||
if (conf->before_body.len) {
|
||||
if (ngx_http_subrequest(r, &conf->before_body, NULL, &sr, NULL, 0)
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (conf->after_body.len == 0) {
|
||||
ngx_http_set_ctx(r, NULL, ngx_http_addition_filter_module);
|
||||
return ngx_http_next_body_filter(r, in);
|
||||
}
|
||||
|
||||
last = 0;
|
||||
|
||||
for (cl = in; cl; cl = cl->next) {
|
||||
if (cl->buf->last_buf) {
|
||||
cl->buf->last_buf = 0;
|
||||
cl->buf->last_in_chain = 1;
|
||||
cl->buf->sync = 1;
|
||||
last = 1;
|
||||
}
|
||||
}
|
||||
|
||||
rc = ngx_http_next_body_filter(r, in);
|
||||
|
||||
if (rc == NGX_ERROR || !last || conf->after_body.len == 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (ngx_http_subrequest(r, &conf->after_body, NULL, &sr, NULL, 0)
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_http_set_ctx(r, NULL, ngx_http_addition_filter_module);
|
||||
|
||||
return ngx_http_send_special(r, NGX_HTTP_LAST);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_addition_filter_init(ngx_conf_t *cf)
|
||||
{
|
||||
ngx_http_next_header_filter = ngx_http_top_header_filter;
|
||||
ngx_http_top_header_filter = ngx_http_addition_header_filter;
|
||||
|
||||
ngx_http_next_body_filter = ngx_http_top_body_filter;
|
||||
ngx_http_top_body_filter = ngx_http_addition_body_filter;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
ngx_http_addition_create_conf(ngx_conf_t *cf)
|
||||
{
|
||||
ngx_http_addition_conf_t *conf;
|
||||
|
||||
conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_addition_conf_t));
|
||||
if (conf == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* set by ngx_pcalloc():
|
||||
*
|
||||
* conf->before_body = { 0, NULL };
|
||||
* conf->after_body = { 0, NULL };
|
||||
* conf->types = { NULL };
|
||||
* conf->types_keys = NULL;
|
||||
*/
|
||||
|
||||
return conf;
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
ngx_http_addition_merge_conf(ngx_conf_t *cf, void *parent, void *child)
|
||||
{
|
||||
ngx_http_addition_conf_t *prev = parent;
|
||||
ngx_http_addition_conf_t *conf = child;
|
||||
|
||||
ngx_conf_merge_str_value(conf->before_body, prev->before_body, "");
|
||||
ngx_conf_merge_str_value(conf->after_body, prev->after_body, "");
|
||||
|
||||
if (ngx_http_merge_types(cf, &conf->types_keys, &conf->types,
|
||||
&prev->types_keys, &prev->types,
|
||||
ngx_http_html_default_types)
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
467
src/http/modules/ngx_http_auth_basic_module.c
Normal file
467
src/http/modules/ngx_http_auth_basic_module.c
Normal file
@@ -0,0 +1,467 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_http.h>
|
||||
#include <ngx_crypt.h>
|
||||
|
||||
|
||||
#define NGX_HTTP_AUTH_BUF_SIZE 2048
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_str_t passwd;
|
||||
} ngx_http_auth_basic_ctx_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_http_complex_value_t *realm;
|
||||
ngx_http_complex_value_t user_file;
|
||||
} ngx_http_auth_basic_loc_conf_t;
|
||||
|
||||
|
||||
static ngx_int_t ngx_http_auth_basic_handler(ngx_http_request_t *r);
|
||||
static ngx_int_t ngx_http_auth_basic_crypt_handler(ngx_http_request_t *r,
|
||||
ngx_http_auth_basic_ctx_t *ctx, ngx_str_t *passwd, ngx_str_t *realm);
|
||||
static ngx_int_t ngx_http_auth_basic_set_realm(ngx_http_request_t *r,
|
||||
ngx_str_t *realm);
|
||||
static void ngx_http_auth_basic_close(ngx_file_t *file);
|
||||
static void *ngx_http_auth_basic_create_loc_conf(ngx_conf_t *cf);
|
||||
static char *ngx_http_auth_basic_merge_loc_conf(ngx_conf_t *cf,
|
||||
void *parent, void *child);
|
||||
static ngx_int_t ngx_http_auth_basic_init(ngx_conf_t *cf);
|
||||
static char *ngx_http_auth_basic_user_file(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
|
||||
|
||||
static ngx_command_t ngx_http_auth_basic_commands[] = {
|
||||
|
||||
{ ngx_string("auth_basic"),
|
||||
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF
|
||||
|NGX_CONF_TAKE1,
|
||||
ngx_http_set_complex_value_slot,
|
||||
NGX_HTTP_LOC_CONF_OFFSET,
|
||||
offsetof(ngx_http_auth_basic_loc_conf_t, realm),
|
||||
NULL },
|
||||
|
||||
{ ngx_string("auth_basic_user_file"),
|
||||
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF
|
||||
|NGX_CONF_TAKE1,
|
||||
ngx_http_auth_basic_user_file,
|
||||
NGX_HTTP_LOC_CONF_OFFSET,
|
||||
offsetof(ngx_http_auth_basic_loc_conf_t, user_file),
|
||||
NULL },
|
||||
|
||||
ngx_null_command
|
||||
};
|
||||
|
||||
|
||||
static ngx_http_module_t ngx_http_auth_basic_module_ctx = {
|
||||
NULL, /* preconfiguration */
|
||||
ngx_http_auth_basic_init, /* postconfiguration */
|
||||
|
||||
NULL, /* create main configuration */
|
||||
NULL, /* init main configuration */
|
||||
|
||||
NULL, /* create server configuration */
|
||||
NULL, /* merge server configuration */
|
||||
|
||||
ngx_http_auth_basic_create_loc_conf, /* create location configuration */
|
||||
ngx_http_auth_basic_merge_loc_conf /* merge location configuration */
|
||||
};
|
||||
|
||||
|
||||
ngx_module_t ngx_http_auth_basic_module = {
|
||||
NGX_MODULE_V1,
|
||||
&ngx_http_auth_basic_module_ctx, /* module context */
|
||||
ngx_http_auth_basic_commands, /* module directives */
|
||||
NGX_HTTP_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_http_auth_basic_handler(ngx_http_request_t *r)
|
||||
{
|
||||
off_t offset;
|
||||
ssize_t n;
|
||||
ngx_fd_t fd;
|
||||
ngx_int_t rc;
|
||||
ngx_err_t err;
|
||||
ngx_str_t pwd, realm, user_file;
|
||||
ngx_uint_t i, level, login, left, passwd;
|
||||
ngx_file_t file;
|
||||
ngx_http_auth_basic_ctx_t *ctx;
|
||||
ngx_http_auth_basic_loc_conf_t *alcf;
|
||||
u_char buf[NGX_HTTP_AUTH_BUF_SIZE];
|
||||
enum {
|
||||
sw_login,
|
||||
sw_passwd,
|
||||
sw_skip
|
||||
} state;
|
||||
|
||||
alcf = ngx_http_get_module_loc_conf(r, ngx_http_auth_basic_module);
|
||||
|
||||
if (alcf->realm == NULL || alcf->user_file.value.data == NULL) {
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
if (ngx_http_complex_value(r, alcf->realm, &realm) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (realm.len == 3 && ngx_strncmp(realm.data, "off", 3) == 0) {
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_auth_basic_module);
|
||||
|
||||
if (ctx) {
|
||||
return ngx_http_auth_basic_crypt_handler(r, ctx, &ctx->passwd,
|
||||
&realm);
|
||||
}
|
||||
|
||||
rc = ngx_http_auth_basic_user(r);
|
||||
|
||||
if (rc == NGX_DECLINED) {
|
||||
|
||||
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
|
||||
"no user/password was provided for basic authentication");
|
||||
|
||||
return ngx_http_auth_basic_set_realm(r, &realm);
|
||||
}
|
||||
|
||||
if (rc == NGX_ERROR) {
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
if (ngx_http_complex_value(r, &alcf->user_file, &user_file) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
fd = ngx_open_file(user_file.data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
|
||||
|
||||
if (fd == NGX_INVALID_FILE) {
|
||||
err = ngx_errno;
|
||||
|
||||
if (err == NGX_ENOENT) {
|
||||
level = NGX_LOG_ERR;
|
||||
rc = NGX_HTTP_FORBIDDEN;
|
||||
|
||||
} else {
|
||||
level = NGX_LOG_CRIT;
|
||||
rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
ngx_log_error(level, r->connection->log, err,
|
||||
ngx_open_file_n " \"%s\" failed", user_file.data);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
ngx_memzero(&file, sizeof(ngx_file_t));
|
||||
|
||||
file.fd = fd;
|
||||
file.name = user_file;
|
||||
file.log = r->connection->log;
|
||||
|
||||
state = sw_login;
|
||||
passwd = 0;
|
||||
login = 0;
|
||||
left = 0;
|
||||
offset = 0;
|
||||
|
||||
for ( ;; ) {
|
||||
i = left;
|
||||
|
||||
n = ngx_read_file(&file, buf + left, NGX_HTTP_AUTH_BUF_SIZE - left,
|
||||
offset);
|
||||
|
||||
if (n == NGX_ERROR) {
|
||||
ngx_http_auth_basic_close(&file);
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
if (n == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = left; i < left + n; i++) {
|
||||
switch (state) {
|
||||
|
||||
case sw_login:
|
||||
if (login == 0) {
|
||||
|
||||
if (buf[i] == '#' || buf[i] == CR) {
|
||||
state = sw_skip;
|
||||
break;
|
||||
}
|
||||
|
||||
if (buf[i] == LF) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (buf[i] != r->headers_in.user.data[login]) {
|
||||
state = sw_skip;
|
||||
break;
|
||||
}
|
||||
|
||||
if (login == r->headers_in.user.len) {
|
||||
state = sw_passwd;
|
||||
passwd = i + 1;
|
||||
}
|
||||
|
||||
login++;
|
||||
|
||||
break;
|
||||
|
||||
case sw_passwd:
|
||||
if (buf[i] == LF || buf[i] == CR || buf[i] == ':') {
|
||||
buf[i] = '\0';
|
||||
|
||||
ngx_http_auth_basic_close(&file);
|
||||
|
||||
pwd.len = i - passwd;
|
||||
pwd.data = &buf[passwd];
|
||||
|
||||
return ngx_http_auth_basic_crypt_handler(r, NULL, &pwd,
|
||||
&realm);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case sw_skip:
|
||||
if (buf[i] == LF) {
|
||||
state = sw_login;
|
||||
login = 0;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (state == sw_passwd) {
|
||||
left = left + n - passwd;
|
||||
ngx_memmove(buf, &buf[passwd], left);
|
||||
passwd = 0;
|
||||
|
||||
} else {
|
||||
left = 0;
|
||||
}
|
||||
|
||||
offset += n;
|
||||
}
|
||||
|
||||
ngx_http_auth_basic_close(&file);
|
||||
|
||||
if (state == sw_passwd) {
|
||||
pwd.len = i - passwd;
|
||||
pwd.data = ngx_pnalloc(r->pool, pwd.len + 1);
|
||||
if (pwd.data == NULL) {
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
ngx_cpystrn(pwd.data, &buf[passwd], pwd.len + 1);
|
||||
|
||||
return ngx_http_auth_basic_crypt_handler(r, NULL, &pwd, &realm);
|
||||
}
|
||||
|
||||
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
|
||||
"user \"%V\" was not found in \"%V\"",
|
||||
&r->headers_in.user, &user_file);
|
||||
|
||||
return ngx_http_auth_basic_set_realm(r, &realm);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_auth_basic_crypt_handler(ngx_http_request_t *r,
|
||||
ngx_http_auth_basic_ctx_t *ctx, ngx_str_t *passwd, ngx_str_t *realm)
|
||||
{
|
||||
ngx_int_t rc;
|
||||
u_char *encrypted;
|
||||
|
||||
rc = ngx_crypt(r->pool, r->headers_in.passwd.data, passwd->data,
|
||||
&encrypted);
|
||||
|
||||
ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"rc: %i user: \"%V\" salt: \"%s\"",
|
||||
rc, &r->headers_in.user, passwd->data);
|
||||
|
||||
if (rc == NGX_OK) {
|
||||
if (ngx_strcmp(encrypted, passwd->data) == 0) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"encrypted: \"%s\"", encrypted);
|
||||
|
||||
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
|
||||
"user \"%V\": password mismatch",
|
||||
&r->headers_in.user);
|
||||
|
||||
return ngx_http_auth_basic_set_realm(r, realm);
|
||||
}
|
||||
|
||||
if (rc == NGX_ERROR) {
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
/* rc == NGX_AGAIN */
|
||||
|
||||
if (ctx == NULL) {
|
||||
ctx = ngx_palloc(r->pool, sizeof(ngx_http_auth_basic_ctx_t));
|
||||
if (ctx == NULL) {
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
ngx_http_set_ctx(r, ctx, ngx_http_auth_basic_module);
|
||||
|
||||
ctx->passwd.len = passwd->len;
|
||||
passwd->len++;
|
||||
|
||||
ctx->passwd.data = ngx_pstrdup(r->pool, passwd);
|
||||
if (ctx->passwd.data == NULL) {
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* TODO: add mutex event */
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_auth_basic_set_realm(ngx_http_request_t *r, ngx_str_t *realm)
|
||||
{
|
||||
size_t len;
|
||||
u_char *basic, *p;
|
||||
|
||||
r->headers_out.www_authenticate = ngx_list_push(&r->headers_out.headers);
|
||||
if (r->headers_out.www_authenticate == NULL) {
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
len = sizeof("Basic realm=\"\"") - 1 + realm->len;
|
||||
|
||||
basic = ngx_pnalloc(r->pool, len);
|
||||
if (basic == NULL) {
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
p = ngx_cpymem(basic, "Basic realm=\"", sizeof("Basic realm=\"") - 1);
|
||||
p = ngx_cpymem(p, realm->data, realm->len);
|
||||
*p = '"';
|
||||
|
||||
r->headers_out.www_authenticate->hash = 1;
|
||||
ngx_str_set(&r->headers_out.www_authenticate->key, "WWW-Authenticate");
|
||||
r->headers_out.www_authenticate->value.data = basic;
|
||||
r->headers_out.www_authenticate->value.len = len;
|
||||
|
||||
return NGX_HTTP_UNAUTHORIZED;
|
||||
}
|
||||
|
||||
static void
|
||||
ngx_http_auth_basic_close(ngx_file_t *file)
|
||||
{
|
||||
if (ngx_close_file(file->fd) == NGX_FILE_ERROR) {
|
||||
ngx_log_error(NGX_LOG_ALERT, file->log, ngx_errno,
|
||||
ngx_close_file_n " \"%s\" failed", file->name.data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
ngx_http_auth_basic_create_loc_conf(ngx_conf_t *cf)
|
||||
{
|
||||
ngx_http_auth_basic_loc_conf_t *conf;
|
||||
|
||||
conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_auth_basic_loc_conf_t));
|
||||
if (conf == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return conf;
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
ngx_http_auth_basic_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
|
||||
{
|
||||
ngx_http_auth_basic_loc_conf_t *prev = parent;
|
||||
ngx_http_auth_basic_loc_conf_t *conf = child;
|
||||
|
||||
if (conf->realm == NULL) {
|
||||
conf->realm = prev->realm;
|
||||
}
|
||||
|
||||
if (conf->user_file.value.data == NULL) {
|
||||
conf->user_file = prev->user_file;
|
||||
}
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_auth_basic_init(ngx_conf_t *cf)
|
||||
{
|
||||
ngx_http_handler_pt *h;
|
||||
ngx_http_core_main_conf_t *cmcf;
|
||||
|
||||
cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
|
||||
|
||||
h = ngx_array_push(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers);
|
||||
if (h == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
*h = ngx_http_auth_basic_handler;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
ngx_http_auth_basic_user_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
||||
{
|
||||
ngx_http_auth_basic_loc_conf_t *alcf = conf;
|
||||
|
||||
ngx_str_t *value;
|
||||
ngx_http_compile_complex_value_t ccv;
|
||||
|
||||
if (alcf->user_file.value.data) {
|
||||
return "is duplicate";
|
||||
}
|
||||
|
||||
value = cf->args->elts;
|
||||
|
||||
ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
|
||||
|
||||
ccv.cf = cf;
|
||||
ccv.value = &value[1];
|
||||
ccv.complex_value = &alcf->user_file;
|
||||
ccv.zero = 1;
|
||||
ccv.conf_prefix = 1;
|
||||
|
||||
if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
444
src/http/modules/ngx_http_auth_request_module.c
Normal file
444
src/http/modules/ngx_http_auth_request_module.c
Normal file
@@ -0,0 +1,444 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Maxim Dounin
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_http.h>
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_str_t uri;
|
||||
ngx_array_t *vars;
|
||||
} ngx_http_auth_request_conf_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_uint_t done;
|
||||
ngx_uint_t status;
|
||||
ngx_http_request_t *subrequest;
|
||||
} ngx_http_auth_request_ctx_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_int_t index;
|
||||
ngx_http_complex_value_t value;
|
||||
ngx_http_set_variable_pt set_handler;
|
||||
} ngx_http_auth_request_variable_t;
|
||||
|
||||
|
||||
static ngx_int_t ngx_http_auth_request_handler(ngx_http_request_t *r);
|
||||
static ngx_int_t ngx_http_auth_request_done(ngx_http_request_t *r,
|
||||
void *data, ngx_int_t rc);
|
||||
static ngx_int_t ngx_http_auth_request_set_variables(ngx_http_request_t *r,
|
||||
ngx_http_auth_request_conf_t *arcf, ngx_http_auth_request_ctx_t *ctx);
|
||||
static ngx_int_t ngx_http_auth_request_variable(ngx_http_request_t *r,
|
||||
ngx_http_variable_value_t *v, uintptr_t data);
|
||||
static void *ngx_http_auth_request_create_conf(ngx_conf_t *cf);
|
||||
static char *ngx_http_auth_request_merge_conf(ngx_conf_t *cf,
|
||||
void *parent, void *child);
|
||||
static ngx_int_t ngx_http_auth_request_init(ngx_conf_t *cf);
|
||||
static char *ngx_http_auth_request(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
static char *ngx_http_auth_request_set(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
|
||||
|
||||
static ngx_command_t ngx_http_auth_request_commands[] = {
|
||||
|
||||
{ ngx_string("auth_request"),
|
||||
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
|
||||
ngx_http_auth_request,
|
||||
NGX_HTTP_LOC_CONF_OFFSET,
|
||||
0,
|
||||
NULL },
|
||||
|
||||
{ ngx_string("auth_request_set"),
|
||||
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
|
||||
ngx_http_auth_request_set,
|
||||
NGX_HTTP_LOC_CONF_OFFSET,
|
||||
0,
|
||||
NULL },
|
||||
|
||||
ngx_null_command
|
||||
};
|
||||
|
||||
|
||||
static ngx_http_module_t ngx_http_auth_request_module_ctx = {
|
||||
NULL, /* preconfiguration */
|
||||
ngx_http_auth_request_init, /* postconfiguration */
|
||||
|
||||
NULL, /* create main configuration */
|
||||
NULL, /* init main configuration */
|
||||
|
||||
NULL, /* create server configuration */
|
||||
NULL, /* merge server configuration */
|
||||
|
||||
ngx_http_auth_request_create_conf, /* create location configuration */
|
||||
ngx_http_auth_request_merge_conf /* merge location configuration */
|
||||
};
|
||||
|
||||
|
||||
ngx_module_t ngx_http_auth_request_module = {
|
||||
NGX_MODULE_V1,
|
||||
&ngx_http_auth_request_module_ctx, /* module context */
|
||||
ngx_http_auth_request_commands, /* module directives */
|
||||
NGX_HTTP_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_http_auth_request_handler(ngx_http_request_t *r)
|
||||
{
|
||||
ngx_table_elt_t *h, *ho;
|
||||
ngx_http_request_t *sr;
|
||||
ngx_http_post_subrequest_t *ps;
|
||||
ngx_http_auth_request_ctx_t *ctx;
|
||||
ngx_http_auth_request_conf_t *arcf;
|
||||
|
||||
arcf = ngx_http_get_module_loc_conf(r, ngx_http_auth_request_module);
|
||||
|
||||
if (arcf->uri.len == 0) {
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"auth request handler");
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_auth_request_module);
|
||||
|
||||
if (ctx != NULL) {
|
||||
if (!ctx->done) {
|
||||
return NGX_AGAIN;
|
||||
}
|
||||
|
||||
/*
|
||||
* as soon as we are done - explicitly set variables to make
|
||||
* sure they will be available after internal redirects
|
||||
*/
|
||||
|
||||
if (ngx_http_auth_request_set_variables(r, arcf, ctx) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
/* return appropriate status */
|
||||
|
||||
if (ctx->status == NGX_HTTP_FORBIDDEN) {
|
||||
return ctx->status;
|
||||
}
|
||||
|
||||
if (ctx->status == NGX_HTTP_UNAUTHORIZED) {
|
||||
sr = ctx->subrequest;
|
||||
|
||||
h = sr->headers_out.www_authenticate;
|
||||
|
||||
if (!h && sr->upstream) {
|
||||
h = sr->upstream->headers_in.www_authenticate;
|
||||
}
|
||||
|
||||
if (h) {
|
||||
ho = ngx_list_push(&r->headers_out.headers);
|
||||
if (ho == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
*ho = *h;
|
||||
|
||||
r->headers_out.www_authenticate = ho;
|
||||
}
|
||||
|
||||
return ctx->status;
|
||||
}
|
||||
|
||||
if (ctx->status >= NGX_HTTP_OK
|
||||
&& ctx->status < NGX_HTTP_SPECIAL_RESPONSE)
|
||||
{
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
|
||||
"auth request unexpected status: %ui", ctx->status);
|
||||
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_auth_request_ctx_t));
|
||||
if (ctx == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ps = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t));
|
||||
if (ps == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ps->handler = ngx_http_auth_request_done;
|
||||
ps->data = ctx;
|
||||
|
||||
if (ngx_http_subrequest(r, &arcf->uri, NULL, &sr, ps,
|
||||
NGX_HTTP_SUBREQUEST_WAITED)
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* allocate fake request body to avoid attempts to read it and to make
|
||||
* sure real body file (if already read) won't be closed by upstream
|
||||
*/
|
||||
|
||||
sr->request_body = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
|
||||
if (sr->request_body == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
sr->header_only = 1;
|
||||
|
||||
ctx->subrequest = sr;
|
||||
|
||||
ngx_http_set_ctx(r, ctx, ngx_http_auth_request_module);
|
||||
|
||||
return NGX_AGAIN;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_auth_request_done(ngx_http_request_t *r, void *data, ngx_int_t rc)
|
||||
{
|
||||
ngx_http_auth_request_ctx_t *ctx = data;
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"auth request done s:%ui", r->headers_out.status);
|
||||
|
||||
ctx->done = 1;
|
||||
ctx->status = r->headers_out.status;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_auth_request_set_variables(ngx_http_request_t *r,
|
||||
ngx_http_auth_request_conf_t *arcf, ngx_http_auth_request_ctx_t *ctx)
|
||||
{
|
||||
ngx_str_t val;
|
||||
ngx_http_variable_t *v;
|
||||
ngx_http_variable_value_t *vv;
|
||||
ngx_http_auth_request_variable_t *av, *last;
|
||||
ngx_http_core_main_conf_t *cmcf;
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"auth request set variables");
|
||||
|
||||
if (arcf->vars == NULL) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
|
||||
v = cmcf->variables.elts;
|
||||
|
||||
av = arcf->vars->elts;
|
||||
last = av + arcf->vars->nelts;
|
||||
|
||||
while (av < last) {
|
||||
/*
|
||||
* explicitly set new value to make sure it will be available after
|
||||
* internal redirects
|
||||
*/
|
||||
|
||||
vv = &r->variables[av->index];
|
||||
|
||||
if (ngx_http_complex_value(ctx->subrequest, &av->value, &val)
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
vv->valid = 1;
|
||||
vv->not_found = 0;
|
||||
vv->data = val.data;
|
||||
vv->len = val.len;
|
||||
|
||||
if (av->set_handler) {
|
||||
/*
|
||||
* set_handler only available in cmcf->variables_keys, so we store
|
||||
* it explicitly
|
||||
*/
|
||||
|
||||
av->set_handler(r, vv, v[av->index].data);
|
||||
}
|
||||
|
||||
av++;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_auth_request_variable(ngx_http_request_t *r,
|
||||
ngx_http_variable_value_t *v, uintptr_t data)
|
||||
{
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"auth request variable");
|
||||
|
||||
v->not_found = 1;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
ngx_http_auth_request_create_conf(ngx_conf_t *cf)
|
||||
{
|
||||
ngx_http_auth_request_conf_t *conf;
|
||||
|
||||
conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_auth_request_conf_t));
|
||||
if (conf == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* set by ngx_pcalloc():
|
||||
*
|
||||
* conf->uri = { 0, NULL };
|
||||
*/
|
||||
|
||||
conf->vars = NGX_CONF_UNSET_PTR;
|
||||
|
||||
return conf;
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
ngx_http_auth_request_merge_conf(ngx_conf_t *cf, void *parent, void *child)
|
||||
{
|
||||
ngx_http_auth_request_conf_t *prev = parent;
|
||||
ngx_http_auth_request_conf_t *conf = child;
|
||||
|
||||
ngx_conf_merge_str_value(conf->uri, prev->uri, "");
|
||||
ngx_conf_merge_ptr_value(conf->vars, prev->vars, NULL);
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_auth_request_init(ngx_conf_t *cf)
|
||||
{
|
||||
ngx_http_handler_pt *h;
|
||||
ngx_http_core_main_conf_t *cmcf;
|
||||
|
||||
cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
|
||||
|
||||
h = ngx_array_push(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers);
|
||||
if (h == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
*h = ngx_http_auth_request_handler;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
ngx_http_auth_request(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
||||
{
|
||||
ngx_http_auth_request_conf_t *arcf = conf;
|
||||
|
||||
ngx_str_t *value;
|
||||
|
||||
if (arcf->uri.data != NULL) {
|
||||
return "is duplicate";
|
||||
}
|
||||
|
||||
value = cf->args->elts;
|
||||
|
||||
if (ngx_strcmp(value[1].data, "off") == 0) {
|
||||
arcf->uri.len = 0;
|
||||
arcf->uri.data = (u_char *) "";
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
arcf->uri = value[1];
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
ngx_http_auth_request_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
||||
{
|
||||
ngx_http_auth_request_conf_t *arcf = conf;
|
||||
|
||||
ngx_str_t *value;
|
||||
ngx_http_variable_t *v;
|
||||
ngx_http_auth_request_variable_t *av;
|
||||
ngx_http_compile_complex_value_t ccv;
|
||||
|
||||
value = cf->args->elts;
|
||||
|
||||
if (value[1].data[0] != '$') {
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"invalid variable name \"%V\"", &value[1]);
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
value[1].len--;
|
||||
value[1].data++;
|
||||
|
||||
if (arcf->vars == NGX_CONF_UNSET_PTR) {
|
||||
arcf->vars = ngx_array_create(cf->pool, 1,
|
||||
sizeof(ngx_http_auth_request_variable_t));
|
||||
if (arcf->vars == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
av = ngx_array_push(arcf->vars);
|
||||
if (av == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
v = ngx_http_add_variable(cf, &value[1], NGX_HTTP_VAR_CHANGEABLE);
|
||||
if (v == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
av->index = ngx_http_get_variable_index(cf, &value[1]);
|
||||
if (av->index == NGX_ERROR) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
if (v->get_handler == NULL) {
|
||||
v->get_handler = ngx_http_auth_request_variable;
|
||||
v->data = (uintptr_t) av;
|
||||
}
|
||||
|
||||
av->set_handler = v->set_handler;
|
||||
|
||||
ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
|
||||
|
||||
ccv.cf = cf;
|
||||
ccv.value = &value[2];
|
||||
ccv.complex_value = &av->value;
|
||||
|
||||
if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
1050
src/http/modules/ngx_http_autoindex_module.c
Normal file
1050
src/http/modules/ngx_http_autoindex_module.c
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user