From b82cfb060fabd2463b01d175b974cca2a2f729f7 Mon Sep 17 00:00:00 2001 From: Xiangyang Wu Date: Tue, 19 Oct 2021 10:40:34 +0800 Subject: [PATCH] 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 Reviewed-by: fei1.li@intel.com --- misc/services/life_mngr/life_mngr_win.c | 220 +++++++++++++++++++--- misc/services/life_mngr/s5_trigger_win.py | 37 ++++ 2 files changed, 226 insertions(+), 31 deletions(-) create mode 100644 misc/services/life_mngr/s5_trigger_win.py diff --git a/misc/services/life_mngr/life_mngr_win.c b/misc/services/life_mngr/life_mngr_win.c index c70f69643..6227d3dfc 100644 --- a/misc/services/life_mngr/life_mngr_win.c +++ b/misc/services/life_mngr/life_mngr_win.c @@ -3,14 +3,121 @@ * SPDX-License-Identifier: BSD-3-Clause */ -#include #include +#include +#include +#include +#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; } - diff --git a/misc/services/life_mngr/s5_trigger_win.py b/misc/services/life_mngr/s5_trigger_win.py new file mode 100644 index 000000000..c99ca837d --- /dev/null +++ b/misc/services/life_mngr/s5_trigger_win.py @@ -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() \ No newline at end of file