Mercurial > hg > nginx-ranges
diff src/core/ngx_connection.c @ 0:f0b350454894 NGINX_0_1_0
nginx 0.1.0
*) The first public version.
author | Igor Sysoev <http://sysoev.ru> |
---|---|
date | Mon, 04 Oct 2004 00:00:00 +0400 |
parents | |
children | cc9f381affaa |
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/src/core/ngx_connection.c @@ -0,0 +1,453 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include <ngx_config.h> +#include <ngx_core.h> +#include <ngx_event.h> + + +ngx_os_io_t ngx_io; + + +ngx_listening_t *ngx_listening_inet_stream_socket(ngx_conf_t *cf, + in_addr_t addr, + in_port_t port) +{ + size_t len; + ngx_listening_t *ls; + struct sockaddr_in *addr_in; + + if (!(ls = ngx_array_push(&cf->cycle->listening))) { + return NULL; + } + + ngx_memzero(ls, sizeof(ngx_listening_t)); + + if (!(addr_in = ngx_pcalloc(cf->pool, sizeof(struct sockaddr_in)))) { + return NULL; + } + +#if (HAVE_SIN_LEN) + addr_in->sin_len = sizeof(struct sockaddr_in); +#endif + addr_in->sin_family = AF_INET; + addr_in->sin_addr.s_addr = addr; + addr_in->sin_port = htons(port); + + if (!(ls->addr_text.data = ngx_palloc(cf->pool, INET_ADDRSTRLEN + 6))) { + return NULL; + } + + len = ngx_inet_ntop(AF_INET, &addr, ls->addr_text.data, INET_ADDRSTRLEN); + ls->addr_text.len = ngx_snprintf((char *) ls->addr_text.data + len, + 6, ":%d", port); + + ls->fd = (ngx_socket_t) -1; + ls->family = AF_INET; + ls->type = SOCK_STREAM; + ls->protocol = IPPROTO_IP; +#if (WIN32) + ls->flags = WSA_FLAG_OVERLAPPED; +#endif + ls->sockaddr = (struct sockaddr *) addr_in; + ls->socklen = sizeof(struct sockaddr_in); + ls->addr = offsetof(struct sockaddr_in, sin_addr); + ls->addr_text_max_len = INET_ADDRSTRLEN; + + return ls; +} + + +ngx_int_t ngx_set_inherited_sockets(ngx_cycle_t *cycle) +{ + ngx_uint_t i; + ngx_listening_t *ls; + struct sockaddr_in *addr_in; + + ls = cycle->listening.elts; + for (i = 0; i < cycle->listening.nelts; i++) { + + /* AF_INET only */ + + ls[i].sockaddr = ngx_palloc(cycle->pool, sizeof(struct sockaddr_in)); + if (ls[i].sockaddr == NULL) { + return NGX_ERROR; + } + + ls[i].socklen = sizeof(struct sockaddr_in); + if (getsockname(ls[i].fd, ls[i].sockaddr, &ls[i].socklen) == -1) { + ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_socket_errno, + "getsockname() of the inherited " + "socket #%d failed", ls[i].fd); + ls[i].ignore = 1; + continue; + } + + addr_in = (struct sockaddr_in *) ls[i].sockaddr; + + if (addr_in->sin_family != AF_INET) { + ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_socket_errno, + "the inherited socket #%d has " + "unsupported family", ls[i].fd); + ls[i].ignore = 1; + continue; + } + ls[i].addr_text_max_len = INET_ADDRSTRLEN; + + ls[i].addr_text.data = ngx_palloc(cycle->pool, ls[i].addr_text_max_len); + if (ls[i].addr_text.data == NULL) { + return NGX_ERROR; + } + + ls[i].family = addr_in->sin_family; + ls[i].addr_text.len = ngx_sock_ntop(ls[i].family, ls[i].sockaddr, + ls[i].addr_text.data, + ls[i].addr_text_max_len); + if (ls[i].addr_text.len == 0) { + return NGX_ERROR; + } + } + + return NGX_OK; +} + + +ngx_int_t ngx_open_listening_sockets(ngx_cycle_t *cycle) +{ + ngx_uint_t tries, failed, reuseaddr, i; + ngx_err_t err; + ngx_log_t *log; + ngx_socket_t s; + ngx_listening_t *ls; + + reuseaddr = 1; +#if (NGX_SUPPRESS_WARN) + failed = 0; +#endif + + log = cycle->log; + + /* TODO: tries configurable */ + + for (tries = /* STUB */ 5; tries; tries--) { + failed = 0; + + /* for each listening socket */ + + ls = cycle->listening.elts; + for (i = 0; i < cycle->listening.nelts; i++) { + + if (ls[i].ignore) { + continue; + } + + if (ls[i].fd != -1) { + continue; + } + + if (ls[i].inherited) { + + /* TODO: close on exit */ + /* TODO: nonblocking */ + /* TODO: deferred accept */ + + continue; + } + + s = ngx_socket(ls[i].family, ls[i].type, ls[i].protocol, + ls[i].flags); + + if (s == -1) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, + ngx_socket_n " %s failed", ls[i].addr_text.data); + return NGX_ERROR; + } + +#if (WIN32) + /* + * Winsock assignes a socket number divisible by 4 + * so to find a connection we divide a socket number by 4. + */ + + if (s % 4) { + ngx_log_error(NGX_LOG_EMERG, ls->log, 0, + ngx_socket_n " created socket %d", s); + return NGX_ERROR; + } +#endif + + if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, + (const void *) &reuseaddr, sizeof(int)) == -1) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, + "setsockopt(SO_REUSEADDR) %s failed", + ls[i].addr_text.data); + return NGX_ERROR; + } + + /* TODO: close on exit */ + + if (!(ngx_event_flags & NGX_USE_AIO_EVENT)) { + if (ngx_nonblocking(s) == -1) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, + ngx_nonblocking_n " %s failed", + ls[i].addr_text.data); + return NGX_ERROR; + } + } + +#if 0 + if (ls[i].nonblocking) { + if (ngx_nonblocking(s) == -1) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, + ngx_nonblocking_n " %s failed", + ls[i].addr_text.data); + return NGX_ERROR; + } + } +#endif + + if (bind(s, ls[i].sockaddr, ls[i].socklen) == -1) { + err = ngx_socket_errno; + ngx_log_error(NGX_LOG_EMERG, log, err, + "bind() to %s failed", ls[i].addr_text.data); + + if (err != NGX_EADDRINUSE) + return NGX_ERROR; + + if (ngx_close_socket(s) == -1) + ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, + ngx_close_socket_n " %s failed", + ls[i].addr_text.data); + + failed = 1; + continue; + } + + if (listen(s, ls[i].backlog) == -1) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, + "listen() to %s failed", ls[i].addr_text.data); + return NGX_ERROR; + } + + /* TODO: deferred accept */ + + ls[i].fd = s; + } + + if (!failed) + break; + + /* TODO: delay configurable */ + + ngx_log_error(NGX_LOG_NOTICE, log, 0, + "try again to bind() after 500ms"); + ngx_msleep(500); + } + + if (failed) { + ngx_log_error(NGX_LOG_EMERG, log, 0, "still can not bind()"); + return NGX_ERROR; + } + + return NGX_OK; +} + + +void ngx_close_listening_sockets(ngx_cycle_t *cycle) +{ + ngx_uint_t i; + ngx_socket_t fd; + ngx_listening_t *ls; + + if (ngx_event_flags & NGX_USE_IOCP_EVENT) { + return; + } + + ngx_accept_mutex_held = 0; + ngx_accept_mutex = NULL; + + ls = cycle->listening.elts; + for (i = 0; i < cycle->listening.nelts; i++) { + fd = ls[i].fd; + +#if (WIN32) + /* + * Winsock assignes a socket number divisible by 4 + * so to find a connection we divide a socket number by 4. + */ + + fd /= 4; +#endif + + if (ngx_event_flags & NGX_USE_RTSIG_EVENT) { + if (cycle->connections[fd].read->active) { + ngx_del_conn(&cycle->connections[fd], NGX_CLOSE_EVENT); + } + + } else { + if (cycle->read_events[fd].active) { + ngx_del_event(&cycle->read_events[fd], + NGX_READ_EVENT, NGX_CLOSE_EVENT); + } + } + + if (ngx_close_socket(ls[i].fd) == -1) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno, + ngx_close_socket_n " %s failed", + ls[i].addr_text.data); + } + + cycle->connections[fd].fd = (ngx_socket_t) -1; + } +} + + +void ngx_close_connection(ngx_connection_t *c) +{ + ngx_socket_t fd; + + if (c->pool == NULL) { + ngx_log_error(NGX_LOG_ALERT, c->log, 0, "connection already closed"); + return; + } + +#if (NGX_OPENSSL) + + if (c->ssl) { + if (ngx_ssl_shutdown(c) == NGX_AGAIN) { + c->read->event_handler = ngx_ssl_close_handler; + c->write->event_handler = ngx_ssl_close_handler; + return; + } + } + +#endif + + if (c->read->timer_set) { + ngx_del_timer(c->read); + } + + if (c->write->timer_set) { + ngx_del_timer(c->write); + } + + if (ngx_del_conn) { + ngx_del_conn(c, NGX_CLOSE_EVENT); + + } else { + if (c->read->active || c->read->disabled) { + ngx_del_event(c->read, NGX_READ_EVENT, NGX_CLOSE_EVENT); + } + + if (c->write->active || c->write->disabled) { + ngx_del_event(c->write, NGX_WRITE_EVENT, NGX_CLOSE_EVENT); + } + } + +#if (NGX_THREADS) + + /* + * we have to clean the connection information before the closing + * because another thread may reopen the same file descriptor + * before we clean the connection + */ + + if (ngx_mutex_lock(ngx_posted_events_mutex) == NGX_OK) { + + if (c->read->prev) { + ngx_delete_posted_event(c->read); + } + + if (c->write->prev) { + ngx_delete_posted_event(c->write); + } + + c->read->closed = 1; + c->write->closed = 1; + + if (c->single_connection) { + ngx_unlock(&c->lock); + c->read->locked = 0; + c->write->locked = 0; + } + + ngx_mutex_unlock(ngx_posted_events_mutex); + } + +#else + + if (c->read->prev) { + ngx_delete_posted_event(c->read); + } + + if (c->write->prev) { + ngx_delete_posted_event(c->write); + } + + c->read->closed = 1; + c->write->closed = 1; + +#endif + + fd = c->fd; + c->fd = (ngx_socket_t) -1; + c->data = NULL; + + ngx_destroy_pool(c->pool); + + if (ngx_close_socket(fd) == -1) { + + /* we use ngx_cycle->log because c->log was in c->pool */ + + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno, + ngx_close_socket_n " failed"); + } +} + + + +ngx_int_t ngx_connection_error(ngx_connection_t *c, ngx_err_t err, char *text) +{ + ngx_uint_t level; + + if (err == NGX_ECONNRESET + && c->log_error == NGX_ERROR_IGNORE_ECONNRESET) + { + return 0; + } + + if (err == NGX_ECONNRESET +#if !(WIN32) + || err == NGX_EPIPE +#endif + || err == NGX_ENOTCONN + || err == NGX_ECONNREFUSED + || err == NGX_EHOSTUNREACH) + { + + switch (c->log_error) { + + case NGX_ERROR_IGNORE_ECONNRESET: + case NGX_ERROR_INFO: + level = NGX_LOG_INFO; + break; + + case NGX_ERROR_ERR: + level = NGX_LOG_ERR; + break; + + default: + level = NGX_LOG_CRIT; + } + + } else { + level = NGX_LOG_CRIT; + } + + ngx_log_error(level, c->log, err, text); + + return NGX_ERROR; +}