NetBurner 3.5.6
PDF Version
Web Sockets

Web Socket functions and defintions. More...

Topics

 Web Socket Definitions
 WebSocket Protocol Implementation for Real-Time Bidirectional Communication #include< websockets.h>

 

Classes

class  NB::WebSocket
 WebSocket connection management class. More...
 

Functions

int WSPing (int fd, uint32_t len, uint32_t *sentTick)
 Send a WebSocket ping frame to test connection liveness and measure round-trip time.
 
int WSGetPingReplyTick (int fd, uint32_t *replyTick)
 Retrieve the timestamp of the most recent pong reply received on a WebSocket connection.
 
int WSWaitForPingReply (int fd, uint32_t timeout)
 Wait for a pong reply to a previously sent ping with a specified timeout.
 
int WSUpgrade (HTTP_Request *req, int sock)
 Upgrade an HTTP connection to a WebSocket connection.
 

Detailed Description

Web Socket functions and defintions.

Function Documentation

◆ WSGetPingReplyTick()

int WSGetPingReplyTick ( int fd,
uint32_t * replyTick )

#include <websockets.h>

Retrieve the timestamp of the most recent pong reply received on a WebSocket connection.

Gets the system tick count when the last pong frame was received in response to a ping. This function is used in conjunction with WSPing() to measure round-trip time and verify connection responsiveness. The reply tick is automatically recorded by the WebSocket implementation when a pong frame arrives.

This is useful for:

  • Calculating network latency after sending a ping
  • Verifying that a connection is still responsive
  • Implementing timeout detection for unresponsive connections
  • Gathering connection quality metrics
Parameters
fdThe file descriptor of the WebSocket connection
replyTickPointer to store the tick count when the last pong was received. If no pong has been received yet, the value is undefined.
Returns
Returns a status code indicating success or failure:
  • 0 or positive: Success, replyTick contains the timestamp of the last pong
  • Negative value: Error occurred (invalid fd, no pong received, connection closed, etc.)
Note
This function returns the timestamp of the most recently received pong frame
Call this after sending a ping with WSPing() to measure round-trip time
The returned tick value is in system ticks (use TICKS_PER_SECOND to convert)
If no pong has been received since the connection opened, behavior is undefined
Compare with the sentTick from WSPing() to calculate latency
The pong reply is automatically processed by the WebSocket stack
Multiple pings can be in flight, but this function only returns the most recent pong timestamp.

Expand for Example Usage

Examples

Example 1: Basic Round-Trip Time Measurement
int wsFd = ...; // WebSocket connection
uint32_t pingSent, pongReceived;
// Send ping
if (WSPing(wsFd, 0, &pingSent) >= 0) {
printf("Ping sent at tick %lu\r\n", pingSent);
// Wait a moment for the pong
OSTimeDly(TICKS_PER_SECOND / 10); // 100ms
// Get pong reply time
if (WSGetPingReplyTick(wsFd, &pongReceived) >= 0) {
uint32_t rtt = pongReceived - pingSent;
uint32_t rttMs = rtt / (TICKS_PER_SECOND / 1000);
printf("Round-trip time: %lu ms\r\n", rttMs);
} else {
printf("No pong received yet\r\n");
}
}
#define TICKS_PER_SECOND
System clock ticks per second.
Definition constants.h:49
int WSPing(int fd, uint32_t len, uint32_t *sentTick)
Send a WebSocket ping frame to test connection liveness and measure round-trip time.
int WSGetPingReplyTick(int fd, uint32_t *replyTick)
Retrieve the timestamp of the most recent pong reply received on a WebSocket connection.
Example 2: Polling for Pong Response
#define PONG_TIMEOUT_MS 3000
bool WaitForPong(int wsFd, uint32_t pingSentTick, uint32_t *latencyMs) {
uint32_t startWait = TimeTick;
uint32_t pongTick;
while (1) {
// Check if pong received
if (WSGetPingReplyTick(wsFd, &pongTick) >= 0) {
// Verify this pong is for our ping
if (pongTick > pingSentTick) {
uint32_t rtt = pongTick - pingSentTick;
*latencyMs = rtt / (TICKS_PER_SECOND / 1000);
return true;
}
}
// Check timeout
uint32_t elapsed = TimeTick - startWait;
if (elapsed / (TICKS_PER_SECOND / 1000) > PONG_TIMEOUT_MS) {
printf("Pong timeout\r\n");
return false;
}
OSTimeDly(TICKS_PER_SECOND / 100); // 10ms poll interval
}
}
// Usage
uint32_t pingSent, latency;
WSPing(wsFd, 0, &pingSent);
if (WaitForPong(wsFd, pingSent, &latency)) {
printf("Connection latency: %lu ms\r\n", latency);
}
Example 3: Connection Quality Monitoring
struct ConnectionStats {
uint32_t minLatency;
uint32_t maxLatency;
uint32_t avgLatency;
uint32_t sampleCount;
};
void UpdateConnectionStats(int wsFd, uint32_t pingSent, ConnectionStats *stats) {
uint32_t pongReceived;
if (WSGetPingReplyTick(wsFd, &pongReceived) >= 0) {
if (pongReceived > pingSent) {
uint32_t latency = (pongReceived - pingSent) / (TICKS_PER_SECOND / 1000);
// Update statistics
if (stats->sampleCount == 0 || latency < stats->minLatency) {
stats->minLatency = latency;
}
if (latency > stats->maxLatency) {
stats->maxLatency = latency;
}
// Calculate running average
stats->avgLatency = ((stats->avgLatency * stats->sampleCount) + latency)
/ (stats->sampleCount + 1);
stats->sampleCount++;
printf("Latency: %lu ms (min: %lu, max: %lu, avg: %lu)\r\n",
latency, stats->minLatency, stats->maxLatency, stats->avgLatency);
}
}
}
Example 4: Timeout Detection
#define PING_INTERVAL_SEC 30
#define PONG_TIMEOUT_SEC 5
void ConnectionHealthCheck(int wsFd) {
static uint32_t lastPingSent = 0;
static bool waitingForPong = false;
uint32_t pongReceived;
if (!waitingForPong) {
// Time to send a new ping
if (WSPing(wsFd, 0, &lastPingSent) >= 0) {
waitingForPong = true;
printf("Ping sent\r\n");
}
} else {
// Check for pong response
if (WSGetPingReplyTick(wsFd, &pongReceived) >= 0) {
if (pongReceived > lastPingSent) {
uint32_t rtt = pongReceived - lastPingSent;
printf("Pong received, RTT: %lu ms\r\n",
rtt / (TICKS_PER_SECOND / 1000));
waitingForPong = false;
}
}
// Check for timeout
uint32_t elapsed = TimeTick - lastPingSent;
if (elapsed / TICKS_PER_SECOND > PONG_TIMEOUT_SEC) {
printf("ERROR: Pong timeout - connection may be dead\r\n");
close(wsFd);
return;
}
}
}
int close(int fd)
Close the specified file descriptor and free the associated resources.
Example 5: Detailed Latency Analysis
void AnalyzeConnectionLatency(int wsFd) {
const int NUM_PINGS = 10;
uint32_t latencies[NUM_PINGS];
int successCount = 0;
printf("Starting latency analysis (%d pings)...\r\n", NUM_PINGS);
for (int i = 0; i < NUM_PINGS; i++) {
uint32_t pingSent, pongReceived;
// Send ping
if (WSPing(wsFd, 0, &pingSent) < 0) {
printf("Ping %d failed\r\n", i + 1);
continue;
}
// Wait for pong (with timeout)
uint32_t waitStart = TimeTick;
bool gotPong = false;
while ((TimeTick - waitStart) < TICKS_PER_SECOND) {
if (WSGetPingReplyTick(wsFd, &pongReceived) >= 0) {
if (pongReceived > pingSent) {
latencies[successCount++] =
(pongReceived - pingSent) / (TICKS_PER_SECOND / 1000);
gotPong = true;
break;
}
}
OSTimeDly(TICKS_PER_SECOND / 100); // 10ms
}
if (!gotPong) {
printf("Ping %d timeout\r\n", i + 1);
}
// Small delay between pings
OSTimeDly(TICKS_PER_SECOND / 2);
}
// Calculate statistics
if (successCount > 0) {
uint32_t sum = 0, min = latencies[0], max = latencies[0];
for (int i = 0; i < successCount; i++) {
sum += latencies[i];
if (latencies[i] < min) min = latencies[i];
if (latencies[i] > max) max = latencies[i];
}
printf("\nLatency Analysis Results:\r\n");
printf(" Successful pings: %d/%d\r\n", successCount, NUM_PINGS);
printf(" Min: %lu ms\r\n", min);
printf(" Max: %lu ms\r\n", max);
printf(" Avg: %lu ms\r\n", sum / successCount);
}
}


See also
WSPing() - Send a ping frame and record sent timestamp
WSPong() - Manually send a pong response
WSRead() - Read WebSocket frames
TimeTick - Current system tick count
TICKS_PER_SECOND - Conversion constant for tick-to-time calculations

◆ WSPing()

int WSPing ( int fd,
uint32_t len,
uint32_t * sentTick )

#include <websockets.h>

Send a WebSocket ping frame to test connection liveness and measure round-trip time.

WSPing

Description

Sends a WebSocket ping control frame with optional payload data. The server or client should respond with a pong frame containing the same payload. This function records the tick count when the ping is sent, allowing calculation of round-trip time when the corresponding pong is received.

Ping frames are used to:

  • Verify that the connection is still alive
  • Measure network latency
  • Keep the connection active (prevent timeouts)
  • Detect unresponsive peers

Parameters

Parameters
fdThe file descriptor of the WebSocket connection
lenLength of the ping payload data in bytes (typically 0-125 bytes)
sentTickPointer to store the system tick count when the ping was sent. Can be NULL if timestamp recording is not needed. Use this value with the pong response timestamp to calculate round-trip time.

Return Value

Returns the number of bytes sent on success, or a negative value on error:

  • Positive value: Number of bytes successfully sent (ping frame)
  • Negative value: Error occurred (connection closed, invalid parameters, etc.)

Usage Notes

  • Ping payloads should be small (WebSocket spec recommends 125 bytes or less)
  • The peer must respond with a pong frame containing the same payload
  • Store the sentTick value to calculate latency when the pong arrives
  • Convert ticks to milliseconds using: (receivedTick - sentTick) / (TICKS_PER_SECOND / 1000)
  • Frequent pings can be used as a keep-alive mechanism
  • If no pong is received within a reasonable timeout, the connection may be dead

Expand for Example Usage

Examples

Example 1: Basic Ping without Payload
int wsFd = ...; // WebSocket connection
uint32_t pingTime;
// Send ping with no payload
int result = WSPing(wsFd, 0, &pingTime);
if (result >= 0) {
printf("Ping sent at tick %lu\r\n", pingTime);
} else {
printf("Failed to send ping\r\n");
}
Example 2: Measuring Round-Trip Time
uint32_t pingSentTick;
uint32_t pongReceivedTick;
// Send ping
if (WSPing(wsFd, 0, &pingSentTick) >= 0) {
// Wait for pong response (in your pong handler)
// ... receive pong ...
pongReceivedTick = TimeTick;
// Calculate latency
uint32_t latencyTicks = pongReceivedTick - pingSentTick;
uint32_t latencyMs = latencyTicks / (TICKS_PER_SECOND / 1000);
printf("Round-trip time: %lu ms\r\n", latencyMs);
}
Example 3: Periodic Keep-Alive Pings
void KeepAliveTask(void *pd) {
int wsFd = (int)(intptr_t)pd;
uint32_t lastPingTime;
while (1) {
// Send ping every 30 seconds
OSTimeDly(TICKS_PER_SECOND * 30);
int result = WSPing(wsFd, 0, &lastPingTime);
if (result < 0) {
printf("Keep-alive ping failed, connection may be closed\r\n");
break;
}
}
}
Example 4: Ping with Payload for Identification
// Send ping with small payload to identify the ping
uint32_t pingId = 12345;
uint32_t sentTime;
// In practice, you'd write the payload first using WSWrite or similar
// This example shows the WSPing call
int result = WSPing(wsFd, sizeof(pingId), &sentTime);
if (result >= 0) {
printf("Sent ping #%lu at tick %lu\r\n", pingId, sentTime);
}
Example 5: Connection Health Monitoring
#define PING_TIMEOUT_MS 5000
#define MAX_MISSED_PONGS 3
struct WSConnection {
int fd;
uint32_t lastPingSent;
uint32_t lastPongReceived;
int missedPongs;
};
void MonitorConnection(WSConnection *conn) {
// Send ping
if (WSPing(conn->fd, 0, &conn->lastPingSent) < 0) {
printf("Connection lost\r\n");
return;
}
// Check if previous pong was received
uint32_t elapsed = TimeTick - conn->lastPingSent;
uint32_t elapsedMs = elapsed / (TICKS_PER_SECOND / 1000);
if (elapsedMs > PING_TIMEOUT_MS) {
conn->missedPongs++;
if (conn->missedPongs >= MAX_MISSED_PONGS) {
printf("Connection appears dead, closing\r\n");
close(conn->fd);
}
}
}


See Also

  • WSPong() - Send a pong response frame
  • WSRead() - Read WebSocket frames (including pong responses)
  • WSWrite() - Send WebSocket data frames
  • WSClose() - Close a WebSocket connection
Note
The WebSocket protocol requires that a pong frame echo back the exact payload received in the ping frame.

◆ WSUpgrade()

int WSUpgrade ( HTTP_Request * req,
int sock )

#include <websockets.h>

Upgrade an HTTP connection to a WebSocket connection.

Performs the WebSocket handshake by upgrading an existing HTTP request to the WebSocket protocol. This function validates the upgrade request, sends the appropriate handshake response, and transitions the socket into WebSocket mode. After a successful upgrade, the socket can be used with WebSocket functions like WSRead() and WSWrite().

This function handles:

  • Validation of WebSocket upgrade headers (Upgrade, Connection, Sec-WebSocket-Key)
  • Generation of the Sec-WebSocket-Accept response header
  • Protocol version negotiation
  • Switching the connection from HTTP to WebSocket mode
Parameters
reqPointer to the HTTP_Request structure containing the upgrade request. The request must contain valid WebSocket upgrade headers including:
  • Upgrade: websocket
  • Connection: Upgrade
  • Sec-WebSocket-Key: <client key>
  • Sec-WebSocket-Version: 13
sockThe socket file descriptor of the HTTP connection to upgrade. This socket will be transitioned to WebSocket mode on success.
Returns
Returns a status code indicating the result:
  • 0 or positive: Success, connection upgraded to WebSocket
  • Negative value: Error occurred (invalid request, missing headers, handshake failed)
Note
This function must be called from within an HTTP request handler
After successful upgrade, do not send HTTP responses on this socket
The socket remains open and must be managed using WebSocket functions
Subprotocol negotiation (Sec-WebSocket-Protocol) may be handled automatically
Extensions (Sec-WebSocket-Extensions) may be negotiated based on implementation
After upgrade, use WSRead() and WSWrite() for all communication on this socket
The HTTP request handler should return without sending additional HTTP data
Always check the return value to ensure the upgrade was successful

Expand for Example Usage

Examples

Example 1: Basic WebSocket Upgrade Handler
// HTTP handler for WebSocket endpoint
int HandleWebSocketUpgrade(HTTP_Request *req, int sock) {
// Attempt to upgrade to WebSocket
if (WSUpgrade(req, sock) >= 0) {
printf("WebSocket connection established on socket %d\r\n", sock);
// Connection is now in WebSocket mode
// Handle WebSocket communication here or in a separate task
return 0; // Don't send HTTP response
} else {
printf("WebSocket upgrade failed\r\n");
// Send error response
writestring(sock, "HTTP/1.1 400 Bad Request\r\n");
writestring(sock, "Content-Type: text/plain\r\n\r\n");
writestring(sock, "WebSocket upgrade failed");
return -1;
}
}
// Register the handler
void UserMain(void *pd) {
init();
// Register WebSocket endpoint
SetNewWSHandler("/ws", HandleWebSocketUpgrade);
while (1) {
OSTimeDly(TICKS_PER_SECOND);
}
}
int writestring(int fd, const char *str)
Write a null terminated ascii string to the stream associated with a file descriptor (fd)....
int WSUpgrade(HTTP_Request *req, int sock)
Upgrade an HTTP connection to a WebSocket connection.
void StartHttp(uint16_t port, bool RunConfigMirror)
Start the HTTP web server. Further documentation in the Initialization section Initialization - Syste...
void init()
System initialization. Ideally called at the beginning of all applications, since the easiest Recover...
HTTP Request Structure.
Definition http.h:87
Example 2: WebSocket Upgrade with Echo Server
// Simple echo server after upgrade
void WebSocketEchoTask(void *pd) {
int sock = (int)(intptr_t)pd;
char buffer[256];
printf("WebSocket echo task started on socket %d\r\n", sock);
while (1) {
// Read WebSocket frame
int len = WSRead(sock, buffer, sizeof(buffer) - 1, TICKS_PER_SECOND * 30);
if (len > 0) {
buffer[len] = '\0';
printf("Received: %s\r\n", buffer);
// Echo back
if (WSWrite(sock, buffer, len) < 0) {
printf("Failed to echo message\r\n");
break;
}
} else if (len < 0) {
printf("WebSocket connection closed or error\r\n");
break;
}
}
close(sock);
printf("WebSocket echo task ended\r\n");
}
int HandleWebSocketUpgrade(HTTP_Request *req, int sock) {
if (WSUpgrade(req, sock) >= 0) {
// Spawn task to handle WebSocket communication
OSSimpleTaskCreatewName(WebSocketEchoTask,
MAIN_PRIO - 1,
(void *)(intptr_t)sock,
"WSEcho");
return 0;
}
return -1;
}
#define MAIN_PRIO
Recommend UserMain priority.
Definition constants.h:130
Example 3: Multiple WebSocket Endpoints
// Chat endpoint handler
int HandleChatWebSocket(HTTP_Request *req, int sock) {
if (WSUpgrade(req, sock) >= 0) {
printf("Chat WebSocket connected\r\n");
// Start chat handler task
OSSimpleTaskCreatewName(ChatTask, MAIN_PRIO - 1,
(void *)(intptr_t)sock, "WSChat");
return 0;
}
return -1;
}
// Data stream endpoint handler
int HandleDataWebSocket(HTTP_Request *req, int sock) {
if (WSUpgrade(req, sock) >= 0) {
printf("Data WebSocket connected\r\n");
// Start data streaming task
OSSimpleTaskCreatewName(DataStreamTask, MAIN_PRIO - 1,
(void *)(intptr_t)sock, "WSData");
return 0;
}
return -1;
}
void UserMain(void *pd) {
init();
// Register multiple WebSocket endpoints
SetNewWSHandler("/chat", HandleChatWebSocket);
SetNewWSHandler("/data", HandleDataWebSocket);
printf("WebSocket server running with multiple endpoints\r\n");
while (1) {
OSTimeDly(TICKS_PER_SECOND);
}
}
Example 4: WebSocket Upgrade with Authentication
// Check authentication token from query string or headers
bool ValidateWebSocketAuth(HTTP_Request *req) {
// Example: Check for auth token in query string
const char *token = GetRequestParam(req, "token");
if (token == NULL) {
return false;
}
// Validate token (simplified example)
return (strcmp(token, "secret123") == 0);
}
int HandleSecureWebSocket(HTTP_Request *req, int sock) {
// Authenticate before upgrading
if (!ValidateWebSocketAuth(req)) {
printf("WebSocket authentication failed\r\n");
writestring(sock, "HTTP/1.1 401 Unauthorized\r\n");
writestring(sock, "Content-Type: text/plain\r\n\r\n");
writestring(sock, "Authentication required");
return -1;
}
// Upgrade to WebSocket
if (WSUpgrade(req, sock) >= 0) {
printf("Authenticated WebSocket connection established\r\n");
OSSimpleTaskCreatewName(SecureWSTask, MAIN_PRIO - 1,
(void *)(intptr_t)sock, "WSSecure");
return 0;
}
return -1;
}
Example 5: WebSocket Upgrade with Connection Tracking
#define MAX_WS_CONNECTIONS 10
struct WSConnectionInfo {
int sock;
bool active;
uint32_t connectedTime;
char clientIP[16];
};
WSConnectionInfo wsConnections[MAX_WS_CONNECTIONS];
OS_CRIT wsCrit;
// Add connection to tracking array
bool AddWSConnection(int sock, const char *clientIP) {
OSCritEnter(&wsCrit, TICKS_PER_SECOND);
for (int i = 0; i < MAX_WS_CONNECTIONS; i++) {
if (!wsConnections[i].active) {
wsConnections[i].sock = sock;
wsConnections[i].active = true;
wsConnections[i].connectedTime = Secs;
strncpy(wsConnections[i].clientIP, clientIP,
sizeof(wsConnections[i].clientIP) - 1);
OSCritLeave(&wsCrit);
return true;
}
}
OSCritLeave(&wsCrit);
return false; // No slots available
}
int HandleTrackedWebSocket(HTTP_Request *req, int sock) {
// Get client IP
IPADDR clientAddr = req->client_addr;
char ipStr[16];
sprintf(ipStr, "%d.%d.%d.%d",
(int)clientAddr.GetByte(0), (int)clientAddr.GetByte(1),
(int)clientAddr.GetByte(2), (int)clientAddr.GetByte(3));
// Check connection limit
if (!AddWSConnection(sock, ipStr)) {
printf("Maximum WebSocket connections reached\r\n");
writestring(sock, "HTTP/1.1 503 Service Unavailable\r\n");
writestring(sock, "Content-Type: text/plain\r\n\r\n");
writestring(sock, "Too many connections");
return -1;
}
// Upgrade to WebSocket
if (WSUpgrade(req, sock) >= 0) {
printf("WebSocket connected from %s (socket %d)\r\n", ipStr, sock);
OSSimpleTaskCreatewName(TrackedWSTask, MAIN_PRIO - 1,
(void *)(intptr_t)sock, "WSTracked");
return 0;
} else {
// Remove from tracking on upgrade failure
OSCritEnter(&wsCrit, TICKS_PER_SECOND);
for (int i = 0; i < MAX_WS_CONNECTIONS; i++) {
if (wsConnections[i].sock == sock) {
wsConnections[i].active = false;
break;
}
}
OSCritLeave(&wsCrit);
}
return -1;
}
// Display active connections
void ShowWSConnections() {
OSCritEnter(&wsCrit, TICKS_PER_SECOND);
printf("\nActive WebSocket Connections:\r\n");
for (int i = 0; i < MAX_WS_CONNECTIONS; i++) {
if (wsConnections[i].active) {
uint32_t uptime = Secs - wsConnections[i].connectedTime;
printf(" [%d] %s (socket %d) - uptime: %lu sec\r\n",
i, wsConnections[i].clientIP,
wsConnections[i].sock, uptime);
}
}
OSCritLeave(&wsCrit);
}
Used to hold and manipulate IPv4 and IPv6 addresses in dual stack mode.
Definition ipv6_addr.h:41
Example 6: WebSocket Upgrade with Subprotocol Negotiation
// Check if client requested a specific subprotocol
const char* NegotiateSubprotocol(HTTP_Request *req) {
// Example: Client sends "Sec-WebSocket-Protocol: chat, superchat"
const char *requested = GetRequestHeader(req, "Sec-WebSocket-Protocol");
if (requested == NULL) {
return NULL; // No subprotocol requested
}
// Check if we support the requested protocol
if (strstr(requested, "chat") != NULL) {
return "chat";
}
return NULL; // Unsupported subprotocol
}
int HandleSubprotocolWebSocket(HTTP_Request *req, int sock) {
const char *subprotocol = NegotiateSubprotocol(req);
if (subprotocol) {
printf("Negotiated subprotocol: %s\r\n", subprotocol);
// Note: WSUpgrade may handle this automatically
// or you may need to add the header before calling WSUpgrade
}
if (WSUpgrade(req, sock) >= 0) {
printf("WebSocket upgraded with subprotocol: %s\r\n",
subprotocol ? subprotocol : "none");
return 0;
}
return -1;
}


See also
SetNewWSHandler() - Register a handler for WebSocket upgrade requests
WSRead() - Read data from a WebSocket connection
WSWrite() - Write data to a WebSocket connection
WSClose() - Close a WebSocket connection gracefully
WSPing() - Send a ping frame to test connection
HTTP_Request - Structure containing HTTP request information

◆ WSWaitForPingReply()

int WSWaitForPingReply ( int fd,
uint32_t timeout )

#include <websockets.h>

Wait for a pong reply to a previously sent ping with a specified timeout.

Blocks execution until a pong frame is received in response to a ping, or until the specified timeout expires. This is a convenience function that combines waiting and timeout detection, simplifying the common pattern of sending a ping and waiting for the corresponding pong response.

This function is useful for:

  • Synchronous ping/pong operations with automatic timeout handling
  • Verifying connection responsiveness in a blocking manner
  • Simplifying connection health checks without manual polling
  • Testing connection latency with built-in timeout protection
Parameters
fdThe file descriptor of the WebSocket connection
timeoutMaximum time to wait for a pong reply, in system ticks. Use TICKS_PER_SECOND to specify timeout in seconds (e.g., TICKS_PER_SECOND * 5 for a 5-second timeout). A timeout of 0 returns immediately.
Returns
Returns a status code indicating the result:
  • 0 or positive: Success, pong received within timeout period
  • Negative value: Error occurred (timeout expired, connection closed, invalid parameters)
Note
This function blocks the calling task until a pong is received or timeout expires
A ping should be sent using WSPing() before calling this function
The timeout parameter is in system ticks, not milliseconds
Use TICKS_PER_SECOND to convert seconds to ticks: timeout = TICKS_PER_SECOND * seconds
This function does not return the latency; use WSGetPingReplyTick() if you need timing info
If multiple pongs arrive, this returns on the first pong received during the wait period
For non-blocking operations, use WSGetPingReplyTick() with manual polling instead

Expand for Example Usage

Examples

Example 1: Basic Ping/Pong with Timeout
int wsFd = ...; // WebSocket connection
uint32_t pingSent;
// Send ping
if (WSPing(wsFd, 0, &pingSent) >= 0) {
printf("Ping sent, waiting for reply...\r\n");
// Wait up to 3 seconds for pong
int result = WSWaitForPingReply(wsFd, TICKS_PER_SECOND * 3);
if (result >= 0) {
printf("Pong received!\r\n");
} else {
printf("Timeout or error waiting for pong\r\n");
}
}
int WSWaitForPingReply(int fd, uint32_t timeout)
Wait for a pong reply to a previously sent ping with a specified timeout.
Example 2: Connection Health Check with Blocking Wait
bool CheckConnectionHealth(int wsFd) {
uint32_t pingSent;
// Send ping and wait for reply
if (WSPing(wsFd, 0, &pingSent) < 0) {
printf("Failed to send ping\r\n");
return false;
}
// Wait up to 5 seconds for pong
if (WSWaitForPingReply(wsFd, TICKS_PER_SECOND * 5) >= 0) {
printf("Connection is healthy\r\n");
return true;
} else {
printf("Connection appears unhealthy or slow\r\n");
return false;
}
}
Example 3: Periodic Keep-Alive with Timeout Detection
void KeepAliveTask(void *pd) {
int wsFd = (int)(intptr_t)pd;
uint32_t pingSent;
int consecutiveFailures = 0;
const int MAX_FAILURES = 3;
while (1) {
// Wait 30 seconds between pings
OSTimeDly(TICKS_PER_SECOND * 30);
// Send ping
if (WSPing(wsFd, 0, &pingSent) < 0) {
printf("Failed to send ping\r\n");
consecutiveFailures++;
} else {
// Wait for pong with 10 second timeout
if (WSWaitForPingReply(wsFd, TICKS_PER_SECOND * 10) >= 0) {
printf("Keep-alive successful\r\n");
consecutiveFailures = 0;
} else {
printf("Keep-alive timeout\r\n");
consecutiveFailures++;
}
}
// Check if connection is dead
if (consecutiveFailures >= MAX_FAILURES) {
printf("Connection lost after %d failures\r\n", MAX_FAILURES);
close(wsFd);
break;
}
}
}
Example 4: Connection Latency Measurement
bool MeasureLatency(int wsFd, uint32_t *latencyMs) {
uint32_t pingSent, pongReceived;
// Send ping
if (WSPing(wsFd, 0, &pingSent) < 0) {
return false;
}
// Wait for pong with 2 second timeout
if (WSWaitForPingReply(wsFd, TICKS_PER_SECOND * 2) < 0) {
printf("Ping timeout\r\n");
return false;
}
// Get the pong timestamp to calculate latency
if (WSGetPingReplyTick(wsFd, &pongReceived) >= 0) {
uint32_t rtt = pongReceived - pingSent;
*latencyMs = rtt / (TICKS_PER_SECOND / 1000);
return true;
}
return false;
}
// Usage
uint32_t latency;
if (MeasureLatency(wsFd, &latency)) {
printf("Connection latency: %lu ms\r\n", latency);
}
Example 5: Progressive Timeout Strategy
typedef enum {
CONN_EXCELLENT, // < 100ms
CONN_GOOD, // < 500ms
CONN_FAIR, // < 2000ms
CONN_POOR // >= 2000ms or timeout
} ConnectionQuality;
ConnectionQuality AssessConnectionQuality(int wsFd) {
uint32_t pingSent, pongReceived;
// Send ping
if (WSPing(wsFd, 0, &pingSent) < 0) {
return CONN_POOR;
}
// Try quick response first (100ms)
if (WSWaitForPingReply(wsFd, TICKS_PER_SECOND / 10) >= 0) {
return CONN_EXCELLENT;
}
// Try good response (additional 400ms)
if (WSWaitForPingReply(wsFd, (TICKS_PER_SECOND * 4) / 10) >= 0) {
return CONN_GOOD;
}
// Try fair response (additional 1500ms)
if (WSWaitForPingReply(wsFd, (TICKS_PER_SECOND * 15) / 10) >= 0) {
return CONN_FAIR;
}
return CONN_POOR;
}
// Usage
ConnectionQuality quality = AssessConnectionQuality(wsFd);
const char* qualityStr[] = {"Excellent", "Good", "Fair", "Poor"};
printf("Connection quality: %s\r\n", qualityStr[quality]);
Example 6: Batch Connection Testing
struct WSConnection {
int fd;
char name[32];
bool isAlive;
};
void TestMultipleConnections(WSConnection *connections, int count) {
printf("Testing %d WebSocket connections...\r\n", count);
for (int i = 0; i < count; i++) {
uint32_t pingSent;
printf("Testing %s... ", connections[i].name);
// Send ping
if (WSPing(connections[i].fd, 0, &pingSent) < 0) {
printf("FAILED (ping)\r\n");
connections[i].isAlive = false;
continue;
}
// Wait for pong with 3 second timeout
if (WSWaitForPingReply(connections[i].fd, TICKS_PER_SECOND * 3) >= 0) {
printf("OK\r\n");
connections[i].isAlive = true;
} else {
printf("FAILED (timeout)\r\n");
connections[i].isAlive = false;
}
}
// Summary
int aliveCount = 0;
for (int i = 0; i < count; i++) {
if (connections[i].isAlive) aliveCount++;
}
printf("\nResults: %d/%d connections alive\r\n", aliveCount, count);
}


See also
WSPing() - Send a ping frame and record sent timestamp
WSGetPingReplyTick() - Get timestamp of last pong (for latency calculation)
WSPong() - Manually send a pong response
WSRead() - Read WebSocket frames
TICKS_PER_SECOND - Conversion constant for timeout specification