1
0
mirror of https://github.com/Ylianst/MeshAgent synced 2025-12-25 20:53:15 +00:00
Files
MeshAgent/microlms/lms/ILibLMS.c
2017-10-12 14:28:03 -07:00

2013 lines
85 KiB
C

/*
Copyright 2006 - 2017 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
Real LMS code can be found here: http://software.intel.com/en-us/articles/download-the-latest-intel-amt-open-source-drivers
*/
#if !defined(_NOHECI)
#if defined(WIN32) && !defined(_WIN32_WCE) && !defined(_MINCORE)
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#endif
#if defined(WINSOCK2)
#include <winsock2.h>
#include <ws2ipdef.h>
#elif defined(WINSOCK1)
#include <winsock.h>
#include <wininet.h>
#endif
#include "../../microstack/ILibParsers.h"
#include "../../microstack/ILibAsyncSocket.h"
#include "../../microstack/ILibAsyncServerSocket.h"
#include "../../microstack/ILibCrypto.h"
#include "ILibLMS.h"
#ifndef NOLMSCOMMANDER
#include "../../microstack/ILibWebClient.h"
#include "../../microstack/ILibWebServer.h"
#include "ILibLMS-WebSite.h"
#endif
#ifdef WIN32
#include "../heci/heciwin.h"
#include "WinBase.h"
#endif
#ifdef _POSIX
#include "../heci/HECILinux.h"
#endif
#include "../heci/PTHICommand.h"
#include "../heci/LMEConnection.h"
#ifdef WIN32
char* strndup(char* ptr, int len) {
char* value;
if ((value = (char*)malloc(len + 1)) == NULL) ILIBCRITICALEXIT(254);
memcpy_s(value, len, ptr, len);
value[len] = 0;
return value;
}
#endif
#define INET_SOCKADDR_LENGTH(x) ((x==AF_INET6?sizeof(struct sockaddr_in6):sizeof(struct sockaddr_in)))
#define LMS_MAX_CONNECTIONS 6 // Maximum is 6, above this channel open starts to fail.
#define LMS_MAX_SESSIONS 32
#define LMS_MIN_SESSIONID 8
//#define _DEBUGLMS
#ifdef _DEBUGLMS
#define LMSDEBUG(...) printf(__VA_ARGS__);
#else
#define LMSDEBUG(...)
#endif
struct ILibLMS_StateModule* IlibExternLMS = NULL; // Glocal pointer to the LMS module. Since we can only have one of these modules running, a global pointer is sometimes useful.
void ILibLMS_SetupConnection(struct ILibLMS_StateModule* module, int i);
void ILibLMS_LaunchHoldingSessions(struct ILibLMS_StateModule* module);
#ifndef NOLMSCOMMANDER
void ILibLMS_ResumeWebSocket(struct ILibWebServer_Session *session);
#endif
// Each LMS session can be in one of these states.
enum LME_CHANNEL_STATUS {
LME_CS_FREE = 0, // The session slot is free, can be used at any time.
LME_CS_PENDING_CONNECT = 1, // A connection as been made to LMS and a notice has been send to Intel AMT asking for a CHANNEL OPEN.
LME_CS_CONNECTED = 2, // Intel AMT confirmed the connection and data can flow in both directions.
LME_CS_PENDING_LMS_DISCONNECT = 3, // The connection to LMS was disconnected, Intel AMT has been notified and we are waitting for Intel AMT confirmation.
LME_CS_PENDING_AMT_DISCONNECT = 4, // Intel AMT decided to close the connection. We are disconnecting the LMS TCP connection.
LME_CS_HOLDING = 5, // We got too much data from the LMS TCP connection, more than Intel AMT can handle. We are holding the connection until AMT can handle more.
LME_CS_CONNECTION_WAIT = 6 // A TCP connection to LMS was made, but there all LMS connections are currently busy. Waitting for one to free up.
};
// This is the structure for a session
struct LMEChannel
{
struct ILibLMS_StateModule* parent; // Pointer to the parent module
int ourid; // The identifier of this channel on our side, this is the same as the index in the "Channel Sessions[LMS_MAX_SESSIONS];" array below.
int amtid; // The Intel AMT identifier for this channel.
enum LME_CHANNEL_STATUS status; // Current status of the channel.
int sockettype; // Type of connected socket: 0 = TCP, 1 = WebSocket
void* socketmodule; // The microstack associated with the LMS connection.
int txwindow; // Transmit window.
int rxwindow; // Receive window.
unsigned short localport; // The Intel AMT connection port.
int errorcount; // Open channel error count.
char* pending; // Buffer pointing to pending data that needs to be sent to Intel AMT, used for websocket only.
int pendingcount; // Buffer pointing to pending data size that needs to be sent to Intel AMT, used for websocket only.
int pendingptr; // Pointer to start of the pending buffer.
};
enum LME_VERSION_HANDSHAKING {
LME_NOT_INITIATED,
LME_INITIATED,
LME_AGREED
};
enum LME_SERVICE_STATUS {
LME_NOT_STARTED,
LME_STARTED
};
// This is the Intel AMT LMS chain module structure
struct ILibLMS_StateModule
{
ILibChain_Link chainLink;
void *Server1; // Microstack TCP server for port 16992
void *Server2; // Microstack TCP server for port 16993
struct LMEConnection MeConnection; // The MEI connection structure
ILibLMS_OnNotification Callback; // Callback for Intel AMT notifications
struct LMEChannel Sessions[LMS_MAX_SESSIONS]; // List of sessions
#ifndef NOLMSCOMMANDER
ILibWebServer_ServerToken WebServer; // LMS Web Server
#endif
enum LME_VERSION_HANDSHAKING handshakingStatus;
enum LME_SERVICE_STATUS pfwdService;
unsigned int AmtProtVersionMajor; // Intel AMT MEI major version
unsigned int AmtProtVersionMinor; // Intel AMT MEI minor version
char* WebDir; // Web Directory
int NextSlotId; // Next time we search for an empty slot, start with this one
int PendingAmtConnection; // Currently pending connection session, used so we never issue two channel open to AMT at the same time
int NotificationSenderChannel; // Channel currently being used for Intel AMT notifications
char* NotificationBuffer;
int NotificationBufferLen;
sem_t Lock; // Global lock, this is needed because MEI listener is a different thread from the microstack thread
};
int ILibMemory_ILibLMS_CONTAINERSIZE = sizeof(struct ILibLMS_StateModule);
#ifdef WIN32
void __fastcall ILibLMS_setregistryA(char* name, char* value)
{
HKEY hKey;
#ifdef _WINSERVICE
// If running as a Windows Service, save the key in LOCAL_MACHINE
if (RegCreateKey(HKEY_LOCAL_MACHINE, TEXT("Software\\Open Source\\MicroLMS"), &hKey) == ERROR_SUCCESS)
#else
// If running in Console mode, save the key in CURRENT_USER
if (RegCreateKey(HKEY_CURRENT_USER, TEXT("Software\\Open Source\\MicroLMS"), &hKey) == ERROR_SUCCESS)
#endif
{
RegSetValueExA(hKey, name, 0, REG_SZ, (BYTE*)value, (DWORD)strnlen_s(value, 65535));
RegCloseKey(hKey);
}
}
int __fastcall ILibLMS_getregistryA(char* name, char** value)
{
HKEY hKey;
DWORD len = 0;
#ifdef _WINSERVICE
// If running as a Windows Service, open the key in LOCAL_MACHINE
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("Software\\Open Source\\MicroLMS"), 0, KEY_QUERY_VALUE, &hKey) != ERROR_SUCCESS) { *value = NULL; return 0; }
#else
// If running in Console mode, save the key in CURRENT_USER
if (RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Software\\Open Source\\MicroLMS"), 0, KEY_QUERY_VALUE, &hKey) != ERROR_SUCCESS) { *value = NULL; return 0; }
#endif
if (RegQueryValueExA(hKey, name, NULL, NULL, NULL, &len) != ERROR_SUCCESS || len == 0) { *value = NULL; RegCloseKey(hKey); return 0; }
if ((*value = (char*)malloc(len)) == NULL) ILIBCRITICALEXIT(254);
if (RegQueryValueExA(hKey, name, NULL, NULL, (LPBYTE)(*value), &len) != ERROR_SUCCESS || len == 0) { free(*value); *value = NULL; RegCloseKey(hKey); return 0; }
RegCloseKey(hKey);
return len - 1;
}
int __fastcall ILibLMS_deleteregistryA(char* name)
{
HKEY hKey;
#ifdef _WINSERVICE
// If running as a Windows Service, open the key in LOCAL_MACHINE
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("Software\\Open Source\\MicroLMS"), 0, KEY_SET_VALUE, &hKey) != ERROR_SUCCESS) { return 0; }
#else
// If running in Console mode, save the key in CURRENT_USER
if (RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Software\\Open Source\\MicroLMS"), 0, KEY_SET_VALUE, &hKey) != ERROR_SUCCESS) { return 0; }
#endif
RegDeleteValueA(hKey, name);
RegCloseKey(hKey);
return 1;
}
#endif
//Parse the XML Tree from rootNode and retrive value of a given key.
//If rootNode is passed as NULL, parsing resumes from last key retrieved node.
//Return 0 on Success , 1 otherwise.
int ILibGetXMLTagValue(struct ILibXMLNode *rootNode, char *tag, int tagLen, char *ns, int nsLen, char** value, int *valueLen)
{
static struct ILibXMLNode *cur = NULL;
static struct ILibXMLNode *pcur = NULL;
if (rootNode != NULL) { cur = rootNode; pcur = cur; }
while (cur != NULL) {
while (pcur != NULL) {
if (pcur->ClosingTag && memcmp((pcur->Name), tag, tagLen) == 0 && (!ns || (memcmp(pcur->NSTag, ns, pcur->NSLength) == 0))) {
char *pValue;
ILibReadInnerXML(pcur, &pValue);
if (pcur->ClosingTag->NSLength) { *valueLen = (int)(pcur->ClosingTag->NSTag - pValue - 2); } else { *valueLen = (int)(pcur->ClosingTag->Name - pValue - 2); }
*value = pValue;
pcur = pcur->Next;
return 0;
}
pcur = pcur->Next;
}
cur = cur->Peer;
pcur = cur;
}
return 1;
}
#define CLASS_URI "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_AlertIndication"
void* ILibLMS_getCIMAlertIndication(struct ILibXMLNode *node, char *ns, int nsLen)
{
char *value = NULL;
int valueLen = 0;
//char tmpBuffer[255] = { 0 };
struct cimAlertIndication *alertIndication = NULL;
if ((alertIndication = malloc(sizeof(struct cimAlertIndication))) == NULL) ILIBCRITICALEXIT(254);
memset(alertIndication, 0, sizeof(struct cimAlertIndication));
if (ILibGetXMLTagValue(node, "MessageID", (int)strlen("MessageID"), ns, nsLen, &value, &valueLen) == 0) {
alertIndication->MessageID.data = strndup(value, valueLen);
alertIndication->MessageID.dataLen = valueLen;
}
if (ILibGetXMLTagValue(node, "MessageArguments", (int)strlen("MessageArguments"), ns, nsLen, &value, &valueLen) == 0) {
alertIndication->MessageArguments.data = strndup(value, valueLen);
alertIndication->MessageArguments.dataLen = valueLen;
}
if (ILibGetXMLTagValue(node, "IndicationTime", (int)strlen("IndicationTime"), ns, nsLen, &value, &valueLen) == 0) {
if (ILibGetXMLTagValue(NULL, "Datetime", (int)strlen("DateTime"), NULL, 0, &value, &valueLen) == 0) {
alertIndication->IndicationTime.data = strndup(value, valueLen);
alertIndication->IndicationTime.dataLen = valueLen;
}
}
/*
if (ILibGetXMLTagValue(node, "AlertType", strlen("AlertType"), ns, nsLen, &value, &valueLen) == 0) {
memcpy(tmpBuffer, value, valueLen);
tmpBuffer[valueLen] = '\0';
alertIndication->AlertType = atoi(tmpBuffer);
}
if (ILibGetXMLTagValue(node, "AlertingElementFormat", strlen("AlertingElementFormat"), ns, nsLen, &value, &valueLen) == 0) {
memcpy(tmpBuffer, value, valueLen);
tmpBuffer[valueLen] = '\0';
alertIndication->AlertingElementFormat = atoi(tmpBuffer);
}
if (ILibGetXMLTagValue(node, "PerceivedSeverity", strlen("PerceivedSeverity"), ns, nsLen, &value, &valueLen) == 0) {
memcpy(tmpBuffer, value, valueLen);
tmpBuffer[valueLen] = '\0';
alertIndication->PerceivedSeverity = atoi(tmpBuffer);
}
if (ILibGetXMLTagValue(node, "ProbableCause", strlen("ProbableCause"), ns, nsLen, &value, &valueLen) == 0) {
memcpy(tmpBuffer, value, valueLen);
tmpBuffer[valueLen] = '\0';
alertIndication->ProbableCause = atoi(tmpBuffer);
}
if (ILibGetXMLTagValue(node, "Trending", strlen("Trending"), ns, nsLen, &value, &valueLen) == 0) {
memcpy(tmpBuffer, value, valueLen);
tmpBuffer[valueLen] = '\0';
alertIndication->Trending = atoi(tmpBuffer);
}
if (ILibGetXMLTagValue(node, "SequenceNumber", strlen("SequenceNumber"), ns, nsLen, &value, &valueLen) == 0) {
memcpy(tmpBuffer, value, valueLen);
tmpBuffer[valueLen] = '\0';
alertIndication->SequenceNumber = atoi(tmpBuffer);
}
if (ILibGetXMLTagValue(node, "AlertingManagedElement", strlen("AlertingManagedElement"), ns, nsLen, &value, &valueLen) == 0) {
alertIndication->AlertingManagedElement.data = strndup(value, valueLen);
alertIndication->AlertingManagedElement.dataLen = valueLen;
}
if (ILibGetXMLTagValue(node, "CorrelatedIndications", strlen("CorrelatedIndications"), ns, nsLen, &value, &valueLen) == 0) {
alertIndication->CorrelatedIndications.data = strndup(value, valueLen);
alertIndication->CorrelatedIndications.dataLen = valueLen;
}
if (ILibGetXMLTagValue(node, "Description", strlen("Description"), ns, nsLen, &value, &valueLen) == 0) {
alertIndication->Description.data = strndup(value, valueLen);
alertIndication->Description.dataLen = valueLen;
}
if (ILibGetXMLTagValue(node, "EventID", strlen("EventID"), ns, nsLen, &value, &valueLen) == 0) {
alertIndication->EventID.data = strndup(value, valueLen);
alertIndication->EventID.dataLen = valueLen;
}
if (ILibGetXMLTagValue(node, "IndicationFilterName", strlen("IndicationFilterName"), ns, nsLen, &value, &valueLen) == 0) {
alertIndication->IndicationFilterName.data = strndup(value, valueLen);
alertIndication->IndicationFilterName.dataLen = valueLen;
}
if (ILibGetXMLTagValue(node, "IndicationIdentifier", strlen("IndicationIdentifier"), ns, nsLen, &value, &valueLen) == 0) {
alertIndication->IndicationIdentifier.data = strndup(value, valueLen);
alertIndication->IndicationIdentifier.dataLen = valueLen;
}
if (ILibGetXMLTagValue(node, "OtherAlertType", strlen("OtherAlertType"), ns, nsLen, &value, &valueLen) == 0) {
alertIndication->OtherAlertType.data = strndup(value, valueLen);
alertIndication->OtherAlertType.dataLen = valueLen;
}
if (ILibGetXMLTagValue(node, "OtherAlertingElementFormat", strlen("OtherAlertingElementFormat"), ns, nsLen, &value, &valueLen) == 0) {
alertIndication->OtherAlertingElementFormat.data = strndup(value, valueLen);
alertIndication->OtherAlertingElementFormat.dataLen = valueLen;
}
if (ILibGetXMLTagValue(node, "OtherSeverity", strlen("OtherSeverity"), ns, nsLen, &value, &valueLen) == 0) {
alertIndication->OtherSeverity.data = strndup(value, valueLen);
alertIndication->OtherSeverity.dataLen = valueLen;
}
if (ILibGetXMLTagValue(node, "OwningEntity", strlen("OwningEntity"), ns, nsLen, &value, &valueLen) == 0) {
alertIndication->OwningEntity.data = strndup(value, valueLen);
alertIndication->OwningEntity.dataLen = valueLen;
}
if (ILibGetXMLTagValue(node, "ProbableCauseDescription", strlen("ProbableCauseDescription"), ns, nsLen, &value, &valueLen) == 0) {
alertIndication->ProbableCauseDescription.data = strndup(value, valueLen);
alertIndication->ProbableCauseDescription.dataLen = valueLen;
}
if (ILibGetXMLTagValue(node, "ProviderName", strlen("ProviderName"), ns, nsLen, &value, &valueLen) == 0) {
alertIndication->ProviderName.data = strndup(value, valueLen);
alertIndication->ProviderName.dataLen = valueLen;
}
if (ILibGetXMLTagValue(node, "RecommendedActions", strlen("RecommendedActions"), ns, nsLen, &value, &valueLen) == 0) {
alertIndication->RecommendedActions.data = strndup(value, valueLen);
alertIndication->RecommendedActions.dataLen = valueLen;
}
if (ILibGetXMLTagValue(node, "SequenceContext", strlen("SequenceContext"), ns, nsLen, &value, &valueLen) == 0) {
alertIndication->SequenceContext.data = strndup(value, valueLen);
alertIndication->SequenceContext.dataLen = valueLen;
}
if (ILibGetXMLTagValue(node, "SystemCreationClassName", strlen("SystemCreationClassName"), ns, nsLen, &value, &valueLen) == 0) {
alertIndication->SystemCreationClassName.data = strndup(value, valueLen);
alertIndication->SystemCreationClassName.dataLen = valueLen;
}
if (ILibGetXMLTagValue(node, "SystemName", strlen("SystemName"), ns, nsLen, &value, &valueLen) == 0) {
alertIndication->SystemName.data = strndup(value, valueLen);
alertIndication->SystemName.dataLen = valueLen;
}
if (ILibGetXMLTagValue(node, "EventTime", strlen("EventTime"), ns, nsLen, &value, &valueLen) == 0) {
if (ILibGetXMLTagValue(NULL, "Datetime", strlen("DateTime"), NULL, 0, &value, &valueLen) == 0) {
alertIndication->EventTime.data = strndup(value, valueLen);
alertIndication->EventTime.dataLen = valueLen;
}
}
*/
return alertIndication;
}
void ILibLMS_destructAlertIndication(struct cimAlertIndication *alertIndication)
{
if (alertIndication == NULL) return;
if (alertIndication->IndicationTime.data) free(alertIndication->IndicationTime.data);
if (alertIndication->MessageID.data) free(alertIndication->MessageID.data);
if (alertIndication->MessageArguments.data) free(alertIndication->MessageArguments.data);
/*
if (alertIndication->AlertingManagedElement.data) free(alertIndication->AlertingManagedElement.data);
if (alertIndication->CorrelatedIndications.data) free(alertIndication->CorrelatedIndications.data);
if (alertIndication->Description.data) free(alertIndication->Description.data);
if (alertIndication->EventID.data) free(alertIndication->EventID.data);
if (alertIndication->IndicationFilterName.data) free(alertIndication->IndicationFilterName.data);
if (alertIndication->IndicationIdentifier.data) free(alertIndication->IndicationIdentifier.data);
if (alertIndication->OtherAlertType.data) free(alertIndication->OtherAlertType.data);
if (alertIndication->OtherAlertingElementFormat.data) free(alertIndication->OtherAlertingElementFormat.data);
if (alertIndication->OtherSeverity.data) free(alertIndication->OtherSeverity.data);
if (alertIndication->OwningEntity.data) free(alertIndication->OwningEntity.data);
if (alertIndication->ProbableCauseDescription.data) free(alertIndication->ProbableCauseDescription.data);
if (alertIndication->ProviderName.data) free(alertIndication->ProviderName.data);
if (alertIndication->RecommendedActions.data) free(alertIndication->RecommendedActions.data);
if (alertIndication->SystemCreationClassName.data) free(alertIndication->SystemCreationClassName.data);
if (alertIndication->SystemName.data) free(alertIndication->SystemName.data);
if (alertIndication->EventTime.data) free(alertIndication->EventTime.data);
if (alertIndication->__any.data) free(alertIndication->__any.data);
if (alertIndication->__anyAttribute.data) free(alertIndication->__anyAttribute.data);
*/
free(alertIndication);
}
void* ILibLMS_getCIMAlertIndicationFromXML(char *buffer, int bufferLen)
{
struct ILibXMLNode *node = NULL;
struct cimAlertIndication *alertIndication = NULL;
struct ILibXMLAttribute *xmlRootAttr = NULL;
struct ILibXMLAttribute *xmlAttr = NULL;
char *nsPrefix = NULL;
int nsPrefixLen = 0;
int foundNS = 0;
do {
node = ILibParseXML(buffer, 0, bufferLen);
if (node == NULL) break;
//Break if XML is not well formed
if (ILibProcessXMLNodeList(node)) break;
xmlRootAttr = ILibGetXMLAttributes(node);
if (xmlRootAttr == NULL) break;
xmlAttr = xmlRootAttr;
while (xmlAttr != NULL)
{
if (xmlAttr->PrefixLength == 5 && xmlAttr->Prefix != NULL && memcmp(xmlAttr->Prefix, "xmlns", 5) == 0 && memcmp(xmlAttr->Value, CLASS_URI, strlen(CLASS_URI)) == 0)
{
nsPrefixLen = xmlAttr->NameLength;
nsPrefix = xmlAttr->Name;
foundNS = 1;
break;
}
else if (xmlAttr->NameLength == 5 && xmlAttr->Name != NULL && memcmp(xmlAttr->Name, "xmlns", 5) == 0 && memcmp(xmlAttr->Value, CLASS_URI, strlen(CLASS_URI)) == 0)
{
nsPrefixLen = xmlAttr->PrefixLength;
nsPrefix = xmlAttr->Prefix;
foundNS = 1;
break;
}
xmlAttr = xmlAttr->Next;
}
if (foundNS == 0) break;
alertIndication = ILibLMS_getCIMAlertIndication(node, nsPrefix, nsPrefixLen);
} while (0);
if (xmlRootAttr) ILibDestructXMLAttributeList(xmlRootAttr);
if (node) ILibDestructXMLNodeList(node);
return alertIndication;
}
#define NOTIFICATION_CHANNEL 55555
#define PACKET_BODY_LENGTH "Content-Length"
void __fastcall ILibLMS_clearNotificationData(struct ILibLMS_StateModule* module)
{
if (module->NotificationBuffer != NULL) { free(module->NotificationBuffer); }
module->NotificationBuffer = NULL;
module->NotificationBufferLen = 0;
}
int __fastcall ILibLMS_processNotificationData(struct ILibLMS_StateModule* module, void *rxBuffer, unsigned int dataLen)
{
char *pRxBuffer = NULL;
char *tmpBuffer = NULL;
char *pPacketBodyLength = NULL;
int rc = -1;
int packetBodyLength = 0;
int headerPacketLen = 0;
struct packetheader *headerPacket = NULL;
struct packetheader *txHeaderPacket = NULL;
struct cimAlertIndication *alertIndication = NULL;
// Append received notification bytes to existing buffer otherwise.
if (module->NotificationBuffer == NULL) {
if ((module->NotificationBuffer = (char*)malloc((dataLen + 1) * sizeof(char))) == NULL) ILIBCRITICALEXIT(254);
} else {
if ((module->NotificationBuffer = (char*)realloc(module->NotificationBuffer, (module->NotificationBufferLen + dataLen + 1) * sizeof(char))) == NULL) ILIBCRITICALEXIT(254);
}
pRxBuffer = module->NotificationBuffer + module->NotificationBufferLen;
memcpy(pRxBuffer, rxBuffer, dataLen);
module->NotificationBufferLen += dataLen;
module->NotificationBuffer[module->NotificationBufferLen] = '\0';
// Process HTTP data
do {
// Look for the end of the HTTP header
pRxBuffer = strstr(module->NotificationBuffer, "\r\n\r\n");
if (pRxBuffer == NULL) break;
// Copy the HTTP header into a temporary place (TODO: See if we can not do this)
headerPacketLen = (int)(pRxBuffer + 4 - module->NotificationBuffer);
if ((tmpBuffer = malloc(headerPacketLen + 1)) == NULL) ILIBCRITICALEXIT(254);
memcpy(tmpBuffer, module->NotificationBuffer, headerPacketLen);
tmpBuffer[headerPacketLen] = 0;
// Parse the HTTP header to get the content length
if ((headerPacket = ILibParsePacketHeader(tmpBuffer, 0, (int)(pRxBuffer + 4 - module->NotificationBuffer))) == NULL) break;
if ((pPacketBodyLength = ILibGetEntry(headerPacket->HeaderTable, PACKET_BODY_LENGTH, (int)strlen(PACKET_BODY_LENGTH))) == NULL) break;
packetBodyLength = atoi(pPacketBodyLength);
pRxBuffer = pRxBuffer + 4;
// If we got the entire message body, process it
if ((module->NotificationBufferLen - (int)(pRxBuffer - module->NotificationBuffer)) < packetBodyLength) break;
if ((alertIndication = ILibLMS_getCIMAlertIndicationFromXML(pRxBuffer, packetBodyLength)) == NULL) break;
// We have a valid notification, call the parent with the notification information
if (module->Callback != NULL) { module->Callback(module, alertIndication, pRxBuffer, packetBodyLength); } // If there is a callback registered, call it now
rc = 0; // Causes notification channel disconnection
} while (0);
if (tmpBuffer) free(tmpBuffer);
if (headerPacket) ILibDestructPacket(headerPacket);
if (txHeaderPacket) ILibDestructPacket(txHeaderPacket);
if (alertIndication) ILibLMS_destructAlertIndication(alertIndication);
return rc;
}
int GetFreeSlot(struct ILibLMS_StateModule* module) {
int i, j;
for (i = 0; i < LMS_MAX_SESSIONS; i++) {
j = (module->NextSlotId + i) % LMS_MAX_SESSIONS;
if (module->Sessions[j].status == LME_CS_FREE) { module->NextSlotId = j + 1; return j; }
}
return -1;
}
int SlotFromChannelId(int channel) {
if (channel < LMS_MIN_SESSIONID || channel >= (LMS_MAX_SESSIONS + LMS_MIN_SESSIONID)) { LMSDEBUG("Invalid ChannelId: %d\r\n", channel); return 0; }
return channel - LMS_MIN_SESSIONID;
}
// This function is called each time a MEI message is received from Intel AMT
void ILibLMS_MEICallback(struct LMEConnection* lmemodule, void *param, void *rxBuffer, unsigned int len)
{
struct ILibLMS_StateModule* module = (struct ILibLMS_StateModule*)param;
int disconnects = 0; // This is a counter of how many sessions are freed up. We use this at the end to place HOLDING sessions into free slots.
// Happens when the chain is being destroyed, don't call anything chain related.
if (rxBuffer == NULL) return;
sem_wait(&(module->Lock));
//LMSDEBUG("ILibLMS_MEICallback %d\r\n", ((unsigned char*)rxBuffer)[0]);
switch (((unsigned char*)rxBuffer)[0])
{
case APF_GLOBAL_REQUEST: // 80
{
int request = 0;
unsigned char *pCurrent;
APF_GENERIC_HEADER *pHeader = (APF_GENERIC_HEADER *)rxBuffer;
pHeader->StringLength = ntohl(pHeader->StringLength);
if (pHeader->StringLength == APF_STR_SIZE_OF(APF_GLOBAL_REQUEST_STR_TCP_FORWARD_REQUEST) && memcmp(pHeader->String, APF_GLOBAL_REQUEST_STR_TCP_FORWARD_REQUEST, APF_STR_SIZE_OF(APF_GLOBAL_REQUEST_STR_TCP_FORWARD_REQUEST)) == 0) { request = 1; }
else if (pHeader->StringLength == APF_STR_SIZE_OF(APF_GLOBAL_REQUEST_STR_TCP_FORWARD_CANCEL_REQUEST) && memcmp(pHeader->String, APF_GLOBAL_REQUEST_STR_TCP_FORWARD_CANCEL_REQUEST, APF_STR_SIZE_OF(APF_GLOBAL_REQUEST_STR_TCP_FORWARD_CANCEL_REQUEST)) == 0) { request = 2; }
else if (pHeader->StringLength == APF_STR_SIZE_OF(APF_GLOBAL_REQUEST_STR_UDP_SEND_TO) && memcmp(pHeader->String, APF_GLOBAL_REQUEST_STR_UDP_SEND_TO, APF_STR_SIZE_OF(APF_GLOBAL_REQUEST_STR_UDP_SEND_TO)) == 0) { request = 3; }
if (request == 1 || request == 2)
{
int port = 0;
unsigned int len2;
unsigned int bytesRead = len;
unsigned int hsize=0;
if (request==1)
hsize = sizeof(APF_GENERIC_HEADER) + APF_STR_SIZE_OF(APF_GLOBAL_REQUEST_STR_TCP_FORWARD_REQUEST) + sizeof(UINT8);
else if (request==2)
hsize = sizeof(APF_GENERIC_HEADER) + APF_STR_SIZE_OF(APF_GLOBAL_REQUEST_STR_TCP_FORWARD_CANCEL_REQUEST) + sizeof(UINT8);
pCurrent = (unsigned char*)rxBuffer + hsize;
bytesRead -= hsize;
if (bytesRead < sizeof(unsigned int)) {
LME_Deinit(lmemodule);
sem_post(&(module->Lock));
return;
}
len2 = ntohl(*((unsigned int *)pCurrent));
pCurrent += sizeof(unsigned int);
if (bytesRead < (sizeof(unsigned int) + len2 + sizeof(unsigned int))) {
LME_Deinit(lmemodule);
sem_post(&(module->Lock));
return;
}
// addr = (char*)pCurrent;
pCurrent += len2;
port = ntohl(*((unsigned int *)pCurrent));
// TODO: Look at port number
// Confirm the new open port
LME_TcpForwardReplySuccess(lmemodule, port);
}
else if (request == 3)
{
// Send a UDP packet
// TODO: Send UDP
}
else{
// do nothing
}
}
break;
case APF_CHANNEL_OPEN: // (90) Sent by Intel AMT when a channel needs to be open from Intel AMT. This is not common, but WSMAN events are a good example of channel coming from AMT.
{
unsigned int len2;
unsigned char *pCurrent;
struct LMEChannelOpenRequestMessage channelOpenRequest;
APF_GENERIC_HEADER *pHeader = (APF_GENERIC_HEADER *)rxBuffer;
if (len < sizeof(APF_GENERIC_HEADER) + ntohl(pHeader->StringLength) + 7 + (5 * sizeof(UINT32))) { LME_Deinit(lmemodule); sem_post(&(module->Lock)); return; }
pCurrent = (unsigned char*)rxBuffer + sizeof(APF_GENERIC_HEADER) + APF_STR_SIZE_OF(APF_OPEN_CHANNEL_REQUEST_DIRECT);
channelOpenRequest.ChannelType = APF_CHANNEL_DIRECT;
channelOpenRequest.SenderChannel = ntohl(*((UINT32 *)pCurrent));
pCurrent += sizeof(UINT32);
channelOpenRequest.InitialWindow = ntohl(*((UINT32 *)pCurrent));
pCurrent += 2 * sizeof(UINT32);
len2 = ntohl(*((UINT32 *)pCurrent));
pCurrent += sizeof(UINT32);
channelOpenRequest.Address = (char*)pCurrent;
pCurrent += len2;
channelOpenRequest.Port = ntohl(*((UINT32 *)pCurrent));
pCurrent += sizeof(UINT32);
//printf("APF_CHANNEL_OPEN - %d, %s, %s:%d\r\n", channelOpenRequest.SenderChannel, (char*)pHeader->String, channelOpenRequest.Address, channelOpenRequest.Port);
// if (ntohl(pHeader->StringLength) == APF_STR_SIZE_OF(APF_OPEN_CHANNEL_REQUEST_DIRECT) && memcmp((char*)pHeader->String, APF_OPEN_CHANNEL_REQUEST_DIRECT, APF_STR_SIZE_OF(APF_OPEN_CHANNEL_REQUEST_DIRECT)) == 0) { }
if ((module->Callback != NULL) && (channelOpenRequest.Port == 0) && (module->NotificationSenderChannel == 0)) {
module->NotificationSenderChannel = channelOpenRequest.SenderChannel;
LME_ChannelOpenReplySuccess(lmemodule, channelOpenRequest.SenderChannel, NOTIFICATION_CHANNEL);
ILibLMS_clearNotificationData(module);
} else {
LME_ChannelOpenReplyFailure(lmemodule, channelOpenRequest.SenderChannel, OPEN_FAILURE_REASON_CONNECT_FAILED);
}
}
break;
case APF_DISCONNECT: // (1) Intel AMT wants to completely disconnect. Not sure when this happens.
{
// First, we decode the message.
LMSDEBUG("LME requested to disconnect with reason code 0x%08x\r\n", ((APF_DISCONNECT_REASON_CODE)ntohl(((APF_DISCONNECT_MESSAGE *)rxBuffer)->ReasonCode)));
//printf("APF_DISCONNECT %d\r\n", ReasonCode);
LME_Deinit(lmemodule);
}
break;
case APF_SERVICE_REQUEST: // (5)
{
int service = 0;
APF_SERVICE_REQUEST_MESSAGE *pMessage = (APF_SERVICE_REQUEST_MESSAGE *)rxBuffer;
pMessage->ServiceNameLength = ntohl(pMessage->ServiceNameLength);
if (pMessage->ServiceNameLength == 18) {
if (memcmp(pMessage->ServiceName, "pfwd@amt.intel.com", 18) == 0) service = 1;
else if (memcmp(pMessage->ServiceName, "auth@amt.intel.com", 18) == 0) service = 2;
}
if (service > 0)
{
if (service == 1)
{
LME_ServiceAccept(lmemodule, "pfwd@amt.intel.com");
module->pfwdService = LME_STARTED;
}
else if (service == 2)
{
LME_ServiceAccept(lmemodule, "auth@amt.intel.com");
}
} else {
LMSDEBUG("APF_SERVICE_REQUEST - APF_DISCONNECT_SERVICE_NOT_AVAILABLE\r\n");
LME_Disconnect(lmemodule, APF_DISCONNECT_SERVICE_NOT_AVAILABLE);
LME_Deinit(lmemodule);
sem_post(&(module->Lock));
return;
}
}
break;
case APF_CHANNEL_OPEN_CONFIRMATION: // (91) Intel AMT confirmation to an APF_CHANNEL_OPEN request.
{
// First, we decode the message.
struct LMEChannel* channel;
APF_CHANNEL_OPEN_CONFIRMATION_MESSAGE *pMessage = (APF_CHANNEL_OPEN_CONFIRMATION_MESSAGE *)rxBuffer;
struct LMEChannelOpenReplySuccessMessage channelOpenReply;
channelOpenReply.RecipientChannel = ntohl(pMessage->RecipientChannel); // This is the identifier on our side.
channelOpenReply.SenderChannel = ntohl(pMessage->SenderChannel); // This is the identifier on the Intel AMT side.
channelOpenReply.InitialWindow = ntohl(pMessage->InitialWindowSize); // This is the starting window size for flow control.
//printf("APF_CHANNEL_OPEN_CONFIRMATION %d\r\n", channelOpenReply.RecipientChannel);
channel = &(module->Sessions[SlotFromChannelId(channelOpenReply.RecipientChannel)]);// Get the current session for this message.
ILibLifeTime_Remove(ILibGetBaseTimer(module->chainLink.ParentChain), channel); // Clear the timer
module->PendingAmtConnection = 0;
if (channel == NULL) break; // This should never happen.
if (channelOpenReply.RecipientChannel != (unsigned int)(channel->ourid)) { LMSDEBUG("APF_CHANNEL_OPEN_CONFIRMATION_MESSAGE - Channel Mismatch %d != %d\r\n", channelOpenReply.RecipientChannel, channel->ourid); break; }
LMSDEBUG("MEI OPEN OK OUR:%d AMT:%d\r\n", channelOpenReply.RecipientChannel, channelOpenReply.SenderChannel);
if (channel->status == LME_CS_PENDING_CONNECT) // If the channel is in PENDING_CONNECT mode, move the session to connected state.
{
channel->amtid = channelOpenReply.SenderChannel; // We have to set the Intel AMT identifier for this session.
channel->txwindow = channelOpenReply.InitialWindow; // Set the session txwindow.
channel->status = LME_CS_CONNECTED; // Now set the session as CONNECTED.
LMSDEBUG("Channel %d now CONNECTED by AMT %p\r\n", channel->ourid, channel->socketmodule);
if (channel->sockettype == 0) // If the current socket is PAUSED, lets resume it so data can start flowing again.
{
ILibAsyncSocket_Resume(channel->socketmodule); // TCP socket resume
}
#ifndef NOLMSCOMMANDER
else
{
ILibLMS_ResumeWebSocket(channel->socketmodule); // Web socket resume
}
#endif
}
else if (channel->status == LME_CS_PENDING_LMS_DISCONNECT) // If the channel is in PENDING_DISCONNECT, we have to disconnect the session now. Happens when we disconnect while connection is pending. We don't want to stop a channel during connection, that is bad.
{
channel->amtid = channelOpenReply.SenderChannel; // We have to set the Intel AMT identifier for this session.
LME_ChannelClose(&(module->MeConnection), channel->amtid, channel->ourid); // Send the Intel AMT close. We keep the channel in LME_CS_PENDING_LMS_DISCONNECT state until the close is confirmed.
LMSDEBUG("Channel %d now CONNECTED by AMT %p, but CLOSING it now\r\n", channel->ourid, channel->socketmodule);
}
else
{
// Here, we get an APF_CHANNEL_OPEN in an unexpected state, this should never happen.
//printf("Channel %d, unexpected CONNECTED by AMT %d\r\n", channel->ourid, channel->socketmodule);
}
sem_post(&(module->Lock));
ILibLMS_LaunchHoldingSessions(module);
return;
}
break;
case APF_CHANNEL_OPEN_FAILURE: // (92) Intel AMT rejected our connection attempt.
{
// First, we decode the message.
struct LMEChannel* channel;
APF_CHANNEL_OPEN_FAILURE_MESSAGE *pMessage = (APF_CHANNEL_OPEN_FAILURE_MESSAGE *)rxBuffer;
struct LMEChannelOpenReplyFailureMessage channelOpenReply;
channelOpenReply.RecipientChannel = ntohl(pMessage->RecipientChannel); // This is the identifier on our side.
channelOpenReply.ReasonCode = (OPEN_FAILURE_REASON)(ntohl(pMessage->ReasonCode)); // Get the error reason code.
//printf("APF_CHANNEL_OPEN_FAILURE %d, %d\r\n", channelOpenReply.RecipientChannel, channelOpenReply.ReasonCode);
channel = &(module->Sessions[SlotFromChannelId(channelOpenReply.RecipientChannel)]);// Get the current session for this message.
ILibLifeTime_Remove(ILibGetBaseTimer(module->chainLink.ParentChain), channel); // Clear the timer
module->PendingAmtConnection = 0;
if (channel == NULL) break; // This should never happen.
if (channelOpenReply.RecipientChannel != (unsigned int)(channel->ourid)) { LMSDEBUG("APF_CHANNEL_OPEN_FAILURE - Channel Mismatch %d != %d\r\n", channelOpenReply.RecipientChannel, channel->ourid); break; }
LMSDEBUG("**OPEN FAIL OUR:%d ERR:%d, ERRCNT:%d\r\n", channelOpenReply.RecipientChannel, channelOpenReply.ReasonCode, channel->errorcount);
if (channel->errorcount++ >= 10 || channel->status == LME_CS_PENDING_LMS_DISCONNECT)
{
// Fail connection
LMSDEBUG("Failed Connection - Channel %d now FREE by AMT, status = %d\r\n", channel->ourid, channel->status);
channel->status = LME_CS_FREE;
sem_post(&(module->Lock));
ILibAsyncSocket_Disconnect(channel->socketmodule);
ILibLMS_LaunchHoldingSessions(module);
return;
}
else
{
// Try again
ILibLMS_SetupConnection(module, SlotFromChannelId(channelOpenReply.RecipientChannel));
}
}
break;
case APF_CHANNEL_CLOSE: // (97) Intel AMT is closing this channel, we need to disconnect the LMS TCP connection
{
// First, we decode the message.
struct LMEChannel* channel;
APF_CHANNEL_CLOSE_MESSAGE *pMessage = (APF_CHANNEL_CLOSE_MESSAGE *)rxBuffer;
struct LMEChannelCloseMessage channelClose;
channelClose.RecipientChannel = ntohl(pMessage->RecipientChannel); // This is the identifier on our side.
// if (channelClose.RecipientChannel == 0) { printf("APF_CHANNEL_CLOSE channel %d\r\n"); break; }
//printf("APF_CHANNEL_CLOSE channel %d\r\n", channelClose.RecipientChannel);
// Check if this is the notification channel
if (channelClose.RecipientChannel == NOTIFICATION_CHANNEL) { module->NotificationSenderChannel = 0; ILibLMS_clearNotificationData(module); break; }
// Check if we know about this channel
channel = &(module->Sessions[SlotFromChannelId(channelClose.RecipientChannel)]); // Get the current session for this message.
if (channel == NULL) break; // This should never happen, but it does. We get close on channel id 0 all the time.
if (channelClose.RecipientChannel != (unsigned int)(channel->ourid)) { LMSDEBUG("APF_CHANNEL_CLOSE - Channel Mismatch %d != %d\r\n", channelClose.RecipientChannel, channel->ourid); break; }
LMSDEBUG("CLOSE OUR:%d\r\n", channelClose.RecipientChannel);
if (channel->status == LME_CS_CONNECTED)
{
if (ILibAsyncSocket_IsConnected(channel->socketmodule))
{
channel->status = LME_CS_PENDING_AMT_DISCONNECT;
LMSDEBUG("Channel %d now PENDING_AMT_DISCONNECT by AMT, calling microstack disconnect %p\r\n", channel->ourid, channel->socketmodule);
LME_ChannelClose(lmemodule, channel->amtid, channel->ourid);
sem_post(&(module->Lock));
if (channel->sockettype == 0) // If the current socket is PAUSED, lets resume it so data can start flowing again.
{
ILibAsyncSocket_Disconnect(channel->socketmodule); // TCP socket close
}
#ifndef NOLMSCOMMANDER
else
{
ILibWebServer_WebSocket_Close(channel->socketmodule); // Web socket close
}
#endif
sem_wait(&(module->Lock));
channel->status = LME_CS_FREE;
disconnects++;
LMSDEBUG("Channel %d now FREE by AMT\r\n", channel->ourid);
}
else
{
channel->status = LME_CS_FREE;
disconnects++;
LMSDEBUG("Channel %d now FREE by AMT\r\n", channel->ourid);
}
}
else if (channel->status == LME_CS_PENDING_LMS_DISCONNECT)
{
channel->status = LME_CS_FREE;
disconnects++;
LMSDEBUG("Channel %d now FREE by AMT\r\n", channel->ourid);
}
else
{
LMSDEBUG("Channel %d CLOSE, UNEXPECTED STATE %d\r\n", channel->ourid, channel->status);
}
}
break;
case APF_CHANNEL_DATA: // (94) Intel AMT is sending data that we must relay into an LMS TCP connection.
{
struct LMEChannel* channel;
APF_CHANNEL_DATA_MESSAGE *pMessage = (APF_CHANNEL_DATA_MESSAGE *)rxBuffer;
struct LMEChannelDataMessage channelData;
enum ILibAsyncSocket_SendStatus r;
channelData.MessageType = APF_CHANNEL_DATA;
channelData.RecipientChannel = ntohl(pMessage->RecipientChannel);
channelData.DataLength = ntohl(pMessage->DataLength);
channelData.Data = (unsigned char*)rxBuffer + sizeof(APF_CHANNEL_DATA_MESSAGE);
// If this is the notification channel, handle it here
if (channelData.RecipientChannel == NOTIFICATION_CHANNEL) {
if (ILibLMS_processNotificationData(module, channelData.Data, channelData.DataLength) == 0) {
LME_ChannelClose(lmemodule, module->NotificationSenderChannel, NOTIFICATION_CHANNEL); // HTTP completed, close the channel
} else {
LME_ChannelWindowAdjust(lmemodule, module->NotificationSenderChannel, channelData.DataLength);
}
break;
}
// Check if we know this channel
channel = &(module->Sessions[SlotFromChannelId(channelData.RecipientChannel)]);
if (channel == NULL || channel->socketmodule == NULL || channel->status != LME_CS_CONNECTED) { sem_post(&(module->Lock)); break; }
if (channel->sockettype == 0) {
r = ILibAsyncSocket_Send(channel->socketmodule, (char*)(channelData.Data), channelData.DataLength, ILibAsyncSocket_MemoryOwnership_USER); // TCP socket
}
#ifndef NOLMSCOMMANDER
else {
r = ILibWebServer_WebSocket_Send(channel->socketmodule, (char*)(channelData.Data), channelData.DataLength, ILibWebServer_WebSocket_DataType_TEXT, ILibAsyncSocket_MemoryOwnership_USER, ILibWebServer_WebSocket_FragmentFlag_Complete); // Web socket
}
#endif
channel->rxwindow += channelData.DataLength;
if (r == ILibAsyncSocket_ALL_DATA_SENT && channel->rxwindow > 1024) {
LME_ChannelWindowAdjust(lmemodule, channel->amtid, channel->rxwindow); channel->rxwindow = 0;
}
}
break;
case APF_CHANNEL_WINDOW_ADJUST: // 93
{
struct LMEChannel* channel;
APF_WINDOW_ADJUST_MESSAGE *pMessage = (APF_WINDOW_ADJUST_MESSAGE *)rxBuffer;
struct LMEChannelWindowAdjustMessage channelWindowAdjust;
channelWindowAdjust.MessageType = APF_CHANNEL_WINDOW_ADJUST;
channelWindowAdjust.RecipientChannel = ntohl(pMessage->RecipientChannel);
channelWindowAdjust.BytesToAdd = ntohl(pMessage->BytesToAdd);
channel = &(module->Sessions[SlotFromChannelId(channelWindowAdjust.RecipientChannel)]);
if (channel == NULL || channel->status == LME_CS_FREE){
sem_post(&(module->Lock));
break;
}
channel->txwindow += channelWindowAdjust.BytesToAdd;
if (channel->sockettype == 0)
{
ILibAsyncSocket_Resume(channel->socketmodule); // TCP socket
}
#ifndef NOLMSCOMMANDER
else
{
ILibLMS_ResumeWebSocket(channel->socketmodule); // Web socket resume
}
#endif
}
break;
case APF_PROTOCOLVERSION: // 192
{
APF_PROTOCOL_VERSION_MESSAGE *pMessage = (APF_PROTOCOL_VERSION_MESSAGE *)rxBuffer;
struct LMEProtocolVersionMessage protVersion;
protVersion.MajorVersion = ntohl(pMessage->MajorVersion);
protVersion.MinorVersion = ntohl(pMessage->MinorVersion);
protVersion.TriggerReason = (APF_TRIGGER_REASON)ntohl(pMessage->TriggerReason);
switch (module->handshakingStatus)
{
case LME_AGREED:
case LME_NOT_INITIATED:
{
LME_ProtocolVersion(lmemodule, 1, 0, protVersion.TriggerReason);
}
case LME_INITIATED:
if (protVersion.MajorVersion != 1 || protVersion.MinorVersion != 0)
{
LMSDEBUG("LME Version %d.%d is not supported.\r\n", protVersion.MajorVersion, protVersion.MinorVersion);
LME_Disconnect(lmemodule, APF_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED);
LME_Deinit(lmemodule);
sem_post(&(module->Lock));
return;
}
module->AmtProtVersionMajor = protVersion.MajorVersion;
module->AmtProtVersionMinor = protVersion.MinorVersion;
module->handshakingStatus = LME_AGREED;
break;
default:
LME_Disconnect(lmemodule, APF_DISCONNECT_BY_APPLICATION);
LME_Deinit(lmemodule);
break;
}
}
break;
case APF_USERAUTH_REQUEST: // 50
{
//printf("APF_USERAUTH_REQUEST\r\n");
// _lme.UserAuthSuccess();
}
break;
default:
// Unknown request.
//printf("**Unknown LME command: %d\r\n", ((unsigned char*)rxBuffer)[0]);
LMSDEBUG("**Unknown LME command: %d\r\n", ((unsigned char*)rxBuffer)[0]);
LME_Disconnect(lmemodule, APF_DISCONNECT_PROTOCOL_ERROR);
LME_Deinit(lmemodule);
break;
}
sem_post(&(module->Lock));
if (disconnects > 0) ILibLMS_LaunchHoldingSessions(module); // If disconnects is set to anything, we have free session slots we can fill up.
}
void ILibLMS_OnReceive(ILibAsyncServerSocket_ServerModule AsyncServerSocketModule, ILibAsyncServerSocket_ConnectionToken ConnectionToken, char* buffer, int *p_beginPointer, int endPointer, ILibAsyncServerSocket_OnInterrupt *OnInterrupt, void **user, int *PAUSE)
{
int r, maxread = endPointer;
struct ILibLMS_StateModule* module = (struct ILibLMS_StateModule*)ILibAsyncServerSocket_GetTag(AsyncServerSocketModule);
struct LMEChannel* channel = (struct LMEChannel*)*user;
UNREFERENCED_PARAMETER( AsyncServerSocketModule );
UNREFERENCED_PARAMETER( ConnectionToken );
UNREFERENCED_PARAMETER( OnInterrupt );
UNREFERENCED_PARAMETER( PAUSE );
if (channel == NULL) return;
sem_wait(&(module->Lock));
if (channel->socketmodule != ConnectionToken) { sem_post(&(module->Lock)); ILibAsyncSocket_Disconnect(ConnectionToken); return; }
if (channel->txwindow < endPointer) maxread = channel->txwindow;
if (channel->status != LME_CS_CONNECTED || maxread == 0) { *PAUSE = 1; sem_post(&(module->Lock)); return; }
r = LME_ChannelData(&(module->MeConnection), channel->amtid, maxread, (unsigned char*)buffer);
LMSDEBUG("ILibLMS_OnReceive, status = %d, txwindow = %d, endPointer = %d, r = %d\r\n", channel->status, channel->txwindow, endPointer, r);
if (r != maxread)
{
LMSDEBUG("ILibLMS_OnReceive, DISCONNECT %d\r\n", channel->ourid);
sem_post(&(module->Lock));
ILibAsyncSocket_Disconnect(ConnectionToken); // Drop the connection
return;
}
channel->txwindow -= maxread;
*p_beginPointer = maxread;
sem_post(&(module->Lock));
}
void ILibLMS_SetupConnectionTimeout(void *obj)
{
struct LMEChannel* channel = (struct LMEChannel*)obj;
struct ILibLMS_StateModule* module = (struct ILibLMS_StateModule*)channel->parent;
if (module == NULL) return;
sem_wait(&(module->Lock));
module->PendingAmtConnection = 0;
if (channel->errorcount++ >= 10 || channel->status == LME_CS_PENDING_LMS_DISCONNECT)
{
// Fail connection
LMSDEBUG("Connection Timeout - Channel %d now FREE by TIMEOUT, status = %d\r\n", channel->ourid, channel->status);
channel->status = LME_CS_FREE;
sem_post(&(module->Lock));
ILibAsyncSocket_Disconnect(channel->socketmodule);
ILibLMS_LaunchHoldingSessions(module);
return;
}
else
{
// Try again
LMSDEBUG("Connection Timeout - Trying again channel %d, status = %d\r\n", channel->ourid, channel->status);
//printf("Connection Timeout - Trying again channel %d, status = %d\r\n", channel->ourid, channel->status);
ILibLMS_SetupConnection(channel->parent, channel->ourid - LMS_MIN_SESSIONID); // Try the connection again.
}
sem_post(&(module->Lock));
}
void ILibLMS_SetupConnection(struct ILibLMS_StateModule* module, int i)
{
int rport = 0;
char* laddr = NULL;
//char tmp[256];
struct sockaddr_in6 remoteAddress;
if (module->Sessions[i].sockettype == 0)
{
// Fetch the socket remote TCP address
ILibAsyncSocket_GetRemoteInterface(module->Sessions[i].socketmodule, (struct sockaddr*)&remoteAddress);
if (remoteAddress.sin6_family == AF_INET6)
{
//ILibInet_ntop2(&remoteAddress, tmp, 256);
//laddr = tmp;
laddr = "::1"; // TODO: decode this properly into a string
rport = ntohs(remoteAddress.sin6_port);
}
else
{
//ILibInet_ntop2(&remoteAddress, tmp, 256);
//laddr = tmp;
laddr = "127.0.0.1"; // TODO: decode this properly into a string
rport = ntohs(((struct sockaddr_in*)(&remoteAddress))->sin_port);
}
}
else
{
// Fetch the socket remote web socket address
laddr = "127.0.0.1"; // TODO: decode this properly into a string
rport = 123; // TODO: decode the remote port
}
// Add a timer, this will be used to retry the connection if AMT does not respond in time.
ILibLifeTime_AddEx(ILibGetBaseTimer(module->chainLink.ParentChain), &(module->Sessions[i]), 1000, ILibLMS_SetupConnectionTimeout, NULL);
// Setup a new LME session
module->PendingAmtConnection = (i + LMS_MIN_SESSIONID);
LME_ChannelOpenForwardedRequest(&(module->MeConnection), (unsigned int)module->Sessions[i].ourid, laddr, module->Sessions[i].localport, laddr, rport);
LMSDEBUG("ILibLMS_OnReceive, CONNECT, Slot %d, Id %d\r\n", i, module->Sessions[i].ourid);
}
void ILibLMS_LaunchHoldingSessions(struct ILibLMS_StateModule* module)
{
int i, activecount = 0, launchcount;
// If we currently have a pending connection, don't launch any new ones.
if (module->PendingAmtConnection != 0) return;
sem_wait(&(module->Lock));
// Count the number of active sessionsLMSDEBUG
activecount = LMS_MAX_SESSIONS;
for (i = 0; i < LMS_MAX_SESSIONS; i++) { if (module->Sessions[i].status == LME_CS_FREE || module->Sessions[i].status == LME_CS_CONNECTION_WAIT) { activecount--; } }
if (activecount >= LMS_MAX_CONNECTIONS) { sem_post(&(module->Lock)); return; }
launchcount = LMS_MAX_CONNECTIONS - activecount;
if (launchcount > 1) launchcount = 1; // Only launch one at a time
for (i = 0; i < LMS_MAX_SESSIONS; i++)
{
if (module->Sessions[i].status == LME_CS_CONNECTION_WAIT)
{
module->Sessions[i].status = LME_CS_PENDING_CONNECT;
LMSDEBUG("ILibLMS_OnConnect %d (RELEASE)\r\n", i + LMS_MIN_SESSIONID);
//printf("ILibLMS_OnConnect %d (RELEASE)\r\n", i + LMS_MIN_SESSIONID);
ILibLMS_SetupConnection(module, i);
launchcount--;
}
if (launchcount == 0) break;
}
sem_post(&(module->Lock));
}
void ILibLMS_OnConnect(ILibAsyncServerSocket_ServerModule AsyncServerSocketModule, ILibAsyncServerSocket_ConnectionToken ConnectionToken, void **user)
{
int i, activecount = 0;
struct ILibLMS_StateModule* module = (struct ILibLMS_StateModule*)ILibAsyncServerSocket_GetTag(AsyncServerSocketModule);
sem_wait(&(module->Lock));
// Count the number of active sessions
activecount = LMS_MAX_SESSIONS;
for (i = 0; i < LMS_MAX_SESSIONS; i++) {
if (module->Sessions[i].status == LME_CS_FREE || module->Sessions[i].status == LME_CS_CONNECTION_WAIT) {
activecount--;
}
}
// Look for an empty session
if ((i = GetFreeSlot(module)) == -1)
{
sem_post(&(module->Lock));
LMSDEBUG("ILibLMS_OnConnect NO SESSION SLOTS AVAILABLE\r\n");
ILibAsyncSocket_Disconnect(ConnectionToken); // Drop the connection
return;
}
// Clear the channel
memset(&(module->Sessions[i]), 0, sizeof(struct LMEChannel));
module->Sessions[i].parent = module;
module->Sessions[i].amtid = -1;
module->Sessions[i].ourid = (i + LMS_MIN_SESSIONID); // Don't use low number channel ID's
module->Sessions[i].socketmodule = ConnectionToken;
module->Sessions[i].localport = ILibAsyncServerSocket_GetPortNumber(AsyncServerSocketModule);
*user = &(module->Sessions[i]);
LMSDEBUG("New TCP connection using SLOT %d, ID %d\r\n", i, module->Sessions[i].ourid);
if (activecount >= LMS_MAX_CONNECTIONS || module->PendingAmtConnection != 0)
{
module->Sessions[i].status = LME_CS_CONNECTION_WAIT;
LMSDEBUG("ILibLMS_OnConnect %d (HOLDING)\r\n", i);
}
else
{
module->Sessions[i].status = LME_CS_PENDING_CONNECT;
LMSDEBUG("ILibLMS_OnConnect TCP %d\r\n", i + LMS_MIN_SESSIONID);
//printf("ILibLMS_OnConnect TCP %d\r\n", i + LMS_MIN_SESSIONID);
ILibLMS_SetupConnection(module, i);
}
sem_post(&(module->Lock));
}
void ILibLMS_OnDisconnect(ILibAsyncServerSocket_ServerModule AsyncServerSocketModule, ILibAsyncServerSocket_ConnectionToken ConnectionToken, void *user)
{
int disconnects = 0;
struct ILibLMS_StateModule* module = (struct ILibLMS_StateModule*)ILibAsyncServerSocket_GetTag(AsyncServerSocketModule);
struct LMEChannel* channel = (struct LMEChannel*)user;
UNREFERENCED_PARAMETER( ConnectionToken );
sem_wait(&(module->Lock));
if (channel == NULL || channel->socketmodule != ConnectionToken)
{
LMSDEBUG("****ILibLMS_OnDisconnect EXIT\r\n");
sem_post(&(module->Lock));
return;
}
LMSDEBUG("ILibLMS_OnDisconnect, Channel %d, %p\r\n", channel->ourid, ConnectionToken);
if (channel->status == LME_CS_CONNECTED)
{
channel->status = LME_CS_PENDING_LMS_DISCONNECT;
if (channel->amtid!=-1 && !LME_ChannelClose(&(module->MeConnection), channel->amtid, channel->ourid))
{
channel->status = LME_CS_FREE;
disconnects++;
LMSDEBUG("Channel %d now FREE by LMS because of failed close\r\n", channel->ourid);
}
else
{
LMSDEBUG("Channel %d now PENDING_LMS_DISCONNECT by LMS\r\n", channel->ourid);
//LMSDEBUG("LME_ChannelClose OK\r\n");
}
}
else if (channel->status == LME_CS_PENDING_CONNECT)
{
channel->status = LME_CS_PENDING_LMS_DISCONNECT;
LMSDEBUG("Channel %d now PENDING_DISCONNECT by LMS\r\n", channel->ourid);
}
else if (channel->status == LME_CS_CONNECTION_WAIT)
{
channel->status = LME_CS_FREE;
disconnects++;
LMSDEBUG("Channel %d now FREE by LMS\r\n", channel->ourid);
}
LMSDEBUG("ILibLMS_OnDisconnect, DISCONNECT %d, status = %d\r\n", channel->ourid, channel->status);
sem_post(&(module->Lock));
if (disconnects > 0) ILibLMS_LaunchHoldingSessions(module);
}
void ILibLMS_OnSendOK(ILibAsyncServerSocket_ServerModule AsyncServerSocketModule, ILibAsyncServerSocket_ConnectionToken ConnectionToken, void *user)
{
struct ILibLMS_StateModule* module = (struct ILibLMS_StateModule*)ILibAsyncServerSocket_GetTag(AsyncServerSocketModule);
struct LMEChannel* channel = (struct LMEChannel*)user;
UNREFERENCED_PARAMETER( ConnectionToken );
// Ok to send more on this socket, adjust the window
sem_wait(&(module->Lock));
if (channel->rxwindow != 0)
{
LMSDEBUG("LME_ChannelWindowAdjust id=%d, rxwindow=%d\r\n", channel->amtid, channel->rxwindow);
LME_ChannelWindowAdjust(&(module->MeConnection), channel->amtid, channel->rxwindow);
channel->rxwindow = 0;
}
sem_post(&(module->Lock));
}
// Private method called when the chain is destroyed, we want to do our cleanup here
void ILibLMS_Destroy(void *object)
{
struct ILibLMS_StateModule* module = (struct ILibLMS_StateModule*)object;
UNREFERENCED_PARAMETER( object );
sem_wait(&(module->Lock));
ILibLMS_clearNotificationData(module);
LME_Disconnect(&(module->MeConnection), APF_DISCONNECT_BY_APPLICATION);
LME_Exit(&(module->MeConnection));
sem_destroy(&(module->Lock));
if (module->WebDir != NULL) { free(module->WebDir); }
if (IlibExternLMS == module) { IlibExternLMS = NULL; } // Clear the global reference to the the LMS module.
}
#ifndef NOLMSCOMMANDER
void ILibLMS_WebSocketOnSendOK(struct ILibWebServer_Session *sender)
{
struct ILibLMS_StateModule* module = (struct ILibLMS_StateModule*)sender->User;
struct LMEChannel* channel = (struct LMEChannel*)sender->User2;
// Ok to send more on this socket, adjust the window
sem_wait(&(module->Lock));
if (channel->rxwindow != 0)
{
LMSDEBUG("LME_ChannelWindowAdjust id=%d, rxwindow=%d\r\n", channel->amtid, channel->rxwindow);
LME_ChannelWindowAdjust(&(module->MeConnection), channel->amtid, channel->rxwindow);
channel->rxwindow = 0;
}
sem_post(&(module->Lock));
}
void ILibLMS_ResumeWebSocket(struct ILibWebServer_Session *session)
{
struct ILibLMS_StateModule* module = (struct ILibLMS_StateModule*)session->User;
struct LMEChannel* channel = (struct LMEChannel*)session->User2;
LMSDEBUG("ILibLMS_ResumeWebSocket %d, %p\r\n", channel->ourid, channel->socketmodule);
if (channel->pending != NULL)
{
int r, maxread = channel->pendingcount;
if (channel->txwindow < maxread) { maxread = channel->txwindow; }
if (channel->status != LME_CS_CONNECTED || maxread == 0) return;
r = LME_ChannelData(&(module->MeConnection), channel->amtid, maxread, (unsigned char*)(channel->pending + channel->pendingptr));
LMSDEBUG("ILibLMS_OnReceive, status = %d, txwindow = %d, endPointer = %d, r = %d\r\n", channel->status, channel->txwindow, maxread, r);
if (r != maxread) return;
channel->txwindow -= maxread;
if (maxread != channel->pendingcount)
{
// More data still to send
channel->pendingptr += maxread;
channel->pendingcount -= maxread;
}
else
{
// We are done
free(channel->pending);
channel->pending = 0;
channel->pendingcount = 0;
channel->pendingptr = 0;
LMSDEBUG("ILibWebServer_Resume %d, %p\r\n", channel->ourid, channel->socketmodule);
ILibWebServer_Resume(channel->socketmodule); // Web socket resume
}
}
else
{
LMSDEBUG("ILibWebServer_Resume %d, %p\r\n", channel->ourid, channel->socketmodule);
ILibWebServer_Resume(channel->socketmodule); // Web socket resume
}
}
#endif
// Get Intel(R) AMT Version
int ILibLMS_GetAmtVersion()
{
int len;
HECI_VERSION heci_version;
CODE_VERSIONS codeVersions;
// Look for HECI driver
if (heci_Init(NULL, 0) == 0 || heci_GetHeciVersion(NULL, &heci_version) == 0) { return 0; }
// Find the Intel AMT version and use that if possible
if (pthi_GetCodeVersions(&codeVersions) == 0)
{
for (len = 0; len < (int)(codeVersions.VersionsCount); len++)
{
if (strcmp((char*)(codeVersions.Versions[len].Description.String), "AMT") == 0)
{
int xa, xb, xc;
#ifdef WIN32
if (sscanf_s((char*)(codeVersions.Versions[len].Version.String), "%d.%d.%d", &xa, &xb, &xc) == 3)
#else
if (sscanf((char*)(codeVersions.Versions[len].Version.String), "%d.%d.%d", &xa, &xb, &xc) == 3)
#endif
{
return (((unsigned long)xa) << 16) | (((unsigned long)xb) << 8) | ((unsigned long)xc);
}
}
}
}
return 0;
}
// Get Intel(R) AMT information
int ILibLMS_GetMeInformation(char** data, int loginmode)
{
int len, controlmode;
HECI_VERSION heci_version;
CFG_PROVISIONING_MODE provisioningmode;
AMT_PROVISIONING_STATE provisioningstate;
CODE_VERSIONS codeVersions;
AMT_EHBC_STATE ehbcstate = EHBC_STATE_DISABLED;
AMT_BOOLEAN b;
AMT_ANSI_STRING dnsSuffix;
UINT8 DedicatedMac[6];
UINT8 HostMac[6];
AMT_HASH_HANDLES hashHandles;
CERTHASH_ENTRY hashEntry;
unsigned long version = 0;
unsigned int i;
int flags = 0;
int ptr = 0;
// Setup the response
*data = (char*)malloc(24000);
ptr += snprintf(*data + ptr, 24000 - ptr, "{");
// Put login mode if non zero
if (loginmode != 0) { ptr += snprintf(*data + ptr, 24000 - ptr, "\"LoginMode\":%d,", loginmode); }
// Look for HECI driver
if (heci_Init(NULL, 0) == 0 || heci_GetHeciVersion(NULL, &heci_version) == 0) { ptr += snprintf(*data + ptr, 24000 - ptr, "\"Error\":\"init\"}"); return ptr; }
ptr += snprintf(*data + ptr, 24000 - ptr, "\"MeiVersion\":\"%d.%d.%d\",\"Versions\":{", heci_version.major, heci_version.minor, heci_version.hotfix);
// Find the Intel AMT version and use that if possible
if (pthi_GetCodeVersions(&codeVersions) == 0)
{
int first = 1;
for (len = 0; len < (int)(codeVersions.VersionsCount); len++)
{
if (first == 0) { ptr += snprintf(*data + ptr, 24000 - ptr, ","); } else { first = 0; }
ptr += snprintf(*data + ptr, 24000 - ptr, "\"%s\":\"%s\"", (char*)(codeVersions.Versions[len].Description.String), (char*)(codeVersions.Versions[len].Version.String));
if (strcmp((char*)(codeVersions.Versions[len].Description.String), "AMT") == 0)
{
int xa, xb, xc;
#ifdef WIN32
if (sscanf_s((char*)(codeVersions.Versions[len].Version.String), "%d.%d.%d", &xa, &xb, &xc) == 3) { version = (((unsigned long)xa) << 16) | (((unsigned long)xb) << 8) | ((unsigned long)xc); }
#else
if (sscanf((char*)(codeVersions.Versions[len].Version.String), "%d.%d.%d", &xa, &xb, &xc) == 3) { version = (((unsigned long)xa) << 16) | (((unsigned long)xb) << 8) | ((unsigned long)xc); }
#endif
}
}
}
ptr += snprintf(*data + ptr, 24000 - ptr, "},");
// Get provisioning state & mode
pthi_GetProvisioningState(&provisioningstate);
pthi_GetProvisioningMode(&provisioningmode, &b);
// Get EHBC settings
if (version > 0x00080100 && pthi_GetStateEHBC(&ehbcstate) == 0)
{
// Add EHBC flag
if (ehbcstate == 1) flags += 0x00000001; // EHBC enabled
}
// Get current control mode
if (version > 0x00060100 && pthi_GetControlMode(&controlmode) == 0) {
if (controlmode == 1) { flags += 0x00000002; } // Client Control Mode enabled
else if (controlmode == 2) { flags += 0x00000004; } // Admin Control Mode enabled
}
// Get wired MAC addresses
if (pthi_GetMacAddresses(DedicatedMac, HostMac) != 0) { heci_Init(NULL, 0); } // If the call fails, we need to re-initalize HECI in all cases. But this case does happen.
// Get the current DNS suffix
if (pthi_GetDnsSuffix(&dnsSuffix) == 0 && dnsSuffix.Length != 0)
{
ptr += snprintf(*data + ptr, 24000 - ptr, "\"DnsSuffix\":\"%s\",", dnsSuffix.Buffer);
}
// Get OS Hostname, this is used to set the computer name within Intel AMT at activation time.
if (gethostname(ILibScratchPad, sizeof(ILibScratchPad)) == 0)
{
ptr += snprintf(*data + ptr, 24000 - ptr, "\"OsHostname\":\"%s\",", ILibScratchPad);
}
/*
// Get OS FQDN
for (k = 0; k < ComputerNameMax; k++)
{
i = sizeof(ILibScratchPad);
if (GetComputerNameExA(k, ILibScratchPad, &i) != 0)
{
ptr += snprintf(*data + ptr, 24000 - ptr, "\"osname%d\":\"%s\",", k, ILibScratchPad);
}
}
*/
// Enumerate all provisioning hashes
memset(&hashHandles, 0, sizeof(AMT_HASH_HANDLES));
if (pthi_EnumerateHashHandles(&hashHandles) == 0)
{
int first = 1;
ptr += snprintf(*data + ptr, 24000 - ptr, "\"TrustedHashes\":[");
for (i = 0; i < hashHandles.Length; i++)
{
if (pthi_GetCertificateHashEntry(hashHandles.Handles[i], &hashEntry) == 0)
{
int hl = 0;
char hexbuf[500];
char namebuf[500];
if (hashEntry.HashAlgorithm == CERT_HASH_ALGORITHM_MD5) hl = 16;
else if (hashEntry.HashAlgorithm == CERT_HASH_ALGORITHM_SHA1) hl = 20;
else if (hashEntry.HashAlgorithm == CERT_HASH_ALGORITHM_SHA256) hl = 32;
else if (hashEntry.HashAlgorithm == CERT_HASH_ALGORITHM_SHA512) hl = 64;
util_tohex((char*)hashEntry.CertificateHash, hl, hexbuf);
if (first == 0) { ptr += snprintf(*data + ptr, 24000 - ptr, ","); } else { first = 0; }
memcpy_s(namebuf, 500, hashEntry.Name.Buffer, hashEntry.Name.Length);
namebuf[hashEntry.Name.Length] = 0;
ptr += snprintf(*data + ptr, 24000 - ptr, "{\"Active\":%d,\"Default\":%d,\"HashAlgorithm\":%d,\"Name\":\"%s\",\"Hash\":\"%s\"}", hashEntry.IsActive, hashEntry.IsDefault, hashEntry.HashAlgorithm, namebuf, hexbuf);
}
}
ptr += snprintf(*data + ptr, 24000 - ptr, "],");
}
// Encode the command
ptr += snprintf(*data + ptr, 24000 - ptr, "\"Flags\":%d,\"ProvisioningMode\":%d,\"ProvisioningState\":%d}", flags, provisioningmode, provisioningstate);
(*data)[ptr] = 0;
return ptr;
}
#ifndef NOLMSCOMMANDER
// Handle LMS control traffic
void ILibLMS_ProcessLmsControlCommand(struct ILibLMS_StateModule* module, struct ILibWebServer_Session *sender, char* cmd, int cmdlen)
{
int auth = (int)(sender->User5);
unsigned short cmdid = ((unsigned short*)(cmd))[0];
((unsigned short*)(ILibScratchPad2))[0] = cmdid; // Useful for building the response
UNREFERENCED_PARAMETER(module);
UNREFERENCED_PARAMETER(cmdlen);
switch (cmdid) {
case 1: // Request basic Intel AMT information (CMD = 1)
{
char* data;
int len = ILibLMS_GetMeInformation(&data, auth);
ILibWebServer_WebSocket_Send(sender, data, len, ILibWebServer_WebSocket_DataType_BINARY, ILibAsyncSocket_MemoryOwnership_USER, ILibWebServer_WebSocket_FragmentFlag_Complete);
free(data);
break;
}
case 2: // Intel AMT MEI Unprovision (CMD = 2)
{
int mode;
AMT_STATUS status;
if (auth < 2 || heci_Init(NULL, 0) == 0) break; // Admin only
mode = ((int*)(cmd + 2))[0];
status = pthi_Unprovision((CFG_PROVISIONING_MODE)mode); // 1 = Enterprise
((unsigned int*)(ILibScratchPad2 + 2))[0] = status;
ILibWebServer_WebSocket_Send(sender, ILibScratchPad2, 6, ILibWebServer_WebSocket_DataType_BINARY, ILibAsyncSocket_MemoryOwnership_USER, ILibWebServer_WebSocket_FragmentFlag_Complete);
break;
}
case 3: // Intel AMT MEI GetLocalSystemAccount (CMD = 3)
{
AMT_STATUS status;
LOCAL_SYSTEM_ACCOUNT* account = (LOCAL_SYSTEM_ACCOUNT*)(ILibScratchPad2 + 6);
if (auth < 2 || heci_Init(NULL, 0) == 0) break; // Admin only
status = pthi_GetLocalSystemAccount(account);
((unsigned int*)(ILibScratchPad2 + 2))[0] = status;
ILibWebServer_WebSocket_Send(sender, ILibScratchPad2, 6 + sizeof(LOCAL_SYSTEM_ACCOUNT), ILibWebServer_WebSocket_DataType_BINARY, ILibAsyncSocket_MemoryOwnership_USER, ILibWebServer_WebSocket_FragmentFlag_Complete);
break;
}
case 4: // Instruct Intel AMT to start remote configuration (CMD = 4)
{
unsigned int status = pthi_StartConfiguration();
if (auth < 2) break; // Admin only
((unsigned int*)(ILibScratchPad2 + 2))[0] = status;
ILibWebServer_WebSocket_Send(sender, ILibScratchPad2, 6, ILibWebServer_WebSocket_DataType_BINARY, ILibAsyncSocket_MemoryOwnership_USER, ILibWebServer_WebSocket_FragmentFlag_Complete);
break;
}
case 5: // Instruct Intel AMT to stop remote configuration (CMD = 5)
{
unsigned int status = pthi_StopConfiguration();
if (auth < 2) break; // Admin only
((unsigned int*)(ILibScratchPad2 + 2))[0] = status;
ILibWebServer_WebSocket_Send(sender, ILibScratchPad2, 6, ILibWebServer_WebSocket_DataType_BINARY, ILibAsyncSocket_MemoryOwnership_USER, ILibWebServer_WebSocket_FragmentFlag_Complete);
break;
}
case 6: // Instruct Intel AMT connect CIRA (CMD = 6)
{
unsigned int status = pthi_OpenUserInitiatedConnection();
((unsigned int*)(ILibScratchPad2 + 2))[0] = status;
ILibWebServer_WebSocket_Send(sender, ILibScratchPad2, 6, ILibWebServer_WebSocket_DataType_BINARY, ILibAsyncSocket_MemoryOwnership_USER, ILibWebServer_WebSocket_FragmentFlag_Complete);
break;
}
case 7: // Instruct Intel AMT disconnect CIRA (CMD = 7)
{
unsigned int status = pthi_CloseUserInitiatedConnection();
((unsigned int*)(ILibScratchPad2 + 2))[0] = status;
ILibWebServer_WebSocket_Send(sender, ILibScratchPad2, 6, ILibWebServer_WebSocket_DataType_BINARY, ILibAsyncSocket_MemoryOwnership_USER, ILibWebServer_WebSocket_FragmentFlag_Complete);
break;
}
case 8: // Get Intel AMT CIRA State (CMD = 8)
{
AMT_STATUS status;
REMOTE_ACCESS_STATUS *remoteAccessStatus = (REMOTE_ACCESS_STATUS*)(ILibScratchPad2 + 6);
if (heci_Init(NULL, 0) == 0) break;
status = pthi_GetRemoteAccessConnectionStatus(remoteAccessStatus);
((unsigned int*)(ILibScratchPad2 + 2))[0] = status;
ILibWebServer_WebSocket_Send(sender, ILibScratchPad2, 6 + sizeof(REMOTE_ACCESS_STATUS), ILibWebServer_WebSocket_DataType_BINARY, ILibAsyncSocket_MemoryOwnership_USER, ILibWebServer_WebSocket_FragmentFlag_Complete);
break;
}
}
}
#define RESPONSE_HEADER_TEMPLATE_JS "\r\nServer: MicroLMS\r\nCache-Control: max-age=0, no-cache\r\nX-Frame-Options: DENY\r\nContent-Type: text/javascript"
#define RESPONSE_HEADER_TEMPLATE_JSON "\r\nServer: MicroLMS\r\nCache-Control: max-age=0, no-cache\r\nX-Frame-Options: DENY\r\nContent-Type: text/html\r\nContent-Encoding: application/json"
#define RESPONSE_HEADER_TEMPLATE_HTML "\r\nServer: MicroLMS\r\nCache-Control: max-age=0, no-cache\r\nX-Frame-Options: DENY\r\nContent-Type: text/html"
#define RESPONSE_HEADER_TEMPLATE_HTML_GZ "\r\nServer: MicroLMS\r\nCache-Control: max-age=0, no-cache\r\nX-Frame-Options: DENY\r\nContent-Type: text/html\r\nContent-Encoding: gzip"
#define RESPONSE_HEADER_TEMPLATE_HTML_GZ_ETAG "\r\nServer: MicroLMS\r\nCache-Control: max-age=0, no-cache\r\nX-Frame-Options: DENY\r\nContent-Type: text/html\r\nContent-Encoding: gzip\r\nETag: %s"
#define RESPONSE_HEADER_TEMPLATE_TEXT "\r\nServer: MicroLMS\r\nCache-Control: max-age=0, no-cache\r\nX-Frame-Options: DENY\r\nContent-Type: text/plain"
#define RESPONSE_HEADER_TEMPLATE_BIN "\r\nServer: MicroLMS\r\nCache-Control: max-age=0, no-cache\r\nX-Frame-Options: DENY\r\nContent-Type: application/octet-stream"
#define RESPONSE_HEADER_SERVER "\r\nServer: MicroLMS\r\n"
// Perform HTTP digest auth when needed
// Returns: 0 if no login is possible, 1 if it's possible and 2 is logged in.
int ILibLMS_HttpServerPerformDigestAuth(struct ILibWebServer_Session *session)
{
#ifdef WIN32
char* xusername;
char* username = NULL;
int usernamelen, passwordlen;
char* password = NULL;
int r = -1;
usernamelen = ILibLMS_getregistryA("username", &username);
passwordlen = ILibLMS_getregistryA("password", &password);
if (usernamelen == 0 || passwordlen == 0) { r = 0; }
if (r == -1) { if (usernamelen == 1 && username[0] == '*') r = 3; } // If username set to '*', we are always admin
if (r == -1) { if (ILibWebServer_Digest_IsAuthenticated(session, "MicroLMS", 8) == 0) r = 1; }
if (r == -1) { xusername = ILibWebServer_Digest_GetUsername(session); if (xusername == NULL || (int)strnlen_s(xusername, 4096) != usernamelen || strncasecmp(xusername, username, usernamelen) != 0) { r = 1; } }
if (r == -1) { r = (ILibWebServer_Digest_ValidatePassword(session, password, passwordlen) == 1) ? 2 : 1; }
if (username != NULL) free(username);
if (password != NULL) free(password);
return r;
#else
return 0;
#endif
}
// Handles all of the HTTP server requests
void ILibLMS_HttpServerSessionReceiveSink(struct ILibWebServer_Session *sender, int InterruptFlag, struct packetheader *header, char *bodyBuffer, int *beginPointer, int endPointer, ILibWebServer_DoneFlag done)
{
int responseSent = 0;
struct ILibLMS_StateModule* module = (struct ILibLMS_StateModule*)sender->User;
if (header == NULL || InterruptFlag != 0) return;
//MSG("HTTP Server Request: %s %s\r\n", header->Directive, header->DirectiveObj);
//LMSDEBUG("HTTP Server Request: %s %s\r\n", header->Directive, header->DirectiveObj);
// This is the LMS relay web socket, all traffic routed to Intel AMT
if (header->DirectiveObjLength >= 14 && strncasecmp(header->DirectiveObj, "/webrelay.ashx", 14) == 0)
{
// Web socket handeling
switch (ILibWebServer_WebSocket_GetDataType(sender))
{
case ILibWebServer_WebSocket_DataType_TEXT:
case ILibWebServer_WebSocket_DataType_BINARY:
{
struct LMEChannel* channel = (struct LMEChannel*)sender->User2;
if (done == 1)
{
// We got a disconnection, process it
int disconnects = 0;
sem_wait(&(module->Lock));
if (channel == NULL || channel->socketmodule != sender)
{
LMSDEBUG("****ILibLMS_OnDisconnect EXIT\r\n");
sem_post(&(module->Lock));
return;
}
LMSDEBUG("ILibLMS_OnDisconnect, Channel %d, %p\r\n", channel->ourid, sender);
//LMSDEBUG("SOCK CLOSE OUR:%d AMT:%d\r\n", channel->ourid, channel->amtid);
if (channel->status == LME_CS_CONNECTED)
{
channel->status = LME_CS_PENDING_LMS_DISCONNECT;
if (!LME_ChannelClose(&(module->MeConnection), channel->amtid, channel->ourid))
{
LMSDEBUG("LME_ChannelClose FAILED\r\n");
channel->status = LME_CS_FREE;
disconnects++;
LMSDEBUG("Channel %d now FREE by LMS because of failed close\r\n", channel->ourid);
}
else
{
LMSDEBUG("Channel %d now PENDING_LMS_DISCONNECT by LMS\r\n", channel->ourid);
//LMSDEBUG("LME_ChannelClose OK\r\n");
}
}
else if (channel->status == LME_CS_PENDING_CONNECT)
{
channel->status = LME_CS_PENDING_LMS_DISCONNECT;
LMSDEBUG("Channel %d now PENDING_DISCONNECT by LMS\r\n", channel->ourid);
}
else if (channel->status == LME_CS_CONNECTION_WAIT)
{
channel->status = LME_CS_FREE;
disconnects++;
LMSDEBUG("Channel %d now FREE by LMS\r\n", channel->ourid);
}
LMSDEBUG("ILibLMS_OnDisconnect, DISCONNECT %d, status = %d\r\n", channel->ourid, channel->status);
channel->socketmodule = NULL;
sem_post(&(module->Lock));
if (disconnects > 0) ILibLMS_LaunchHoldingSessions(module);
}
else
{
// We got binary data, process it
int r, maxread = endPointer;
if (channel == NULL) return;
sem_wait(&(module->Lock));
if (channel->socketmodule != sender) { sem_post(&(module->Lock)); ILibWebServer_WebSocket_Close(sender); return; }
if (channel->txwindow < endPointer) maxread = channel->txwindow;
if (channel->status != LME_CS_CONNECTED || maxread == 0)
{
// Pause the web socket and stuff the rest of the data from this fragment into a pending buffer
LMSDEBUG("ILibWebServer_Pause %d, %p\r\n", channel->ourid, channel->socketmodule);
ILibWebServer_Pause(sender);
channel->pendingcount = endPointer;
channel->pending = malloc(endPointer);
channel->pendingptr = 0;
memcpy_s(channel->pending, endPointer, bodyBuffer, endPointer);
sem_post(&(module->Lock));
return;
}
r = LME_ChannelData(&(module->MeConnection), channel->amtid, maxread, (unsigned char*)bodyBuffer);
LMSDEBUG("ILibLMS_OnReceive, status = %d, txwindow = %d, endPointer = %d, r = %d\r\n", channel->status, channel->txwindow, endPointer, r);
if (r != maxread)
{
LMSDEBUG("ILibLMS_OnReceive, DISCONNECT %d\r\n", channel->ourid);
sem_post(&(module->Lock));
ILibWebServer_WebSocket_Close(sender); // Drop the connection
return;
}
channel->txwindow -= maxread;
*beginPointer = maxread;
if (maxread != endPointer)
{
// Pause the web socket and stuff the rest of the data from this fragment into a pending buffer
LMSDEBUG("ILibWebServer_Pause %d, %p\r\n", channel->ourid, channel->socketmodule);
ILibWebServer_Pause(sender);
channel->pendingcount = endPointer - maxread;
channel->pending = malloc(endPointer - maxread);
channel->pendingptr = 0;
memcpy_s(channel->pending, endPointer - maxread, bodyBuffer + maxread, channel->pendingcount);
}
sem_post(&(module->Lock));
}
break;
}
case ILibWebServer_WebSocket_DataType_REQUEST:
{
int i, sessionid = -1, activecount = 0;
struct ILibLMS_StateModule* module = (struct ILibLMS_StateModule*)sender->User;
// Cross-site requests are not allowed
if (ILibWebServer_IsCrossSiteRequest(sender) != NULL) {
ILibWebServer_StreamHeader_Raw(sender, 400, "400 - Access Denied", RESPONSE_HEADER_TEMPLATE_HTML, ILibAsyncSocket_MemoryOwnership_STATIC);
ILibWebServer_StreamBody(sender, "400 - Access Denied", 19, ILibAsyncSocket_MemoryOwnership_STATIC, 1);
}
// If this is a websocket request, upgrade it.
if (ILibWebServer_UpgradeWebSocket(sender, 8096) == 1) { ILibWebServer_StreamBody(sender, "404 - File not found", 20, ILibAsyncSocket_MemoryOwnership_STATIC, 1); return; }
// Setup a connection to Guardpost
sender->OnSendOK = &ILibLMS_WebSocketOnSendOK;
sem_wait(&(module->Lock));
// Count the number of active sessions
activecount = LMS_MAX_SESSIONS;
for (i = 0; i < LMS_MAX_SESSIONS; i++) {
if (module->Sessions[i].status == LME_CS_FREE || module->Sessions[i].status == LME_CS_CONNECTION_WAIT) {
activecount--;
}
}
// Look for an empty session
sessionid = GetFreeSlot(module);
if (sessionid == -1)
{
sem_post(&(module->Lock));
LMSDEBUG("ILibLMS_OnConnect NO SESSION SLOTS AVAILABLE\r\n");
ILibWebServer_WebSocket_Close(sender); // Drop the connection
return;
}
i = sessionid;
// Clear the channel
memset(&(module->Sessions[i]), 0, sizeof(struct LMEChannel));
module->Sessions[i].amtid = -1;
module->Sessions[i].ourid = (i + LMS_MIN_SESSIONID); // Don't use low channel ID's
module->Sessions[i].sockettype = 1; // Websocket Type
module->Sessions[i].socketmodule = sender;
module->Sessions[i].localport = 16992; // Use this port, may use 16993 in the future if passed as URL argument.
LMSDEBUG("New websocket connection using SLOT %d, ID %d\r\n", i, module->Sessions[i].ourid);
sender->User2 = &(module->Sessions[i]);
if (activecount >= LMS_MAX_CONNECTIONS || module->PendingAmtConnection != 0)
{
module->Sessions[i].status = LME_CS_CONNECTION_WAIT;
LMSDEBUG("ILibLMS_OnConnect %d (HOLDING)\r\n", i);
}
else
{
module->Sessions[i].status = LME_CS_PENDING_CONNECT;
//printf("ILibLMS_OnConnect WEB %d\r\n", i + LMS_MIN_SESSIONID);
LMSDEBUG("ILibLMS_OnConnect WEB %d\r\n", i + LMS_MIN_SESSIONID);
ILibLMS_SetupConnection(module, i);
}
sem_post(&(module->Lock));
break;
}
case ILibWebServer_WebSocket_DataType_UNKNOWN:
{
// This is a normal HTTP request, don't handle this.
ILibWebServer_StreamBody(sender, "404 - File not found", 20, ILibAsyncSocket_MemoryOwnership_STATIC, 1);
break;
}
}
return;
}
// This is the LMS control channel, used for MEI and other things
if (header->DirectiveObjLength >= 9 && strncasecmp(header->DirectiveObj, "/lms.ashx", 9) == 0)
{
// Web socket handeling
int type = ILibWebServer_WebSocket_GetDataType(sender);
switch (type)
{
case ILibWebServer_WebSocket_DataType_TEXT:
case ILibWebServer_WebSocket_DataType_BINARY:
{
struct ILibLMS_StateModule* module = (struct ILibLMS_StateModule*)sender->User;
//struct LMEChannel* channel = (struct LMEChannel*)sender->User2;
// Web socket disconnection
if (done == 1)
{
//LMSDEBUG("LMS-CTRL: Disconnected.\r\n");
return;
}
// We got data, process it
//LMSDEBUG("LMS-CTRL: Got %d bytes on LMS control socket, traffic echo.\r\n", endPointer);
// Process LMS control command
ILibLMS_ProcessLmsControlCommand(module, sender, bodyBuffer, endPointer);
// Set the beginpointer to the end since we consumed all data.
*beginPointer = endPointer;
break;
}
case ILibWebServer_WebSocket_DataType_REQUEST:
{
// struct ILibLMS_StateModule* module = (struct ILibLMS_StateModule*)sender->User;
// Store the authention state in the web socket session
sender->User5 = ILibLMS_HttpServerPerformDigestAuth(sender);
// Cross-site requests are not allowed
if (ILibWebServer_IsCrossSiteRequest(sender) != NULL) {
ILibWebServer_StreamHeader_Raw(sender, 400, "400 - Access Denied", RESPONSE_HEADER_TEMPLATE_HTML, ILibAsyncSocket_MemoryOwnership_STATIC);
ILibWebServer_StreamBody(sender, "400 - Access Denied", 19, ILibAsyncSocket_MemoryOwnership_STATIC, 1);
}
// If this is a websocket request, upgrade it.
if (ILibWebServer_UpgradeWebSocket(sender, 8096) == 1) { ILibWebServer_StreamBody(sender, "404 - File not found", 20, ILibAsyncSocket_MemoryOwnership_STATIC, 1); return; }
// If we plan on sending lots of data, we will need this. Probably not needed since we are localhost only and data is small.
// sender->OnSendOK = &ILibLMS_CtrlWebSocketOnSendOK;
break;
}
case ILibWebServer_WebSocket_DataType_UNKNOWN:
{
// This is a normal HTTP request, don't handle this.
ILibWebServer_StreamBody(sender, "404 - File not found", 20, ILibAsyncSocket_MemoryOwnership_STATIC, 1);
break;
}
}
return;
}
// If the query is not complete, stop here and wait for the completed body.
if (done != ILibWebServer_DoneFlag_Done) return;
// Cross-site requests are not allowed
if (ILibWebServer_IsCrossSiteRequest(sender) != NULL) {
ILibWebServer_StreamHeader_Raw(sender, 400, "400 - Access Denied", RESPONSE_HEADER_TEMPLATE_HTML, ILibAsyncSocket_MemoryOwnership_STATIC);
ILibWebServer_StreamBody(sender, "400 - Access Denied", 19, ILibAsyncSocket_MemoryOwnership_STATIC, 1);
}
if (header->DirectiveObjLength == 7 && strncasecmp(header->DirectiveObj, "/meinfo", 7) == 0)
{
char* data;
int len = ILibLMS_GetMeInformation(&data, ILibLMS_HttpServerPerformDigestAuth(sender));
ILibWebServer_StreamHeader_Raw(sender, 200, "OK", RESPONSE_HEADER_TEMPLATE_JSON, ILibAsyncSocket_MemoryOwnership_STATIC);
ILibWebServer_StreamBody(sender, data + 2, len - 2, ILibAsyncSocket_MemoryOwnership_USER, 1);
free(data);
responseSent = 1;
}
if (header->DirectiveObjLength == 9 && strncasecmp(header->DirectiveObj, "/channels", 9) == 0)
{
int i, ptr = 0;
ptr += snprintf(ILibScratchPad2 + ptr, sizeof(ILibScratchPad2) - ptr, "<html><head><meta http-equiv=\"refresh\" content=\"1\"></head><body><pre>");
for (i = 0; i < LMS_MAX_SESSIONS; i++)
{
ptr += snprintf(ILibScratchPad2 + ptr, sizeof(ILibScratchPad2) - ptr, "status: %d, ", module->Sessions[i].status);
ptr += snprintf(ILibScratchPad2 + ptr, sizeof(ILibScratchPad2) - ptr, "our: %d, ", module->Sessions[i].ourid);
ptr += snprintf(ILibScratchPad2 + ptr, sizeof(ILibScratchPad2) - ptr, "amt: %d, ", module->Sessions[i].amtid);
ptr += snprintf(ILibScratchPad2 + ptr, sizeof(ILibScratchPad2) - ptr, "type: %d, ", module->Sessions[i].sockettype);
ptr += snprintf(ILibScratchPad2 + ptr, sizeof(ILibScratchPad2) - ptr, "tx: %d, ", module->Sessions[i].txwindow);
ptr += snprintf(ILibScratchPad2 + ptr, sizeof(ILibScratchPad2) - ptr, "rx: %d, ", module->Sessions[i].rxwindow);
ptr += snprintf(ILibScratchPad2 + ptr, sizeof(ILibScratchPad2) - ptr, "port: %d, ", module->Sessions[i].localport);
ptr += snprintf(ILibScratchPad2 + ptr, sizeof(ILibScratchPad2) - ptr, "errors: %d, ", module->Sessions[i].errorcount);
ptr += snprintf(ILibScratchPad2 + ptr, sizeof(ILibScratchPad2) - ptr, "pending: %d, ", module->Sessions[i].pendingcount);
ptr += snprintf(ILibScratchPad2 + ptr, sizeof(ILibScratchPad2) - ptr, "pendingptr: %d\r\n", module->Sessions[i].pendingptr);
}
ptr += snprintf(ILibScratchPad2 + ptr, sizeof(ILibScratchPad2) - ptr, "</pre></body></html>");
ILibWebServer_StreamHeader_Raw(sender, 200, "OK", RESPONSE_HEADER_TEMPLATE_HTML, ILibAsyncSocket_MemoryOwnership_STATIC);
ILibWebServer_StreamBody(sender, ILibScratchPad2, ptr, ILibAsyncSocket_MemoryOwnership_USER, 1);
responseSent = 1;
}
if (responseSent == 0 && module->WebDir != NULL)
{
#if !defined(WIN32)
int i;
#endif
int len = (int)strnlen_s(module->WebDir, sizeof(ILibScratchPad));
//int SessionAuth = 0;
char* HeaderTemplate = RESPONSE_HEADER_TEMPLATE_BIN;
char* tmp;
if (header->DirectiveObjLength == 15 && strncasecmp(header->DirectiveObj, "/authindex.html", 15) == 0 && ILibLMS_HttpServerPerformDigestAuth(sender) == 1) {
// Send authentication required response if the auth page is requested.
ILibWebServer_Digest_SendUnauthorized(sender, "MicroLMS", 8, "<html><head><meta http-equiv='refresh' content='0; url = /index.html' /></head>Authentication failed. <a href='/authindex.html'>Retry here</a>.</html>", 151);
return;
}
memcpy_s(ILibScratchPad, sizeof(ILibScratchPad), module->WebDir, len);
if (header->DirectiveObjLength == 1 || (header->DirectiveObjLength == 11 && strncasecmp(header->DirectiveObj, "/index.html", 11) == 0) || (header->DirectiveObjLength == 15 && strncasecmp(header->DirectiveObj, "/authindex.html", 15) == 0))
{
memcpy_s(ILibScratchPad + len, sizeof(ILibScratchPad), "\\index.html", 11);
len += 11;
}
else
{
memcpy_s(ILibScratchPad + len, sizeof(ILibScratchPad) - len, header->DirectiveObj, header->DirectiveObjLength);
len += header->DirectiveObjLength;
}
ILibScratchPad[len] = 0;
#if !defined(WIN32)
// Replace all "\" for "/" to make this a correct Linux path. Windows does not seem to mind about this.
for (i = 0; i < len; i++) { if (ILibScratchPad[i] == '\\') ILibScratchPad[i] = '/'; }
#endif
// Send normal response
tmp = strrchr(ILibScratchPad, '.');
if (tmp != NULL)
{
// Check the file type
if (strncasecmp(tmp, ".html", 5) == 0) HeaderTemplate = RESPONSE_HEADER_TEMPLATE_HTML;
if (strncasecmp(tmp, ".txt", 4) == 0) HeaderTemplate = RESPONSE_HEADER_TEMPLATE_TEXT;
if (strncasecmp(tmp, ".json", 5) == 0) HeaderTemplate = RESPONSE_HEADER_TEMPLATE_JSON;
if (strncasecmp(tmp, ".js", 3) == 0) HeaderTemplate = RESPONSE_HEADER_TEMPLATE_JS;
if (strncasecmp(tmp, ".gz", 3) == 0) HeaderTemplate = RESPONSE_HEADER_TEMPLATE_HTML_GZ;
// Read the file in the /web folder
tmp = NULL;
len = (int)util_readfile(ILibScratchPad, &tmp, 2000000);
if (len > 0 && tmp != NULL)
{
// Send the matching file in the /web folder
ILibWebServer_StreamHeader_Raw(sender, 200, "200 - OK", HeaderTemplate, ILibAsyncSocket_MemoryOwnership_STATIC);
ILibWebServer_StreamBody(sender, tmp, (int)len, ILibAsyncSocket_MemoryOwnership_CHAIN, 1);
responseSent = 1;
}
}
}
if (responseSent == 0 && ((header->DirectiveObjLength == 1 && strncasecmp(header->DirectiveObj, "/", 1) == 0) || (header->DirectiveObjLength == 11 && strncasecmp(header->DirectiveObj, "/index.html", 11) == 0) || (header->DirectiveObjLength == 15 && strncasecmp(header->DirectiveObj, "/authindex.html", 15) == 0)))
{
char* etag = ILibGetHeaderLine(header, "if-none-match", 13);
if (etag != NULL && strnlen_s(etag, 1024) == strnlen_s(IntelAmtWebApp_etag, 1023) && memcmp(etag, IntelAmtWebApp_etag, strnlen_s(IntelAmtWebApp_etag, 1024)) == 0)
{
// ETag match, send "NOT MODIFIED" response
ILibWebServer_StreamHeader_Raw(sender, 304, "NOT MODIFIED", RESPONSE_HEADER_SERVER, ILibAsyncSocket_MemoryOwnership_STATIC);
ILibWebServer_StreamBody(sender, NULL, 0, ILibAsyncSocket_MemoryOwnership_STATIC, 1);
}
else
{
// Send the built-in web site
char temp[2000];
snprintf(temp, 2000, RESPONSE_HEADER_TEMPLATE_HTML_GZ_ETAG, IntelAmtWebApp_etag);
ILibWebServer_StreamHeader_Raw(sender, 200, "OK", temp, ILibAsyncSocket_MemoryOwnership_USER);
ILibWebServer_StreamBody(sender, (char*)IntelAmtWebApp, sizeof(IntelAmtWebApp), ILibAsyncSocket_MemoryOwnership_STATIC, 1);
}
}
if (responseSent == 0)
{
// Unknown URL, 404 error
ILibWebServer_StreamHeader_Raw(sender, 404, "404 - File not found", RESPONSE_HEADER_TEMPLATE_HTML, ILibAsyncSocket_MemoryOwnership_STATIC);
ILibWebServer_StreamBody(sender, "404 - File not found", 20, ILibAsyncSocket_MemoryOwnership_STATIC, 1);
}
}
// Called when an HTTP session is disconnected.
void ILibLMS_HttpServerSessionDisconnect(struct ILibWebServer_Session *session)
{
UNREFERENCED_PARAMETER(session);
}
// Called when a new HTTP session connects
void ILibLMS_WebServer_OnSession(struct ILibWebServer_Session *SessionToken, void *User)
{
SessionToken->OnReceive = &ILibLMS_HttpServerSessionReceiveSink;
SessionToken->OnDisconnect = &ILibLMS_HttpServerSessionDisconnect;
SessionToken->User = User;
}
#endif
// Create a new MicroLMS module.
void *ILibLMS_CreateEx(void *Chain, char* SelfExe, ILibLMS_OnNotification callback, int extraMemorySize)
{
struct ILibLMS_StateModule *module;
// Allocate the new module
module = ILibMemory_Allocate(sizeof(struct ILibLMS_StateModule), extraMemorySize, NULL, NULL);
// Setup the web folder
if (SelfExe != NULL) {
#if defined(WIN32)
char* tmp = strrchr(SelfExe, '\\');
memcpy_s(ILibScratchPad, sizeof(ILibScratchPad), SelfExe, tmp - SelfExe);
memcpy_s(ILibScratchPad, sizeof(ILibScratchPad) - (tmp - SelfExe) + (tmp - SelfExe), "\\lmsweb", 7);
if ((module->WebDir = (char*)malloc(strnlen_s(ILibScratchPad, sizeof(ILibScratchPad)) + 1)) == NULL) ILIBCRITICALEXIT(254);
memcpy_s(module->WebDir, strnlen_s(ILibScratchPad, sizeof(ILibScratchPad)) + 1, ILibScratchPad, strnlen_s(ILibScratchPad, sizeof(ILibScratchPad)) + 1);
#else
char* tmp = strrchr(SelfExe, '/');
memcpy_s(ILibScratchPad, sizeof(ILibScratchPad), SelfExe, tmp - SelfExe);
memcpy_s(ILibScratchPad + (tmp - SelfExe), sizeof(ILibScratchPad) - (tmp - SelfExe), "/lmsweb", 7);
#endif
}
{
char localName[256] = "\0";
struct hostent* s = NULL;
// Setup MEI normal commands and set the local FQDN
if (heci_Init(NULL, 0) == 0)
{
if (module->WebDir != NULL) { free(module->WebDir); }
free(module);
return NULL;
}
gethostname(localName, sizeof(localName));
s = gethostbyname(localName);
if (s != NULL) pthi_SetHostFQDN(s->h_name);
}
// Setup MEI with LMS interface, if we can't return null
if (LME_Init(&(module->MeConnection), &ILibLMS_MEICallback, module) == 0) {
free(module);
return NULL;
}
// Setup the module
module->chainLink.DestroyHandler = &ILibLMS_Destroy;
module->chainLink.ParentChain = Chain;
module->Callback = callback;
sem_init(&(module->Lock), 0, 1);
// TCP servers
module->Server1 = ILibCreateAsyncServerSocketModule(Chain, LMS_MAX_CONNECTIONS, 16992, 4096, 2, &ILibLMS_OnConnect, &ILibLMS_OnDisconnect, &ILibLMS_OnReceive, NULL, &ILibLMS_OnSendOK);
ILibAsyncServerSocket_SetTag(module->Server1, module);
module->Server2 = ILibCreateAsyncServerSocketModule(Chain, LMS_MAX_CONNECTIONS, 16993, 4096, 2, &ILibLMS_OnConnect, &ILibLMS_OnDisconnect, &ILibLMS_OnReceive, NULL, &ILibLMS_OnSendOK);
ILibAsyncServerSocket_SetTag(module->Server2, module);
#ifndef NOLMSCOMMANDER
// Web Server on port 16994
module->WebServer = ILibWebServer_CreateEx(Chain, 8, 16994, 2, &ILibLMS_WebServer_OnSession, module);
#endif
IlibExternLMS = module; // Set the global reference to the LMS module.
ILibAddToChain(Chain, module); // Add this module to the chain.
return module;
}
#endif