src/event/ngx_event_connect.c - nginx source code

Functions defined

Source code


  1. /*
  2. * Copyright (C) Igor Sysoev
  3. * Copyright (C) Nginx, Inc.
  4. */


  5. #include <ngx_config.h>
  6. #include <ngx_core.h>
  7. #include <ngx_event.h>
  8. #include <ngx_event_connect.h>


  9. #if (NGX_HAVE_TRANSPARENT_PROXY)
  10. static ngx_int_t ngx_event_connect_set_transparent(ngx_peer_connection_t *pc,
  11.     ngx_socket_t s);
  12. #endif


  13. ngx_int_t
  14. ngx_event_connect_peer(ngx_peer_connection_t *pc)
  15. {
  16.     int                rc, type, value;
  17. #if (NGX_HAVE_IP_BIND_ADDRESS_NO_PORT || NGX_LINUX)
  18.     in_port_t          port;
  19. #endif
  20.     ngx_int_t          event;
  21.     ngx_err_t          err;
  22.     ngx_uint_t         level;
  23.     ngx_socket_t       s;
  24.     ngx_event_t       *rev, *wev;
  25.     ngx_connection_t  *c;

  26.     rc = pc->get(pc, pc->data);
  27.     if (rc != NGX_OK) {
  28.         return rc;
  29.     }

  30.     type = (pc->type ? pc->type : SOCK_STREAM);

  31.     s = ngx_socket(pc->sockaddr->sa_family, type, 0);

  32.     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, pc->log, 0, "%s socket %d",
  33.                    (type == SOCK_STREAM) ? "stream" : "dgram", s);

  34.     if (s == (ngx_socket_t) -1) {
  35.         ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
  36.                       ngx_socket_n " failed");
  37.         return NGX_ERROR;
  38.     }


  39.     c = ngx_get_connection(s, pc->log);

  40.     if (c == NULL) {
  41.         if (ngx_close_socket(s) == -1) {
  42.             ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
  43.                           ngx_close_socket_n " failed");
  44.         }

  45.         return NGX_ERROR;
  46.     }

  47.     c->type = type;

  48.     if (pc->rcvbuf) {
  49.         if (setsockopt(s, SOL_SOCKET, SO_RCVBUF,
  50.                        (const void *) &pc->rcvbuf, sizeof(int)) == -1)
  51.         {
  52.             ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
  53.                           "setsockopt(SO_RCVBUF) failed");
  54.             goto failed;
  55.         }
  56.     }

  57.     if (pc->so_keepalive) {
  58.         value = 1;

  59.         if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE,
  60.                        (const void *) &value, sizeof(int))
  61.             == -1)
  62.         {
  63.             ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
  64.                           "setsockopt(SO_KEEPALIVE) failed, ignored");
  65.         }
  66.     }

  67.     if (ngx_nonblocking(s) == -1) {
  68.         ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
  69.                       ngx_nonblocking_n " failed");

  70.         goto failed;
  71.     }

  72.     if (pc->local) {

  73. #if (NGX_HAVE_TRANSPARENT_PROXY)
  74.         if (pc->transparent) {
  75.             if (ngx_event_connect_set_transparent(pc, s) != NGX_OK) {
  76.                 goto failed;
  77.             }
  78.         }
  79. #endif

  80. #if (NGX_HAVE_IP_BIND_ADDRESS_NO_PORT || NGX_LINUX)
  81.         port = ngx_inet_get_port(pc->local->sockaddr);
  82. #endif

  83. #if (NGX_HAVE_IP_BIND_ADDRESS_NO_PORT)

  84.         if (pc->sockaddr->sa_family != AF_UNIX && port == 0) {
  85.             static int  bind_address_no_port = 1;

  86.             if (bind_address_no_port) {
  87.                 if (setsockopt(s, IPPROTO_IP, IP_BIND_ADDRESS_NO_PORT,
  88.                                (const void *) &bind_address_no_port,
  89.                                sizeof(int)) == -1)
  90.                 {
  91.                     err = ngx_socket_errno;

  92.                     if (err != NGX_EOPNOTSUPP && err != NGX_ENOPROTOOPT) {
  93.                         ngx_log_error(NGX_LOG_ALERT, pc->log, err,
  94.                                       "setsockopt(IP_BIND_ADDRESS_NO_PORT) "
  95.                                       "failed, ignored");

  96.                     } else {
  97.                         bind_address_no_port = 0;
  98.                     }
  99.                 }
  100.             }
  101.         }

  102. #endif

  103. #if (NGX_LINUX)

  104.         if (pc->type == SOCK_DGRAM && port != 0) {
  105.             int  reuse_addr = 1;

  106.             if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
  107.                            (const void *) &reuse_addr, sizeof(int))
  108.                  == -1)
  109.             {
  110.                 ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
  111.                               "setsockopt(SO_REUSEADDR) failed");
  112.                 goto failed;
  113.             }
  114.         }

  115. #endif

  116.         if (bind(s, pc->local->sockaddr, pc->local->socklen) == -1) {
  117.             ngx_log_error(NGX_LOG_CRIT, pc->log, ngx_socket_errno,
  118.                           "bind(%V) failed", &pc->local->name);

  119.             goto failed;
  120.         }
  121.     }

  122.     if (type == SOCK_STREAM) {
  123.         c->recv = ngx_recv;
  124.         c->send = ngx_send;
  125.         c->recv_chain = ngx_recv_chain;
  126.         c->send_chain = ngx_send_chain;

  127.         c->sendfile = 1;

  128.         if (pc->sockaddr->sa_family == AF_UNIX) {
  129.             c->tcp_nopush = NGX_TCP_NOPUSH_DISABLED;
  130.             c->tcp_nodelay = NGX_TCP_NODELAY_DISABLED;

  131. #if (NGX_SOLARIS)
  132.             /* Solaris's sendfilev() supports AF_NCA, AF_INET, and AF_INET6 */
  133.             c->sendfile = 0;
  134. #endif
  135.         }

  136.     } else { /* type == SOCK_DGRAM */
  137.         c->recv = ngx_udp_recv;
  138.         c->send = ngx_send;
  139.         c->send_chain = ngx_udp_send_chain;

  140.         c->need_flush_buf = 1;
  141.     }

  142.     c->log_error = pc->log_error;

  143.     rev = c->read;
  144.     wev = c->write;

  145.     rev->log = pc->log;
  146.     wev->log = pc->log;

  147.     pc->connection = c;

  148.     c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1);

  149.     c->start_time = ngx_current_msec;

  150.     if (ngx_add_conn) {
  151.         if (ngx_add_conn(c) == NGX_ERROR) {
  152.             goto failed;
  153.         }
  154.     }

  155.     ngx_log_debug3(NGX_LOG_DEBUG_EVENT, pc->log, 0,
  156.                    "connect to %V, fd:%d #%uA", pc->name, s, c->number);

  157.     rc = connect(s, pc->sockaddr, pc->socklen);

  158.     if (rc == -1) {
  159.         err = ngx_socket_errno;


  160.         if (err != NGX_EINPROGRESS
  161. #if (NGX_WIN32)
  162.             /* Winsock returns WSAEWOULDBLOCK (NGX_EAGAIN) */
  163.             && err != NGX_EAGAIN
  164. #endif
  165.             )
  166.         {
  167.             if (err == NGX_ECONNREFUSED
  168. #if (NGX_LINUX)
  169.                 /*
  170.                  * Linux returns EAGAIN instead of ECONNREFUSED
  171.                  * for unix sockets if listen queue is full
  172.                  */
  173.                 || err == NGX_EAGAIN
  174. #endif
  175.                 || err == NGX_ECONNRESET
  176.                 || err == NGX_ENETDOWN
  177.                 || err == NGX_ENETUNREACH
  178.                 || err == NGX_EHOSTDOWN
  179.                 || err == NGX_EHOSTUNREACH)
  180.             {
  181.                 level = NGX_LOG_ERR;

  182.             } else {
  183.                 level = NGX_LOG_CRIT;
  184.             }

  185.             ngx_log_error(level, c->log, err, "connect() to %V failed",
  186.                           pc->name);

  187.             ngx_close_connection(c);
  188.             pc->connection = NULL;

  189.             return NGX_DECLINED;
  190.         }
  191.     }

  192.     if (ngx_add_conn) {
  193.         if (rc == -1) {

  194.             /* NGX_EINPROGRESS */

  195.             return NGX_AGAIN;
  196.         }

  197.         ngx_log_debug0(NGX_LOG_DEBUG_EVENT, pc->log, 0, "connected");

  198.         wev->ready = 1;

  199.         return NGX_OK;
  200.     }

  201.     if (ngx_event_flags & NGX_USE_IOCP_EVENT) {

  202.         ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pc->log, ngx_socket_errno,
  203.                        "connect(): %d", rc);

  204.         if (ngx_blocking(s) == -1) {
  205.             ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
  206.                           ngx_blocking_n " failed");
  207.             goto failed;
  208.         }

  209.         /*
  210.          * FreeBSD's aio allows to post an operation on non-connected socket.
  211.          * NT does not support it.
  212.          *
  213.          * TODO: check in Win32, etc. As workaround we can use NGX_ONESHOT_EVENT
  214.          */

  215.         rev->ready = 1;
  216.         wev->ready = 1;

  217.         return NGX_OK;
  218.     }

  219.     if (ngx_event_flags & NGX_USE_CLEAR_EVENT) {

  220.         /* kqueue */

  221.         event = NGX_CLEAR_EVENT;

  222.     } else {

  223.         /* select, poll, /dev/poll */

  224.         event = NGX_LEVEL_EVENT;
  225.     }

  226.     if (ngx_add_event(rev, NGX_READ_EVENT, event) != NGX_OK) {
  227.         goto failed;
  228.     }

  229.     if (rc == -1) {

  230.         /* NGX_EINPROGRESS */

  231.         if (ngx_add_event(wev, NGX_WRITE_EVENT, event) != NGX_OK) {
  232.             goto failed;
  233.         }

  234.         return NGX_AGAIN;
  235.     }

  236.     ngx_log_debug0(NGX_LOG_DEBUG_EVENT, pc->log, 0, "connected");

  237.     wev->ready = 1;

  238.     return NGX_OK;

  239. failed:

  240.     ngx_close_connection(c);
  241.     pc->connection = NULL;

  242.     return NGX_ERROR;
  243. }


  244. #if (NGX_HAVE_TRANSPARENT_PROXY)

  245. static ngx_int_t
  246. ngx_event_connect_set_transparent(ngx_peer_connection_t *pc, ngx_socket_t s)
  247. {
  248.     int  value;

  249.     value = 1;

  250. #if defined(SO_BINDANY)

  251.     if (setsockopt(s, SOL_SOCKET, SO_BINDANY,
  252.                    (const void *) &value, sizeof(int)) == -1)
  253.     {
  254.         ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
  255.                       "setsockopt(SO_BINDANY) failed");
  256.         return NGX_ERROR;
  257.     }

  258. #else

  259.     switch (pc->local->sockaddr->sa_family) {

  260.     case AF_INET:

  261. #if defined(IP_TRANSPARENT)

  262.         if (setsockopt(s, IPPROTO_IP, IP_TRANSPARENT,
  263.                        (const void *) &value, sizeof(int)) == -1)
  264.         {
  265.             ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
  266.                           "setsockopt(IP_TRANSPARENT) failed");
  267.             return NGX_ERROR;
  268.         }

  269. #elif defined(IP_BINDANY)

  270.         if (setsockopt(s, IPPROTO_IP, IP_BINDANY,
  271.                        (const void *) &value, sizeof(int)) == -1)
  272.         {
  273.             ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
  274.                           "setsockopt(IP_BINDANY) failed");
  275.             return NGX_ERROR;
  276.         }

  277. #endif

  278.         break;

  279. #if (NGX_HAVE_INET6)

  280.     case AF_INET6:

  281. #if defined(IPV6_TRANSPARENT)

  282.         if (setsockopt(s, IPPROTO_IPV6, IPV6_TRANSPARENT,
  283.                        (const void *) &value, sizeof(int)) == -1)
  284.         {
  285.             ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
  286.                           "setsockopt(IPV6_TRANSPARENT) failed");
  287.             return NGX_ERROR;
  288.         }

  289. #elif defined(IPV6_BINDANY)

  290.         if (setsockopt(s, IPPROTO_IPV6, IPV6_BINDANY,
  291.                        (const void *) &value, sizeof(int)) == -1)
  292.         {
  293.             ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
  294.                           "setsockopt(IPV6_BINDANY) failed");
  295.             return NGX_ERROR;
  296.         }

  297. #else

  298.         ngx_log_error(NGX_LOG_ALERT, pc->log, 0,
  299.                       "could not enable transparent proxying for IPv6 "
  300.                       "on this platform");

  301.         return NGX_ERROR;

  302. #endif

  303.         break;

  304. #endif /* NGX_HAVE_INET6 */

  305.     }

  306. #endif /* SO_BINDANY */

  307.     return NGX_OK;
  308. }

  309. #endif


  310. ngx_int_t
  311. ngx_event_get_peer(ngx_peer_connection_t *pc, void *data)
  312. {
  313.     return NGX_OK;
  314. }