Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.13.12 ]​[ nginx-1.12.2 ]​

0001 
0002 /*
0003  * Copyright (C) Igor Sysoev
0004  * Copyright (C) Nginx, Inc.
0005  */
0006 
0007 
0008 #include <ngx_config.h>
0009 #include <ngx_core.h>
0010 #include <ngx_event.h>
0011 #include <ngx_event_connect.h>
0012 
0013 
0014 #if (NGX_HAVE_TRANSPARENT_PROXY)
0015 static ngx_int_t ngx_event_connect_set_transparent(ngx_peer_connection_t *pc,
0016     ngx_socket_t s);
0017 #endif
0018 
0019 
0020 ngx_int_t
0021 ngx_event_connect_peer(ngx_peer_connection_t *pc)
0022 {
0023     int                rc, type;
0024 #if (NGX_HAVE_IP_BIND_ADDRESS_NO_PORT || NGX_LINUX)
0025     in_port_t          port;
0026 #endif
0027     ngx_int_t          event;
0028     ngx_err_t          err;
0029     ngx_uint_t         level;
0030     ngx_socket_t       s;
0031     ngx_event_t       *rev, *wev;
0032     ngx_connection_t  *c;
0033 
0034     rc = pc->get(pc, pc->data);
0035     if (rc != NGX_OK) {
0036         return rc;
0037     }
0038 
0039     type = (pc->type ? pc->type : SOCK_STREAM);
0040 
0041     s = ngx_socket(pc->sockaddr->sa_family, type, 0);
0042 
0043     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, pc->log, 0, "%s socket %d",
0044                    (type == SOCK_STREAM) ? "stream" : "dgram", s);
0045 
0046     if (s == (ngx_socket_t) -1) {
0047         ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
0048                       ngx_socket_n " failed");
0049         return NGX_ERROR;
0050     }
0051 
0052 
0053     c = ngx_get_connection(s, pc->log);
0054 
0055     if (c == NULL) {
0056         if (ngx_close_socket(s) == -1) {
0057             ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
0058                           ngx_close_socket_n "failed");
0059         }
0060 
0061         return NGX_ERROR;
0062     }
0063 
0064     c->type = type;
0065 
0066     if (pc->rcvbuf) {
0067         if (setsockopt(s, SOL_SOCKET, SO_RCVBUF,
0068                        (const void *) &pc->rcvbuf, sizeof(int)) == -1)
0069         {
0070             ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
0071                           "setsockopt(SO_RCVBUF) failed");
0072             goto failed;
0073         }
0074     }
0075 
0076     if (ngx_nonblocking(s) == -1) {
0077         ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
0078                       ngx_nonblocking_n " failed");
0079 
0080         goto failed;
0081     }
0082 
0083     if (pc->local) {
0084 
0085 #if (NGX_HAVE_TRANSPARENT_PROXY)
0086         if (pc->transparent) {
0087             if (ngx_event_connect_set_transparent(pc, s) != NGX_OK) {
0088                 goto failed;
0089             }
0090         }
0091 #endif
0092 
0093 #if (NGX_HAVE_IP_BIND_ADDRESS_NO_PORT || NGX_LINUX)
0094         port = ngx_inet_get_port(pc->local->sockaddr);
0095 #endif
0096 
0097 #if (NGX_HAVE_IP_BIND_ADDRESS_NO_PORT)
0098 
0099         if (pc->sockaddr->sa_family != AF_UNIX && port == 0) {
0100             static int  bind_address_no_port = 1;
0101 
0102             if (bind_address_no_port) {
0103                 if (setsockopt(s, IPPROTO_IP, IP_BIND_ADDRESS_NO_PORT,
0104                                (const void *) &bind_address_no_port,
0105                                sizeof(int)) == -1)
0106                 {
0107                     err = ngx_socket_errno;
0108 
0109                     if (err != NGX_EOPNOTSUPP && err != NGX_ENOPROTOOPT) {
0110                         ngx_log_error(NGX_LOG_ALERT, pc->log, err,
0111                                       "setsockopt(IP_BIND_ADDRESS_NO_PORT) "
0112                                       "failed, ignored");
0113 
0114                     } else {
0115                         bind_address_no_port = 0;
0116                     }
0117                 }
0118             }
0119         }
0120 
0121 #endif
0122 
0123 #if (NGX_LINUX)
0124 
0125         if (pc->type == SOCK_DGRAM && port != 0) {
0126             int  reuse_addr = 1;
0127 
0128             if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
0129                            (const void *) &reuse_addr, sizeof(int))
0130                  == -1)
0131             {
0132                 ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
0133                               "setsockopt(SO_REUSEADDR) failed");
0134                 goto failed;
0135             }
0136         }
0137 
0138 #endif
0139 
0140         if (bind(s, pc->local->sockaddr, pc->local->socklen) == -1) {
0141             ngx_log_error(NGX_LOG_CRIT, pc->log, ngx_socket_errno,
0142                           "bind(%V) failed", &pc->local->name);
0143 
0144             goto failed;
0145         }
0146     }
0147 
0148     if (type == SOCK_STREAM) {
0149         c->recv = ngx_recv;
0150         c->send = ngx_send;
0151         c->recv_chain = ngx_recv_chain;
0152         c->send_chain = ngx_send_chain;
0153 
0154         c->sendfile = 1;
0155 
0156         if (pc->sockaddr->sa_family == AF_UNIX) {
0157             c->tcp_nopush = NGX_TCP_NOPUSH_DISABLED;
0158             c->tcp_nodelay = NGX_TCP_NODELAY_DISABLED;
0159 
0160 #if (NGX_SOLARIS)
0161             /* Solaris's sendfilev() supports AF_NCA, AF_INET, and AF_INET6 */
0162             c->sendfile = 0;
0163 #endif
0164         }
0165 
0166     } else { /* type == SOCK_DGRAM */
0167         c->recv = ngx_udp_recv;
0168         c->send = ngx_send;
0169         c->send_chain = ngx_udp_send_chain;
0170     }
0171 
0172     c->log_error = pc->log_error;
0173 
0174     rev = c->read;
0175     wev = c->write;
0176 
0177     rev->log = pc->log;
0178     wev->log = pc->log;
0179 
0180     pc->connection = c;
0181 
0182     c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1);
0183 
0184     if (ngx_add_conn) {
0185         if (ngx_add_conn(c) == NGX_ERROR) {
0186             goto failed;
0187         }
0188     }
0189 
0190     ngx_log_debug3(NGX_LOG_DEBUG_EVENT, pc->log, 0,
0191                    "connect to %V, fd:%d #%uA", pc->name, s, c->number);
0192 
0193     rc = connect(s, pc->sockaddr, pc->socklen);
0194 
0195     if (rc == -1) {
0196         err = ngx_socket_errno;
0197 
0198 
0199         if (err != NGX_EINPROGRESS
0200 #if (NGX_WIN32)
0201             /* Winsock returns WSAEWOULDBLOCK (NGX_EAGAIN) */
0202             && err != NGX_EAGAIN
0203 #endif
0204             )
0205         {
0206             if (err == NGX_ECONNREFUSED
0207 #if (NGX_LINUX)
0208                 /*
0209                  * Linux returns EAGAIN instead of ECONNREFUSED
0210                  * for unix sockets if listen queue is full
0211                  */
0212                 || err == NGX_EAGAIN
0213 #endif
0214                 || err == NGX_ECONNRESET
0215                 || err == NGX_ENETDOWN
0216                 || err == NGX_ENETUNREACH
0217                 || err == NGX_EHOSTDOWN
0218                 || err == NGX_EHOSTUNREACH)
0219             {
0220                 level = NGX_LOG_ERR;
0221 
0222             } else {
0223                 level = NGX_LOG_CRIT;
0224             }
0225 
0226             ngx_log_error(level, c->log, err, "connect() to %V failed",
0227                           pc->name);
0228 
0229             ngx_close_connection(c);
0230             pc->connection = NULL;
0231 
0232             return NGX_DECLINED;
0233         }
0234     }
0235 
0236     if (ngx_add_conn) {
0237         if (rc == -1) {
0238 
0239             /* NGX_EINPROGRESS */
0240 
0241             return NGX_AGAIN;
0242         }
0243 
0244         ngx_log_debug0(NGX_LOG_DEBUG_EVENT, pc->log, 0, "connected");
0245 
0246         wev->ready = 1;
0247 
0248         return NGX_OK;
0249     }
0250 
0251     if (ngx_event_flags & NGX_USE_IOCP_EVENT) {
0252 
0253         ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pc->log, ngx_socket_errno,
0254                        "connect(): %d", rc);
0255 
0256         if (ngx_blocking(s) == -1) {
0257             ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
0258                           ngx_blocking_n " failed");
0259             goto failed;
0260         }
0261 
0262         /*
0263          * FreeBSD's aio allows to post an operation on non-connected socket.
0264          * NT does not support it.
0265          *
0266          * TODO: check in Win32, etc. As workaround we can use NGX_ONESHOT_EVENT
0267          */
0268 
0269         rev->ready = 1;
0270         wev->ready = 1;
0271 
0272         return NGX_OK;
0273     }
0274 
0275     if (ngx_event_flags & NGX_USE_CLEAR_EVENT) {
0276 
0277         /* kqueue */
0278 
0279         event = NGX_CLEAR_EVENT;
0280 
0281     } else {
0282 
0283         /* select, poll, /dev/poll */
0284 
0285         event = NGX_LEVEL_EVENT;
0286     }
0287 
0288     if (ngx_add_event(rev, NGX_READ_EVENT, event) != NGX_OK) {
0289         goto failed;
0290     }
0291 
0292     if (rc == -1) {
0293 
0294         /* NGX_EINPROGRESS */
0295 
0296         if (ngx_add_event(wev, NGX_WRITE_EVENT, event) != NGX_OK) {
0297             goto failed;
0298         }
0299 
0300         return NGX_AGAIN;
0301     }
0302 
0303     ngx_log_debug0(NGX_LOG_DEBUG_EVENT, pc->log, 0, "connected");
0304 
0305     wev->ready = 1;
0306 
0307     return NGX_OK;
0308 
0309 failed:
0310 
0311     ngx_close_connection(c);
0312     pc->connection = NULL;
0313 
0314     return NGX_ERROR;
0315 }
0316 
0317 
0318 #if (NGX_HAVE_TRANSPARENT_PROXY)
0319 
0320 static ngx_int_t
0321 ngx_event_connect_set_transparent(ngx_peer_connection_t *pc, ngx_socket_t s)
0322 {
0323     int  value;
0324 
0325     value = 1;
0326 
0327 #if defined(SO_BINDANY)
0328 
0329     if (setsockopt(s, SOL_SOCKET, SO_BINDANY,
0330                    (const void *) &value, sizeof(int)) == -1)
0331     {
0332         ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
0333                       "setsockopt(SO_BINDANY) failed");
0334         return NGX_ERROR;
0335     }
0336 
0337 #else
0338 
0339     switch (pc->local->sockaddr->sa_family) {
0340 
0341     case AF_INET:
0342 
0343 #if defined(IP_TRANSPARENT)
0344 
0345         if (setsockopt(s, IPPROTO_IP, IP_TRANSPARENT,
0346                        (const void *) &value, sizeof(int)) == -1)
0347         {
0348             ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
0349                           "setsockopt(IP_TRANSPARENT) failed");
0350             return NGX_ERROR;
0351         }
0352 
0353 #elif defined(IP_BINDANY)
0354 
0355         if (setsockopt(s, IPPROTO_IP, IP_BINDANY,
0356                        (const void *) &value, sizeof(int)) == -1)
0357         {
0358             ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
0359                           "setsockopt(IP_BINDANY) failed");
0360             return NGX_ERROR;
0361         }
0362 
0363 #endif
0364 
0365         break;
0366 
0367 #if (NGX_HAVE_INET6)
0368 
0369     case AF_INET6:
0370 
0371 #if defined(IPV6_TRANSPARENT)
0372 
0373         if (setsockopt(s, IPPROTO_IPV6, IPV6_TRANSPARENT,
0374                        (const void *) &value, sizeof(int)) == -1)
0375         {
0376             ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
0377                           "setsockopt(IPV6_TRANSPARENT) failed");
0378             return NGX_ERROR;
0379         }
0380 
0381 #elif defined(IPV6_BINDANY)
0382 
0383         if (setsockopt(s, IPPROTO_IPV6, IPV6_BINDANY,
0384                        (const void *) &value, sizeof(int)) == -1)
0385         {
0386             ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
0387                           "setsockopt(IPV6_BINDANY) failed");
0388             return NGX_ERROR;
0389         }
0390 
0391 #endif
0392         break;
0393 
0394 #endif /* NGX_HAVE_INET6 */
0395 
0396     }
0397 
0398 #endif /* SO_BINDANY */
0399 
0400     return NGX_OK;
0401 }
0402 
0403 #endif
0404 
0405 
0406 ngx_int_t
0407 ngx_event_get_peer(ngx_peer_connection_t *pc, void *data)
0408 {
0409     return NGX_OK;
0410 }