#include "TCPClient.h" #include "TCPListener.h" #include "NetworkManager.h" #include #include #include #include "logging/Logger.h" #include namespace Feather::Network { TCPClient::TCPClient(TCPListener* parent, SocketHandle socket, SocketAddress&& addr) : m_parent(parent) , m_bufferEvent(bufferevent_socket_new(NetworkManager::Instance().GetEventBase(), socket, BEV_OPT_CLOSE_ON_FREE | BEV_OPT_THREADSAFE | BEV_OPT_DEFER_CALLBACKS | BEV_OPT_UNLOCK_CALLBACKS)) , m_address(std::move(addr)) { bufferevent_setcb(m_bufferEvent, [](bufferevent* be, void* self) { static_cast(self)->ReadCallback(); }, [](bufferevent* be, void* self) { static_cast(self)->WriteCallback(); }, [](bufferevent* be, int16_t event, void* self) { static_cast(self)->EventCallback(event); }, this); bufferevent_enable(m_bufferEvent, EV_READ | EV_WRITE); } TCPClient::~TCPClient() { bufferevent_free(m_bufferEvent); } void TCPClient::ReadCallback() { evbuffer* buffer = bufferevent_get_input(m_bufferEvent); const size_t size = evbuffer_get_length(buffer); auto [data, lock] = m_data.borrow(); const size_t offset = data.size(); data.resize(offset + size); if (evbuffer_remove(buffer, &data[offset], size) != size) { Log::Error("Failed to remove data from buffer."); return; } } void TCPClient::WriteCallback() { } void TCPClient::EventCallback(int16_t event) { if (event & BEV_EVENT_ERROR) { const char* errorString = evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR()); Log::Error("TCPClient: {}", errorString); } if (event & BEV_EVENT_EOF) m_parent->OnClientDisconnected(this); } void TCPClient::Write(const uint8_t* data, size_t size) { if (bufferevent_write(m_bufferEvent, data, size) != 0) Log::Error("Failed to write to socket, size: " PRIuPTR ".", size); } }