#include "td/network/TCPSocket.h" #include "td/misc/Compression.h" #include #ifdef _WIN32 #define WOULDBLOCK WSAEWOULDBLOCK #define MSG_DONTWAIT 0 #else #define WOULDBLOCK EWOULDBLOCK #endif namespace td { namespace network { TCPSocket::TCPSocket() : Socket(Socket::TCP), m_Port(0) { m_Handle = static_cast(INVALID_SOCKET); } bool TCPSocket::Connect(const IPAddress& address, unsigned short port) { if (this->GetStatus() == Connected) return true; struct addrinfo hints {}; memset(&hints, 0, sizeof(addrinfo)); struct addrinfo* result = nullptr; hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; if (::getaddrinfo(address.ToString().c_str(), std::to_string(static_cast(port)).c_str(), &hints, &result) != 0) { std::cerr << "Failed to get address info !\n"; return false; } if ((m_Handle = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { std::cerr << "Failed to create socket !\n"; return false; } struct addrinfo* ptr = nullptr; for (ptr = result; ptr != nullptr; ptr = ptr->ai_next) { struct sockaddr* sockaddr = ptr->ai_addr; if (::connect(m_Handle, sockaddr, sizeof(sockaddr_in)) != 0) { std::cerr << "Failed to connect with this address !\n"; continue; } m_RemoteAddr = *sockaddr; break; } freeaddrinfo(result); if (!ptr) { std::cerr << "Could not find a suitable interface for connecting !\n"; return false; } this->SetStatus(Connected); m_RemoteIP = address; m_Port = port; return true; } size_t TCPSocket::Send(const unsigned char* data, size_t size) { if (this->GetStatus() != Connected) return 0; size_t sent = 0; while (sent < size) { int cur = ::send(m_Handle, reinterpret_cast(data + sent), size - sent, 0); if (cur <= 0) { Disconnect(); return 0; } sent += static_cast(cur); } return sent; } std::size_t TCPSocket::Receive(DataBuffer& buffer, std::size_t amount) { buffer.Resize(amount); buffer.SetReadOffset(0); int recvAmount = ::recv(m_Handle, reinterpret_cast(buffer.data()), amount, 0); if (recvAmount <= 0) { #if defined(_WIN32) || defined(WIN32) int err = WSAGetLastError(); #else int err = errno; #endif if (err == WOULDBLOCK) { buffer.Clear(); return 0; } Disconnect(); buffer.Clear(); return 0; } buffer.Resize(static_cast(recvAmount)); return static_cast(recvAmount); } DataBuffer TCPSocket::Receive(std::size_t amount) { std::unique_ptr buf(new char[amount]); int received = ::recv(m_Handle, buf.get(), amount, 0); if (received <= 0) { #if defined(_WIN32) || defined(WIN32) int err = WSAGetLastError(); #else int err = errno; #endif if (err == WOULDBLOCK) return DataBuffer(); Disconnect(); return DataBuffer(); } return DataBuffer(std::string(buf.get(), static_cast(received))); } TCPSocket::TCPSocket(TCPSocket&& other) : Socket(TCP) { m_Handle = other.m_Handle; m_Port = other.m_Port; m_RemoteAddr = other.m_RemoteAddr; m_RemoteIP = other.m_RemoteIP; SetStatus(other.GetStatus()); SetBlocking(other.IsBlocking()); other.m_Handle = static_cast(INVALID_SOCKET); } void SendPacket(const DataBuffer& data, network::TCPSocket& socket) { DataBuffer compressed = utils::Compress(data); socket.Send(reinterpret_cast(compressed.ToString().data()), compressed.GetSize()); } } // ns network } // ns mc