spdlog
Loading...
Searching...
No Matches
tcp_client-windows.h
Go to the documentation of this file.
1// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
2// Distributed under the MIT License (http://opensource.org/licenses/MIT)
3
4#pragma once
5
6#define WIN32_LEAN_AND_MEAN
7// tcp client helper
8#include <spdlog/common.h>
9#include <spdlog/details/os.h>
10
11#include <winsock2.h>
12#include <windows.h>
13#include <ws2tcpip.h>
14#include <stdlib.h>
15#include <stdio.h>
16#include <string>
17
18#pragma comment(lib, "Ws2_32.lib")
19#pragma comment(lib, "Mswsock.lib")
20#pragma comment(lib, "AdvApi32.lib")
21
22namespace spdlog {
23namespace details {
25{
26 SOCKET socket_ = INVALID_SOCKET;
27
29 {
30 SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
31 if (s == INVALID_SOCKET)
32 {
33 return false;
34 }
35 else
36 {
37 closesocket(s);
38 return true;
39 }
40 }
41
42 static void init_winsock_()
43 {
44 WSADATA wsaData;
45 auto rv = WSAStartup(MAKEWORD(2, 2), &wsaData);
46 if (rv != 0)
47 {
48 throw_winsock_error_("WSAStartup failed", ::WSAGetLastError());
49 }
50 }
51
52 static void throw_winsock_error_(const std::string &msg, int last_error)
53 {
54 char buf[512];
55 ::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, last_error,
56 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, (sizeof(buf) / sizeof(char)), NULL);
57
58 throw_spdlog_ex(fmt::format("tcp_sink - {}: {}", msg, buf));
59 }
60
61public:
62 bool is_connected() const
63 {
64 return socket_ != INVALID_SOCKET;
65 }
66
67 void close()
68 {
69 ::closesocket(socket_);
70 socket_ = INVALID_SOCKET;
71 WSACleanup();
72 }
73
74 SOCKET fd() const
75 {
76 return socket_;
77 }
78
80 {
81 close();
82 }
83
84 // try to connect or throw on failure
85 void connect(const std::string &host, int port)
86 {
87 // initialize winsock if needed
89 {
91 }
92
93 if (is_connected())
94 {
95 close();
96 }
97 struct addrinfo hints
98 {};
99 ZeroMemory(&hints, sizeof(hints));
100
101 hints.ai_family = AF_INET; // IPv4
102 hints.ai_socktype = SOCK_STREAM; // TCP
103 hints.ai_flags = AI_NUMERICSERV; // port passed as as numeric value
104 hints.ai_protocol = 0;
105
106 auto port_str = std::to_string(port);
107 struct addrinfo *addrinfo_result;
108 auto rv = ::getaddrinfo(host.c_str(), port_str.c_str(), &hints, &addrinfo_result);
109 int last_error = 0;
110 if (rv != 0)
111 {
112 last_error = ::WSAGetLastError();
113 WSACleanup();
114 throw_winsock_error_("getaddrinfo failed", last_error);
115 }
116
117 // Try each address until we successfully connect(2).
118
119 for (auto *rp = addrinfo_result; rp != nullptr; rp = rp->ai_next)
120 {
121 socket_ = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
122 if (socket_ == INVALID_SOCKET)
123 {
124 last_error = ::WSAGetLastError();
125 WSACleanup();
126 continue;
127 }
128 if (::connect(socket_, rp->ai_addr, (int)rp->ai_addrlen) == 0)
129 {
130 break;
131 }
132 else
133 {
134 last_error = ::WSAGetLastError();
135 close();
136 }
137 }
138 ::freeaddrinfo(addrinfo_result);
139 if (socket_ == INVALID_SOCKET)
140 {
141 WSACleanup();
142 throw_winsock_error_("connect failed", last_error);
143 }
144
145 // set TCP_NODELAY
146 int enable_flag = 1;
147 ::setsockopt(socket_, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<char *>(&enable_flag), sizeof(enable_flag));
148 }
149
150 // Send exactly n_bytes of the given data.
151 // On error close the connection and throw.
152 void send(const char *data, size_t n_bytes)
153 {
154 size_t bytes_sent = 0;
155 while (bytes_sent < n_bytes)
156 {
157 const int send_flags = 0;
158 auto write_result = ::send(socket_, data + bytes_sent, (int)(n_bytes - bytes_sent), send_flags);
159 if (write_result == SOCKET_ERROR)
160 {
161 int last_error = ::WSAGetLastError();
162 close();
163 throw_winsock_error_("send failed", last_error);
164 }
165
166 if (write_result == 0) // (probably should not happen but in any case..)
167 {
168 break;
169 }
170 bytes_sent += static_cast<size_t>(write_result);
171 }
172 }
173};
174} // namespace details
175} // namespace spdlog
T c_str(T... args)
void connect(const std::string &host, int port)
void send(const char *data, size_t n_bytes)
static void throw_winsock_error_(const std::string &msg, int last_error)
Definition async.h:25
SPDLOG_INLINE void throw_spdlog_ex(const std::string &msg, int last_errno)
Definition common-inl.h:68
Definition format.h:897
T to_string(T... args)