Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6487e74a authored by Josh Gao's avatar Josh Gao
Browse files

adb: add fd exhaustion test, fix errno reporting in sysdeps_win32.

Add a test for FD exhaustion, and fix cases where we weren't properly
setting errno.

Change-Id: I486055bb9ead31089ce76b210c11de9e973f3256
parent b6232b96
Loading
Loading
Loading
Loading
+20 −0
Original line number Diff line number Diff line
@@ -84,6 +84,26 @@ TEST(sysdeps_socketpair, smoke) {
    ASSERT_EQ(0, adb_close(fds[1]));
}

TEST(sysdeps_fd, exhaustion) {
    std::vector<int> fds;
    int socketpair[2];

    while (adb_socketpair(socketpair) == 0) {
        fds.push_back(socketpair[0]);
        fds.push_back(socketpair[1]);
    }

    ASSERT_EQ(EMFILE, errno) << strerror(errno);
    for (int fd : fds) {
        ASSERT_EQ(0, adb_close(fd));
    }
    ASSERT_EQ(0, adb_socketpair(socketpair));
    ASSERT_EQ(socketpair[0], fds[0]);
    ASSERT_EQ(socketpair[1], fds[1]);
    ASSERT_EQ(0, adb_close(socketpair[0]));
    ASSERT_EQ(0, adb_close(socketpair[1]));
}

class sysdeps_poll : public ::testing::Test {
  protected:
    int fds[2];
+76 −73
Original line number Diff line number Diff line
@@ -726,8 +726,9 @@ static int _fh_socket_close( FH f ) {
#endif
        }
        if (closesocket(f->fh_socket) == SOCKET_ERROR) {
            D("closesocket failed: %s",
              android::base::SystemErrorCodeToString(WSAGetLastError()).c_str());
            // Don't set errno here, since adb_close will ignore it.
            const DWORD err = WSAGetLastError();
            D("closesocket failed: %s", android::base::SystemErrorCodeToString(err).c_str());
        }
        f->fh_socket = INVALID_SOCKET;
    }
@@ -847,8 +848,7 @@ int network_loopback_client(int port, int type, std::string* error) {
        return -1;
    }

    if (!_winsock_init)
        _init_winsock();
    if (!_winsock_init) _init_winsock();

    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
@@ -857,9 +857,11 @@ int network_loopback_client(int port, int type, std::string* error) {

    s = socket(AF_INET, type, GetSocketProtocolFromSocketType(type));
    if (s == INVALID_SOCKET) {
        const DWORD err = WSAGetLastError();
        *error = android::base::StringPrintf("cannot create socket: %s",
                android::base::SystemErrorCodeToString(WSAGetLastError()).c_str());
                                             android::base::SystemErrorCodeToString(err).c_str());
        D("%s", error->c_str());
        _socket_set_errno(err);
        return -1;
    }
    f->fh_socket = s;
@@ -870,16 +872,16 @@ int network_loopback_client(int port, int type, std::string* error) {
        *error = android::base::StringPrintf("cannot connect to %s:%u: %s",
                                             inet_ntoa(addr.sin_addr), ntohs(addr.sin_port),
                                             android::base::SystemErrorCodeToString(err).c_str());
        D("could not connect to %s:%d: %s",
          type != SOCK_STREAM ? "udp" : "tcp", port, error->c_str());
        D("could not connect to %s:%d: %s", type != SOCK_STREAM ? "udp" : "tcp", port,
          error->c_str());
        _socket_set_errno(err);
        return -1;
    }

    const int fd = _fh_to_int(f.get());
    snprintf( f->name, sizeof(f->name), "%d(lo-client:%s%d)", fd,
              type != SOCK_STREAM ? "udp:" : "", port );
    D( "port %d type %s => fd %d", port, type != SOCK_STREAM ? "udp" : "tcp",
       fd );
    snprintf(f->name, sizeof(f->name), "%d(lo-client:%s%d)", fd, type != SOCK_STREAM ? "udp:" : "",
             port);
    D("port %d type %s => fd %d", port, type != SOCK_STREAM ? "udp" : "tcp", fd);
    f.release();
    return fd;
}
@@ -887,8 +889,7 @@ int network_loopback_client(int port, int type, std::string* error) {
#define LISTEN_BACKLOG 4

// interface_address is INADDR_LOOPBACK or INADDR_ANY.
static int _network_server(int port, int type, u_long interface_address,
                           std::string* error) {
static int _network_server(int port, int type, u_long interface_address, std::string* error) {
    struct sockaddr_in addr;
    SOCKET s;
    int n;
@@ -899,8 +900,7 @@ static int _network_server(int port, int type, u_long interface_address,
        return -1;
    }

    if (!_winsock_init)
        _init_winsock();
    if (!_winsock_init) _init_winsock();

    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
@@ -911,9 +911,11 @@ static int _network_server(int port, int type, u_long interface_address,
    // IPv4 and IPv6.
    s = socket(AF_INET, type, GetSocketProtocolFromSocketType(type));
    if (s == INVALID_SOCKET) {
        const DWORD err = WSAGetLastError();
        *error = android::base::StringPrintf("cannot create socket: %s",
                android::base::SystemErrorCodeToString(WSAGetLastError()).c_str());
                                             android::base::SystemErrorCodeToString(err).c_str());
        D("%s", error->c_str());
        _socket_set_errno(err);
        return -1;
    }

@@ -922,40 +924,41 @@ static int _network_server(int port, int type, u_long interface_address,
    // Note: SO_REUSEADDR on Windows allows multiple processes to bind to the
    // same port, so instead use SO_EXCLUSIVEADDRUSE.
    n = 1;
    if (setsockopt(s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const char*)&n,
                   sizeof(n)) == SOCKET_ERROR) {
        *error = android::base::StringPrintf(
                "cannot set socket option SO_EXCLUSIVEADDRUSE: %s",
                android::base::SystemErrorCodeToString(WSAGetLastError()).c_str());
    if (setsockopt(s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const char*)&n, sizeof(n)) == SOCKET_ERROR) {
        const DWORD err = WSAGetLastError();
        *error = android::base::StringPrintf("cannot set socket option SO_EXCLUSIVEADDRUSE: %s",
                                             android::base::SystemErrorCodeToString(err).c_str());
        D("%s", error->c_str());
        _socket_set_errno(err);
        return -1;
    }

    if (bind(s, (struct sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR) {
        // Save err just in case inet_ntoa() or ntohs() changes the last error.
        const DWORD err = WSAGetLastError();
        *error = android::base::StringPrintf("cannot bind to %s:%u: %s",
                inet_ntoa(addr.sin_addr), ntohs(addr.sin_port),
        *error = android::base::StringPrintf("cannot bind to %s:%u: %s", inet_ntoa(addr.sin_addr),
                                             ntohs(addr.sin_port),
                                             android::base::SystemErrorCodeToString(err).c_str());
        D("could not bind to %s:%d: %s",
          type != SOCK_STREAM ? "udp" : "tcp", port, error->c_str());
        D("could not bind to %s:%d: %s", type != SOCK_STREAM ? "udp" : "tcp", port, error->c_str());
        _socket_set_errno(err);
        return -1;
    }
    if (type == SOCK_STREAM) {
        if (listen(s, LISTEN_BACKLOG) == SOCKET_ERROR) {
            *error = android::base::StringPrintf("cannot listen on socket: %s",
                    android::base::SystemErrorCodeToString(WSAGetLastError()).c_str());
            D("could not listen on %s:%d: %s",
              type != SOCK_STREAM ? "udp" : "tcp", port, error->c_str());
            const DWORD err = WSAGetLastError();
            *error = android::base::StringPrintf(
                "cannot listen on socket: %s", android::base::SystemErrorCodeToString(err).c_str());
            D("could not listen on %s:%d: %s", type != SOCK_STREAM ? "udp" : "tcp", port,
              error->c_str());
            _socket_set_errno(err);
            return -1;
        }
    }
    const int fd = _fh_to_int(f.get());
    snprintf(f->name, sizeof(f->name), "%d(%s-server:%s%d)", fd,
              interface_address == INADDR_LOOPBACK ? "lo" : "any",
              type != SOCK_STREAM ? "udp:" : "", port );
    D( "port %d type %s => fd %d", port, type != SOCK_STREAM ? "udp" : "tcp",
       fd );
             interface_address == INADDR_LOOPBACK ? "lo" : "any", type != SOCK_STREAM ? "udp:" : "",
             port);
    D("port %d type %s => fd %d", port, type != SOCK_STREAM ? "udp" : "tcp", fd);
    f.release();
    return fd;
}
@@ -996,25 +999,28 @@ int network_connect(const std::string& host, int port, int type, int timeout, st
// with GetProcAddress("GetAddrInfoW").
#endif
    if (getaddrinfo(host.c_str(), port_str, &hints, &addrinfo_ptr) != 0) {
        *error = android::base::StringPrintf(
                "cannot resolve host '%s' and port %s: %s", host.c_str(),
                port_str, android::base::SystemErrorCodeToString(WSAGetLastError()).c_str());
        const DWORD err = WSAGetLastError();
        *error = android::base::StringPrintf("cannot resolve host '%s' and port %s: %s",
                                             host.c_str(), port_str,
                                             android::base::SystemErrorCodeToString(err).c_str());

        D("%s", error->c_str());
        _socket_set_errno(err);
        return -1;
    }
    std::unique_ptr<struct addrinfo, decltype(freeaddrinfo)*>
        addrinfo(addrinfo_ptr, freeaddrinfo);
    std::unique_ptr<struct addrinfo, decltype(freeaddrinfo)*> addrinfo(addrinfo_ptr, freeaddrinfo);
    addrinfo_ptr = nullptr;

    // TODO: Try all the addresses if there's more than one? This just uses
    // the first. Or, could call WSAConnectByName() (Windows Vista and newer)
    // which tries all addresses, takes a timeout and more.
    SOCKET s = socket(addrinfo->ai_family, addrinfo->ai_socktype,
                      addrinfo->ai_protocol);
    SOCKET s = socket(addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol);
    if (s == INVALID_SOCKET) {
        const DWORD err = WSAGetLastError();
        *error = android::base::StringPrintf("cannot create socket: %s",
                android::base::SystemErrorCodeToString(WSAGetLastError()).c_str());
                                             android::base::SystemErrorCodeToString(err).c_str());
        D("%s", error->c_str());
        _socket_set_errno(err);
        return -1;
    }
    f->fh_socket = s;
@@ -1023,20 +1029,20 @@ int network_connect(const std::string& host, int port, int type, int timeout, st
    // (according to http://serverfault.com/a/671453) and in practice is 21 sec.
    if (connect(s, addrinfo->ai_addr, addrinfo->ai_addrlen) == SOCKET_ERROR) {
        // TODO: Use WSAAddressToString or inet_ntop on address.
        *error = android::base::StringPrintf("cannot connect to %s:%s: %s",
                host.c_str(), port_str,
                android::base::SystemErrorCodeToString(WSAGetLastError()).c_str());
        D("could not connect to %s:%s:%s: %s",
          type != SOCK_STREAM ? "udp" : "tcp", host.c_str(), port_str,
          error->c_str());
        const DWORD err = WSAGetLastError();
        *error = android::base::StringPrintf("cannot connect to %s:%s: %s", host.c_str(), port_str,
                                             android::base::SystemErrorCodeToString(err).c_str());
        D("could not connect to %s:%s:%s: %s", type != SOCK_STREAM ? "udp" : "tcp", host.c_str(),
          port_str, error->c_str());
        _socket_set_errno(err);
        return -1;
    }

    const int fd = _fh_to_int(f.get());
    snprintf( f->name, sizeof(f->name), "%d(net-client:%s%d)", fd,
              type != SOCK_STREAM ? "udp:" : "", port );
    D( "host '%s' port %d type %s => fd %d", host.c_str(), port,
       type != SOCK_STREAM ? "udp" : "tcp", fd );
    snprintf(f->name, sizeof(f->name), "%d(net-client:%s%d)", fd, type != SOCK_STREAM ? "udp:" : "",
             port);
    D("host '%s' port %d type %s => fd %d", host.c_str(), port, type != SOCK_STREAM ? "udp" : "tcp",
      fd);
    f.release();
    return fd;
}
@@ -1180,10 +1186,7 @@ int adb_socketpair(int sv[2]) {

    accepted = adb_socket_accept(server, nullptr, nullptr);
    if (accepted < 0) {
        const DWORD err = WSAGetLastError();
        D("adb_socketpair: failed to accept: %s",
          android::base::SystemErrorCodeToString(err).c_str());
        _socket_set_errno(err);
        D("adb_socketpair: failed to accept: %s", strerror(errno));
        goto fail;
    }
    adb_close(server);