Enigma  3.2.0
A Simple, Reliable and Efficient Encryption Tool
SingleProcessInstance.hpp
Go to the documentation of this file.
1 #pragma once
2 #ifndef ENIGMA_SINGLE_INSTANCE_H
3 #define ENIGMA_SINGLE_INSTANCE_H
4 
5 #if defined(ENIGMA_PLATFORM_WINDOWS)
6 #ifndef WIN32_LEAN_AND_MEAN
7 #define WIN32_LEAN_AND_MEAN
8 #endif
9 #if defined(_WIN32_WINNT)
10 #undef _WIN32_WINNT
11 #define _WIN32_WINNT 0x06000100
12 #endif
13 #include <Winsock2.h> // WARNING: make sure winsock is included before windows.h
14 #include <SDKDDKVer.h>
15 #include <Windows.h>
16 using socket_t = SOCKET;
17 constexpr socket_t M_INVALID_SOCKET = INVALID_SOCKET;
18 #else
19 //#elif defined(ENIGMA_PLATFORM_LINUX) || defined(ENIGMA_PLATFORM_MACOS)
20 // Linux/Unix libraries will work in macos aswell.
21 #include <netinet/in.h>
22 using socket_t = std::int32_t;
23 constexpr socket_t M_INVALID_SOCKET = -1;
24 #endif
25 
26 #include <Core/Core.hpp>
27 #include <Logger/Logger.hpp>
28 
36  public:
40  explicit SingleProcessInstance(const std::uint16_t port) noexcept
41  : m_socket_fd(M_INVALID_SOCKET),
42  m_port(port),
43  m_rc(-1) {
44 #if defined(ENIGMA_PLATFORM_WINDOWS)
45  // Windows Initialize WinSock
46  WSAData data{};
47  const auto err = WSAStartup(MAKEWORD(2, 2), &data);
48  if (err != 0) {
49  // https://docs.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-wsastartup
50  auto err_reason = [err]() -> const char * {
51 #define CASE_RET(c, v) \
52  case c: \
53  return v
54  switch (err) {
55  CASE_RET(WSASYSNOTREADY, "The underlying network subsystem is not ready for network communication.");
56  CASE_RET(WSAVERNOTSUPPORTED, "The version of Windows Sockets support requested is not provided by this particular Windows Sockets implementation.");
57  CASE_RET(WSAEINPROGRESS, "A blocking Windows Sockets 1.1 operation is in progress.");
58  CASE_RET(WSAEPROCLIM, "A limit on the number of tasks supported by the Windows Sockets implementation has been reached.");
59  CASE_RET(WSAEFAULT, "The lpWSAData parameter is not a valid pointer.");
60  default:
61  return "<unknown winsock err>";
62  }
63 #undef CASE_RET
64  };
65 
66  ENIGMA_ERROR("Failed to start WinSock: #{}: {}", err, err_reason());
67  return;
68  }
69 #endif
70 
71  // Create socket
72  m_socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
73  if (m_socket_fd != M_INVALID_SOCKET) {
74  // Bind to socket
75  struct sockaddr_in name {};
76  name.sin_family = AF_INET;
77  name.sin_port = htons(port);
78  name.sin_addr.s_addr = htonl(INADDR_ANY);
79  m_rc = bind(m_socket_fd, (struct sockaddr *) &name, sizeof(name));
80  if (m_rc < 0) {
81  ENIGMA_ERROR("Failed to bind socket: {}", std::strerror(errno));
82  return;
83  }
84  } else {
85  ENIGMA_ERROR("Failed to create socket: {}", std::strerror(errno));
86  return;
87  }
88 
89  ENIGMA_INFO("Created Single Process Instance Socket: {} Port: {}", m_socket_fd, m_port);
90  }
91 
93  bool IsUnique() const noexcept {
94  return (m_socket_fd != M_INVALID_SOCKET) && (m_rc == 0); // valid socket and no binding errors.
95  }
96 
100  virtual ~SingleProcessInstance() noexcept {
101  if (m_socket_fd != M_INVALID_SOCKET) {
102 #if defined(ENIGMA_PLATFORM_WINDOWS)
103  closesocket(m_socket_fd);
104  WSACleanup(); // Shutdown WinSock
105 #else
106  close(m_socket_fd);
107 #endif
108  ENIGMA_INFO("Closed Single Process Instance Socket: {} Port: {}", m_socket_fd, m_port);
109  }
110  }
111 
112  private:
113  socket_t m_socket_fd{};
114  std::uint16_t m_port{};
115  std::int32_t m_rc{};
116 };
118 
119 #endif // !ENIGMA_SINGLE_INSTANCE_H
#define CASE_RET(c)
#define ENIGMA_ERROR(...)
Definition: Logger.hpp:43
#define ENIGMA_INFO(...)
Definition: Logger.hpp:41
#define NS_ENIGMA_BEGIN
Enable/Disable Assertions.
Definition: Macros.hpp:13
#define NS_ENIGMA_END
Definition: Macros.hpp:14
std::int32_t socket_t
constexpr socket_t M_INVALID_SOCKET
Single process instance class.
virtual ~SingleProcessInstance() noexcept
bool IsUnique() const noexcept
SingleProcessInstance(const std::uint16_t port) noexcept