nginx-0.0.1-2003-05-29-17:02:09 import
diff --git a/src/core/nginx.c b/src/core/nginx.c
index c2fdc87..e1894f4 100644
--- a/src/core/nginx.c
+++ b/src/core/nginx.c
@@ -90,8 +90,8 @@
conf.module_type = NGX_CORE_MODULE;
conf.cmd_type = NGX_MAIN_CONF;
- conf_file.len = sizeof("nginx.conf") - 1;
- conf_file.data = "nginx.conf";
+ conf_file.len = sizeof(NGINX_CONF) - 1;
+ conf_file.data = NGINX_CONF;
if (ngx_conf_parse(&conf, &conf_file) != NGX_CONF_OK) {
return 1;
diff --git a/src/core/nginx.h b/src/core/nginx.h
index df00add..3bc4bf5 100644
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -2,7 +2,8 @@
#define _NGINX_H_INCLUDED_
-#define NGINX_VER "nginx/0.0.1"
+#define NGINX_VER "nginx/0.0.1"
+#define NGINX_CONF "nginx.conf"
extern int ngx_max_module;
diff --git a/src/core/ngx_string.h b/src/core/ngx_string.h
index 7c97c13..9f72f17 100644
--- a/src/core/ngx_string.h
+++ b/src/core/ngx_string.h
@@ -52,9 +52,11 @@
int ngx_rstrncmp(char *s1, char *s2, size_t n);
int ngx_atoi(char *line, size_t n);
+#define ngx_qsort qsort
-#define ngx_value_helper(n) #n
-#define ngx_value(n) ngx_value_helper(n)
+
+#define ngx_value_helper(n) #n
+#define ngx_value(n) ngx_value_helper(n)
#endif /* _NGX_STRING_H_INCLUDED_ */
diff --git a/src/event/ngx_event.c b/src/event/ngx_event.c
index 2361a3f..be9af20 100644
--- a/src/event/ngx_event.c
+++ b/src/event/ngx_event.c
@@ -9,7 +9,7 @@
#define DEF_CONNECTIONS 1024
-extern ngx_event_module_t ngx_select_module_ctx;
+extern ngx_module_t ngx_select_module;
#if (HAVE_KQUEUE)
#include <ngx_kqueue_module.h>
@@ -122,12 +122,11 @@
int ngx_pre_thread(ngx_array_t *ls, ngx_pool_t *pool, ngx_log_t *log)
{
- int m, i, fd;
-
- ngx_listen_t *s;
- ngx_event_t *ev;
- ngx_connection_t *c;
- ngx_event_conf_t *ecf;
+ int m, i, fd;
+ ngx_listen_t *s;
+ ngx_event_t *ev;
+ ngx_connection_t *c;
+ ngx_event_conf_t *ecf;
ngx_event_module_t *module;
ecf = ngx_event_get_conf(ngx_event_module);
diff --git a/src/event/ngx_event.h b/src/event/ngx_event.h
index 3e27ab0..928d2cf 100644
--- a/src/event/ngx_event.h
+++ b/src/event/ngx_event.h
@@ -90,9 +90,7 @@
unsigned ignore_econnreset:1;
unsigned unexpected_eof:1;
-#if (HAVE_DEFERRED_ACCEPT)
unsigned deferred_accept:1;
-#endif
#if (HAVE_KQUEUE)
unsigned eof:1;
@@ -277,6 +275,7 @@
#define ngx_process_events ngx_event_actions.process
#define ngx_add_event ngx_event_actions.add
#define ngx_del_event ngx_event_actions.del
+#define ngx_add_conn ngx_event_actions.add_conn
#define ngx_del_conn ngx_event_actions.del_conn
#if 0
diff --git a/src/event/ngx_event_accept.c b/src/event/ngx_event_accept.c
index c69427f..4bf1043 100644
--- a/src/event/ngx_event_accept.c
+++ b/src/event/ngx_event_accept.c
@@ -1,11 +1,9 @@
-#include <nginx.h>
-
#include <ngx_config.h>
#include <ngx_core.h>
-#include <ngx_types.h>
-#include <ngx_log.h>
-#include <ngx_connection.h>
+
+#include <nginx.h>
+
#include <ngx_event.h>
@@ -19,18 +17,17 @@
ngx_socket_t s;
ngx_event_t *rev, *wev;
ngx_connection_t *c, *ls;
+ ngx_event_conf_t *ecf;
- ls = (ngx_connection_t *) ev->data;
+ ecf = ngx_event_get_conf(ngx_event_module);
+
+ ls = ev->data;
ngx_log_debug(ev->log, "ngx_event_accept: accept ready: %d" _
ev->available);
ev->ready = 0;
-#if 0
-/* DEBUG */ ev->available++;
-#endif
-
do {
/* Create the pool before accept() to avoid copy the sockaddr.
@@ -52,16 +49,37 @@
s = accept(ls->fd, sa, &len);
if (s == -1) {
err = ngx_socket_errno;
- ngx_destroy_pool(pool);
if (err == NGX_EAGAIN) {
ngx_log_error(NGX_LOG_NOTICE, ev->log, err,
- "EAGAIN while accept %s", ls->addr_text.data);
+ "EAGAIN while accept() %s", ls->addr_text.data);
return;
}
ngx_log_error(NGX_LOG_ALERT, ev->log, err,
- "accept %s failed", ls->addr_text.data);
+ "accept() %s failed", ls->addr_text.data);
+
+ ngx_destroy_pool(pool);
+ return;
+ }
+
+ if (s >= ecf->connections) {
+
+ ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
+ "accept() %s returned socket #%d while "
+ "only %d connections was configured, "
+ "sleeping for 1 second",
+ ls->addr_text.data, s, ecf->connections);
+
+ if (ngx_close_socket(s) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
+ ngx_close_socket_n " %s failed",
+ ls->addr_text.data);
+ }
+
+ sleep(1);
+
+ ngx_destroy_pool(pool);
return;
}
@@ -73,6 +91,14 @@
ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
ngx_blocking_n " %s failed",
ls->addr_text.data);
+
+ if (ngx_close_socket(s) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
+ ngx_close_socket_n " %s failed",
+ ls->addr_text.data);
+ }
+
+ ngx_destroy_pool(pool);
return;
}
}
@@ -83,6 +109,14 @@
ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
ngx_nonblocking_n " %s failed",
ls->addr_text.data);
+
+ if (ngx_close_socket(s) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
+ ngx_close_socket_n " %s failed",
+ ls->addr_text.data);
+ }
+
+ ngx_destroy_pool(pool);
return;
}
}
@@ -133,28 +167,28 @@
ngx_memcpy(c->log, ev->log, sizeof(ngx_log_t));
rev->log = wev->log = c->log;
- /* STUB: x86: SP: xadd ?, MT: lock xadd, MP: lock xadd, shared */
+ /* STUB: x86: MT: lock xadd, MP: lock xadd, shared */
c->number = ngx_connection_counter++;
- ngx_log_debug(ev->log, "ngx_event_accept: accept: %d, %d" _
- s _ c->number);
+ ngx_log_debug(ev->log, "accept: %d, %d" _ s _ c->number);
-#if (HAVE_DEFERRED_ACCEPT)
- if (ev->accept_filter) {
+ if (ev->deferred_accept) {
rev->ready = 1;
}
-#endif
-#if (HAVE_EDGE_EVENT) /* epoll */
+ if (ngx_add_conn) {
+ if (ngx_add_conn(c) == NGX_ERROR) {
+ if (ngx_close_socket(s) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
+ ngx_close_socket_n " %s failed",
+ ls->addr_text.data);
+ }
- if (ngx_event_flags & NGX_HAVE_EDGE_EVENT) {
- if (ngx_edge_add_event(ev) == NGX_ERROR) {
+ ngx_destroy_pool(pool);
return;
}
}
-#endif
-
ls->handler(c);
if (ngx_event_flags & NGX_HAVE_KQUEUE_EVENT) {
diff --git a/src/http/modules/ngx_http_index_handler.c b/src/http/modules/ngx_http_index_handler.c
index 4946214..0286669 100644
--- a/src/http/modules/ngx_http_index_handler.c
+++ b/src/http/modules/ngx_http_index_handler.c
@@ -59,7 +59,7 @@
{
int i, rc, test_dir;
char *name, *file;
- ngx_str_t loc, *index;
+ ngx_str_t redirect, *index;
ngx_err_t err;
ngx_fd_t fd;
ngx_http_index_conf_t *icf;
@@ -74,14 +74,14 @@
+ icf->max_index_len),
NGX_HTTP_INTERNAL_SERVER_ERROR);
- loc.data = ngx_cpystrn(r->path.data, clcf->doc_root.data,
- clcf->doc_root.len + 1);
- file = ngx_cpystrn(loc.data, r->uri.data, r->uri.len + 1);
+ redirect.data = ngx_cpymem(r->path.data, clcf->doc_root.data,
+ clcf->doc_root.len);
+ file = ngx_cpystrn(redirect.data, r->uri.data, r->uri.len + 1);
r->path.len = file - r->path.data;
test_dir = 1;
- index = (ngx_str_t *) icf->indices.elts;
+ index = icf->indices.elts;
for (i = 0; i < icf->indices.nelts; i++) {
if (index[i].data[0] != '/') {
@@ -136,18 +136,15 @@
if (index[i].data[0] == '/') {
r->file.name.len = index[i].len;
- loc.len = index[i].len;
- loc.data = index[i].data;
+ redirect.len = index[i].len;
+ redirect.data = index[i].data;
} else {
- loc.len = r->uri.len + index[i].len;
- r->file.name.len = clcf->doc_root.len + r->uri.len
- + index[i].len;
+ redirect.len = r->uri.len + index[i].len;
+ r->file.name.len = clcf->doc_root.len + r->uri.len + index[i].len;
}
-/* STUB */ r->exten.len = 4; r->exten.data = "html";
-
- return ngx_http_internal_redirect(r, loc);
+ return ngx_http_internal_redirect(r, &redirect, NULL);
}
return NGX_DECLINED;
@@ -177,7 +174,6 @@
}
ngx_log_error(NGX_LOG_CRIT, r->connection->log, r->path_err,
- "ngx_http_index_test_dir: "
ngx_file_type_n " %s failed", r->path.data);
return NGX_HTTP_INTERNAL_SERVER_ERROR;
@@ -263,7 +259,7 @@
}
-/* TODO: check duplicate indices */
+/* TODO: warn about duplicate indices */
static char *ngx_http_index_set_index(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf)
@@ -283,7 +279,9 @@
for (i = 1; i < cf->args->nelts; i++) {
if (value[i].len == 0) {
- return "is invalid";
+ ngx_snprintf(ngx_conf_errstr, sizeof(ngx_conf_errstr) - 1,
+ "index \"%s\" is invalid", value[1].data);
+ return ngx_conf_errstr;
}
ngx_test_null(index, ngx_push_array(&icf->indices), NGX_CONF_ERROR);
@@ -295,5 +293,5 @@
}
}
- return NULL;
+ return NGX_CONF_OK;
}
diff --git a/src/http/ngx_http_cache.c b/src/http/ngx_http_cache.c
new file mode 100644
index 0000000..f9e36f5
--- /dev/null
+++ b/src/http/ngx_http_cache.c
@@ -0,0 +1,63 @@
+
+
+
+#define NGX_HTTP_CACHE_ENTRY_DELETED 0x00000001
+#define NGX_HTTP_CACHE_ENTRY_MMAPED 0x00000002
+
+/* "/" -> "/index.html" in ngx_http_index_handler */
+#define NGX_HTTP_CACHE_ENTRY_URI 0x00000004
+
+#define NGX_HTTP_CACHE_FILTER_FLAGS 0xFFFF0000
+
+
+typedef struct {
+ ngx_fd_t fd;
+ off_t size;
+ void *data;
+ time_t accessed;
+ time_t last_modified;
+ time_t updated; /* no needed with kqueue */
+ int refs;
+ int flags;
+} ngx_http_cache_entry_t;
+
+
+typedef struct {
+ u_int32_t crc;
+ ngx_str_t uri;
+ ngx_http_cache_t *cache;
+} ngx_http_cache_hash_entry_t;
+
+
+typedef struct {
+ ngx_http_cache_t *cache;
+ u_int32_t crc;
+ int n;
+} ngx_http_cache_handle_t;
+
+
+int ngx_http_cache_get(ngx_http_cache_hash_t *cache_hash,
+ ngx_str_t *uri, ngx_http_cache_handle_t *h)
+{
+ int hi;
+ ngx_http_cache_hash_entry_t *entry;
+
+ h->crc = ngx_crc32(uri->data, uri->len);
+
+ hi = h->crc % cache_hash->size;
+ entry = cache_hash[hi].elts;
+
+ for (i = 0; i < cache_hash[hi].nelts; i++) {
+ if (entry[i].crc == crc
+ && entry[i].uri.len == uri->len
+ && ngx_strncmp(entry[i].uri.data, uri->data, uri->len) == 0
+ {
+ h->cache = entry[i].cache;
+ h->cache->refs++;
+ h->n = hi;
+ return NGX_OK;
+ }
+ }
+
+ return NGX_ERROR;
+}
diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c
index ba07718..b678669 100644
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -28,10 +28,13 @@
static int ngx_http_core_init(ngx_pool_t *pool);
static char *ngx_server_block(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy);
+static int ngx_cmp_locations(const void *first, const void *second);
static char *ngx_location_block(ngx_conf_t *cf, ngx_command_t *cmd,
void *dummy);
static char *ngx_types_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
static char *ngx_set_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
+static char *ngx_set_server_name(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);
static ngx_command_t ngx_http_core_commands[] = {
@@ -41,7 +44,7 @@
ngx_server_block,
0,
0,
- NULL,},
+ NULL},
{ngx_string("connection_pool_size"),
NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
@@ -99,6 +102,13 @@
0,
NULL},
+ {ngx_string("server_name"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_ANY,
+ ngx_set_server_name,
+ NGX_HTTP_SRV_CONF_OFFSET,
+ 0,
+ NULL},
+
{ngx_string("types"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF
|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
@@ -215,8 +225,10 @@
continue;
}
- rc = ngx_rstrncmp(r->uri.data, clcfp[i]->name.data,
- clcfp[i]->name.len);
+ rc = ngx_strncmp(r->uri.data, clcfp[i]->name.data,
+ clcfp[i]->name.len);
+
+ngx_log_debug(r->connection->log, "rc: %d" _ rc);
if (rc < 0) {
break;
@@ -235,9 +247,10 @@
/* run translation phase */
- h = (ngx_http_handler_pt *) ngx_http_translate_handlers.elts;
- for (i = ngx_http_translate_handlers.nelts; i > 0; /* void */) {
- rc = h[--i](r);
+ h = ngx_http_translate_handlers.elts;
+ for (i = ngx_http_translate_handlers.nelts - 1; i >= 0; i--) {
+
+ rc = h[i](r);
if (rc == NGX_DECLINED) {
continue;
@@ -457,21 +470,46 @@
}
-int ngx_http_internal_redirect(ngx_http_request_t *r, ngx_str_t uri)
+int ngx_http_internal_redirect(ngx_http_request_t *r,
+ ngx_str_t *uri, ngx_str_t *args)
{
- ngx_log_debug(r->connection->log, "internal redirect: '%s'" _ uri.data);
+ int i;
- r->uri.len = uri.len;
- r->uri.data = uri.data;
+ ngx_log_debug(r->connection->log, "internal redirect: '%s'" _ uri->data);
- /* BROKEN, NEEDED ? */
- /* r->exten */
- r->uri_start = uri.data;
- r->uri_end = uri.data + uri.len;
- /**/
+ r->uri.len = uri->len;
+ r->uri.data = uri->data;
+
+ if (args) {
+ r->args.len = args->len;
+ r->args.data = args->data;
+ }
+
+ r->exten.len = 0;
+ r->exten.data = NULL;
+
+ for (i = uri->len - 1; i > 1; i--) {
+ if (uri->data[i] == '.' && uri->data[i - 1] != '/') {
+ r->exten.len = uri->len - i - 1;
+
+ if (r->exten.len > 0) {
+ ngx_test_null(r->exten.data,
+ ngx_palloc(r->pool, r->exten.len + 1),
+ NGX_HTTP_INTERNAL_SERVER_ERROR);
+
+ ngx_cpystrn(r->exten.data, &uri->data[i + 1], r->exten.len + 1);
+ }
+
+ break;
+
+ } else if (uri->data[i] == '/') {
+ break;
+ }
+ }
ngx_http_handler(r);
- return 0;
+
+ return NGX_OK;
}
@@ -554,10 +592,26 @@
rv = ngx_conf_parse(cf, NULL);
*cf = pcf;
+ if (rv != NGX_CONF_OK) {
+ return rv;
+ }
+
+ ngx_qsort(cscf->locations.elts, cscf->locations.nelts,
+ sizeof(void *), ngx_cmp_locations);
+
return rv;
}
+static int ngx_cmp_locations(const void *first, const void *second)
+{
+ ngx_http_core_loc_conf_t *one = *(ngx_http_core_loc_conf_t **) first;
+ ngx_http_core_loc_conf_t *two = *(ngx_http_core_loc_conf_t **) second;
+
+ return ngx_strcmp(one->name.data, two->name.data);
+}
+
+
static char *ngx_location_block(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)
{
int m;
@@ -724,6 +778,7 @@
ngx_http_core_srv_conf_t *prev = (ngx_http_core_srv_conf_t *) parent;
ngx_http_core_srv_conf_t *conf = (ngx_http_core_srv_conf_t *) child;
+ ngx_err_t err;
ngx_http_listen_t *l;
ngx_http_server_name_t *n;
@@ -740,10 +795,15 @@
ngx_test_null(n, ngx_push_array(&conf->server_names), NGX_CONF_ERROR);
ngx_test_null(n->name.data, ngx_palloc(pool, NGX_MAXHOSTNAMELEN),
NGX_CONF_ERROR);
+
if (gethostname(n->name.data, NGX_MAXHOSTNAMELEN) == -1) {
- /* TODO: need ngx_errno here */
- return "gethostname() failed";
+ err = ngx_errno;
+ ngx_snprintf(ngx_conf_errstr, sizeof(ngx_conf_errstr) - 1,
+ "gethostname() failed (%d: %s)",
+ err, ngx_strerror(err));
+ return ngx_conf_errstr;
}
+
n->name.len = ngx_strlen(n->name.data);
n->core_srv_conf = conf;
}
@@ -868,7 +928,7 @@
ngx_http_listen_t *ls;
/* TODO: check duplicate 'listen' directives,
- add resolved name to server names */
+ add resolved name to server names ??? */
ngx_test_null(ls, ngx_push_array(&scf->listen), NGX_CONF_ERROR);
@@ -879,37 +939,75 @@
ls->file_name = cf->conf_file->file.name;
ls->line = cf->conf_file->line;
- args = (ngx_str_t *) cf->args->elts;
+ args = cf->args->elts;
addr = args[1].data;
for (p = 0; p < args[1].len; p++) {
if (addr[p] == ':') {
addr[p++] = '\0';
-
- ls->addr = inet_addr(addr);
- if (ls->addr == INADDR_NONE) {
- h = gethostbyname(addr);
-
- if (h == NULL || h->h_addr_list[0] == NULL) {
- return "can not resolve host name";
- }
-
- ls->addr = *(u_int32_t *)(h->h_addr_list[0]);
- }
-
break;
}
}
if (p == args[1].len) {
- ls->addr = INADDR_ANY;
+ /* no ":" in the "listen" */
p = 0;
}
ls->port = ngx_atoi(&addr[p], args[1].len - p);
- if (ls->port < 1 || ls->port > 65536) {
- return "port must be between 1 and 65535";
+ if (ls->port == NGX_ERROR && p == 0) {
+
+ /* "listen host" */
+ ls->port = 80;
+
+ } else if ((ls->port == NGX_ERROR && p != 0) /* "listen host:NONNUMBER" */
+ || (ls->port < 1 || ls->port > 65536)) { /* "listen 99999" */
+
+ ngx_snprintf(ngx_conf_errstr, sizeof(ngx_conf_errstr) - 1,
+ "invalid port \"%s\", "
+ "it must be a number between 1 and 65535",
+ &addr[p]);
+ return ngx_conf_errstr;
+
+ } else if (p == 0) {
+ ls->addr = INADDR_ANY;
+ return NGX_CONF_OK;
}
+ ls->addr = inet_addr(addr);
+ if (ls->addr == INADDR_NONE) {
+ h = gethostbyname(addr);
+
+ if (h == NULL || h->h_addr_list[0] == NULL) {
+ ngx_snprintf(ngx_conf_errstr, sizeof(ngx_conf_errstr) - 1,
+ "can not resolve host \"%s\"", addr);
+ return ngx_conf_errstr;
+ }
+
+ ls->addr = *(u_int32_t *)(h->h_addr_list[0]);
+ }
+
+ return NGX_CONF_OK;
+}
+
+
+static char *ngx_set_server_name(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ ngx_http_core_srv_conf_t *scf = (ngx_http_core_srv_conf_t *) conf;
+
+ ngx_str_t *args;
+ ngx_http_server_name_t *sn;
+
+ /* TODO: several names */
+ /* TODO: warn about duplicate 'server_name' directives */
+
+ ngx_test_null(sn, ngx_push_array(&scf->server_names), NGX_CONF_ERROR);
+
+ args = cf->args->elts;
+
+ sn->name.len = args[1].len;
+ sn->name.data = args[1].data;
+ sn->core_srv_conf = scf;
+
return NGX_CONF_OK;
}
diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h
index 6d4acff..113c197 100644
--- a/src/http/ngx_http_core_module.h
+++ b/src/http/ngx_http_core_module.h
@@ -138,7 +138,8 @@
int ngx_http_core_translate_handler(ngx_http_request_t *r);
-int ngx_http_internal_redirect(ngx_http_request_t *r, ngx_str_t uri);
+int ngx_http_internal_redirect(ngx_http_request_t *r,
+ ngx_str_t *uri, ngx_str_t *args);
int ngx_http_error(ngx_http_request_t *r, int error);
diff --git a/src/os/unix/ngx_errno.h b/src/os/unix/ngx_errno.h
index b980281..6006471 100644
--- a/src/os/unix/ngx_errno.h
+++ b/src/os/unix/ngx_errno.h
@@ -24,6 +24,8 @@
#define ngx_socket_errno errno
#define ngx_set_socket_errno(err) errno = err
+#define ngx_strerror(err) strerror(err)
+
#define ngx_strerror_r(err, errstr, size) \
ngx_cpystrn(errstr, strerror(err), size) - (errstr)
diff --git a/src/os/unix/ngx_freebsd_init.c b/src/os/unix/ngx_freebsd_init.c
index 100dfc4..cacc457 100644
--- a/src/os/unix/ngx_freebsd_init.c
+++ b/src/os/unix/ngx_freebsd_init.c
@@ -2,6 +2,7 @@
#include <ngx_freebsd_init.h>
+/* FreeBSD 3.4 at least */
char ngx_freebsd_kern_ostype[20];
char ngx_freebsd_kern_osrelease[20];
int ngx_freebsd_kern_osreldate;
@@ -9,6 +10,9 @@
int ngx_freebsd_net_inet_tcp_sendspace;
int ngx_freebsd_sendfile_nbytes_bug;
+/* FreeBSD 5.0 */
+int ngx_freebsd_kern_ipc_zero_copy_send;
+
ngx_os_io_t ngx_os_io = {
ngx_unix_recv,
@@ -19,9 +23,35 @@
};
+typedef struct {
+ char *name;
+ int *value;
+ size_t size;
+} sysctl_t;
+
+
+sysctl_t sysctls[] = {
+ {"hw.ncpu",
+ &ngx_freebsd_hw_ncpu,
+ sizeof(int)},
+
+ {"net.inet.tcp.sendspace",
+ &ngx_freebsd_net_inet_tcp_sendspace,
+ sizeof(int)},
+
+ {"kern.ipc.zero_copy.send",
+ &ngx_freebsd_kern_ipc_zero_copy_send,
+ sizeof(int)},
+
+ {NULL, NULL, 0}
+};
+
+
int ngx_os_init(ngx_log_t *log)
{
- size_t size;
+ int i;
+ size_t size;
+ ngx_err_t err;
size = 20;
if (sysctlbyname("kern.ostype",
@@ -85,28 +115,23 @@
#endif /* HAVE_FREEBSD_SENDFILE */
- size = 4;
- if (sysctlbyname("hw.ncpu", &ngx_freebsd_hw_ncpu, &size, NULL, 0) == -1) {
- ngx_log_error(NGX_LOG_ALERT, log, errno,
- "sysctlbyname(hw.ncpu) failed");
- return NGX_ERROR;
+ for (i = 0; sysctls[i].name; i++) {
+ *sysctls[i].value = 0;
+ size = sysctls[i].size;
+ if (sysctlbyname(sysctls[i].name, sysctls[i].value, &size, NULL, 0)
+ == -1) {
+ err = errno;
+ if (err != NGX_ENOENT) {
+ ngx_log_error(NGX_LOG_ALERT, log, err,
+ "sysctlbyname(%s) failed", sysctls[i].name);
+ return NGX_ERROR;
+ }
+
+ } else {
+ ngx_log_error(NGX_LOG_INFO, log, 0, "%s: %d",
+ sysctls[i].name, *sysctls[i].value);
+ }
}
- ngx_log_error(NGX_LOG_INFO, log, 0, "hw.ncpu: %d", ngx_freebsd_hw_ncpu);
-
-
- size = 4;
- if (sysctlbyname("net.inet.tcp.sendspace",
- &ngx_freebsd_net_inet_tcp_sendspace,
- &size, NULL, 0) == -1)
- {
- ngx_log_error(NGX_LOG_ALERT, log, errno,
- "sysctlbyname(net.inet.tcp.sendspace) failed");
- return NGX_ERROR;
- }
-
- ngx_log_error(NGX_LOG_INFO, log, 0, "net.inet.tcp.sendspace: %d",
- ngx_freebsd_net_inet_tcp_sendspace);
-
return ngx_posix_init(log);
}
diff --git a/src/os/unix/ngx_linux_config.h b/src/os/unix/ngx_linux_config.h
index e4c5dd0..cfd9413 100644
--- a/src/os/unix/ngx_linux_config.h
+++ b/src/os/unix/ngx_linux_config.h
@@ -26,6 +26,7 @@
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
+#include <netdb.h>
typedef unsigned int u_int;
diff --git a/src/os/unix/ngx_linux_sendfile_chain.c b/src/os/unix/ngx_linux_sendfile_chain.c
new file mode 100644
index 0000000..6ea67f4
--- /dev/null
+++ b/src/os/unix/ngx_linux_sendfile_chain.c
@@ -0,0 +1,183 @@
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_linux_init.h>
+
+
+ngx_chain_t *ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in)
+{
+ int rc, on, off;
+ char *prev;
+ size_t hsize, size;
+ ssize_t sent;
+ struct iovec *iov;
+ struct sf_hdtr hdtr;
+ ngx_err_t err;
+ ngx_array_t header, trailer;
+ ngx_hunk_t *file;
+ ngx_chain_t *ce;
+
+ ce = in;
+ file = NULL;
+ hsize = 0;
+
+ on = 1;
+ off = 0;
+
+ ngx_init_array(header, c->pool, 10, sizeof(struct iovec), NGX_CHAIN_ERROR);
+ ngx_init_array(trailer, c->pool, 10, sizeof(struct iovec), NGX_CHAIN_ERROR);
+
+ /* create the header iovec */
+ if (ngx_hunk_in_memory_only(ce->hunk)) {
+ prev = NULL;
+ iov = NULL;
+
+ /* create the iovec and coalesce the neighbouring chain entries */
+ while (ce && ngx_hunk_in_memory_only(ce->hunk)) {
+
+ if (prev == ce->hunk->pos) {
+ iov->iov_len += ce->hunk->last - ce->hunk->pos;
+ prev = ce->hunk->last;
+
+ } else {
+ ngx_test_null(iov, ngx_push_array(&header), NGX_CHAIN_ERROR);
+ iov->iov_base = ce->hunk->pos;
+ iov->iov_len = ce->hunk->last - ce->hunk->pos;
+ prev = ce->hunk->last;
+ }
+
+ if (ngx_freebsd_sendfile_nbytes_bug) {
+ hsize += ce->hunk->last - ce->hunk->pos;
+ }
+
+ ce = ce->next;
+ }
+ }
+
+ /* TODO: coalesce the neighbouring file hunks */
+ if (ce && (ce->hunk->type & NGX_HUNK_FILE)) {
+ file = ce->hunk;
+ ce = ce->next;
+ }
+
+ /* create the trailer iovec */
+ if (ce && ngx_hunk_in_memory_only(ce->hunk)) {
+ prev = NULL;
+ iov = NULL;
+
+ /* create the iovec and coalesce the neighbouring chain entries */
+ while (ce && ngx_hunk_in_memory_only(ce->hunk)) {
+
+ if (prev == ce->hunk->pos) {
+ iov->iov_len += ce->hunk->last - ce->hunk->pos;
+ prev = ce->hunk->last;
+
+ } else {
+ ngx_test_null(iov, ngx_push_array(&trailer), NGX_CHAIN_ERROR);
+ iov->iov_base = ce->hunk->pos;
+ iov->iov_len = ce->hunk->last - ce->hunk->pos;
+ prev = ce->hunk->last;
+ }
+
+ ce = ce->next;
+ }
+ }
+
+ if (file) {
+ if (setsockopt(c->fd, IPPROTO_TCP, TCP_CORK,
+ (const void *) &on, sizeof(int)) == -1) {
+ ngx_log_error(NGX_LOG_CRIT, c->log, err,
+ "setsockopt(TCP_CORK, 1) failed");
+ return NGX_CHAIN_ERROR;
+ }
+
+
+ rc = sendfile(c->fd, file->file->fd, file->file_pos,
+ (size_t) (file->file_last - file->file_pos));
+
+ if (rc == -1) {
+ err = ngx_errno;
+ if (err == NGX_EAGAIN) {
+ ngx_log_error(NGX_LOG_INFO, c->log, err, "senfile() EAGAIN");
+
+ } else if (err == NGX_EINTR) {
+ ngx_log_error(NGX_LOG_INFO, c->log, err, "senfile() EINTR");
+
+ } else {
+ ngx_log_error(NGX_LOG_CRIT, c->log, err, "sendfile() failed");
+ return NGX_CHAIN_ERROR;
+ }
+ }
+
+ sent = rc > 0 ? rc : 0;
+
+#if (NGX_DEBUG_WRITE_CHAIN)
+ ngx_log_debug(c->log, "sendfile: %d, @%qd %d:%d" _
+ rc _ file->file_pos _ sent _
+ (size_t) (file->file_last - file->file_pos));
+#endif
+
+ } else {
+ rc = writev(c->fd, (struct iovec *) header.elts, header.nelts);
+
+ if (rc == -1) {
+ err = ngx_errno;
+ if (err == NGX_EAGAIN) {
+ ngx_log_error(NGX_LOG_INFO, c->log, err, "writev() EAGAIN");
+
+ } else if (err == NGX_EINTR) {
+ ngx_log_error(NGX_LOG_INFO, c->log, err, "writev() EINTR");
+
+ } else {
+ ngx_log_error(NGX_LOG_CRIT, c->log, err, "writev() failed");
+ return NGX_CHAIN_ERROR;
+ }
+ }
+
+ sent = rc > 0 ? rc : 0;
+
+#if (NGX_DEBUG_WRITE_CHAIN)
+ ngx_log_debug(c->log, "writev: %d" _ sent);
+#endif
+ }
+
+ c->sent += sent;
+
+ for (ce = in; ce && sent > 0; ce = ce->next) {
+
+ if (ce->hunk->type & NGX_HUNK_IN_MEMORY) {
+ size = ce->hunk->last - ce->hunk->pos;
+ } else {
+ size = ce->hunk->file_last - ce->hunk->file_pos;
+ }
+
+ if (sent >= size) {
+ sent -= size;
+
+ if (ce->hunk->type & NGX_HUNK_IN_MEMORY) {
+ ce->hunk->pos = ce->hunk->last;
+ }
+
+ if (ce->hunk->type & NGX_HUNK_FILE) {
+ ce->hunk->file_pos = ce->hunk->file_last;
+ }
+
+ continue;
+ }
+
+ if (ce->hunk->type & NGX_HUNK_IN_MEMORY) {
+ ce->hunk->pos += sent;
+ }
+
+ if (ce->hunk->type & NGX_HUNK_FILE) {
+ ce->hunk->file_pos += sent;
+ }
+
+ break;
+ }
+
+ ngx_destroy_array(&trailer);
+ ngx_destroy_array(&header);
+
+ return ce;
+}
diff --git a/src/os/unix/ngx_solaris_config.h b/src/os/unix/ngx_solaris_config.h
index 786cf0b..1977501 100644
--- a/src/os/unix/ngx_solaris_config.h
+++ b/src/os/unix/ngx_solaris_config.h
@@ -22,6 +22,7 @@
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
+#include <netdb.h>
typedef uint32_t u_int32_t;