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_ */
|
||||
Reference in New Issue
Block a user