133 lines
3.9 KiB
C++
133 lines
3.9 KiB
C++
/**
|
|
* @file WSServer.h
|
|
* @brief Multi-client WebSocket server using MARTe2 BasicTCPSocket.
|
|
*
|
|
* Accepts WebSocket connections over HTTP/1.1 (RFC 6455 upgrade).
|
|
* - One accept thread (started by Start()).
|
|
* - One read thread per connected client (started when client upgrades).
|
|
* - BroadcastText / BroadcastBinary called from any thread (push loop or
|
|
* command handlers); per-client write is protected by a mutex.
|
|
*
|
|
* Maximum concurrent clients: WS_MAX_CLIENTS (16).
|
|
*/
|
|
|
|
#ifndef STREAMHUB_WSSERVER_H_
|
|
#define STREAMHUB_WSSERVER_H_
|
|
|
|
#include "BasicTCPSocket.h"
|
|
#include "FastPollingMutexSem.h"
|
|
|
|
namespace StreamHub {
|
|
|
|
using MARTe::uint8;
|
|
using MARTe::uint16;
|
|
using MARTe::uint32;
|
|
using MARTe::BasicTCPSocket;
|
|
using MARTe::FastPollingMutexSem;
|
|
|
|
/** Maximum simultaneously connected WebSocket clients. */
|
|
static const uint32 WS_MAX_CLIENTS = 16u;
|
|
|
|
/** Maximum WebSocket frame payload we will receive (commands are JSON, small). */
|
|
static const uint32 WS_MAX_RECV_PAYLOAD = 65536u;
|
|
|
|
/** Maximum WebSocket frame payload we will send (data frames can be large). */
|
|
static const uint32 WS_MAX_SEND_PAYLOAD = 4u * 1024u * 1024u; /* 4 MiB */
|
|
|
|
/**
|
|
* @brief Callback interface — implemented by StreamHub.
|
|
*/
|
|
class WSCommandCallback {
|
|
public:
|
|
virtual ~WSCommandCallback() {}
|
|
/** Called from client read thread with a fully-received text frame.
|
|
* @param slotIdx Client slot index — usable with WSServer::SendText for
|
|
* unicast replies. */
|
|
virtual void OnWSCommand(const char *json, uint32 len, uint32 slotIdx) = 0;
|
|
/** Called from accept thread when a new client upgrades. */
|
|
virtual void OnWSClientConnected() = 0;
|
|
/** Called from client read thread when the connection closes. */
|
|
virtual void OnWSClientDisconnected() = 0;
|
|
};
|
|
|
|
/**
|
|
* @brief One connected WebSocket client slot.
|
|
*/
|
|
struct WSClientSlot {
|
|
BasicTCPSocket *sock; ///< Owned pointer; NULL when slot is free
|
|
bool active;
|
|
MARTe::ThreadIdentifier readTid;
|
|
FastPollingMutexSem writeMutex; ///< Serialises writes from push + pong threads
|
|
};
|
|
|
|
/**
|
|
* @brief Minimal HTTP/1.1 + WebSocket server.
|
|
*/
|
|
class WSServer {
|
|
public:
|
|
|
|
WSServer();
|
|
~WSServer();
|
|
|
|
/**
|
|
* @brief Open listen socket and start the accept thread.
|
|
* @param port TCP port to listen on.
|
|
* @param cb Command callback (StreamHub); must outlive WSServer.
|
|
* @return true on success.
|
|
*/
|
|
bool Start(uint16 port, WSCommandCallback *cb);
|
|
|
|
/**
|
|
* @brief Stop accept thread; close all client connections; close listener.
|
|
*/
|
|
bool Stop();
|
|
|
|
/**
|
|
* @brief Broadcast a text (JSON) frame to all connected clients.
|
|
* Safe to call from any thread.
|
|
*/
|
|
void BroadcastText(const char *json, uint32 len);
|
|
|
|
/**
|
|
* @brief Broadcast a binary frame to all connected clients.
|
|
* Safe to call from any thread.
|
|
*/
|
|
void BroadcastBinary(const uint8 *buf, uint32 len);
|
|
|
|
/**
|
|
* @brief Send a text frame to a single client slot.
|
|
* Used internally to send pong / direct responses.
|
|
*/
|
|
void SendText(uint32 slotIdx, const char *json, uint32 len);
|
|
|
|
/** @return Number of currently active client connections. */
|
|
uint32 ClientCount() const;
|
|
|
|
/* ---- Internal thread entry points (public for Threads trampoline) ---- */
|
|
void AcceptLoop();
|
|
void ClientReadLoop(uint32 slotIdx);
|
|
|
|
private:
|
|
|
|
bool UpgradeHTTP(BasicTCPSocket *sock);
|
|
bool SendFrame(WSClientSlot &slot, uint8 opcode,
|
|
const uint8 *payload, uint32 payloadLen);
|
|
|
|
uint32 AllocSlot(BasicTCPSocket *sock);
|
|
void FreeSlot(uint32 idx);
|
|
|
|
BasicTCPSocket tcpListener;
|
|
WSClientSlot clients[WS_MAX_CLIENTS];
|
|
uint32 numClients;
|
|
mutable FastPollingMutexSem clientsMutex; ///< Protects numClients and clients[] array
|
|
|
|
WSCommandCallback *callback;
|
|
volatile bool running;
|
|
|
|
MARTe::ThreadIdentifier acceptTid;
|
|
};
|
|
|
|
} /* namespace StreamHub */
|
|
|
|
#endif /* STREAMHUB_WSSERVER_H_ */
|