# HG changeset patch # User Igor Sysoev # Date 1028651985 0 # Node ID 4eff17414a4378feaba42876e0d3a6a50646cdee nginx-0.0.1-2002-08-06-20:39:45 import The first code that uses "ngx_" prefix, the previous one used "gx_" prefix. At that point the code is not yet usable. The first draft ideas are dated back to 23.10.2001. diff --git a/src/core/nginx.c b/src/core/nginx.c new file mode 100644 --- /dev/null +++ b/src/core/nginx.c @@ -0,0 +1,118 @@ + +#include + +#include +#include +#include +#include +#include +#include +#include + +/* +#include +*/ + + +#if !(WIN32) +static int ngx_options(int argc, char *const *argv); +#endif + +char *ngx_root = "/home/is/work/xml/xml/html"; + +int ngx_http_init_connection(void *data); + + +int ngx_max_conn = 512; +struct sockaddr_in ngx_addr = {0, AF_INET, 0, 0, 0}; + + +ngx_pool_t ngx_pool; +ngx_log_t ngx_log; +ngx_server_t ngx_server; + + +int main(int argc, char *const *argv) +{ + char addr_text[22]; + ngx_socket_t fd; + ngx_listen_t ls; +#if (WIN32) + WSADATA wsd; +#endif + + + ngx_log.log_level = NGX_LOG_DEBUG; + ngx_pool.log = &ngx_log; + ngx_addr.sin_port = htons(8000); + ngx_addr.sin_family = AF_INET; + +#if !(WIN32) + if (ngx_options(argc, argv) == -1) + ngx_log_error(NGX_LOG_EMERG, (&ngx_log), 0, "invalid argument"); +#endif + + ngx_log_debug((&ngx_log), "%d, %s:%d" _ ngx_max_conn _ + inet_ntoa(ngx_addr.sin_addr) _ ntohs(ngx_addr.sin_port)); + +#if (WIN32) + if (WSAStartup(MAKEWORD(2,2), &wsd) != 0) + ngx_log_error(NGX_LOG_EMERG, (&ngx_log), ngx_socket_errno, + "WSAStartup failed"); +#endif + + ngx_snprintf(ngx_cpystrn(addr_text, inet_ntoa(ngx_addr.sin_addr), 16), + 7, ":%d", ntohs(ngx_addr.sin_port)); + fd = ngx_listen((struct sockaddr *) &ngx_addr, -1, &ngx_log, addr_text); + + ngx_server.buff_size = 1024; + ngx_server.handler = ngx_http_init_connection; + + /* daemon */ + + ls.fd = fd; + ls.server = &ngx_server; + ls.log = &ngx_log; + + /* fork */ + + ngx_worker(&ls, 1, &ngx_pool, &ngx_log); +} + +#if !(WIN32) +extern char *optarg; + +static int ngx_options(int argc, char *const *argv) +{ + char ch, *pos; + int port; + + while ((ch = getopt(argc, argv, "l:c:")) != -1) { + switch (ch) { + case 'l': + if (pos = strchr(optarg, ':')) { + *(pos) = '\0'; + if ((port = atoi(pos + 1)) <= 0) + return -1; + ngx_addr.sin_port = htons(port); + } + + if ((ngx_addr.sin_addr.s_addr = inet_addr(optarg)) == INADDR_NONE) + return -1; + break; + + case 'c': + if ((ngx_max_conn = atoi(optarg)) <= 0) + return -1; + break; + + case '?': + default: + return -1; + } + + } + + return 0; +} +#endif diff --git a/src/core/nginx.h b/src/core/nginx.h new file mode 100644 --- /dev/null +++ b/src/core/nginx.h @@ -0,0 +1,8 @@ +#ifndef _NGINX_H_INCLUDED_ +#define _NGINX_H_INCLUDED_ + + +extern char *gx_root; + + +#endif /* _NGINX_H_INCLUDED_ */ diff --git a/src/core/ngx_alloc.c b/src/core/ngx_alloc.c new file mode 100644 --- /dev/null +++ b/src/core/ngx_alloc.c @@ -0,0 +1,136 @@ + +#include + +#include +#include +#include + + +void *ngx_alloc(size_t size, ngx_log_t *log) +{ + void *p; + + p = malloc(size); + if (p == NULL) + ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, + "ngx_alloc: malloc %d bytes failed", size); + return p; +} + +void *ngx_calloc(size_t size, ngx_log_t *log) +{ + void *p; + + p = ngx_alloc(size, log); + if (p) + ngx_memzero(p, size); + + return p; +} + +ngx_pool_t *ngx_create_pool(size_t size, ngx_log_t *log) +{ + ngx_pool_t *p; + + ngx_test_null(p, ngx_alloc(size, log), NULL); + + p->last = (char *) p + sizeof(ngx_pool_t); + p->end = (char *) p + size; + p->next = NULL; + p->large = NULL; + p->log = log; + + return p; +} + +void ngx_destroy_pool(ngx_pool_t *pool) +{ + ngx_pool_t *p, *n; + ngx_pool_large_t *l; + + for (l = pool->large; l; l = l->next) + free(l->alloc); + + for (p = pool, n = pool->next; /* void */; p = n, n = n->next) { + free(p); + + if (n == NULL) + break; + } +} + +void *ngx_palloc(ngx_pool_t *pool, size_t size) +{ + void *m; + ngx_pool_t *p, *n; + ngx_pool_large_t *large, *last; + + if (size <= NGX_MAX_ALLOC_FROM_POOL) { + + for (p = pool, n = pool->next; /* void */; p = n, n = n->next) { + if ((size_t) (p->end - p->last) >= size) { + m = p->last; + p->last += size; + + return m; + } + + if (n == NULL) + break; + } + + /* alloc new pool block */ + ngx_test_null(n, ngx_create_pool(p->end - (char *) p, p->log), NULL); + p->next = n; + m = n->last; + n->last += size; + return m; + + /* alloc large block */ + } else { + large = NULL; + last = NULL; + + if (pool->large) { + for (last = pool->large; /* void */; last = last->next) { + if (last->alloc == NULL) { + large = last; + last = NULL; + break; + } + + if (last->next == NULL) + break; + } + } + + if (large == NULL) { + ngx_test_null(large, ngx_palloc(pool, sizeof(ngx_pool_large_t)), + NULL); + } + + ngx_test_null(p, ngx_alloc(size, pool->log), NULL); + + if (pool->large == NULL) { + pool->large = large; + + } else if (last) { + last->next = large; + } + + large->alloc = p; + + return p; + } +} + +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; +} diff --git a/src/core/ngx_alloc.h b/src/core/ngx_alloc.h new file mode 100644 --- /dev/null +++ b/src/core/ngx_alloc.h @@ -0,0 +1,42 @@ +#ifndef _NGX_ALLOC_H_INCLUDED_ +#define _NGX_ALLOC_H_INCLUDED_ + + +#include + +#include + + +#define NGX_MAX_ALLOC_FROM_POOL (8192 - sizeof(ngx_pool_t)) +#define NGX_DEFAULT_POOL_SIZE (16 * 1024) + +#define ngx_test_null(p, alloc, rc) if ((p = alloc) == NULL) return rc + + +typedef struct ngx_pool_large_s ngx_pool_large_t; +struct ngx_pool_large_s { + ngx_pool_large_t *next; + void *alloc; +}; + +typedef struct ngx_pool_s ngx_pool_t; +struct ngx_pool_s { + char *last; + char *end; + ngx_pool_t *next; + ngx_pool_large_t *large; + ngx_log_t *log; +}; + + +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_palloc(ngx_pool_t *pool, size_t size); +void *ngx_pcalloc(ngx_pool_t *pool, size_t size); + + +#endif /* _NGX_ALLOC_H_INCLUDED_ */ diff --git a/src/core/ngx_array.c b/src/core/ngx_array.c new file mode 100644 --- /dev/null +++ b/src/core/ngx_array.c @@ -0,0 +1,69 @@ + +#include + +#include +#include + +ngx_array_t *ngx_create_array(ngx_pool_t *p, int n, size_t size) +{ + ngx_array_t *a; + + a = ngx_palloc(p, sizeof(ngx_array_t)); + if (a == NULL) + return NULL; + + a->elts = ngx_palloc(p, n * size); + if (a->elts == NULL) + return NULL; + + a->pool = p; + a->nelts = 0; + a->nalloc = n; + a->size = size; + + return a; +} + +void ngx_destroy_array(ngx_array_t *a) +{ + ngx_pool_t *p = a->pool; + + if (a->elts + a->size * a->nalloc == p->last) + p->last -= a->size * a->nalloc; + + if ((char *) a + sizeof(ngx_array_t) == p->last) + p->last = (char *) a; +} + +void *ngx_push_array(ngx_array_t *a) +{ + void *elt; + + /* array is full */ + if (a->nelts == a->nalloc) { + ngx_pool_t *p = a->pool; + + /* array allocation is the last in the pool */ + if (a->elts + a->size * a->nelts == p->last + && (unsigned) (p->end - p->last) >= a->size) + { + p->last += a->size; + a->nalloc++; + + /* allocate new array */ + } else { + void *new = ngx_palloc(p, 2 * a->nalloc * a->size); + if (new == NULL) + return NULL; + + memcpy(new, a->elts, a->nalloc * a->size); + a->elts = new; + a->nalloc *= 2; + } + } + + elt = a->elts + a->size * a->nelts; + a->nelts++; + + return elt; +} diff --git a/src/core/ngx_array.h b/src/core/ngx_array.h new file mode 100644 --- /dev/null +++ b/src/core/ngx_array.h @@ -0,0 +1,23 @@ +#ifndef _NGX_ARRAY_H_INCLUDED_ +#define _NGX_ARRAY_H_INCLUDED_ + + +#include + +#include + +typedef struct { + char *elts; + int nelts; + size_t size; + int nalloc; + ngx_pool_t *pool; +} ngx_array_t; + + +ngx_array_t *ngx_create_array(ngx_pool_t *p, int n, size_t size); +void ngx_destroy_array(ngx_array_t *a); +void *ngx_push_array(ngx_array_t *a); + + +#endif /* _NGX_ARRAY_H_INCLUDED_ */ diff --git a/src/core/ngx_auto_config.h b/src/core/ngx_auto_config.h new file mode 100644 --- /dev/null +++ b/src/core/ngx_auto_config.h @@ -0,0 +1,4 @@ + +#ifndef OFF_EQUAL_PTR +#define OFF_EQUAL_PTR 0 +#endif diff --git a/src/core/ngx_config.h b/src/core/ngx_config.h new file mode 100644 --- /dev/null +++ b/src/core/ngx_config.h @@ -0,0 +1,130 @@ +#ifndef _NGX_CONFIG_H_INCLUDED_ +#define _NGX_CONFIG_H_INCLUDED_ + + +#include + +/* + auto_conf + ngx_inline inline __inline __inline__ +*/ + +#define FD_SETSIZE 1024 + + +#ifdef _WIN32 + +#define WIN32 1 + +#include +#include +#include +#include + + +#define ngx_inline __inline + +#define ngx_memzero ZeroMemory + +#define ngx_close_socket closesocket + +#ifndef HAVE_WIN32_TRANSMITPACKETS +#define HAVE_WIN32_TRANSMITPACKETS 1 +#define HAVE_WIN32_TRANSMITFILE 0 +#endif + +#ifndef HAVE_WIN32_TRANSMITFILE +#define HAVE_WIN32_TRANSMITFILE 1 +#endif + +#if (HAVE_WIN32_TRANSMITPACKETS) || (HAVE_WIN32_TRANSMITFILE) +#define HAVE_SENDFILE 1 +#endif + +#else /* POSIX */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ngx_inline inline + +#define ngx_memzero bzero + +#define ngx_close_socket close + +#endif /* POSIX */ + + + +#define LF 10 +#define CR 13 +#define CRLF "\x0d\x0a" + + + +#if defined SO_ACCEPTFILTER || defined TCP_DEFER_ACCEPT + +#ifndef HAVE_DEFERRED_ACCEPT +#define HAVE_DEFERRED_ACCEPT 1 +#endif + +#endif + + + +#ifdef __FreeBSD__ + +#include + +#if __FreeBSD_version >= 300007 + +#ifndef HAVE_FREEBSD_SENDFILE +#define HAVE_FREEBSD_SENDFILE 1 +#endif + +#ifndef HAVE_FREEBSD_SENDFILE_NBYTES_BUG +#define HAVE_FREEBSD_SENDFILE_NBYTES_BUG 2 +#endif + +#endif + +#if (__FreeBSD__ == 4 && __FreeBSD_version >= 460100) \ + || __FreeBSD_version == 460001 + || __FreeBSD_version >= 500029 + +#if (HAVE_FREEBSD_SENDFILE_NBYTES_BUG == 2) +#define HAVE_FREEBSD_SENDFILE_NBYTES_BUG 0 +#endif + +#endif + +#if (HAVE_FREEBSD_SENDFILE) +#define HAVE_SENDFILE 1 +#endif + + +#if (__FreeBSD__ == 4 && __FreeBSD_version >= 410000) \ + || __FreeBSD_version >= 500011 + +#ifndef HAVE_KQUEUE +#define HAVE_KQUEUE 1 +#include +#endif + +#endif + + +#endif /* __FreeBSD__ */ + + +#endif /* _NGX_CONFIG_H_INCLUDED_ */ diff --git a/src/core/ngx_connection.h b/src/core/ngx_connection.h new file mode 100644 --- /dev/null +++ b/src/core/ngx_connection.h @@ -0,0 +1,54 @@ +#ifndef _NGX_CONNECTION_H_INCLUDED_ +#define _NGX_CONNECTION_H_INCLUDED_ + +#include +#include +#include + +typedef struct ngx_connection_s ngx_connection_t; + +#ifdef NGX_EVENT +#include +#endif + +struct ngx_connection_s { + ngx_socket_t fd; + void *data; + +#ifdef NGX_EVENT + ngx_event_t *read; + ngx_event_t *write; +#endif + + ngx_log_t *log; + ngx_server_t *server; + ngx_server_t *servers; + ngx_pool_t *pool; +}; + + +/* + +cached file + int fd; -2 unused, -1 closed (but read or mmaped), >=0 open + char *name; + + void *buf; addr if read or mmaped + aiocb* if aio_read + OVERLAPPED if TransmitFile or TransmitPackets + NULL if sendfile + + size_t buf_size; for plain read + off_t offset; for plain read + + size_t size; + time_t mod; + char *last_mod; 'Sun, 17 Mar 2002 19:39:50 GMT' + char *etag; '"a6d08-1302-3c94f106"' + char *len; '4866' + +EV_VNODE should notify by some signal if diretory tree is changed + or stat if aged >= N seconds (big enough) +*/ + +#endif /* _NGX_CONNECTION_H_INCLUDED_ */ diff --git a/src/core/ngx_hunk.c b/src/core/ngx_hunk.c new file mode 100644 --- /dev/null +++ b/src/core/ngx_hunk.c @@ -0,0 +1,85 @@ + +#include +#include + + +ngx_hunk_t *ngx_get_hunk(ngx_pool_t *pool, int size, int before, int after) +{ + ngx_hunk_t *h = ngx_palloc(pool, sizeof(ngx_hunk_t)); + +#ifndef OFF_EQUAL_PTR + h->pos.f = h->last.f = 0; +#endif + + h->pre_start = ngx_palloc(pool, size + before + after); + h->start = h->pos.p = h->last.p = h->pre_start + before; + h->end = h->last.p + size; + h->post_end = h->end + after; + + h->type = NGX_HUNK_TEMP; + h->tag = 0; + h->fd = (ngx_file_t) -1; + + return h; +} + +ngx_hunk_t *ngx_get_hunk_before(ngx_pool_t *pool, ngx_hunk_t *hunk, int size) +{ + ngx_hunk_t *h = ngx_palloc(pool, sizeof(ngx_hunk_t)); + +#ifndef OFF_EQUAL_PTR + h->pos.f = h->last.f = 0; +#endif + + if (hunk->type & NGX_HUNK_TEMP && hunk->pos.p - hunk->pre_start >= size) { + /* keep hunk->start unchanged - used in restore */ + h->pre_start = hunk->pre_start; + h->end = h->post_end = hunk->pre_start = hunk->pos.p; + h->start = h->pos.p = h->last.p = h->end - size; + + h->type = NGX_HUNK_TEMP; + h->tag = 0; + h->fd = (ngx_file_t) -1; + + } else { + h->pre_start = h->start = h->pos.p = h->last.p = ngx_palloc(pool, size); + h->end = h->post_end = h->start + size; + + h->type = NGX_HUNK_TEMP; + h->tag = 0; + h->fd = (ngx_file_t) -1; + } + + return h; +} + +ngx_hunk_t *ngx_get_hunk_after(ngx_pool_t *pool, ngx_hunk_t *hunk, int size) +{ + ngx_hunk_t *h = ngx_palloc(pool, sizeof(ngx_hunk_t)); + +#ifndef OFF_EQUAL_PTR + h->pos.f = h->last.f = 0; +#endif + + if (hunk->type & NGX_HUNK_TEMP + && hunk->last.p == hunk->end + && hunk->post_end - hunk->end >= size) + { + h->post_end = hunk->post_end; + h->pre_start = h->start = h->pos.p = h->last.p = hunk->post_end = + hunk->last.p; + h->type = NGX_HUNK_TEMP; + h->tag = 0; + h->fd = (ngx_file_t) -1; + + } else { + h->pre_start = h->start = h->pos.p = h->last.p = ngx_palloc(pool, size); + h->end = h->post_end = h->start + size; + + h->type = NGX_HUNK_TEMP; + h->tag = 0; + h->fd = (ngx_file_t) -1; + } + + return h; +} diff --git a/src/core/ngx_hunk.h b/src/core/ngx_hunk.h new file mode 100644 --- /dev/null +++ b/src/core/ngx_hunk.h @@ -0,0 +1,57 @@ +#ifndef _NGX_CHUNK_H_INCLUDED_ +#define _NGX_CHUNK_H_INCLUDED_ + + +#include +#include +#include + + +/* type */ +#define NGX_HUNK_TEMP 0x0001 +#define NGX_HUNK_MEMORY 0x0002 +#define NGX_HUNK_MMAP 0x0004 +#define NGX_HUNK_FILE 0x0008 +#define NGX_HUNK_FLUSH 0x0010 +/* in thread state flush means to write the hunk completely before return + in event-driven state flush means to start to write the hunk */ +#define NGX_HUNK_LAST 0x0020 + +#define NGX_HUNK_IN_MEMORY (NGX_HUNK_TEMP | NGX_HUNK_MEMORY | NGX_HUNK_MMAP ) +#define NGX_HUNK_TYPE 0x0ffff + +/* flags */ +#define NGX_HUNK_SHUTDOWN 0x10000 +/* can be used with NGX_HUNK_LAST only */ + + +typedef struct ngx_hunk_s ngx_hunk_t; +struct ngx_hunk_s { + union { + char *p; /* start of current data */ + off_t f; + } pos; + union { + char *p; /* end of current data */ + off_t f; + } last; + int type; + char *start; /* start of hunk */ + char *end; /* end of hunk */ + char *pre_start; /* start of pre-allocated hunk */ + char *post_end; /* end of post-allocated hunk */ + int tag; + ngx_file_t fd; +}; + +typedef struct ngx_chain_s ngx_chain_t; +struct ngx_chain_s { + ngx_hunk_t *hunk; + ngx_chain_t *next; +}; + + +ngx_hunk_t *ngx_get_hunk(ngx_pool_t *pool, int size, int before, int after); + + +#endif /* _NGX_CHUNK_H_INCLUDED_ */ diff --git a/src/core/ngx_listen.c b/src/core/ngx_listen.c new file mode 100644 --- /dev/null +++ b/src/core/ngx_listen.c @@ -0,0 +1,44 @@ + +#include +#include +#include +#include +#include + +ngx_socket_t ngx_listen(struct sockaddr *addr, int backlog, + ngx_log_t *log, char *addr_text) +{ + ngx_socket_t s; + int reuseaddr = 1; +#if (WIN32) + unsigned long nb = 1; +#endif + + if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) + ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, "socket failed"); + + if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, + (const void *) &reuseaddr, sizeof(int)) == -1) + ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, + "ngx_listen: setsockopt (SO_REUSEADDR) failed"); + +#if (WIN32) + if (ioctlsocket(s, FIONBIO, &nb) == -1) + ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, + "ngx_listen: ioctlsocket (FIONBIO) failed"); +#else + if (fcntl(s, F_SETFL, O_NONBLOCK) == -1) + ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, + "ngx_listen: fcntl (O_NONBLOCK) failed"); +#endif + + if (bind(s, (struct sockaddr *) addr, sizeof(struct sockaddr_in)) == -1) + ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, + "ngx_listen: bind to %s failed", addr_text); + + if (listen(s, backlog) == -1) + ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, + "ngx_listen: listen to %s failed", addr_text); + + return s; +} diff --git a/src/core/ngx_listen.h b/src/core/ngx_listen.h new file mode 100644 --- /dev/null +++ b/src/core/ngx_listen.h @@ -0,0 +1,9 @@ +#ifndef _NGX_LISTEN_H_INCLUDED_ +#define _NGX_LISTEN_H_INCLUDED_ + + +ngx_socket_t ngx_listen(struct sockaddr *addr, int backlog, + ngx_log_t *log, char *addr_text); + + +#endif /* _NGX_LISTEN_H_INCLUDED_ */ diff --git a/src/core/ngx_log.c b/src/core/ngx_log.c new file mode 100644 --- /dev/null +++ b/src/core/ngx_log.c @@ -0,0 +1,116 @@ + +/* + TODO: log pid and tid +*/ + +/* + "[time as ctime()] [alert] 412:3 (32)Broken pipe: anything" + + "[time as ctime()] [alert] (32)Broken pipe: anything" + "[time as ctime()] [alert] anything" +*/ + +#include +#include +#include +#include +#include + + +static const char *err_levels[] = { + "emerg", "alert", "crit", "error", "warn", "notice", "info", "debug" +}; + +#if (HAVE_VARIADIC_MACROS) +void ngx_log_error_core(int level, ngx_log_t *log, ngx_err_t err, + const char *fmt, ...) +#else +void ngx_log_error_core(int level, ngx_log_t *log, ngx_err_t err, + const char *fmt, va_list args) +#endif +{ + char errstr[MAX_ERROR_STR]; + ngx_tm_t tm; + size_t len; +#if (HAVE_VARIADIC_MACROS) + va_list args; +#endif + + ngx_localtime(&tm); + len = ngx_snprintf(errstr, sizeof(errstr), "%02d:%02d:%02d", + tm.ngx_tm_hour, tm.ngx_tm_min, tm.ngx_tm_sec); + + if (err) { + if ((unsigned) err < 0x80000000) + len += ngx_snprintf(errstr + len, sizeof(errstr) - len - 1, + " [%s] (%d)", + err_levels[level], err); + len += ngx_snprintf(errstr + len, sizeof(errstr) - len - 1, + " [%s] (%X)", + err_levels[level], err); + + len += ngx_strerror_r(err, errstr + len, sizeof(errstr) - len - 1); + if (len < sizeof(errstr) - 2) { + errstr[len++] = ':'; + errstr[len++] = ' '; + } else { + len = sizeof(errstr) - 2; + } + + } else { + len += ngx_snprintf(errstr + len, sizeof(errstr) - len - 1, + " [%s] ", err_levels[level]); + } + +#if (HAVE_VARIADIC_MACROS) + va_start(args, fmt); + len += ngx_vsnprintf(errstr + len, sizeof(errstr) - len - 1, fmt, args); + va_end(args); +#else + len += ngx_vsnprintf(errstr + len, sizeof(errstr) - len - 1, fmt, args); +#endif + + if (len > sizeof(errstr) - 2) + len = sizeof(errstr) - 2; + errstr[len] = '\n'; + errstr[len + 1] = '\0'; + + fputs(errstr, stderr); + + if (level == NGX_LOG_EMERG) + exit(1); +} + +#if !(HAVE_VARIADIC_MACROS) + +void ngx_log_error(int 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_log_debug_core(ngx_log_t *log, const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + ngx_log_error_core(NGX_LOG_DEBUG, log, 0, fmt, args); + va_end(args); +} + +void ngx_assert_core(ngx_log_t *log, const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + ngx_log_error_core(NGX_LOG_ALERT, log, 0, fmt, args); + va_end(args); +} + +#endif diff --git a/src/core/ngx_log.h b/src/core/ngx_log.h new file mode 100644 --- /dev/null +++ b/src/core/ngx_log.h @@ -0,0 +1,118 @@ +#ifndef _NGX_LOG_H_INCLUDED_ +#define _NGX_LOG_H_INCLUDED_ + + +#include + +typedef enum { + NGX_LOG_EMERG = 0, + NGX_LOG_ALERT, + NGX_LOG_CRIT, + NGX_LOG_ERR, + NGX_LOG_WARN, + NGX_LOG_NOTICE, + NGX_LOG_INFO, + NGX_LOG_DEBUG +} ngx_log_e; + +/* + "... while ", action = "reading client request headers" + "... while reading client request headers" + "... while ", action = "reading client request headers" + context: pop3 user account + "... while reading client command for 'john_doe'" +*/ + +typedef struct { + int log_level; + char *action; + char *context; +/* char *func(ngx_log_t *log); */ +} ngx_log_t; + +#define MAX_ERROR_STR 2048 + +#define _ , + + +#if (HAVE_GCC_VARIADIC_MACROS) + +#define HAVE_VARIADIC_MACROS 1 + +#define ngx_log_error(level, log, args...) \ + if (log->log_level >= level) ngx_log_error_core(level, log, args) + +#ifdef NGX_DEBUG +#define ngx_log_debug(log, args...) \ + if (log->log_level == NGX_LOG_DEBUG) \ + ngx_log_error_core(NGX_LOG_DEBUG, log, 0, args) +#else +#define ngx_log_debug(log, args...) +#endif + +#define ngx_assert(assert, fallback, log, args...) \ + if (!(assert)) { \ + if (log->log_level >= NGX_LOG_ALERT) \ + ngx_log_error_core(NGX_LOG_ALERT, log, 0, args); \ + fallback; \ + } + +void ngx_log_error_core(int level, ngx_log_t *log, ngx_err_t err, + const char *fmt, ...); + +#elif (HAVE_C99_VARIADIC_MACROS) + +#define HAVE_VARIADIC_MACROS 1 + +#define ngx_log_error(level, log, ...) \ + if (log->log_level >= level) ngx_log_error_core(level, log, __VA_ARGS__) + +#ifdef NGX_DEBUG +#define ngx_log_debug(log, ...) \ + if (log->log_level == NGX_LOG_DEBUG) \ + ngx_log_error_core(NGX_LOG_DEBUG, log, 0, __VA_ARGS__) +#else +#define ngx_log_debug(log, ...) +#endif + +#define ngx_assert(assert, fallback, log, ...) \ + if (!(assert)) { \ + if (log->log_level >= NGX_LOG_ALERT) \ + ngx_log_error_core(NGX_LOG_ALERT, log, 0, __VA_ARGS__); \ + fallback; \ + } + +void ngx_log_error_core(int level, ngx_log_t *log, ngx_err_t err, + const char *fmt, ...); + +#else /* NO VARIADIC MACROS */ + +#include + +#ifdef NGX_DEBUG +#define ngx_log_debug(log, text) \ + if (log->log_level == NGX_LOG_DEBUG) \ + ngx_log_debug_core(log, text) +#else +#define ngx_log_debug(log, text) +#endif + +#define ngx_assert(assert, fallback, log, text) \ + if (!(assert)) { \ + if (log->log_level >= NGX_LOG_ALERT) \ + ngx_assert_core(log, text); \ + fallback; \ + } + +void ngx_log_error(int level, ngx_log_t *log, ngx_err_t err, + const char *fmt, ...); +void ngx_log_error_core(int level, ngx_log_t *log, ngx_err_t err, + const char *fmt, va_list args); +void ngx_log_debug_core(ngx_log_t *log, const char *fmt, ...); +void ngx_assert_core(ngx_log_t *log, const char *fmt, ...); + + +#endif /* VARIADIC MACROS */ + + +#endif /* _NGX_LOG_H_INCLUDED_ */ diff --git a/src/core/ngx_server.h b/src/core/ngx_server.h new file mode 100644 --- /dev/null +++ b/src/core/ngx_server.h @@ -0,0 +1,30 @@ +#ifndef _NGX_SERVER_H_INCLUDED_ +#define _NGX_SERVER_H_INCLUDED_ + + +#include +#include +#include + +typedef struct { + int log_level; + ngx_pool_t *pool; + int (*handler)(void *data); + int buff_size; +} ngx_server_t; + + +typedef struct { + ngx_socket_t fd; + + ngx_log_t *log; + ngx_server_t *server; + + unsigned shared:1; +#if (HAVE_DEFERRED_ACCEPT) + unsigned accept_filter:1; +#endif +} ngx_listen_t; + + +#endif /* _NGX_SERVER_H_INCLUDED_ */ diff --git a/src/core/ngx_string.c b/src/core/ngx_string.c new file mode 100644 --- /dev/null +++ b/src/core/ngx_string.c @@ -0,0 +1,21 @@ + +#include +#include + + +char *ngx_cpystrn(char *dst, char *src, size_t n) +{ + if (n == 0) + return dst; + + for (/* void */; --n; dst++, src++) { + *dst = *src; + + if (*dst == '\0') + return dst; + } + + *dst = '\0'; + + return dst; +} diff --git a/src/core/ngx_string.h b/src/core/ngx_string.h new file mode 100644 --- /dev/null +++ b/src/core/ngx_string.h @@ -0,0 +1,26 @@ +#ifndef _NGX_STRING_H_INCLUDED_ +#define _NGX_STRING_H_INCLUDED_ + + +#include + + +#if (WIN32) + +#define ngx_snprintf _snprintf +#define ngx_vsnprintf _vsnprintf + +#else + +#define ngx_snprintf snprintf +#define ngx_vsnprintf vsnprintf + +#endif + +#define ngx_memcpy(dst, src, n) memcpy(dst, src, n) +#define ngx_cpymem(dst, src, n) memcpy(dst, src, n) + n + +char *ngx_cpystrn(char *dst, char *src, size_t n); + + +#endif /* _NGX_STRING_H_INCLUDED_ */ diff --git a/src/event/modules/ngx_aio_module.c b/src/event/modules/ngx_aio_module.c new file mode 100644 --- /dev/null +++ b/src/event/modules/ngx_aio_module.c @@ -0,0 +1,37 @@ + +int ngx_posix_aio_process_events(ngx_log_t *log) +{ + unmask signal + + listen via signal; + + aio_suspend()/aiowait()/aio_waitcomplete(); + + mask signal + + if (ngx_socket_errno == NGX_EINTR) + look listen + select()/accept() nb listen sockets + else + aio +} + +int ngx_posix_aio_process_events(ngx_log_t *log) +{ + unmask signal + + /* BUG: signal can be delivered before select() */ + + select(listen); + + mask signal + + if (ngx_socket_errno == NGX_EINTR) + look ready array +} + +void aio_sig_handler(int signo, siginfo_t *siginfo, void *context) +{ + push siginfo->si_value.sival_ptr +} + diff --git a/src/event/modules/ngx_kqueue_module.c b/src/event/modules/ngx_kqueue_module.c new file mode 100644 --- /dev/null +++ b/src/event/modules/ngx_kqueue_module.c @@ -0,0 +1,240 @@ +/* + * Copyright (C) 2002 Igor Sysoev, http://sysoev.ru + */ + +/* + NEED ? : unify change_list and event_list: + event_list = change_list; +*/ + +#include +#include +#include +#include +#include +#include + +#if (USE_KQUEUE) && !(HAVE_KQUEUE) +#error "kqueue is not supported on this platform" +#endif + +static void ngx_add_timer(ngx_event_t *ev, u_int timer); +static void ngx_inline ngx_del_timer(ngx_event_t *ev); + + +static int kq; +static struct kevent *change_list, *event_list; +static int nchanges, nevents; + +static ngx_event_t timer_queue; + +void ngx_kqueue_init(int max_connections, ngx_log_t *log) +{ + int size = sizeof(struct kevent) * 512; + + nchanges = 0; + nevents = 512; + + if ((kq = kqueue()) == -1) + ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, + "ngx_kqueue_init: kqueue failed"); + + change_list = ngx_alloc(size, log); + event_list = ngx_alloc(size, log); + + timer_queue.timer_prev = &timer_queue; + timer_queue.timer_next = &timer_queue; + +#if !(USE_KQUEUE) + ngx_event_actions.add = ngx_kqueue_add_event; + ngx_event_actions.del = ngx_kqueue_del_event; + ngx_event_actions.process = ngx_kqueue_process_events; +#endif + +} + +int ngx_kqueue_add_event(ngx_event_t *ev, int event, u_int flags) +{ + if (event == NGX_TIMER_EVENT) { + ngx_add_timer(ev, flags); + return 0; + } + + return ngx_kqueue_set_event(ev, event, EV_ADD | flags); +} + +int ngx_kqueue_del_event(ngx_event_t *ev, int event) +{ + if (event == NGX_TIMER_EVENT) { + ngx_del_timer(ev); + return 0; + } + + return ngx_kqueue_set_event(ev, event, EV_DELETE); +} + +int ngx_kqueue_set_event(ngx_event_t *ev, int filter, u_int flags) +{ + struct timespec ts = { 0, 0 }; + ngx_connection_t *cn = (ngx_connection_t *) ev->data; + + ngx_log_debug(ev->log, "ngx_kqueue_set_event: %d: ft:%d f:%08x" _ + cn->fd _ filter _ flags); + + if (nchanges >= nevents) { + ngx_log_error(NGX_LOG_WARN, ev->log, 0, + "ngx_kqueue_set_event: change list is filled up"); + + if (kevent(kq, change_list, nchanges, NULL, 0, &ts) == -1) { + ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno, + "ngx_kqueue_set_event: kevent failed"); + return -1; + } + nchanges = 0; + } + + change_list[nchanges].ident = cn->fd; + change_list[nchanges].filter = filter; + change_list[nchanges].flags = flags; + change_list[nchanges].fflags = 0; + change_list[nchanges].data = 0; + change_list[nchanges].udata = ev; + nchanges++; + + return 0; +} + +int ngx_kqueue_process_events(ngx_log_t *log) +{ + int events, i; + u_int timer = 0, delta = 0; + ngx_event_t *ev, *nx; + struct timeval tv; + struct timespec ts, *tp = NULL; + + if (timer_queue.timer_next != &timer_queue) { + timer = timer_queue.timer_next->timer_delta; + ts.tv_sec = timer / 1000; + ts.tv_nsec = (timer % 1000) * 1000000; + tp = &ts; + gettimeofday(&tv, NULL); + delta = tv.tv_sec * 1000 + tv.tv_usec / 1000; + } + + ngx_log_debug(log, "ngx_kqueue_process_events: timer: %d" _ timer); + + if ((events = kevent(kq, change_list, nchanges, event_list, nevents, tp)) + == -1) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + "ngx_kqueue_process_events: kevent failed"); + return -1; + } + + nchanges = 0; + + if (timer) { + gettimeofday(&tv, NULL); + delta = tv.tv_sec * 1000 + tv.tv_usec / 1000 - delta; + + } else { + ngx_assert((events != 0), return -1, log, + "ngx_kqueue_process_events: " + "kevent returns no events without timeout"); + } + + ngx_log_debug(log, "ngx_kqueue_process_events: " + "timer: %d, delta: %d" _ timer _ delta); + + if (timer) { + if (delta >= timer) { + for (ev = timer_queue.timer_next; + ev != &timer_queue && delta >= ev->timer_delta; + /* void */) + { + delta -= ev->timer_delta; + nx = ev->timer_next; + ngx_del_timer(ev); + if (ev->timer_handler(ev) == -1) + ev->close_handler(ev); + ev = nx; + } + + } else { + timer_queue.timer_next->timer_delta -= delta; + } + } + + for (i = 0; i < events; i++) { + + ngx_log_debug(log, "ngx_kqueue_process_events: kevent: " + "%d: ft:%d f:%08x ff:%08x d:%d ud:%08x" _ + event_list[i].ident _ event_list[i].filter _ + event_list[i].flags _ event_list[i].fflags _ + event_list[i].data _ event_list[i].udata); + + if (event_list[i].flags & EV_ERROR) { + ngx_log_error(NGX_LOG_ALERT, log, event_list[i].data, + "ngx_kqueue_process_events: kevent error"); + continue; + } + + ev = (ngx_event_t *) event_list[i].udata; + + switch (event_list[i].filter) { + + case EVFILT_READ: + case EVFILT_WRITE: + ev->ready = 1; + ev->available = event_list[i].data; + + if (event_list[i].flags & EV_EOF) { + ev->eof = 1; + ev->error = event_list[i].fflags; + } + + if (ev->event_handler(ev) == -1) + ev->close_handler(ev); + + break; + + default: + ngx_assert(0, /* void */, log, + "ngx_kqueue_process_events: unknown filter %d" _ + event_list[i].filter); + } + } + + return 0; +} + +static void ngx_add_timer(ngx_event_t *ev, u_int timer) +{ + ngx_event_t *e; + + for (e = timer_queue.timer_next; + e != &timer_queue && timer > e->timer_delta; + e = e->timer_next) + timer -= e->timer_delta; + + ev->timer_delta = timer; + + ev->timer_next = e; + ev->timer_prev = e->timer_prev; + + e->timer_prev->timer_next = ev; + e->timer_prev = ev; +} + +static void ngx_inline ngx_del_timer(ngx_event_t *ev) +{ + if (ev->timer_prev) + ev->timer_prev->timer_next = ev->timer_next; + + if (ev->timer_next) { + ev->timer_next->timer_prev = ev->timer_prev; + ev->timer_prev = NULL; + } + + if (ev->timer_prev) + ev->timer_next = NULL; +} diff --git a/src/event/modules/ngx_kqueue_module.h b/src/event/modules/ngx_kqueue_module.h new file mode 100644 --- /dev/null +++ b/src/event/modules/ngx_kqueue_module.h @@ -0,0 +1,16 @@ +#ifndef _NGX_KQUEUE_MODULE_H_INCLUDED_ +#define _NGX_KQUEUE_MODULE_H_INCLUDED_ + + +#include +#include +#include + +void ngx_kqueue_init(int max_connections, ngx_log_t *log); +int ngx_kqueue_add_event(ngx_event_t *ev, int event, u_int flags); +int ngx_kqueue_del_event(ngx_event_t *ev, int event); +int ngx_kqueue_set_event(ngx_event_t *ev, int filter, u_int flags); +int ngx_kqueue_process_events(ngx_log_t *log); + + +#endif /* _NGX_KQUEUE_MODULE_H_INCLUDED_ */ diff --git a/src/event/modules/ngx_overlapped_module.c b/src/event/modules/ngx_overlapped_module.c new file mode 100644 --- /dev/null +++ b/src/event/modules/ngx_overlapped_module.c @@ -0,0 +1,17 @@ + +int ngx_overlapped_process_events(ngx_log_t *log) +{ + if (acceptex) + event = SleepEx(timer, 1); + else + event = WSAWaitForMultipleEvents(n_events, events, 0, timer, 1); + + if (event == WSA_IO_COMPLETION) + look ready array +} + +void CALLBACK overlapped_completion_procedure(DWORD error, DWORD nbytes, + LPWSAOVERLAPPED overlapped, DWORD flags) +{ + push overlapped; +} diff --git a/src/event/modules/ngx_select_module.c b/src/event/modules/ngx_select_module.c new file mode 100644 --- /dev/null +++ b/src/event/modules/ngx_select_module.c @@ -0,0 +1,349 @@ + +#include +#include +#include +#include +#include +#include +#include + +static fd_set master_read_fds; +static fd_set master_write_fds; +static fd_set work_read_fds; +static fd_set work_write_fds; + +#if (WIN32) +static int max_read; +static int max_write; +#else +static int max_fd; +#endif + +static ngx_event_t event_queue; +static ngx_event_t timer_queue; + + +static void ngx_add_timer(ngx_event_t *ev, u_int timer); +static void ngx_inline ngx_del_timer(ngx_event_t *ev); + +static fd_set *ngx_select_get_fd_set(ngx_socket_t fd, int event, + ngx_log_t *log); + +void ngx_select_init(int max_connections, ngx_log_t *log) +{ +#if (WIN32) + if (max_connections > FD_SETSIZE) + ngx_log_error(NGX_LOG_EMERG, log, 0, + "ngx_select_init: maximum number of descriptors " + "supported by select() is %d", + FD_SETSIZE); +#else + if (max_connections >= FD_SETSIZE) + ngx_log_error(NGX_LOG_EMERG, log, 0, + "ngx_select_init: maximum descriptor number" + "supported by select() is %d", + FD_SETSIZE - 1); +#endif + + FD_ZERO(&master_read_fds); + FD_ZERO(&master_write_fds); + + event_queue.prev = &event_queue; + event_queue.next = &event_queue; + + timer_queue.timer_prev = &timer_queue; + timer_queue.timer_next = &timer_queue; + + ngx_event_actions.add = ngx_select_add_event; + ngx_event_actions.del = ngx_select_del_event; + ngx_event_actions.process = ngx_select_process_events; + +#if (WIN32) + max_read = max_write = 0; +#else + max_fd = -1; +#endif +} + +int ngx_select_add_event(ngx_event_t *ev, int event, u_int flags) +{ + fd_set *fds; + ngx_connection_t *cn = (ngx_connection_t *) ev->data; + + if (event == NGX_TIMER_EVENT) { + ngx_add_timer(ev, flags); + return 0; + } + + ngx_assert((flags != NGX_ONESHOT_EVENT), return -1, ev->log, + "ngx_select_add_event: NGX_ONESHOT_EVENT is not supported"); + + fds = ngx_select_get_fd_set(cn->fd, event, ev->log); + if (fds == NULL) + return -1; + + ev->prev = &event_queue; + ev->next = event_queue.next; + event_queue.next->prev = ev; + event_queue.next = ev; + + FD_SET(cn->fd, fds); + +#if (WIN32) + switch (event) { + case NGX_READ_EVENT: + max_read++; + break; + case NGX_WRITE_EVENT: + max_write++; + break; + } +#else + if (max_fd != -1 && max_fd < cn->fd) + max_fd = cn->fd; +#endif + + return 0; +} + +int ngx_select_del_event(ngx_event_t *ev, int event) +{ + fd_set *fds; + ngx_connection_t *cn = (ngx_connection_t *) ev->data; + + if (event == NGX_TIMER_EVENT) { + ngx_del_timer(ev); + return 0; + } + + fds = ngx_select_get_fd_set(cn->fd, event, ev->log); + if (fds == NULL) + return -1; + + if (ev->prev) + ev->prev->next = ev->next; + + if (ev->next) { + ev->next->prev = ev->prev; + ev->prev = NULL; + } + + if (ev->prev) + ev->next = NULL; + + FD_CLR(cn->fd, fds); + +#if (WIN32) + switch (event) { + case NGX_READ_EVENT: + max_read--; + break; + case NGX_WRITE_EVENT: + max_write--; + break; + } +#else + if (max_fd == cn->fd) + max_fd = -1; +#endif + + return 0; +} + +static fd_set *ngx_select_get_fd_set(ngx_socket_t fd, int event, ngx_log_t *log) +{ + ngx_log_debug(log, "ngx_select_get_fd_set: %d %d" _ fd _ event); + +#if !(WIN32) + if (fd >= FD_SETSIZE) { + ngx_log_error(NGX_LOG_ERR, log, 0, + "ngx_select_get_event: maximum descriptor number" + "supported by select() is %d", + FD_SETSIZE - 1); + return NULL; + } +#endif + + switch (event) { + case NGX_READ_EVENT: +#if (WIN32) + if (max_read >= FD_SETSIZE) { + ngx_log_error(NGX_LOG_ERR, log, 0, + "ngx_select_get_event: maximum number of descriptors " + "supported by select() is %d", + FD_SETSIZE); + return NULL; + } +#endif + return &master_read_fds; + + case NGX_WRITE_EVENT: +#if (WIN32) + if (max_write >= FD_SETSIZE) { + ngx_log_error(NGX_LOG_ERR, log, 0, + "ngx_select_get_event: maximum number of descriptors " + "supported by select() is %d", + FD_SETSIZE); + return NULL; + } +#endif + return &master_write_fds; + + default: + ngx_assert(0, return NULL, log, + "ngx_select_get_fd_set: invalid event %d" _ event); + } + + return NULL; +} + +int ngx_select_process_events(ngx_log_t *log) +{ + int ready, found; + u_int timer, delta; + ngx_event_t *ev, *nx; + ngx_connection_t *cn; + struct timeval tv, *tp; + + work_read_fds = master_read_fds; + work_write_fds = master_write_fds; + + if (timer_queue.timer_next != &timer_queue) { + timer = timer_queue.timer_next->timer_delta; + tv.tv_sec = timer / 1000; + tv.tv_usec = (timer % 1000) * 1000; + tp = &tv; + + delta = ngx_msec(); + + } else { + timer = 0; + tp = NULL; + delta = 0; + } + +#if !(WIN32) + if (max_fd == -1) { + for (ev = event_queue.next; ev != &event_queue; ev = ev->next) { + cn = (ngx_connection_t *) ev->data; + if (max_fd < cn->fd) + max_fd = cn->fd; + } + + ngx_log_debug(log, "ngx_select_process_events: change max_fd: %d" _ + max_fd); + } +#endif + + ngx_log_debug(log, "ngx_select_process_events: timer: %d" _ timer); + +#if (WIN32) + if ((ready = select(0, &work_read_fds, &work_write_fds, NULL, tp)) +#else + if ((ready = select(max_fd + 1, &work_read_fds, &work_write_fds, NULL, tp)) +#endif + == -1) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_socket_errno, + "ngx_select_process_events: select failed"); + return -1; + } + + ngx_log_debug(log, "ngx_select_process_events: ready %d" _ ready); + + if (timer) { + delta = ngx_msec() - delta; + + } else { + ngx_assert((ready != 0), return -1, log, + "ngx_select_process_events: " + "select returns no events without timeout"); + } + + ngx_log_debug(log, "ngx_select_process_events: " + "timer: %d, delta: %d" _ timer _ delta); + + if (timer) { + if (delta >= timer) { + for (ev = timer_queue.timer_next; + ev != &timer_queue && delta >= ev->timer_delta; + /* void */) + { + delta -= ev->timer_delta; + nx = ev->timer_next; + ngx_del_timer(ev); + if (ev->timer_handler(ev) == -1) + ev->close_handler(ev); + ev = nx; + } + + } else { + timer_queue.timer_next->timer_delta -= delta; + } + } + + for (ev = event_queue.next; ev != &event_queue; ev = ev->next) { + cn = (ngx_connection_t *) ev->data; + found = 0; + + if (ev->write) { + if (FD_ISSET(cn->fd, &work_write_fds)) { + ngx_log_debug(log, "ngx_select_process_events: write %d" _ + cn->fd); + found = 1; + } + + } else { + if (FD_ISSET(cn->fd, &work_read_fds)) { + ngx_log_debug(log, "ngx_select_process_events: read %d" _ + cn->fd); + found = 1; + } + } + + if (found) { + ev->ready = 1; + if (ev->event_handler(ev) == -1) + ev->close_handler(ev); + + ready--; + } + + } + + ngx_assert((ready == 0), return 0, log, + "ngx_select_process_events: ready != events"); + + return 0; +} + +static void ngx_add_timer(ngx_event_t *ev, u_int timer) +{ + ngx_event_t *e; + + for (e = timer_queue.timer_next; + e != &timer_queue && timer > e->timer_delta; + e = e->timer_next) + timer -= e->timer_delta; + + ev->timer_delta = timer; + + ev->timer_next = e; + ev->timer_prev = e->timer_prev; + + e->timer_prev->timer_next = ev; + e->timer_prev = ev; +} + +static void ngx_inline ngx_del_timer(ngx_event_t *ev) +{ + if (ev->timer_prev) + ev->timer_prev->timer_next = ev->timer_next; + + if (ev->timer_next) { + ev->timer_next->timer_prev = ev->timer_prev; + ev->timer_prev = NULL; + } + + if (ev->timer_prev) + ev->timer_next = NULL; +} diff --git a/src/event/modules/ngx_select_module.h b/src/event/modules/ngx_select_module.h new file mode 100644 --- /dev/null +++ b/src/event/modules/ngx_select_module.h @@ -0,0 +1,16 @@ +#ifndef _NGX_SELECT_MODULE_H_INCLUDED_ +#define _NGX_SELECT_MODULE_H_INCLUDED_ + + +#include +#include +#include + +void ngx_select_init(int max_connections, ngx_log_t *log); +int ngx_select_add_event(ngx_event_t *ev, int event, u_int flags); +int ngx_select_del_event(ngx_event_t *ev, int event); +int ngx_select_set_event(ngx_event_t *ev, int filter, u_int flags); +int ngx_select_process_events(ngx_log_t *log); + + +#endif /* _NGX_SELECT_MODULE_H_INCLUDED_ */ diff --git a/src/event/ngx_event.c b/src/event/ngx_event.c new file mode 100644 --- /dev/null +++ b/src/event/ngx_event.c @@ -0,0 +1,87 @@ + +#include +#include +#include +#include +#include +#include +#include + +#include +#if (HAVE_KQUEUE) +#include +#endif + + +ngx_connection_t *ngx_connections; +ngx_event_t *ngx_read_events, *ngx_write_events; + +#if !(USE_KQUEUE) + +#if 1 +ngx_event_type_e ngx_event_type = NGX_SELECT_EVENT; +#else +ngx_event_type_e ngx_event_type = NGX_KQUEUE_EVENT; +#endif + +ngx_event_actions_t ngx_event_actions; + +/* ngx_event_type_e order */ +static void (*ngx_event_init[]) (int max_connections, ngx_log_t *log) = { + ngx_select_init, +#if (HAVE_POLL) + ngx_poll_init, +#endif +#if (HAVE_KQUEUE) + ngx_kqueue_init +#endif +}; + +#endif /* USE_KQUEUE */ + + +void ngx_worker(ngx_listen_t *sock, int n, ngx_pool_t *pool, ngx_log_t *log) +{ + int i, fd; + + /* per group */ + int max_connections = 512; + + ngx_init_events(max_connections, log); + + ngx_read_events = ngx_alloc(sizeof(ngx_event_t) * max_connections, log); + ngx_write_events = ngx_alloc(sizeof(ngx_event_t) * max_connections, log); + ngx_connections = ngx_alloc(sizeof(ngx_connection_t) + * max_connections, log); + + /* for each listening socket */ + for (i = 0; i < n; i++) { + fd = sock[i].fd; + + ngx_memzero(&ngx_read_events[fd], sizeof(ngx_event_t)); + ngx_memzero(&ngx_write_events[fd], sizeof(ngx_event_t)); + ngx_memzero(&ngx_connections[fd], sizeof(ngx_connection_t)); + + ngx_connections[fd].fd = fd; + ngx_connections[fd].server = sock[i].server; + ngx_connections[fd].read = (void *) &ngx_read_events[fd].data; + ngx_read_events[fd].data = &ngx_connections[fd]; + ngx_read_events[fd].log = ngx_connections[fd].log = sock[i].log; + ngx_read_events[fd].data = &ngx_connections[fd]; + ngx_read_events[fd].event_handler = &ngx_event_accept; + ngx_read_events[fd].listening = 1; + + ngx_read_events[fd].available = 0; + +#if (HAVE_DEFERRED_ACCEPT) + ngx_read_events[fd].accept_filter = sock->accept_filter; +#endif + ngx_add_event(&ngx_read_events[fd], NGX_READ_EVENT, 0); + } + + while (1) { + ngx_log_debug(log, "ngx_worker cycle"); + + ngx_process_events(log); + } +} diff --git a/src/event/ngx_event.h b/src/event/ngx_event.h new file mode 100644 --- /dev/null +++ b/src/event/ngx_event.h @@ -0,0 +1,127 @@ +#ifndef _NGX_EVENT_H_INCLUDED_ +#define _NGX_EVENT_H_INCLUDED_ + + +#include +#include +#include + +typedef struct ngx_event_s ngx_event_t; + +struct ngx_event_s { + void *data; + + int (*event_handler)(ngx_event_t *ev); + int (*close_handler)(ngx_event_t *ev); + void *context; + char *action; + + ngx_event_t *prev; /* queue in select(), poll() */ + ngx_event_t *next; + + int (*timer_handler)(ngx_event_t *ev); + ngx_event_t *timer_prev; + ngx_event_t *timer_next; + + u_int timer_delta; + u_int timer; + + ngx_log_t *log; + + int available; /* kqueue only: */ + /* accept: number of sockets that wait */ + /* to be accepted */ + /* read: bytes to read */ + /* write: available space in buffer */ + /* otherwise: */ + /* accept: 1 if accept many, 0 otherwise */ + + /* flags - int are probably faster on write then bits ??? */ + unsigned listening:1; + unsigned write:1; + + unsigned ready:1; + unsigned timedout:1; + unsigned process:1; + unsigned read_discarded:1; + + unsigned unexpected_eof:1; + +#if (HAVE_DEFERRED_ACCEPT) + unsigned accept_filter:1; +#endif +#if (HAVE_KQUEUE) + unsigned eof:1; + int errno; +#endif +}; + +typedef enum { + NGX_SELECT_EVENT = 0, +#if (HAVE_POLL) + NGX_POLL_EVENT, +#endif +#if (HAVE_KQUEUE) + NGX_KQUEUE_EVENT, +#endif +} ngx_event_type_e ; + +typedef struct { + int (*add)(ngx_event_t *ev, int event, u_int flags); + int (*del)(ngx_event_t *ev, int event); + int (*process)(ngx_log_t *log); +/* + int (*read)(ngx_event_t *ev, char *buf, size_t size); + int (*write)(ngx_event_t *ev, char *buf, size_t size); +*/ +} ngx_event_actions_t; + + +#if (HAVE_KQUEUE) + +#define NGX_READ_EVENT EVFILT_READ +#define NGX_WRITE_EVENT EVFILT_WRITE +#define NGX_TIMER_EVENT (-EVFILT_SYSCOUNT - 1) + +#define NGX_ONESHOT_EVENT EV_ONESHOT +#define NGX_CLEAR_EVENT EV_CLEAR + +#else + +#define NGX_READ_EVENT 0 +#define NGX_WRITE_EVENT 1 +#define NGX_TIMER_EVENT 2 + +#define NGX_ONESHOT_EVENT 1 +#define NGX_CLEAR_EVENT 2 + +#endif + + +#if (USE_KQUEUE) +#define ngx_init_events ngx_kqueue_init +#define ngx_process_events ngx_kqueue_process_events +#define ngx_add_event ngx_kqueue_add_event +#define ngx_del_event ngx_kqueue_del_event +#else +#define ngx_init_events (ngx_event_init[ngx_event_type]) +#define ngx_process_events ngx_event_actions.process +#define ngx_add_event ngx_event_actions.add +#define ngx_del_event ngx_event_actions.del +#endif + + +extern ngx_event_t *ngx_read_events; +extern ngx_event_t *ngx_write_events; +extern ngx_connection_t *ngx_connections; + +#if !(USE_KQUEUE) +extern ngx_event_actions_t ngx_event_actions; +extern ngx_event_type_e ngx_event_type; +#endif + + +void ngx_worker(ngx_listen_t *sock, int n, ngx_pool_t *pool, ngx_log_t *log); + + +#endif /* _NGX_EVENT_H_INCLUDED_ */ diff --git a/src/event/ngx_event_accept.c b/src/event/ngx_event_accept.c new file mode 100644 --- /dev/null +++ b/src/event/ngx_event_accept.c @@ -0,0 +1,83 @@ + +#include +#include +#include +#include +#include +#include +#include + + +int ngx_event_accept(ngx_event_t *ev) +{ + ngx_err_t err; + ngx_socket_t s; + struct sockaddr_in addr; + int addrlen = sizeof(struct sockaddr_in); + ngx_connection_t *cn = (ngx_connection_t *) ev->data; + + ngx_log_debug(ev->log, "ngx_event_accept: accept ready: %d" _ + ev->available); + + ev->ready = 0; + + do { + if ((s = accept(cn->fd, (struct sockaddr *) &addr, &addrlen)) == -1) { + err = ngx_socket_errno; + if (err == NGX_EAGAIN) { + ngx_log_error(NGX_LOG_INFO, ev->log, err, + "ngx_event_accept: EAGAIN while accept"); + return 0; + } + + ngx_log_error(NGX_LOG_ERR, ev->log, err, + "ngx_event_accept: accept failed"); + /* if we return -1 listen socket would be closed */ + return 0; + } + + ngx_log_debug(ev->log, "ngx_event_accept: accepted socket: %d" _ s); + + ngx_memzero(&ngx_read_events[s], sizeof(ngx_event_t)); + ngx_memzero(&ngx_write_events[s], sizeof(ngx_event_t)); + ngx_memzero(&ngx_connections[s], sizeof(ngx_connection_t)); + + ngx_read_events[s].data = ngx_write_events[s].data + = &ngx_connections[s]; + ngx_connections[s].read = &ngx_read_events[s]; + ngx_connections[s].write = &ngx_write_events[s]; + + ngx_connections[s].fd = s; + ngx_read_events[s].unexpected_eof = 1; + ngx_write_events[s].ready = 1; + + ngx_write_events[s].timer = ngx_read_events[s].timer = 10000; + + ngx_write_events[s].timer_handler = + ngx_read_events[s].timer_handler = ngx_event_close; + + ngx_write_events[s].close_handler = + ngx_read_events[s].close_handler = ngx_event_close; + + ngx_connections[s].server = cn->server; + ngx_connections[s].servers = cn->servers; + ngx_connections[s].log = + ngx_read_events[s].log = ngx_write_events[s].log = ev->log; + +#if (HAVE_DEFERRED_ACCEPT) + if (ev->accept_filter) + ngx_read_events[s].ready = 1; +#endif + + cn->server->handler(&ngx_connections[s]); + +#if (HAVE_KQUEUE) +#if !(USE_KQUEUE) + if (ngx_event_type == NGX_KQUEUE_EVENT) +#endif + ev->available--; +#endif + } while (ev->available); + + return 0; +} diff --git a/src/event/ngx_event_accept.h b/src/event/ngx_event_accept.h new file mode 100644 --- /dev/null +++ b/src/event/ngx_event_accept.h @@ -0,0 +1,10 @@ +#ifndef _NGX_EVENT_ACCEPT_H_INCLUDED_ +#define _NGX_EVENT_ACCEPT_H_INCLUDED_ + + +#include + +int ngx_event_accept(ngx_event_t *ev); + + +#endif /* _NGX_EVENT_ACCEPT_H_INCLUDED_ */ diff --git a/src/event/ngx_event_close.c b/src/event/ngx_event_close.c new file mode 100644 --- /dev/null +++ b/src/event/ngx_event_close.c @@ -0,0 +1,29 @@ + +#include +#include +#include +#include + + +int ngx_event_close(ngx_event_t *ev) +{ + int rc; + ngx_connection_t *cn = (ngx_connection_t *) ev->data; + + ngx_assert((cn->fd != -1), return -1, ev->log, + "ngx_event_close: already closed"); + + if ((rc = ngx_close_socket(cn->fd)) == -1) + ngx_log_error(NGX_LOG_ERR, ev->log, ngx_socket_errno, + "ngx_event_close: close failed"); + + if (cn->read->next) + ngx_del_event(cn->read, NGX_READ_EVENT); + + if (cn->write->next) + ngx_del_event(cn->write, NGX_WRITE_EVENT); + + cn->fd = -1; + + return rc; +} diff --git a/src/event/ngx_event_close.h b/src/event/ngx_event_close.h new file mode 100644 --- /dev/null +++ b/src/event/ngx_event_close.h @@ -0,0 +1,10 @@ +#ifndef _NGX_EVENT_CLOSE_H_INCLUDED_ +#define _NGX_EVENT_CLOSE_H_INCLUDED_ + + +#include + +int ngx_event_close(ngx_event_t *ev); + + +#endif /* _NGX_EVENT_CLOSE_H_INCLUDED_ */ diff --git a/src/event/ngx_event_read.c b/src/event/ngx_event_read.c new file mode 100644 --- /dev/null +++ b/src/event/ngx_event_read.c @@ -0,0 +1,55 @@ + +#include +#include +#include +#include + +int ngx_event_recv(ngx_connection_t *c, char *buf, size_t size) +{ + int n; + ngx_err_t err; + ngx_event_t *ev = c->read; + +#if (HAVE_KQUEUE) +#if !(USE_KQUEUE) + if (ngx_event_type == NGX_KQUEUE_EVENT) +#endif + if (ev->eof && ev->available == 0) { + if (ev->error) { + ngx_log_error(NGX_LOG_ERR, ev->log, ev->error, + "ngx_event_recv: recv failed while %s", + ev->log->action); + + return -1; + } + + return 0; + } +#endif + + n = recv(c->fd, buf, size, 0); + + if (n == -1) { + err = ngx_socket_errno; + + if (err == NGX_EAGAIN) { + ngx_log_error(NGX_LOG_INFO, ev->log, err, + "ngx_event_recv: EAGAIN while %s", ev->log->action); + return -2; + } + + ngx_log_error(NGX_LOG_INFO, ev->log, err, + "ngx_event_recv: recv failed while %s", ev->log->action); + + return -1; + } + +#if (HAVE_KQUEUE) +#if !(USE_KQUEUE) + if (ngx_event_type == NGX_KQUEUE_EVENT) +#endif + ev->available -= n; +#endif + + return n; +} diff --git a/src/event/ngx_event_write.c b/src/event/ngx_event_write.c new file mode 100644 --- /dev/null +++ b/src/event/ngx_event_write.c @@ -0,0 +1,136 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +ngx_chain_t *ngx_event_writer(ngx_connection_t *cn, ngx_chain_t *in, + off_t flush) +{ + int rc; + char *last; + off_t sent; + ngx_iovec_t *iov; + ngx_array_t *header, *trailer; + ngx_hunk_t *file; + ngx_chain_t *ch; + + ch = in; + file = NULL; + + ngx_test_null(header, ngx_create_array(cn->pool, 10, sizeof(ngx_iovec_t)), + (ngx_chain_t *) -1); + + ngx_test_null(trailer, ngx_create_array(cn->pool, 10, sizeof(ngx_iovec_t)), + (ngx_chain_t *) -1); + + do { + header->nelts = 0; + trailer->nelts = 0; + + if (ch->hunk->type & (NGX_HUNK_IN_MEMORY | NGX_HUNK_FLUSH)) { + last = NULL; + iov = NULL; + + while (ch + && (ch->hunk->type & (NGX_HUNK_IN_MEMORY | NGX_HUNK_FLUSH))) + { + if (ch->hunk->type & NGX_HUNK_FLUSH) + continue; + + if (last == ch->hunk->pos.p) { + iov->ngx_iov_len += ch->hunk->last.p - ch->hunk->pos.p; + + } else { + ngx_test_null(iov, ngx_push_array(header), + (ngx_chain_t *) -1); + iov->ngx_iov_base = ch->hunk->pos.p; + iov->ngx_iov_len = ch->hunk->last.p - ch->hunk->pos.p; + last = ch->hunk->last.p; + } + + ch = ch->next; + } + } + + if (ch && (ch->hunk->type & NGX_HUNK_FILE)) { + file = ch->hunk; + ch = ch->next; + } + +#if (HAVE_MAX_SENDFILE_IOVEC) + if (file && header->nelts > HAVE_MAX_SENDFILE_IOVEC) { + rc = ngx_sendv(cn->fd, (ngx_iovec_t *) header->elts, header->nelts, + &sent); + } else { +#endif + if (ch && ch->hunk->type & (NGX_HUNK_IN_MEMORY | NGX_HUNK_FLUSH)) { + last = NULL; + iov = NULL; + + while (ch + && (ch->hunk->type & (NGX_HUNK_IN_MEMORY | NGX_HUNK_FLUSH))) + { + if (ch->hunk->type & NGX_HUNK_FLUSH) + continue; + + if (last == ch->hunk->pos.p) { + iov->ngx_iov_len += ch->hunk->last.p - ch->hunk->pos.p; + + } else { + ngx_test_null(iov, ngx_push_array(trailer), + (ngx_chain_t *) -1); + iov->ngx_iov_base = ch->hunk->pos.p; + iov->ngx_iov_len = ch->hunk->last.p - ch->hunk->pos.p; + last = ch->hunk->last.p; + } + + ch = ch->next; + } + } + + if (file) { + rc = ngx_sendfile(cn->fd, + (ngx_iovec_t *) header->elts, header->nelts, + file->fd, file->pos.f, + (size_t) (file->last.f - file->pos.f), + (ngx_iovec_t *) trailer->elts, trailer->nelts, + &sent, cn->log); + } else { + rc = ngx_sendv(cn->fd, (ngx_iovec_t *) header->elts, + header->nelts, (size_t *) &sent); + } +#if (HAVE_MAX_SENDFILE_IOVEC) + } +#endif + /* save sent for logging */ + + if (rc == -1) + return (ngx_chain_t *) -1; + + flush -= sent; + + for (ch = in; ch && !(ch->hunk->type & NGX_HUNK_LAST); ch = ch->next) { + if (sent >= ch->hunk->last.f - ch->hunk->pos.f) { + sent -= ch->hunk->last.f - ch->hunk->pos.f; + ch->hunk->last.f = ch->hunk->pos.f; + continue; + } + + ch->hunk->pos.f += sent; + break; + } + + } while (flush > 0); + + ngx_destroy_array(trailer); + ngx_destroy_array(header); + + return ch; +} diff --git a/src/event/ngx_event_write.h b/src/event/ngx_event_write.h new file mode 100644 --- /dev/null +++ b/src/event/ngx_event_write.h @@ -0,0 +1,13 @@ +#ifndef _NGX_EVENT_WRITE_H_INCLUDED_ +#define _NGX_EVENT_WRITE_H_INCLUDED_ + + +#include +#include +#include + +ngx_chain_t *ngx_event_write(ngx_connection_t *cn, ngx_chain_t *in, + off_t flush); + + +#endif /* _NGX_EVENT_WRITE_H_INCLUDED_ */ diff --git a/src/http/modules/ngx_http_index_handler.c b/src/http/modules/ngx_http_index_handler.c new file mode 100644 --- /dev/null +++ b/src/http/modules/ngx_http_index_handler.c @@ -0,0 +1,123 @@ + +#include + +#include +#include +#include + +#include + +int ngx_http_index_handler(ngx_http_request_t *r) +{ + int index_len, err, i; + char *name, *loc, *file + ngx_file_t fd; + + ngx_http_index_t *index; + ngx_http_index_handler_loc_conf_t *cf; + + cf = (ngx_http_index_handler_loc_conf_t *) + ngx_get_module_loc_conf(r, &ngx_http_index_handler_module); + + index_len = (*(r->uri_end - 1) == '/') ? cf->max_index_len : 0; + name = ngx_palloc(r->pool, r->uri_end - r->uri_start + index_len + + r->server->doc_root_len); + if (name == NULL) + return NGX_ERROR; + + loc = ngx_cpystrn(name, r->server->doc_root, r->server->doc_root_len); + file = ngx_cpystrn(loc, r->uri_start, r->uri_end - r->uri_start + 1); + + /* URI without / on the end - check directory */ + if (index_len == 0) { + + if (ngx_stat(name, &r->stat) == -1) { + err = ngx_errno; + ngx_log_error(GX_LOG_ERR, r->connection->log, err, + "ngx_http_handler: " ngx_stat_n " %s failed", name); + + if (err == NGX_ENOENT) + return NGX_HTTP_NOT_FOUND; + else + return NGX_ERROR; + } + + if (ngx_is_dir(r->stat)) { + *file++ = '/'; + *file = '\0'; + r->headers_out->location = loc; + return NGX_HTTP_MOVED_PERMANENTLY; + } + + r->file = name; + r->stat_valid = 1; + + return NGX_OK; + } + + /* look for index file */ + index = (ngx_http_index_t *) cf->indices->elts; + for (i = 0; i < cf->indices->nelts; i++) { + ngx_memcpy(file, index[i].name; index[i].len); + + fd = ngx_open(name, O_RDONLY); + if (fd != -1) { + r->file = name; + r->fd = fd; + return NGX_OK; + } + } + + return NGX_HTTP_FORBIDDEN; +} + +/* + +static void *ngx_create_index_config() +{ + ngx_http_index_handler_loc_conf_t *cf; + + ngx_check_null(cf, ngx_alloc(p, sizeof(ngx_http_index_handler_loc_conf)), + NULL); + + cf->indices = ngx_create_array(p, sizeof(ngx_http_index_t), 5); + if (cf->indices == NULL) + return NULL; + + cf->max_index_len = 0; + + return cf; +} + +static void *ngx_merge_index_config() +{ + if (p->indices->nelts > 0) { + + copy and check dups + + if (c->max_index_len < c->max_index_len) + c->max_index_len < c->max_index_len); + } +} + +static void *ngx_set_index() +{ + if (*conf == NULL) { + cf = ngx_create_index_conf(); + if (cf == NULL) + return "can not create config"; + } + + while (args) { + index = ngx_push_array(cf->indices); + index->name = arg; + index->len = ngx_strlen(arg) + 1; + + if (cf->max_index_len < index->len) + cf->max_index_len = index->len; + } + + *conf = cf; +} + +*/ diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h new file mode 100644 --- /dev/null +++ b/src/http/ngx_http.h @@ -0,0 +1,84 @@ +#ifndef _NGX_HTTP_H_INCLUDED_ +#define _NGX_HTTP_H_INCLUDED_ + + +#include +#include +#include + + +#define NGX_SYS_ERROR -1 +#define NGX_HTTP_INVALID_METHOD -2 +#define NGX_HTTP_INVALID_REQUEST -3 +#define NGX_HTTP_INVALID_HEADER -4 + +#define NGX_HTTP_GET 1 +#define NGX_HTTP_HEAD 2 +#define NGX_HTTP_POST 3 + +#define NGX_HTTP_CONN_CLOSE 0 +#define NGX_HTTP_CONN_KEEP_ALIVE 1 + +#define NGX_HTTP_OK 200 + + +typedef struct { + char *buff; + char *pos; + char *last; + char *end; +} ngx_buff_t; + +typedef struct { + int status; + int connection; + size_t content_length; + char *content_type; + char *charset; + char *etag; + time_t date; + time_t last_modified; +} ngx_http_header_out_t; + +typedef struct ngx_http_request_s ngx_http_request_t; + +struct ngx_http_request_s { + int method; + + int http_version; + int http_major; + int http_minor; + + char *uri; + ngx_http_request_t *main; + + ngx_connection_t *connection; + ngx_buff_t *buff; + ngx_pool_t *pool; + + /* internal */ + unsigned unusual_uri:1; + unsigned complex_uri:1; + + int state; + char *uri_start; + char *uri_end; + char *uri_ext; + char *args_start; + char *header_name_start; + char *header_name_end; + char *header_start; + char *header_end; +#ifdef NGX_EVENT + int (*state_handler)(ngx_http_request_t *r); +#endif +}; + + +#define NGX_INDEX "index.html" + + +int ngx_http_init_connection(ngx_connection_t *c); + + +#endif /* _NGX_HTTP_H_INCLUDED_ */ diff --git a/src/http/ngx_http_event.c b/src/http/ngx_http_event.c new file mode 100644 --- /dev/null +++ b/src/http/ngx_http_event.c @@ -0,0 +1,273 @@ + +#include +#include +#include +#include +#include + +#include + +/* +ngx_read should check errors (if we ask) and return + -2 EAGAIN + -1 error + 0 EOF + >0 number of bytes +*/ + + int ngx_http_init_connection(ngx_connection_t *c); +static int ngx_http_init_request(ngx_event_t *ev); +static int ngx_http_process_request(ngx_event_t *ev); + +static int ngx_process_http_request_line(ngx_http_request_t *r); +static int ngx_process_http_request_header(ngx_http_request_t *r); + +static int ngx_process_http_request(ngx_http_request_t *r); + +static int ngx_http_close_request(ngx_event_t *ev); + +/* + returns + -1 if error + 0 need more data or EOF (filter is deleted) + 1 there is unread data +*/ + +int ngx_http_init_connection(ngx_connection_t *c) +{ + ngx_event_t *ev; + + ev = c->read; +/* + ev->event_handler = ngx_http_init_request; +*/ + ev->event_handler = NULL; + ev->log->action = "reading client request line"; + + ngx_log_debug(ev->log, "ngx_http_init_connection: entered"); + + /* XXX: ev->timer ? */ + if (ngx_add_event(ev, NGX_TIMER_EVENT, ev->timer) == -1) + return -1; + +#if (HAVE_DEFERRED_ACCEPT) + if (ev->ready) + return ngx_http_init_request(ev); + else +#endif +#if (NGX_CLEAR_EVENT) + return ngx_add_event(ev, NGX_READ_EVENT, NGX_CLEAR_EVENT); +#else + return ngx_add_event(ev, NGX_READ_EVENT, NGX_ONESHOT_EVENT); +#endif +} + +#if 0 + +int ngx_http_init_request(ngx_event_t *ev) +{ + ngx_connection_t *c = (ngx_connection_t *) ev->data; + ngx_http_request_t *r; + + ngx_log_debug(ev->log, "ngx_http_init_request: entered"); + + ngx_test_null(r, ngx_pcalloc(c->pool, sizeof(ngx_http_request_t)), -1); + + c->data = r; + r->connection = c; + + ngx_test_null(r->buff, ngx_palloc(r->pool, sizeof(ngx_buff_t)), -1); + ngx_test_null(r->buff->buff, + ngx_pcalloc(r->pool, sizeof(c->server->buff_size)), -1); + + r->buff->pos = r->buff->last = r->buff->buff; + r->buff->end = r->buff->buff + c->server->buff_size; + + r->state_handler = ngx_process_http_request_line; + + ev->event_handler = ngx_http_process_request; + ev->close_handler = ngx_http_close_request; + c->write->close_handler = ngx_http_close_request; + return ngx_http_process_request(ev); +} + +int ngx_http_process_request(ngx_event_t *ev) +{ + int n; + ngx_connection_t *c = (ngx_connection_t *) ev->data; + ngx_http_request_t *r = (ngx_http_request_t *) c->data; + + ngx_log_debug(ev->log, "http process request"); + + ngx_log_debug(ev->log, "http: eof:%d, avail:%d", ev->eof, ev->available); + + if (ev->eof && ev->available == 0) { + if (ev->err_no) + ngx_log_error(NGX_LOG_ERR, ev->log, ev->err_no, + "ngx_http_process_request: " + "read failed while %s", ev->action); + + return -1; + } + + if ((n = read(c->fd, r->buff->last, r->buff->end - r->buff->last)) == -1) { + + if (errno == NGX_EWOULDBLOCK) { + ngx_log_error(NGX_LOG_INFO, ev->log, errno, + "ngx_http_process_request: " + "EAGAIN while %s", ev->action); + return 0; + } + + ngx_log_error(NGX_LOG_ERR, ev->log, errno, + "ngx_http_process_request: " + "read failed while %s", ev->action); + return -1; + } + + ngx_log_debug(ev->log, "http read %d", n); + + if (n == 0) { + if (ev->unexpected_eof) { + ngx_log_error(NGX_LOG_INFO, ev->log, 0, + "ngx_http_process_request: " + "connection is closed while %s", ev->action); + return -1; + } + + return ngx_http_close_request(ev); + } + + n == r->buff->end - r->buff->last; + + if (!ev->read_discarded) { + r->buff->last += n; + + /* state_handlers are called in following order: + ngx_process_http_request_line() + ngx_process_http_request_header() */ + + do { + if ((r->state_handler)(r) < 0) + return -1; + } while (r->buff->pos < r->buff->last); + } + + if (ngx_del_event(ev, NGX_TIMER_EVENT) == -1) + return -1; + + if (ngx_add_event(ev, NGX_TIMER_EVENT, ev->timer) == -1) + return -1; + + return 0; +} + +static int ngx_process_http_request_line(ngx_http_request_t *r) +{ + int n; + + if ((n = ngx_read_http_request_line(r)) == 1) { + *r->uri_end = '\0'; + ngx_log_debug(r->connection->log, "HTTP: %d, %d, %s", + r->method, r->http_version, r->uri_start); + r->state_handler = ngx_process_http_request_header; + r->connection->read->action = "reading client request headers"; + } + + return n; +} + +static int ngx_process_http_request_header(ngx_http_request_t *r) +{ + int n; + + while ((n = ngx_read_http_header_line(r)) == 1) { + *r->header_name_end = '\0'; + *r->header_end = '\0'; + ngx_log_debug(r->connection->log, "HTTP header: '%s: %s'", + r->header_name_start, r->header_start); + } + + if (n != 2) + return n; + + r->state_handler = NULL; + r->connection->read->action = "reading client request body"; + + r->connection->read->read_discarded = 1; + r->connection->read->unexpected_eof = 0; + ngx_log_debug(r->connection->log, "HTTP header done"); + + return ngx_process_http_request(r); +} + +static int ngx_process_http_request(ngx_http_request_t *r) +{ + int fd; + struct stat sb; + ngx_http_header_out_t *header_out; + ngx_chunk_t *header, *ch; + + int index = (*(r->uri_end - 1) == '/') ? sizeof(NGX_INDEX) : 1; + char *name = ngx_palloc(r->pool, + r->uri_end - r->uri_start + strlen(ngx_root) + index); + strcpy(name, ngx_root); + strcat(name, r->uri_start); + if (*(r->uri_end - 1) == '/') + strcat(name, NGX_INDEX); + + ngx_log_debug(r->connection->log, "HTTP URI: '%s'", name); + + if ((fd = open(name, O_RDONLY)) == -1) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, errno, + "open %s failed", name); + return -1; + } + + if (fstat(fd, &sb) == -1) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, errno, + "fstat %s failed", name); + return -1; + } + + header_out = ngx_palloc(r->pool, sizeof(ngx_http_header_out_t)); + + header_out->status = NGX_HTTP_OK; + header_out->content_length = sb.st_size; + header_out->last_modified = sb.st_mtime; + header_out->content_type = "text/html"; + header_out->charset = "koi8-r"; + header_out->date = time(NULL); + header_out->connection = NGX_HTTP_CONN_CLOSE; + +/* + header_out->connection = NGX_HTTP_CONN_KEEP_ALIVE; + r->connection->read->event_handler = ngx_http_init_request; +*/ + + header = ngx_http_header(r, header_out); + ch = ngx_palloc(r->pool, sizeof(ngx_chunk_t)); + ch->ident = fd; + ch->offset = 0; + ch->size = sb.st_size; + ch->next = NULL; + header->next = ch; + + ngx_event_write(r->connection, header); + + return 0; +} + +static int ngx_http_close_request(ngx_event_t *ev) +{ + ngx_connection_t *c = (ngx_connection_t *) ev->data; + + ngx_log_debug(ev->log, "http close"); + + ngx_del_event(c->read, NGX_TIMER_EVENT); + ngx_del_event(c->write, NGX_TIMER_EVENT); + + return ngx_event_close(ev); +} + +#endif diff --git a/src/http/ngx_http_header.h b/src/http/ngx_http_header.h new file mode 100644 --- /dev/null +++ b/src/http/ngx_http_header.h @@ -0,0 +1,2 @@ + +gx_chunk_t *gx_http_header(gx_http_request_t *r, gx_http_header_out_t *out); diff --git a/src/os/unix/ngx_errno.h b/src/os/unix/ngx_errno.h new file mode 100644 --- /dev/null +++ b/src/os/unix/ngx_errno.h @@ -0,0 +1,21 @@ +#ifndef _NGX_ERRNO_H_INCLUDED_ +#define _NGX_ERRNO_H_INCLUDED_ + + +#include +#include + +typedef int ngx_err_t; + +#define NGX_ENOENT ENOENT +#define NGX_EINTR EINTR +#define NGX_EAGAIN EWOULDBLOCK + +#define ngx_errno errno +#define ngx_socket_errno errno + +#define ngx_strerror_r(err, errstr, size) \ + ngx_cpystrn(errstr, strerror(err), size) - (errstr) + + +#endif /* _NGX_ERRNO_H_INCLUDED_ */ diff --git a/src/os/unix/ngx_sendfile.c b/src/os/unix/ngx_sendfile.c new file mode 100644 --- /dev/null +++ b/src/os/unix/ngx_sendfile.c @@ -0,0 +1,65 @@ + +#include +#include +#include +#include +#include +#include + +/* + TODO: + FreeBSD: + check sent if errno == EINTR then should return right sent. +*/ + +/* + returns + 0 done + -1 error +*/ + +#if (HAVE_FREEBSD_SENDFILE) + +int ngx_sendfile(ngx_socket_t s, + ngx_iovec_t *headers, int hdr_cnt, + ngx_file_t fd, off_t offset, size_t nbytes, + ngx_iovec_t *trailers, int trl_cnt, + off_t *sent, + ngx_log_t *log) +{ + int rc, i; + ngx_err_t err; + struct sf_hdtr hdtr; + + hdtr.headers = headers; + hdtr.hdr_cnt = hdr_cnt; + hdtr.trailers = trailers; + hdtr.trl_cnt = trl_cnt; + +#if (HAVE_FREEBSD_SENDFILE_NBYTES_BUG) + for (i = 0; i < hdr_cnt; i++) + nbytes += headers[i].iov_len; +#endif + + rc = sendfile(fd, s, offset, nbytes, &hdtr, sent, 0); + + if (rc == -1) { + err = ngx_socket_errno; + if (err != NGX_EAGAIN && err != NGX_EINTR) { + ngx_log_error(NGX_LOG_ERR, log, err, + "ngx_sendfile: sendfile failed"); + return -1; + + } else { + ngx_log_error(NGX_LOG_INFO, log, err, + "ngx_sendfile: sendfile sent only %qd bytes", *sent); + } + } + + ngx_log_debug(log, "ngx_sendfile: %d, @%qd %d:%qd" _ + rc _ offset _ nbytes _ *sent); + + return 0; +} + +#endif diff --git a/src/os/unix/ngx_sendfile.h b/src/os/unix/ngx_sendfile.h new file mode 100644 --- /dev/null +++ b/src/os/unix/ngx_sendfile.h @@ -0,0 +1,17 @@ +#ifndef _NGX_SENDFILE_H_INCLUDED_ +#define _NGX_SENDFILE_H_INCLUDED_ + + +#include +#include +#include + +int ngx_sendfile(ngx_socket_t s, + ngx_iovec_t *headers, int hdr_cnt, + ngx_file_t fd, off_t offset, size_t nbytes, + ngx_iovec_t *trailers, int trl_cnt, + off_t *sent, + ngx_log_t *log); + + +#endif /* _NGX_SENDFILE_H_INCLUDED_ */ diff --git a/src/os/unix/ngx_sendv.c b/src/os/unix/ngx_sendv.c new file mode 100644 --- /dev/null +++ b/src/os/unix/ngx_sendv.c @@ -0,0 +1,14 @@ + +#include +#include + +ssize_t ngx_sendv(ngx_socket_t s, ngx_iovec_t *iovec, int n, size_t *sent) +{ + ssize_t rc = writev(s, iovec, n); + + if (rc == -1) + return -1; + + *sent = rc; + return 0; +} diff --git a/src/os/unix/ngx_sendv.h b/src/os/unix/ngx_sendv.h new file mode 100644 --- /dev/null +++ b/src/os/unix/ngx_sendv.h @@ -0,0 +1,14 @@ +#ifndef _NGX_SENDV_H_INCLUDED_ +#define _NGX_SENDV_H_INCLUDED_ + + +#include + +typedef struct iovec ngx_iovec_t; +#define ngx_iov_base iov_base +#define ngx_iov_len iov_len + +ssize_t ngx_sendv(ngx_socket_t s, ngx_iovec_t *iovec, int n, size_t *sent); + + +#endif /* _NGX_SENDV_H_INCLUDED_ */ diff --git a/src/os/unix/ngx_stat.h b/src/os/unix/ngx_stat.h new file mode 100644 --- /dev/null +++ b/src/os/unix/ngx_stat.h @@ -0,0 +1,19 @@ +#ifndef _NGX_STAT_H_INCLUDED_ +#define _NGX_STAT_H_INCLUDED_ + + +#include +#include + +typedef struct stat ngx_stat_t; + +#define ngx_is_dir(sb) (S_ISDIR(sb.st_mode)) + +#define ngx_stat(file, sb) stat(file, sb) +#define ngx_stat_n "stat" + +#define ngx_fstat(file, fd, sb) fstat(fd, sb) +#define ngx_fstat_n "stat" + + +#endif /* _NGX_STAT_H_INCLUDED_ */ diff --git a/src/os/unix/ngx_time.c b/src/os/unix/ngx_time.c new file mode 100644 --- /dev/null +++ b/src/os/unix/ngx_time.c @@ -0,0 +1,19 @@ + +#include +#include + +void ngx_localtime(ngx_tm_t *tm) +{ + time_t clock = time(NULL); + localtime_r(&clock, tm); +} + +u_int ngx_msec(void) +{ + struct timeval tv; + + gettimeofday(&tv, NULL); + + return tv.tv_sec * 1000 + tv.tv_usec / 1000; +} + diff --git a/src/os/unix/ngx_time.h b/src/os/unix/ngx_time.h new file mode 100644 --- /dev/null +++ b/src/os/unix/ngx_time.h @@ -0,0 +1,22 @@ +#ifndef _NGX_TIME_H_INCLUDED_ +#define _NGX_TIME_H_INCLUDED_ + + +#include + +typedef struct tm ngx_tm_t; + +#define ngx_tm_sec tm_sec +#define ngx_tm_min tm_min +#define ngx_tm_hour tm_hour +#define ngx_tm_mday tm_mday +#define ngx_tm_mon tm_mon +#define ngx_tm_year tm_year +#define ngx_tm_wday tm_wday + +void ngx_localtime(ngx_tm_t *tm); + +u_int ngx_msec(void); + + +#endif /* _NGX_TIME_H_INCLUDED_ */ diff --git a/src/os/unix/ngx_types.h b/src/os/unix/ngx_types.h new file mode 100644 --- /dev/null +++ b/src/os/unix/ngx_types.h @@ -0,0 +1,12 @@ +#ifndef _NGX_TYPES_H_INCLUDED_ +#define _NGX_TYPES_H_INCLUDED_ + + +#include + + +typedef int ngx_file_t; +typedef int ngx_socket_t; + + +#endif /* _NGX_TYPES_H_INCLUDED_ */ diff --git a/src/os/win32/ngx_errno.c b/src/os/win32/ngx_errno.c new file mode 100644 --- /dev/null +++ b/src/os/win32/ngx_errno.c @@ -0,0 +1,38 @@ + +/* + TODO: + add WSA error messages + test for English only messages +*/ + +#include +#include +#include + +int ngx_strerror_r(ngx_err_t err, char *errstr, size_t size) +{ + int len; + + len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM + | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, err, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + errstr, size, NULL); + + /* add WSA error messages */ + + if (len == 0) { + + len = ngx_snprintf(errstr, size, + "FormatMessage error:(%d)", GetLastError()); + return len; + + } + + /* remove ".\r\n\0" */ + while (errstr[len] == '\0' || errstr[len] == CR + || errstr[len] == LF || errstr[len] == '.') + --len; + + return ++len; +} diff --git a/src/os/win32/ngx_errno.h b/src/os/win32/ngx_errno.h new file mode 100644 --- /dev/null +++ b/src/os/win32/ngx_errno.h @@ -0,0 +1,18 @@ +#ifndef _NGX_ERRNO_H_INCLUDED_ +#define _NGX_ERRNO_H_INCLUDED_ + + +#include + +typedef DWORD ngx_err_t; + +#define ngx_errno GetLastError() +#define ngx_socket_errno WSAGetLastError() + +#define NGX_ENOENT ERROR_FILE_NOT_FOUND +#define NGX_EAGAIN WSAEWOULDBLOCK + +int ngx_strerror_r(ngx_err_t err, char *errstr, size_t size); + + +#endif /* _NGX_ERRNO_H_INCLUDED_ */ diff --git a/src/os/win32/ngx_sendfile.c b/src/os/win32/ngx_sendfile.c new file mode 100644 --- /dev/null +++ b/src/os/win32/ngx_sendfile.c @@ -0,0 +1,89 @@ + +#include +#include +#include +#include +#include +#include + +/* + TODO: + various flags + TransmitPackets +*/ + +/* + returns + 0 done + -1 error +*/ + +#if (HAVE_WIN32_TRANSMITFILE) + +int ngx_sendfile(ngx_socket_t s, + ngx_iovec_t *headers, int hdr_cnt, + ngx_file_t fd, off_t offset, size_t nbytes, + ngx_iovec_t *trailers, int trl_cnt, + off_t *sent, + ngx_log_t *log) +{ + int tfrc, rc; + ngx_err_t tf_err, err; + OVERLAPPED olp; + TRANSMIT_FILE_BUFFERS tfb, *ptfb; + + tf_err = 0; + err = 0; + + olp.Internal = 0; + olp.InternalHigh = 0; + olp.Offset = (DWORD) offset; + olp.OffsetHigh = (DWORD) (offset >> 32); + olp.hEvent = NULL; + + if (headers || trailers) { + tfb.Head = headers->ngx_iov_base; + tfb.HeadLength = headers->ngx_iov_len; + tfb.Tail = trailers->ngx_iov_base; + tfb.TailLength = trailers->ngx_iov_len; + ptfb = &tfb; + + } else { + ptfb = NULL; + } + + tfrc = TransmitFile(s, fd, nbytes, 0, &olp, ptfb, 0); + + if (tfrc == 0) + tf_err = ngx_socket_errno; + + /* set sent */ + rc = WSAGetOverlappedResult(s, &olp, (unsigned long *) sent, 0, NULL); + + ngx_log_debug(log, "ngx_sendfile: %d, @%qd %d:%qd" _ + tfrc _ offset _ nbytes _ *sent); + + if (rc == 0) { + err = ngx_socket_errno; + ngx_log_error(NGX_LOG_ERR, log, err, + "ngx_sendfile: WSAGetOverlappedResult failed"); + } + + if (tfrc == 0) { + if (tf_err != NGX_EAGAIN) { + ngx_log_error(NGX_LOG_ERR, log, tf_err, + "ngx_sendfile: TransmitFile failed"); + return -1; + } + + ngx_log_error(NGX_LOG_INFO, log, tf_err, + "ngx_sendfile: TransmitFile sent only %qd bytes", *sent); + } + + if (rc == 0) + return -1; + + return 0; +} + +#endif diff --git a/src/os/win32/ngx_sendfile.h b/src/os/win32/ngx_sendfile.h new file mode 100644 --- /dev/null +++ b/src/os/win32/ngx_sendfile.h @@ -0,0 +1,18 @@ +#ifndef _NGX_SENDFILE_H_INCLUDED_ +#define _NGX_SENDFILE_H_INCLUDED_ + + +#include +#include +#include +#include + +int ngx_sendfile(ngx_socket_t s, + ngx_iovec_t *headers, int hdr_cnt, + ngx_file_t fd, off_t offset, size_t nbytes, + ngx_iovec_t *trailers, int trl_cnt, + off_t *sent, + ngx_log_t *log); + + +#endif /* _NGX_SENDFILE_H_INCLUDED_ */ diff --git a/src/os/win32/ngx_sendv.h b/src/os/win32/ngx_sendv.h new file mode 100644 --- /dev/null +++ b/src/os/win32/ngx_sendv.h @@ -0,0 +1,14 @@ +#ifndef _NGX_SENDV_H_INCLUDED_ +#define _NGX_SENDV_H_INCLUDED_ + + +#include + +typedef WSABUF ngx_iovec_t; +#define ngx_iov_base buf +#define ngx_iov_len len + +#define ngx_sendv(s, iovec, n, sent) WSASend(s, iovec, n, sent, 0, NULL, NULL) + + +#endif /* _NGX_SENDV_H_INCLUDED_ */ diff --git a/src/os/win32/ngx_stat.c b/src/os/win32/ngx_stat.c new file mode 100644 --- /dev/null +++ b/src/os/win32/ngx_stat.c @@ -0,0 +1,15 @@ + +#include + +#include + +int ngx_stat(char *file, ngx_stat_t *sb) +{ + *sb = GetFileAttributes(file); + + if (*sb == INVALID_FILE_ATTRIBUTES) { + return -1; + } + + return 0; +} diff --git a/src/os/win32/ngx_stat.h b/src/os/win32/ngx_stat.h new file mode 100644 --- /dev/null +++ b/src/os/win32/ngx_stat.h @@ -0,0 +1,26 @@ +#ifndef _NGX_STAT_H_INCLUDED_ +#define _NGX_STAT_H_INCLUDED_ + + +#include + +/* INVALID_FILE_ATTRIBUTES specified but never defined */ +#ifndef INVALID_FILE_ATTRIBUTES +#define INVALID_FILE_ATTRIBUTES 0xFFFFFFFF +#endif + +typedef DWORD ngx_stat_t; + + +#define ngx_is_dir(sb) (*sb & FILE_ATTRIBUTE_DIRECTORY) + +#define ngx_stat_n "GetFileAttributes" + +#define ngx_fstat(file, fd, sb) ngx_stat(file, sb) +#define ngx_fstat_n "GetFileAttributes" + + +int ngx_stat(char *file, ngx_stat_t *sb); + + +#endif /* _NGX_STAT_H_INCLUDED_ */ diff --git a/src/os/win32/ngx_time.h b/src/os/win32/ngx_time.h new file mode 100644 --- /dev/null +++ b/src/os/win32/ngx_time.h @@ -0,0 +1,21 @@ +#ifndef _NGX_TIME_H_INCLUDED_ +#define _NGX_TIME_H_INCLUDED_ + + +#include + +typedef SYSTEMTIME ngx_tm_t; + +#define ngx_tm_sec wSecond +#define ngx_tm_min wMinute +#define ngx_tm_hour wHour +#define ngx_tm_mday wDay +#define ngx_tm_mon wMonth +#define ngx_tm_year wYear +#define ngx_tm_wday wDayOfWeek + +#define ngx_localtime GetLocalTime +#define ngx_msec GetTickCount + + +#endif /* _NGX_TIME_H_INCLUDED_ */ diff --git a/src/os/win32/ngx_types.h b/src/os/win32/ngx_types.h new file mode 100644 --- /dev/null +++ b/src/os/win32/ngx_types.h @@ -0,0 +1,14 @@ +#ifndef _NGX_TYPES_H_INCLUDED_ +#define _NGX_TYPES_H_INCLUDED_ + + +#include + + +typedef HANDLE ngx_file_t; +typedef SOCKET ngx_socket_t; +typedef long time_t; +typedef unsigned __int64 off_t; + + +#endif /* _NGX_TYPES_H_INCLUDED_ */