in src/source/Signaling/LwsApiCalls.c [14:286]
INT32 lwsHttpCallbackRoutine(struct lws* wsi, enum lws_callback_reasons reason, PVOID user, PVOID pDataIn, size_t dataSize)
{
UNUSED_PARAM(user);
STATUS retStatus = STATUS_SUCCESS;
PVOID customData;
INT32 status, retValue = 0, size;
PCHAR pCurPtr, pBuffer;
CHAR dateHdrBuffer[MAX_DATE_HEADER_BUFFER_LENGTH+1];
PBYTE pEndPtr;
PBYTE* ppStartPtr;
PLwsCallInfo pLwsCallInfo;
PRequestInfo pRequestInfo = NULL;
PSingleListNode pCurNode;
UINT64 item, serverTime;
UINT32 headerCount;
UINT32 logLevel;
PRequestHeader pRequestHeader;
PSignalingClient pSignalingClient = NULL;
BOOL locked = FALSE;
time_t td;
SIZE_T len;
UINT64 nowTime, clockSkew = 0;
PStateMachineState pStateMachineState;
BOOL skewMapContains = FALSE;
DLOGV("HTTPS callback with reason %d", reason);
// Early check before accessing the custom data field to see if we are interested in processing the message
switch (reason) {
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:
case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ:
case LWS_CALLBACK_RECEIVE_CLIENT_HTTP:
case LWS_CALLBACK_COMPLETED_CLIENT_HTTP:
case LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER:
case LWS_CALLBACK_CLIENT_HTTP_WRITEABLE:
break;
default:
CHK(FALSE, retStatus);
}
customData = lws_get_opaque_user_data(wsi);
pLwsCallInfo = (PLwsCallInfo) customData;
lws_set_log_level(LLL_NOTICE | LLL_WARN | LLL_ERR, NULL);
CHK(pLwsCallInfo != NULL && pLwsCallInfo->pSignalingClient != NULL && pLwsCallInfo->pSignalingClient->pLwsContext != NULL &&
pLwsCallInfo->callInfo.pRequestInfo != NULL && pLwsCallInfo->protocolIndex == PROTOCOL_INDEX_HTTPS,
retStatus);
// Quick check whether we need to exit
if (ATOMIC_LOAD(&pLwsCallInfo->cancelService)) {
retValue = 1;
ATOMIC_STORE_BOOL(&pRequestInfo->terminating, TRUE);
CHK(FALSE, retStatus);
}
pSignalingClient = pLwsCallInfo->pSignalingClient;
nowTime = SIGNALING_GET_CURRENT_TIME(pSignalingClient);
pRequestInfo = pLwsCallInfo->callInfo.pRequestInfo;
pBuffer = pLwsCallInfo->buffer + LWS_PRE;
logLevel = loggerGetLogLevel();
MUTEX_LOCK(pSignalingClient->lwsServiceLock);
locked = TRUE;
switch (reason) {
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
pCurPtr = pDataIn == NULL ? "(None)" : (PCHAR) pDataIn;
DLOGW("Client connection failed. Connection error string: %s", pCurPtr);
STRNCPY(pLwsCallInfo->callInfo.errorBuffer, pCurPtr, CALL_INFO_ERROR_BUFFER_LEN);
// TODO: Attempt to get more meaningful service return code
ATOMIC_STORE_BOOL(&pRequestInfo->terminating, TRUE);
ATOMIC_STORE(&pLwsCallInfo->pSignalingClient->result, (SIZE_T) SERVICE_CALL_UNKNOWN);
break;
case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
DLOGD("Client http closed");
ATOMIC_STORE_BOOL(&pRequestInfo->terminating, TRUE);
break;
case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:
status = lws_http_client_http_response(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);
time(&td);
if (len) {
// on failure to parse lws_http_date_unix returns non zero value
if (0 == lws_http_date_parse_unix(&dateHdrBuffer[0], len, &td)) {
DLOGV("Date Header Returned By Server: %s", dateHdrBuffer);
serverTime = ((UINT64) td) * HUNDREDS_OF_NANOS_IN_A_SECOND;
if (serverTime > nowTime + MIN_CLOCK_SKEW_TIME_TO_CORRECT) {
// Server time is ahead
clockSkew = (serverTime - nowTime);
DLOGD("Detected Clock Skew! Server time is AHEAD of Device time: Server time: %" PRIu64 ", now time: %" PRIu64, serverTime,
nowTime);
} else if (nowTime > serverTime + MIN_CLOCK_SKEW_TIME_TO_CORRECT) {
clockSkew = (nowTime - serverTime);
clockSkew |= ((UINT64)(1ULL << 63));
DLOGD("Detected Clock Skew! Device time is AHEAD of Server time: Server time: %" PRIu64 ", now time: %" PRIu64, serverTime,
nowTime);
// PIC hashTable implementation only stores UINT64 so I will flip the sign of the msb
// This limits the range of the max clock skew we can represent to just under 2925 years.
}
hashTableContains(pSignalingClient->diagnostics.pEndpointToClockSkewHashMap, pStateMachineState->state, &skewMapContains);
if (clockSkew > 0) {
hashTablePut(pSignalingClient->diagnostics.pEndpointToClockSkewHashMap, pStateMachineState->state, clockSkew);
} else if (clockSkew == 0 && skewMapContains) {
// This means the item is in the map so at one point there was a clock skew offset but it has been corrected
// So we should no longer be correcting for a clock skew, remove this item from the map
hashTableRemove(pSignalingClient->diagnostics.pEndpointToClockSkewHashMap, pStateMachineState->state);
}
}
}
// Store the Request ID header
if ((size = lws_hdr_custom_copy(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);
}
break;
case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ:
DLOGD("Received client http read: %d bytes", (INT32) dataSize);
lwsl_hexdump_debug(pDataIn, dataSize);
if (dataSize != 0) {
CHK(NULL != (pLwsCallInfo->callInfo.responseData = (PCHAR) MEMALLOC(dataSize+1)), STATUS_NOT_ENOUGH_MEMORY);
MEMCPY(pLwsCallInfo->callInfo.responseData, pDataIn, dataSize);
pLwsCallInfo->callInfo.responseData[dataSize] = '\0';
pLwsCallInfo->callInfo.responseDataLen = (UINT32) dataSize;
if (pLwsCallInfo->callInfo.callResult != SERVICE_CALL_RESULT_OK) {
DLOGW("Received client http read response: %s", pLwsCallInfo->callInfo.responseData);
if (pLwsCallInfo->callInfo.callResult == SERVICE_CALL_FORBIDDEN) {
if (isCallResultSignatureExpired(&pLwsCallInfo->callInfo)) {
// Set more specific result, this is so in the state machine
// We don't call GetToken again rather RETRY the existing API (now with clock skew correction)
pLwsCallInfo->callInfo.callResult = SERVICE_CALL_SIGNATURE_EXPIRED;
} else if (isCallResultSignatureNotYetCurrent(&pLwsCallInfo->callInfo)) {
// server time is ahead
pLwsCallInfo->callInfo.callResult = SERVICE_CALL_SIGNATURE_NOT_YET_CURRENT;
}
}
} else {
DLOGV("Received client http read response: %s", pLwsCallInfo->callInfo.responseData);
}
}
break;
case LWS_CALLBACK_RECEIVE_CLIENT_HTTP:
DLOGD("Received client http");
size = LWS_SCRATCH_BUFFER_SIZE;
if (lws_http_client_read(wsi, &pBuffer, &size) < 0) {
retValue = -1;
}
break;
case LWS_CALLBACK_COMPLETED_CLIENT_HTTP:
DLOGD("Http client completed");
break;
case LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER:
DLOGD("Client append handshake header\n");
CHK_STATUS(singleListGetNodeCount(pRequestInfo->pRequestHeaders, &headerCount));
ppStartPtr = (PBYTE*) pDataIn;
pEndPtr = *ppStartPtr + dataSize - 1;
// Iterate through the headers
while (headerCount != 0) {
CHK_STATUS(singleListGetHeadNode(pRequestInfo->pRequestHeaders, &pCurNode));
CHK_STATUS(singleListGetNodeData(pCurNode, &item));
pRequestHeader = (PRequestHeader) item;
// Append the colon at the end of the name
if (pRequestHeader->pName[pRequestHeader->nameLen - 1] != ':') {
STRCPY(pBuffer, pRequestHeader->pName);
pBuffer[pRequestHeader->nameLen] = ':';
pBuffer[pRequestHeader->nameLen + 1] = '\0';
pRequestHeader->pName = pBuffer;
pRequestHeader->nameLen++;
}
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);
if (status != 0) {
retValue = 1;
CHK(FALSE, retStatus);
}
// Remove the head
CHK_STATUS(singleListDeleteHead(pRequestInfo->pRequestHeaders));
MEMFREE(pRequestHeader);
// Decrement to iterate
headerCount--;
}
lws_client_http_body_pending(wsi, 1);
lws_callback_on_writable(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);
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);
} else {
// Quit
retValue = 1;
}
} else {
lws_client_http_body_pending(wsi, 0);
}
break;
default:
break;
}
CleanUp:
if (STATUS_FAILED(retStatus)) {
DLOGW("Failed in HTTPS handling routine with 0x%08x", retStatus);
if (pRequestInfo != NULL) {
ATOMIC_STORE_BOOL(&pRequestInfo->terminating, TRUE);
}
lws_cancel_service(lws_get_context(wsi));
retValue = -1;
}
if (locked) {
MUTEX_UNLOCK(pSignalingClient->lwsServiceLock);
}
return retValue;
}