void hpc_rpc_session::on_connect_events_ready(uintptr_t lolp_or_events)
        {
            dassert(is_connecting(), "session must be connecting at this time");

            struct kevent& e = *((struct kevent*)lolp_or_events);
            dinfo("(s = %d) epoll for connect to %s:%hu, events = %x",
                _socket,
                _remote_addr.name(),
                _remote_addr.port(),
                e.filter
                );

            if ((e.filter == EVFILT_WRITE)
                && ((e.flags & EV_ERROR) == 0)
                && ((e.flags & EV_EOF) == 0)
                )
            {
                socklen_t addr_len = (socklen_t)sizeof(_peer_addr);
                if (getpeername(_socket, (struct sockaddr*)&_peer_addr, &addr_len) == -1)
                {
                    dassert(false, "(s = %d) (client) getpeername failed, err = %s",
                        _socket, strerror(errno));
                }

                dinfo("(s = %d) client session %s:%hu connected",
                    _socket,
                    _remote_addr.name(),
                    _remote_addr.port()
                    );

                set_connected();
                
                if (_looper->bind_io_handle(
                    (dsn_handle_t)(intptr_t)_socket,
                    &_ready_event,
                    EVFILT_READ_WRITE
                    ) != ERR_OK)
                {
                    on_failure();
                    return;
                }

                // start first round send
                do_safe_write(nullptr);
            }
            else
            {
                int err = 0;
                socklen_t err_len = (socklen_t)sizeof(err);

                if (getsockopt(_socket, SOL_SOCKET, SO_ERROR, (void*)&err, &err_len) < 0)
                {
                    dassert(false, "getsockopt for SO_ERROR failed, err = %s", strerror(errno));
                }

                derror("(s = %d) connect failed (in epoll), err = %s", _socket, strerror(err));
                on_failure();
            }
        }
void hpc_rpc_session::do_read(int sz)
{
    add_ref();
    _read_event.callback = [this](int err, uint32_t length, uintptr_t lolp)
    {
        //dinfo("WSARecv completed, err = %d, size = %u", err, length);
        dassert((LPOVERLAPPED)lolp == &_read_event.olp, "must be exact this overlapped");
        if (err != ERROR_SUCCESS)
        {
            dwarn("WSARecv failed, err = %d", err);
            on_failure();
        }
        else
        {
            int read_next;
            message_ex* msg = _parser->get_message_on_receive((int)length, read_next);

            while (msg != nullptr)
            {
                this->on_read_completed(msg);
                msg = _parser->get_message_on_receive(0, read_next);
            }

            do_read(read_next);
        }

        release_ref();
    };
    memset(&_read_event.olp, 0, sizeof(_read_event.olp));

    WSABUF buf[1];

    void* ptr = _parser->read_buffer_ptr((int)sz);
    int remaining = _parser->read_buffer_capacity();
    buf[0].buf = (char*)ptr;
    buf[0].len = remaining;

    DWORD bytes = 0;
    DWORD flag = 0;
    int rt = WSARecv(
                 _socket,
                 buf,
                 1,
                 &bytes,
                 &flag,
                 &_read_event.olp,
                 NULL
             );

    if (SOCKET_ERROR == rt && (WSAGetLastError() != ERROR_IO_PENDING))
    {
        dwarn("WSARecv failed, err = %d", ::WSAGetLastError());
        release_ref();
        on_failure();
    }

    //dinfo("WSARecv called, err = %d", rt);
}
Beispiel #3
0
        void net_io::do_write()
        {
            auto msg = _sq.peek();
            if (nullptr == msg.get())
                return;

            std::vector<blob> buffers;
            _parser->prepare_buffers_for_send(msg, buffers);

            std::vector<boost::asio::const_buffer> buffers2;
            for (auto& b : buffers)
            {
                buffers2.push_back(boost::asio::const_buffer(b.data(), b.length()));
            }

            add_reference();
            boost::asio::async_write(_socket, buffers2,
                [this, msg](boost::system::error_code ec, std::size_t length)
            {
                if (!!ec)
                {
                    on_failure();
                }
                else
                {
                    auto smsg = _sq.dequeue_peeked();
                    dassert(smsg == msg, "sent msg must be the first msg in send queue");
                    //dinfo("network message sent, rpc_id = %016llx", msg->header().rpc_id);

                    do_write();
                }

                release_reference();
            });
        }
Beispiel #4
0
        void net_io::do_read(size_t sz)
        {
            add_reference();

            void* ptr = _parser->read_buffer_ptr((int)sz);
            int remaining = _parser->read_buffer_capacity();

            _socket.async_read_some(boost::asio::buffer(ptr, remaining),
                [this](boost::system::error_code ec, std::size_t length)
            {
                if (!!ec)
                {
                    on_failure();
                }
                else
                {
                    int read_next;
                    message_ptr msg = _parser->get_message_on_receive((int)length, read_next);

                    while (msg != nullptr)
                    {
                        this->on_message_read(msg);
                        msg = _parser->get_message_on_receive(0, read_next);
                    }
                     
                    do_read(read_next);
                }

                release_reference();
            });
        }
Beispiel #5
0
        void asio_rpc_session::do_read(size_t sz)
        {
            add_ref();

            void* ptr = _parser->read_buffer_ptr((int)sz);
            int remaining = _parser->read_buffer_capacity();

            _socket->async_read_some(boost::asio::buffer(ptr, remaining),
                [this](boost::system::error_code ec, std::size_t length)
            {
                if (!!ec)
                {
                    derror("asio read failed: %s", ec.message().c_str());
                    on_failure();
                }
                else
                {
                    int read_next;
                    message_ex* msg = _parser->get_message_on_receive((int)length, read_next);

                    while (msg != nullptr)
                    {
                        this->on_message_read(msg);
                        msg = _parser->get_message_on_receive(0, read_next);
                    }
                     
                    do_read(read_next);
                }

                release_ref();
            });
        }
Beispiel #6
0
        void asio_rpc_session::connect()
        {
            if (try_connecting())
            {
                boost::asio::ip::tcp::endpoint ep(
                    boost::asio::ip::address_v4(_remote_addr.ip()), _remote_addr.port());

                add_ref();
                _socket->async_connect(ep, [this](boost::system::error_code ec)
                {
                    if (!ec)
                    {
                        dinfo("client session %s connected",
                            _remote_addr.to_string()
                            );

                        set_options();
                        set_connected();
                        on_send_completed();
                        do_read();
                    }
                    else
                    {
                        derror("client session connect to %s failed, error = %s",
                            _remote_addr.to_string(),
                            ec.message().c_str()
                            );
                        on_failure();
                    }
                    release_ref();
                });
            }
        }   
Beispiel #7
0
        void asio_rpc_session::write(uint64_t signature)
        {
            std::vector<boost::asio::const_buffer> buffers2;
            int bcount = (int)_sending_buffers.size();
            
            // prepare buffers
            buffers2.resize(bcount);            
            for (int i = 0; i < bcount; i++)
            {
                buffers2[i] = boost::asio::const_buffer(_sending_buffers[i].buf, _sending_buffers[i].sz);
            }

            add_ref();
            boost::asio::async_write(*_socket, buffers2,
                [this, signature](boost::system::error_code ec, std::size_t length)
            {
                if (!!ec)
                {
                    derror("asio write failed: %s", ec.message().c_str());
                    on_failure();
                }
                else
                {
                    on_send_completed(signature);
                }

                release_ref();
            });
        }
        void hpc_rpc_session::connect()
        {
            if (!try_connecting())
                return;
            
            dassert(_socket != -1, "invalid given socket handle");

            struct sockaddr_in addr;
            addr.sin_family = AF_INET;
            addr.sin_addr.s_addr = htonl(_remote_addr.ip());
            addr.sin_port = htons(_remote_addr.port());

            int rt = ::connect(_socket, (struct sockaddr*)&addr, (int)sizeof(addr));
            int err = errno;
            dinfo("(s = %d) call connect to %s:%hu, return %d, err = %s",
                _socket,
                _remote_addr.name(),
                _remote_addr.port(),
                rt,
                strerror(err)
                );

            if (rt == -1 && err != EINPROGRESS)
            {
                dwarn("(s = %d) connect failed, err = %s", _socket, strerror(err));
                on_failure();
                return;
            }

            // bind for connect
            _looper->bind_io_handle((dsn_handle_t)(intptr_t)_socket, &_ready_event,
                EVFILT_WRITE,
                this
                );
        }
void hpc_rpc_session::connect()
{
    if (!try_connecting())
        return;

    _connect_event.callback = [this](int err, uint32_t io_size, uintptr_t lpolp)
    {
        //dinfo("ConnectEx completed, err = %d, size = %u", err, io_size);
        if (err != ERROR_SUCCESS)
        {
            dwarn("ConnectEx failed, err = %d", err);
            this->on_failure();
        }
        else
        {
            dinfo("client session %s:%hu connected",
                  _remote_addr.name(),
                  _remote_addr.port()
                 );

            set_connected();
            on_send_completed(nullptr);
            do_read();
        }
        this->release_ref(); // added before ConnectEx
    };
    memset(&_connect_event.olp, 0, sizeof(_connect_event.olp));

    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = htonl(_remote_addr.ip());
    addr.sin_port = htons(_remote_addr.port());

    this->add_ref(); // released in _connect_event.callback
    BOOL rt = s_lpfnConnectEx(
                  _socket,
                  (struct sockaddr*)&addr,
                  (int)sizeof(addr),
                  0,
                  0,
                  0,
                  &_connect_event.olp
              );

    if (!rt && (WSAGetLastError() != ERROR_IO_PENDING))
    {
        dwarn("ConnectEx failed, err = %d", ::WSAGetLastError());
        this->release_ref();

        on_failure();
    }
}
        void hpc_rpc_session::on_send_recv_events_ready(uintptr_t lolp_or_events)
        {
            struct kevent& e = *((struct kevent*)lolp_or_events);
            // shutdown or send/recv error
            if (((e.flags & EV_ERROR) != 0) || ((e.flags & EV_EOF) != 0))
            {
                dinfo("(s = %d) epoll failure on %s:%hu, events = %x",
                    _socket,
                    _remote_addr.name(),
                    _remote_addr.port(),
                    e.filter
                    );
                on_failure();
                return;
            }

            //  send
            if (e.filter == EVFILT_WRITE)
            {
                dinfo("(s = %d) kqueue EVFILT_WRITE on %s:%hu, events = %x",
                    _socket,
                    _remote_addr.name(),
                    _remote_addr.port(),
                    e.filter
                    );

                do_safe_write(nullptr);
            }

            // recv
            if (e.filter == EVFILT_READ)
            {
                dinfo("(s = %d) kqueue EVFILT_READ on %s:%hu, events = %x",
                    _socket,
                    _remote_addr.name(),
                    _remote_addr.port(),
                    e.filter 
                    );

                do_read();
            }
        }
        void hpc_rpc_session::do_read(int read_next)
        {
            utils::auto_lock<utils::ex_lock_nr> l(_send_lock);

            while (true)
            {
                char* ptr = (char*)_parser->read_buffer_ptr((int)read_next);
                int remaining = _parser->read_buffer_capacity();

                int sz = recv(_socket, ptr, remaining, 0);
                int err = errno;
                dinfo("(s = %d) call recv on %s:%hu, return %d, err = %s",
                    _socket,
                    _remote_addr.name(),
                    _remote_addr.port(),
                    sz,
                    strerror(err)
                    );

                if (sz > 0)
                {
                    message_ex* msg = _parser->get_message_on_receive(sz, read_next);

                    while (msg != nullptr)
                    {
                        this->on_read_completed(msg);
                        msg = _parser->get_message_on_receive(0, read_next);
                    }
                }
                else
                {
                    if (err != EAGAIN && err != EWOULDBLOCK)
                    {
                        derror("(s = %d) recv failed, err = %s", _socket, strerror(err));
                        on_failure();
                    }
                    break;
                }
            }
        }
Beispiel #12
0
        void client_net_io::connect()
        {
            session_state closed_state = SS_CLOSED;

            if (_state.compare_exchange_strong(closed_state, SS_CONNECTING))
            {
                boost::asio::ip::tcp::endpoint ep(
                    boost::asio::ip::address_v4(ntohl(_remote_addr.ip)), _remote_addr.port);

                add_reference();
                _socket.async_connect(ep, [this](boost::system::error_code ec)
                {
                    if (!ec)
                    {
                        _reconnect_count = 0;
                        _state = SS_CONNECTED;

                        dinfo("client session %s:%d connected",
                            _remote_addr.name.c_str(),
                            static_cast<int>(_remote_addr.port)
                            );

                        set_options();

                        do_write();
                        do_read();                        
                    }
                    else
                    {
                        derror("network client session connect failed, error = %s",
                            ec.message().c_str()
                            );
                        on_failure();
                    }
                    release_reference();
                });
            }
        }
void hpc_rpc_session::do_write(message_ex* msg)
{
    add_ref();

    _write_event.callback = [this](int err, uint32_t length, uintptr_t lolp)
    {
        dassert((LPOVERLAPPED)lolp == &_write_event.olp, "must be exact this overlapped");
        if (err != ERROR_SUCCESS)
        {
            dwarn("WSASend failed, err = %d", err);
            on_failure();
        }
        else
        {
            int len = (int)length;
            int buf_i = _sending_buffer_start_index;
            while (len > 0)
            {
                auto& buf = _sending_buffers[buf_i];
                if (len >= (int)buf.sz)
                {
                    buf_i++;
                    len -= (int)buf.sz;
                }
                else
                {
                    buf.buf = (char*)buf.buf + len;
                    buf.sz -= (uint32_t)len;
                    break;
                }
            }
            _sending_buffer_start_index = buf_i;

            // message completed, continue next message
            if (_sending_buffer_start_index == (int)_sending_buffers.size())
            {
                dassert(len == 0, "buffer must be sent completely");
                auto lmsg = _sending_msg;
                _sending_msg = nullptr;
                on_send_completed(lmsg);
            }
            else
                do_write(_sending_msg);
        }

        release_ref();
    };
    memset(&_write_event.olp, 0, sizeof(_write_event.olp));

    // new msg
    if (_sending_msg != msg)
    {
        dassert(_sending_msg == nullptr, "only one sending msg is possible");
        _sending_msg = msg;
        _sending_buffer_start_index = 0;
    }

    // continue old msg
    else
    {
        // nothing to do
    }

    int buffer_count = (int)_sending_buffers.size() - _sending_buffer_start_index;
    static_assert (sizeof(dsn_message_parser::send_buf) == sizeof(WSABUF), "make sure they are compatible");

    DWORD bytes = 0;
    int rt = WSASend(
                 _socket,
                 (LPWSABUF)&_sending_buffers[_sending_buffer_start_index],
                 (DWORD)buffer_count,
                 &bytes,
                 0,
                 &_write_event.olp,
                 NULL
             );

    if (SOCKET_ERROR == rt && (WSAGetLastError() != ERROR_IO_PENDING))
    {
        dwarn("WSASend failed, err = %d", ::WSAGetLastError());
        release_ref();
        on_failure();
    }

    //dinfo("WSASend called, err = %d", rt);
}
        void hpc_rpc_session::do_write(message_ex* msg)
        {
            static_assert (sizeof(dsn_message_parser::send_buf) == sizeof(struct iovec), 
                "make sure they are compatible");

            dbg_dassert(msg != nullptr, "cannot send empty msg");
                        
            // new msg
            if (_sending_msg == nullptr)
            {
                _sending_msg = msg;
                _sending_buffer_start_index = 0;
            }

            // continue old msg
            else
            {
                dassert(_sending_msg == msg, "only one sending msg is possible");
            }

            // prepare send buffer, make sure header is already in the buffer
            while (true)
            {
                int buffer_count = (int)_sending_buffers.size() - _sending_buffer_start_index;
                struct msghdr hdr;
                memset((void*)&hdr, 0, sizeof(hdr));
                hdr.msg_name = (void*)&_peer_addr;
                hdr.msg_namelen = (socklen_t)sizeof(_peer_addr);
                hdr.msg_iov = (struct iovec*)&_sending_buffers[_sending_buffer_start_index];
                hdr.msg_iovlen = (size_t)buffer_count;

                int sz = sendmsg(_socket, &hdr, MSG_NOSIGNAL);
                int err = errno;
                dinfo("(s = %d) call sendmsg on %s:%hu, return %d, err = %s",
                    _socket,
                    _remote_addr.name(),
                    _remote_addr.port(),
                    sz,
                    strerror(err)
                    );

                if (sz < 0)
                {
                    if (err != EAGAIN && err != EWOULDBLOCK)
                    {
                        derror("(s = %d) sendmsg failed, err = %s", _socket, strerror(err));
                        on_failure();                        
                    }
                    else
                    {
                        // wait for epoll_wait notification
                    }
                    return;
                }
                else
                {
                    int len = (int)sz;
                    int buf_i = _sending_buffer_start_index;
                    while (len > 0)
                    {
                        auto& buf = _sending_buffers[buf_i];
                        if (len >= (int)buf.sz)
                        {
                            buf_i++;
                            len -= (int)buf.sz;
                        }
                        else
                        {
                            buf.buf = (char*)buf.buf + len;
                            buf.sz -= len;
                            break;
                        }
                    }
                    _sending_buffer_start_index = buf_i;

                    // message completed, continue next message
                    if (_sending_buffer_start_index == (int)_sending_buffers.size())
                    {
                        dassert(len == 0, "buffer must be sent completely");
                        _sending_msg = nullptr;

                        _send_lock.unlock(); // avoid recursion
                        // try next msg recursively
                        on_send_completed(msg);
                        _send_lock.lock();
                        return;
                    }

                    else
                    {
                        // try next while(true) loop to continue sending current msg
                    }
                }
            }
        }