Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.15.11 ]​[ nginx-1.14.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, value;
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 (pc->so_keepalive) {
0077         value = 1;
0078 
0079         if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE,
0080                        (const void *) &value, sizeof(int))
0081             == -1)
0082         {
0083             ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
0084                           "setsockopt(SO_KEEPALIVE) failed, ignored");
0085         }
0086     }
0087 
0088     if (ngx_nonblocking(s) == -1) {
0089         ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
0090                       ngx_nonblocking_n " failed");
0091 
0092         goto failed;
0093     }
0094 
0095     if (pc->local) {
0096 
0097 #if (NGX_HAVE_TRANSPARENT_PROXY)
0098         if (pc->transparent) {
0099             if (ngx_event_connect_set_transparent(pc, s) != NGX_OK) {
0100                 goto failed;
0101             }
0102         }
0103 #endif
0104 
0105 #if (NGX_HAVE_IP_BIND_ADDRESS_NO_PORT || NGX_LINUX)
0106         port = ngx_inet_get_port(pc->local->sockaddr);
0107 #endif
0108 
0109 #if (NGX_HAVE_IP_BIND_ADDRESS_NO_PORT)
0110 
0111         if (pc->sockaddr->sa_family != AF_UNIX && port == 0) {
0112             static int  bind_address_no_port = 1;
0113 
0114             if (bind_address_no_port) {
0115                 if (setsockopt(s, IPPROTO_IP, IP_BIND_ADDRESS_NO_PORT,
0116                                (const void *) &bind_address_no_port,
0117                                sizeof(int)) == -1)
0118                 {
0119                     err = ngx_socket_errno;
0120 
0121                     if (err != NGX_EOPNOTSUPP && err != NGX_ENOPROTOOPT) {
0122                         ngx_log_error(NGX_LOG_ALERT, pc->log, err,
0123                                       "setsockopt(IP_BIND_ADDRESS_NO_PORT) "
0124                                       "failed, ignored");
0125 
0126                     } else {
0127                         bind_address_no_port = 0;
0128                     }
0129                 }
0130             }
0131         }
0132 
0133 #endif
0134 
0135 #if (NGX_LINUX)
0136 
0137         if (pc->type == SOCK_DGRAM && port != 0) {
0138             int  reuse_addr = 1;
0139 
0140             if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
0141                            (const void *) &reuse_addr, sizeof(int))
0142                  == -1)
0143             {
0144                 ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
0145                               "setsockopt(SO_REUSEADDR) failed");
0146                 goto failed;
0147             }
0148         }
0149 
0150 #endif
0151 
0152         if (bind(s, pc->local->sockaddr, pc->local->socklen) == -1) {
0153             ngx_log_error(NGX_LOG_CRIT, pc->log, ngx_socket_errno,
0154                           "bind(%V) failed", &pc->local->name);
0155 
0156             goto failed;
0157         }
0158     }
0159 
0160     if (type == SOCK_STREAM) {
0161         c->recv = ngx_recv;
0162         c->send = ngx_send;
0163         c->recv_chain = ngx_recv_chain;
0164         c->send_chain = ngx_send_chain;
0165 
0166         c->sendfile = 1;
0167 
0168         if (pc->sockaddr->sa_family == AF_UNIX) {
0169             c->tcp_nopush = NGX_TCP_NOPUSH_DISABLED;
0170             c->tcp_nodelay = NGX_TCP_NODELAY_DISABLED;
0171 
0172 #if (NGX_SOLARIS)
0173             /* Solaris's sendfilev() supports AF_NCA, AF_INET, and AF_INET6 */
0174             c->sendfile = 0;
0175 #endif
0176         }
0177 
0178     } else { /* type == SOCK_DGRAM */
0179         c->recv = ngx_udp_recv;
0180         c->send = ngx_send;
0181         c->send_chain = ngx_udp_send_chain;
0182     }
0183 
0184     c->log_error = pc->log_error;
0185 
0186     rev = c->read;
0187     wev = c->write;
0188 
0189     rev->log = pc->log;
0190     wev->log = pc->log;
0191 
0192     pc->connection = c;
0193 
0194     c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1);
0195 
0196     if (ngx_add_conn) {
0197         if (ngx_add_conn(c) == NGX_ERROR) {
0198             goto failed;
0199         }
0200     }
0201 
0202     ngx_log_debug3(NGX_LOG_DEBUG_EVENT, pc->log, 0,
0203                    "connect to %V, fd:%d #%uA", pc->name, s, c->number);
0204 
0205     rc = connect(s, pc->sockaddr, pc->socklen);
0206 
0207     if (rc == -1) {
0208         err = ngx_socket_errno;
0209 
0210 
0211         if (err != NGX_EINPROGRESS
0212 #if (NGX_WIN32)
0213             /* Winsock returns WSAEWOULDBLOCK (NGX_EAGAIN) */
0214             && err != NGX_EAGAIN
0215 #endif
0216             )
0217         {
0218             if (err == NGX_ECONNREFUSED
0219 #if (NGX_LINUX)
0220                 /*
0221                  * Linux returns EAGAIN instead of ECONNREFUSED
0222                  * for unix sockets if listen queue is full
0223                  */
0224                 || err == NGX_EAGAIN
0225 #endif
0226                 || err == NGX_ECONNRESET
0227                 || err == NGX_ENETDOWN
0228                 || err == NGX_ENETUNREACH
0229                 || err == NGX_EHOSTDOWN
0230                 || err == NGX_EHOSTUNREACH)
0231             {
0232                 level = NGX_LOG_ERR;
0233 
0234             } else {
0235                 level = NGX_LOG_CRIT;
0236             }
0237 
0238             ngx_log_error(level, c->log, err, "connect() to %V failed",
0239                           pc->name);
0240 
0241             ngx_close_connection(c);
0242             pc->connection = NULL;
0243 
0244             return NGX_DECLINED;
0245         }
0246     }
0247 
0248     if (ngx_add_conn) {
0249         if (rc == -1) {
0250 
0251             /* NGX_EINPROGRESS */
0252 
0253             return NGX_AGAIN;
0254         }
0255 
0256         ngx_log_debug0(NGX_LOG_DEBUG_EVENT, pc->log, 0, "connected");
0257 
0258         wev->ready = 1;
0259 
0260         return NGX_OK;
0261     }
0262 
0263     if (ngx_event_flags & NGX_USE_IOCP_EVENT) {
0264 
0265         ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pc->log, ngx_socket_errno,
0266                        "connect(): %d", rc);
0267 
0268         if (ngx_blocking(s) == -1) {
0269             ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
0270                           ngx_blocking_n " failed");
0271             goto failed;
0272         }
0273 
0274         /*
0275          * FreeBSD's aio allows to post an operation on non-connected socket.
0276          * NT does not support it.
0277          *
0278          * TODO: check in Win32, etc. As workaround we can use NGX_ONESHOT_EVENT
0279          */
0280 
0281         rev->ready = 1;
0282         wev->ready = 1;
0283 
0284         return NGX_OK;
0285     }
0286 
0287     if (ngx_event_flags & NGX_USE_CLEAR_EVENT) {
0288 
0289         /* kqueue */
0290 
0291         event = NGX_CLEAR_EVENT;
0292 
0293     } else {
0294 
0295         /* select, poll, /dev/poll */
0296 
0297         event = NGX_LEVEL_EVENT;
0298     }
0299 
0300     if (ngx_add_event(rev, NGX_READ_EVENT, event) != NGX_OK) {
0301         goto failed;
0302     }
0303 
0304     if (rc == -1) {
0305 
0306         /* NGX_EINPROGRESS */
0307 
0308         if (ngx_add_event(wev, NGX_WRITE_EVENT, event) != NGX_OK) {
0309             goto failed;
0310         }
0311 
0312         return NGX_AGAIN;
0313     }
0314 
0315     ngx_log_debug0(NGX_LOG_DEBUG_EVENT, pc->log, 0, "connected");
0316 
0317     wev->ready = 1;
0318 
0319     return NGX_OK;
0320 
0321 failed:
0322 
0323     ngx_close_connection(c);
0324     pc->connection = NULL;
0325 
0326     return NGX_ERROR;
0327 }
0328 
0329 
0330 #if (NGX_HAVE_TRANSPARENT_PROXY)
0331 
0332 static ngx_int_t
0333 ngx_event_connect_set_transparent(ngx_peer_connection_t *pc, ngx_socket_t s)
0334 {
0335     int  value;
0336 
0337     value = 1;
0338 
0339 #if defined(SO_BINDANY)
0340 
0341     if (setsockopt(s, SOL_SOCKET, SO_BINDANY,
0342                    (const void *) &value, sizeof(int)) == -1)
0343     {
0344         ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
0345                       "setsockopt(SO_BINDANY) failed");
0346         return NGX_ERROR;
0347     }
0348 
0349 #else
0350 
0351     switch (pc->local->sockaddr->sa_family) {
0352 
0353     case AF_INET:
0354 
0355 #if defined(IP_TRANSPARENT)
0356 
0357         if (setsockopt(s, IPPROTO_IP, IP_TRANSPARENT,
0358                        (const void *) &value, sizeof(int)) == -1)
0359         {
0360             ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
0361                           "setsockopt(IP_TRANSPARENT) failed");
0362             return NGX_ERROR;
0363         }
0364 
0365 #elif defined(IP_BINDANY)
0366 
0367         if (setsockopt(s, IPPROTO_IP, IP_BINDANY,
0368                        (const void *) &value, sizeof(int)) == -1)
0369         {
0370             ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
0371                           "setsockopt(IP_BINDANY) failed");
0372             return NGX_ERROR;
0373         }
0374 
0375 #endif
0376 
0377         break;
0378 
0379 #if (NGX_HAVE_INET6)
0380 
0381     case AF_INET6:
0382 
0383 #if defined(IPV6_TRANSPARENT)
0384 
0385         if (setsockopt(s, IPPROTO_IPV6, IPV6_TRANSPARENT,
0386                        (const void *) &value, sizeof(int)) == -1)
0387         {
0388             ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
0389                           "setsockopt(IPV6_TRANSPARENT) failed");
0390             return NGX_ERROR;
0391         }
0392 
0393 #elif defined(IPV6_BINDANY)
0394 
0395         if (setsockopt(s, IPPROTO_IPV6, IPV6_BINDANY,
0396                        (const void *) &value, sizeof(int)) == -1)
0397         {
0398             ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
0399                           "setsockopt(IPV6_BINDANY) failed");
0400             return NGX_ERROR;
0401         }
0402 
0403 #else
0404 
0405         ngx_log_error(NGX_LOG_ALERT, pc->log, 0,
0406                       "could not enable transparent proxying for IPv6 "
0407                       "on this platform");
0408 
0409         return NGX_ERROR;
0410 
0411 #endif
0412 
0413         break;
0414 
0415 #endif /* NGX_HAVE_INET6 */
0416 
0417     }
0418 
0419 #endif /* SO_BINDANY */
0420 
0421     return NGX_OK;
0422 }
0423 
0424 #endif
0425 
0426 
0427 ngx_int_t
0428 ngx_event_get_peer(ngx_peer_connection_t *pc, void *data)
0429 {
0430     return NGX_OK;
0431 }