File indexing completed on 2025-01-18 10:12:41
0001
0002
0003
0004 #pragma once
0005
0006
0007
0008
0009 #include <spdlog/common.h>
0010 #include <spdlog/details/os.h>
0011 #include <spdlog/details/windows_include.h>
0012 #include <winsock2.h>
0013 #include <ws2tcpip.h>
0014 #include <stdlib.h>
0015 #include <stdio.h>
0016 #include <string>
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 udp_client
0025 {
0026 static constexpr int TX_BUFFER_SIZE = 1024 * 10;
0027 SOCKET socket_ = INVALID_SOCKET;
0028 sockaddr_in addr_ = {0};
0029
0030 static void init_winsock_()
0031 {
0032 WSADATA wsaData;
0033 auto rv = ::WSAStartup(MAKEWORD(2, 2), &wsaData);
0034 if (rv != 0)
0035 {
0036 throw_winsock_error_("WSAStartup failed", ::WSAGetLastError());
0037 }
0038 }
0039
0040 static void throw_winsock_error_(const std::string &msg, int last_error)
0041 {
0042 char buf[512];
0043 ::FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, last_error,
0044 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, (sizeof(buf) / sizeof(char)), NULL);
0045
0046 throw_spdlog_ex(fmt_lib::format("udp_sink - {}: {}", msg, buf));
0047 }
0048
0049 void cleanup_()
0050 {
0051 if (socket_ != INVALID_SOCKET)
0052 {
0053 ::closesocket(socket_);
0054 }
0055 socket_ = INVALID_SOCKET;
0056 ::WSACleanup();
0057 }
0058
0059 public:
0060 udp_client(const std::string &host, uint16_t port)
0061 {
0062 init_winsock_();
0063
0064 addr_.sin_family = PF_INET;
0065 addr_.sin_port = htons(port);
0066 addr_.sin_addr.s_addr = INADDR_ANY;
0067 if (InetPtonA(PF_INET, host.c_str(), &addr_.sin_addr.s_addr) != 1)
0068 {
0069 int last_error = ::WSAGetLastError();
0070 ::WSACleanup();
0071 throw_winsock_error_("error: Invalid address!", last_error);
0072 }
0073
0074 socket_ = ::socket(PF_INET, SOCK_DGRAM, 0);
0075 if (socket_ == INVALID_SOCKET)
0076 {
0077 int last_error = ::WSAGetLastError();
0078 ::WSACleanup();
0079 throw_winsock_error_("error: Create Socket failed", last_error);
0080 }
0081
0082 int option_value = TX_BUFFER_SIZE;
0083 if (::setsockopt(socket_, SOL_SOCKET, SO_SNDBUF, reinterpret_cast<const char *>(&option_value), sizeof(option_value)) < 0)
0084 {
0085 int last_error = ::WSAGetLastError();
0086 cleanup_();
0087 throw_winsock_error_("error: setsockopt(SO_SNDBUF) Failed!", last_error);
0088 }
0089 }
0090
0091 ~udp_client()
0092 {
0093 cleanup_();
0094 }
0095
0096 SOCKET fd() const
0097 {
0098 return socket_;
0099 }
0100
0101 void send(const char *data, size_t n_bytes)
0102 {
0103 socklen_t tolen = sizeof(struct sockaddr);
0104 if (::sendto(socket_, data, static_cast<int>(n_bytes), 0, (struct sockaddr *)&addr_, tolen) == -1)
0105 {
0106 throw_spdlog_ex("sendto(2) failed", errno);
0107 }
0108 }
0109 };
0110 }
0111 }