Home | History | Annotate | Line # | Download | only in test
      1 /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
      2  *
      3  * Permission is hereby granted, free of charge, to any person obtaining a copy
      4  * of this software and associated documentation files (the "Software"), to
      5  * deal in the Software without restriction, including without limitation the
      6  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
      7  * sell copies of the Software, and to permit persons to whom the Software is
      8  * furnished to do so, subject to the following conditions:
      9  *
     10  * The above copyright notice and this permission notice shall be included in
     11  * all copies or substantial portions of the Software.
     12  *
     13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     14  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     16  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     17  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     18  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     19  * IN THE SOFTWARE.
     20  */
     21 
     22 #if !defined(_WIN32)
     23 
     24 #include "uv.h"
     25 #include "task.h"
     26 
     27 #include <errno.h>
     28 #include <sys/resource.h>
     29 #include <unistd.h>
     30 
     31 static void connection_cb(uv_stream_t* server_handle, int status);
     32 static void connect_cb(uv_connect_t* req, int status);
     33 
     34 static const int maxfd = 31;
     35 static unsigned connect_cb_called;
     36 static uv_tcp_t server_handle;
     37 static uv_tcp_t client_handle;
     38 
     39 
     40 TEST_IMPL(emfile) {
     41   struct sockaddr_in addr;
     42   struct rlimit limits;
     43   uv_connect_t connect_req;
     44   uv_loop_t* loop;
     45   int first_fd;
     46 #if defined(_AIX) || defined(__MVS__)
     47   /* On AIX, if a 'accept' call fails ECONNRESET is set on the socket
     48    * which causes uv__emfile_trick to not work as intended and this test
     49    * to fail.
     50    */
     51   RETURN_SKIP("uv__emfile_trick does not work on this OS");
     52 #endif
     53 
     54   /* Lower the file descriptor limit and use up all fds save one. */
     55   limits.rlim_cur = limits.rlim_max = maxfd + 1;
     56   if (setrlimit(RLIMIT_NOFILE, &limits)) {
     57     ASSERT_EQ(errno, EPERM);  /* Valgrind blocks the setrlimit() call. */
     58     RETURN_SKIP("setrlimit(RLIMIT_NOFILE) failed, running under valgrind?");
     59   }
     60 
     61   loop = uv_default_loop();
     62   ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
     63   ASSERT_OK(uv_tcp_init(loop, &server_handle));
     64   ASSERT_OK(uv_tcp_init(loop, &client_handle));
     65   ASSERT_OK(uv_tcp_bind(&server_handle, (const struct sockaddr*) &addr, 0));
     66   ASSERT_OK(uv_listen((uv_stream_t*) &server_handle, 8, connection_cb));
     67 
     68   /* Remember the first one so we can clean up afterwards. */
     69   do
     70     first_fd = dup(0);
     71   while (first_fd == -1 && errno == EINTR);
     72   ASSERT_GT(first_fd, 0);
     73 
     74   while (dup(0) != -1 || errno == EINTR);
     75   ASSERT_EQ(errno, EMFILE);
     76   close(maxfd);
     77 
     78 #if defined(__ANDROID__)
     79   /* Android connect syscall requires an extra file descriptor
     80    *
     81    * It fails in uv__tcp_connect
     82    * */
     83   close(maxfd - 1);
     84 #endif
     85 
     86   /* Now connect and use up the last available file descriptor.  The EMFILE
     87    * handling logic in src/unix/stream.c should ensure that connect_cb() runs
     88    * whereas connection_cb() should *not* run.
     89    */
     90   ASSERT_OK(uv_tcp_connect(&connect_req,
     91                            &client_handle,
     92                            (const struct sockaddr*) &addr,
     93                            connect_cb));
     94   ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT));
     95   ASSERT_EQ(1, connect_cb_called);
     96 
     97   /* Close the dups again. Ignore errors in the unlikely event that the
     98    * file descriptors were not contiguous.
     99    */
    100   while (first_fd < maxfd) {
    101     close(first_fd);
    102     first_fd += 1;
    103   }
    104 
    105   MAKE_VALGRIND_HAPPY(loop);
    106   return 0;
    107 }
    108 
    109 
    110 static void connection_cb(uv_stream_t* server_handle, int status) {
    111   ASSERT(0 && "connection_cb should not be called.");
    112 }
    113 
    114 
    115 static void connect_cb(uv_connect_t* req, int status) {
    116   /* |status| should equal 0 because the connection should have been accepted,
    117    * it's just that the server immediately closes it again.
    118    */
    119   ASSERT_OK(status);
    120   connect_cb_called += 1;
    121   uv_close((uv_handle_t*) &server_handle, NULL);
    122   uv_close((uv_handle_t*) &client_handle, NULL);
    123 }
    124 
    125 #else
    126 
    127 typedef int file_has_no_tests; /* ISO C forbids an empty translation unit. */
    128 
    129 #endif /* !_WIN32 */
    130