#if _WIN32 #define _WINSOCK_DEPRECATED_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS #include #include #else #include #endif #include #include #include #include #include #include #include //build under linux //g++ -O3 -std=c++17 checkUniq.cpp server.cpp -o Visualizer_2 -lpthread -lstdc++fs"; #if _WIN32 #include #include namespace fs = std::filesystem; #define getcwd _getcwd #else //с++14 unix + -lstdc++fs /*#include namespace fs = std::experimental::filesystem;*/ //с++17 unix #include namespace fs = std::filesystem; #include #endif #include #include #include using namespace std; #if _WIN32 //link with Ws2_32.lib #pragma comment(lib, "Ws2_32.lib") #define SPF_NAME "Components\\Sapfor_F.exe" #define SPF_NAME_NEW "Components\\Sapfor_F_new.exe" #define SPC_NAME "Components\\Sapfor_C.exe" #define SPC_NAME_NEW "Components\\Sapfor_C_new.exe" #define VIZ_NAME "Components\\VisualSapfor.jar" #define VIZ_NAME_NEW "Components\\VisualSapfor_new.jar" #define FILE_LOG "Components\\Server_log.txt" #define SPF_ASYNC " " #else #include #include #include #include #include #define SOCKET int #define INVALID_SOCKET (SOCKET)(~0) #define SOCKADDR sockaddr #define closesocket close #define SPF_NAME "Components/Sapfor_F" #define SPF_NAME_NEW "Components/Sapfor_F_new" #define SPC_NAME "Components/Sapfor_C" #define SPC_NAME_NEW "Components/Sapfor_C_new" #define VIZ_NAME "Components/VisualSapfor.jar" #define VIZ_NAME_NEW "Components/VisualSapfor_new.jar" #define FILE_LOG "Components/Server_log.txt" #define SPF_ASYNC "&" void WSACleanup() { } int WSAGetLastError() { return 0; } void Sleep(int millisec) { usleep(millisec * 2000); } #endif #define __print(prefix, format, ...) do { } while (0) #define __print_log(file, format, ...) do { } while (0) /* #define __print(prefix, format, ...) do {\ printf((string("%s: ") + format + string("\n")).c_str(), prefix, ##__VA_ARGS__); \ fflush(NULL); \ } while (0) #define __print_log(file, format, ...) do {\ if (file) { \ time_t now = time(0);\ auto dt = string(ctime(&now)); \ dt = dt.erase(dt.size() - 1); \ fprintf(file, (string("%s: ") + format + string("\n")).c_str(), dt.c_str(), ##__VA_ARGS__); \ fflush(file); \ } \ } while (0) */ #define SERV "[SERVER]" static const char* VERSION = "11"; static FILE* logFile = NULL; extern void __bst_create(const char* name); extern bool __bst_tryToLock(); extern void __bst_unlock(); static void signal_handler(int s) { __print(SERV, "Caught signal %d", s); __bst_unlock(); exit(1); } static int getPort(const SOCKET& listenSocket) { sockaddr_in info; socklen_t len = sizeof(info); memset(&info, 0, len); int err = getsockname(listenSocket, (sockaddr*)&info, &len); if (err != 0) { __print(SERV, "Error of getaddrinfo(): %d", err); WSACleanup(); __bst_unlock(); exit(1); } return ntohs(info.sin_port); } static int initServer(SOCKET& listenSocket, const string& address, int port = 0) { int iResult; #if _WIN32 WSADATA wsaData = { 0 }; int resultc = WSAStartup(MAKEWORD(2, 0), &wsaData); if (resultc != 0) { __print(SERV, "result of WSAStartup is %d", resultc); return 1; } #endif #if _WIN32 addrinfo* result = NULL, hints; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; hints.ai_flags = AI_PASSIVE; iResult = getaddrinfo(address.c_str(), to_string(port).c_str(), &hints, &result); if (iResult != 0) { __print(SERV, "Error of getaddrinfo(): %d", iResult); WSACleanup(); return 1; } listenSocket = INVALID_SOCKET; listenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol); #else listenSocket = socket(AF_INET, SOCK_STREAM, 0); #endif if (listenSocket < 0) { __print(SERV, "Error of socket(): %d", listenSocket); WSACleanup(); return 1; } linger lin; lin.l_onoff = 1; lin.l_linger = 2; iResult = setsockopt(listenSocket, SOL_SOCKET, SO_LINGER, (char*)(&lin), sizeof(lin)); if (iResult != 0) { __print(SERV, "Error of setsockopt(): %d", iResult); return 1; } #if _WIN32 iResult = bind(listenSocket, result->ai_addr, result->ai_addrlen); #else sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = htonl(INADDR_ANY); iResult = ::bind(listenSocket, (struct sockaddr*) & addr, sizeof(addr)); #endif if (iResult < 0) { __print(SERV, "Bind failed with error: %d", iResult); closesocket(listenSocket); WSACleanup(); return 1; } iResult = listen(listenSocket, 1); if (iResult < 0) { __print(SERV, "Listen failed with error: %d", iResult); closesocket(listenSocket); WSACleanup(); return 1; } return 0; } static int initClient(SOCKET& javaSocket, const string& address, int port) { javaSocket = socket(AF_INET, SOCK_STREAM, 0); if (javaSocket == INVALID_SOCKET) { __print(SERV, "Error of creating java socket"); return -1; } linger lin; lin.l_onoff = 1; lin.l_linger = 2; int iResult = setsockopt(javaSocket, SOL_SOCKET, SO_LINGER, (char*)(&lin), sizeof(lin)); if (iResult != 0) { __print(SERV, "Error of setsockopt(): %d", iResult); return 1; } sockaddr_in clientService; clientService.sin_family = AF_INET; clientService.sin_addr.s_addr = inet_addr(address.c_str()); clientService.sin_port = htons(port); int result = connect(javaSocket, (SOCKADDR*)(&clientService), sizeof(clientService)); if (result != 0) __print(SERV, "Error %d of connect to socket %s: %d", WSAGetLastError(), address.c_str(), port); return result; } static volatile bool spfRun = false; static volatile int retCodeF = 0; static void runSapfor(const string command) { spfRun = true; __print("[SERVER-th1]", "Try to start Sapfor"); __print_log(logFile, "Try to start Sapfor"); retCodeF = 0; retCodeF = system(command.c_str()); __print("[SERVER-th1]", "SAPFOR done with exit code %d", retCodeF); __print_log(logFile, "SAPFOR done with exit code %d", retCodeF); spfRun = false; } static volatile bool spcRun = false; static volatile int retCodeC = 0; static void runSapforC(const string command) { spcRun = true; __print("[SERVER-th3]", "Try to start Sapfor(C)"); __print_log(logFile, "Try to start Sapfor(C)"); retCodeC = 0; retCodeC = system(command.c_str()); __print("[SERVER-th3]", "SAPFOR(C) done with exit code %d", retCodeC); __print_log(logFile, "SAPFOR(C) done with exit code %d", retCodeC); spcRun = false; } static volatile bool vizRun = false; static void runVisulizer(const string command) { vizRun = true; __print("[SERVER-th2]", "Try to start Visualizer"); __print_log(logFile, "Try to start Visualizer"); int id = system(command.c_str()); __print("[SERVER-th2]", "Visualizer done with exit code %d", id); __print_log(logFile, "Visualizer done with exit code %d", id); vizRun = false; } static bool doCommand(SOCKET& spfSoc, SOCKET& javaSoc, SOCKET& serverSoc1, SOCKET& serverSoc2, const string& command, bool& needToUpdateViz, string &returnToJava) { if (command.find("restart:") == 0) { __print(SERV, "Restart SAPFOR"); closesocket(spfSoc); spfSoc = INVALID_SOCKET; //wait shutdown of spf while (spfRun) ; return true; } else if (command.find("close:") == 0) { __print(SERV, "Shutdown"); closesocket(spfSoc); closesocket(javaSoc); closesocket(serverSoc1); closesocket(serverSoc2); javaSoc = spfSoc = INVALID_SOCKET; Sleep(500); __bst_unlock(); exit(0); } else if (command.find("update:") == 0) { __print(SERV, "Update Visualizer"); closesocket(spfSoc); closesocket(javaSoc); javaSoc = spfSoc = INVALID_SOCKET; //wait shutdown of viz while (vizRun) ; //copy new version if (fs::exists(VIZ_NAME_NEW)) { int countOf = 0; error_code err; do { ++countOf; fs::copy_file(VIZ_NAME_NEW, VIZ_NAME, fs::copy_options::overwrite_existing, err); __print(SERV, "Updated with error code %d: %s", err.value(), err.message().c_str()); if (err.value() != 0) std::this_thread::sleep_for(std::chrono::milliseconds(200)); } while (err.value() != 0 && countOf < 5); } else __print(SERV, "Can not find new version of Visualizer in '%s' path", VIZ_NAME_NEW); //restart needToUpdateViz = true; return true; } else if (command.find("update_spf:") == 0) { __print(SERV, "Update SAPFOR"); closesocket(spfSoc); spfSoc = INVALID_SOCKET; //wait shutdown of spf while (spfRun) ; //copy new version if (fs::exists(SPF_NAME_NEW)) { int countOf = 0; error_code err; do { ++countOf; fs::copy_file(SPF_NAME_NEW, SPF_NAME, fs::copy_options::overwrite_existing, err); __print(SERV, "Updated with error code %d: %s", err.value(), err.message().c_str()); if (err.value() != 0) std::this_thread::sleep_for(std::chrono::milliseconds(200)); } while (err.value() != 0 && countOf < 5); } else __print(SERV, "Can not find new version of sapfor in '%s' path", SPF_NAME_NEW); //restart return true; } else if (command.find("update_spc:") == 0) { __print(SERV, "Update SAPFOR"); closesocket(spfSoc); spfSoc = INVALID_SOCKET; //wait shutdown of spc while (spcRun) ; //copy new version if (fs::exists(SPC_NAME_NEW)) { int countOf = 0; error_code err; do { ++countOf; fs::copy_file(SPC_NAME_NEW, SPC_NAME, fs::copy_options::overwrite_existing, err); __print(SERV, "Updated with error code %d: %s", err.value(), err.message().c_str()); if (err.value() != 0) std::this_thread::sleep_for(std::chrono::milliseconds(200)); } while (err.value() != 0 && countOf < 5); } else __print(SERV, "Can not find new version of sapfor in '%s' path", SPC_NAME_NEW); //restart return true; } else if (command.find("update_server:") == 0) { __print(SERV, "Update SERVER"); closesocket(spfSoc); spfSoc = INVALID_SOCKET; //wait shutdown of spf while (spfRun) ; //wait shutdown of spc while (spcRun) ; closesocket(javaSoc); javaSoc = INVALID_SOCKET; __print(SERV, "SAPFOR was closed, Visualizer socker was closed, exit"); Sleep(500); __bst_unlock(); exit(0); } else if (command.find("get_version:") == 0) { __print(SERV, "Get version of server: %s", VERSION); returnToJava = string(VERSION) + " |" + __DATE__ + "| |" + __TIME__ + "|\n"; return true; } else if (command.find("get_pid:") == 0) { unsigned int pid = 0; #ifdef _WIN32 pid = GetCurrentProcessId(); #else pid = getpid(); #endif const string pids = std::to_string(pid); __print(SERV, "Get pid of server: %s", pids.c_str()); returnToJava = pids + "\n"; return true; } else { string copy = command; if (copy.back() == '\n') copy = copy.erase(copy.size() - 1); __print(SERV, "Recv command %s", copy.c_str()); } return false; } static void closeAndExit(const vector& toClose, const string& message, int exitCode = 0) { for (auto& elem : toClose) closesocket(elem); if (message != "") __print(SERV, "%s", message.c_str()); __bst_unlock(); exit(exitCode); } static bool isSapforDebug(int argc, char** argv) { for (int z = 1; z < argc; ++z) if (string("-spfDeb") == argv[z]) return true; return false; } static bool isVizDebug(int argc, char** argv) { for (int z = 1; z < argc; ++z) if (string("-vizDeb") == argv[z]) return true; return false; } static string getJavaPath(int argc, char** argv) { string path = ""; for (int z = 1; z < argc; ++z) if (string("-javaPath") == argv[z]) return argv[z + 1]; return path; } static int doRecv(SOCKET& soc, string& command) { int count = 0; //общее количество прочитаного int err = 0; //количество прочитанного на данной итерации. const int maxSize = 4096; //максимальный размер прочитываемой за раз порции. char* buf = NULL; //буфер do { buf = new char[maxSize + 1]; err = recv(soc, buf, maxSize, 0); if (err > 0) { count += err; buf[err] = '\0'; command += buf; } delete[] buf; buf = NULL; } while (err > 0 && command.back() != '\n'); __print(SERV, "'%s' length='%d'\n", command.c_str(), command.length()); return err < 0 ? err : count; } int main(int argc, char** argv) { if (argc == 2 && argv[1] == string("-help")) { printf("commands:\n"); printf(" -hashSkip\n"); printf(" -unlock\n"); printf(" -javaPath \n"); exit(0); } signal(SIGINT, signal_handler); signal(SIGABRT, signal_handler); #if _WIN32 signal(SIGBREAK, signal_handler); #else signal(SIGKILL, signal_handler); #endif char buff[1024]; char* test = getcwd(buff, 1024); const string path = test ? buff : argv[0]; bool isSpfDeb = isSapforDebug(argc, argv); bool isVizDeb = isVizDebug(argc, argv); string javaPath = getJavaPath(argc, argv); if (argc == 2 && argv[1] == string("-hashSkip")) ; else { const size_t hashOfPath = hash{}(path); __print(SERV, "Open or create mutex of '%s' path, hash = %zu", path.c_str(), hashOfPath); __bst_create(to_string(hashOfPath).c_str()); if (argc == 2 && argv[1] == string("-unlock")) { if (!__bst_tryToLock()) { __print(SERV, "Try to unlock '%s' path", path.c_str()); __bst_unlock(); exit(0); } } if (!__bst_tryToLock()) { __print(SERV, "The instance of Visualizer from '%s' path was started", path.c_str()); exit(0); } } logFile = fopen(FILE_LOG, "w"); if (logFile == NULL) __print(SERV, "Can not open log file '%s'", FILE_LOG); setlocale(LC_ALL, "Russian"); SOCKET serverSPF = INVALID_SOCKET, serverJAVA = INVALID_SOCKET; int sapforPort = 0, javaPort = 0; __print_log(logFile, "create socket for Sapfor"); if (initServer(serverSPF, "127.0.0.1", sapforPort) != 0) // create server for Sapfor return -1; sapforPort = getPort(serverSPF); __print_log(logFile, "done with port %d", sapforPort); __print_log(logFile, "create socket for Visualizer"); if (initServer(serverJAVA, "127.0.0.1", javaPort) != 0) // create server for Visuzlier { closesocket(serverSPF); return -1; } javaPort = getPort(serverJAVA); __print_log(logFile, "done with port %d", javaPort); printf("SOCKET PORT for SAPFOR %d, SOCKET PORT for Visualizer %d\n", sapforPort, javaPort); const int maxSize = 4096; char* buf = new char[maxSize + 1]; int err; SOCKET spfSoc = INVALID_SOCKET, javaSoc = INVALID_SOCKET; bool needToUpdateViz = true; int t = 0; __print_log(logFile, "start main communications"); while (true) { if (!vizRun && needToUpdateViz && !isVizDeb) { __print_log(logFile, "try to restart Visualizer, flags before: vizRun(%d), needToUpdateViz(%d), isVizDeb(%d)", vizRun, needToUpdateViz, isVizDeb); __print(SERV, "Run Visualizer from '%s' path with port %d", VIZ_NAME, javaPort); if (fs::exists(VIZ_NAME)) { needToUpdateViz = false; string toRun = string("-Dfile.encoding=UTF-8 -jar ") + VIZ_NAME + " --port " + to_string(javaPort) + SPF_ASYNC; if (javaPath != "") toRun = "\"" + javaPath + "\\java\" " + toRun; else toRun = "java " + toRun; __print_log(logFile, "try to start with command '%s'", toRun.c_str()); thread viz(runVisulizer, toRun); viz.detach(); __print_log(logFile, "done"); //wait run of viz //while (!vizRun) ; } else { __print(SERV, "Can not find Visualizer in '%s' path", VIZ_NAME); __print_log(logFile, "Can not find Visualizer in '%s' path", VIZ_NAME); //closeAndExit({ serverSPF , serverJAVA }, "Component not found", -1); } } if (!spfRun && !isSpfDeb) { __print_log(logFile, "try to restart Sapfor, flags before: spfRun(%d), isSpfDeb(%d)", spfRun, isSpfDeb); __print(SERV, "Run Sapfor from '%s' path with port %d", SPF_NAME, sapforPort); if (fs::exists(SPF_NAME)) { const string toRun = SPF_NAME + string(" -client ") + to_string(sapforPort) + SPF_ASYNC; __print_log(logFile, "try to start with command '%s'", toRun.c_str()); thread sapfor(runSapfor, toRun); sapfor.detach(); __print_log(logFile, "done"); //wait run of spf //while (!spfRun) ; } else { __print(SERV, "Can not find Sapfor in '%s' path", SPF_NAME); __print_log(logFile, "Can not find Sapfor in '%s' path", SPF_NAME); //closeAndExit({ serverSPF , serverJAVA }, "Component not found", -1); } } bool spfExists = (fs::exists(SPF_NAME) || isSpfDeb); __print_log(logFile, "start connections"); for (int z = 0; z < 2; ++z) { if (javaSoc == INVALID_SOCKET && z == 1) { __print_log(logFile, "wait acception from Visualizer"); javaSoc = accept(serverJAVA, NULL, NULL); if (javaSoc != INVALID_SOCKET) { __print(SERV, "VISUALIZER connected to server"); __print_log(logFile, "VISUALIZER connected to server"); } } if (spfSoc == INVALID_SOCKET && z == 0 && spfExists) { __print_log(logFile, "wait acception from Sapfor"); spfSoc = accept(serverSPF, NULL, NULL); if (spfSoc != INVALID_SOCKET) { __print(SERV, "SAPFOR connected to server"); __print_log(logFile, "SAPFOR connected to server"); } } } __print_log(logFile, "done connections"); while ( ((spfSoc != INVALID_SOCKET && spfExists) || (!fs::exists(SPF_NAME) && !isSpfDeb)) && javaSoc != INVALID_SOCKET) { string retCode = ""; string command = ""; __print_log(logFile, "wait for command from Visualizer"); err = doRecv(javaSoc, command); __print_log(logFile, "done with code %d", err); if (err <= 0) { __print(SERV, "Error recv from Visualizer with code %d", err); __print_log(logFile, "error recv from Visualizer with code %d", err); closesocket(javaSoc); closesocket(spfSoc); javaSoc = spfSoc = INVALID_SOCKET; break; } else { string returnToJava = ""; __print_log(logFile, "do command '%s'", command.c_str()); if (doCommand(spfSoc, javaSoc, serverSPF, serverJAVA, command, needToUpdateViz, returnToJava)) { if (javaSoc != INVALID_SOCKET) { int needToRecv = 1; if (returnToJava == "") buf[0] = '\n'; else { memcpy(buf, returnToJava.c_str(), sizeof(char) * returnToJava.size()); needToRecv = returnToJava.size(); } int err = send(javaSoc, buf, needToRecv, 0); if (err != needToRecv) { closesocket(javaSoc); javaSoc = INVALID_SOCKET; __print_log(logFile, "done with invalid break "); break; } else { //after 'get_version' command if (needToRecv > 1) { __print_log(logFile, "done with continue"); continue; } } } __print_log(logFile, "done with break"); break; } __print_log(logFile, "done"); } __print_log(logFile, "try to send command to Sapfor with size %d", command.size()); err = send(spfSoc, command.c_str(), command.size(), 0); __print_log(logFile, "done with code %d", err); if (err != command.size()) { __print(SERV, "Error of send(): %d", err); __print_log(logFile, "error of send(): %d", err); closesocket(spfSoc); spfSoc = INVALID_SOCKET; } else __print(SERV, "Send command to SAPFOR"); __print_log(logFile, "try to recv answer from Sapfor"); err = recv(spfSoc, buf, maxSize, 0); __print_log(logFile, "done with code %d", err); int sizeLong = -1; char* bufLong = NULL; if (err <= 0) { __print(SERV, "Error recv(): %d", err); __print_log(logFile, "error recv(): %d", err); closesocket(spfSoc); spfSoc = INVALID_SOCKET; if (spfRun) retCode = "WRONG\n"; else { if (fs::exists(SPF_NAME)) { if (retCodeF != 0) retCode = "SIG_FAULT\n"; else retCode = "WRONG\n"; } else retCode = "NOT_FOUND\n"; } } else { if (err >= maxSize) closeAndExit({ spfSoc , javaSoc , serverSPF , serverJAVA }, "Critical error", -1); buf[err] = '\0'; err = sscanf(buf, "%d", &sizeLong); if (err == -1) closeAndExit({ spfSoc , javaSoc , serverSPF , serverJAVA }, "Critical error", -1); bufLong = (char*)malloc(sizeof(char) * (sizeLong + 1)); if (bufLong == NULL) { __print(SERV, "Error in malloc, exit, need to alloc %d", sizeLong + 1); closeAndExit({ spfSoc , javaSoc , serverSPF , serverJAVA }, "", -1); } } if (retCode.find("WRONG") == string::npos && retCode.find("NOT_FOUND") == string::npos && retCode.find("SIG_FAULT") == string::npos) { retCode = ""; err = send(spfSoc, buf, 1, 0); int start = 0; int sum = 0; while (sum != sizeLong) { __print_log(logFile, "try to recv results from Sapfor"); err = recv(spfSoc, bufLong + start, sizeLong - sum, 0); __print_log(logFile, "done with code %d", err); if (err <= 0) { __print(SERV, "Error of recv from SAPFOR with code %d", err); __print_log(logFile, "error of recv from SAPFOR with code %d", err); retCode = "WRONG\n"; closesocket(spfSoc); spfSoc = INVALID_SOCKET; break; } else __print(SERV, "Recv from SAPFOR result == %d size, request size %d", err, sizeLong - sum); sum += err; start += err; } __print(SERV, "Recv from SAPFOR total %d size", sum); __print_log(logFile, "done recv from SAPFOR with total %d size", sum); if (sum >= sizeLong + 1) closeAndExit({ spfSoc , javaSoc , serverSPF , serverJAVA }, "Critical error", -1); bufLong[sum] = '\0'; retCode = bufLong; free(bufLong); } else __print(SERV, "Send error code to Visualizer: %s", retCode.c_str()); __print_log(logFile, "send response to Sapfor"); err = send(spfSoc, buf, 1, 0); __print_log(logFile, "done with code %d", err); __print_log(logFile, "send response to Visualizer"); err = send(javaSoc, retCode.c_str(), retCode.size(), 0); __print_log(logFile, "done with code %d", err); if (err != retCode.size()) { __print(SERV, "Error send to Visualizer"); __print_log(logFile, "error send to Visualizer"); closesocket(spfSoc); closesocket(javaSoc); javaSoc = spfSoc = INVALID_SOCKET; break; } else __print(SERV, "Send result to Visualizer %d", (int)retCode.size()); } __print(SERV, "Invalid SAPFOR socket, try to restart"); __print_log(logFile, "invalid SAPFOR socket, try to restart"); Sleep(100); } __bst_unlock(); return 0; }