Ember
Loading...
Searching...
No Matches
TCPServer.cpp
Go to the documentation of this file.
1#include "Network/TCPServer.h"
2
3#include <arpa/inet.h>
4#include <cerrno>
5#include <cstring>
6#include <fcntl.h>
7#include <netinet/in.h>
8#include <sys/select.h>
9#include <sys/socket.h>
10#include <unistd.h>
11
12namespace Ember {
13namespace Monitor {
14
16
18
19bool TCPServer::SetNonBlocking(int socket) {
20 int flags = fcntl(socket, F_GETFL, 0);
21 if (flags == -1) {
22 return false;
23 }
24 return fcntl(socket, F_SETFL, flags | O_NONBLOCK) != -1;
25}
26
27bool TCPServer::Start(uint16_t port) {
28 if (IsRunning()) {
29 Stop();
30 }
31
32 m_serverSocket = socket(AF_INET, SOCK_STREAM, 0);
33 if (m_serverSocket < 0) {
34 return false;
35 }
36
37 int opt = 1;
38 if (setsockopt(m_serverSocket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
39 close(m_serverSocket);
40 m_serverSocket = -1;
41 return false;
42 }
43
45 close(m_serverSocket);
46 m_serverSocket = -1;
47 return false;
48 }
49
50 struct sockaddr_in addr;
51 std::memset(&addr, 0, sizeof(addr));
52 addr.sin_family = AF_INET;
53 addr.sin_addr.s_addr = INADDR_ANY;
54 addr.sin_port = htons(port);
55
56 if (bind(m_serverSocket, reinterpret_cast<struct sockaddr *>(&addr), sizeof(addr)) < 0) {
57 close(m_serverSocket);
58 m_serverSocket = -1;
59 return false;
60 }
61
62 if (listen(m_serverSocket, 1) < 0) {
63 close(m_serverSocket);
64 m_serverSocket = -1;
65 return false;
66 }
67
68 m_port = port;
69 return true;
70}
71
74
75 if (m_serverSocket >= 0) {
76 close(m_serverSocket);
77 m_serverSocket = -1;
78 }
79 m_port = 0;
80}
81
83 if (m_clientSocket >= 0) {
84 close(m_clientSocket);
85 m_clientSocket = -1;
86 m_clientAddress.clear();
87 m_clientName.clear();
88 m_recvBuffer.clear();
89
92 }
93 }
94}
95
97 struct sockaddr_in clientAddr;
98 socklen_t addrLen = sizeof(clientAddr);
99
100 int newSocket = accept(m_serverSocket, reinterpret_cast<struct sockaddr *>(&clientAddr), &addrLen);
101 if (newSocket < 0) {
102 return;
103 }
104
105 if (IsClientConnected()) {
107 }
108
109 if (!SetNonBlocking(newSocket)) {
110 close(newSocket);
111 return;
112 }
113
114 m_clientSocket = newSocket;
115
116 char addrStr[INET_ADDRSTRLEN];
117 inet_ntop(AF_INET, &clientAddr.sin_addr, addrStr, INET_ADDRSTRLEN);
118 m_clientAddress = std::string(addrStr) + ":" + std::to_string(ntohs(clientAddr.sin_port));
119
120 if (m_connectCallback) {
122 }
123}
124
126 if (!IsClientConnected()) {
127 return;
128 }
129
130 uint8_t tempBuffer[65536];
131 for (;;) {
132 ssize_t bytesRead = recv(m_clientSocket, tempBuffer, sizeof(tempBuffer), 0);
133
134 if (bytesRead < 0) {
135 if (errno == EAGAIN || errno == EWOULDBLOCK) {
136 break;
137 }
139 return;
140 }
141
142 if (bytesRead == 0) {
144 return;
145 }
146
147 m_recvBuffer.insert(m_recvBuffer.end(), tempBuffer, tempBuffer + bytesRead);
148 }
149
150 while (m_recvBuffer.size() >= Network::FRAME_HEADER_SIZE) {
151 uint32_t payloadLength = 0;
153
154 if (!Network::MessageFrame::ParseHeader(m_recvBuffer.data(), m_recvBuffer.size(), payloadLength, msgType)) {
155 break;
156 }
157
158 size_t totalFrameSize = Network::FRAME_HEADER_SIZE + payloadLength;
159 if (m_recvBuffer.size() < totalFrameSize) {
160 break;
161 }
162
164
165 m_recvBuffer.erase(m_recvBuffer.begin(), m_recvBuffer.begin() + totalFrameSize);
166
167 if (frame.IsValid() && m_messageCallback) {
168 m_messageCallback(frame);
169 }
170 }
171}
172
174 if (!IsRunning()) {
175 return;
176 }
177
178 fd_set readFds;
179 FD_ZERO(&readFds);
180 FD_SET(m_serverSocket, &readFds);
181
182 int maxFd = m_serverSocket;
183
184 if (IsClientConnected()) {
185 FD_SET(m_clientSocket, &readFds);
186 if (m_clientSocket > maxFd) {
187 maxFd = m_clientSocket;
188 }
189 }
190
191 struct timeval timeout;
192 timeout.tv_sec = 0;
193 timeout.tv_usec = 0;
194
195 int activity = select(maxFd + 1, &readFds, nullptr, nullptr, &timeout);
196 if (activity < 0) {
197 return;
198 }
199
200 if (FD_ISSET(m_serverSocket, &readFds)) {
202 }
203
204 if (IsClientConnected() && FD_ISSET(m_clientSocket, &readFds)) {
206 }
207}
208
210 if (!IsClientConnected()) {
211 return false;
212 }
213
214 std::vector<uint8_t> data = frame.ToBytes();
215 size_t totalSent = 0;
216
217 while (totalSent < data.size()) {
218 ssize_t sent = send(m_clientSocket, data.data() + totalSent, data.size() - totalSent, MSG_NOSIGNAL);
219 if (sent < 0) {
220 if (errno == EAGAIN || errno == EWOULDBLOCK) {
221 continue;
222 }
224 return false;
225 }
226 totalSent += static_cast<size_t>(sent);
227 }
228
229 return true;
230}
231
232} // namespace Monitor
233} // namespace Ember
ConnectCallback m_connectCallback
Definition TCPServer.h:74
void Stop()
Stops the server and disconnects any client.
Definition TCPServer.cpp:72
bool Send(const Network::MessageFrame &frame)
Sends a message frame to the connected client. Returns true on success.
bool Start(uint16_t port)
Starts the server listening on the given port. Returns true on success.
Definition TCPServer.cpp:27
DisconnectCallback m_disconnectCallback
Definition TCPServer.h:75
void DisconnectClient()
Disconnects the current client without stopping the server.
Definition TCPServer.cpp:82
std::vector< uint8_t > m_recvBuffer
Definition TCPServer.h:71
bool IsClientConnected() const
Returns true if a client is currently connected.
Definition TCPServer.h:33
bool IsRunning() const
Returns true if the server is listening.
Definition TCPServer.h:31
std::string m_clientAddress
Definition TCPServer.h:67
void Poll()
Processes pending I/O (accept, read). Call periodically from the main loop.
MessageCallback m_messageCallback
Definition TCPServer.h:73
bool SetNonBlocking(int socket)
Definition TCPServer.cpp:19
constexpr size_t FRAME_HEADER_SIZE
static MessageFrame FromBytes(const uint8_t *data, size_t dataSize)
static bool ParseHeader(const uint8_t *data, size_t dataSize, uint32_t &outLength, Protocol::MessageType &outType)
std::vector< uint8_t > ToBytes() const