|  |  | 
|  | /* | 
|  | * Copyright (C) Igor Sysoev | 
|  | */ | 
|  |  | 
|  |  | 
|  | #include <ngx_config.h> | 
|  | #include <ngx_core.h> | 
|  | #include <ngx_event.h> | 
|  |  | 
|  |  | 
|  | typedef struct { | 
|  | ngx_connection_t      *connection; | 
|  |  | 
|  | struct sockaddr       *sockaddr; | 
|  | socklen_t              socklen; | 
|  |  | 
|  | ngx_str_r              server; | 
|  | ngx_str_r              name; | 
|  |  | 
|  | ngx_event_handler_pt   handler; | 
|  |  | 
|  | ngx_log_t             *pool; | 
|  | ngx_log_t             *log; | 
|  | } ngx_resolver_t; | 
|  |  | 
|  |  | 
|  | ngx_int_t | 
|  | ngx_gethostbyname(ngx_resolver_t *r) | 
|  | { | 
|  | ngx_socket_t  s; | 
|  |  | 
|  | if (r->connection) { | 
|  | return NGX_OK; | 
|  | } | 
|  |  | 
|  | s = ngx_socket(AF_INET, SOCK_DGRAM, 0); | 
|  |  | 
|  | ngx_log_debug1(NGX_LOG_DEBUG_EVENT, r->log, 0, "socket %d", s); | 
|  |  | 
|  | if (s == -1) { | 
|  | ngx_log_error(NGX_LOG_ALERT, r->log, ngx_socket_errno, | 
|  | ngx_socket_n " failed"); | 
|  | return NGX_ERROR; | 
|  | } | 
|  |  | 
|  | c = ngx_get_connection(s, r->log); | 
|  |  | 
|  | if (c == NULL) { | 
|  | if (ngx_close_socket(s) == -1) { | 
|  | ngx_log_error(NGX_LOG_ALERT, r->log, ngx_socket_errno, | 
|  | ngx_close_socket_n "failed"); | 
|  | } | 
|  |  | 
|  | return NGX_ERROR; | 
|  | } | 
|  |  | 
|  | rev = c->read; | 
|  | wev = c->write; | 
|  |  | 
|  | rev->log = pc->log; | 
|  | wev->log = pc->log; | 
|  |  | 
|  | r->connection = c; | 
|  |  | 
|  | /* | 
|  | * TODO: MT: - ngx_atomic_fetch_add() | 
|  | *             or protection by critical section or mutex | 
|  | * | 
|  | * TODO: MP: - allocated in a shared memory | 
|  | *           - ngx_atomic_fetch_add() | 
|  | *             or protection by critical section or mutex | 
|  | */ | 
|  |  | 
|  | c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1); | 
|  |  | 
|  | #if (NGX_THREADS) | 
|  | rev->lock = pc->lock; | 
|  | wev->lock = pc->lock; | 
|  | rev->own_lock = &c->lock; | 
|  | wev->own_lock = &c->lock; | 
|  | #endif | 
|  |  | 
|  | ngx_log_debug3(NGX_LOG_DEBUG_EVENT, pc->log, 0, | 
|  | "connect to %V, fd:%d #%d", &r->server, s, c->number); | 
|  |  | 
|  | rc = connect(s, r->sockaddr, r->socklen); | 
|  |  | 
|  | if (rc == -1) { | 
|  | ngx_log_error(level, r->log, ngx_socket_errno, | 
|  | "connect() to %V failed", &r->server); | 
|  |  | 
|  | return NGX_ERROR; | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | if (ngx_add_conn) { | 
|  | if (ngx_add_conn(c) == NGX_ERROR) { | 
|  | return NGX_ERROR; | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | if (ngx_add_conn) { | 
|  | if (rc == -1) { | 
|  |  | 
|  | /* NGX_EINPROGRESS */ | 
|  |  | 
|  | return NGX_AGAIN; | 
|  | } | 
|  |  | 
|  | ngx_log_debug0(NGX_LOG_DEBUG_EVENT, pc->log, 0, "connected"); | 
|  |  | 
|  | wev->ready = 1; | 
|  |  | 
|  | return NGX_OK; | 
|  | } | 
|  |  | 
|  | if (ngx_event_flags & NGX_USE_AIO_EVENT) { | 
|  |  | 
|  | ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pc->log, ngx_socket_errno, | 
|  | "connect(): %d", rc); | 
|  |  | 
|  | /* aio, iocp */ | 
|  |  | 
|  | if (ngx_blocking(s) == -1) { | 
|  | ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, | 
|  | ngx_blocking_n " failed"); | 
|  | return NGX_ERROR; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * FreeBSD's aio allows to post an operation on non-connected socket. | 
|  | * NT does not support it. | 
|  | * | 
|  | * TODO: check in Win32, etc. As workaround we can use NGX_ONESHOT_EVENT | 
|  | */ | 
|  |  | 
|  | rev->ready = 1; | 
|  | wev->ready = 1; | 
|  |  | 
|  | return NGX_OK; | 
|  | } | 
|  |  | 
|  | if (ngx_event_flags & NGX_USE_CLEAR_EVENT) { | 
|  |  | 
|  | /* kqueue */ | 
|  |  | 
|  | event = NGX_CLEAR_EVENT; | 
|  |  | 
|  | } else { | 
|  |  | 
|  | /* select, poll, /dev/poll */ | 
|  |  | 
|  | event = NGX_LEVEL_EVENT; | 
|  | } | 
|  |  | 
|  | if (ngx_add_event(rev, NGX_READ_EVENT, event) != NGX_OK) { | 
|  | return NGX_ERROR; | 
|  | } | 
|  |  | 
|  | if (rc == -1) { | 
|  |  | 
|  | /* NGX_EINPROGRESS */ | 
|  |  | 
|  | if (ngx_add_event(wev, NGX_WRITE_EVENT, event) != NGX_OK) { | 
|  | return NGX_ERROR; | 
|  | } | 
|  |  | 
|  | return NGX_AGAIN; | 
|  | } | 
|  |  | 
|  | ngx_log_debug0(NGX_LOG_DEBUG_EVENT, pc->log, 0, "connected"); | 
|  |  | 
|  | wev->ready = 1; | 
|  |  | 
|  | return NGX_OK; | 
|  | } |