Esempio n. 1
0
File: tcp.cpp Progetto: ha1t/yrmcds
tcp_socket::tcp_socket(int fd, unsigned int bufcnt):
    resource(fd) {
    if( bufcnt > MAX_BUFCNT )
        throw std::logic_error("tcp_socket: Too many buffers");
    m_free_buffers.reserve(bufcnt);
    m_pending.reserve(bufcnt);

    int v = 1;
    if( setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &v, sizeof(v)) == -1 )
        throw_unix_error(errno, "setsockopt(SO_KEEPALIVE)");

    v = 1;
    if( setsockopt(fd, IPPROTO_TCP, TCP_CORK, &v, sizeof(v)) == -1 )
        throw_unix_error(errno, "setsockopt(TCP_CORK)");

    v = KEEPALIVE_IDLE;
    if( setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &v, sizeof(v)) == -1 )
        throw_unix_error(errno, "setsockopt(TCP_KEEPIDLE)");

    v = KEEPALIVE_INTERVAL;
    if( setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &v, sizeof(v)) == -1 )
        throw_unix_error(errno, "setsockopt(TCP_KEEPINTVL)");

    for( unsigned int i = 0; i < bufcnt; ++i ) {
        char* p = (char*)MALLOC(SENDBUF_SIZE);
        if( p == NULL ) {
            for( char* p2: m_free_buffers )
                FREE(p2);
            m_free_buffers.clear();
            throw std::runtime_error("tcp_socket: failed to allocate buffers");
        }
        // reserved, hence no throw
        m_free_buffers.push_back(p);
    }
}
Esempio n. 2
0
File: tcp.cpp Progetto: ha1t/yrmcds
bool tcp_server_socket::on_readable() {
    while( true ) {
        union {
            struct sockaddr sa;
            struct sockaddr_storage ss;
        } addr;
        socklen_t addrlen = sizeof(addr);
#ifdef _GNU_SOURCE
        int s = ::accept4(m_fd, &(addr.sa), &addrlen,
                          SOCK_NONBLOCK|SOCK_CLOEXEC);
#else
        int s = ::accept(m_fd, &(addr.sa), &addrlen);
        if( s != -1 ) {
            int fl = fcntl(s, F_GETFL, 0);
            if( fl == -1 ) fl = 0;
            if( fcntl(s, F_SETFL, fl | O_NONBLOCK) == -1 ) {
                ::close(s);
                throw_unix_error(errno, "fcntl(F_SETFL)");
            }
            fl = fcntl(s, F_GETFD, 0);
            if( fl == -1 ) fl = 0;
            if( fcntl(s, F_SETFD, fl | FD_CLOEXEC) == -1 ) {
                ::close(s);
                throw_unix_error(errno, "fcntl(F_SETFD)");
            }
        }
#endif
        if( s == -1 ) {
            if( errno == EINTR || errno == ECONNABORTED )
                continue;
            if( errno == EMFILE || errno == ENFILE ) {
                logger::error() << "accept: Too many open files.";
                continue;
            }
            if( errno == EAGAIN || errno == EWOULDBLOCK )
                break;
            throw_unix_error(errno, "accept");
        }

        try {
            std::unique_ptr<tcp_socket> t = m_wrapper(s, ip_address(&(addr.sa)));
            if( t.get() == nullptr ) {
                ::close(s);
            } else {
                m_reactor->add_resource( std::move(t),
                                         reactor::EVENT_IN|reactor::EVENT_OUT );
            }

        } catch( ... ) {
            ::close(s);
            throw;
        }
    }
    return true;
}
Esempio n. 3
0
 void _flush() {
     // with TCP_CORK, setting TCP_NODELAY effectively flushes
     // the kernel send buffer.
     int v = 1;
     if( setsockopt(m_fd, IPPROTO_TCP, TCP_NODELAY, &v, sizeof(v)) == -1 )
         throw_unix_error(errno, "setsockopt(TCP_NODELAY)");
 }
Esempio n. 4
0
File: tcp.cpp Progetto: ha1t/yrmcds
int setup_server_socket(const char* bind_addr, std::uint16_t port) {
    struct addrinfo hint, *res;
    std::string s_port = std::to_string(port);
    std::memset(&hint, 0, sizeof(hint));
    hint.ai_family = AF_INET6; // can accept IPv4 address
    hint.ai_socktype = SOCK_STREAM;
    hint.ai_flags = AI_PASSIVE | AI_NUMERICSERV;
    int e = getaddrinfo(bind_addr, s_port.c_str(), &hint, &res);
    if( e == EAI_FAMILY || e == EAI_ADDRFAMILY || e == EAI_NODATA ) {
        logger::info() << "Binding to IPv6 fails, trying IPv4...";
        hint.ai_family = AF_INET;
        e = getaddrinfo(bind_addr, s_port.c_str(), &hint, &res);
    }
    if( e == EAI_SYSTEM ) {
        throw_unix_error(errno, "getaddrinfo");
    } else if( e != 0 ) {
        throw std::runtime_error(std::string("getaddrinfo: ") +
                                 gai_strerror(e));
    }

    int s = ::socket(res->ai_family,
                     res->ai_socktype | SOCK_NONBLOCK | SOCK_CLOEXEC,
                     res->ai_protocol);
    if( s == -1 ) {
        freeaddrinfo(res);
        throw_unix_error(errno, "socket");
    }

    // intentionally ignore errors
    int ok = 1;
    setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &ok, sizeof(ok));

    if( bind(s, res->ai_addr, res->ai_addrlen) == -1 ) {
        ::close(s);
        freeaddrinfo(res);
        throw_unix_error(errno, "bind");
    }
    freeaddrinfo(res);

    if( listen(s, 128) == -1 ) {
        ::close(s);
        throw_unix_error(errno, "listen");
    }
    return s;
}
Esempio n. 5
0
std::unique_ptr<signal_reader> signal_setup(std::initializer_list<int> sigs) {
    sigset_t mask[1];
    sigemptyset(mask);
    for( int i: sigs )
        sigaddset(mask, i);
    int e = pthread_sigmask(SIG_BLOCK, mask, NULL);
    if( e != 0 )
        throw_unix_error(e, "pthread_sigmask");

    // signal disposition is a per-process attribute.
    struct sigaction act;
    std::memset(&act, 0, sizeof(act));
    act.sa_handler = SIG_IGN;
    if( sigaction(SIGPIPE, &act, NULL) == -1 )
        throw_unix_error(errno, "sigaction");

    std::memset(&act, 0, sizeof(act));
    act.sa_handler = handle_abort;
    act.sa_flags = SA_RESETHAND;
    if( sigaction(SIGABRT, &act, NULL) == -1 )
        throw_unix_error(errno, "sigaction");

    return std::unique_ptr<signal_reader>( new signal_reader(mask) );
}
Esempio n. 6
0
File: tcp.cpp Progetto: ha1t/yrmcds
int tcp_connect(const char* node, std::uint16_t port, unsigned int timeout) {
    std::string s_port = std::to_string(port);

    struct addrinfo hint, *res;
    std::memset(&hint, 0, sizeof(hint));
    hint.ai_family = AF_INET;  // prefer IPv4
    hint.ai_socktype = SOCK_STREAM;
    hint.ai_flags = AI_NUMERICSERV|AI_ADDRCONFIG;
    int e = getaddrinfo(node, s_port.c_str(), &hint, &res);
    if( e == EAI_FAMILY || e == EAI_ADDRFAMILY || e == EAI_NODATA ) {
        hint.ai_family = AF_INET6;
        hint.ai_flags |= AI_V4MAPPED;
        e = getaddrinfo(node, s_port.c_str(), &hint, &res);
    }
    if( e == EAI_SYSTEM ) {
        throw_unix_error(errno, "getaddrinfo");
    } else if( e != 0 ) {
        throw std::runtime_error(std::string("getaddrinfo: ") +
                                 gai_strerror(e));
    }

    int s = ::socket(res->ai_family,
                     res->ai_socktype | SOCK_NONBLOCK | SOCK_CLOEXEC,
                     res->ai_protocol);
    if( s == -1 ) {
        freeaddrinfo(res);
        throw_unix_error(errno, "socket");
    }
    e = ::connect(s, res->ai_addr, res->ai_addrlen);
    freeaddrinfo(res);
    if( e == 0 ) return s;
    if( errno != EINPROGRESS ) {
        ::close(s);
        throw_unix_error(errno, "connect");
    }

    struct pollfd fds;
    fds.fd = s;
    fds.events = POLLOUT;
    int poll_timeout = timeout ? timeout*1000 : -1;
    int n = ::poll(&fds, 1, poll_timeout);
    if( n == 0 ) { // timeout
        ::close(s);
        return -1;
    }
    if( n == -1 ) {
        ::close(s);
        throw_unix_error(errno, "poll");
    }

    if( fds.revents & (POLLERR|POLLHUP|POLLNVAL) ) {
        ::close(s);
        return -1;
    }
    socklen_t l = sizeof(e);
    if( getsockopt(s, SOL_SOCKET, SO_ERROR, &e, &l) == -1 ) {
        ::close(s);
        throw_unix_error(errno, "getsockopt(SO_ERROR)");
    }
    if( e != 0 ) {
        ::close(s);
        return -1;
    }
    return s;
}