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