src/event/ngx_event_connect.c - nginx-1.31.4 nginx/ @ 8d9666701

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))
  51.             == -1)
  52.         {
  53.             ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
  54.                           "setsockopt(SO_RCVBUF, %d) failed, ignored",
  55.                           pc->rcvbuf);
  56.         }
  57.     }

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

  68.     if (pc->so_keepalive) {
  69.         value = 1;

  70.         if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE,
  71.                        (const void *) &value, sizeof(int))
  72.             == -1)
  73.         {
  74.             ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
  75.                           "setsockopt(SO_KEEPALIVE) failed, ignored");
  76.         }
  77.     }

  78.     if (ngx_nonblocking(s) == -1) {
  79.         ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
  80.                       ngx_nonblocking_n " failed");

  81.         goto failed;
  82.     }

  83.     if (pc->local) {

  84. #if (NGX_HAVE_TRANSPARENT_PROXY)
  85.         if (pc->transparent) {
  86.             if (ngx_event_connect_set_transparent(pc, s) != NGX_OK) {
  87.                 goto failed;
  88.             }
  89.         }
  90. #endif

  91. #if (NGX_HAVE_IP_BIND_ADDRESS_NO_PORT || NGX_LINUX)
  92.         port = ngx_inet_get_port(pc->local->sockaddr);
  93. #endif

  94. #if (NGX_HAVE_IP_BIND_ADDRESS_NO_PORT)

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

  97.             if (bind_address_no_port) {
  98.                 if (setsockopt(s, IPPROTO_IP, IP_BIND_ADDRESS_NO_PORT,
  99.                                (const void *) &bind_address_no_port,
  100.                                sizeof(int)) == -1)
  101.                 {
  102.                     err = ngx_socket_errno;

  103.                     if (err != NGX_EOPNOTSUPP && err != NGX_ENOPROTOOPT) {
  104.                         ngx_log_error(NGX_LOG_ALERT, pc->log, err,
  105.                                       "setsockopt(IP_BIND_ADDRESS_NO_PORT) "
  106.                                       "failed, ignored");

  107.                     } else {
  108.                         bind_address_no_port = 0;
  109.                     }
  110.                 }
  111.             }
  112.         }

  113. #endif

  114. #if (NGX_LINUX)

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

  117.             if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
  118.                            (const void *) &reuse_addr, sizeof(int))
  119.                  == -1)
  120.             {
  121.                 ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
  122.                               "setsockopt(SO_REUSEADDR) failed");
  123.                 goto failed;
  124.             }
  125.         }

  126. #endif

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

  130.             goto failed;
  131.         }
  132.     }

  133.     if (type == SOCK_STREAM) {
  134.         c->recv = ngx_recv;
  135.         c->send = ngx_send;
  136.         c->recv_chain = ngx_recv_chain;
  137.         c->send_chain = ngx_send_chain;

  138.         c->sendfile = 1;

  139.         if (pc->sockaddr->sa_family == AF_UNIX) {
  140.             c->tcp_nopush = NGX_TCP_NOPUSH_DISABLED;
  141.             c->tcp_nodelay = NGX_TCP_NODELAY_DISABLED;

  142. #if (NGX_SOLARIS)
  143.             /* Solaris's sendfilev() supports AF_NCA, AF_INET, and AF_INET6 */
  144.             c->sendfile = 0;
  145. #endif
  146.         }

  147.     } else { /* type == SOCK_DGRAM */
  148.         c->recv = ngx_udp_recv;
  149.         c->send = ngx_send;
  150.         c->send_chain = ngx_udp_send_chain;

  151.         c->need_flush_buf = 1;
  152.     }

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

  154.     rev = c->read;
  155.     wev = c->write;

  156.     rev->log = pc->log;
  157.     wev->log = pc->log;

  158.     pc->connection = c;

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

  160.     c->start_time = ngx_current_msec;

  161.     if (ngx_add_conn) {
  162.         if (ngx_add_conn(c) == NGX_ERROR) {
  163.             goto failed;
  164.         }
  165.     }

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

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

  169.     if (rc == -1) {
  170.         err = ngx_socket_errno;


  171.         if (err != NGX_EINPROGRESS
  172. #if (NGX_WIN32)
  173.             /* Winsock returns WSAEWOULDBLOCK (NGX_EAGAIN) */
  174.             && err != NGX_EAGAIN
  175. #endif
  176.             )
  177.         {
  178.             if (err == NGX_ECONNREFUSED
  179. #if (NGX_LINUX)
  180.                 /*
  181.                  * Linux returns EAGAIN instead of ECONNREFUSED
  182.                  * for unix sockets if listen queue is full
  183.                  */
  184.                 || err == NGX_EAGAIN
  185. #endif
  186.                 || err == NGX_ECONNRESET
  187.                 || err == NGX_ENETDOWN
  188.                 || err == NGX_ENETUNREACH
  189.                 || err == NGX_EHOSTDOWN
  190.                 || err == NGX_EHOSTUNREACH)
  191.             {
  192.                 level = NGX_LOG_ERR;

  193.             } else {
  194.                 level = NGX_LOG_CRIT;
  195.             }

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

  198.             ngx_close_connection(c);
  199.             pc->connection = NULL;

  200.             return NGX_DECLINED;
  201.         }
  202.     }

  203.     if (ngx_add_conn) {
  204.         if (rc == -1) {

  205.             /* NGX_EINPROGRESS */

  206.             return NGX_AGAIN;
  207.         }

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

  209.         wev->ready = 1;

  210.         return NGX_OK;
  211.     }

  212.     if (ngx_event_flags & NGX_USE_IOCP_EVENT) {

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

  215.         if (ngx_blocking(s) == -1) {
  216.             ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
  217.                           ngx_blocking_n " failed");
  218.             goto failed;
  219.         }

  220.         /*
  221.          * FreeBSD's aio allows to post an operation on non-connected socket.
  222.          * NT does not support it.
  223.          *
  224.          * TODO: check in Win32, etc. As workaround we can use NGX_ONESHOT_EVENT
  225.          */

  226.         rev->ready = 1;
  227.         wev->ready = 1;

  228.         return NGX_OK;
  229.     }

  230.     if (ngx_event_flags & NGX_USE_CLEAR_EVENT) {

  231.         /* kqueue */

  232.         event = NGX_CLEAR_EVENT;

  233.     } else {

  234.         /* select, poll, /dev/poll */

  235.         event = NGX_LEVEL_EVENT;
  236.     }

  237.     if (ngx_add_event(rev, NGX_READ_EVENT, event) != NGX_OK) {
  238.         goto failed;
  239.     }

  240.     if (rc == -1) {

  241.         /* NGX_EINPROGRESS */

  242.         if (ngx_add_event(wev, NGX_WRITE_EVENT, event) != NGX_OK) {
  243.             goto failed;
  244.         }

  245.         return NGX_AGAIN;
  246.     }

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

  248.     wev->ready = 1;

  249.     return NGX_OK;

  250. failed:

  251.     ngx_close_connection(c);
  252.     pc->connection = NULL;

  253.     return NGX_ERROR;
  254. }


  255. #if (NGX_HAVE_TRANSPARENT_PROXY)

  256. static ngx_int_t
  257. ngx_event_connect_set_transparent(ngx_peer_connection_t *pc, ngx_socket_t s)
  258. {
  259.     int  value;

  260.     value = 1;

  261. #if defined(SO_BINDANY)

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

  269. #else

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

  271.     case AF_INET:

  272. #if defined(IP_TRANSPARENT)

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

  280. #elif defined(IP_BINDANY)

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

  288. #endif

  289.         break;

  290. #if (NGX_HAVE_INET6)

  291.     case AF_INET6:

  292. #if defined(IPV6_TRANSPARENT)

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

  300. #elif defined(IPV6_BINDANY)

  301.         if (setsockopt(s, IPPROTO_IPV6, IPV6_BINDANY,
  302.                        (const void *) &value, sizeof(int)) == -1)
  303.         {
  304.             ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
  305.                           "setsockopt(IPV6_BINDANY) failed");
  306.             return NGX_ERROR;
  307.         }

  308. #else

  309.         ngx_log_error(NGX_LOG_ALERT, pc->log, 0,
  310.                       "could not enable transparent proxying for IPv6 "
  311.                       "on this platform");

  312.         return NGX_ERROR;

  313. #endif

  314.         break;

  315. #endif /* NGX_HAVE_INET6 */

  316.     }

  317. #endif /* SO_BINDANY */

  318.     return NGX_OK;
  319. }

  320. #endif


  321. ngx_int_t
  322. ngx_event_get_peer(ngx_peer_connection_t *pc, void *data)
  323. {
  324.     return NGX_OK;
  325. }