Merge pull request #1 from open-amt-cloud-toolkit/q2-release
Initial commit.
This commit is contained in:
11
.gitignore
vendored
Normal file
11
.gitignore
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
CMakeCache.txt
|
||||
CMakeFiles
|
||||
CMakeScripts
|
||||
Testing
|
||||
Makefile
|
||||
cmake_install.cmake
|
||||
install_manifest.txt
|
||||
compile_commands.json
|
||||
CTestTestfile.cmake
|
||||
build/
|
||||
.vscode/*
|
76
AMTHIClient/Include/GetControlModeCommand.h
Normal file
76
AMTHIClient/Include/GetControlModeCommand.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/* SPDX-License-Identifier: Apache-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2010-2019 Intel Corporation
|
||||
*/
|
||||
/*++
|
||||
|
||||
@file: GetControlModeCommand.h
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef __GET_CONTROL_MODE_COMMAND_H__
|
||||
#define __GET_CONTROL_MODE_COMMAND_H__
|
||||
|
||||
#include "AMTHICommand.h"
|
||||
#include "MEIparser.h"
|
||||
|
||||
namespace Intel
|
||||
{
|
||||
namespace MEI_Client
|
||||
{
|
||||
namespace AMTHI_Client
|
||||
{
|
||||
struct GET_CONTROL_MODE_RESPONSE
|
||||
{
|
||||
uint32_t ControlMode;
|
||||
|
||||
void parse (std::vector<uint8_t>::const_iterator& itr, const std::vector<uint8_t>::const_iterator end)
|
||||
{
|
||||
Intel::MEI_Client::parseData(*this, itr, end);
|
||||
}
|
||||
};
|
||||
|
||||
class GetControlModeRequest;
|
||||
class GetControlModeCommand : public AMTHICommand
|
||||
{
|
||||
public:
|
||||
|
||||
GetControlModeCommand();
|
||||
virtual ~GetControlModeCommand() {}
|
||||
|
||||
virtual void reTransact();
|
||||
GET_CONTROL_MODE_RESPONSE getResponse();
|
||||
|
||||
private:
|
||||
virtual void parseResponse(const std::vector<uint8_t>& buffer);
|
||||
|
||||
std::shared_ptr<AMTHICommandResponse<GET_CONTROL_MODE_RESPONSE>> m_response;
|
||||
|
||||
static const uint32_t RESPONSE_COMMAND_NUMBER = 0x0480006B;
|
||||
};
|
||||
|
||||
class GetControlModeRequest : public AMTHICommandRequest
|
||||
{
|
||||
public:
|
||||
GetControlModeRequest() {}
|
||||
virtual ~GetControlModeRequest() {}
|
||||
|
||||
private:
|
||||
static const uint32_t REQUEST_COMMAND_NUMBER = 0x0400006B;
|
||||
virtual unsigned int requestHeaderCommandNumber()
|
||||
{
|
||||
//this is the command number (taken from the AMTHI document)
|
||||
return REQUEST_COMMAND_NUMBER;
|
||||
}
|
||||
|
||||
virtual uint32_t requestDataSize()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
virtual std::vector<uint8_t> SerializeData();
|
||||
};
|
||||
} // namespace AMTHI_Client
|
||||
} // namespace MEI_Client
|
||||
} // namespace Intel
|
||||
|
||||
#endif //__GET_CONTROL_MODE_COMMAND_H__
|
51
AMTHIClient/Src/GetControlModeCommand.cpp
Normal file
51
AMTHIClient/Src/GetControlModeCommand.cpp
Normal file
@@ -0,0 +1,51 @@
|
||||
/* SPDX-License-Identifier: Apache-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2010-2019 Intel Corporation
|
||||
*/
|
||||
/*++
|
||||
|
||||
@file: GetControlModeCommand.cpp
|
||||
|
||||
--*/
|
||||
|
||||
#include "GetControlModeCommand.h"
|
||||
#include "StatusCodeDefinitions.h"
|
||||
#include <string.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
using namespace Intel::MEI_Client::AMTHI_Client;
|
||||
|
||||
GetControlModeCommand::GetControlModeCommand()
|
||||
{
|
||||
shared_ptr<MEICommandRequest> tmp(new GetControlModeRequest());
|
||||
m_request = tmp;
|
||||
Transact();
|
||||
}
|
||||
|
||||
void GetControlModeCommand::reTransact()
|
||||
{
|
||||
shared_ptr<MEICommandRequest> tmp(new GetControlModeRequest());
|
||||
m_request = tmp;
|
||||
Transact();
|
||||
}
|
||||
|
||||
GET_CONTROL_MODE_RESPONSE GetControlModeCommand::getResponse()
|
||||
{
|
||||
return m_response->getResponse();
|
||||
}
|
||||
|
||||
void
|
||||
GetControlModeCommand::parseResponse(const vector<uint8_t>& buffer)
|
||||
{
|
||||
shared_ptr<AMTHICommandResponse<GET_CONTROL_MODE_RESPONSE>> tmp(
|
||||
new AMTHICommandResponse<GET_CONTROL_MODE_RESPONSE>(buffer, RESPONSE_COMMAND_NUMBER));
|
||||
m_response = tmp;
|
||||
}
|
||||
|
||||
std::vector<uint8_t>
|
||||
GetControlModeRequest::SerializeData()
|
||||
{
|
||||
vector<uint8_t> output;
|
||||
return output;
|
||||
}
|
131
CMakeLists.txt
Normal file
131
CMakeLists.txt
Normal file
@@ -0,0 +1,131 @@
|
||||
cmake_minimum_required (VERSION 3.1)
|
||||
|
||||
project (rpc VERSION 1.0.0)
|
||||
|
||||
set (CMAKE_CXX_STANDARD 11)
|
||||
|
||||
# RPC version info
|
||||
configure_file(version.h.in
|
||||
version.h)
|
||||
include_directories(${PROJECT_BINARY_DIR})
|
||||
|
||||
# TODO: figure out how to read the LMS version from repo like the main lms CMakeLists.txt
|
||||
set (LMS_VERSION_STRING 1932.0.0.0)
|
||||
|
||||
# Compiler settings [Obtained from CmakeLists.txt for lms]
|
||||
string(APPEND CMAKE_CXX_FLAGS_DEBUG " -DDEBUG -D_DEBUG")
|
||||
string(APPEND CMAKE_C_FLAGS_DEBUG " -DDEBUG -D_DEBUG")
|
||||
|
||||
set (CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
if (UNIX)
|
||||
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -z noexecstack -z relro -z now")
|
||||
set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -z noexecstack -z relro -z now")
|
||||
|
||||
#CMake issue #14983
|
||||
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pie")
|
||||
|
||||
#Secure library usage and secure compile flags
|
||||
add_definitions (-fstack-protector-strong -D_FORTIFY_SOURCE=2 -O2 -Wformat -Wformat-security)
|
||||
add_definitions (-fno-strict-overflow -fno-delete-null-pointer-checks -fwrapv)
|
||||
else (UNIX)
|
||||
add_definitions (/GS /sdl)
|
||||
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /NXCompat /DynamicBase")
|
||||
#add_definitions (/D UNICODE /D _UNICODE)
|
||||
add_definitions (/D UNICODE /D _UNICODE /D_NO_ASYNCRTIMP /D_ASYNCRT_EXPORT /D_NO_PPLXIMP /DWIN32 /DMBCS /D_USRDLL /DCPPREST_EXCLUDE_COMPRESSION /D_WINSOCK_DEPRECATED_NO_WARNINGS)
|
||||
add_compile_options ($<$<CONFIG:Release>:/O2>)
|
||||
add_compile_options (/MT$<$<CONFIG:Debug>:d>)
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
|
||||
endif (UNIX)
|
||||
|
||||
|
||||
# Download and unpack lms at configure time
|
||||
configure_file(lms.cmake.in
|
||||
lms-download/CMakeLists.txt)
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/lms-download )
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} --build .
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/lms-download )
|
||||
|
||||
# Add MEIClient directly to our build. This adds
|
||||
# the following targets: LmsMEIClient and LIBMETEE
|
||||
add_subdirectory(${CMAKE_BINARY_DIR}/lms-src/MEIClient
|
||||
${CMAKE_BINARY_DIR}/lms-build/MEIClient)
|
||||
add_dependencies(LmsMEIClient libmetee)
|
||||
|
||||
|
||||
if (UNIX)
|
||||
|
||||
# Find threads [unix it pthreads]
|
||||
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
|
||||
set(THREADS_PREFER_PTHREAD_FLAG TRUE)
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
# Find Boost
|
||||
find_package(Boost COMPONENTS system REQUIRED)
|
||||
|
||||
# Find OpenSSL
|
||||
find_package(OpenSSL)
|
||||
|
||||
# Download and build CppRestSDK, If GIT_TAG is changed then need to delete cpprestsdk-prefix because UPDATE_COMMAND is set to ""
|
||||
include(ExternalProject)
|
||||
ExternalProject_Add(cpprestsdk
|
||||
GIT_REPOSITORY https://github.com/Microsoft/cpprestsdk.git
|
||||
GIT_TAG v2.10.14
|
||||
CMAKE_ARGS -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=0 -DBUILD_SAMPLES=OFF -DBUILD_TESTS=OFF -DCMAKE_INSTALL_PREFIX=<SOURCE_DIR>/../../install
|
||||
TEST_COMMAND ""
|
||||
UPDATE_COMMAND ""
|
||||
)
|
||||
ExternalProject_Get_Property(cpprestsdk SOURCE_DIR)
|
||||
set(CPPRESTSDK_LIBARIES ${SOURCE_DIR}/../../install/lib/)
|
||||
set(CPPRESTSDK_INCLUDE_DIR ${SOURCE_DIR}/../../install/include/)
|
||||
|
||||
add_library(cpprest INTERFACE)
|
||||
target_link_libraries(cpprest INTERFACE ${CPPRESTSDK_LIBARIES}/libcpprest.a OpenSSL::SSL OpenSSL::Crypto ${Boost_LIBRARIES} Threads::Threads)
|
||||
target_include_directories(cpprest INTERFACE ${CPPRESTSDK_INCLUDE_DIR})
|
||||
|
||||
else (UNIX)
|
||||
|
||||
# CppRestSDK
|
||||
find_package(cpprestsdk CONFIG REQUIRED)
|
||||
|
||||
endif (UNIX)
|
||||
|
||||
# ccu-poc
|
||||
add_executable (rpc
|
||||
AMTHIClient/Include/GetControlModeCommand.h
|
||||
AMTHIClient/Src/GetControlModeCommand.cpp
|
||||
commands.h
|
||||
commands.cpp
|
||||
lms.h
|
||||
lms.cpp
|
||||
main.cpp
|
||||
)
|
||||
|
||||
target_include_directories(rpc PUBLIC
|
||||
"AMTHIClient/Include/"
|
||||
)
|
||||
|
||||
if (UNIX)
|
||||
|
||||
add_dependencies(rpc cpprestsdk)
|
||||
|
||||
target_link_libraries (rpc PRIVATE
|
||||
LmsMEIClient
|
||||
cpprest
|
||||
)
|
||||
|
||||
else (UNIX)
|
||||
|
||||
target_link_libraries (rpc PRIVATE
|
||||
LmsMEIClient
|
||||
iphlpapi
|
||||
cpprestsdk::cpprest
|
||||
cpprestsdk::cpprestsdk_zlib_internal
|
||||
cpprestsdk::cpprestsdk_boost_internal
|
||||
cpprestsdk::cpprestsdk_brotli_internal
|
||||
${Boost_LIBRARIES}
|
||||
)
|
||||
|
||||
endif (UNIX)
|
67
README.md
67
README.md
@@ -1 +1,66 @@
|
||||
# rpc
|
||||
# Remote Provisioning Client (RPC)
|
||||
|
||||
RPC is an application which enables remote capabilities for AMT, such as as device activation. To accomplish this, RPC communicates with the RPS (Remote Provisioning Server).
|
||||
|
||||
As a prerequisite, a Local Management Service (LMS) must be installed and running on the operating system.
|
||||
|
||||
## Linux
|
||||
|
||||
Steps below are for Ubuntu 18.04.
|
||||
|
||||
### Dependencies
|
||||
|
||||
- sudo apt install git cmake build-essential libboost-system-dev libboost-thread-dev libboost-random-dev libboost-regex-dev libboost-filesystem-dev libssl-dev zlib1g-dev
|
||||
|
||||
### Build
|
||||
|
||||
- mkdir build
|
||||
- cd build
|
||||
- cmake -DCMAKE_BUILD_TYPE=Release ..
|
||||
- Build debug: cmake -DCMAKE_BUILD_TYPE=Debug ..
|
||||
- cmake --build .
|
||||
|
||||
### Run
|
||||
|
||||
- See ./rpc --help for details.
|
||||
- Example
|
||||
- sudo ./rpc --url wss://localhost:8080 --profile profile1
|
||||
|
||||
## Windows
|
||||
|
||||
Steps below are for Windows 10 and Visual Studio 2019 Professional.
|
||||
|
||||
### Build VCPKG
|
||||
|
||||
Open an x64 native command prompt for Visual Studio 2019 as Administrator.
|
||||
|
||||
- git clone --branch 2020.01 https://github.com/microsoft/vcpkg.git
|
||||
- cd vcpkg
|
||||
- bootstrap-vcpkg.bat
|
||||
- vcpkg integrate install
|
||||
|
||||
### Build C++ REST SDK
|
||||
|
||||
Open an x64 native tools command prompt for Visual Studio 2019.
|
||||
|
||||
- cd vcpkg
|
||||
- vcpkg install cpprestsdk:x64-windows-static
|
||||
|
||||
### Build
|
||||
|
||||
Open an x64 native tools command prompt for Visual Studio 2019.
|
||||
|
||||
- mkdir build
|
||||
- cd build
|
||||
- cmake .. -DVCPKG_TARGET_TRIPLET=x64-windows-static -DCMAKE_TOOLCHAIN_FILE=/vcpkg/scripts/buildsystems/vcpkg.cmake
|
||||
- cmake --build . --config Release
|
||||
- Build debug: cmake --build . --config Debug
|
||||
|
||||
### Run
|
||||
|
||||
Open a command prompt as Administrator.
|
||||
|
||||
- See rpc.exe --help for details.
|
||||
- Example
|
||||
- cd build\Release
|
||||
- rpc.exe --url wss://localhost:8080 --profile profile1
|
||||
|
499
commands.cpp
Normal file
499
commands.cpp
Normal file
@@ -0,0 +1,499 @@
|
||||
/*
|
||||
Copyright 2019 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.
|
||||
*/
|
||||
|
||||
#include "commands.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <boost/asio.hpp>
|
||||
#include <winsock2.h>
|
||||
#include <iphlpapi.h>
|
||||
#endif
|
||||
|
||||
#include "AMTHICommand.h"
|
||||
#include "MEIClientException.h"
|
||||
#include "GetUUIDCommand.h"
|
||||
#include "GetLocalSystemAccountCommand.h"
|
||||
#include "GetCodeVersionCommand.h"
|
||||
#include "GetControlModeCommand.h"
|
||||
#include "GetProvisioningStateCommand.h"
|
||||
#include "GetDNSSuffixCommand.h"
|
||||
#include "GetLanInterfaceSettingsCommand.h"
|
||||
#include "GetCertificateHashEntryCommand.h"
|
||||
#include "EnumerateHashHandlesCommand.h"
|
||||
#include "MEIparser.h"
|
||||
#include "version.h"
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#include <cpprest/ws_client.h>
|
||||
#include <cpprest/json.h>
|
||||
#include <cpprest/streams.h>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include "lms.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace Intel::MEI_Client::AMTHI_Client;
|
||||
using namespace web::websockets::client;
|
||||
using namespace web;
|
||||
|
||||
#define WORKING_BUFFER_SIZE 15000
|
||||
#define MAX_TRIES 3
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
std::string getDNSFromMAC(char *macAddress)
|
||||
{
|
||||
std::string dnsSuffix = "";
|
||||
char dns[256];
|
||||
memset(dns, 0, 256);
|
||||
|
||||
PIP_ADAPTER_ADDRESSES pAddresses = NULL;
|
||||
DWORD dwSize = 0;
|
||||
DWORD dwRetVal = 0;
|
||||
ULONG outBufLen = 0;
|
||||
ULONG Iterations = 0;
|
||||
outBufLen = WORKING_BUFFER_SIZE;
|
||||
|
||||
// get info for all adapters
|
||||
do {
|
||||
|
||||
pAddresses = (IP_ADAPTER_ADDRESSES *) malloc(outBufLen);
|
||||
if (pAddresses == NULL) {
|
||||
cout << "dns memory error" << std::endl;
|
||||
return dnsSuffix;
|
||||
}
|
||||
|
||||
dwRetVal = GetAdaptersAddresses(AF_INET, GAA_FLAG_INCLUDE_PREFIX, NULL, pAddresses, &outBufLen);
|
||||
|
||||
if (dwRetVal == ERROR_BUFFER_OVERFLOW)
|
||||
{
|
||||
free(pAddresses);
|
||||
pAddresses = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
Iterations++;
|
||||
|
||||
} while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (Iterations < MAX_TRIES));
|
||||
|
||||
// get DNS from MAC
|
||||
PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL;
|
||||
pCurrAddresses = pAddresses;
|
||||
while (pCurrAddresses)
|
||||
{
|
||||
if (pCurrAddresses->PhysicalAddressLength != 0)
|
||||
{
|
||||
if (memcmp(macAddress, (char *) pCurrAddresses->PhysicalAddress, 6) == 0)
|
||||
{
|
||||
if (wcslen(pCurrAddresses->DnsSuffix) > 0)
|
||||
{
|
||||
snprintf(dns, 256, "%ws", pCurrAddresses->DnsSuffix );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pCurrAddresses = pCurrAddresses->Next;
|
||||
}
|
||||
|
||||
dnsSuffix = dns;
|
||||
|
||||
return dnsSuffix;
|
||||
}
|
||||
|
||||
#else
|
||||
std::string getDNSFromMAC(char *macAddress)
|
||||
{
|
||||
std::string dnsSuffix = "";
|
||||
|
||||
// get socket
|
||||
SOCKET s = 0;
|
||||
s = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
if (s < 0)
|
||||
{
|
||||
cout << "couldn't get socket" << endl;
|
||||
return dnsSuffix;
|
||||
}
|
||||
|
||||
// get info for all adapters
|
||||
struct ifconf ifc;
|
||||
memset(&ifc, 0, sizeof(ifconf));
|
||||
char buffer[8192];
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
|
||||
ifc.ifc_buf = buffer;
|
||||
ifc.ifc_len = sizeof(buffer);
|
||||
if(ioctl(s, SIOCGIFCONF, &ifc) < 0)
|
||||
{
|
||||
cout << "ioctl SIOCGIFCONF failed" << endl;
|
||||
return dnsSuffix;
|
||||
}
|
||||
|
||||
// get DNS from IP associated with MAC
|
||||
struct ifreq *ifr = ifc.ifc_req;
|
||||
int interfaceCount = ifc.ifc_len / sizeof(struct ifreq);
|
||||
|
||||
char ip[INET6_ADDRSTRLEN] = {0};
|
||||
struct ifreq *item;
|
||||
struct sockaddr *addr;
|
||||
for(int i = 0; i < interfaceCount; i++)
|
||||
{
|
||||
item = &ifr[i];
|
||||
addr = &(item->ifr_addr);
|
||||
|
||||
// get IP address
|
||||
if(ioctl(s, SIOCGIFADDR, item) < 0)
|
||||
{
|
||||
cout << "ioctl SIOCGIFADDR failed" << endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (inet_ntop(AF_INET, &( ((struct sockaddr_in *)addr)->sin_addr ),
|
||||
ip, sizeof(ip) ) == NULL)
|
||||
{
|
||||
cout << "inet_ntop" << endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
// get MAC address
|
||||
if(ioctl(s, SIOCGIFHWADDR, item) < 0)
|
||||
{
|
||||
cout << "ioctl SIOCGIFHWADDR failed" << endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (memcmp(macAddress, (char *) item->ifr_hwaddr.sa_data, 6) == 0)
|
||||
{
|
||||
// Get host by using the IP address which AMT device is using
|
||||
struct in_addr addr = {0};
|
||||
struct hostent *host;
|
||||
addr.s_addr = inet_addr(ip);
|
||||
host = gethostbyaddr((char *)&addr, 4, AF_INET);
|
||||
if (host == NULL)
|
||||
{
|
||||
cout << "gethostbyaddr() failed";
|
||||
return dnsSuffix;
|
||||
}
|
||||
|
||||
// strip off the hostname to get actual domain name
|
||||
int domainNameSize = 256;
|
||||
char domainName[domainNameSize];
|
||||
memset(domainName, 0, domainNameSize);
|
||||
|
||||
char *dn = strchr(host->h_name, '.');
|
||||
if (dn != NULL)
|
||||
{
|
||||
if (domainNameSize >= strlen(dn + 1))
|
||||
{
|
||||
snprintf(domainName, domainNameSize, "%s", ++dn);
|
||||
|
||||
dnsSuffix = domainName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dnsSuffix;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
json::value getCertificateHashes()
|
||||
{
|
||||
json::value certHashes;
|
||||
vector<json::value> hashValues;
|
||||
|
||||
// get the hash handles
|
||||
EnumerateHashHandlesCommand command;
|
||||
ENUMERATE_HASH_HANDLES_RESPONSE response = command.getResponse();
|
||||
|
||||
vector<unsigned int>::iterator itr = response.HashHandles.begin();
|
||||
vector<unsigned int>::iterator endItr = response.HashHandles.end();
|
||||
for (; itr != endItr; ++itr)
|
||||
{
|
||||
// get each entry
|
||||
GetCertificateHashEntryCommand command(*itr);
|
||||
GET_CERTIFICATE_HASH_ENTRY_RESPONSE response = command.getResponse();
|
||||
|
||||
int hashSize;
|
||||
switch (response.HashAlgorithm) {
|
||||
case 0: // MD5
|
||||
hashSize = 16;
|
||||
break;
|
||||
case 1: // SHA1
|
||||
hashSize = 20;
|
||||
break;
|
||||
case 2: // SHA256
|
||||
hashSize = 32;
|
||||
break;
|
||||
case 3: // SHA512
|
||||
hashSize = 64;
|
||||
break;
|
||||
default:
|
||||
hashSize = 64;
|
||||
break;
|
||||
}
|
||||
|
||||
if (response.IsActive == 1) {
|
||||
string hashString;
|
||||
hashString.clear();
|
||||
for (int i = 0; i < hashSize; i++)
|
||||
{
|
||||
char hex[10];
|
||||
snprintf(hex, 10, "%02x", response.CertificateHash[i]);
|
||||
hashString += hex;
|
||||
}
|
||||
|
||||
hashValues.push_back( json::value::string( utility::conversions::convertstring(hashString) ) );
|
||||
}
|
||||
}
|
||||
|
||||
return json::value::array(hashValues);
|
||||
}
|
||||
|
||||
std::string getDNSInfo()
|
||||
{
|
||||
std::string dnsSuffix;
|
||||
|
||||
// Get interface info which AMT is using. We don't worry about wireless since
|
||||
// only wired used for configuration
|
||||
GetLanInterfaceSettingsCommand getLanInterfaceSettingsCommandWired(Intel::MEI_Client::AMTHI_Client::WIRED);
|
||||
LAN_SETTINGS lanSettings = getLanInterfaceSettingsCommandWired.getResponse();
|
||||
|
||||
if (!lanSettings.Enabled)
|
||||
{
|
||||
cout << "error: no wired AMT interfaces enabled" << endl;
|
||||
return "";
|
||||
}
|
||||
|
||||
// Get DNS according to AMT
|
||||
GetDNSSuffixCommand getDnsSuffixCommand;
|
||||
dnsSuffix = getDnsSuffixCommand.getResponse();
|
||||
|
||||
// get DNS from OS
|
||||
if (!dnsSuffix.length())
|
||||
{
|
||||
dnsSuffix = getDNSFromMAC((char *)&lanSettings.MacAddress);
|
||||
}
|
||||
|
||||
return dnsSuffix;
|
||||
}
|
||||
|
||||
|
||||
string getActivateInfo(string profile)
|
||||
{
|
||||
utility::string_t tmp;
|
||||
|
||||
// Activation parameters
|
||||
json::value activationParams;
|
||||
|
||||
// Get code version
|
||||
GetCodeVersionCommand codeVersionCommand;
|
||||
CODE_VERSIONS codeVersion = codeVersionCommand.getResponse();
|
||||
|
||||
// Additional versions
|
||||
// UINT8[16] UUID;
|
||||
// AMT_VERSION_TYPE Version and Description are std::string.
|
||||
for (vector<AMT_VERSION_TYPE>::iterator it = codeVersion.Versions.begin(); it != codeVersion.Versions.end(); it++)
|
||||
{
|
||||
if (boost::iequals(it->Description, "AMT"))
|
||||
{
|
||||
tmp = utility::conversions::convertstring(it->Version);
|
||||
activationParams[U("ver")] = json::value::string(tmp);
|
||||
}
|
||||
else if (boost::iequals(it->Description, "Build Number"))
|
||||
{
|
||||
tmp = utility::conversions::convertstring(it->Version);
|
||||
activationParams[U("build")] = json::value::string(tmp);
|
||||
}
|
||||
else if (boost::iequals(it->Description, "Sku"))
|
||||
{
|
||||
tmp = utility::conversions::convertstring(it->Version);
|
||||
activationParams[U("sku")] = json::value::string(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
// Get UUID
|
||||
GetUUIDCommand get;
|
||||
GET_UUID_RESPONSE res = get.getResponse();
|
||||
std::vector<json::value> UUID;
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
UUID.push_back(json::value(res.UUID[i]));
|
||||
}
|
||||
activationParams[U("uuid")] = json::value::array(UUID);
|
||||
|
||||
// Get local system account
|
||||
// User name in ASCII char-set. The string is NULL terminated. CFG_MAX_ACL_USER_LENGTH is 33
|
||||
// Password in ASCII char set. From AMT 6.1 this field is in BASE64 format. The string is NULL terminated.
|
||||
GetLocalSystemAccountCommand sac;
|
||||
tmp = utility::conversions::convertstring(sac.getResponse().UserName);
|
||||
activationParams[U("username")] = json::value::string(tmp);
|
||||
tmp = utility::conversions::convertstring(sac.getResponse().Password);
|
||||
activationParams[U("password")] = json::value::string(tmp);
|
||||
|
||||
// Get Control Mode
|
||||
GetControlModeCommand controlModeCommand;
|
||||
GET_CONTROL_MODE_RESPONSE controlMode = controlModeCommand.getResponse();
|
||||
activationParams[U("currentMode")] = json::value::number(controlMode.ControlMode);
|
||||
|
||||
// Get DNS Info
|
||||
tmp = utility::conversions::convertstring("");
|
||||
string dnsSuffix = getDNSInfo();
|
||||
|
||||
if (dnsSuffix.length())
|
||||
{
|
||||
tmp = utility::conversions::convertstring(dnsSuffix);
|
||||
}
|
||||
|
||||
activationParams[U("fqdn")] = json::value::string(tmp);
|
||||
|
||||
tmp = utility::conversions::convertstring("PPC");
|
||||
activationParams[U("client")] = json::value::string(tmp);
|
||||
|
||||
tmp = utility::conversions::convertstring(profile);
|
||||
activationParams[U("profile")] = json::value::string(tmp);
|
||||
|
||||
// Get certificate hashes
|
||||
activationParams[U("certHashes")] = getCertificateHashes();
|
||||
|
||||
// Return serialized parameters in base64
|
||||
string serializedParams = utility::conversions::to_utf8string(activationParams.serialize());
|
||||
#ifdef DEBUG
|
||||
cout << "Activation info payload:" << serializedParams << std::endl;
|
||||
#endif
|
||||
|
||||
return encodeBase64(serializedParams);
|
||||
}
|
||||
|
||||
string encodeBase64(string str)
|
||||
{
|
||||
std::vector<unsigned char> strVector(str.begin(), str.end());
|
||||
utility::string_t base64 = utility::conversions::to_base64(strVector);
|
||||
string encodedString = utility::conversions::to_utf8string(base64);
|
||||
|
||||
return encodedString;
|
||||
}
|
||||
|
||||
string decodeBase64(string str)
|
||||
{
|
||||
utility::string_t serializedData = utility::conversions::to_string_t(str);
|
||||
std::vector<unsigned char> strVector = utility::conversions::from_base64(serializedData);
|
||||
string decodedString(strVector.begin(), strVector.end());
|
||||
|
||||
return decodedString;
|
||||
}
|
||||
|
||||
string createActivationRequest(string profile)
|
||||
{
|
||||
// Activation parameters
|
||||
json::value request;
|
||||
|
||||
// placeholder stuff; will likely change
|
||||
utility::string_t tmp = utility::conversions::convertstring("activation");
|
||||
request[U("method")] = json::value::string(tmp);
|
||||
|
||||
tmp = utility::conversions::convertstring("key");
|
||||
request[U("apiKey")] = json::value::string(tmp);
|
||||
|
||||
tmp = utility::conversions::convertstring(PROJECT_VER);
|
||||
request[U("appVersion")] = json::value::string(tmp);
|
||||
|
||||
tmp = utility::conversions::convertstring(PROTOCOL_VERSION);
|
||||
request[U("protocolVersion")] = json::value::string(tmp);
|
||||
|
||||
tmp = utility::conversions::convertstring("ok");
|
||||
request[U("status")] = json::value::string(tmp);
|
||||
|
||||
tmp = utility::conversions::convertstring("all\'s good!");
|
||||
request[U("message")] = json::value::string(tmp);
|
||||
|
||||
// payload
|
||||
string activationInfo = getActivateInfo(profile);
|
||||
utility::string_t payload = utility::conversions::to_string_t(activationInfo);
|
||||
|
||||
request[U("payload")] = json::value::string(payload);
|
||||
|
||||
return utility::conversions::to_utf8string(request.serialize());
|
||||
}
|
||||
|
||||
string createResponse(string payload)
|
||||
{
|
||||
// Activation parameters
|
||||
json::value response;
|
||||
|
||||
// placeholder stuff; will likely change
|
||||
utility::string_t tmp = utility::conversions::convertstring("response");
|
||||
response[U("method")] = json::value::string(tmp);
|
||||
|
||||
tmp = utility::conversions::convertstring("key");
|
||||
response[U("apiKey")] = json::value::string(tmp);
|
||||
|
||||
tmp = utility::conversions::convertstring(PROJECT_VER);
|
||||
response[U("appVersion")] = json::value::string(tmp);
|
||||
|
||||
tmp = utility::conversions::convertstring(PROTOCOL_VERSION);
|
||||
response[U("protocolVersion")] = json::value::string(tmp);
|
||||
|
||||
tmp = utility::conversions::convertstring("ok");
|
||||
response[U("status")] = json::value::string(tmp);
|
||||
|
||||
tmp = utility::conversions::convertstring("all\'s good!");
|
||||
response[U("message")] = json::value::string(tmp);
|
||||
|
||||
// payload
|
||||
tmp = utility::conversions::convertstring( encodeBase64(payload) );
|
||||
response[U("payload")] = json::value::string(tmp);
|
||||
|
||||
return utility::conversions::to_utf8string(response.serialize());
|
||||
}
|
||||
|
||||
void dumpMessage(utility::string_t tmp)
|
||||
{
|
||||
web::json::value parsed = web::json::value::parse(tmp);
|
||||
|
||||
if ( !parsed.has_field(U("method")) || !parsed.has_field(U("apiKey")) || !parsed.has_field(U("appVersion")) ||
|
||||
!parsed.has_field(U("protocolVersion")) || !parsed.has_field(U("status")) || !parsed.has_field(U("message")) ||
|
||||
!parsed.has_field(U("payload")) ) {
|
||||
cout << "error: dumpMessage message is empty" << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
utility::string_t out = parsed[U("method")].as_string();
|
||||
cout << "method: " << utility::conversions::to_utf8string(out) << endl;
|
||||
|
||||
out = parsed[U("apiKey")].as_string();
|
||||
cout << "apiKey: " << utility::conversions::to_utf8string(out) << endl;
|
||||
|
||||
out = parsed[U("appVersion")].as_string();
|
||||
cout << "appVersion: " << utility::conversions::to_utf8string(out) << endl;
|
||||
|
||||
out = parsed[U("protocolVersion")].as_string();
|
||||
cout << "protocolVersion: " << utility::conversions::to_utf8string(out) << endl;
|
||||
|
||||
out = parsed[U("status")].as_string();
|
||||
cout << "status: " << utility::conversions::to_utf8string(out) << endl;
|
||||
|
||||
out = parsed[U("message")].as_string();
|
||||
cout << "message: " << utility::conversions::to_utf8string(out) << endl;
|
||||
|
||||
out = parsed[U("payload")].as_string();
|
||||
cout << "payload: " << utility::conversions::to_utf8string(out) << endl;
|
||||
}
|
48
commands.h
Normal file
48
commands.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
Copyright 2019 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.
|
||||
*/
|
||||
|
||||
#ifndef __COMMANDS_H__
|
||||
#define __COMMANDS_H__
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include <cpprest/ws_client.h>
|
||||
#include <cpprest/json.h>
|
||||
#include <cpprest/streams.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace web::websockets::client;
|
||||
using namespace web;
|
||||
|
||||
#define PROTOCOL_VERSION "2.0.0"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define convertstring to_utf16string
|
||||
#else
|
||||
#define convertstring to_utf8string
|
||||
#endif
|
||||
|
||||
string getDNSInfo();
|
||||
string createActivationRequest(string profile);
|
||||
json::value getCertificateHashes();
|
||||
string createResponse(string payload);
|
||||
string getActivateInfo(string profile);
|
||||
string encodeBase64(string str);
|
||||
string decodeBase64(string str);
|
||||
void dumpMessage(string tmp);
|
||||
|
||||
#endif
|
15
lms.cmake.in
Normal file
15
lms.cmake.in
Normal file
@@ -0,0 +1,15 @@
|
||||
cmake_minimum_required(VERSION 3.1)
|
||||
|
||||
project(lms-download NONE)
|
||||
|
||||
include(ExternalProject)
|
||||
ExternalProject_Add(lms
|
||||
GIT_REPOSITORY https://github.com/intel/lms.git
|
||||
GIT_TAG v1932.0.0.0
|
||||
SOURCE_DIR "${CMAKE_BINARY_DIR}/lms-src"
|
||||
BINARY_DIR "${CMAKE_BINARY_DIR}/lms-build"
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
TEST_COMMAND ""
|
||||
)
|
88
lms.cpp
Normal file
88
lms.cpp
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
Copyright 2019 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.
|
||||
*/
|
||||
#include "lms.h"
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
// Windows
|
||||
#include <Ws2tcpip.h>
|
||||
#else
|
||||
// Linux
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
|
||||
SOCKET lmsConnect()
|
||||
{
|
||||
std::string lmsAddress = "localhost";
|
||||
std::string lmsPort = "16992";
|
||||
SOCKET s = INVALID_SOCKET;
|
||||
struct addrinfo *addr, hints;
|
||||
|
||||
#ifdef _WIN32
|
||||
WSADATA wsa;
|
||||
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
|
||||
{
|
||||
throw std::runtime_error("error: unable to connect to LMS");
|
||||
}
|
||||
#endif
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_protocol = IPPROTO_TCP;
|
||||
|
||||
if (getaddrinfo(lmsAddress.c_str(), lmsPort.c_str(), &hints, &addr) != 0)
|
||||
{
|
||||
throw std::runtime_error("error: unable to connect to LMS");
|
||||
}
|
||||
|
||||
if (addr == NULL)
|
||||
{
|
||||
throw std::runtime_error("error: unable to connect to LMS");
|
||||
}
|
||||
|
||||
for (addr; addr != NULL; addr = addr->ai_next)
|
||||
{
|
||||
s = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
|
||||
if (s == INVALID_SOCKET)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (connect(s, addr->ai_addr, (int)addr->ai_addrlen) == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
closesocket(s);
|
||||
s = INVALID_SOCKET;
|
||||
}
|
||||
|
||||
if (addr != NULL)
|
||||
{
|
||||
freeaddrinfo(addr);
|
||||
}
|
||||
|
||||
if (s == INVALID_SOCKET)
|
||||
{
|
||||
throw std::runtime_error("error: unable to connect to LMS");
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
44
lms.h
Normal file
44
lms.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
Copyright 2019 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.
|
||||
*/
|
||||
|
||||
#ifndef __LMS_H__
|
||||
#define __LMS_H__
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
typedef int SOCKET;
|
||||
#define INVALID_SOCKET (SOCKET)(-1)
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
// Windows
|
||||
#else
|
||||
// Linux
|
||||
static inline int closesocket(int fd)
|
||||
{
|
||||
return close(fd);
|
||||
}
|
||||
#define SD_BOTH SHUT_RDWR
|
||||
#endif
|
||||
|
||||
SOCKET lmsConnect();
|
||||
|
||||
#endif
|
480
main.cpp
Normal file
480
main.cpp
Normal file
@@ -0,0 +1,480 @@
|
||||
/*
|
||||
Copyright 2019 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.
|
||||
*/
|
||||
|
||||
#include <cpprest/ws_client.h>
|
||||
#include <cpprest/streams.h>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include "commands.h"
|
||||
#include "lms.h"
|
||||
#include "version.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace web;
|
||||
using namespace web::websockets::client;
|
||||
|
||||
#include <cpprest/json.h>
|
||||
|
||||
void showUsage();
|
||||
|
||||
string websocket_address = "";
|
||||
string server_profile = "";
|
||||
string websocket_proxy = "";
|
||||
|
||||
long long timeoutTimer = 0;
|
||||
const int MAX_TIMEOUT = 10; // seconds
|
||||
bool timeoutThreadAlive = true;
|
||||
|
||||
void timeoutFunc(std::condition_variable *cv, std::mutex *mx)
|
||||
{
|
||||
while (timeoutThreadAlive)
|
||||
{
|
||||
std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now();
|
||||
auto duration = now.time_since_epoch();
|
||||
long long currTime = std::chrono::duration_cast<std::chrono::seconds>(duration).count();
|
||||
|
||||
if (currTime > timeoutTimer)
|
||||
{
|
||||
if (currTime - timeoutTimer >= MAX_TIMEOUT)
|
||||
{
|
||||
cv->notify_all();
|
||||
|
||||
// check if timeoutTimer is not 0 since we explicitly set to zero when an
|
||||
// activation is successfull. If it's not zero, we are in a time out scenario.
|
||||
if (timeoutTimer)
|
||||
{
|
||||
cout << endl << "Timed-out due to inactivity." <<endl;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
string activationInfo;
|
||||
|
||||
bool gotURL = false;
|
||||
bool gotProfile = false;
|
||||
bool gotProxy = false;
|
||||
bool gotDns = false;
|
||||
|
||||
if (argc==1)
|
||||
{
|
||||
std::cout << "Use --h, --help for help." << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (int i=1; i<argc; i++)
|
||||
{
|
||||
if ( (boost::equals(argv[i], "--help")) || (boost::equals(argv[i], "--h")) )
|
||||
{
|
||||
showUsage();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i=1; i<argc; i++)
|
||||
{
|
||||
if ( (boost::equals(argv[i], "--url")) || (boost::equals(argv[i], "--u")) )
|
||||
{
|
||||
if (i+1<argc)
|
||||
{
|
||||
gotURL = true;
|
||||
websocket_address = argv[++i];
|
||||
}
|
||||
}
|
||||
else if ( (boost::equals(argv[i], "--profile")) || (boost::equals(argv[i], "--p")) )
|
||||
{
|
||||
if (i+1<argc)
|
||||
{
|
||||
gotProfile = true;
|
||||
server_profile = argv[++i];
|
||||
}
|
||||
}
|
||||
else if ( (boost::equals(argv[i], "--proxy")) ||(boost::equals(argv[i], "--x")) )
|
||||
{
|
||||
if (i+1<argc)
|
||||
{
|
||||
gotProxy = true;
|
||||
websocket_proxy = argv[++i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Unrecognized command line arguments." << std::endl;
|
||||
std::cout << "Use --h, --help for help." << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!gotURL || !gotProfile)
|
||||
{
|
||||
std::cout << "Incorrect or missing arguments." << std::endl;
|
||||
std::cout << "Use --h, --help for help." << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Print version info
|
||||
cout << PROJECT_NAME << " v" PROJECT_VER << endl;
|
||||
|
||||
try {
|
||||
// Get activation info
|
||||
activationInfo = createActivationRequest(server_profile);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cerr << endl << "Unable to get activation info. Check AMT configuration." << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Check if LMS is available
|
||||
SOCKET s = lmsConnect();
|
||||
closesocket(s);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cerr << endl << "Unable to connect to Local Management Service (LMS). Please ensure LMS is running." << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Show activation info
|
||||
#ifdef DEBUG
|
||||
cout << "Activation info: " << endl << activationInfo << endl;
|
||||
#endif
|
||||
|
||||
// WebSocket Interface
|
||||
websocket_client_config client_config;
|
||||
if (!websocket_proxy.empty())
|
||||
{
|
||||
client_config.set_proxy(web::web_proxy(utility::conversions::to_string_t(websocket_proxy)));
|
||||
}
|
||||
#ifdef DEBUG
|
||||
// skip certificate verification if debug build
|
||||
cout << "!!! SKIPPING CERTIFICATE VERIFICATION !!!" << endl;
|
||||
client_config.set_validate_certificates(false);
|
||||
#endif
|
||||
websocket_callback_client client(client_config);
|
||||
std::condition_variable cv;
|
||||
std::mutex mx;
|
||||
SOCKET s;
|
||||
|
||||
// set receive handler
|
||||
client.set_message_handler([&client, &mx, &cv, &s](websocket_incoming_message ret_msg)
|
||||
{
|
||||
// kick the timer
|
||||
std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now();
|
||||
auto duration = now.time_since_epoch();
|
||||
timeoutTimer = std::chrono::duration_cast<std::chrono::seconds>(duration).count();
|
||||
|
||||
try
|
||||
{
|
||||
// handle message from server...
|
||||
string rcv_websocket_msg = ret_msg.extract_string().get();
|
||||
#ifdef DEBUG
|
||||
cout << endl << "<<<<< Received Message " << endl;
|
||||
cout << rcv_websocket_msg << endl;
|
||||
#endif
|
||||
cout << "." << std::flush; // dot status output
|
||||
|
||||
// parse incoming JSON message
|
||||
utility::string_t tmp = utility::conversions::convertstring(rcv_websocket_msg);
|
||||
web::json::value parsed = web::json::value::parse(tmp);
|
||||
|
||||
utility::string_t out = U("");
|
||||
string msgMethod = "";
|
||||
string msgApiKey = "";
|
||||
string msgAppVersion = "";
|
||||
string msgProtocolVersion = "";
|
||||
string msgStatus = "";
|
||||
string msgMessage = "";
|
||||
string msgPayload = "";
|
||||
string payloadDecoded = "";
|
||||
|
||||
if ( !parsed.has_field(U("method")) || !parsed.has_field(U("apiKey")) || !parsed.has_field(U("appVersion")) ||
|
||||
!parsed.has_field(U("protocolVersion")) || !parsed.has_field(U("status")) || !parsed.has_field(U("message")) ||
|
||||
!parsed.has_field(U("payload")) ) {
|
||||
std::cerr << endl << "Received incorrectly formatted message." << endl;
|
||||
cv.notify_all();
|
||||
timeoutThreadAlive = false;
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
out = parsed[U("method")].as_string();
|
||||
msgMethod = utility::conversions::to_utf8string(out);
|
||||
|
||||
out = parsed[U("apiKey")].as_string();
|
||||
msgApiKey = utility::conversions::to_utf8string(out);
|
||||
|
||||
out = parsed[U("appVersion")].as_string();
|
||||
msgAppVersion = utility::conversions::to_utf8string(out);
|
||||
|
||||
out = parsed[U("protocolVersion")].as_string();
|
||||
msgProtocolVersion = utility::conversions::to_utf8string(out);
|
||||
|
||||
out = parsed[U("status")].as_string();
|
||||
msgStatus = utility::conversions::to_utf8string(out);
|
||||
|
||||
out = parsed[U("message")].as_string();
|
||||
msgMessage = utility::conversions::to_utf8string(out);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cerr << endl << "Received message parse error." << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
cout << msgMethod << ", " << msgStatus << ", " << msgMessage << endl;
|
||||
cout << rcv_websocket_msg << endl;
|
||||
#endif
|
||||
|
||||
// process any messages we can
|
||||
// - if success, done
|
||||
// - if error, get out
|
||||
if (boost::iequals(msgMethod, "success"))
|
||||
{
|
||||
// cleanup
|
||||
timeoutTimer = 0;
|
||||
|
||||
// exit
|
||||
cout << endl << msgMessage << endl;
|
||||
return;
|
||||
}
|
||||
else if (boost::iequals(msgMethod, "error"))
|
||||
{
|
||||
// cleanup
|
||||
timeoutTimer = 0;
|
||||
|
||||
// exit
|
||||
cout << endl << msgMessage << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// process payload afterward since success/error messages have zero length
|
||||
// payloads which cause an exception to be thrown
|
||||
try
|
||||
{
|
||||
out = parsed[U("payload")].as_string();
|
||||
|
||||
if (out.length()>0)
|
||||
{
|
||||
msgPayload = utility::conversions::to_utf8string(out);
|
||||
|
||||
// decode payload
|
||||
payloadDecoded = decodeBase64(msgPayload);
|
||||
}
|
||||
else
|
||||
{
|
||||
// no payload, nothing to do
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cerr << endl << "JSON format error. Unable to parse message." << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// conntect to lms
|
||||
s = lmsConnect();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cerr << endl << "Unable to connect to Local Management Service (LMS). Please ensure LMS is running." << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
cout << endl << "vvvvv Sending Message " << endl;
|
||||
cout << payloadDecoded << endl;
|
||||
#endif
|
||||
|
||||
// send message to LMS
|
||||
if (send(s, payloadDecoded.c_str(), (int)payloadDecoded.length(), 0) < 0)
|
||||
{
|
||||
throw std::runtime_error("error: socket send");
|
||||
}
|
||||
|
||||
// handle response message from LMS
|
||||
int fd = ((int) s) + 1;
|
||||
fd_set rset;
|
||||
FD_ZERO(&rset);
|
||||
FD_SET(s, &rset);
|
||||
|
||||
timeval timeout;
|
||||
memset(&timeout, 0, sizeof(timeval));
|
||||
timeout.tv_sec = 2;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
// read until connection is closed by LMS
|
||||
while (1)
|
||||
{
|
||||
string superBuffer = "";
|
||||
while (1)
|
||||
{
|
||||
int res = select(fd, &rset, NULL, NULL, &timeout);
|
||||
if (res == 0)
|
||||
{
|
||||
// we timed-out waiting for the ME. ME usually delivers data very fast. If
|
||||
// we time out, it means that there is no more data that the ME needs to send,
|
||||
// but it's keeping the connection open.
|
||||
break;
|
||||
}
|
||||
|
||||
// read from LMS
|
||||
char recv_buffer[4096];
|
||||
memset(recv_buffer, 0, 4096);
|
||||
res = recv(s, recv_buffer, 4096, 0);
|
||||
if (res > 0)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
cout << endl << "^^^^^ Received Message" << endl;
|
||||
cout << recv_buffer << endl;
|
||||
#endif
|
||||
superBuffer += recv_buffer;
|
||||
}
|
||||
else if (res < 0)
|
||||
{
|
||||
// on LMS read exception
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
// case where res is zero bytes
|
||||
// discussion below, but select returns 1 with recv returning 0 to indicate close
|
||||
// https://stackoverflow.com/questions/2992547/waiting-for-data-via-select-not-working
|
||||
break;
|
||||
}
|
||||
} // while select()
|
||||
|
||||
// if there is some data send it
|
||||
if (superBuffer.length() > 0)
|
||||
{
|
||||
string response = createResponse(superBuffer.c_str());
|
||||
websocket_outgoing_message send_websocket_msg;
|
||||
string send_websocket_buffer(response);
|
||||
send_websocket_msg.set_utf8_message(send_websocket_buffer);
|
||||
#ifdef DEBUG
|
||||
cout << endl << ">>>>> Sending Message" << endl;
|
||||
cout << superBuffer << endl;
|
||||
cout << send_websocket_buffer << endl;
|
||||
#endif
|
||||
client.send(send_websocket_msg).wait();
|
||||
|
||||
// done
|
||||
closesocket(s);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
closesocket(s);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cerr << endl << "Communication error in receive handler." << endl;
|
||||
closesocket(s);
|
||||
}
|
||||
});
|
||||
|
||||
// set close handler
|
||||
client.set_close_handler([&mx,&cv](websocket_close_status status, const utility::string_t &reason, const std::error_code &code)
|
||||
{
|
||||
// websocket closed by server, notify main thread
|
||||
cv.notify_all();
|
||||
});
|
||||
|
||||
try
|
||||
{
|
||||
// Connect to web socket server; AMT activation server
|
||||
client.connect(utility::conversions::to_string_t(websocket_address)).wait();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cerr << "Unable to connect to websocket server. Please check url." << endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Send activationParams to websocket
|
||||
websocket_outgoing_message out_msg;
|
||||
out_msg.set_utf8_message(activationInfo);
|
||||
|
||||
#ifdef DEBUG
|
||||
cout << endl << ">>>>> Sending Activiation Info" << endl;
|
||||
cout << activationInfo << endl;
|
||||
#endif
|
||||
client.send(out_msg).wait();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cerr << endl << "Unable to send message to websocket server." << endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now();
|
||||
auto duration = now.time_since_epoch();
|
||||
timeoutTimer = std::chrono::duration_cast<std::chrono::seconds>(duration).count();
|
||||
std::thread timeoutThread(timeoutFunc, &cv, &mx);
|
||||
|
||||
// wait for server to send success/failure command
|
||||
std::unique_lock<std::mutex> lock(mx);
|
||||
cv.wait(lock);
|
||||
|
||||
// wait for timeout thread
|
||||
timeoutThread.join();
|
||||
|
||||
// clean-up websocket
|
||||
client.close().wait();
|
||||
|
||||
// clean-up socket
|
||||
if (s) {
|
||||
shutdown(s, SD_BOTH);
|
||||
closesocket(s);
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void showUsage()
|
||||
{
|
||||
cout << "Usage: " << PROJECT_NAME << " --url <url> --profile <name> [--proxy <addr>]" << endl;
|
||||
cout << "Required:" << endl;
|
||||
cout << " --u, --url <url> websocket server" << endl;
|
||||
cout << " --p, --profile <name> server profile" << endl;
|
||||
cout << "Optional:" << endl;
|
||||
cout << " --x, --proxy <addr> proxy address and port" << endl;
|
||||
cout << endl;
|
||||
cout << "Examples:" << endl;
|
||||
cout << " " << PROJECT_NAME << " --url wss://localhost --profile profile1" << endl;
|
||||
cout << " " << PROJECT_NAME << " --u wss://localhost --profile profile1 --proxy http://proxy.com:1000" << endl;
|
||||
cout << " " << PROJECT_NAME << " --u wss://localhost --p profile1 --x http://proxy.com:1000" << endl;
|
||||
cout << endl;
|
||||
}
|
10
version.h.in
Normal file
10
version.h.in
Normal file
@@ -0,0 +1,10 @@
|
||||
#ifndef __VERSION_H__
|
||||
#define __VERSION_H__
|
||||
|
||||
#define PROJECT_NAME "@PROJECT_NAME@"
|
||||
#define PROJECT_VER "@PROJECT_VERSION@"
|
||||
#define PROJECT_VER_MAJOR "@PROJECT_VERSION_MAJOR@"
|
||||
#define PROJECT_VER_MINOR "@PROJECT_VERSION_MINOR@"
|
||||
#define PTOJECT_VER_PATCH "@PROJECT_VERSION_PATCH@"
|
||||
|
||||
#endif // __VERSION_H__
|
Reference in New Issue
Block a user