misc: life_mngr: refine lifecycle manager for windows VM
Refine lifecycle manager for windows VM since new commands are introduced in the lifecycle manager. v1-->v2: Implement socket service to receive system shutdown request command through local host socket. Add one python script to trigger system shutdown request in windows VM. v2-->v3: Update log message. v3-->v4: Support guest shutdown. v4-->v5: Update command name. v5-->v7: Add resend message logic. Tracked-On: #6652 Signed-off-by: Xiangyang Wu <xiangyang.wu@intel.com> Reviewed-by: fei1.li@intel.com
This commit is contained in:
parent
7a5146c2ed
commit
e297839fc3
|
@ -3,14 +3,121 @@
|
|||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
|
||||
#define WIN_VM_NAME "windows"
|
||||
#define REQ_SYS_SHUTDOWN "req_sys_shutdown"
|
||||
|
||||
#define SERVICE_VM_REQ "shutdown"
|
||||
#define USER_VM_ACK "acked"
|
||||
#define BUFF_SIZE 16U
|
||||
#define MSG_SIZE 8U
|
||||
#define ACK_REQ_SYS_SHUTDOWN "ack_req_sys_shutdown"
|
||||
#define SYNC_CMD "sync"
|
||||
#define ACK_SYNC "ack_sync"
|
||||
#define POWEROFF_CMD "poweroff_cmd"
|
||||
#define ACK_POWEROFF "ack_poweroff"
|
||||
#define USER_VM_SHUTDOWN "user_vm_shutdown"
|
||||
#define ACK_USER_VM_SHUTDOWN "ack_user_vm_shutdown"
|
||||
#define SYNC_FMT "sync:%s"
|
||||
#define S5_REJECTED "system shutdown request is rejected"
|
||||
|
||||
#define BUFF_SIZE (32U)
|
||||
#define MSG_SIZE (8U)
|
||||
#define VM_NAME_LEN (sizeof(WIN_VM_NAME))
|
||||
#define UVM_SOCKET_PORT (0x2001U)
|
||||
#define READ_INTERVAL (100U) /* The time unit is microsecond */
|
||||
#define MIN_RESEND_TIME (3U)
|
||||
#define MS_TO_SECOND (1000U)
|
||||
#define RETRY_RECV_TIMES (8U)
|
||||
|
||||
HANDLE hCom2;
|
||||
unsigned int resend_time;
|
||||
char resend_buf[BUFF_SIZE];
|
||||
|
||||
void send_message_by_uart(HANDLE hCom, char *buf, unsigned int len)
|
||||
{
|
||||
int i;
|
||||
DWORD written;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
WriteFile(hCom, &buf[i], 1, &written, NULL);
|
||||
|
||||
WriteFile(hCom, "\n", 1, &written, NULL);
|
||||
}
|
||||
void enable_uart_resend(char *buf, unsigned int time)
|
||||
{
|
||||
if (resend_time < MIN_RESEND_TIME)
|
||||
resend_time = MIN_RESEND_TIME;
|
||||
strncpy(resend_buf, buf, BUFF_SIZE - 1);
|
||||
resend_time = time + 1U;
|
||||
}
|
||||
void diable_uart_resend(void)
|
||||
{
|
||||
memset(resend_buf, 0x0, BUFF_SIZE);
|
||||
resend_time = 0U;
|
||||
}
|
||||
DWORD WINAPI open_socket_server(LPVOID lpParam)
|
||||
{
|
||||
WORD sockVersion = MAKEWORD(2, 2);
|
||||
WSADATA wsaData;
|
||||
char revData[BUFF_SIZE];
|
||||
struct sockaddr_in sin;
|
||||
SOCKET sClient;
|
||||
struct sockaddr_in remoteAddr;
|
||||
int nAddrlen = sizeof(remoteAddr);
|
||||
char *sendData = ACK_REQ_SYS_SHUTDOWN;
|
||||
int ret;
|
||||
|
||||
ret = WSAStartup(sockVersion, &wsaData);
|
||||
if (ret != 0) {
|
||||
printf("Failed to initiate Windows Socket, error: %d\n", ret);
|
||||
return -1;
|
||||
}
|
||||
SOCKET slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
|
||||
if (slisten == INVALID_SOCKET) {
|
||||
printf("Socket error !\n");
|
||||
goto start_error;
|
||||
}
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_port = htons(UVM_SOCKET_PORT);
|
||||
sin.sin_addr.S_un.S_addr = INADDR_ANY;
|
||||
if (bind(slisten, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR) {
|
||||
printf("Bind error !\n");
|
||||
goto sock_exit;
|
||||
}
|
||||
if (listen(slisten, 5) == SOCKET_ERROR) {
|
||||
printf("Listen error !\n");
|
||||
goto sock_exit;
|
||||
}
|
||||
printf("Wait for connect ...\n");
|
||||
sClient = accept(slisten, (SOCKADDR *)&remoteAddr, &nAddrlen);
|
||||
if (sClient == INVALID_SOCKET) {
|
||||
printf("Accept error\n");
|
||||
goto sock_exit;
|
||||
}
|
||||
printf("Accept one connect %s\n", inet_ntoa(remoteAddr.sin_addr));
|
||||
do {
|
||||
memset(revData, 0, sizeof(revData));
|
||||
int ret = recv(sClient, revData, BUFF_SIZE, 0);
|
||||
if (ret > 0) {
|
||||
revData[ret] = 0x00;
|
||||
printf(revData);
|
||||
}
|
||||
Sleep(READ_INTERVAL);
|
||||
} while (strncmp(revData, REQ_SYS_SHUTDOWN, sizeof(REQ_SYS_SHUTDOWN)) != 0);
|
||||
Sleep(6U * MS_TO_SECOND);
|
||||
send(sClient, sendData, strlen(sendData), 0);
|
||||
enable_uart_resend(REQ_SYS_SHUTDOWN, MIN_RESEND_TIME);
|
||||
send_message_by_uart(hCom2, REQ_SYS_SHUTDOWN, sizeof(REQ_SYS_SHUTDOWN));
|
||||
Sleep(2 * READ_INTERVAL);
|
||||
closesocket(sClient);
|
||||
sock_exit:
|
||||
closesocket(slisten);
|
||||
start_error:
|
||||
WSACleanup();
|
||||
return 0;
|
||||
}
|
||||
|
||||
HANDLE initCom(const char *szStr)
|
||||
{
|
||||
|
@ -24,29 +131,29 @@ HANDLE initCom(const char *szStr)
|
|||
|
||||
if (hCom == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
printf("open %s failed!\n", szStr);
|
||||
printf("Opening %s failed!\n", szStr);
|
||||
return hCom;
|
||||
}
|
||||
|
||||
printf("open %s successed!\n", szStr);
|
||||
printf("%s opened succesfully!", szStr);
|
||||
SetupComm(hCom, 1024, 1024);
|
||||
|
||||
COMMTIMEOUTS TimeOuts;
|
||||
TimeOuts.ReadIntervalTimeout = 100; /* Maximum time between read chars. */
|
||||
TimeOuts.ReadTotalTimeoutMultiplier = 5000; /* Multiplier of characters. */
|
||||
TimeOuts.ReadTotalTimeoutConstant = 5000; /* Constant in milliseconds. */
|
||||
TimeOuts.WriteTotalTimeoutMultiplier = 500; /* Multiplier of characters. */
|
||||
TimeOuts.WriteTotalTimeoutConstant = 2000; /* Constant in milliseconds. */
|
||||
TimeOuts.ReadIntervalTimeout = MAXDWORD; /* Maximum time between read chars. */
|
||||
TimeOuts.ReadTotalTimeoutMultiplier = 0; /* Multiplier of characters. */
|
||||
TimeOuts.ReadTotalTimeoutConstant = 0; /* Constant in milliseconds. */
|
||||
TimeOuts.WriteTotalTimeoutMultiplier = 500; /* Multiplier of characters. */
|
||||
TimeOuts.WriteTotalTimeoutConstant = 100; /* Constant in milliseconds. */
|
||||
SetCommTimeouts(hCom, &TimeOuts);
|
||||
|
||||
DCB dcb;
|
||||
GetCommState(hCom, &dcb);
|
||||
DCB dcb = {0};
|
||||
dcb.BaudRate = 115200;
|
||||
dcb.ByteSize = 8;
|
||||
dcb.Parity = NOPARITY;
|
||||
dcb.StopBits = ONESTOPBIT;
|
||||
SetCommState(hCom, &dcb);
|
||||
|
||||
SetCommState(hCom, &dcb);
|
||||
PurgeComm(hCom, PURGE_TXCLEAR | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_RXABORT);
|
||||
return hCom;
|
||||
}
|
||||
|
||||
|
@ -54,29 +161,80 @@ int main()
|
|||
{
|
||||
DWORD recvsize = 0;
|
||||
char recvbuf[BUFF_SIZE];
|
||||
char buf[VM_NAME_LEN + 5];
|
||||
DWORD dwError;
|
||||
DWORD threadId;
|
||||
bool poweroff = false;
|
||||
unsigned int retry_times;
|
||||
|
||||
HANDLE hCom = initCom("COM2");
|
||||
if (hCom == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
hCom2 = initCom("COM2");
|
||||
if (hCom2 == INVALID_HANDLE_VALUE)
|
||||
return -1;
|
||||
memset(buf, 0, sizeof(buf));
|
||||
memset(resend_buf, 0, sizeof(resend_buf));
|
||||
CreateThread(NULL, 0, open_socket_server, NULL, 0, &threadId);
|
||||
if (ClearCommError(hCom2, &dwError, NULL)) {
|
||||
PurgeComm(hCom2, PURGE_TXABORT | PURGE_TXCLEAR);
|
||||
}
|
||||
|
||||
snprintf(buf, sizeof(buf), SYNC_FMT, WIN_VM_NAME);
|
||||
enable_uart_resend(buf, MIN_RESEND_TIME);
|
||||
send_message_by_uart(hCom2, buf, strlen(buf));
|
||||
do {
|
||||
memset(recvbuf, 0, sizeof(recvbuf));
|
||||
ReadFile(hCom, recvbuf, sizeof(recvbuf), &recvsize, NULL);
|
||||
if (recvsize < MSG_SIZE)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
do {
|
||||
retry_times = RETRY_RECV_TIMES;
|
||||
memset(recvbuf, 0, sizeof(recvbuf));
|
||||
do {
|
||||
ReadFile(hCom2, recvbuf, sizeof(recvbuf), &recvsize, NULL);
|
||||
Sleep(READ_INTERVAL);
|
||||
retry_times--;
|
||||
} while ((recvsize < MSG_SIZE) && (retry_times > 0));
|
||||
if (recvsize < MSG_SIZE) {
|
||||
if (resend_time > 1U) {
|
||||
Sleep(6U * MS_TO_SECOND);
|
||||
printf("Resend command (%s) service VM\n", resend_buf);
|
||||
send_message_by_uart(hCom2, resend_buf, strlen(resend_buf));
|
||||
resend_time--;
|
||||
} else if (resend_time == 1U) {
|
||||
printf("Failed to resend command (%s)\n", resend_buf);
|
||||
break;
|
||||
} else {
|
||||
/* No action if resend_time is 0 */
|
||||
}
|
||||
}
|
||||
} while (recvsize < MSG_SIZE);
|
||||
|
||||
if (strncmp(recvbuf, SERVICE_VM_REQ, MSG_SIZE) == 0)
|
||||
{
|
||||
WriteFile(hCom, USER_VM_ACK, sizeof(USER_VM_ACK), NULL, NULL);
|
||||
system("shutdown -s -t 0");
|
||||
if (resend_time == 1U)
|
||||
break;
|
||||
if (recvbuf[recvsize - 1] == '\n')
|
||||
recvbuf[recvsize - 1] = '\0';
|
||||
|
||||
if (strncmp(recvbuf, ACK_SYNC, sizeof(ACK_SYNC)) == 0)
|
||||
{
|
||||
diable_uart_resend();
|
||||
printf("Received acked sync message from service VM\n");
|
||||
} else if (strncmp(recvbuf, ACK_REQ_SYS_SHUTDOWN, sizeof(ACK_REQ_SYS_SHUTDOWN)) == 0) {
|
||||
diable_uart_resend();
|
||||
printf("Received acked system shutdown request from service VM\n");
|
||||
} else if (strncmp(recvbuf, POWEROFF_CMD, sizeof(POWEROFF_CMD)) == 0) {
|
||||
printf("Received system shutdown message from service VM\n");
|
||||
send_message_by_uart(hCom2, ACK_POWEROFF, sizeof(ACK_POWEROFF));
|
||||
Sleep(2 * READ_INTERVAL);
|
||||
printf("Windows VM will shutdown.\n");
|
||||
poweroff = true;
|
||||
break;
|
||||
} else if (strncmp(recvbuf, USER_VM_SHUTDOWN, sizeof(USER_VM_SHUTDOWN)) == 0) {
|
||||
printf("Received guest shutdown message from service VM\n");
|
||||
send_message_by_uart(hCom2, ACK_USER_VM_SHUTDOWN, sizeof(ACK_USER_VM_SHUTDOWN));
|
||||
Sleep(2 * READ_INTERVAL);
|
||||
printf("Windows VM will shutdown.\n");
|
||||
poweroff = true;
|
||||
break;
|
||||
} else {
|
||||
printf("Received invalid message (%s) from service VM.\n", recvbuf);
|
||||
}
|
||||
} while (1);
|
||||
|
||||
CloseHandle(hCom2);
|
||||
if (poweroff)
|
||||
system("shutdown -s -t 0");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (C) 2021 Intel Corporation.
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
#
|
||||
import socket
|
||||
import sys
|
||||
|
||||
if __name__ == "__main__":
|
||||
HOST = '127.0.0.1'
|
||||
PORT = 8193
|
||||
SHUTDOWN_REQ = 'req_sys_shutdown'
|
||||
MSG_LEN = 32
|
||||
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
print(["Socket Created"])
|
||||
|
||||
try:
|
||||
s.connect((HOST,PORT))
|
||||
print("[Connection established]")
|
||||
except Exception:
|
||||
print('[Connection error: ' + HOST + ":" + str(PORT)+']')
|
||||
s.close()
|
||||
|
||||
try:
|
||||
s.send(SHUTDOWN_REQ.encode('utf-8'))
|
||||
except Exception as _:
|
||||
raise _
|
||||
print(["Shutdown request sent\n"])
|
||||
|
||||
try:
|
||||
data_input = (s.recv(MSG_LEN).decode("UTF-8"))
|
||||
except Exception:
|
||||
pass
|
||||
print("Waiting for ACK message...: ", data_input)
|
||||
s.close()
|
Loading…
Reference in New Issue