3434#include < cstddef>
3535#include < cstdint>
3636#include < functional>
37+ #include < mutex>
3738#include < thread>
3839#include < vector>
3940
@@ -79,9 +80,13 @@ class TCPServer
7980 *
8081 * \param func Function handling the event information. The file descriptor created by the
8182 * connection event will be passed to the function.
83+ *
84+ * \note: The connection callback will be triggered with the socket being accepted. Hence, it
85+ * is possible to send data from the connection callback directly.
8286 */
8387 void setConnectCallback (std::function<void (const socket_t )> func)
8488 {
89+ std::lock_guard<std::mutex> lk (callback_mutex_);
8590 new_connection_callback_ = func;
8691 }
8792
@@ -90,9 +95,13 @@ class TCPServer
9095 *
9196 * \param func Function handling the event information. The file descriptor created by the
9297 * connection event will be passed to the function.
98+ *
99+ * \note: The socket will already be closed when the disconnect callback is triggered, thus
100+ * trying to interact with the socket from the disconnect callback will fail.
93101 */
94102 void setDisconnectCallback (std::function<void (const socket_t )> func)
95103 {
104+ std::lock_guard<std::mutex> lk (callback_mutex_);
96105 disconnect_callback_ = func;
97106 }
98107
@@ -104,6 +113,7 @@ class TCPServer
104113 */
105114 void setMessageCallback (std::function<void (const socket_t , char *, int )> func)
106115 {
116+ std::lock_guard<std::mutex> lk (message_mutex_);
107117 message_callback_ = func;
108118 }
109119
@@ -116,9 +126,11 @@ class TCPServer
116126 void start ();
117127
118128 /* !
119- * \brief Shut down the event listener thread. After calling this, no events will be handled
120- * anymore, but the socket will remain open and bound to the port. Call start() in order to
121- * restart event handling.
129+ * \brief Shutdown the server and close all client connections.
130+ *
131+ * \note: This should not be called from within any of the registered callback functions, as
132+ * it will cause a deadlock. If you want to shutdown the server from a callback, you can e.g.
133+ * start a new thread that calls shutdown() from there.
122134 */
123135 void shutdown ();
124136
@@ -135,6 +147,21 @@ class TCPServer
135147 */
136148 bool write (const socket_t fd, const uint8_t * buf, const size_t buf_len, size_t & written);
137149
150+ /* !
151+ * \brief Writes to a filedescriptor without verifying that it is a client or even a valid
152+ * filedescriptor. It is the caller's responsibility to ensure that the filedescriptor is valid
153+ * and belongs to a client.
154+ *
155+ * \param[in] fd File descriptor belonging to the client the data should be sent to. The file
156+ * descriptor will be given from the connection callback.
157+ * \param[in] buf Buffer of bytes to write
158+ * \param[in] buf_len Number of bytes in the buffer
159+ * \param[out] written Number of bytes actually written
160+ *
161+ * \returns True on success, false otherwise
162+ */
163+ bool writeUnchecked (const socket_t fd, const uint8_t * buf, const size_t buf_len, size_t & written);
164+
138165 /* !
139166 * \brief Get the maximum number of clients allowed to connect to this server
140167 *
@@ -182,15 +209,15 @@ class TCPServer
182209 void handleDisconnect (const socket_t fd);
183210
184211 // ! read data from socket
185- void readData (const socket_t fd);
212+ bool readData (const socket_t fd);
186213
187214 // ! Event handler. Blocks until activity on any client or connection attempt
188215 void spin ();
189216
190217 // ! Runs spin() as long as keep_running_ is set to true.
191218 void worker ();
192219
193- std::atomic<bool > keep_running_;
220+ std::atomic<bool > keep_running_{ false } ;
194221 std::thread worker_thread_;
195222
196223 std::atomic<socket_t > listen_fd_;
@@ -202,6 +229,10 @@ class TCPServer
202229
203230 uint32_t max_clients_allowed_;
204231 std::vector<socket_t > client_fds_;
232+ std::mutex clients_mutex_;
233+ std::mutex message_mutex_;
234+ std::mutex listen_fd_mutex_;
235+ std::mutex callback_mutex_;
205236
206237 static const int INPUT_BUFFER_SIZE = 4096 ;
207238 char input_buffer_[INPUT_BUFFER_SIZE ];
0 commit comments