Skip to content

Refactor Signaling sources to make Include_i.h independent of libwebsockets #2141

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions src/source/Include_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,6 @@ extern "C" {
#define INET6 1
#include <usrsctp.h>

#include <libwebsockets.h>

#if !defined __WINDOWS_BUILD__
#include <signal.h>
#include <sys/types.h>
Expand All @@ -65,6 +63,7 @@ extern "C" {
#include <arpa/inet.h>
#include <fcntl.h>
#include <netinet/tcp.h>
#include <poll.h>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because this was earlier satisfied from libwebsockets.h

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To make this platform independent, I think we should pass it as a compiler flag and only include if true.

cmake:

include(CheckIncludeFile)
check_include_file("poll.h" HAVE_POLL_H)

if(HAVE_POLL_H)
    add_definitions(-DHAVE_POLL_H=1)
endif()

C:

#ifdef HAVE_POLL_H
#include <poll.h>
#endif

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe similar for ifaddrs.h

#endif

// Max uFrag and uPwd length as documented in https://tools.ietf.org/html/rfc5245#section-15.4
Expand Down
51 changes: 28 additions & 23 deletions src/source/Signaling/LwsApiCalls.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
*/
#define LOG_CLASS "LwsApiCalls"
#include "../Include_i.h"

#include <libwebsockets.h>
#include "Signaling.h"
#include "LwsApiCalls.h"

#define WEBRTC_SCHEME_NAME "webrtc"

static BOOL gInterruptedFlagBySignalHandler;
Expand All @@ -12,7 +17,7 @@ VOID lwsSignalHandler(INT32 signal)
gInterruptedFlagBySignalHandler = TRUE;
}

INT32 lwsHttpCallbackRoutine(struct lws* wsi, enum lws_callback_reasons reason, PVOID user, PVOID pDataIn, size_t dataSize)
INT32 lwsHttpCallbackRoutine(PVOID wsi, INT32 reason, PVOID user, PVOID pDataIn, size_t dataSize)
{
UNUSED_PARAM(user);
STATUS retStatus = STATUS_SUCCESS;
Expand Down Expand Up @@ -53,12 +58,12 @@ INT32 lwsHttpCallbackRoutine(struct lws* wsi, enum lws_callback_reasons reason,
CHK(FALSE, retStatus);
}

customData = lws_get_opaque_user_data(wsi);
customData = lws_get_opaque_user_data((struct lws*) wsi);
pLwsCallInfo = (PLwsCallInfo) customData;

CHK_STATUS(configureLwsLogging(loggerGetLogLevel()));

CHK(pLwsCallInfo != NULL && pLwsCallInfo->pSignalingClient != NULL && pLwsCallInfo->pSignalingClient->pLwsContext != NULL &&
CHK(pLwsCallInfo != NULL && pLwsCallInfo->pSignalingClient != NULL && pLwsCallInfo->pSignalingClient->pWebsocketContext != NULL &&
pLwsCallInfo->callInfo.pRequestInfo != NULL && pLwsCallInfo->protocolIndex == PROTOCOL_INDEX_HTTPS,
retStatus);

Expand Down Expand Up @@ -98,13 +103,13 @@ INT32 lwsHttpCallbackRoutine(struct lws* wsi, enum lws_callback_reasons reason,
break;

case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:
status = lws_http_client_http_response(wsi);
status = lws_http_client_http_response((struct lws*) wsi);
getStateMachineCurrentState(pSignalingClient->pStateMachine, &pStateMachineState);

DLOGD("Connected with server response: %d", status);
pLwsCallInfo->callInfo.callResult = getServiceCallResultFromHttpStatus((UINT32) status);

len = (SIZE_T) lws_hdr_copy(wsi, &dateHdrBuffer[0], MAX_DATE_HEADER_BUFFER_LENGTH, WSI_TOKEN_HTTP_DATE);
len = (SIZE_T) lws_hdr_copy((struct lws*) wsi, &dateHdrBuffer[0], MAX_DATE_HEADER_BUFFER_LENGTH, WSI_TOKEN_HTTP_DATE);

time(&td);

Expand Down Expand Up @@ -141,7 +146,7 @@ INT32 lwsHttpCallbackRoutine(struct lws* wsi, enum lws_callback_reasons reason,
}

// Store the Request ID header
if ((size = lws_hdr_custom_copy(wsi, pBuffer, LWS_SCRATCH_BUFFER_SIZE, SIGNALING_REQUEST_ID_HEADER_NAME,
if ((size = lws_hdr_custom_copy((struct lws*) wsi, pBuffer, LWS_SCRATCH_BUFFER_SIZE, SIGNALING_REQUEST_ID_HEADER_NAME,
(SIZEOF(SIGNALING_REQUEST_ID_HEADER_NAME) - 1) * SIZEOF(CHAR))) > 0) {
pBuffer[size] = '\0';
DLOGI("Request ID: %s", pBuffer);
Expand Down Expand Up @@ -182,7 +187,7 @@ INT32 lwsHttpCallbackRoutine(struct lws* wsi, enum lws_callback_reasons reason,
DLOGD("Received client http");
size = LWS_SCRATCH_BUFFER_SIZE;

if (lws_http_client_read(wsi, &pBuffer, &size) < 0) {
if (lws_http_client_read((struct lws*) wsi, &pBuffer, &size) < 0) {
retValue = -1;
}

Expand Down Expand Up @@ -217,8 +222,8 @@ INT32 lwsHttpCallbackRoutine(struct lws* wsi, enum lws_callback_reasons reason,

DLOGV("Appending header - %s %s", pRequestHeader->pName, pRequestHeader->pValue);

status = lws_add_http_header_by_name(wsi, (PBYTE) pRequestHeader->pName, (PBYTE) pRequestHeader->pValue, pRequestHeader->valueLen,
ppStartPtr, pEndPtr);
status = lws_add_http_header_by_name((struct lws*) wsi, (PBYTE) pRequestHeader->pName, (PBYTE) pRequestHeader->pValue,
pRequestHeader->valueLen, ppStartPtr, pEndPtr);
if (status != 0) {
retValue = 1;
CHK(FALSE, retStatus);
Expand All @@ -232,29 +237,29 @@ INT32 lwsHttpCallbackRoutine(struct lws* wsi, enum lws_callback_reasons reason,
headerCount--;
}

lws_client_http_body_pending(wsi, 1);
lws_callback_on_writable(wsi);
lws_client_http_body_pending((struct lws*) wsi, 1);
lws_callback_on_writable((struct lws*) wsi);

break;

case LWS_CALLBACK_CLIENT_HTTP_WRITEABLE:
DLOGD("Sending the body %.*s, size %d", pRequestInfo->bodySize, pRequestInfo->body, pRequestInfo->bodySize);
MEMCPY(pBuffer, pRequestInfo->body, pRequestInfo->bodySize);

size = lws_write(wsi, (PBYTE) pBuffer, (SIZE_T) pRequestInfo->bodySize, LWS_WRITE_TEXT);
size = lws_write((struct lws*) wsi, (PBYTE) pBuffer, (SIZE_T) pRequestInfo->bodySize, LWS_WRITE_TEXT);

if (size != (INT32) pRequestInfo->bodySize) {
DLOGW("Failed to write out the body of POST request entirely. Expected to write %d, wrote %d", pRequestInfo->bodySize, size);
if (size > 0) {
// Schedule again
lws_client_http_body_pending(wsi, 1);
lws_callback_on_writable(wsi);
lws_client_http_body_pending((struct lws*) wsi, 1);
lws_callback_on_writable((struct lws*) wsi);
} else {
// Quit
retValue = 1;
}
} else {
lws_client_http_body_pending(wsi, 0);
lws_client_http_body_pending((struct lws*) wsi, 0);
}

break;
Expand All @@ -271,7 +276,7 @@ INT32 lwsHttpCallbackRoutine(struct lws* wsi, enum lws_callback_reasons reason,
ATOMIC_STORE_BOOL(&pRequestInfo->terminating, TRUE);
}

lws_cancel_service(lws_get_context(wsi));
lws_cancel_service(lws_get_context((struct lws*) wsi));

retValue = -1;
}
Expand All @@ -283,7 +288,7 @@ INT32 lwsHttpCallbackRoutine(struct lws* wsi, enum lws_callback_reasons reason,
return retValue;
}

INT32 lwsWssCallbackRoutine(struct lws* wsi, enum lws_callback_reasons reason, PVOID user, PVOID pDataIn, size_t dataSize)
INT32 lwsWssCallbackRoutine(PVOID wsi, INT32 reason, PVOID user, PVOID pDataIn, size_t dataSize)
{
UNUSED_PARAM(user);
STATUS retStatus = STATUS_SUCCESS;
Expand Down Expand Up @@ -312,14 +317,14 @@ INT32 lwsWssCallbackRoutine(struct lws* wsi, enum lws_callback_reasons reason, P
CHK(FALSE, retStatus);
}

customData = lws_get_opaque_user_data(wsi);
customData = lws_get_opaque_user_data((struct lws*) wsi);
pLwsCallInfo = (PLwsCallInfo) customData;

CHK_STATUS(configureLwsLogging(loggerGetLogLevel()));

CHK(pLwsCallInfo != NULL && pLwsCallInfo->pSignalingClient != NULL && pLwsCallInfo->pSignalingClient->pOngoingCallInfo != NULL &&
pLwsCallInfo->pSignalingClient->pLwsContext != NULL && pLwsCallInfo->pSignalingClient->pOngoingCallInfo->callInfo.pRequestInfo != NULL &&
pLwsCallInfo->protocolIndex == PROTOCOL_INDEX_WSS,
pLwsCallInfo->pSignalingClient->pWebsocketContext != NULL &&
pLwsCallInfo->pSignalingClient->pOngoingCallInfo->callInfo.pRequestInfo != NULL && pLwsCallInfo->protocolIndex == PROTOCOL_INDEX_WSS,
retStatus);
pSignalingClient = pLwsCallInfo->pSignalingClient;
pLwsCallInfo = pSignalingClient->pOngoingCallInfo;
Expand Down Expand Up @@ -564,7 +569,7 @@ STATUS lwsCompleteSync(PLwsCallInfo pCallInfo)
CHK_STATUS(removeRequestHeader(pCallInfo->callInfo.pRequestInfo, AWS_SIG_V4_HEADER_HOST));
}

pContext = pCallInfo->pSignalingClient->pLwsContext;
pContext = (struct lws_context*) pCallInfo->pSignalingClient->pWebsocketContext;

// Execute the LWS REST call
MEMSET(&connectInfo, 0x00, SIZEOF(struct lws_client_connect_info));
Expand Down Expand Up @@ -596,7 +601,7 @@ STATUS lwsCompleteSync(PLwsCallInfo pCallInfo)
connectInfo.path = path;
connectInfo.host = connectInfo.address;
connectInfo.method = pVerb;
connectInfo.protocol = pCallInfo->pSignalingClient->signalingProtocols[pCallInfo->protocolIndex].name;
connectInfo.protocol = ((struct lws_protocols*) pCallInfo->pSignalingClient->signalingProtocols[pCallInfo->protocolIndex])->name;
connectInfo.pwsi = &clientLws;

connectInfo.opaque_user_data = pCallInfo;
Expand Down Expand Up @@ -2413,7 +2418,7 @@ STATUS wakeLwsServiceEventLoop(PSignalingClient pSignalingClient, UINT32 protoco
STATUS retStatus = STATUS_SUCCESS;

// Early exit in case we don't need to do anything
CHK(pSignalingClient != NULL && pSignalingClient->pLwsContext != NULL, retStatus);
CHK(pSignalingClient != NULL && pSignalingClient->pWebsocketContext != NULL, retStatus);

if (pSignalingClient->currentWsi[protocolIndex] != NULL) {
lws_callback_on_writable(pSignalingClient->currentWsi[protocolIndex]);
Expand Down
11 changes: 7 additions & 4 deletions src/source/Signaling/LwsApiCalls.h
Original file line number Diff line number Diff line change
Expand Up @@ -167,11 +167,14 @@ extern "C" {
// Encoded max ice server infos string len
#define MAX_ENCODED_ICE_SERVER_INFOS_STR_LEN (MAX_ICE_SERVER_INFOS_STR_LEN + ICE_SERVER_INFO_TEMPLATE_BLOAT_SIZE)

// Alignment bytes for libwebsockets (Internally, it might end up using lesser than 16)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LWS_PRE is libwebsockets defined macro! We just use 16 bytes extra than required by message. libwebsockets can freely use these extra 16 bytes for its alignment needs.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like it would eventually make sense to have an "ApiCalls" interface to abstract away lws (similar to how Tls.h is setup).

Copy link
Contributor Author

@vikramdattu vikramdattu May 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My first thoughts were to have a function pointers structure and have it initialised with the required ApiCalls by the implementation. (The default would be the libwebsockets).
I think that would be more involved re-structuring. This one simply keeps everything at places just making headers more implementation dependent.

#define LWS_ALIGN_BYTES 16

// Scratch buffer size
#define LWS_SCRATCH_BUFFER_SIZE (MAX_JSON_PARAMETER_STRING_LEN + LWS_PRE)
#define LWS_SCRATCH_BUFFER_SIZE (MAX_JSON_PARAMETER_STRING_LEN + LWS_ALIGN_BYTES)

// Send and receive buffer size
#define LWS_MESSAGE_BUFFER_SIZE (SIZEOF(CHAR) * (MAX_SIGNALING_MESSAGE_LEN + LWS_PRE))
#define LWS_MESSAGE_BUFFER_SIZE (SIZEOF(CHAR) * (MAX_SIGNALING_MESSAGE_LEN + LWS_ALIGN_BYTES))

#define AWS_SIG_V4_HEADER_HOST (PCHAR) "host"

Expand Down Expand Up @@ -251,8 +254,8 @@ PVOID lwsListenerHandler(PVOID);
PVOID reconnectHandler(PVOID);

// LWS callback routine
INT32 lwsHttpCallbackRoutine(struct lws*, enum lws_callback_reasons, PVOID, PVOID, size_t);
INT32 lwsWssCallbackRoutine(struct lws*, enum lws_callback_reasons, PVOID, PVOID, size_t);
INT32 lwsHttpCallbackRoutine(PVOID, INT32, PVOID, PVOID, size_t);
INT32 lwsWssCallbackRoutine(PVOID, INT32, PVOID, PVOID, size_t);

BOOL isCallResultSignatureExpired(PCallInfo);
BOOL isCallResultSignatureNotYetCurrent(PCallInfo);
Expand Down
36 changes: 26 additions & 10 deletions src/source/Signaling/Signaling.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#define LOG_CLASS "Signaling"
#include "../Include_i.h"
#include <libwebsockets.h>
#include "LwsApiCalls.h"

extern StateMachineState SIGNALING_STATE_MACHINE_STATES[];
extern UINT32 SIGNALING_STATE_MACHINE_STATE_COUNT;
Expand All @@ -21,6 +23,8 @@ STATUS createSignalingSync(PSignalingClientInfoInternal pClientInfo, PChannelInf
BOOL cacheFound = FALSE;
PSignalingFileCacheEntry pFileCacheEntry = NULL;

struct lws_protocols* pProtocols = NULL;

CHK(pClientInfo != NULL && pChannelInfo != NULL && pCallbacks != NULL && pCredentialProvider != NULL && ppSignalingClient != NULL,
STATUS_NULL_ARG);
CHK(pChannelInfo->version <= CHANNEL_INFO_CURRENT_VERSION, STATUS_SIGNALING_INVALID_CHANNEL_INFO_VERSION);
Expand All @@ -33,6 +37,14 @@ STATUS createSignalingSync(PSignalingClientInfoInternal pClientInfo, PChannelInf
CHK_STATUS(initializeThreadTracker(&pSignalingClient->listenerTracker));
CHK_STATUS(initializeThreadTracker(&pSignalingClient->reconnecterTracker));

// Allocate memory for the protocols array (+ 1 for the null terminator protocol)
pProtocols = (struct lws_protocols*) MEMCALLOC(LWS_PROTOCOL_COUNT + 1, SIZEOF(struct lws_protocols));
CHK(pProtocols != NULL, STATUS_NOT_ENOUGH_MEMORY);

// Store the protocols pointer in the signalingProtocols array
pSignalingClient->signalingProtocols[PROTOCOL_INDEX_HTTPS] = pProtocols;
pSignalingClient->signalingProtocols[PROTOCOL_INDEX_WSS] = &pProtocols[PROTOCOL_INDEX_WSS];

// Validate and store the input
CHK_STATUS(createValidateChannelInfo(pChannelInfo, &pSignalingClient->pChannelInfo));
CHK_STATUS(validateSignalingCallbacks(pSignalingClient, pCallbacks));
Expand Down Expand Up @@ -93,18 +105,19 @@ STATUS createSignalingSync(PSignalingClientInfoInternal pClientInfo, PChannelInf
&pSignalingClient->pStateMachine));

// Prepare the signaling channel protocols array
pSignalingClient->signalingProtocols[PROTOCOL_INDEX_HTTPS].name = HTTPS_SCHEME_NAME;
pSignalingClient->signalingProtocols[PROTOCOL_INDEX_HTTPS].callback = lwsHttpCallbackRoutine;
pSignalingClient->signalingProtocols[PROTOCOL_INDEX_WSS].name = WSS_SCHEME_NAME;
pSignalingClient->signalingProtocols[PROTOCOL_INDEX_WSS].callback = lwsWssCallbackRoutine;
pProtocols = (struct lws_protocols*) pSignalingClient->signalingProtocols[PROTOCOL_INDEX_HTTPS];
pProtocols[PROTOCOL_INDEX_HTTPS].name = HTTPS_SCHEME_NAME;
pProtocols[PROTOCOL_INDEX_HTTPS].callback = (lws_callback_function*) lwsHttpCallbackRoutine;
pProtocols[PROTOCOL_INDEX_WSS].name = WSS_SCHEME_NAME;
pProtocols[PROTOCOL_INDEX_WSS].callback = (lws_callback_function*) lwsWssCallbackRoutine;

pSignalingClient->currentWsi[PROTOCOL_INDEX_HTTPS] = NULL;
pSignalingClient->currentWsi[PROTOCOL_INDEX_WSS] = NULL;

MEMSET(&creationInfo, 0x00, SIZEOF(struct lws_context_creation_info));
creationInfo.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
creationInfo.port = CONTEXT_PORT_NO_LISTEN;
creationInfo.protocols = pSignalingClient->signalingProtocols;
creationInfo.protocols = pProtocols;
creationInfo.timeout_secs = SIGNALING_SERVICE_API_CALL_TIMEOUT_IN_SECONDS;
creationInfo.gid = -1;
creationInfo.uid = -1;
Expand Down Expand Up @@ -165,8 +178,8 @@ STATUS createSignalingSync(PSignalingClientInfoInternal pClientInfo, PChannelInf

CHK_STATUS(configureLwsLogging(loggerGetLogLevel()));

pSignalingClient->pLwsContext = lws_create_context(&creationInfo);
CHK(pSignalingClient->pLwsContext != NULL, STATUS_SIGNALING_LWS_CREATE_CONTEXT_FAILED);
pSignalingClient->pWebsocketContext = lws_create_context(&creationInfo);
CHK(pSignalingClient->pWebsocketContext != NULL, STATUS_SIGNALING_LWS_CREATE_CONTEXT_FAILED);

// Initializing the diagnostics mostly is taken care of by zero-mem in MEMCALLOC
pSignalingClient->diagnostics.createTime = SIGNALING_GET_CURRENT_TIME(pSignalingClient);
Expand Down Expand Up @@ -223,13 +236,16 @@ STATUS freeSignaling(PSignalingClient* ppSignalingClient)

terminateOngoingOperations(pSignalingClient);

if (pSignalingClient->pLwsContext != NULL) {
if (pSignalingClient->pWebsocketContext != NULL) {
MUTEX_LOCK(pSignalingClient->lwsServiceLock);
lws_context_destroy(pSignalingClient->pLwsContext);
pSignalingClient->pLwsContext = NULL;
lws_context_destroy((struct lws_context*) pSignalingClient->pWebsocketContext);
pSignalingClient->pWebsocketContext = NULL;
MUTEX_UNLOCK(pSignalingClient->lwsServiceLock);
}

// Frees up the entire structure., both HTTPS and WSS protocols (it was allocated as single block)
SAFE_MEMFREE(pSignalingClient->signalingProtocols[PROTOCOL_INDEX_HTTPS]);

freeStateMachine(pSignalingClient->pStateMachine);

freeClientRetryStrategy(pSignalingClient);
Expand Down
13 changes: 7 additions & 6 deletions src/source/Signaling/Signaling.h
Original file line number Diff line number Diff line change
Expand Up @@ -337,14 +337,15 @@ typedef struct {
// Restarted thread handler
ThreadTracker reconnecterTracker;

// LWS context to use for Restful API
struct lws_context* pLwsContext;
// Generic websocket context - can be used by any implementation
PVOID pWebsocketContext;

// Signaling protocols - one more for the NULL terminator protocol
struct lws_protocols signalingProtocols[LWS_PROTOCOL_COUNT + 1];
// Generic websocket protocols array - can be used by any implementation
// + 1 for the null terminator protocol
PVOID signalingProtocols[LWS_PROTOCOL_COUNT + 1];

// Stored wsi objects
struct lws* currentWsi[LWS_PROTOCOL_COUNT];
// Generic websocket connection objects - can be used by any implementation
PVOID currentWsi[LWS_PROTOCOL_COUNT];

// List of the ongoing messages
PStackQueue pMessageQueue;
Expand Down
Loading