532 lines
15 KiB
C++
532 lines
15 KiB
C++
#include <string>
|
|
#include <locale>
|
|
#include <vector>
|
|
#include <iostream>
|
|
#include <ctime>
|
|
#include <chrono>
|
|
|
|
#include "SendMessage.h"
|
|
#include "../Utils/utils.h"
|
|
#include "get_information.h"
|
|
|
|
|
|
#ifdef _WIN32
|
|
#include <Windows.h>
|
|
#include <winsock.h>
|
|
|
|
#define WM_USER 0x0400 //ñîîáùåíèÿ äëÿ îáðàáîò÷èêà ñîîáùåíèé
|
|
#define STATUS_MESSAGE WM_USER + 16
|
|
|
|
// link with Ws2_32.lib
|
|
#pragma comment(lib,"Ws2_32.lib")
|
|
|
|
#else
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <unistd.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
|
|
#define SOCKET int
|
|
#define INVALID_SOCKET (SOCKET)(~0)
|
|
#define SOCKADDR sockaddr
|
|
#define closesocket close
|
|
|
|
void WSACleanup() { }
|
|
int WSAGetLastError() { return 0; }
|
|
void Sleep(int millisec) { usleep(millisec * 1000); }
|
|
|
|
#endif
|
|
|
|
using std::wstring;
|
|
using std::string;
|
|
using std::vector;
|
|
using std::chrono::high_resolution_clock;
|
|
using std::chrono::duration_cast;
|
|
using std::chrono::milliseconds;
|
|
|
|
static SOCKET clientSocket = INVALID_SOCKET;
|
|
static FILE* logFile = NULL;
|
|
|
|
#if _WIN32
|
|
#define FILE_LOG "Components\\Sapfor_log.txt"
|
|
#else
|
|
#define FILE_LOG "Components/Sapfor_log.txt"
|
|
#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 CLIENT "[SAPFOR]"
|
|
|
|
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(CLIENT, "'%s' length='%d'\n", command.c_str(), command.length());
|
|
return err < 0 ? err : count;
|
|
}
|
|
|
|
static int decodeMessage(const string& message, vector<string>& pars, int &winH, int countPars)
|
|
{
|
|
int sI = 0;
|
|
for (int z = 0; z < countPars; ++z)
|
|
{
|
|
string d = "";
|
|
for ( ;sI != message.size() && message[sI] != ' '; ++sI)
|
|
d += message[sI];
|
|
if (sI == message.size())
|
|
return -1;
|
|
++sI;
|
|
|
|
int countElems = -1;
|
|
if (sscanf(d.c_str(), "%d", &countElems) != 1)
|
|
return -2;
|
|
|
|
string par = "";
|
|
|
|
for (int z = 0; sI != message.size() && z < countElems; ++z, ++sI)
|
|
par += message[sI];
|
|
if (sI == message.size())
|
|
return -3;
|
|
pars.push_back(par);
|
|
}
|
|
|
|
string d = "", toPrint = "";
|
|
for (; sI != message.size() && message[sI] != ' '; ++sI)
|
|
d += message[sI];
|
|
|
|
if (d[d.size() - 1] == '\n' && d.size() >= 2)
|
|
toPrint = d.substr(0, d.size() - 2);
|
|
else
|
|
toPrint = d;
|
|
|
|
__print(CLIENT, "Read port from '%s'", toPrint.c_str());
|
|
if (sscanf(d.c_str(), "%d", &winH) != 1)
|
|
{
|
|
__print(CLIENT, "PORT ERROR");
|
|
return -4;
|
|
}
|
|
else
|
|
__print(CLIENT, "PORT = %d", winH);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void sendMessage_1lvl(const wstring& toSend) { MessageManager::sendFirstLvl (toSend); }
|
|
void sendMessage_2lvl(const wstring& toSend) { MessageManager::sendSecondLvl(toSend); }
|
|
void sendMessage_progress(const wstring& toSend) { MessageManager::sendProgress (toSend); }
|
|
|
|
static string utf8_encode(const wstring& wstr)
|
|
{
|
|
if (wstr.empty())
|
|
return string();
|
|
#ifdef _WIN32
|
|
int size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL);
|
|
string strTo(size_needed, 0);
|
|
WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), &strTo[0], size_needed, NULL, NULL);
|
|
#else
|
|
/*char* buf = NULL;
|
|
int size_needed = wcstombs(buf, wstr.c_str(), sizeof(char));
|
|
printf("%d for \n", size_needed);
|
|
buf = new char[size_needed + 1];
|
|
wcstombs(buf, wstr.c_str(), sizeof(char));
|
|
string strTo(buf);
|
|
delete[] buf;*/
|
|
|
|
string strTo(wstr.size(), 0);
|
|
for (int z = 0; z < wstr.size(); ++z)
|
|
strTo[z] = wstr[z];
|
|
#endif
|
|
return strTo;
|
|
}
|
|
|
|
/*static wstring utf8_decode(const string& str)
|
|
{
|
|
if (str.empty())
|
|
return wstring();
|
|
|
|
int size_needed = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.length(), NULL, 0);
|
|
wstring wstr;
|
|
wstr.resize(size_needed, 0);
|
|
MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.length(), &wstr[0], size_needed);
|
|
return wstr;
|
|
}*/
|
|
|
|
void MessageManager::sendMessage(const wstring& toSend)
|
|
{
|
|
if (WinHandler > 0) //to C#
|
|
{
|
|
#ifdef _WIN32
|
|
cachedMessages.push_back(toSend);
|
|
PostMessage((HWND)WinHandler, STATUS_MESSAGE, (WPARAM)(cachedMessages.back().c_str()), (LPARAM)cachedMessages.back().size());
|
|
#endif
|
|
}
|
|
else if (WinHandler < -1) // to JAVA
|
|
{
|
|
vector<wstring> splited;
|
|
splitString(toSend, '\n', splited);
|
|
|
|
int i = 1;
|
|
for (auto& elem : splited)
|
|
{
|
|
string result = utf8_encode(L"message_" + std::to_wstring(i++) + L":" + elem + L"\n");
|
|
const char* ret = result.c_str();
|
|
|
|
int size = result.size();
|
|
#ifdef _WIN32
|
|
int iResult = send(clientSocket, ret, size, 0);
|
|
#else
|
|
int iResult = write(clientSocket, ret, size);
|
|
#endif
|
|
if (iResult < 0)
|
|
printf("Wrong send is %d\n", iResult);
|
|
}
|
|
}
|
|
}
|
|
|
|
static int connectAndCreate(SOCKET& socket_t, string address, int port)
|
|
{
|
|
socket_t = socket(AF_INET, SOCK_STREAM, 0);
|
|
if (socket_t == INVALID_SOCKET)
|
|
{
|
|
printf("Wrong socket\n");
|
|
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(socket_t, (SOCKADDR*)(&clientService), sizeof(clientService));
|
|
|
|
if (result != 0)
|
|
{
|
|
__print(CLIENT, "Wrong connect to socket %d\n", WSAGetLastError());
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void MessageManager::setWinHandler(const int winH)
|
|
{
|
|
if (winH < -1) // to JAVA
|
|
{
|
|
if (MessageManager::init() != 0)
|
|
{
|
|
WinHandler = -1;
|
|
return;
|
|
}
|
|
|
|
__print(CLIENT, "set handler with PORT = %d", winH);
|
|
if (connectAndCreate(clientSocket, "127.0.0.1", winH == -2 ? 8888 : -winH) != 0)
|
|
{
|
|
WinHandler = -1;
|
|
return;
|
|
}
|
|
|
|
}
|
|
else if (winH == -1 && WinHandler < -1) // close JAVA
|
|
{
|
|
if (Started == 0)
|
|
{
|
|
Sleep(100);
|
|
closesocket(clientSocket);
|
|
clientSocket == INVALID_SOCKET;
|
|
}
|
|
}
|
|
WinHandler = winH;
|
|
}
|
|
|
|
//from get_information.cpp
|
|
extern bool showDebug;
|
|
|
|
static int send(SOCKET& client, const wstring& messageIn)
|
|
{
|
|
wstring message = messageIn;
|
|
for (int z = 0; z < message.size(); ++z)
|
|
if (message[z] == L'\n')
|
|
message[z] = 1;
|
|
message += L"\n";
|
|
|
|
string result = utf8_encode(message);
|
|
string size = std::to_string(result.size());
|
|
|
|
if (showDebug)
|
|
{
|
|
wprintf(L"%s: Original message '%s'", CLIENT, message.c_str());
|
|
printf("%s: Converted message '%s'", CLIENT, result.c_str());
|
|
}
|
|
|
|
#ifdef _WIN32
|
|
int err = send(client, size.c_str(), size.size(), 0);
|
|
#else
|
|
size += "\n";
|
|
int err = write(client, size.c_str(), size.size());
|
|
#endif
|
|
__print(CLIENT, "Send message size: %d", (int)result.size());
|
|
if (err != size.size())
|
|
{
|
|
__print(CLIENT, "Error of send(): %d", err); // exit
|
|
return -1;
|
|
}
|
|
|
|
char buf;
|
|
recv(client, &buf, 1, 0);
|
|
|
|
__print(CLIENT, "send start\n", CLIENT);
|
|
auto timeForPass = high_resolution_clock::now();
|
|
#ifdef _WIN32
|
|
err = send(client, result.c_str(), result.size(), 0);
|
|
#else
|
|
err = write(client, result.c_str(), result.size());
|
|
#endif
|
|
|
|
const float elapsed = duration_cast<milliseconds>(high_resolution_clock::now() - timeForPass).count() / 1000.;
|
|
__print(CLIENT, "send end with time %f sec\n", elapsed);
|
|
__print(CLIENT, "Send message with size %d", (int)result.size());
|
|
|
|
if (err != result.size())
|
|
{
|
|
__print(CLIENT, "Error of send(): %d", err); // exit
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
err = recv(client, &buf, 1, 0);
|
|
if (err != 1)
|
|
{
|
|
__print(CLIENT, "Error of recv(): %d", err); // exit
|
|
return -1;
|
|
}
|
|
else
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
void MessageManager::sendProgress(const std::wstring& str)
|
|
{
|
|
if (WinHandler < -1) // to JAVA
|
|
{
|
|
string result = utf8_encode(L"progress:" + str + L"\n");
|
|
const char* ret = result.c_str();
|
|
|
|
int size = result.size();
|
|
#ifdef _WIN32
|
|
int iResult = send(clientSocket, ret, size, 0);
|
|
#else
|
|
int iResult = write(clientSocket, ret, size);
|
|
#endif
|
|
if (iResult == -1)
|
|
__print(CLIENT, "Error of send(): %d", iResult);
|
|
}
|
|
}
|
|
|
|
int MessageManager::init()
|
|
{
|
|
#if _WIN32
|
|
if (Started == -1)
|
|
{
|
|
WSADATA wsaData = { 0 };
|
|
int result = WSAStartup(MAKEWORD(2, 0), &wsaData);
|
|
if (result != 0)
|
|
{
|
|
__print(CLIENT, "Wrong WSAStartup(): %d", result);
|
|
Started = -2;
|
|
}
|
|
else
|
|
Started = 0;
|
|
}
|
|
#else
|
|
Started = 0;
|
|
#endif
|
|
return Started;
|
|
}
|
|
|
|
SOCKET client = INVALID_SOCKET;
|
|
|
|
void sendErrorCode(const wstring& message)
|
|
{
|
|
send(client, message);
|
|
closesocket(client);
|
|
client = INVALID_SOCKET;
|
|
}
|
|
|
|
void RunSapforAsClient(int serverPort)
|
|
{
|
|
if (MessageManager::init() != 0)
|
|
return;
|
|
|
|
logFile = fopen(FILE_LOG, "w");
|
|
if (logFile == NULL)
|
|
__print(CLIENT, "Can not open log file '%s'", FILE_LOG);
|
|
|
|
client = INVALID_SOCKET;
|
|
__print_log(logFile, "create and connect to server socket with port %d", serverPort > 0 ? serverPort : 8889);
|
|
if (connectAndCreate(client, "127.0.0.1", serverPort > 0 ? serverPort : 8889) != 0)
|
|
return;
|
|
__print_log(logFile, "done");
|
|
|
|
__print_log(logFile, "start main communications");
|
|
while (true)
|
|
{
|
|
wstring result = L"";
|
|
string message = "";
|
|
|
|
__print(CLIENT, "start recv message");
|
|
__print_log(logFile, "wait for command from server");
|
|
|
|
const int count = doRecv(client, message);
|
|
|
|
__print(CLIENT, "end recv message with size %d", count);
|
|
__print_log(logFile, "done with message size %d", count);
|
|
|
|
if (count > 0)
|
|
{
|
|
string code;
|
|
/*string copy = message;
|
|
if (copy.back() == '\n')
|
|
copy = copy.erase(copy.size() - 1);
|
|
__print(CLIENT, "Recv message: '%s'", copy.c_str());*/
|
|
|
|
int z = 0;
|
|
for (; z < message.size(); ++z)
|
|
{
|
|
if (message[z] == ':')
|
|
{
|
|
z++;
|
|
break;
|
|
}
|
|
else
|
|
code += message[z];
|
|
}
|
|
|
|
if (z == message.size()) // wrong message
|
|
{
|
|
__print(CLIENT, "Wrong message");
|
|
|
|
__print_log(logFile, "send WRONG message to server ");
|
|
int err = send(client, L"WRONG");
|
|
__print_log(logFile, "done with code %d", err);
|
|
if (err != 0)
|
|
break;
|
|
continue;
|
|
}
|
|
|
|
message = message.substr(z);
|
|
|
|
vector<string> pars;
|
|
int winHandler = -1;
|
|
|
|
if (code == "analysis")
|
|
{
|
|
__print_log(logFile, "decode message as analysis");
|
|
int err = decodeMessage(message, pars, winHandler, 3);
|
|
|
|
if (err == 0)
|
|
result = Sapfor_RunAnalysis(pars[0].c_str(), pars[1].c_str(), pars[2].c_str(), winHandler);
|
|
else
|
|
result = Sapfor_RunAnalysis(NULL, NULL, NULL, -1);
|
|
}
|
|
else if (code == "transformation")
|
|
{
|
|
__print_log(logFile, "decode message as transformation");
|
|
int err = decodeMessage(message, pars, winHandler, 5);
|
|
if (err == 0)
|
|
result = Sapfor_RunTransformation(pars[0].c_str(), pars[1].c_str(), pars[2].c_str(), pars[3].c_str(), pars[4].c_str(), winHandler);
|
|
else
|
|
result = Sapfor_RunTransformation(NULL, NULL, NULL, NULL, NULL, -1);
|
|
}
|
|
else if (code == "modification")
|
|
{
|
|
__print_log(logFile, "decode message as modification");
|
|
int err = decodeMessage(message, pars, winHandler, 6);
|
|
if (err == 0)
|
|
result = Sapfor_RunModification(pars[0].c_str(), pars[1].c_str(), pars[2].c_str(), pars[3].c_str(), pars[4].c_str(), pars[5].c_str(), winHandler);
|
|
else
|
|
result = Sapfor_RunModification(NULL, NULL, NULL, NULL, NULL, NULL, -1);
|
|
}
|
|
else
|
|
{
|
|
__print(CLIENT, "Wrong code of message: %s", code.c_str()); // exit
|
|
__print_log(logFile, "wrong code of message, send WRONG");
|
|
int err = send(client, L"WRONG");
|
|
__print_log(logFile, "done with code %d", err);
|
|
|
|
if (err != 0)
|
|
break;
|
|
continue;
|
|
}
|
|
|
|
__print_log(logFile, "send results to server");
|
|
int err = send(client, result.c_str());
|
|
__print_log(logFile, "done with code %d", err);
|
|
|
|
if (err != 0)
|
|
break;
|
|
}
|
|
else if (count == 0) // close and exit
|
|
{
|
|
closesocket(client);
|
|
__print(CLIENT, "Socket was closed");
|
|
__print_log(logFile, "done with normal exit");
|
|
break;
|
|
}
|
|
else // error
|
|
{
|
|
closesocket(client);
|
|
__print(CLIENT, "Recv return error code %d", count);
|
|
__print_log(logFile, "done with error exit");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
unsigned int GetPid()
|
|
{
|
|
unsigned int pid = 0;
|
|
#ifdef _WIN32
|
|
pid = GetCurrentProcessId();
|
|
#else
|
|
pid = getpid();
|
|
#endif
|
|
return pid;
|
|
}
|
|
|
|
vector<wstring> MessageManager::cachedMessages = vector<wstring>();
|
|
int MessageManager::WinHandler = -1;
|
|
wstring MessageManager::firstLvlMessage = L"";
|
|
wstring MessageManager::secondLvlMessage = L"";
|
|
int MessageManager::Started = -1;
|