mirror of
https://github.com/nginx/nginx.git
synced 2025-07-26 07:06:55 +08:00
nginx-0.0.1-2003-05-12-19:52:24 import
This commit is contained in:
parent
4fe262b682
commit
6b863e353d
@ -67,6 +67,10 @@ int main(int argc, char *const *argv)
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (ngx_os_init(&ngx_log) == NGX_ERROR) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
ngx_init_array(ngx_listening_sockets, ngx_pool, 10, sizeof(ngx_listen_t),
|
ngx_init_array(ngx_listening_sockets, ngx_pool, 10, sizeof(ngx_listen_t),
|
||||||
1);
|
1);
|
||||||
|
|
||||||
|
@ -141,7 +141,7 @@ int ngx_kqueue_del_event(ngx_event_t *ev, int event, u_int flags)
|
|||||||
|
|
||||||
if (nchanges > 0
|
if (nchanges > 0
|
||||||
&& ev->index < nchanges
|
&& ev->index < nchanges
|
||||||
&& change_list[ev->index].udata == ev)
|
&& (void *) ((uintptr_t) change_list[ev->index].udata & ~1) == ev)
|
||||||
{
|
{
|
||||||
#if (NGX_DEBUG_EVENT)
|
#if (NGX_DEBUG_EVENT)
|
||||||
ngx_connection_t *c = (ngx_connection_t *) ev->data;
|
ngx_connection_t *c = (ngx_connection_t *) ev->data;
|
||||||
@ -159,8 +159,9 @@ int ngx_kqueue_del_event(ngx_event_t *ev, int event, u_int flags)
|
|||||||
return NGX_OK;
|
return NGX_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* when a socket is closed kqueue automatically deletes its filters
|
/* when the file descriptor is closed a kqueue automatically deletes
|
||||||
so we do not need to delete a event explicity before a socket closing */
|
its filters so we do not need to delete explicity the event
|
||||||
|
before the closing the file descriptor */
|
||||||
|
|
||||||
if (flags & NGX_CLOSE_EVENT) {
|
if (flags & NGX_CLOSE_EVENT) {
|
||||||
return NGX_OK;
|
return NGX_OK;
|
||||||
@ -200,7 +201,7 @@ int ngx_kqueue_set_event(ngx_event_t *ev, int filter, u_int flags)
|
|||||||
change_list[nchanges].ident = c->fd;
|
change_list[nchanges].ident = c->fd;
|
||||||
change_list[nchanges].filter = filter;
|
change_list[nchanges].filter = filter;
|
||||||
change_list[nchanges].flags = flags;
|
change_list[nchanges].flags = flags;
|
||||||
change_list[nchanges].udata = ev;
|
change_list[nchanges].udata = (void *) ((uintptr_t) ev | ev->instance);
|
||||||
|
|
||||||
#if (HAVE_LOWAT_EVENT)
|
#if (HAVE_LOWAT_EVENT)
|
||||||
|
|
||||||
@ -230,7 +231,7 @@ int ngx_kqueue_set_event(ngx_event_t *ev, int filter, u_int flags)
|
|||||||
|
|
||||||
int ngx_kqueue_process_events(ngx_log_t *log)
|
int ngx_kqueue_process_events(ngx_log_t *log)
|
||||||
{
|
{
|
||||||
int events, i;
|
int events, instance, i;
|
||||||
ngx_msec_t timer, delta;
|
ngx_msec_t timer, delta;
|
||||||
ngx_event_t *ev;
|
ngx_event_t *ev;
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
@ -310,12 +311,15 @@ int ngx_kqueue_process_events(ngx_log_t *log)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ev = (ngx_event_t *) event_list[i].udata;
|
ev = (ngx_event_t *) event_list[i].udata;
|
||||||
|
instance = (uintptr_t) ev & 1;
|
||||||
|
ev = (void *) ((uintptr_t) ev & ~1);
|
||||||
|
|
||||||
/* It's a stale event from a socket
|
/* It's a stale event from a file descriptor
|
||||||
that was just closed in this iteration */
|
that was just closed in this iteration */
|
||||||
|
|
||||||
if (!ev->active) {
|
if (ev->active == 0 || ev->instance != instance) {
|
||||||
continue;
|
ngx_log_debug(log, "stale kevent");
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (event_list[i].filter) {
|
switch (event_list[i].filter) {
|
||||||
@ -323,28 +327,6 @@ int ngx_kqueue_process_events(ngx_log_t *log)
|
|||||||
case EVFILT_READ:
|
case EVFILT_READ:
|
||||||
case EVFILT_WRITE:
|
case EVFILT_WRITE:
|
||||||
|
|
||||||
if (ev->first) {
|
|
||||||
if (nchanges > 0
|
|
||||||
&& ev->index < nchanges
|
|
||||||
&& change_list[ev->index].udata == ev) {
|
|
||||||
|
|
||||||
/* It's a stale event from a socket that was just closed
|
|
||||||
in this iteration and during processing another socket
|
|
||||||
was opened with the same number by accept() or socket()
|
|
||||||
and its event has been added the event to the change_list
|
|
||||||
but has not been passed to a kernel. Nevertheless
|
|
||||||
there's small chance that ngx_kqueue_set_event() has
|
|
||||||
flushed the new event if the change_list was filled up.
|
|
||||||
In this very rare case we would get EAGAIN while
|
|
||||||
a reading or a writing */
|
|
||||||
|
|
||||||
continue;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
ev->first = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ev->available = event_list[i].data;
|
ev->available = event_list[i].data;
|
||||||
|
|
||||||
if (event_list[i].flags & EV_EOF) {
|
if (event_list[i].flags & EV_EOF) {
|
||||||
|
@ -63,7 +63,9 @@ struct ngx_event_s {
|
|||||||
#endif
|
#endif
|
||||||
unsigned write:1;
|
unsigned write:1;
|
||||||
|
|
||||||
unsigned first:1;
|
unsigned instance:1; /* used to detect stale events in kqueue,
|
||||||
|
rt signals and epoll */
|
||||||
|
|
||||||
unsigned active:1;
|
unsigned active:1;
|
||||||
unsigned ready:1;
|
unsigned ready:1;
|
||||||
unsigned timedout:1;
|
unsigned timedout:1;
|
||||||
@ -114,6 +116,7 @@ struct ngx_event_s {
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
NGX_SELECT_EVENT_N = 0,
|
NGX_SELECT_EVENT_N = 0,
|
||||||
#if (HAVE_POLL)
|
#if (HAVE_POLL)
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
int ngx_event_accept(ngx_event_t *ev)
|
int ngx_event_accept(ngx_event_t *ev)
|
||||||
{
|
{
|
||||||
|
int instance;
|
||||||
socklen_t len;
|
socklen_t len;
|
||||||
struct sockaddr *sa;
|
struct sockaddr *sa;
|
||||||
ngx_err_t err;
|
ngx_err_t err;
|
||||||
@ -95,6 +96,8 @@ int ngx_event_accept(ngx_event_t *ev)
|
|||||||
wev = &ngx_write_events[s];
|
wev = &ngx_write_events[s];
|
||||||
c = &ngx_connections[s];
|
c = &ngx_connections[s];
|
||||||
|
|
||||||
|
instance = rev->instance;
|
||||||
|
|
||||||
ngx_memzero(rev, sizeof(ngx_event_t));
|
ngx_memzero(rev, sizeof(ngx_event_t));
|
||||||
ngx_memzero(wev, sizeof(ngx_event_t));
|
ngx_memzero(wev, sizeof(ngx_event_t));
|
||||||
ngx_memzero(c, sizeof(ngx_connection_t));
|
ngx_memzero(c, sizeof(ngx_connection_t));
|
||||||
@ -108,6 +111,8 @@ int ngx_event_accept(ngx_event_t *ev)
|
|||||||
c->addr_text_max_len = ls->addr_text_max_len;
|
c->addr_text_max_len = ls->addr_text_max_len;
|
||||||
c->post_accept_timeout = ls->post_accept_timeout;
|
c->post_accept_timeout = ls->post_accept_timeout;
|
||||||
|
|
||||||
|
rev->instance = wev->instance = !instance;
|
||||||
|
|
||||||
rev->index = wev->index = NGX_INVALID_INDEX;
|
rev->index = wev->index = NGX_INVALID_INDEX;
|
||||||
|
|
||||||
rev->data = wev->data = c;
|
rev->data = wev->data = c;
|
||||||
@ -117,7 +122,6 @@ int ngx_event_accept(ngx_event_t *ev)
|
|||||||
c->fd = s;
|
c->fd = s;
|
||||||
c->unexpected_eof = 1;
|
c->unexpected_eof = 1;
|
||||||
wev->write = 1;
|
wev->write = 1;
|
||||||
rev->first = wev->first = 1;
|
|
||||||
|
|
||||||
#if (USE_KQUEUE)
|
#if (USE_KQUEUE)
|
||||||
wev->ready = 1;
|
wev->ready = 1;
|
||||||
|
126
src/event/ngx_event_connect.c
Normal file
126
src/event/ngx_event_connect.c
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
|
||||||
|
#include <ngx_event_connect.h>
|
||||||
|
|
||||||
|
|
||||||
|
int ngx_event_connect_peer(ngx_connect_peer_t *cp)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
if (cp->peers->number > 1) {
|
||||||
|
|
||||||
|
/* it's a first try - get current peer */
|
||||||
|
|
||||||
|
if (cp->tries == cp->peers->number) {
|
||||||
|
|
||||||
|
/* Here is the race condition
|
||||||
|
when the peers are shared between
|
||||||
|
the threads or the processes but it should not be serious */
|
||||||
|
|
||||||
|
cp->cur_peer = cp->peers->current++;
|
||||||
|
|
||||||
|
if (cp->peers->current >= cp->peers->number) {
|
||||||
|
cp->peers->current = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
|
||||||
|
#if (NGX_MULTITHREADED || NGX_MULTIPROCESSED)
|
||||||
|
/* eliminate the sequences of the race condition */
|
||||||
|
if (cp->cur_peer >= cp->peers->number) {
|
||||||
|
cp->cur_peer = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cp->peers->max_fails > 0) {
|
||||||
|
|
||||||
|
for ( ;; ) {
|
||||||
|
peer = &cp->peers->peers[cp->cur_peer];
|
||||||
|
|
||||||
|
/* Here is the race condition
|
||||||
|
when the peers are shared between
|
||||||
|
the threads or the processes but it should not be serious */
|
||||||
|
|
||||||
|
if (peer->fails <= cp->peers->max_fails
|
||||||
|
|| (now - peer->accessed > cp->peers->fail_timeout))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
|
||||||
|
cp->cur_peer++;
|
||||||
|
|
||||||
|
if (cp->cur_peer >= cp->peers->number) {
|
||||||
|
cp->cur_peer = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
cp->tries--;
|
||||||
|
|
||||||
|
if (cp->tries == 0) {
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
s = ngx_socket(AF_INET, SOCK_STREAM, IPPROTO_IP, 0);
|
||||||
|
|
||||||
|
if (s == -1) {
|
||||||
|
ngx_log_error(NGX_LOG_ALERT, cn->log, ngx_socket_errno,
|
||||||
|
ngx_socket_n " failed");
|
||||||
|
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cn->rcvbuf) {
|
||||||
|
if (setsockopt(s, SOL_SOCKET, SO_RCVBUF,
|
||||||
|
(const void *) &cn->rcvbuf, sizeof(int)) == -1) {
|
||||||
|
ngx_log_error(NGX_LOG_ALERT, cn->log, ngx_socket_errno,
|
||||||
|
"setsockopt(SO_RCVBUF) failed");
|
||||||
|
|
||||||
|
if (ngx_close_socket(s) == -1) {
|
||||||
|
ngx_log_error(NGX_LOG_ALERT, cn->log, ngx_socket_errno,
|
||||||
|
ngx_close_socket_n " failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ngx_nonblocking(s) == -1) {
|
||||||
|
ngx_log_error(NGX_LOG_ALERT, cn->log, ngx_socket_errno,
|
||||||
|
ngx_nonblocking_n " failed");
|
||||||
|
|
||||||
|
if (ngx_close_socket(s) == -1) {
|
||||||
|
ngx_log_error(NGX_LOG_ALERT, cn->log, ngx_socket_errno,
|
||||||
|
ngx_close_socket_n " failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
c = &ngx_connections[s];
|
||||||
|
rev = &ngx_read_events[s];
|
||||||
|
wev = &ngx_write_events[s];
|
||||||
|
|
||||||
|
instance = rev->instance;
|
||||||
|
|
||||||
|
ngx_memzero(c, sizeof(ngx_connection_t));
|
||||||
|
ngx_memzero(rev, sizeof(ngx_event_t));
|
||||||
|
ngx_memzero(wev, sizeof(ngx_event_t));
|
||||||
|
|
||||||
|
rev->index = wev->index = NGX_INVALID_INDEX;
|
||||||
|
rev->data = wev->data = c;
|
||||||
|
c->read = rev;
|
||||||
|
c->write = wev;
|
||||||
|
|
||||||
|
rev->instance = wev->instance = !instance;
|
||||||
|
|
||||||
|
rev->log = wev->log = c->log = cn->log;
|
||||||
|
c->fd = s;
|
||||||
|
wev->close_handler = rev->close_handler = ngx_event_close_connection;
|
||||||
|
|
43
src/event/ngx_event_connect.h
Normal file
43
src/event/ngx_event_connect.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#ifndef _NGX_EVENT_CONNECT_H_INCLUDED_
|
||||||
|
#define _NGX_EVENT_CONNECT_H_INCLUDED_
|
||||||
|
|
||||||
|
|
||||||
|
#include <ngx_config.h>
|
||||||
|
#include <ngx_string.h>
|
||||||
|
#include <ngx_log.h>
|
||||||
|
#include <ngx_event.h>
|
||||||
|
#include <ngx_connection.h>
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
u_int32_t addr;
|
||||||
|
ngx_str_t host;
|
||||||
|
int port;
|
||||||
|
ngx_str_t addr_port_name;
|
||||||
|
|
||||||
|
int fails;
|
||||||
|
time_t accessed;
|
||||||
|
} ngx_peer_t;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int current;
|
||||||
|
int number;
|
||||||
|
int max_fails;
|
||||||
|
int fail_timeout;
|
||||||
|
|
||||||
|
/* ngx_mutex_t *mutex; */
|
||||||
|
/* ngx_connection_t *cached; */
|
||||||
|
|
||||||
|
ngx_peer_t peers[1];
|
||||||
|
} ngx_peers_t;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
ngx_peers_t *peers;
|
||||||
|
int cur_peer;
|
||||||
|
int tries;
|
||||||
|
} ngx_connect_peer_t;
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* _NGX_EVENT_CONNECT_H_INCLUDED_ */
|
@ -45,7 +45,8 @@ void ngx_event_add_timer(ngx_event_t *ev, ngx_msec_t timer)
|
|||||||
|
|
||||||
#if (NGX_DEBUG_EVENT)
|
#if (NGX_DEBUG_EVENT)
|
||||||
ngx_connection_t *c = (ngx_connection_t *) ev->data;
|
ngx_connection_t *c = (ngx_connection_t *) ev->data;
|
||||||
ngx_log_debug(ev->log, "set timer: %d:%d" _ c->fd _ timer);
|
ngx_log_debug(ev->log, "set timer: %d:%d, slot: %d" _
|
||||||
|
c->fd _ timer _ ngx_timer_cur_queue);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (ev->timer_next || ev->timer_prev) {
|
if (ev->timer_next || ev->timer_prev) {
|
||||||
@ -53,10 +54,6 @@ void ngx_event_add_timer(ngx_event_t *ev, ngx_msec_t timer)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if (NGX_DEBUG_EVENT)
|
|
||||||
ngx_log_debug(ev->log, "timer slot: %d" _ ngx_timer_cur_queue);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for (e = ngx_timer_queue[ngx_timer_cur_queue].timer_next;
|
for (e = ngx_timer_queue[ngx_timer_cur_queue].timer_next;
|
||||||
e != &ngx_timer_queue[ngx_timer_cur_queue] && timer > e->timer_delta;
|
e != &ngx_timer_queue[ngx_timer_cur_queue] && timer > e->timer_delta;
|
||||||
e = e->timer_next)
|
e = e->timer_next)
|
||||||
|
@ -481,7 +481,7 @@ static int ngx_http_proxy_process_upstream(ngx_http_proxy_ctx_t *p,
|
|||||||
|
|
||||||
static int ngx_http_proxy_connect(ngx_http_proxy_ctx_t *p)
|
static int ngx_http_proxy_connect(ngx_http_proxy_ctx_t *p)
|
||||||
{
|
{
|
||||||
int rc, event;
|
int rc, event, instance;
|
||||||
struct sockaddr_in *addr;
|
struct sockaddr_in *addr;
|
||||||
ngx_err_t err;
|
ngx_err_t err;
|
||||||
ngx_socket_t s;
|
ngx_socket_t s;
|
||||||
@ -590,6 +590,8 @@ static int ngx_http_proxy_connect(ngx_http_proxy_ctx_t *p)
|
|||||||
rev = &ngx_read_events[s];
|
rev = &ngx_read_events[s];
|
||||||
wev = &ngx_write_events[s];
|
wev = &ngx_write_events[s];
|
||||||
|
|
||||||
|
instance = rev->instance;
|
||||||
|
|
||||||
ngx_memzero(c, sizeof(ngx_connection_t));
|
ngx_memzero(c, sizeof(ngx_connection_t));
|
||||||
ngx_memzero(rev, sizeof(ngx_event_t));
|
ngx_memzero(rev, sizeof(ngx_event_t));
|
||||||
ngx_memzero(wev, sizeof(ngx_event_t));
|
ngx_memzero(wev, sizeof(ngx_event_t));
|
||||||
@ -598,7 +600,9 @@ static int ngx_http_proxy_connect(ngx_http_proxy_ctx_t *p)
|
|||||||
rev->data = wev->data = c;
|
rev->data = wev->data = c;
|
||||||
c->read = rev;
|
c->read = rev;
|
||||||
c->write = wev;
|
c->write = wev;
|
||||||
rev->first = wev->first = 1;
|
|
||||||
|
rev->instance = wev->instance = !instance;
|
||||||
|
|
||||||
rev->log = wev->log = c->log = p->log;
|
rev->log = wev->log = c->log = p->log;
|
||||||
c->fd = s;
|
c->fd = s;
|
||||||
wev->close_handler = rev->close_handler = ngx_event_close_connection;
|
wev->close_handler = rev->close_handler = ngx_event_close_connection;
|
||||||
@ -1002,7 +1006,7 @@ static int ngx_http_proxy_process_upstream_headers(ngx_http_proxy_ctx_t *p)
|
|||||||
r = p->request;
|
r = p->request;
|
||||||
|
|
||||||
for ( ;; ) {
|
for ( ;; ) {
|
||||||
rc = ngx_read_http_header_line(r, p->header_in);
|
rc = ngx_parse_http_header_line(r, p->header_in);
|
||||||
|
|
||||||
/* a header line has been parsed successfully */
|
/* a header line has been parsed successfully */
|
||||||
|
|
||||||
|
@ -231,9 +231,9 @@ typedef int (*ngx_http_output_body_filter_p)
|
|||||||
int ngx_http_init(ngx_pool_t *pool, ngx_log_t *log);
|
int ngx_http_init(ngx_pool_t *pool, ngx_log_t *log);
|
||||||
/**/
|
/**/
|
||||||
|
|
||||||
int ngx_http_init_connection(ngx_connection_t *c);
|
void ngx_http_init_connection(ngx_connection_t *c);
|
||||||
int ngx_read_http_request_line(ngx_http_request_t *r);
|
int ngx_parse_http_request_line(ngx_http_request_t *r);
|
||||||
int ngx_read_http_header_line(ngx_http_request_t *r, ngx_hunk_t *h);
|
int ngx_parse_http_header_line(ngx_http_request_t *r, ngx_hunk_t *h);
|
||||||
int ngx_http_handler(ngx_http_request_t *r);
|
int ngx_http_handler(ngx_http_request_t *r);
|
||||||
|
|
||||||
|
|
||||||
|
@ -568,9 +568,9 @@ int ngx_http_close_request(ngx_http_request_t *r, int error)
|
|||||||
c->write->timer_set = 0;
|
c->write->timer_set = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ngx_log_debug(c->log, "http closed");
|
ngx_log_debug(c->log, "http request closed");
|
||||||
|
|
||||||
return NGX_ERROR; /* to close connection */
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -18,10 +18,17 @@
|
|||||||
#include <ngx_http_output_filter.h>
|
#include <ngx_http_output_filter.h>
|
||||||
|
|
||||||
|
|
||||||
static int ngx_http_init_request(ngx_event_t *ev);
|
static void ngx_http_init_request(ngx_event_t *ev);
|
||||||
|
static void ngx_http_process_request_line(ngx_event_t *rev);
|
||||||
|
static void ngx_http_process_request_headers(ngx_event_t *rev);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static ssize_t ngx_http_read_request_header(ngx_http_request_t *r);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static int ngx_http_process_request(ngx_event_t *ev);
|
static int ngx_http_process_request(ngx_event_t *ev);
|
||||||
static int ngx_http_process_request_line(ngx_http_request_t *r);
|
|
||||||
static int ngx_http_process_request_headers(ngx_http_request_t *r);
|
|
||||||
static int ngx_http_process_request_header_line(ngx_http_request_t *r);
|
static int ngx_http_process_request_header_line(ngx_http_request_t *r);
|
||||||
static int ngx_http_request_handler(ngx_http_request_t *r, int error);
|
static int ngx_http_request_handler(ngx_http_request_t *r, int error);
|
||||||
|
|
||||||
@ -33,11 +40,12 @@ static int ngx_http_keepalive_handler(ngx_event_t *ev);
|
|||||||
static int ngx_http_set_lingering_close(ngx_http_request_t *r);
|
static int ngx_http_set_lingering_close(ngx_http_request_t *r);
|
||||||
static int ngx_http_lingering_close_handler(ngx_event_t *ev);
|
static int ngx_http_lingering_close_handler(ngx_event_t *ev);
|
||||||
|
|
||||||
static int ngx_http_close_connection(ngx_event_t *ev);
|
static int ngx_http_close_connection(ngx_connection_t *c);
|
||||||
static void ngx_http_header_parse_error(ngx_http_request_t *r, int parse_err);
|
static void ngx_http_header_parse_error(ngx_http_request_t *r, int parse_err);
|
||||||
static size_t ngx_http_log_error(void *data, char *buf, size_t len);
|
static size_t ngx_http_log_error(void *data, char *buf, size_t len);
|
||||||
|
|
||||||
|
|
||||||
|
/* NGX_HTTP_PARSE_ ... errors */
|
||||||
|
|
||||||
static char *header_errors[] = {
|
static char *header_errors[] = {
|
||||||
"client %s sent invalid method",
|
"client %s sent invalid method",
|
||||||
@ -67,127 +75,142 @@ static ngx_http_header_t headers_in[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
int ngx_http_init_connection(ngx_connection_t *c)
|
void ngx_http_init_connection(ngx_connection_t *c)
|
||||||
{
|
{
|
||||||
|
int event;
|
||||||
ngx_event_t *rev;
|
ngx_event_t *rev;
|
||||||
ngx_http_log_ctx_t *ctx;
|
ngx_http_log_ctx_t *lcx;
|
||||||
|
|
||||||
|
c->addr_text.data = ngx_palloc(c->pool, c->addr_text_max_len);
|
||||||
|
if (c->addr_text.data == NULL) {
|
||||||
|
ngx_http_close_connection(c);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
c->addr_text.len = ngx_sock_ntop(c->family, c->sockaddr,
|
||||||
|
c->addr_text.data, c->addr_text_max_len);
|
||||||
|
if (c->addr_text.len == 0) {
|
||||||
|
ngx_http_close_connection(c);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lcx = ngx_pcalloc(c->pool, sizeof(ngx_http_log_ctx_t));
|
||||||
|
if (lcx == NULL) {
|
||||||
|
ngx_http_close_connection(c);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lcx->client = c->addr_text.data;
|
||||||
|
lcx->action = "reading client request line";
|
||||||
|
c->log->data = lcx;
|
||||||
|
c->log->handler = ngx_http_log_error;
|
||||||
|
|
||||||
rev = c->read;
|
rev = c->read;
|
||||||
rev->event_handler = ngx_http_init_request;
|
rev->event_handler = ngx_http_init_request;
|
||||||
|
|
||||||
rev->close_handler = ngx_http_close_connection;
|
|
||||||
c->write->close_handler = ngx_http_close_connection;
|
|
||||||
|
|
||||||
ngx_test_null(c->addr_text.data, ngx_palloc(c->pool, c->addr_text_max_len),
|
|
||||||
NGX_ERROR);
|
|
||||||
|
|
||||||
c->addr_text.len = ngx_sock_ntop(c->family, c->sockaddr,
|
|
||||||
c->addr_text.data, c->addr_text_max_len);
|
|
||||||
|
|
||||||
if (c->addr_text.len == 0) {
|
|
||||||
return NGX_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
ngx_test_null(ctx, ngx_pcalloc(c->pool, sizeof(ngx_http_log_ctx_t)),
|
|
||||||
NGX_ERROR);
|
|
||||||
ctx->client = c->addr_text.data;
|
|
||||||
ctx->action = "reading client request line";
|
|
||||||
c->log->data = ctx;
|
|
||||||
c->log->handler = ngx_http_log_error;
|
|
||||||
|
|
||||||
#if (HAVE_DEFERRED_ACCEPT)
|
|
||||||
|
|
||||||
if (rev->ready) {
|
if (rev->ready) {
|
||||||
return ngx_http_init_request(rev);
|
/* deferred accept */
|
||||||
|
ngx_http_init_request(rev);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ngx_add_timer(rev, c->post_accept_timeout);
|
ngx_add_timer(rev, c->post_accept_timeout);
|
||||||
rev->timer_set = 1;
|
rev->timer_set = 1;
|
||||||
|
|
||||||
#if (USE_KQUEUE)
|
if (ngx_event_flags & (NGX_HAVE_AIO_EVENT|NGX_HAVE_EDGE_EVENT)) {
|
||||||
|
/* aio, iocp, epoll */
|
||||||
return ngx_add_event(rev, NGX_READ_EVENT, NGX_CLEAR_EVENT);
|
ngx_http_init_request(rev);
|
||||||
|
return;
|
||||||
#else
|
}
|
||||||
|
|
||||||
/* kqueue */
|
|
||||||
|
|
||||||
if (ngx_event_flags & NGX_HAVE_CLEAR_EVENT) {
|
if (ngx_event_flags & NGX_HAVE_CLEAR_EVENT) {
|
||||||
return ngx_add_event(rev, NGX_READ_EVENT, NGX_CLEAR_EVENT);
|
/* kqueue */
|
||||||
|
event = NGX_CLEAR_EVENT;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* select, poll, /dev/poll */
|
||||||
|
event = NGX_LEVEL_EVENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* aio, iocp, epoll */
|
if (ngx_add_event(rev, NGX_READ_EVENT, event) == NGX_ERROR) {
|
||||||
|
ngx_http_close_connection(c);
|
||||||
if (ngx_event_flags & (NGX_HAVE_AIO_EVENT|NGX_HAVE_EDGE_EVENT)) {
|
|
||||||
return ngx_http_init_request(rev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* select, poll, /dev/poll */
|
return;
|
||||||
|
|
||||||
return ngx_add_event(rev, NGX_READ_EVENT, NGX_LEVEL_EVENT);
|
|
||||||
|
|
||||||
#endif /* USE_KQUEUE */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int ngx_http_init_request(ngx_event_t *rev)
|
static void ngx_http_init_request(ngx_event_t *rev)
|
||||||
{
|
{
|
||||||
ngx_connection_t *c;
|
ngx_connection_t *c;
|
||||||
ngx_http_request_t *r;
|
ngx_http_request_t *r;
|
||||||
ngx_http_conf_ctx_t *ctx;
|
ngx_http_conf_ctx_t *ctx;
|
||||||
|
|
||||||
c = (ngx_connection_t *) rev->data;
|
c = (ngx_connection_t *) rev->data;
|
||||||
c->sent = 0;
|
|
||||||
|
|
||||||
ngx_test_null(r, ngx_pcalloc(c->pool, sizeof(ngx_http_request_t)),
|
|
||||||
NGX_ERROR);
|
|
||||||
|
|
||||||
c->data = r;
|
|
||||||
r->connection = c;
|
|
||||||
r->file.fd = NGX_INVALID_FILE;
|
|
||||||
|
|
||||||
if (c->buffer == NULL) {
|
if (c->buffer == NULL) {
|
||||||
ngx_test_null(c->buffer,
|
c->buffer = ngx_create_temp_hunk(c->pool,
|
||||||
ngx_create_temp_hunk(c->pool,
|
ngx_http_client_header_buffer_size,
|
||||||
ngx_http_client_header_buffer_size,
|
0, 0);
|
||||||
0, 0),
|
if (c->buffer == NULL) {
|
||||||
NGX_ERROR);
|
ngx_http_close_connection(c);
|
||||||
} else {
|
return;
|
||||||
r->header_read = 1;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
r->pipeline = c->pipeline;
|
r = ngx_pcalloc(c->pool, sizeof(ngx_http_request_t));
|
||||||
r->header_in = c->buffer;
|
if (r == NULL) {
|
||||||
|
ngx_http_close_connection(c);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ngx_test_null(r->pool, ngx_create_pool(ngx_http_request_pool_size, c->log),
|
r->pool = ngx_create_pool(ngx_http_request_pool_size, c->log);
|
||||||
NGX_ERROR);
|
if (r->pool == NULL) {
|
||||||
|
ngx_http_close_connection(c);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ngx_test_null(r->ctx,
|
r->headers_out.headers = ngx_create_table(r->pool, 10);
|
||||||
ngx_pcalloc(r->pool, sizeof(void *) * ngx_http_max_module),
|
if (r->headers_out.headers == NULL) {
|
||||||
ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR));
|
ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
|
||||||
|
ngx_http_close_connection(c);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
r->ctx = ngx_pcalloc(r->pool, sizeof(void *) * ngx_http_max_module);
|
||||||
|
if (r->ctx == NULL) {
|
||||||
|
ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
|
||||||
|
ngx_http_close_connection(c);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ctx = (ngx_http_conf_ctx_t *) c->ctx;
|
ctx = (ngx_http_conf_ctx_t *) c->ctx;
|
||||||
r->srv_conf = ctx->srv_conf;
|
r->srv_conf = ctx->srv_conf;
|
||||||
r->loc_conf = ctx->loc_conf;
|
r->loc_conf = ctx->loc_conf;
|
||||||
|
|
||||||
|
c->sent = 0;
|
||||||
|
c->data = r;
|
||||||
|
r->connection = c;
|
||||||
|
r->pipeline = c->pipeline;
|
||||||
|
r->header_in = c->buffer;
|
||||||
|
|
||||||
|
r->file.fd = NGX_INVALID_FILE;
|
||||||
|
|
||||||
r->headers_in.content_length_n = -1;
|
r->headers_in.content_length_n = -1;
|
||||||
r->headers_out.headers = ngx_create_table(r->pool, 10);
|
|
||||||
r->headers_out.content_length = -1;
|
r->headers_out.content_length = -1;
|
||||||
r->headers_out.last_modified_time = -1;
|
r->headers_out.last_modified_time = -1;
|
||||||
|
|
||||||
rev->event_handler = ngx_http_process_request;
|
rev->event_handler = ngx_http_process_request_line;
|
||||||
r->state_handler = ngx_http_process_request_line;
|
ngx_http_process_request_line(rev);
|
||||||
|
|
||||||
return ngx_http_process_request(rev);
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int ngx_http_process_request(ngx_event_t *rev)
|
static void ngx_http_process_request_line(ngx_event_t *rev)
|
||||||
{
|
{
|
||||||
int n, rc;
|
int rc, offset;
|
||||||
ngx_event_t *wev;
|
ssize_t n;
|
||||||
ngx_connection_t *c;
|
ngx_connection_t *c;
|
||||||
ngx_http_request_t *r;
|
ngx_http_request_t *r;
|
||||||
ngx_http_log_ctx_t *lcx;
|
ngx_http_log_ctx_t *lcx;
|
||||||
@ -195,139 +218,35 @@ static int ngx_http_process_request(ngx_event_t *rev)
|
|||||||
c = (ngx_connection_t *) rev->data;
|
c = (ngx_connection_t *) rev->data;
|
||||||
r = (ngx_http_request_t *) c->data;
|
r = (ngx_http_request_t *) c->data;
|
||||||
|
|
||||||
ngx_log_debug(c->log, "http process request");
|
ngx_log_debug(rev->log, "http process request line");
|
||||||
|
|
||||||
if (rev->timedout) {
|
if (rev->timedout) {
|
||||||
return ngx_http_close_request(r, NGX_HTTP_REQUEST_TIME_OUT);
|
ngx_http_close_request(r, NGX_HTTP_REQUEST_TIME_OUT);
|
||||||
|
ngx_http_close_connection(c);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
n = ngx_http_read_request_header(r);
|
||||||
|
|
||||||
if (r->header_read) {
|
|
||||||
r->header_read = 0;
|
|
||||||
ngx_log_debug(c->log, "http preread %d" _
|
|
||||||
r->header_in->last - r->header_in->pos);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
n = ngx_event_recv(c, r->header_in->last,
|
|
||||||
r->header_in->end - r->header_in->last);
|
|
||||||
|
|
||||||
if (n == NGX_AGAIN) {
|
|
||||||
if (!r->header_timeout_set) {
|
|
||||||
|
|
||||||
if (rev->timer_set) {
|
|
||||||
ngx_del_timer(rev);
|
|
||||||
} else {
|
|
||||||
rev->timer_set = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ngx_add_timer(rev, ngx_http_client_header_timeout);
|
|
||||||
r->header_timeout_set = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NGX_AGAIN;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (n == NGX_ERROR) {
|
|
||||||
return ngx_http_close_request(r, NGX_HTTP_BAD_REQUEST);
|
|
||||||
}
|
|
||||||
|
|
||||||
ngx_log_debug(c->log, "http read %d" _ n);
|
|
||||||
|
|
||||||
if (n == 0) {
|
|
||||||
ngx_log_error(NGX_LOG_INFO, c->log, 0,
|
|
||||||
"client closed prematurely connection");
|
|
||||||
return ngx_http_close_request(r, NGX_HTTP_BAD_REQUEST);
|
|
||||||
}
|
|
||||||
|
|
||||||
r->header_in->last += n;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* the state handlers are called in the following order:
|
|
||||||
ngx_http_process_request_line(r)
|
|
||||||
ngx_http_process_request_headers(r) */
|
|
||||||
|
|
||||||
do {
|
|
||||||
rc = r->state_handler(r);
|
|
||||||
|
|
||||||
} while (rc == NGX_AGAIN && r->header_in->pos < r->header_in->last);
|
|
||||||
|
|
||||||
} while (rc == NGX_AGAIN
|
|
||||||
&& (rev->ready || ngx_event_flags & NGX_HAVE_AIO_EVENT));
|
|
||||||
|
|
||||||
if (rc >= NGX_OK) {
|
|
||||||
|
|
||||||
/* HTTP header done */
|
|
||||||
|
|
||||||
rev->event_handler = ngx_http_block_read;
|
|
||||||
|
|
||||||
if (rc != NGX_OK) {
|
|
||||||
return ngx_http_finalize_request(r, rc);
|
|
||||||
}
|
|
||||||
|
|
||||||
lcx = c->log->data;
|
|
||||||
lcx->action = "processing client request";
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
wev = c->write;
|
|
||||||
ngx_add_timer(wev, 5000);
|
|
||||||
wev->delayed = 1;
|
|
||||||
wev->timer_set = 1;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
rc = ngx_http_handler(r);
|
|
||||||
|
|
||||||
/* a handler does its own processing */
|
|
||||||
if (rc == NGX_DONE) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rc == NGX_ERROR) {
|
|
||||||
rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ngx_http_finalize_request(r, rc);
|
|
||||||
|
|
||||||
|
if (n == NGX_AGAIN || n == NGX_ERROR) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* NGX_AGAIN */
|
rc = ngx_parse_http_request_line(r);
|
||||||
|
|
||||||
if (!r->header_timeout_set) {
|
|
||||||
|
|
||||||
if (rev->timer_set) {
|
|
||||||
ngx_del_timer(rev);
|
|
||||||
} else {
|
|
||||||
rev->timer_set = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ngx_add_timer(rev, ngx_http_client_header_timeout);
|
|
||||||
r->header_timeout_set = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int ngx_http_process_request_line(ngx_http_request_t *r)
|
|
||||||
{
|
|
||||||
int rc, offset;
|
|
||||||
ngx_connection_t *c;
|
|
||||||
ngx_http_log_ctx_t *lcx;
|
|
||||||
|
|
||||||
rc = ngx_read_http_request_line(r);
|
|
||||||
|
|
||||||
c = r->connection;
|
|
||||||
|
|
||||||
/* a request line has been parsed successfully */
|
|
||||||
|
|
||||||
if (rc == NGX_OK) {
|
if (rc == NGX_OK) {
|
||||||
|
|
||||||
|
/* the request line has been parsed successfully */
|
||||||
|
|
||||||
if (r->http_version >= NGX_HTTP_VERSION_10
|
if (r->http_version >= NGX_HTTP_VERSION_10
|
||||||
&& ngx_http_large_client_header == 0
|
&& ngx_http_large_client_header == 0
|
||||||
&& r->header_in->pos == r->header_in->end)
|
&& r->header_in->pos == r->header_in->end)
|
||||||
{
|
{
|
||||||
|
/* no space for "\r\n" at the end of the header */
|
||||||
|
|
||||||
ngx_http_header_parse_error(r, NGX_HTTP_PARSE_TOO_LONG_URI);
|
ngx_http_header_parse_error(r, NGX_HTTP_PARSE_TOO_LONG_URI);
|
||||||
return NGX_HTTP_REQUEST_URI_TOO_LARGE;
|
ngx_http_finalize_request(r, NGX_HTTP_REQUEST_URI_TOO_LARGE);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* copy URI */
|
/* copy URI */
|
||||||
@ -338,20 +257,28 @@ static int ngx_http_process_request_line(ngx_http_request_t *r)
|
|||||||
r->uri.len = r->uri_end - r->uri_start;
|
r->uri.len = r->uri_end - r->uri_start;
|
||||||
}
|
}
|
||||||
|
|
||||||
ngx_test_null(r->uri.data, ngx_palloc(r->pool, r->uri.len + 1),
|
r->uri.data = ngx_palloc(r->pool, r->uri.len + 1);
|
||||||
NGX_HTTP_INTERNAL_SERVER_ERROR);
|
if (r->uri.data == NULL) {
|
||||||
|
ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
|
||||||
|
ngx_http_close_connection(c);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ngx_cpystrn(r->uri.data, r->uri_start, r->uri.len + 1);
|
ngx_cpystrn(r->uri.data, r->uri_start, r->uri.len + 1);
|
||||||
|
|
||||||
r->request_line.len = r->request_end - r->request_start;
|
r->request_line.len = r->request_end - r->request_start;
|
||||||
|
|
||||||
/* if the large client headers are enabled then
|
/* if the large client header is enabled then
|
||||||
we need to copy a request line */
|
we need to copy a request line */
|
||||||
|
|
||||||
if (ngx_http_large_client_header) {
|
if (ngx_http_large_client_header) {
|
||||||
ngx_test_null(r->request_line.data,
|
|
||||||
ngx_palloc(r->pool, r->request_line.len + 1),
|
r->request_line.data = ngx_palloc(r->pool, r->request_line.len + 1);
|
||||||
NGX_HTTP_INTERNAL_SERVER_ERROR);
|
if (r->request_line.data == NULL) {
|
||||||
|
ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
|
||||||
|
ngx_http_close_connection(c);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ngx_cpystrn(r->request_line.data, r->request_start,
|
ngx_cpystrn(r->request_line.data, r->request_start,
|
||||||
r->request_line.len + 1);
|
r->request_line.len + 1);
|
||||||
@ -370,9 +297,12 @@ static int ngx_http_process_request_line(ngx_http_request_t *r)
|
|||||||
r->exten.len = r->uri_end - r->uri_ext;
|
r->exten.len = r->uri_end - r->uri_ext;
|
||||||
}
|
}
|
||||||
|
|
||||||
ngx_test_null(r->exten.data,
|
r->exten.data = ngx_palloc(r->pool, r->exten.len + 1);
|
||||||
ngx_palloc(r->pool, r->exten.len + 1),
|
if (r->exten.data == NULL) {
|
||||||
NGX_HTTP_INTERNAL_SERVER_ERROR);
|
ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
|
||||||
|
ngx_http_close_connection(c);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ngx_cpystrn(r->exten.data, r->uri_ext, r->exten.len + 1);
|
ngx_cpystrn(r->exten.data, r->uri_ext, r->exten.len + 1);
|
||||||
}
|
}
|
||||||
@ -382,53 +312,45 @@ static int ngx_http_process_request_line(ngx_http_request_t *r)
|
|||||||
if (r->args_start && r->uri_end > r->args_start) {
|
if (r->args_start && r->uri_end > r->args_start) {
|
||||||
r->args.len = r->uri_end - r->args_start;
|
r->args.len = r->uri_end - r->args_start;
|
||||||
|
|
||||||
ngx_test_null(r->args.data,
|
r->args.data = ngx_palloc(r->pool, r->args.len + 1);
|
||||||
ngx_palloc(r->pool, r->args.len + 1),
|
if (r->args.data == NULL) {
|
||||||
NGX_HTTP_INTERNAL_SERVER_ERROR);
|
ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
|
||||||
|
ngx_http_close_connection(c);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ngx_cpystrn(r->args.data, r->args_start, r->args.len + 1);
|
ngx_cpystrn(r->args.data, r->args_start, r->args.len + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 1
|
#if 1 /* DEBUG */
|
||||||
if (r->exten.data == NULL) {
|
if (r->exten.data == NULL) { r->exten.data = ""; }
|
||||||
r->exten.data = "";
|
if (r->args.data == NULL) { r->args.data = ""; }
|
||||||
}
|
ngx_log_debug(c->log, "HTTP: %d, %d, '%s', '%s', '%s'" _
|
||||||
if (r->args.data == NULL) {
|
|
||||||
r->args.data = "";
|
|
||||||
}
|
|
||||||
ngx_log_debug(r->connection->log, "HTTP: %d, %d, '%s', '%s', '%s'" _
|
|
||||||
r->method _ r->http_version _
|
r->method _ r->http_version _
|
||||||
r->uri.data _ r->exten.data _ r->args.data);
|
r->uri.data _ r->exten.data _ r->args.data);
|
||||||
if (r->exten.data[0] == '\0') {
|
if (r->exten.data[0] == '\0') { r->exten.data = NULL; }
|
||||||
r->exten.data = NULL;
|
if (r->args.data[0] == '\0') { r->args.data = NULL; }
|
||||||
}
|
|
||||||
if (r->args.data[0] == '\0') {
|
|
||||||
r->args.data = NULL;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
lcx = r->connection->log->data;
|
lcx = c->log->data;
|
||||||
|
|
||||||
if (ngx_http_url_in_error_log) {
|
if (ngx_http_url_in_error_log) {
|
||||||
ngx_test_null(lcx->url,
|
lcx->url = ngx_palloc(r->pool, r->uri_end - r->uri_start + 1);
|
||||||
ngx_palloc(r->pool, r->uri_end - r->uri_start + 1),
|
if (lcx->url == NULL) {
|
||||||
NGX_HTTP_INTERNAL_SERVER_ERROR);
|
ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
|
||||||
|
ngx_http_close_connection(c);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ngx_cpystrn(lcx->url, r->uri_start, r->uri_end - r->uri_start + 1);
|
ngx_cpystrn(lcx->url, r->uri_start, r->uri_end - r->uri_start + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if we need to parse the headers then return NGX_AGAIN
|
|
||||||
becuase of HTTP/0.9 has no headers so return NGX_OK */
|
|
||||||
|
|
||||||
if (r->http_version == NGX_HTTP_VERSION_9) {
|
if (r->http_version == NGX_HTTP_VERSION_9) {
|
||||||
r->state_handler = NULL;
|
/* STUB */ return;
|
||||||
return NGX_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
r->headers_in.headers = ngx_create_table(r->pool, 10);
|
|
||||||
|
|
||||||
r->state_handler = ngx_http_process_request_headers;
|
|
||||||
lcx->action = "reading client request headers";
|
lcx->action = "reading client request headers";
|
||||||
|
r->headers_in.headers = ngx_create_table(r->pool, 10);
|
||||||
|
|
||||||
if (ngx_http_large_client_header
|
if (ngx_http_large_client_header
|
||||||
&& r->header_in->pos == r->header_in->last)
|
&& r->header_in->pos == r->header_in->last)
|
||||||
@ -436,13 +358,13 @@ static int ngx_http_process_request_line(ngx_http_request_t *r)
|
|||||||
r->header_in->pos = r->header_in->last = r->header_in->start;
|
r->header_in->pos = r->header_in->last = r->header_in->start;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NGX_AGAIN;
|
|
||||||
|
|
||||||
/* there was error while a request line parsing */
|
|
||||||
|
|
||||||
} else if (rc != NGX_AGAIN) {
|
} else if (rc != NGX_AGAIN) {
|
||||||
|
|
||||||
|
/* there was error while a request line parsing */
|
||||||
|
|
||||||
ngx_http_header_parse_error(r, rc);
|
ngx_http_header_parse_error(r, rc);
|
||||||
return NGX_HTTP_BAD_REQUEST;
|
ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* NGX_AGAIN: a request line parsing is still not complete */
|
/* NGX_AGAIN: a request line parsing is still not complete */
|
||||||
@ -450,17 +372,18 @@ static int ngx_http_process_request_line(ngx_http_request_t *r)
|
|||||||
if (r->header_in->last == r->header_in->end) {
|
if (r->header_in->last == r->header_in->end) {
|
||||||
|
|
||||||
/* If it's a pipelined request and a request line is not complete
|
/* If it's a pipelined request and a request line is not complete
|
||||||
then we need to copy it to the start of r->header_in hunk.
|
then we need to copy it to the start of the r->header_in hunk.
|
||||||
We need to copy it here only if the large client headers
|
We need to copy it here only if the large client headers
|
||||||
are enabled otherwise a request line had been already copied
|
are enabled otherwise a request line had been already copied
|
||||||
to the start of r->header_in hunk in ngx_http_set_keepalive() */
|
to the start of the r->header_in hunk in ngx_http_set_keepalive() */
|
||||||
|
|
||||||
if (ngx_http_large_client_header) {
|
if (ngx_http_large_client_header) {
|
||||||
offset = r->request_start - r->header_in->start;
|
offset = r->request_start - r->header_in->start;
|
||||||
|
|
||||||
if (offset == 0) {
|
if (offset == 0) {
|
||||||
ngx_http_header_parse_error(r, NGX_HTTP_PARSE_TOO_LONG_URI);
|
ngx_http_header_parse_error(r, NGX_HTTP_PARSE_TOO_LONG_URI);
|
||||||
return NGX_HTTP_REQUEST_URI_TOO_LARGE;
|
ngx_http_finalize_request(r, NGX_HTTP_REQUEST_URI_TOO_LARGE);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ngx_memcpy(r->header_in->start, r->request_start,
|
ngx_memcpy(r->header_in->start, r->request_start,
|
||||||
@ -481,22 +404,41 @@ static int ngx_http_process_request_line(ngx_http_request_t *r)
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
ngx_http_header_parse_error(r, NGX_HTTP_PARSE_TOO_LONG_URI);
|
ngx_http_header_parse_error(r, NGX_HTTP_PARSE_TOO_LONG_URI);
|
||||||
return NGX_HTTP_REQUEST_URI_TOO_LARGE;
|
ngx_http_finalize_request(r, NGX_HTTP_REQUEST_URI_TOO_LARGE);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return NGX_AGAIN;
|
rev->event_handler = ngx_http_process_request_headers;
|
||||||
|
ngx_http_process_request_headers(rev);
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int ngx_http_process_request_headers(ngx_http_request_t *r)
|
static void ngx_http_process_request_headers(ngx_event_t *rev)
|
||||||
{
|
{
|
||||||
int rc, offset;
|
int rc, offset;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
ssize_t n;
|
||||||
|
ngx_connection_t *c;
|
||||||
|
ngx_http_request_t *r;
|
||||||
ngx_http_log_ctx_t *ctx;
|
ngx_http_log_ctx_t *ctx;
|
||||||
|
|
||||||
|
if (rev->timedout) {
|
||||||
|
ngx_http_close_request(r, NGX_HTTP_REQUEST_TIME_OUT);
|
||||||
|
ngx_http_close_connection(c);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
n = ngx_http_read_request_header(r);
|
||||||
|
|
||||||
|
if (n == NGX_AGAIN || n == NGX_ERROR) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for ( ;; ) {
|
for ( ;; ) {
|
||||||
rc = ngx_read_http_header_line(r, r->header_in);
|
rc = ngx_parse_http_header_line(r, r->header_in);
|
||||||
|
|
||||||
/* a header line has been parsed successfully */
|
/* a header line has been parsed successfully */
|
||||||
|
|
||||||
@ -792,6 +734,53 @@ static int ngx_http_writer(ngx_event_t *wev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static ssize_t ngx_http_read_request_header(ngx_http_request_t *r)
|
||||||
|
{
|
||||||
|
ssize_t n;
|
||||||
|
ngx_event_t *rev;
|
||||||
|
|
||||||
|
n = r->header_in->last - r->header_in->pos;
|
||||||
|
|
||||||
|
if (n > 0) {
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
n = ngx_event_recv(r->connection, r->header_in->last,
|
||||||
|
r->header_in->end - r->header_in->last);
|
||||||
|
|
||||||
|
if (n == NGX_AGAIN) {
|
||||||
|
if (!r->header_timeout_set) {
|
||||||
|
rev = r->connection->read;
|
||||||
|
|
||||||
|
if (rev->timer_set) {
|
||||||
|
ngx_del_timer(rev);
|
||||||
|
} else {
|
||||||
|
rev->timer_set = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngx_add_timer(rev, ngx_http_client_header_timeout);
|
||||||
|
r->header_timeout_set = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NGX_AGAIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n == 0) {
|
||||||
|
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
|
||||||
|
"client closed prematurely connection");
|
||||||
|
|
||||||
|
if (n == 0 || n == NGX_ERROR) {
|
||||||
|
ngx_http_close_request(r, NGX_HTTP_BAD_REQUEST);
|
||||||
|
ngx_http_close_connection(c);
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
r->header_in->last += n;
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int ngx_http_block_read(ngx_event_t *ev)
|
static int ngx_http_block_read(ngx_event_t *ev)
|
||||||
{
|
{
|
||||||
ngx_log_debug(ev->log, "http read blocked");
|
ngx_log_debug(ev->log, "http read blocked");
|
||||||
@ -1144,7 +1133,46 @@ static int ngx_http_lingering_close_handler(ngx_event_t *rev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int ngx_http_close_connection(ngx_event_t *ev)
|
static void ngx_http_close_connection(ngx_connection_t *c)
|
||||||
|
{
|
||||||
|
ngx_log_debug(c->log, "close connection: %d" _ c->fd);
|
||||||
|
|
||||||
|
if (c->fd == -1) {
|
||||||
|
ngx_log_error(NGX_LOG_ALERT, c->log, 0, "connection already closed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c->read->timer_set) {
|
||||||
|
ngx_del_timer(c->read);
|
||||||
|
c->read->timer_set = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c->read->active) {
|
||||||
|
ngx_del_event(c->read, NGX_READ_EVENT, NGX_CLOSE_EVENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c->write->timer_set) {
|
||||||
|
ngx_del_timer(c->write);
|
||||||
|
c->write->timer_set = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c->write->active) {
|
||||||
|
ngx_del_event(c->write, NGX_WRITE_EVENT, NGX_CLOSE_EVENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ngx_close_socket(c->fd) == -1) {
|
||||||
|
ngx_log_error(NGX_LOG_ALERT, c->log, ngx_socket_errno,
|
||||||
|
ngx_close_socket_n " failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
c->fd = -1;
|
||||||
|
|
||||||
|
ngx_destroy_pool(c->pool);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ngx_http_close_connection0(ngx_event_t *ev)
|
||||||
{
|
{
|
||||||
return ngx_event_close_connection(ev);
|
return ngx_event_close_connection(ev);
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
#include <ngx_core.h>
|
#include <ngx_core.h>
|
||||||
#include <ngx_http.h>
|
#include <ngx_http.h>
|
||||||
|
|
||||||
int ngx_read_http_request_line(ngx_http_request_t *r)
|
int ngx_parse_http_request_line(ngx_http_request_t *r)
|
||||||
{
|
{
|
||||||
char ch;
|
char ch;
|
||||||
char *p;
|
char *p;
|
||||||
@ -326,7 +326,7 @@ int ngx_read_http_request_line(ngx_http_request_t *r)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int ngx_read_http_header_line(ngx_http_request_t *r, ngx_hunk_t *h)
|
int ngx_parse_http_header_line(ngx_http_request_t *r, ngx_hunk_t *h)
|
||||||
{
|
{
|
||||||
char c, ch;
|
char c, ch;
|
||||||
char *p;
|
char *p;
|
||||||
|
80
src/os/unix/ngx_daemon.c
Normal file
80
src/os/unix/ngx_daemon.c
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
|
||||||
|
#include <ngx_config.h>
|
||||||
|
#include <ngx_core.h>
|
||||||
|
#include <ngx_log.h>
|
||||||
|
|
||||||
|
/* daemon in Linux */
|
||||||
|
|
||||||
|
int ngx_daemon(ngx_log_t *log)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
switch (fork()) {
|
||||||
|
case -1:
|
||||||
|
ngx_log_error(NGX_LOG_ALERT, log, errno, "fork() failed");
|
||||||
|
return NGX_ERROR;
|
||||||
|
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setsid() == -1) {
|
||||||
|
ngx_log_error(NGX_LOG_ALERT, log, errno, "setsid() failed");
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if (__SVR4 || linux)
|
||||||
|
|
||||||
|
/* need HUP IGN ? check in Solaris and Linux */
|
||||||
|
|
||||||
|
switch (fork()) {
|
||||||
|
case -1:
|
||||||
|
ngx_log_error(NGX_LOG_ALERT, log, errno, "fork() failed");
|
||||||
|
return NGX_ERROR;
|
||||||
|
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
umask(0);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
fd = open("/dev/null", O_RDWR);
|
||||||
|
if (fd == -1) {
|
||||||
|
ngx_log_error(NGX_LOG_ALERT, log, errno, "open(\"/dev/null\") failed");
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dup2(fd, STDIN_FILENO) == -1) {
|
||||||
|
ngx_log_error(NGX_LOG_ALERT, log, errno, "dup2(STDIN) failed");
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dup2(fd, STDOUT_FILENO) == -1) {
|
||||||
|
ngx_log_error(NGX_LOG_ALERT, log, errno, "dup2(STDOUT) failed");
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dup2(fd, STDERR_FILENO) == -1) {
|
||||||
|
ngx_log_error(NGX_LOG_ALERT, log, errno, "dup2(STDERR) failed");
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fd > STDERR_FILENO) {
|
||||||
|
if (close(fd) == -1) {
|
||||||
|
ngx_log_error(NGX_LOG_ALERT, log, errno, "close() failed");
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return NGX_OK;
|
||||||
|
}
|
67
src/os/unix/ngx_freebsd_init.c
Normal file
67
src/os/unix/ngx_freebsd_init.c
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
|
||||||
|
#include <ngx_freebsd_init.h>
|
||||||
|
|
||||||
|
|
||||||
|
int freebsd_kern_osreldate;
|
||||||
|
int freebsd_hw_ncpu;
|
||||||
|
|
||||||
|
int freebsd_sendfile_nbytes_bug;
|
||||||
|
|
||||||
|
|
||||||
|
int ngx_os_init(ngx_log_t *log)
|
||||||
|
{
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
size = 4;
|
||||||
|
if (sysctlbyname("kern.osreldate",
|
||||||
|
&freebsd_kern_osreldate, &size, NULL, 0) == -1) {
|
||||||
|
ngx_log_error(NGX_LOG_ALERT, log, errno,
|
||||||
|
"sysctlbyname(kern.osreldate) failed");
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngx_log_error(NGX_LOG_INFO, log, 0,
|
||||||
|
"kern.osreldate: %d, built on %d",
|
||||||
|
freebsd_kern_osreldate, __FreeBSD_version);
|
||||||
|
|
||||||
|
|
||||||
|
#if HAVE_FREEBSD_SENDFILE
|
||||||
|
|
||||||
|
/* The determination of the sendfile() nbytes bug is complex enough.
|
||||||
|
There're two sendfile() syscalls: a new 393 has no bug while
|
||||||
|
an old 336 has the bug in some versions and has not in others.
|
||||||
|
libc_r wrapper also emulates the bug in some versions.
|
||||||
|
There's no way to say exactly if a given FreeBSD version has bug.
|
||||||
|
Here is the algorithm that work at least for RELEASEs
|
||||||
|
and for syscalls only (not libc_r wrapper). */
|
||||||
|
|
||||||
|
/* detect was the new sendfile() version available at the compile time
|
||||||
|
to allow an old binary to run correctly on an updated FreeBSD system. */
|
||||||
|
|
||||||
|
#if (__FreeBSD__ == 4 && __FreeBSD_version >= 460102) \
|
||||||
|
|| __FreeBSD_version == 460002 || __FreeBSD_version >= 500039
|
||||||
|
|
||||||
|
/* a new syscall without the bug */
|
||||||
|
freebsd_sendfile_nbytes_bug = 0;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
/* an old syscall that can have the bug */
|
||||||
|
freebsd_sendfile_nbytes_bug = 1;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* HAVE_FREEBSD_SENDFILE */
|
||||||
|
|
||||||
|
|
||||||
|
size = 4;
|
||||||
|
if (sysctlbyname("hw.ncpu", &freebsd_hw_ncpu, &size, NULL, 0) == -1) {
|
||||||
|
ngx_log_error(NGX_LOG_ALERT, log, errno,
|
||||||
|
"sysctlbyname(hw.ncpu) failed");
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngx_log_error(NGX_LOG_INFO, log, 0, "hw.ncpu: %d", freebsd_hw_ncpu);
|
||||||
|
|
||||||
|
return NGX_OK;
|
||||||
|
}
|
18
src/os/unix/ngx_freebsd_init.h
Normal file
18
src/os/unix/ngx_freebsd_init.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#ifndef _NGX_OS_INIT_H_INCLUDED_
|
||||||
|
#define _NGX_OS_INIT_H_INCLUDED_
|
||||||
|
|
||||||
|
|
||||||
|
#include <ngx_config.h>
|
||||||
|
#include <ngx_core.h>
|
||||||
|
#include <ngx_log.h>
|
||||||
|
#include <sys/sysctl.h>
|
||||||
|
|
||||||
|
|
||||||
|
int ngx_os_init(ngx_log_t *log);
|
||||||
|
|
||||||
|
|
||||||
|
extern int freebsd_kern_osreldate;
|
||||||
|
extern int freebsd_hw_ncpu;
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* _NGX_OS_INIT_H_INCLUDED_ */
|
@ -11,57 +11,76 @@ extern int __isthreaded;
|
|||||||
|
|
||||||
typedef int ngx_tid_t;
|
typedef int ngx_tid_t;
|
||||||
|
|
||||||
#define NGX_MAX_THREADS 10
|
|
||||||
|
|
||||||
|
|
||||||
static inline int ngx_gettid();
|
static inline int ngx_gettid();
|
||||||
|
|
||||||
|
|
||||||
static char *stacks_start;
|
static char *usrstack;
|
||||||
static char *stacks_end;
|
|
||||||
static size_t stack_size;
|
|
||||||
static char *last_stack;
|
|
||||||
static int last_thread;
|
|
||||||
|
|
||||||
static ngx_log_t *log;
|
|
||||||
|
|
||||||
static ngx_tid_t tids[NGX_MAX_THREADS];
|
|
||||||
|
|
||||||
static int red_zone = 4096;
|
static int red_zone = 4096;
|
||||||
|
|
||||||
|
static size_t stack_size;
|
||||||
|
static size_t usable_stack_size;
|
||||||
|
static char *last_stack;
|
||||||
|
|
||||||
|
static int threads;
|
||||||
|
static int nthreads;
|
||||||
|
static ngx_tid_t *tids;
|
||||||
|
|
||||||
/* the thread-safe errno */
|
/* the thread-safe errno */
|
||||||
|
|
||||||
static int errnos[NGX_MAX_THREADS];
|
static int errno0; /* the main thread's errno */
|
||||||
|
static int *errnos;
|
||||||
|
|
||||||
int *__error()
|
int *__error()
|
||||||
{
|
{
|
||||||
return &errnos[ngx_gettid()];
|
int tid;
|
||||||
|
|
||||||
|
tid = ngx_gettid();
|
||||||
|
|
||||||
|
return tid ? &errnos[tid - 1] : &errno0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int ngx_create_thread(ngx_tid_t *tid, int (*func)(void *arg), void *arg)
|
int ngx_create_thread(ngx_tid_t *tid, int (*func)(void *arg), void *arg,
|
||||||
|
ngx_log_t *log)
|
||||||
{
|
{
|
||||||
int id, err;
|
int id, err;
|
||||||
char *stack_top;
|
char *stack, *stack_top;
|
||||||
|
|
||||||
last_stack += stack_size;
|
if (threads >= nthreads) {
|
||||||
stack_top = last_stack - red_zone;
|
ngx_log_error(NGX_LOG_CRIT, log, 0,
|
||||||
|
"no more than %d threads can be created", nthreads);
|
||||||
if (stack_top > stacks_end) {
|
|
||||||
ngx_log_error(NGX_LOG_CRIT, log, 0, "no more threads allocated");
|
|
||||||
return NGX_ERROR;
|
return NGX_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
last_stack -= stack_size;
|
||||||
id = rfork(RFFDG|RFCFDG);
|
stack = mmap(last_stack, usable_stack_size, PROT_READ|PROT_WRITE,
|
||||||
#elif 0
|
MAP_STACK, -1, 0);
|
||||||
id = rfork_thread(RFFDG|RFCFDG, stack_top, func, arg);
|
if (stack == MAP_FAILED) {
|
||||||
#elif 0
|
ngx_log_error(NGX_LOG_ALERT, log, errno,
|
||||||
id = rfork_thread(RFPROC|RFMEM, stack_top, func, arg);
|
"mmap(%08X:%d, MAP_STACK) thread stack failed",
|
||||||
#else
|
last_stack, usable_stack_size);
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stack != last_stack) {
|
||||||
|
ngx_log_error(NGX_LOG_ALERT, log, 0, "stack address was changed");
|
||||||
|
}
|
||||||
|
|
||||||
|
stack_top = stack + usable_stack_size;
|
||||||
|
|
||||||
|
printf("stack: %08X-%08X\n", stack, stack_top);
|
||||||
|
|
||||||
|
#if 1
|
||||||
id = rfork_thread(RFPROC|RFTHREAD|RFMEM, stack_top, func, arg);
|
id = rfork_thread(RFPROC|RFTHREAD|RFMEM, stack_top, func, arg);
|
||||||
|
#elif 1
|
||||||
|
id = rfork_thread(RFPROC|RFMEM, stack_top, func, arg);
|
||||||
|
#elif 1
|
||||||
|
id = rfork_thread(RFFDG|RFCFDG, stack_top, func, arg);
|
||||||
|
#else
|
||||||
|
id = rfork(RFFDG|RFCFDG);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
err = errno;
|
err = errno;
|
||||||
|
|
||||||
if (id == -1) {
|
if (id == -1) {
|
||||||
@ -69,7 +88,8 @@ int ngx_create_thread(ngx_tid_t *tid, int (*func)(void *arg), void *arg)
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
*tid = id;
|
*tid = id;
|
||||||
tids[last_thread++] = id;
|
threads = (usrstack - stack_top) / stack_size;
|
||||||
|
tids[threads] = id;
|
||||||
|
|
||||||
/* allow the spinlock in libc malloc() */
|
/* allow the spinlock in libc malloc() */
|
||||||
__isthreaded = 1;
|
__isthreaded = 1;
|
||||||
@ -79,14 +99,12 @@ int ngx_create_thread(ngx_tid_t *tid, int (*func)(void *arg), void *arg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int ngx_init_thread_env(int n, size_t size, ngx_log_t *lg)
|
int ngx_init_thread_env(int n, size_t size, ngx_log_t *log)
|
||||||
{
|
{
|
||||||
int len, i;
|
int len;
|
||||||
char *usrstack, *zone;
|
char *rz, *zone;
|
||||||
|
|
||||||
log = lg;
|
nthreads = n;
|
||||||
|
|
||||||
/* create the thread stacks */
|
|
||||||
|
|
||||||
len = 4;
|
len = 4;
|
||||||
if (sysctlbyname("kern.usrstack", &usrstack, &len, NULL, 0) == -1) {
|
if (sysctlbyname("kern.usrstack", &usrstack, &len, NULL, 0) == -1) {
|
||||||
@ -96,41 +114,37 @@ int ngx_init_thread_env(int n, size_t size, ngx_log_t *lg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
printf("usrstack: %08X\n", usrstack);
|
printf("usrstack: %08X\n", usrstack);
|
||||||
printf("red zone: %08X\n", usrstack - (size + red_zone));
|
|
||||||
|
|
||||||
#if 1
|
|
||||||
/* red zone */
|
/* red zone */
|
||||||
zone = mmap(usrstack - (size + red_zone), red_zone,
|
rz = usrstack - (size + red_zone);
|
||||||
PROT_NONE, MAP_ANON, -1, 0);
|
|
||||||
|
printf("red zone: %08X\n", rz);
|
||||||
|
|
||||||
|
zone = mmap(rz, red_zone, PROT_NONE, MAP_ANON, -1, 0);
|
||||||
if (zone == MAP_FAILED) {
|
if (zone == MAP_FAILED) {
|
||||||
ngx_log_error(NGX_LOG_ALERT, log, errno,
|
ngx_log_error(NGX_LOG_ALERT, log, errno,
|
||||||
"mmap(%d, PROT_NONE, MAP_ANON) failed", red_zone);
|
"mmap(%08X:%d, PROT_NONE, MAP_ANON) red zone failed",
|
||||||
|
rz, red_zone);
|
||||||
return NGX_ERROR;
|
return NGX_ERROR;
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
zone = usrstack - (size + red_zone);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
last_stack = zone + red_zone;
|
if (zone != rz) {
|
||||||
|
ngx_log_error(NGX_LOG_ALERT, log, 0, "red zone address was changed");
|
||||||
for (i = 0; i < n; i++) {
|
|
||||||
last_stack -= size + red_zone;
|
|
||||||
printf("stack: %08X\n", last_stack);
|
|
||||||
last_stack = mmap(last_stack, size, PROT_READ|PROT_WRITE,
|
|
||||||
MAP_STACK, -1, 0);
|
|
||||||
if (last_stack == MAP_FAILED) {
|
|
||||||
ngx_log_error(NGX_LOG_ALERT, log, errno,
|
|
||||||
"mmap(%d, MAP_STACK) failed", size);
|
|
||||||
return NGX_ERROR;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
stacks_start = last_stack;
|
/* create the thread errno array */
|
||||||
stack_size = size + red_zone;
|
ngx_test_null(errnos, ngx_calloc(n * sizeof(int), log), NGX_ERROR);
|
||||||
stacks_end = stacks_start + n * stack_size;
|
|
||||||
|
/* create the thread tid array */
|
||||||
|
ngx_test_null(tids, ngx_calloc((n + 1) * sizeof(ngx_tid_t), log),
|
||||||
|
NGX_ERROR);
|
||||||
|
|
||||||
tids[0] = ngx_getpid();
|
tids[0] = ngx_getpid();
|
||||||
last_thread = 1;
|
threads = 1;
|
||||||
|
|
||||||
|
last_stack = zone + red_zone;
|
||||||
|
usable_stack_size = size;
|
||||||
|
stack_size = size + red_zone;
|
||||||
|
|
||||||
return NGX_OK;
|
return NGX_OK;
|
||||||
}
|
}
|
||||||
@ -138,7 +152,18 @@ printf("stack: %08X\n", last_stack);
|
|||||||
|
|
||||||
ngx_tid_t ngx_thread_self()
|
ngx_tid_t ngx_thread_self()
|
||||||
{
|
{
|
||||||
return tids[ngx_gettid()];
|
int tid;
|
||||||
|
ngx_tid_t pid;
|
||||||
|
|
||||||
|
tid = ngx_gettid();
|
||||||
|
|
||||||
|
if (tids[tid] == 0) {
|
||||||
|
pid = ngx_getpid();
|
||||||
|
tids[tid] = pid;
|
||||||
|
return pid;
|
||||||
|
}
|
||||||
|
|
||||||
|
return tids[tid];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -146,7 +171,11 @@ static inline int ngx_gettid()
|
|||||||
{
|
{
|
||||||
char *sp;
|
char *sp;
|
||||||
|
|
||||||
|
if (stack_size == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
__asm__ ("mov %%esp, %0" : "=q" (sp));
|
__asm__ ("mov %%esp, %0" : "=q" (sp));
|
||||||
|
|
||||||
return (sp > stacks_end) ? 0 : ((sp - stacks_start) / stack_size + 1);
|
return (usrstack - sp) / stack_size;
|
||||||
}
|
}
|
||||||
|
20
src/os/unix/ngx_init.c
Normal file
20
src/os/unix/ngx_init.c
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
|
||||||
|
|
||||||
|
int ngx_unix_init(ngx_log_t *log)
|
||||||
|
{
|
||||||
|
struct rlimit rlmt;
|
||||||
|
|
||||||
|
if (getrlimit(RLIMIT_NOFILE, &rlmt) == -1) {
|
||||||
|
ngx_log_error(NGX_LOG_ALERT, log, errno,
|
||||||
|
"getrlimit(RLIMIT_NOFILE) failed)");
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngx_log_error(NGX_LOG_INFO, log, 0,
|
||||||
|
"getrlimit(RLIMIT_NOFILE): %d", rlmt.rlim_cur);
|
||||||
|
|
||||||
|
RLIM_INFINITY
|
||||||
|
max_connections =< rlmt.rlim_cur;
|
||||||
|
|
||||||
|
return NGX_OK;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user