19 _fd = socket(AF_INET, SOCK_STREAM, 0);
21 throw TcpException(
"Failed to create socket: " + std::string(strerror(errno)));
25 int flags = fcntl(
_fd, F_GETFL, 0);
26 if (flags == -1 || fcntl(
_fd, F_SETFL, flags | O_NONBLOCK) == -1) {
29 throw TcpException(
"Failed to set non-blocking mode: " + std::string(strerror(errno)));
33 struct addrinfo hints = {};
34 struct addrinfo* result =
nullptr;
36 hints.ai_family = AF_INET;
37 hints.ai_socktype = SOCK_STREAM;
39 std::string portStr = std::to_string(port);
40 int err = getaddrinfo(host.c_str(), portStr.c_str(), &hints, &result);
44 throw TcpException(
"Failed to resolve host: " + std::string(gai_strerror(err)));
48 int connectResult =
::connect(
_fd, result->ai_addr, result->ai_addrlen);
51 if (connectResult == -1 && errno != EINPROGRESS) {
54 throw TcpException(
"Failed to connect: " + std::string(strerror(errno)));
60 FD_SET(
_fd, &writefds);
62 struct timeval timeout;
66 int selectResult = select(
_fd + 1,
nullptr, &writefds,
nullptr, &timeout);
67 if (selectResult <= 0) {
70 throw TcpException(selectResult == 0 ?
"Connection timeout" :
"Connection failed");
75 socklen_t len =
sizeof(error);
76 if (getsockopt(
_fd, SOL_SOCKET, SO_ERROR, &error, &len) == -1 || error != 0) {
79 throw TcpException(
"Connection failed: " + std::string(strerror(error)));
103 if (newlinePos != std::string::npos) {
104 std::string line =
_recvBuffer.substr(0, newlinePos + 1);
111 ssize_t received = recv(
_fd, buffer,
sizeof(buffer), MSG_DONTWAIT);
113 if (received == -1) {
114 if (errno == EAGAIN || errno == EWOULDBLOCK) {
118 throw TcpException(
"Failed to receive data: " + std::string(strerror(errno)));
119 }
else if (received == 0) {
129 if (newlinePos != std::string::npos) {
130 std::string line =
_recvBuffer.substr(0, newlinePos + 1);