Enigma 3.2.2
A Simple, Reliable and Efficient Encryption Tool
Loading...
Searching...
No Matches
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>
16using socket_t = SOCKET;
17constexpr 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>
22using socket_t = std::int32_t;
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