File indexing completed on 2025-07-03 08:52:59
0001
0002
0003
0004 #pragma once
0005
0006 #define WIN32_LEAN_AND_MEAN
0007
0008 #include <spdlog/common.h>
0009 #include <spdlog/details/os.h>
0010
0011 #include <stdio.h>
0012 #include <stdlib.h>
0013 #include <string>
0014 #include <windows.h>
0015 #include <winsock2.h>
0016 #include <ws2tcpip.h>
0017
0018 #pragma comment(lib, "Ws2_32.lib")
0019 #pragma comment(lib, "Mswsock.lib")
0020 #pragma comment(lib, "AdvApi32.lib")
0021
0022 namespace spdlog {
0023 namespace details {
0024 class tcp_client {
0025 SOCKET socket_ = INVALID_SOCKET;
0026
0027 static void init_winsock_() {
0028 WSADATA wsaData;
0029 auto rv = WSAStartup(MAKEWORD(2, 2), &wsaData);
0030 if (rv != 0) {
0031 throw_winsock_error_("WSAStartup failed", ::WSAGetLastError());
0032 }
0033 }
0034
0035 static void throw_winsock_error_(const std::string &msg, int last_error) {
0036 char buf[512];
0037 ::FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL,
0038 last_error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf,
0039 (sizeof(buf) / sizeof(char)), NULL);
0040
0041 throw_spdlog_ex(fmt_lib::format("tcp_sink - {}: {}", msg, buf));
0042 }
0043
0044 public:
0045 tcp_client() { init_winsock_(); }
0046
0047 ~tcp_client() {
0048 close();
0049 ::WSACleanup();
0050 }
0051
0052 bool is_connected() const { return socket_ != INVALID_SOCKET; }
0053
0054 void close() {
0055 ::closesocket(socket_);
0056 socket_ = INVALID_SOCKET;
0057 }
0058
0059 SOCKET fd() const { return socket_; }
0060
0061
0062 void connect(const std::string &host, int port) {
0063 if (is_connected()) {
0064 close();
0065 }
0066 struct addrinfo hints {};
0067 ZeroMemory(&hints, sizeof(hints));
0068
0069 hints.ai_family = AF_UNSPEC;
0070 hints.ai_socktype = SOCK_STREAM;
0071 hints.ai_flags = AI_NUMERICSERV;
0072 hints.ai_protocol = 0;
0073
0074 auto port_str = std::to_string(port);
0075 struct addrinfo *addrinfo_result;
0076 auto rv = ::getaddrinfo(host.c_str(), port_str.c_str(), &hints, &addrinfo_result);
0077 int last_error = 0;
0078 if (rv != 0) {
0079 last_error = ::WSAGetLastError();
0080 WSACleanup();
0081 throw_winsock_error_("getaddrinfo failed", last_error);
0082 }
0083
0084
0085
0086 for (auto *rp = addrinfo_result; rp != nullptr; rp = rp->ai_next) {
0087 socket_ = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
0088 if (socket_ == INVALID_SOCKET) {
0089 last_error = ::WSAGetLastError();
0090 WSACleanup();
0091 continue;
0092 }
0093 if (::connect(socket_, rp->ai_addr, (int)rp->ai_addrlen) == 0) {
0094 break;
0095 } else {
0096 last_error = ::WSAGetLastError();
0097 close();
0098 }
0099 }
0100 ::freeaddrinfo(addrinfo_result);
0101 if (socket_ == INVALID_SOCKET) {
0102 WSACleanup();
0103 throw_winsock_error_("connect failed", last_error);
0104 }
0105
0106
0107 int enable_flag = 1;
0108 ::setsockopt(socket_, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<char *>(&enable_flag),
0109 sizeof(enable_flag));
0110 }
0111
0112
0113
0114 void send(const char *data, size_t n_bytes) {
0115 size_t bytes_sent = 0;
0116 while (bytes_sent < n_bytes) {
0117 const int send_flags = 0;
0118 auto write_result =
0119 ::send(socket_, data + bytes_sent, (int)(n_bytes - bytes_sent), send_flags);
0120 if (write_result == SOCKET_ERROR) {
0121 int last_error = ::WSAGetLastError();
0122 close();
0123 throw_winsock_error_("send failed", last_error);
0124 }
0125
0126 if (write_result == 0)
0127 {
0128 break;
0129 }
0130 bytes_sent += static_cast<size_t>(write_result);
0131 }
0132 }
0133 };
0134 }
0135 }