MXVK Vulkan Framework 0.24.0
C++20 Vulkan rendering framework for practical 2D and 3D application development with SDL3.
Loading...
Searching...
No Matches
relay.cpp
Go to the documentation of this file.
2#include <atomic>
3#include <cstdlib>
4#include <iostream>
5#include <mutex>
6#include <poll.h>
7#include <signal.h>
8#include <string>
9#include <thread>
10#include <vector>
11
12std::atomic<bool> active{false};
13std::mutex mut;
14static constexpr size_t BUFFER_SIZE = 1024 * 8;
15
16class Relay {
17 public:
19 std::cout << "relay: init.\n";
21 }
23 std::cout << "relay: quit.\n";
24 }
25 void stop() {
26 active.store(false);
27 }
28 bool listen(std::string_view port) {
29 if (sockfd.listen(port, 5)) {
30 active.store(true);
31 std::vector<mxnetwork::Socket> sockets;
32 Messages message(&sockets);
33 std::thread background(std::move(message));
34 while (active.load()) {
35 std::optional<mxnetwork::Socket> new_s = sockfd.accept();
36 if (new_s == std::nullopt) {
37 if (errno == EINTR)
38 continue;
39 active.store(false);
40 continue;
41 }
42 mut.lock();
43 new_s->setblocking(false);
44 sockets.push_back(std::move(*new_s));
45 mut.unlock();
46 }
47 background.join();
48 } else {
49 perror("listen");
50 return false;
51 }
52 return true;
53 }
54
55 private:
57 class Messages {
58 public:
59 Messages(std::vector<mxnetwork::Socket> *s) : sockets(s) {}
60 void operator()() {
61 while (active.load()) {
62 std::vector<pollfd> p_fd;
63 {
64 std::lock_guard<std::mutex> lock(mut);
65 p_fd.reserve(sockets->size());
66 for (const auto &s : *sockets) {
67 pollfd pfd{};
68 pfd.fd = s.sockfd();
69 pfd.events = POLLIN;
70 p_fd.push_back(pfd);
71 }
72 }
73
74 if (p_fd.empty()) {
75 std::this_thread::sleep_for(std::chrono::milliseconds(10));
76 continue;
77 }
78
79 int value = poll(p_fd.data(), p_fd.size(), 100);
80 if (value <= 0)
81 continue;
82 std::lock_guard<std::mutex> lock(mut);
83 if (p_fd.size() != sockets->size())
84 continue;
85 for (size_t i = 0; i < p_fd.size(); ++i) {
86 if (p_fd[i].revents & POLLIN) {
87 char buffer[BUFFER_SIZE] = {};
88 ssize_t bytes = (*sockets)[i].read(buffer, BUFFER_SIZE - 1, 0);
89 if (bytes < 0) {
90 if (errno != EAGAIN || errno != EWOULDBLOCK) {
91 if (!sockets->empty())
92 (*sockets)[i].close();
93 }
94 } else if (bytes == 0) {
95 (*sockets)[i].close();
96 std::cout << "relay: Disconnected safely.\n";
97 } else {
98 buffer[bytes] = 0;
99 std::cout << "relay: Got message: " << buffer << "\n";
100 send_all(i, buffer, bytes);
101 }
102 }
103 }
104 std::erase_if(*sockets, [](const mxnetwork::Socket &s) {
106 if (dead) {
107 std::cout << "relay: removing dead socket.\n";
108 }
109 return dead;
110 });
111 }
112 }
113
114 void send_all(size_t i, const char *buffer, size_t bytes) {
115 for (size_t z = 0; z < sockets->size(); ++z) {
116 if (i != z) {
117 ssize_t b = (*sockets)[z].write(buffer, bytes, 0);
118 if (b == -1) {
119 if (errno != EAGAIN && errno != EWOULDBLOCK)
120 if (!sockets->empty())
121 (*sockets)[z].close();
122 continue;
123 }
124 std::cout << "relay: Sent message to: " << (*sockets)[z].sockfd() << " " << buffer << "\n";
125 }
126 }
127 }
128
129 std::vector<mxnetwork::Socket> *sockets;
130 };
131};
132
133void quit_signal(int) {
134 active.store(false);
135}
136
137int main(int argc, char **argv) {
138
139 if (argc != 2) {
140 std::cout << "Use:\n"
141 << argv[0] << " <port>\n";
142 return EXIT_FAILURE;
143 }
144 try {
145
146 struct sigaction sa{};
147 sa.sa_handler = quit_signal;
148 if (sigaction(SIGINT, &sa, nullptr) == -1) {
149 perror("sigaction");
150 return EXIT_FAILURE;
151 }
152
153 Relay relay;
154 relay.listen(argv[1]);
155 return EXIT_SUCCESS;
156 } catch (const mxnetwork::Exception &e) {
157 std::cerr << "relay: Exception: " << e.text() << "\n";
158 return EXIT_FAILURE;
159 }
160 return EXIT_SUCCESS;
161}
void stop()
Definition relay.cpp:25
~Relay()
Definition relay.cpp:22
Relay()
Definition relay.cpp:18
bool listen(std::string_view port)
Definition relay.cpp:28
Lightweight exception wrapper for MXNetwork failures.
Definition exception.hpp:11
std::string text() const
Return the stored error text.
Definition exception.cpp:5
C++ wrapper around the MXNetwork socket API.
Definition socket.hpp:57
SocketType socket_type() const
Return the socket family and transport type.
Definition socket.cpp:179
int main(void)
Definition main.cpp:7
void mx_socket_ignore_pipe_signal()
Ignore SIGPIPE on platforms that require it.
Definition mxsocket.c:577
@ TYPE_INVALID
No socket type selected.
Definition socket.hpp:39
@ TYPE_INET
IPv4 stream socket.
Definition socket.hpp:41
void quit_signal(int)
Definition relay.cpp:133
std::mutex mut
Definition relay.cpp:13
std::atomic< bool > active
Definition relay.cpp:12