/******************************************************************************* * Copyright (C) 2004-2008 Intel Corp. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * - Neither the name of Intel Corp. nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL Intel Corp. OR THE CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. *******************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "types.h" #include "LMEConnection.h" #include "LMS_if.h" #include "Lock.h" #include "glue.h" #if defined(__sun) || defined(_LINUX) #include #define _strnicmp strncasecmp #endif // __sun || _LINUX #define HECI_IO_TIMEOUT 5000 extern glue plugin; const GUID LMEConnection::_guid = {0x6733a4db, 0x0476, 0x4e7b, {0xb3, 0xaf, 0xbc, 0xfc, 0x29, 0xbe, 0xe7, 0xa7}}; const UINT32 LMEConnection::RX_WINDOW_SIZE = 1024; LMEConnection::LMEConnection(bool verbose) : _reqID(0), _txBuffer(NULL), _rxThread(NULL), _cb(NULL), _cbParam(NULL), _initState(INIT_STATE_DISCONNECTED), _heci(_guid, verbose), _heciCompat(_guidCompat, verbose), _pHeci(NULL) { } LMEConnection::~LMEConnection() { } bool LMEConnection::IsInitialized() { Lock il(_initLock); return ((_initState == INIT_STATE_CONNECTED) ? true : false); } bool LMEConnection::Init(HECICallback cb, void *param) { Lock il(_initLock); if (_initState == INIT_STATE_CONNECTING) { return false; } _initState = INIT_STATE_CONNECTING; _cb = cb; _cbParam = param; if (_heci.Init(LMS_PROCOL_VERSION)) { protocolVer = _heci.GetProtocolVersion(); _pHeci = &_heci; } else if (_heciCompat.Init()) { protocolVer = _heciCompat.GetProtocolVersion(); if (protocolVer > LMS_PROCOL_VERSION_COMPAT) { _heciCompat.Deinit(); _initState = INIT_STATE_DISCONNECTED; return false; } _pHeci = &_heciCompat; } else { _initState = INIT_STATE_DISCONNECTED; return false; } _initState = INIT_STATE_CONNECTED; plugin.version(protocolVer); // launch RX thread _txBuffer = new unsigned char[_pHeci->GetBufferSize()]; _rxThread = new Thread(_rxThreadFunc, this); _rxThread->start(); _threadStartedEvent.wait(); return true; } void LMEConnection::Deinit() { Lock il(_initLock); _initState = INIT_STATE_DISCONNECTED; if (_pHeci != NULL) { _pHeci->Deinit(); _pHeci = NULL; } if (_rxThread != NULL) { delete _rxThread; _rxThread = NULL; } if (_txBuffer != NULL) { delete[] _txBuffer; _txBuffer = NULL; } } bool LMEConnection::Disconnect(APF_DISCONNECT_REASON_CODE reasonCode) { if (!IsInitialized()) { PRINT("State: not connected to HECI.\n"); return false; } unsigned char buf[sizeof(APF_DISCONNECT_MESSAGE)]; APF_DISCONNECT_MESSAGE *disconnectMessage = (APF_DISCONNECT_MESSAGE *)buf; memset(disconnectMessage, 0, sizeof(buf)); disconnectMessage->MessageType = APF_DISCONNECT; disconnectMessage->ReasonCode = htonl(reasonCode); PRINT("Sending disconnect to LME.\n"); int res = _sendMessage(buf, sizeof(buf)); return (res == sizeof(buf)); } bool LMEConnection::ServiceAccept(std::string serviceName) { if (!IsInitialized()) { PRINT("State: not connected to HECI.\n"); return false; } //APF_SERVICE_ACCEPT_MESSAGE //memcpy(pCurrent, "127.0.0.1", APF_STR_SIZE_OF("127.0.0.1")); //pCurrent += APF_STR_SIZE_OF("127.0.0.1"); unsigned char *buf = new unsigned char[sizeof(APF_SERVICE_ACCEPT_MESSAGE) + serviceName.length()]; if (buf == NULL) { PRINT("Failed to allocate memory for ServiceAccept.\n"); return false; } unsigned char *pCurrent = buf; *pCurrent = APF_SERVICE_ACCEPT; ++pCurrent; *((UINT32 *)pCurrent) = htonl(serviceName.size()); pCurrent += 4; memcpy(pCurrent, serviceName.c_str(), serviceName.size()); pCurrent += serviceName.size(); PRINT("Sending service accept to LME: %s\n", serviceName.c_str()); int len = pCurrent - buf; int res = _sendMessage(buf, len); delete [] buf; return (res == len); } bool LMEConnection::UserAuthSuccess() { if (!IsInitialized()) { PRINT("State: not connected to HECI.\n"); return false; } unsigned char buf = APF_USERAUTH_SUCCESS; PRINT("Sending user authentication success to LME.\n"); int res = _sendMessage(&buf, sizeof(buf)); return (res == sizeof(buf)); } bool LMEConnection::ProtocolVersion(const LMEProtocolVersionMessage versionMessage) { if (!IsInitialized()) { PRINT("State: not connected to HECI.\n"); return false; } APF_PROTOCOL_VERSION_MESSAGE protVersion; memset(&protVersion, 0, sizeof(protVersion)); protVersion.MessageType = APF_PROTOCOLVERSION; protVersion.MajorVersion = htonl(versionMessage.MajorVersion); protVersion.MinorVersion = htonl(versionMessage.MinorVersion); protVersion.TriggerReason = htonl(versionMessage.TriggerReason); PRINT("Sending protocol version to LME: %d.%d\n", versionMessage.MajorVersion, versionMessage.MinorVersion); int res = _sendMessage((unsigned char *)&protVersion, sizeof(protVersion)); return (res == sizeof(protVersion)); } bool LMEConnection::TcpForwardReplySuccess(UINT32 port) { if (!IsInitialized()) { PRINT("State: not connected to HECI.\n"); return false; } APF_TCP_FORWARD_REPLY_MESSAGE message; message.MessageType = APF_REQUEST_SUCCESS; message.PortBound = htonl(port); PRINT("Sending TCP forward replay success to LME: Port %d.\n", port); int res = _sendMessage((unsigned char *)&message, sizeof(message)); return (res == sizeof(message)); } bool LMEConnection::TcpForwardReplyFailure() { if (!IsInitialized()) { PRINT("State: not connected to HECI.\n"); return false; } unsigned char buf = APF_REQUEST_FAILURE; PRINT("Sending TCP forward replay failure to LME.\n"); int res = _sendMessage(&buf, sizeof(buf)); return (res == sizeof(buf)); } bool LMEConnection::TcpForwardCancelReplySuccess() { if (!IsInitialized()) { PRINT("State: not connected to HECI.\n"); return false; } unsigned char buf = APF_REQUEST_SUCCESS; PRINT("Sending TCP forward cancel replay success to LME.\n"); int res = _sendMessage(&buf, sizeof(buf)); return (res == sizeof(buf)); } bool LMEConnection::TcpForwardCancelReplyFailure() { if (!IsInitialized()) { PRINT("State: not connected to HECI.\n"); return false; } unsigned char buf = APF_REQUEST_FAILURE; PRINT("Sending TCP forward cancel replay failure to LME.\n"); int res = _sendMessage(&buf, sizeof(buf)); return (res == sizeof(buf)); } bool LMEConnection::ChannelOpenForwardedRequest(UINT32 senderChannel, UINT32 connectedPort, std::string originatorIP, UINT32 originatorPort) { if (!IsInitialized()) { PRINT("State: not connected to HECI.\n"); return false; } unsigned char buf[5 + APF_STR_SIZE_OF(APF_OPEN_CHANNEL_REQUEST_FORWARDED) + 16 + APF_STR_SIZE_OF("127.0.0.1") + 8 + 16 + 4]; unsigned char *pCurrent = buf; if (originatorIP.size() > 16) { return false; } *pCurrent = APF_CHANNEL_OPEN; ++pCurrent; *((UINT32 *)pCurrent) = htonl(APF_STR_SIZE_OF(APF_OPEN_CHANNEL_REQUEST_FORWARDED)); pCurrent += sizeof(UINT32); memcpy(pCurrent, APF_OPEN_CHANNEL_REQUEST_FORWARDED, APF_STR_SIZE_OF(APF_OPEN_CHANNEL_REQUEST_FORWARDED)); pCurrent += APF_STR_SIZE_OF(APF_OPEN_CHANNEL_REQUEST_FORWARDED); *((UINT32 *)pCurrent) = htonl(senderChannel); pCurrent += sizeof(UINT32); *((UINT32 *)pCurrent) = htonl(RX_WINDOW_SIZE); pCurrent += sizeof(UINT32); *((UINT32 *)pCurrent) = 0xFFFFFFFF; pCurrent += sizeof(UINT32); *((UINT32 *)pCurrent) = htonl(APF_STR_SIZE_OF("127.0.0.1")); pCurrent += sizeof(UINT32); memcpy(pCurrent, "127.0.0.1", APF_STR_SIZE_OF("127.0.0.1")); pCurrent += APF_STR_SIZE_OF("127.0.0.1"); *((UINT32 *)pCurrent) = htonl(connectedPort); pCurrent += sizeof(UINT32); *((UINT32 *)pCurrent) = htonl((UINT32)originatorIP.size()); pCurrent += sizeof(UINT32); memcpy(pCurrent, originatorIP.c_str(), originatorIP.size()); pCurrent += originatorIP.size(); *((UINT32 *)pCurrent) = htonl(originatorPort); pCurrent += sizeof(UINT32); PRINT("Sending channel open request to LME. Address: %s, requested port: %d.\n", originatorIP.c_str(), connectedPort); int res = _sendMessage(buf, (int)(pCurrent - buf)); return (res == pCurrent - buf); } bool LMEConnection::ChannelOpenReplaySuccess(UINT32 recipientChannel, UINT32 senderChannel) { if (!IsInitialized()) { PRINT("State: not connected to HECI.\n"); return false; } APF_CHANNEL_OPEN_CONFIRMATION_MESSAGE message; message.MessageType = APF_CHANNEL_OPEN_CONFIRMATION; message.RecipientChannel = htonl(recipientChannel); message.SenderChannel = htonl(senderChannel); message.InitialWindowSize = htonl(RX_WINDOW_SIZE); message.Reserved = 0xFFFFFFFF; PRINT("Sending channel open replay success to LME. Recipient: %d.\n", recipientChannel); int res = _sendMessage((unsigned char *)&message, sizeof(message)); return (res == sizeof(message)); } bool LMEConnection::ChannelOpenReplayFailure(UINT32 recipientChannel, UINT32 reason) { if (!IsInitialized()) { PRINT("State: not connected to HECI.\n"); return false; } APF_CHANNEL_OPEN_FAILURE_MESSAGE message; message.MessageType = APF_CHANNEL_OPEN_FAILURE; message.RecipientChannel = htonl(recipientChannel); message.ReasonCode = htonl(reason); message.Reserved = 0x00000000; message.Reserved2 = 0x00000000; PRINT("Sending channel open replay failure to LME. Recipient: %d, Reason: %d.\n", recipientChannel, reason); int res = _sendMessage((unsigned char *)&message, sizeof(message)); return (res == sizeof(message)); } bool LMEConnection::ChannelClose(UINT32 recipientChannel) { if (!IsInitialized()) { PRINT("State: not connected to HECI.\n"); return false; } APF_CHANNEL_CLOSE_MESSAGE message; message.MessageType = APF_CHANNEL_CLOSE; message.RecipientChannel = htonl(recipientChannel); PRINT("Sending channel close to LME. Recipient: %d.\n", recipientChannel); int res = _sendMessage((unsigned char *)&message, sizeof(message)); return (res == sizeof(message)); } int LMEConnection::ChannelData(UINT32 recipientChannel, UINT32 len, unsigned char *buffer) { if (!IsInitialized()) { PRINT("State: not connected to HECI.\n"); return false; } APF_CHANNEL_DATA_MESSAGE *message; if (len > _heci.GetBufferSize() - sizeof(APF_CHANNEL_DATA_MESSAGE)) { return -1; } message = (APF_CHANNEL_DATA_MESSAGE *)_txBuffer; message->MessageType = APF_CHANNEL_DATA; message->RecipientChannel = htonl(recipientChannel); message->DataLength = htonl(len); memcpy(message->Data, buffer, len); PRINT("Sending %d bytes to recipient channel %d.\n", len, recipientChannel); return _sendMessage((unsigned char *)message, sizeof(APF_CHANNEL_DATA_MESSAGE) + len); } bool LMEConnection::ChannelWindowAdjust(UINT32 recipientChannel, UINT32 len) { if (!IsInitialized()) { PRINT("State: not connected to HECI.\n"); return false; } APF_WINDOW_ADJUST_MESSAGE message; message.MessageType = APF_CHANNEL_WINDOW_ADJUST; message.RecipientChannel = htonl(recipientChannel); message.BytesToAdd = htonl(len); PRINT("Sending Window Adjust with %d bytes to recipient channel %d.\n", len, recipientChannel); int res = _sendMessage((unsigned char *)&message, sizeof(message)); return (res == sizeof(message)); } int LMEConnection::_receiveMessage(unsigned char *buffer, int len) { int result; if (!IsInitialized()) { return -1; } result = _pHeci->ReceiveMessage(buffer, len, WAIT_INFINITE); if (result < 0 && errno == ENOENT) { Lock il(_initLock); _initState = INIT_STATE_DISCONNECTED; } return result; } int LMEConnection::_sendMessage(unsigned char *buffer, int len) { int result; if (!IsInitialized()) { return -1; } _sendMessageLock.acquire(); result = _pHeci->SendMessage(buffer, len, HECI_IO_TIMEOUT); _sendMessageLock.release(); if (result < 0 && errno == ENOENT) { Lock il(_initLock); _initState = INIT_STATE_DISCONNECTED; } return result; } void LMEConnection::_rxThreadFunc(void *param) { LMEConnection *connection = (LMEConnection *)param; try { if (LMS_PROCOL_VERSION == connection->protocolVer) { connection->_doRX(); } else if (LMS_PROCOL_VERSION_COMPAT == connection->protocolVer) { connection->_doRXCompat(); } } catch (...) { PRINT("LMEConnection do RX exception\n"); } pthread_exit(NULL); } bool LMEConnection::_checkMinMsgSize(unsigned char *buf, unsigned int bytesRead) { switch (buf[0]) { case APF_DISCONNECT: if (bytesRead < sizeof(APF_DISCONNECT_MESSAGE)) { return false; } break; case APF_SERVICE_REQUEST: if (bytesRead < sizeof(APF_SERVICE_REQUEST)) { return false; } if (bytesRead < (sizeof(APF_SERVICE_REQUEST) + ntohl(((APF_SERVICE_REQUEST_MESSAGE *)buf)->ServiceNameLength))) { return false; } break; case APF_USERAUTH_REQUEST: if (bytesRead < (3 * sizeof(UINT32))) { return false; } break; case APF_GLOBAL_REQUEST: if (bytesRead < (sizeof(APF_GENERIC_HEADER) + sizeof(UINT8))) { return false; } if (bytesRead < (sizeof(APF_GENERIC_HEADER) + sizeof(UINT8) + ntohl(((APF_GENERIC_HEADER *)buf)->StringLength))) { return false; } break; case APF_CHANNEL_OPEN: if (bytesRead < sizeof(APF_GENERIC_HEADER)) { return false; } if (bytesRead < (sizeof(APF_GENERIC_HEADER) + ntohl(((APF_GENERIC_HEADER *)buf)->StringLength))) { return false; } break; case APF_CHANNEL_OPEN_CONFIRMATION: if (bytesRead < sizeof(APF_CHANNEL_OPEN_CONFIRMATION_MESSAGE)) { return false; } break; case APF_CHANNEL_OPEN_FAILURE: if (bytesRead < sizeof(APF_CHANNEL_OPEN_FAILURE_MESSAGE)) { return false; } break; case APF_CHANNEL_CLOSE: if (bytesRead < sizeof(APF_CHANNEL_CLOSE_MESSAGE)) { return false; } break; case APF_CHANNEL_DATA: if (bytesRead < sizeof(APF_CHANNEL_DATA_MESSAGE)) { return false; } if (bytesRead < (sizeof(APF_CHANNEL_DATA_MESSAGE) + ntohl(((APF_CHANNEL_DATA_MESSAGE *)buf)->DataLength))) { return false; } break; case APF_CHANNEL_WINDOW_ADJUST: if (bytesRead < sizeof(APF_WINDOW_ADJUST_MESSAGE)) { return false; } break; case APF_PROTOCOLVERSION: if (bytesRead < sizeof(APF_PROTOCOL_VERSION_MESSAGE)) { return false; } break; default: return false; } return true; } void LMEConnection::_doRX() { unsigned int bytesRead; int status = 1; _threadStartedEvent.set(); unsigned char *rxBuffer = new unsigned char[_heci.GetBufferSize()]; while (true) { bytesRead = (unsigned int)_receiveMessage(rxBuffer, _heci.GetBufferSize()); if ((int)bytesRead < 0) { PRINT("Error receiving data from HECI\n"); Deinit(); break; } if (bytesRead == 0) { // ERROR continue; } PRINT("Received from LME %d bytes (msg type %02d)\n", bytesRead, rxBuffer[0]); if (!_checkMinMsgSize(rxBuffer, bytesRead)) { PRINT("Error receiving data from HECI\n"); Deinit(); break; } if (plugin.preprocess(rxBuffer, bytesRead) == LMS_DROPPED) { continue; } switch (rxBuffer[0]) { case APF_DISCONNECT: { LMEDisconnectMessage disconnectMessage( (APF_DISCONNECT_REASON_CODE)ntohl( ((APF_DISCONNECT_MESSAGE *)rxBuffer)->ReasonCode)); _cb(_cbParam, &disconnectMessage, sizeof(disconnectMessage), &status); } break; case APF_SERVICE_REQUEST: { APF_SERVICE_REQUEST_MESSAGE *pMessage = (APF_SERVICE_REQUEST_MESSAGE *)rxBuffer; LMEServiceRequestMessage serviceRequestMessage; serviceRequestMessage.ServiceName.append( (char *)(pMessage->ServiceName), ntohl(pMessage->ServiceNameLength)); _cb(_cbParam, &serviceRequestMessage, sizeof(serviceRequestMessage), &status); } break; case APF_USERAUTH_REQUEST: _apfUserAuthRequest(rxBuffer, bytesRead, &status); break; case APF_GLOBAL_REQUEST: _apfGlobalRequest(rxBuffer, bytesRead, &status); break; case APF_CHANNEL_OPEN: _apfChannelOpen(rxBuffer, bytesRead, &status); break; case APF_CHANNEL_OPEN_CONFIRMATION: { APF_CHANNEL_OPEN_CONFIRMATION_MESSAGE *pMessage = (APF_CHANNEL_OPEN_CONFIRMATION_MESSAGE *)rxBuffer; LMEChannelOpenReplaySuccessMessage channelOpenReply; channelOpenReply.RecipientChannel = ntohl(pMessage->RecipientChannel); channelOpenReply.SenderChannel = ntohl(pMessage->SenderChannel); channelOpenReply.InitialWindow = ntohl(pMessage->InitialWindowSize); _cb(_cbParam, &channelOpenReply, sizeof(channelOpenReply), &status); } break; case APF_CHANNEL_OPEN_FAILURE: { APF_CHANNEL_OPEN_FAILURE_MESSAGE *pMessage = (APF_CHANNEL_OPEN_FAILURE_MESSAGE *)rxBuffer; LMEChannelOpenReplayFailureMessage channelOpenReply; channelOpenReply.RecipientChannel = ntohl(pMessage->RecipientChannel); channelOpenReply.ReasonCode = (OPEN_FAILURE_REASON)(ntohl(pMessage->ReasonCode)); _cb(_cbParam, &channelOpenReply, sizeof(channelOpenReply), &status); } break; case APF_CHANNEL_CLOSE: { APF_CHANNEL_CLOSE_MESSAGE *pMessage = (APF_CHANNEL_CLOSE_MESSAGE *)rxBuffer; LMEChannelCloseMessage channelClose; channelClose.RecipientChannel = ntohl(pMessage->RecipientChannel); _cb(_cbParam, &channelClose, sizeof(channelClose), &status); } break; case APF_CHANNEL_DATA: { APF_CHANNEL_DATA_MESSAGE *pMessage = (APF_CHANNEL_DATA_MESSAGE *)rxBuffer; LMEChannelDataMessage channelData(ntohl(pMessage->RecipientChannel), ntohl(pMessage->DataLength), pMessage->Data); _cb(_cbParam, &channelData, sizeof(channelData), &status); } break; case APF_CHANNEL_WINDOW_ADJUST: { APF_WINDOW_ADJUST_MESSAGE *pMessage = (APF_WINDOW_ADJUST_MESSAGE *)rxBuffer; LMEChannelWindowAdjustMessage channelWindowAdjust; channelWindowAdjust.RecipientChannel = ntohl(pMessage->RecipientChannel); channelWindowAdjust.BytesToAdd = ntohl(pMessage->BytesToAdd); _cb(_cbParam, &channelWindowAdjust, sizeof(channelWindowAdjust), &status); } break; case APF_PROTOCOLVERSION: { APF_PROTOCOL_VERSION_MESSAGE *pMessage = (APF_PROTOCOL_VERSION_MESSAGE *)rxBuffer; LMEProtocolVersionMessage protVersion; protVersion.MajorVersion = ntohl(pMessage->MajorVersion); protVersion.MinorVersion = ntohl(pMessage->MinorVersion); protVersion.TriggerReason = (APF_TRIGGER_REASON)ntohl(pMessage->TriggerReason); _cb(_cbParam, &protVersion, sizeof(protVersion), &status); } break; default: // Uknown request. Ignore break; } if (IsInitialized()) { plugin.postprocess(rxBuffer, bytesRead, status); } } if (rxBuffer != NULL) { delete[] rxBuffer; } } void LMEConnection::_apfChannelOpen(unsigned char *rxBuffer, unsigned int bytesRead, int *status) { APF_GENERIC_HEADER *pHeader = (APF_GENERIC_HEADER *)rxBuffer; if (_strnicmp((char *)pHeader->String, APF_OPEN_CHANNEL_REQUEST_DIRECT, APF_STR_SIZE_OF(APF_OPEN_CHANNEL_REQUEST_DIRECT)) == 0) { UINT32 senderChannel = 0; _apfChannelOpenDirect(rxBuffer, bytesRead, &senderChannel, status); if (IsInitialized() && (*status == 1)) { if (plugin.retry(rxBuffer, bytesRead) != LMS_DROPPED) { _apfChannelOpenDirect(rxBuffer, bytesRead, NULL, status); } } if (IsInitialized() && (*status == 1)) { ChannelOpenReplayFailure(senderChannel, OPEN_FAILURE_REASON_CONNECT_FAILED); } } } void LMEConnection::_apfChannelOpenDirect(unsigned char *rxBuffer, unsigned int bytesRead, UINT32 *senderChannel, int *status) { unsigned char *pCurrent; APF_GENERIC_HEADER *pHeader = (APF_GENERIC_HEADER *)rxBuffer; if (bytesRead < sizeof(APF_GENERIC_HEADER) + ntohl(pHeader->StringLength) + 7 + (5 * sizeof(UINT32))) { PRINT("Error receiving data from HECI\n"); Deinit(); return; } pCurrent = rxBuffer + sizeof(APF_GENERIC_HEADER) + APF_STR_SIZE_OF(APF_OPEN_CHANNEL_REQUEST_DIRECT); LMEChannelOpenRequestMessage channelOpenRequest; channelOpenRequest.ChannelType = LMEChannelOpenRequestMessage::DIRECT; channelOpenRequest.SenderChannel = ntohl(*((UINT32 *)pCurrent)); if (senderChannel) { *senderChannel = channelOpenRequest.SenderChannel; } pCurrent += sizeof(UINT32); channelOpenRequest.InitialWindow = ntohl(*((UINT32 *)pCurrent)); pCurrent += 2 * sizeof(UINT32); UINT32 len = ntohl(*((UINT32 *)pCurrent)); pCurrent += sizeof(UINT32); channelOpenRequest.Address.append((char *)pCurrent, len); pCurrent += len; channelOpenRequest.Port = ntohl(*((UINT32 *)pCurrent)); pCurrent += sizeof(UINT32); _cb(_cbParam, &channelOpenRequest, sizeof(channelOpenRequest), status); } void LMEConnection::_apfGlobalRequest(unsigned char *rxBuffer, unsigned int bytesRead, int *status) { unsigned char *pCurrent; APF_GENERIC_HEADER *pHeader = (APF_GENERIC_HEADER *)rxBuffer; if (_strnicmp((char *)pHeader->String, APF_GLOBAL_REQUEST_STR_TCP_FORWARD_REQUEST, APF_STR_SIZE_OF(APF_GLOBAL_REQUEST_STR_TCP_FORWARD_REQUEST)) == 0) { LMETcpForwardRequestMessage tcpForwardRequest; unsigned int hsize = sizeof(APF_GENERIC_HEADER) + APF_STR_SIZE_OF(APF_GLOBAL_REQUEST_STR_TCP_FORWARD_REQUEST) + sizeof(UINT8); pCurrent = rxBuffer + hsize; bytesRead -= hsize; if (bytesRead < sizeof(UINT32)) { PRINT("Error receiving data from HECI\n"); Deinit(); return; } UINT32 len = ntohl(*((UINT32 *)pCurrent)); pCurrent += sizeof(UINT32); if (bytesRead < (sizeof(UINT32) + len + sizeof(UINT32))) { PRINT("Error receiving data from HECI\n"); Deinit(); return; } tcpForwardRequest.Address.append((char *)pCurrent, len); pCurrent += len; tcpForwardRequest.Port = ntohl(*((UINT32 *)pCurrent)); _cb(_cbParam, &tcpForwardRequest, sizeof(tcpForwardRequest), status); } else if (_strnicmp((char *)pHeader->String, APF_GLOBAL_REQUEST_STR_TCP_FORWARD_CANCEL_REQUEST, APF_STR_SIZE_OF(APF_GLOBAL_REQUEST_STR_TCP_FORWARD_CANCEL_REQUEST)) == 0) { LMETcpForwardCancelRequestMessage tcpForwardCancelRequest; unsigned int hsize = sizeof(APF_GENERIC_HEADER) + APF_STR_SIZE_OF(APF_GLOBAL_REQUEST_STR_TCP_FORWARD_CANCEL_REQUEST) + sizeof(UINT8); pCurrent = rxBuffer + hsize; bytesRead -= hsize; if (bytesRead < sizeof(UINT32)) { PRINT("Error receiving data from HECI\n"); Deinit(); return; } UINT32 len = ntohl(*((UINT32 *)pCurrent)); pCurrent += sizeof(UINT32); if (bytesRead < (sizeof(UINT32) + len + sizeof(UINT32))) { PRINT("Error receiving data from HECI\n"); Deinit(); return; } tcpForwardCancelRequest.Address.append((char *)pCurrent, len); pCurrent += len; tcpForwardCancelRequest.Port = ntohl(*((UINT32 *)pCurrent)); _cb(_cbParam, &tcpForwardCancelRequest, sizeof(tcpForwardCancelRequest), status); } else if (_strnicmp((char *)pHeader->String, APF_GLOBAL_REQUEST_STR_UDP_SEND_TO, APF_STR_SIZE_OF(APF_GLOBAL_REQUEST_STR_UDP_SEND_TO)) == 0) { unsigned int hsize = sizeof(APF_GENERIC_HEADER) + APF_STR_SIZE_OF(APF_GLOBAL_REQUEST_STR_UDP_SEND_TO) + sizeof(UINT8); pCurrent = rxBuffer + hsize; bytesRead -= hsize; if (bytesRead < sizeof(UINT32)) { PRINT("Error receiving data from HECI\n"); Deinit(); return; } UINT32 len = ntohl(*((UINT32 *)pCurrent)); pCurrent += sizeof(UINT32); if (bytesRead < (sizeof(UINT32) + len + sizeof(UINT32))) { PRINT("Error receiving data from HECI\n"); Deinit(); return; } bytesRead -= (sizeof(UINT32) + len + sizeof(UINT32)); std::string address; address.append((char *)pCurrent, len); pCurrent += len; UINT32 port = ntohl(*((UINT32 *)pCurrent)); pCurrent += sizeof(UINT32); if (bytesRead < sizeof(UINT32)) { PRINT("Error receiving data from HECI\n"); Deinit(); return; } // Skip Originator IP and Port len = ntohl(*((UINT32 *)pCurrent)); pCurrent += sizeof(UINT32); if (bytesRead < (sizeof(UINT32) + len + sizeof(UINT32))) { PRINT("Error receiving data from HECI\n"); Deinit(); return; } bytesRead -= (sizeof(UINT32) + len + sizeof(UINT32)); pCurrent += len; pCurrent += sizeof(UINT32); if (bytesRead < sizeof(UINT32)) { PRINT("Error receiving data from HECI\n"); Deinit(); return; } // Retrieve Data len = ntohl(*((UINT32 *)pCurrent)); pCurrent += sizeof(UINT32); if (bytesRead < (sizeof(UINT32) + len)) { PRINT("Error receiving data from HECI\n"); Deinit(); return; } LMEUdpSendToMessage udpSendTo(address, port, len, pCurrent); _cb(_cbParam, &udpSendTo, sizeof(udpSendTo), status); } } void LMEConnection::_apfUserAuthRequest(unsigned char *rxBuffer, unsigned int bytesRead, int *status) { unsigned char *pCurrent = rxBuffer; ++pCurrent; LMEUserAuthRequestMessage userAuthRequest; UINT32 len = ntohl(*((UINT32 *)pCurrent)); pCurrent += sizeof(UINT32); if ((bytesRead - (pCurrent - rxBuffer)) < len) { PRINT("Error receiving data from HECI\n"); Deinit(); return; } userAuthRequest.Username.append((char *)pCurrent, len); pCurrent += len; if ((unsigned int)(bytesRead - (pCurrent - rxBuffer)) < sizeof(UINT32)) { PRINT("Error receiving data from HECI\n"); Deinit(); return; } len = ntohl(*((UINT32 *)pCurrent)); pCurrent += sizeof(UINT32); if ((bytesRead - (pCurrent - rxBuffer)) < len) { PRINT("Error receiving data from HECI\n"); Deinit(); return; } userAuthRequest.ServiceName.append((char *)pCurrent, len); pCurrent += len; if ((unsigned int)(bytesRead - (pCurrent - rxBuffer)) < sizeof(UINT32)) { PRINT("Error receiving data from HECI\n"); Deinit(); return; } len = ntohl(*((UINT32 *)pCurrent)); pCurrent += sizeof(UINT32); if ((bytesRead - (pCurrent - rxBuffer)) < len) { PRINT("Error receiving data from HECI\n"); Deinit(); return; } userAuthRequest.MethodName.append((char *)pCurrent, len); pCurrent += len; if (_strnicmp(userAuthRequest.MethodName.c_str(), APF_AUTH_PASSWORD, userAuthRequest.MethodName.size()) == 0) { if ((unsigned int)(bytesRead - (pCurrent - rxBuffer)) < sizeof(UINT32) + 1) { PRINT("Error receiving data from HECI\n"); Deinit(); return; } ++pCurrent; len = ntohl(*((UINT32 *)pCurrent)); pCurrent += sizeof(UINT32); if ((bytesRead - (pCurrent - rxBuffer)) < len) { PRINT("Error receiving data from HECI\n"); Deinit(); return; } AuthPasswordData authData; authData.Password.append((char *)pCurrent, len); pCurrent += len; userAuthRequest.MethodData = &authData; } _cb(_cbParam, &userAuthRequest, sizeof(userAuthRequest), status); } unsigned int LMEConnection::GetHeciBufferSize() const { if (_pHeci == NULL) { return 0; } return _pHeci->GetBufferSize(); }