mirror of
https://github.com/thiagoralves/OpenPLC_v3.git
synced 2025-05-09 04:41:06 +08:00
Add files via upload
This commit is contained in:
parent
ddcae72b01
commit
f3da2df734
923
utils/snap7_src/src/sys/snap_msgsock.cpp
Normal file
923
utils/snap7_src/src/sys/snap_msgsock.cpp
Normal file
@ -0,0 +1,923 @@
|
|||||||
|
/*=============================================================================|
|
||||||
|
| PROJECT SNAP7 1.3.0 |
|
||||||
|
|==============================================================================|
|
||||||
|
| Copyright (C) 2013, 2015 Davide Nardella |
|
||||||
|
| All rights reserved. |
|
||||||
|
|==============================================================================|
|
||||||
|
| SNAP7 is free software: you can redistribute it and/or modify |
|
||||||
|
| it under the terms of the Lesser GNU General Public License as published by |
|
||||||
|
| the Free Software Foundation, either version 3 of the License, or |
|
||||||
|
| (at your option) any later version. |
|
||||||
|
| |
|
||||||
|
| It means that you can distribute your commercial software linked with |
|
||||||
|
| SNAP7 without the requirement to distribute the source code of your |
|
||||||
|
| application and without the requirement that your application be itself |
|
||||||
|
| distributed under LGPL. |
|
||||||
|
| |
|
||||||
|
| SNAP7 is distributed in the hope that it will be useful, |
|
||||||
|
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||||
|
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
|
| Lesser GNU General Public License for more details. |
|
||||||
|
| |
|
||||||
|
| You should have received a copy of the GNU General Public License and a |
|
||||||
|
| copy of Lesser GNU General Public License along with Snap7. |
|
||||||
|
| If not, see http://www.gnu.org/licenses/ |
|
||||||
|
|=============================================================================*/
|
||||||
|
|
||||||
|
#include "snap_msgsock.h"
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static SocketsLayer SocketsLayerInitializer;
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Base class endian aware
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
TSnapBase::TSnapBase()
|
||||||
|
{
|
||||||
|
int x = 1;
|
||||||
|
LittleEndian=*(char *)&x == 1;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
word TSnapBase::SwapWord(word Value)
|
||||||
|
{
|
||||||
|
if (LittleEndian)
|
||||||
|
return ((Value >> 8) & 0xFF) | ((Value << 8) & 0xFF00);
|
||||||
|
else
|
||||||
|
return Value;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
longword TSnapBase::SwapDWord(longword Value)
|
||||||
|
{
|
||||||
|
if (LittleEndian)
|
||||||
|
return (Value >> 24) | ((Value << 8) & 0x00FF0000) | ((Value >> 8) & 0x0000FF00) | (Value << 24);
|
||||||
|
else
|
||||||
|
return Value;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
void Msg_CloseSocket(socket_t FSocket)
|
||||||
|
{
|
||||||
|
#ifdef OS_WINDOWS
|
||||||
|
closesocket(FSocket);
|
||||||
|
#else
|
||||||
|
close(FSocket);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
longword Msg_GetSockAddr(socket_t FSocket)
|
||||||
|
{
|
||||||
|
sockaddr_in RemoteSin;
|
||||||
|
#ifdef OS_WINDOWS
|
||||||
|
int namelen = sizeof(RemoteSin);
|
||||||
|
#else
|
||||||
|
uint32_t namelen = sizeof(RemoteSin);
|
||||||
|
#endif
|
||||||
|
namelen=sizeof(sockaddr_in);
|
||||||
|
if (getpeername(FSocket,(struct sockaddr*)&RemoteSin, &namelen)==0)
|
||||||
|
return RemoteSin.sin_addr.s_addr;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
TMsgSocket::TMsgSocket()
|
||||||
|
{
|
||||||
|
Pinger = new TPinger();
|
||||||
|
// Set Defaults
|
||||||
|
strcpy(LocalAddress,"0.0.0.0");
|
||||||
|
LocalPort=0;
|
||||||
|
strcpy(RemoteAddress,"127.0.0.1");
|
||||||
|
RemotePort=0;
|
||||||
|
WorkInterval=100;
|
||||||
|
RecvTimeout=500;
|
||||||
|
SendTimeout=10;
|
||||||
|
PingTimeout=750;
|
||||||
|
Connected=false;
|
||||||
|
FSocket=INVALID_SOCKET;
|
||||||
|
LastTcpError=0;
|
||||||
|
LocalBind=0;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
TMsgSocket::~TMsgSocket()
|
||||||
|
{
|
||||||
|
DestroySocket();
|
||||||
|
delete Pinger;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
void TMsgSocket::SetSin(sockaddr_in &sin, char *Address, u_short Port)
|
||||||
|
{
|
||||||
|
uint32_t in_addr;
|
||||||
|
in_addr=inet_addr(Address);
|
||||||
|
memset(&sin, 0, sizeof(sin));
|
||||||
|
LastTcpError=0;
|
||||||
|
|
||||||
|
if (in_addr!=INADDR_NONE)
|
||||||
|
{
|
||||||
|
sin.sin_addr.s_addr = in_addr; //INADDR_ANY;
|
||||||
|
sin.sin_family = AF_INET;
|
||||||
|
sin.sin_port = htons(Port);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LastTcpError=WSAEINVALIDADDRESS;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
void TMsgSocket::GetSin(sockaddr_in sin, char *Address, u_short &Port)
|
||||||
|
{
|
||||||
|
strcpy(Address,inet_ntoa(sin.sin_addr));
|
||||||
|
Port=htons(sin.sin_port);
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
void TMsgSocket::GetLocal()
|
||||||
|
{
|
||||||
|
#ifdef OS_WINDOWS
|
||||||
|
int namelen = sizeof(LocalSin);
|
||||||
|
#else
|
||||||
|
uint32_t namelen = sizeof(LocalSin);
|
||||||
|
#endif
|
||||||
|
if (getsockname(FSocket, (struct sockaddr*)&LocalSin, &namelen)==0)
|
||||||
|
GetSin(LocalSin, LocalAddress, LocalPort);
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
void TMsgSocket::GetRemote()
|
||||||
|
{
|
||||||
|
#ifdef OS_WINDOWS
|
||||||
|
int namelen = sizeof(RemoteSin);
|
||||||
|
#else
|
||||||
|
uint32_t namelen = sizeof(RemoteSin);
|
||||||
|
#endif
|
||||||
|
if (getpeername(FSocket,(struct sockaddr*)&RemoteSin, &namelen)==0)
|
||||||
|
GetSin(RemoteSin, RemoteAddress, RemotePort);
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
int TMsgSocket::GetLastSocketError()
|
||||||
|
{
|
||||||
|
#ifdef OS_WINDOWS
|
||||||
|
return WSAGetLastError();
|
||||||
|
#else
|
||||||
|
return errno;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
void TMsgSocket::Purge()
|
||||||
|
{
|
||||||
|
// small buffer to empty the socket
|
||||||
|
char Trash[512];
|
||||||
|
int Read;
|
||||||
|
if (LastTcpError!=WSAECONNRESET)
|
||||||
|
{
|
||||||
|
if (CanRead(0)) {
|
||||||
|
do
|
||||||
|
{
|
||||||
|
Read=recv(FSocket, Trash, 512, MSG_NOSIGNAL );
|
||||||
|
} while(Read==512);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
void TMsgSocket::CreateSocket()
|
||||||
|
{
|
||||||
|
DestroySocket();
|
||||||
|
LastTcpError=0;
|
||||||
|
FSocket =socket(AF_INET, SOCK_STREAM, IPPROTO_TCP );
|
||||||
|
if (FSocket!=INVALID_SOCKET)
|
||||||
|
SetSocketOptions();
|
||||||
|
else
|
||||||
|
LastTcpError =GetLastSocketError();
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
void TMsgSocket::GotSocket()
|
||||||
|
{
|
||||||
|
ClientHandle=RemoteSin.sin_addr.s_addr;
|
||||||
|
// could be inherited it if wee need further actions on the socket
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
void TMsgSocket::SetSocket(socket_t s)
|
||||||
|
{
|
||||||
|
FSocket=s;
|
||||||
|
if (FSocket!=INVALID_SOCKET)
|
||||||
|
{
|
||||||
|
SetSocketOptions();
|
||||||
|
GetLocal();
|
||||||
|
GetRemote();
|
||||||
|
GotSocket();
|
||||||
|
}
|
||||||
|
Connected=FSocket!=INVALID_SOCKET;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
void TMsgSocket::DestroySocket()
|
||||||
|
{
|
||||||
|
if(FSocket != INVALID_SOCKET)
|
||||||
|
{
|
||||||
|
if (shutdown(FSocket, SD_SEND)==0)
|
||||||
|
Purge();
|
||||||
|
#ifdef OS_WINDOWS
|
||||||
|
closesocket(FSocket);
|
||||||
|
#else
|
||||||
|
close(FSocket);
|
||||||
|
#endif
|
||||||
|
FSocket=INVALID_SOCKET;
|
||||||
|
}
|
||||||
|
LastTcpError=0;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
int TMsgSocket::WaitingData()
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
u_long x = 0;
|
||||||
|
#ifdef OS_WINDOWS
|
||||||
|
if (ioctlsocket(FSocket, FIONREAD, &x) == 0)
|
||||||
|
result = x;
|
||||||
|
#else
|
||||||
|
if (ioctl(FSocket, FIONREAD, &x) == 0)
|
||||||
|
result = x;
|
||||||
|
#endif
|
||||||
|
if (result>MaxPacketSize)
|
||||||
|
result = MaxPacketSize;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
int TMsgSocket::WaitForData(int Size, int Timeout)
|
||||||
|
{
|
||||||
|
longword Elapsed;
|
||||||
|
|
||||||
|
// Check for connection active
|
||||||
|
if (CanRead(0) && (WaitingData()==0))
|
||||||
|
LastTcpError=WSAECONNRESET;
|
||||||
|
else
|
||||||
|
LastTcpError=0;
|
||||||
|
|
||||||
|
// Enter main loop
|
||||||
|
if (LastTcpError==0)
|
||||||
|
{
|
||||||
|
Elapsed =SysGetTick();
|
||||||
|
while((WaitingData()<Size) && (LastTcpError==0))
|
||||||
|
{
|
||||||
|
// Checks timeout
|
||||||
|
if (DeltaTime(Elapsed)>=(longword)(Timeout))
|
||||||
|
LastTcpError =WSAETIMEDOUT;
|
||||||
|
else
|
||||||
|
SysSleep(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(LastTcpError==WSAECONNRESET)
|
||||||
|
Connected =false;
|
||||||
|
|
||||||
|
return LastTcpError;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
void TMsgSocket::SetSocketOptions()
|
||||||
|
{
|
||||||
|
int NoDelay = 1;
|
||||||
|
int KeepAlive = 1;
|
||||||
|
LastTcpError=0;
|
||||||
|
SockCheck(setsockopt(FSocket, IPPROTO_TCP, TCP_NODELAY,(char*)&NoDelay, sizeof(NoDelay)));
|
||||||
|
|
||||||
|
if (LastTcpError==0)
|
||||||
|
SockCheck(setsockopt(FSocket, SOL_SOCKET, SO_KEEPALIVE,(char*)&KeepAlive, sizeof(KeepAlive)));
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
int TMsgSocket::SockCheck(int SockResult)
|
||||||
|
{
|
||||||
|
if (SockResult == (int)(SOCKET_ERROR))
|
||||||
|
LastTcpError = GetLastSocketError();
|
||||||
|
|
||||||
|
return LastTcpError;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
bool TMsgSocket::CanWrite(int Timeout)
|
||||||
|
{
|
||||||
|
timeval TimeV;
|
||||||
|
int64_t x;
|
||||||
|
fd_set FDset;
|
||||||
|
|
||||||
|
if(FSocket == INVALID_SOCKET)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
TimeV.tv_usec = (Timeout % 1000) * 1000;
|
||||||
|
TimeV.tv_sec = Timeout / 1000;
|
||||||
|
|
||||||
|
FD_ZERO(&FDset);
|
||||||
|
FD_SET(FSocket, &FDset);
|
||||||
|
|
||||||
|
x = select(FSocket + 1, NULL, &FDset, NULL, &TimeV); //<-Ignore this warning in 64bit Visual Studio
|
||||||
|
if (x==(int)SOCKET_ERROR)
|
||||||
|
{
|
||||||
|
LastTcpError = GetLastSocketError();
|
||||||
|
x=0;
|
||||||
|
}
|
||||||
|
return (x > 0);
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
bool TMsgSocket::CanRead(int Timeout)
|
||||||
|
{
|
||||||
|
timeval TimeV;
|
||||||
|
int64_t x;
|
||||||
|
fd_set FDset;
|
||||||
|
|
||||||
|
if(FSocket == INVALID_SOCKET)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
TimeV.tv_usec = (Timeout % 1000) * 1000;
|
||||||
|
TimeV.tv_sec = Timeout / 1000;
|
||||||
|
|
||||||
|
FD_ZERO(&FDset);
|
||||||
|
FD_SET(FSocket, &FDset);
|
||||||
|
|
||||||
|
x = select(FSocket + 1, &FDset, NULL, NULL, &TimeV); //<-Ignore this warning in 64bit Visual Studio
|
||||||
|
if (x==(int)SOCKET_ERROR)
|
||||||
|
{
|
||||||
|
LastTcpError = GetLastSocketError();
|
||||||
|
x=0;
|
||||||
|
}
|
||||||
|
return (x > 0);
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
#ifdef NON_BLOCKING_CONNECT
|
||||||
|
//
|
||||||
|
// Non blocking connection (UNIX) Thanks to Rolf Stalder
|
||||||
|
//
|
||||||
|
int TMsgSocket::SckConnect()
|
||||||
|
{
|
||||||
|
int n, flags, err;
|
||||||
|
socklen_t len;
|
||||||
|
fd_set rset, wset;
|
||||||
|
struct timeval tval;
|
||||||
|
|
||||||
|
SetSin(RemoteSin, RemoteAddress, RemotePort);
|
||||||
|
|
||||||
|
if (LastTcpError == 0) {
|
||||||
|
CreateSocket();
|
||||||
|
if (LastTcpError == 0) {
|
||||||
|
flags = fcntl(FSocket, F_GETFL, 0);
|
||||||
|
if (flags >= 0) {
|
||||||
|
if (fcntl(FSocket, F_SETFL, flags | O_NONBLOCK) != -1) {
|
||||||
|
n = connect(FSocket, (struct sockaddr*)&RemoteSin, sizeof(RemoteSin));
|
||||||
|
if (n < 0) {
|
||||||
|
if (errno != EINPROGRESS) {
|
||||||
|
LastTcpError = GetLastSocketError();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// still connecting ...
|
||||||
|
FD_ZERO(&rset);
|
||||||
|
FD_SET(FSocket, &rset);
|
||||||
|
wset = rset;
|
||||||
|
tval.tv_sec = PingTimeout / 1000;
|
||||||
|
tval.tv_usec = (PingTimeout % 1000) * 1000;
|
||||||
|
|
||||||
|
n = select(FSocket+1, &rset, &wset, NULL,
|
||||||
|
(PingTimeout ? &tval : NULL));
|
||||||
|
if (n == 0) {
|
||||||
|
// timeout
|
||||||
|
LastTcpError = WSAEHOSTUNREACH;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (FD_ISSET(FSocket, &rset) || FD_ISSET(FSocket, &wset)) {
|
||||||
|
err = 0;
|
||||||
|
len = sizeof(err);
|
||||||
|
if (getsockopt(
|
||||||
|
FSocket, SOL_SOCKET, SO_ERROR, &err, &len) == 0) {
|
||||||
|
if (err) {
|
||||||
|
LastTcpError = err;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (fcntl(FSocket, F_SETFL, flags) != -1) {
|
||||||
|
GetLocal();
|
||||||
|
ClientHandle = LocalSin.sin_addr.s_addr;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LastTcpError = GetLastSocketError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LastTcpError = GetLastSocketError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LastTcpError = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // still connecting
|
||||||
|
}
|
||||||
|
else if (n == 0) {
|
||||||
|
// connected immediatly
|
||||||
|
GetLocal();
|
||||||
|
ClientHandle = LocalSin.sin_addr.s_addr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LastTcpError = GetLastSocketError();
|
||||||
|
} // fcntl(F_SETFL)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LastTcpError = GetLastSocketError();
|
||||||
|
} // fcntl(F_GETFL)
|
||||||
|
} //valid socket
|
||||||
|
} // LastTcpError==0
|
||||||
|
Connected=LastTcpError==0;
|
||||||
|
return LastTcpError;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
//
|
||||||
|
// Regular connection (Windows)
|
||||||
|
//
|
||||||
|
int TMsgSocket::SckConnect()
|
||||||
|
{
|
||||||
|
int Result;
|
||||||
|
SetSin(RemoteSin, RemoteAddress, RemotePort);
|
||||||
|
if (LastTcpError==0)
|
||||||
|
{
|
||||||
|
if (Ping(RemoteSin))
|
||||||
|
{
|
||||||
|
CreateSocket();
|
||||||
|
if (LastTcpError==0)
|
||||||
|
{
|
||||||
|
Result=connect(FSocket, (struct sockaddr*)&RemoteSin, sizeof(RemoteSin));
|
||||||
|
if (SockCheck(Result)==0)
|
||||||
|
{
|
||||||
|
GetLocal();
|
||||||
|
// Client handle is self_address (here the connection is ACTIVE)
|
||||||
|
ClientHandle=LocalSin.sin_addr.s_addr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LastTcpError=WSAEHOSTUNREACH;
|
||||||
|
}
|
||||||
|
Connected=LastTcpError==0;
|
||||||
|
return LastTcpError;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
void TMsgSocket::SckDisconnect()
|
||||||
|
{
|
||||||
|
DestroySocket();
|
||||||
|
Connected=false;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
void TMsgSocket::ForceClose()
|
||||||
|
{
|
||||||
|
if(FSocket != INVALID_SOCKET)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
#ifdef OS_WINDOWS
|
||||||
|
closesocket(FSocket);
|
||||||
|
#else
|
||||||
|
close(FSocket);
|
||||||
|
#endif
|
||||||
|
} catch (...) {
|
||||||
|
}
|
||||||
|
FSocket=INVALID_SOCKET;
|
||||||
|
}
|
||||||
|
LastTcpError=0;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
int TMsgSocket::SckBind()
|
||||||
|
{
|
||||||
|
int Res;
|
||||||
|
int Opt=1;
|
||||||
|
SetSin(LocalSin, LocalAddress, LocalPort);
|
||||||
|
if (LastTcpError==0)
|
||||||
|
{
|
||||||
|
CreateSocket();
|
||||||
|
if (LastTcpError==0)
|
||||||
|
{
|
||||||
|
setsockopt(FSocket ,SOL_SOCKET, SO_REUSEADDR, (const char *)&Opt, sizeof(int));
|
||||||
|
Res =bind(FSocket, (struct sockaddr*)&LocalSin, sizeof(sockaddr_in));
|
||||||
|
SockCheck(Res);
|
||||||
|
if (Res==0)
|
||||||
|
{
|
||||||
|
LocalBind=LocalSin.sin_addr.s_addr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LastTcpError=WSAEINVALIDADDRESS;
|
||||||
|
|
||||||
|
return LastTcpError;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
int TMsgSocket::SckListen()
|
||||||
|
{
|
||||||
|
LastTcpError=0;
|
||||||
|
SockCheck(listen(FSocket ,SOMAXCONN));
|
||||||
|
return LastTcpError;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
bool TMsgSocket::Ping(char *Host)
|
||||||
|
{
|
||||||
|
return Pinger->Ping(Host, PingTimeout);
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
bool TMsgSocket::Ping(sockaddr_in Addr)
|
||||||
|
{
|
||||||
|
if (PingTimeout == 0)
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return Pinger->Ping(Addr.sin_addr.s_addr, PingTimeout);
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
socket_t TMsgSocket::SckAccept()
|
||||||
|
{
|
||||||
|
socket_t result;
|
||||||
|
LastTcpError=0;
|
||||||
|
result = accept(FSocket, NULL, NULL);
|
||||||
|
if(result==INVALID_SOCKET)
|
||||||
|
LastTcpError =GetLastSocketError();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
int TMsgSocket::SendPacket(void *Data, int Size)
|
||||||
|
{
|
||||||
|
int Result;
|
||||||
|
|
||||||
|
LastTcpError=0;
|
||||||
|
if (SendTimeout>0)
|
||||||
|
{
|
||||||
|
if (!CanWrite(SendTimeout))
|
||||||
|
{
|
||||||
|
LastTcpError = WSAETIMEDOUT;
|
||||||
|
return LastTcpError;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (send(FSocket, (char*)Data, Size, MSG_NOSIGNAL)==Size)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
Result =SOCKET_ERROR;
|
||||||
|
|
||||||
|
SockCheck(Result);
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
bool TMsgSocket::PacketReady(int Size)
|
||||||
|
{
|
||||||
|
return (WaitingData()>=Size);
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
int TMsgSocket::Receive(void *Data, int BufSize, int &SizeRecvd)
|
||||||
|
{
|
||||||
|
LastTcpError=0;
|
||||||
|
if (CanRead(RecvTimeout))
|
||||||
|
{
|
||||||
|
SizeRecvd=recv(FSocket ,(char*)Data ,BufSize ,MSG_NOSIGNAL );
|
||||||
|
|
||||||
|
if (SizeRecvd>0) // something read (default case)
|
||||||
|
LastTcpError=0;
|
||||||
|
else
|
||||||
|
if (SizeRecvd==0)
|
||||||
|
LastTcpError = WSAECONNRESET; // Connection reset by Peer
|
||||||
|
else
|
||||||
|
LastTcpError=GetLastSocketError(); // we need to know what happened
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LastTcpError = WSAETIMEDOUT;
|
||||||
|
|
||||||
|
if (LastTcpError==WSAECONNRESET)
|
||||||
|
Connected = false;
|
||||||
|
|
||||||
|
return LastTcpError;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
int TMsgSocket::RecvPacket(void *Data, int Size)
|
||||||
|
{
|
||||||
|
int BytesRead;
|
||||||
|
WaitForData(Size, RecvTimeout);
|
||||||
|
if (LastTcpError==0)
|
||||||
|
{
|
||||||
|
BytesRead=recv(FSocket, (char*)Data, Size, MSG_NOSIGNAL);
|
||||||
|
if (BytesRead==0)
|
||||||
|
LastTcpError = WSAECONNRESET; // Connection reset by Peer
|
||||||
|
else
|
||||||
|
if (BytesRead<0)
|
||||||
|
LastTcpError = GetLastSocketError();
|
||||||
|
}
|
||||||
|
else // After the timeout the bytes waiting were less then we expected
|
||||||
|
if (LastTcpError==WSAETIMEDOUT)
|
||||||
|
Purge();
|
||||||
|
|
||||||
|
if (LastTcpError==WSAECONNRESET)
|
||||||
|
Connected =false;
|
||||||
|
|
||||||
|
return LastTcpError;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
int TMsgSocket::PeekPacket(void *Data, int Size)
|
||||||
|
{
|
||||||
|
int BytesRead;
|
||||||
|
WaitForData(Size, RecvTimeout);
|
||||||
|
if (LastTcpError==0)
|
||||||
|
{
|
||||||
|
BytesRead=recv(FSocket, (char*)Data, Size, MSG_PEEK | MSG_NOSIGNAL );
|
||||||
|
if (BytesRead==0)
|
||||||
|
LastTcpError = WSAECONNRESET; // Connection reset by Peer
|
||||||
|
else
|
||||||
|
if (BytesRead<0)
|
||||||
|
LastTcpError = GetLastSocketError();
|
||||||
|
}
|
||||||
|
else // After the timeout the bytes waiting were less then we expected
|
||||||
|
if (LastTcpError==WSAETIMEDOUT)
|
||||||
|
Purge();
|
||||||
|
|
||||||
|
if (LastTcpError==WSAECONNRESET)
|
||||||
|
Connected =false;
|
||||||
|
|
||||||
|
return LastTcpError;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
bool TMsgSocket::Execute()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//==============================================================================
|
||||||
|
// PING
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
static int PingKind;
|
||||||
|
|
||||||
|
#ifdef OS_WINDOWS
|
||||||
|
// iphlpapi, is loaded dinamically because if this fails we can still try
|
||||||
|
// to use raw sockets
|
||||||
|
|
||||||
|
static char const *iphlpapi = "\\iphlpapi.dll";
|
||||||
|
#pragma pack(1)
|
||||||
|
|
||||||
|
//typedef byte TTxBuffer[40];
|
||||||
|
typedef byte TTxBuffer[32];
|
||||||
|
#pragma pack()
|
||||||
|
|
||||||
|
typedef HANDLE (__stdcall *pfn_IcmpCreateFile)();
|
||||||
|
typedef bool (__stdcall *pfn_IcmpCloseHandle)(HANDLE PingHandle);
|
||||||
|
|
||||||
|
typedef int (__stdcall *pfn_IcmpSendEcho2)(
|
||||||
|
HANDLE PingHandle,
|
||||||
|
void *Event,
|
||||||
|
void *AcpRoutine,
|
||||||
|
void *AcpContext,
|
||||||
|
unsigned long DestinationAddress,
|
||||||
|
void *RequestData,
|
||||||
|
int RequestSize,
|
||||||
|
void *not_used, //should be *IP_OPTION_INFORMATION but we don't use it
|
||||||
|
void *ReplyBuffer,
|
||||||
|
int ReplySize,
|
||||||
|
int Timeout
|
||||||
|
);
|
||||||
|
|
||||||
|
static pfn_IcmpCreateFile IcmpCreateFile;
|
||||||
|
static pfn_IcmpCloseHandle IcmpCloseHandle;
|
||||||
|
static pfn_IcmpSendEcho2 IcmpSendEcho2;
|
||||||
|
static HINSTANCE IcmpDllHandle = 0;
|
||||||
|
static bool IcmpAvail = false;
|
||||||
|
|
||||||
|
bool IcmpInit()
|
||||||
|
{
|
||||||
|
char iphlppath[MAX_PATH+12];
|
||||||
|
|
||||||
|
int PathLen = GetSystemDirectoryA(iphlppath, MAX_PATH);
|
||||||
|
if (PathLen != 0)
|
||||||
|
{
|
||||||
|
strcat(iphlppath, iphlpapi);
|
||||||
|
IcmpDllHandle = LoadLibraryA(iphlppath);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
IcmpDllHandle = 0;
|
||||||
|
|
||||||
|
if (IcmpDllHandle != 0)
|
||||||
|
{
|
||||||
|
IcmpCreateFile=(pfn_IcmpCreateFile)GetProcAddress(IcmpDllHandle,"IcmpCreateFile");
|
||||||
|
IcmpCloseHandle=(pfn_IcmpCloseHandle)GetProcAddress(IcmpDllHandle,"IcmpCloseHandle");
|
||||||
|
IcmpSendEcho2=(pfn_IcmpSendEcho2)GetProcAddress(IcmpDllHandle,"IcmpSendEcho2");
|
||||||
|
return (IcmpCreateFile!=NULL) && (IcmpCloseHandle!=NULL) && (IcmpSendEcho2!=NULL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IcmpDone()
|
||||||
|
{
|
||||||
|
if (IcmpDllHandle!=0)
|
||||||
|
FreeLibrary(IcmpDllHandle);
|
||||||
|
IcmpAvail=false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// RAW Socket Pinger
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
TRawSocketPinger::TRawSocketPinger()
|
||||||
|
{
|
||||||
|
FSocket =socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
|
||||||
|
FId =word(size_t(this));
|
||||||
|
FSeq =0;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
TRawSocketPinger::~TRawSocketPinger()
|
||||||
|
{
|
||||||
|
if (FSocket!=INVALID_SOCKET)
|
||||||
|
{
|
||||||
|
#ifdef OS_WINDOWS
|
||||||
|
closesocket(FSocket);
|
||||||
|
#else
|
||||||
|
close(FSocket);
|
||||||
|
#endif
|
||||||
|
FSocket=INVALID_SOCKET;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
void TRawSocketPinger::InitPacket()
|
||||||
|
{
|
||||||
|
memset(&IcmpBuffer,0,ICmpBufferSize);
|
||||||
|
FSeq++;
|
||||||
|
|
||||||
|
SendPacket=PIcmpPacket(pbyte(&IcmpBuffer)+sizeof(TIPHeader));
|
||||||
|
SendPacket->Header.ic_type=ICMP_ECHORQ;
|
||||||
|
SendPacket->Header.ic_code=0;
|
||||||
|
SendPacket->Header.ic_cksum=0;
|
||||||
|
SendPacket->Header.ic_id=FId;
|
||||||
|
SendPacket->Header.ic_seq=FSeq;
|
||||||
|
|
||||||
|
memset(&SendPacket->Data,0,sizeof(SendPacket->Data));
|
||||||
|
SendPacket->Header.ic_cksum=PacketChecksum();
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
word TRawSocketPinger::PacketChecksum()
|
||||||
|
{
|
||||||
|
word *P = (word*)(SendPacket);
|
||||||
|
longword Sum = 0;
|
||||||
|
int c;
|
||||||
|
for (c = 0; c < int(sizeof(TIcmpPacket) / 2); c++) {
|
||||||
|
Sum+=*P;
|
||||||
|
P++;
|
||||||
|
}
|
||||||
|
Sum=(Sum >> 16) + (Sum & 0xFFFF);
|
||||||
|
Sum=Sum+(Sum >> 16);
|
||||||
|
return word(~Sum);
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
bool TRawSocketPinger::CanRead(int Timeout)
|
||||||
|
{
|
||||||
|
timeval TimeV;
|
||||||
|
int64_t x;
|
||||||
|
fd_set FDset;
|
||||||
|
|
||||||
|
TimeV.tv_usec = (Timeout % 1000) * 1000;
|
||||||
|
TimeV.tv_sec = Timeout / 1000;
|
||||||
|
|
||||||
|
FD_ZERO(&FDset);
|
||||||
|
FD_SET(FSocket, &FDset);
|
||||||
|
|
||||||
|
x = select(FSocket + 1, &FDset, NULL, NULL, &TimeV); //<-Ignore this warning in 64bit Visual Studio
|
||||||
|
if (x==(int)(SOCKET_ERROR))
|
||||||
|
x=0;
|
||||||
|
return (x > 0);
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
bool TRawSocketPinger::Ping(longword ip_addr, int Timeout)
|
||||||
|
{
|
||||||
|
sockaddr_in LSockAddr;
|
||||||
|
sockaddr_in RSockAddr;
|
||||||
|
PIcmpReply Reply;
|
||||||
|
|
||||||
|
if (FSocket==INVALID_SOCKET)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Init packet
|
||||||
|
InitPacket();
|
||||||
|
Reply=PIcmpReply(&IcmpBuffer);
|
||||||
|
// Init Remote and Local Addresses struct
|
||||||
|
RSockAddr.sin_family=AF_INET;
|
||||||
|
RSockAddr.sin_port=0;
|
||||||
|
RSockAddr.sin_addr.s_addr=ip_addr;
|
||||||
|
|
||||||
|
LSockAddr.sin_family=AF_INET;
|
||||||
|
LSockAddr.sin_port=0;
|
||||||
|
LSockAddr.sin_addr.s_addr=inet_addr("0.0.0.0");
|
||||||
|
|
||||||
|
// Bind to local
|
||||||
|
if (bind(FSocket, (struct sockaddr*)&LSockAddr, sizeof(sockaddr_in))!=0)
|
||||||
|
return false;
|
||||||
|
// Connect to remote (not a really TCP connection, only to setup the socket)
|
||||||
|
if (connect(FSocket, (struct sockaddr*)&RSockAddr, sizeof(sockaddr_in))!=0)
|
||||||
|
return false;
|
||||||
|
// Send ICMP packet
|
||||||
|
if (send(FSocket, (char*)SendPacket, sizeof(TIcmpPacket), MSG_NOSIGNAL)!=int(sizeof(TIcmpPacket)))
|
||||||
|
return false;
|
||||||
|
// Wait for a reply
|
||||||
|
if (!CanRead(Timeout))
|
||||||
|
return false;// time expired
|
||||||
|
// Get the answer
|
||||||
|
if (recv(FSocket, (char*)&IcmpBuffer, ICmpBufferSize, MSG_NOSIGNAL)<int(sizeof(TIcmpReply)))
|
||||||
|
return false;
|
||||||
|
// Check the answer
|
||||||
|
return (Reply->IPH.ip_src==RSockAddr.sin_addr.s_addr) && // the peer is what we are looking for
|
||||||
|
(Reply->ICmpReply.Header.ic_type==ICMP_ECHORP); // type = reply
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Pinger
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
TPinger::TPinger()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
TPinger::~TPinger()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
bool TPinger::RawPing(longword ip_addr, int Timeout)
|
||||||
|
{
|
||||||
|
PRawSocketPinger RawPinger = new TRawSocketPinger();
|
||||||
|
bool Result;
|
||||||
|
Result=RawPinger->Ping(ip_addr, Timeout);
|
||||||
|
delete RawPinger;
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
#ifdef OS_WINDOWS
|
||||||
|
bool TPinger::WinPing(longword ip_addr, int Timeout)
|
||||||
|
{
|
||||||
|
HANDLE PingHandle;
|
||||||
|
TTxBuffer TxBuffer;
|
||||||
|
TIcmpBuffer IcmpBuffer;
|
||||||
|
bool Result;
|
||||||
|
|
||||||
|
PingHandle = IcmpCreateFile();
|
||||||
|
if (PingHandle != INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
memset(&TxBuffer,'\55',sizeof(TTxBuffer));
|
||||||
|
Result=(IcmpSendEcho2(PingHandle, NULL, NULL, NULL, ip_addr,
|
||||||
|
&TxBuffer, sizeof(TxBuffer), NULL, &IcmpBuffer, ICmpBufferSize, Timeout))>0;
|
||||||
|
IcmpCloseHandle(PingHandle);
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
bool TPinger::Ping(char *Host, int Timeout)
|
||||||
|
{
|
||||||
|
longword Addr;
|
||||||
|
Addr=inet_addr(Host);
|
||||||
|
return Ping(Addr, Timeout);
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
bool TPinger::Ping(longword ip_addr, int Timeout)
|
||||||
|
{
|
||||||
|
#ifdef OS_WINDOWS
|
||||||
|
if (PingKind==pkWinHelper)
|
||||||
|
return WinPing(ip_addr, Timeout);
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
if (PingKind==pkRawSocket)
|
||||||
|
return RawPing(ip_addr, Timeout);
|
||||||
|
else
|
||||||
|
return true; // we still need to continue
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Checks if raw sockets are allowed
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
bool RawSocketsCheck()
|
||||||
|
{
|
||||||
|
socket_t RawSocket;
|
||||||
|
bool Result;
|
||||||
|
RawSocket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
|
||||||
|
|
||||||
|
Result=RawSocket != INVALID_SOCKET;
|
||||||
|
if (Result)
|
||||||
|
#ifdef OS_WINDOWS
|
||||||
|
closesocket(RawSocket);
|
||||||
|
#else
|
||||||
|
close(RawSocket);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Sockets init
|
||||||
|
// - Winsock Startup (Windows)
|
||||||
|
// - ICMP Helper Load (Windows)
|
||||||
|
// - Check for raw socket (Unix or Windows if ICMP load failed)
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
SocketsLayer::SocketsLayer()
|
||||||
|
{
|
||||||
|
#ifdef OS_WINDOWS
|
||||||
|
timeBeginPeriod(1); // it's not strictly related to socket but here is a nice place
|
||||||
|
WSAStartup(0x202,&wsaData);
|
||||||
|
if (IcmpInit())
|
||||||
|
PingKind=pkWinHelper;
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
if (RawSocketsCheck())
|
||||||
|
PingKind=pkRawSocket;
|
||||||
|
else
|
||||||
|
PingKind=pkCannotPing;
|
||||||
|
}
|
||||||
|
|
||||||
|
SocketsLayer::~SocketsLayer()
|
||||||
|
{
|
||||||
|
#ifdef OS_WINDOWS
|
||||||
|
IcmpDone();
|
||||||
|
WSACleanup();
|
||||||
|
timeEndPeriod(1);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
339
utils/snap7_src/src/sys/snap_msgsock.h
Normal file
339
utils/snap7_src/src/sys/snap_msgsock.h
Normal file
@ -0,0 +1,339 @@
|
|||||||
|
/*=============================================================================|
|
||||||
|
| PROJECT SNAP7 1.3.0 |
|
||||||
|
|==============================================================================|
|
||||||
|
| Copyright (C) 2013, 2015 Davide Nardella |
|
||||||
|
| All rights reserved. |
|
||||||
|
|==============================================================================|
|
||||||
|
| SNAP7 is free software: you can redistribute it and/or modify |
|
||||||
|
| it under the terms of the Lesser GNU General Public License as published by |
|
||||||
|
| the Free Software Foundation, either version 3 of the License, or |
|
||||||
|
| (at your option) any later version. |
|
||||||
|
| |
|
||||||
|
| It means that you can distribute your commercial software linked with |
|
||||||
|
| SNAP7 without the requirement to distribute the source code of your |
|
||||||
|
| application and without the requirement that your application be itself |
|
||||||
|
| distributed under LGPL. |
|
||||||
|
| |
|
||||||
|
| SNAP7 is distributed in the hope that it will be useful, |
|
||||||
|
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||||
|
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
|
| Lesser GNU General Public License for more details. |
|
||||||
|
| |
|
||||||
|
| You should have received a copy of the GNU General Public License and a |
|
||||||
|
| copy of Lesser GNU General Public License along with Snap7. |
|
||||||
|
| If not, see http://www.gnu.org/licenses/ |
|
||||||
|
|=============================================================================*/
|
||||||
|
#ifndef snap_msgsock_h
|
||||||
|
#define snap_msgsock_h
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
#include "snap_platform.h"
|
||||||
|
#include "snap_sysutils.h"
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
#if defined(OS_WINDOWS) || defined (OS_SOLARIS) || defined(OS_OSX)
|
||||||
|
# define MSG_NOSIGNAL 0
|
||||||
|
#endif
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
// Non blocking connection to avoid root priviledges under UNIX
|
||||||
|
// i.e. raw socket pinger is not more used.
|
||||||
|
// Thanks to Rolf Stalder that made it ;)
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
#ifdef PLATFORM_UNIX
|
||||||
|
#define NON_BLOCKING_CONNECT
|
||||||
|
#endif
|
||||||
|
#ifdef NON_BLOCKING_CONNECT
|
||||||
|
#include <fcntl.h>
|
||||||
|
#endif
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
In Windows sizeof socket varies depending of the platform :
|
||||||
|
win32 -> sizeof(SOCKET) = 4
|
||||||
|
win64 -> sizeof(SOCKET) = 8
|
||||||
|
|
||||||
|
Even though sizeof(SOCKET) is 8, should be safe to cast it to int, because
|
||||||
|
the value constitutes an index in per-process table of limited size
|
||||||
|
and not a real pointer.
|
||||||
|
|
||||||
|
Other Os define the socket as int regardless of the processor.
|
||||||
|
|
||||||
|
We want to sleep peacefully, so it's better to define a portable socket.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef OS_WINDOWS
|
||||||
|
typedef SOCKET socket_t;
|
||||||
|
#else
|
||||||
|
typedef int socket_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
#define SD_RECEIVE 0x00
|
||||||
|
#define SD_SEND 0x01
|
||||||
|
#define SD_BOTH 0x02
|
||||||
|
#define MaxPacketSize 65536
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
// For other platform we need to re-define next constants
|
||||||
|
#if defined(PLATFORM_UNIX) || defined(OS_OSX)
|
||||||
|
|
||||||
|
#define INVALID_SOCKET (socket_t)(~0)
|
||||||
|
#define SOCKET_ERROR (-1)
|
||||||
|
|
||||||
|
#define WSAEINTR EINTR
|
||||||
|
#define WSAEBADF EBADF
|
||||||
|
#define WSAEACCES EACCES
|
||||||
|
#define WSAEFAULT EFAULT
|
||||||
|
#define WSAEINVAL EINVAL
|
||||||
|
#define WSAEMFILE EMFILE
|
||||||
|
#define WSAEWOULDBLOCK EWOULDBLOCK
|
||||||
|
#define WSAEINPROGRESS EINPROGRESS
|
||||||
|
#define WSAEALREADY EALREADY
|
||||||
|
#define WSAENOTSOCK ENOTSOCK
|
||||||
|
#define WSAEDESTADDRREQ EDESTADDRREQ
|
||||||
|
#define WSAEMSGSIZE EMSGSIZE
|
||||||
|
#define WSAEPROTOTYPE EPROTOTYPE
|
||||||
|
#define WSAENOPROTOOPT ENOPROTOOPT
|
||||||
|
#define WSAEPROTONOSUPPORT EPROTONOSUPPORT
|
||||||
|
#define WSAESOCKTNOSUPPORT ESOCKTNOSUPPORT
|
||||||
|
#define WSAEOPNOTSUPP EOPNOTSUPP
|
||||||
|
#define WSAEPFNOSUPPORT EPFNOSUPPORT
|
||||||
|
#define WSAEAFNOSUPPORT EAFNOSUPPORT
|
||||||
|
#define WSAEADDRINUSE EADDRINUSE
|
||||||
|
#define WSAEADDRNOTAVAIL EADDRNOTAVAIL
|
||||||
|
#define WSAENETDOWN ENETDOWN
|
||||||
|
#define WSAENETUNREACH ENETUNREACH
|
||||||
|
#define WSAENETRESET ENETRESET
|
||||||
|
#define WSAECONNABORTED ECONNABORTED
|
||||||
|
#define WSAECONNRESET ECONNRESET
|
||||||
|
#define WSAENOBUFS ENOBUFS
|
||||||
|
#define WSAEISCONN EISCONN
|
||||||
|
#define WSAENOTCONN ENOTCONN
|
||||||
|
#define WSAESHUTDOWN ESHUTDOWN
|
||||||
|
#define WSAETOOMANYREFS ETOOMANYREFS
|
||||||
|
#define WSAETIMEDOUT ETIMEDOUT
|
||||||
|
#define WSAECONNREFUSED ECONNREFUSED
|
||||||
|
#define WSAELOOP ELOOP
|
||||||
|
#define WSAENAMETOOLONG ENAMETOOLONG
|
||||||
|
#define WSAEHOSTDOWN EHOSTDOWN
|
||||||
|
#define WSAEHOSTUNREACH EHOSTUNREACH
|
||||||
|
#define WSAENOTEMPTY ENOTEMPTY
|
||||||
|
#define WSAEUSERS EUSERS
|
||||||
|
#define WSAEDQUOT EDQUOT
|
||||||
|
#define WSAESTALE ESTALE
|
||||||
|
#define WSAEREMOTE EREMOTE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define WSAEINVALIDADDRESS 12001
|
||||||
|
|
||||||
|
#define ICmpBufferSize 4096
|
||||||
|
typedef byte TIcmpBuffer[ICmpBufferSize];
|
||||||
|
|
||||||
|
// Ping result
|
||||||
|
#define PR_CANNOT_PERFORM -1 // cannot ping :
|
||||||
|
// unix : no root rights or SUID flag set to
|
||||||
|
// open raw sockets
|
||||||
|
// windows : neither helper DLL found nor raw
|
||||||
|
// sockets can be opened (no administrator rights)
|
||||||
|
// In this case the execution continues whitout
|
||||||
|
// the benefit of the smart-connect.
|
||||||
|
|
||||||
|
#define PR_SUCCESS 0 // Host found
|
||||||
|
#define PR_ERROR 1 // Ping Error, Ping was performed but ...
|
||||||
|
// - host didn't replied (not found)
|
||||||
|
// - routing error
|
||||||
|
// - TTL expired
|
||||||
|
// - ... all other icmp error that we don't need
|
||||||
|
// to know.
|
||||||
|
|
||||||
|
// Ping Kind
|
||||||
|
#define pkCannotPing 1 // see PR_CANNOT_PERFORM comments
|
||||||
|
#define pkWinHelper 2 // use iphlpapi.dll (only windows)
|
||||||
|
#define pkRawSocket 3 // use raw sockets (unix/windows)
|
||||||
|
|
||||||
|
const byte ICMP_ECHORP = 0; // ECHO Reply
|
||||||
|
const byte ICMP_ECHORQ = 8; // ECHO Request
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// RAW SOCKET PING STRUCTS
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
#pragma pack(1)
|
||||||
|
typedef struct{
|
||||||
|
byte ip_hl_v;
|
||||||
|
byte ip_tos;
|
||||||
|
word ip_len;
|
||||||
|
word ip_id ;
|
||||||
|
word ip_off;
|
||||||
|
byte ip_ttl;
|
||||||
|
byte ip_p;
|
||||||
|
word ip_sum;
|
||||||
|
longword ip_src;
|
||||||
|
longword ip_dst;
|
||||||
|
}TIPHeader;
|
||||||
|
|
||||||
|
typedef struct{
|
||||||
|
byte ic_type; // Type of message
|
||||||
|
byte ic_code; // Code
|
||||||
|
word ic_cksum; // 16 bit checksum
|
||||||
|
word ic_id; // ID (ic1 : ipv4)
|
||||||
|
word ic_seq; // Sequence
|
||||||
|
}TIcmpHeader;
|
||||||
|
|
||||||
|
typedef struct{
|
||||||
|
TIcmpHeader Header;
|
||||||
|
byte Data[32]; // use the well known default
|
||||||
|
}TIcmpPacket, *PIcmpPacket;
|
||||||
|
|
||||||
|
typedef struct{
|
||||||
|
TIPHeader IPH;
|
||||||
|
TIcmpPacket ICmpReply;
|
||||||
|
}TIcmpReply, *PIcmpReply;
|
||||||
|
#pragma pack()
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
class TRawSocketPinger
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
socket_t FSocket;
|
||||||
|
PIcmpPacket SendPacket;
|
||||||
|
TIcmpBuffer IcmpBuffer;
|
||||||
|
word FId, FSeq;
|
||||||
|
void InitPacket();
|
||||||
|
word PacketChecksum();
|
||||||
|
bool CanRead(int Timeout);
|
||||||
|
public:
|
||||||
|
bool Ping(longword ip_addr, int Timeout);
|
||||||
|
TRawSocketPinger();
|
||||||
|
~TRawSocketPinger();
|
||||||
|
};
|
||||||
|
typedef TRawSocketPinger *PRawSocketPinger;
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
class TPinger
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
PRawSocketPinger RawPinger;
|
||||||
|
bool RawAvail;
|
||||||
|
#ifdef OS_WINDOWS
|
||||||
|
bool WinPing(longword ip_addr, int Timeout);
|
||||||
|
#endif
|
||||||
|
bool RawPing(longword ip_addr, int Timeout);
|
||||||
|
public:
|
||||||
|
TPinger();
|
||||||
|
~TPinger();
|
||||||
|
bool Ping(char *Host, int Timeout);
|
||||||
|
bool Ping(longword ip_addr, int Timeout);
|
||||||
|
};
|
||||||
|
typedef TPinger *PPinger;
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
class TSnapBase // base class endian-aware
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
bool LittleEndian;
|
||||||
|
protected:
|
||||||
|
longword SwapDWord(longword Value);
|
||||||
|
word SwapWord(word Value);
|
||||||
|
public:
|
||||||
|
TSnapBase();
|
||||||
|
};
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
class TMsgSocket : public TSnapBase
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
PPinger Pinger;
|
||||||
|
int GetLastSocketError();
|
||||||
|
int SockCheck(int SockResult);
|
||||||
|
void DestroySocket();
|
||||||
|
void SetSocketOptions();
|
||||||
|
bool CanWrite(int Timeout);
|
||||||
|
void GetLocal();
|
||||||
|
void GetRemote();
|
||||||
|
void SetSin(sockaddr_in &sin, char *Address, u_short Port);
|
||||||
|
void GetSin(sockaddr_in sin, char *Address, u_short &Port);
|
||||||
|
protected:
|
||||||
|
socket_t FSocket;
|
||||||
|
sockaddr_in LocalSin;
|
||||||
|
sockaddr_in RemoteSin;
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
// low level socket
|
||||||
|
void CreateSocket();
|
||||||
|
// Called when a socket is assigned externally
|
||||||
|
void GotSocket();
|
||||||
|
// Returns how many bytes are ready to be read in the winsock buffer
|
||||||
|
int WaitingData();
|
||||||
|
// Waits until there at least "size" bytes ready to be read or until receive timeout occurs
|
||||||
|
int WaitForData(int Size, int Timeout);
|
||||||
|
// Clear socket input buffer
|
||||||
|
void Purge();
|
||||||
|
public:
|
||||||
|
longword ClientHandle;
|
||||||
|
longword LocalBind;
|
||||||
|
// Coordinates Address:Port
|
||||||
|
char LocalAddress[16];
|
||||||
|
char RemoteAddress[16];
|
||||||
|
word LocalPort;
|
||||||
|
word RemotePort;
|
||||||
|
// "speed" of the socket listener (used server-side)
|
||||||
|
int WorkInterval;
|
||||||
|
// Timeouts : 3 different values for fine tuning.
|
||||||
|
// Send timeout should be small since with work with small packets and TCP_NO_DELAY
|
||||||
|
// option, so we don't expect "time to wait".
|
||||||
|
// Recv timeout depends of equipment's processing time : we send a packet, the equipment
|
||||||
|
// processes the message, finally it sends the answer. In any case Recv timeout > Send Timeout.
|
||||||
|
// PingTimeout is the maximum time interval during which we expect that the PLC answers.
|
||||||
|
// By default is 750 ms, increase it if there are many switch/repeaters.
|
||||||
|
int PingTimeout;
|
||||||
|
int RecvTimeout;
|
||||||
|
int SendTimeout;
|
||||||
|
//int ConnTimeout;
|
||||||
|
// Output : Last operation error
|
||||||
|
int LastTcpError;
|
||||||
|
// Output : Connected to the remote Host/Peer/Client
|
||||||
|
bool Connected;
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
TMsgSocket();
|
||||||
|
virtual ~TMsgSocket();
|
||||||
|
// Returns true if "something" can be read during the Timeout interval..
|
||||||
|
bool CanRead(int Timeout);
|
||||||
|
// Connects to a peer (using RemoteAddress and RemotePort)
|
||||||
|
int SckConnect(); // (client-side)
|
||||||
|
// Disconnects from a peer (gracefully)
|
||||||
|
void SckDisconnect();
|
||||||
|
// Disconnects RAW
|
||||||
|
void ForceClose();
|
||||||
|
// Binds to a local adapter (using LocalAddress and LocalPort) (server-side)
|
||||||
|
int SckBind();
|
||||||
|
// Listens for an incoming connection (server-side)
|
||||||
|
int SckListen();
|
||||||
|
// Set an external socket reference (tipically from a listener)
|
||||||
|
void SetSocket(socket_t s);
|
||||||
|
// Accepts an incoming connection returning a socket descriptor (server-side)
|
||||||
|
socket_t SckAccept();
|
||||||
|
// Pings the peer before connecting
|
||||||
|
bool Ping(char *Host);
|
||||||
|
bool Ping(sockaddr_in Addr);
|
||||||
|
// Sends a packet
|
||||||
|
int SendPacket(void *Data, int Size);
|
||||||
|
// Returns true if a Packet at least of "Size" bytes is ready to be read
|
||||||
|
bool PacketReady(int Size);
|
||||||
|
// Receives everything
|
||||||
|
int Receive(void *Data, int BufSize, int & SizeRecvd);
|
||||||
|
// Receives a packet of size specified.
|
||||||
|
int RecvPacket(void *Data, int Size);
|
||||||
|
// Peeks a packet of size specified without extract it from the socket queue
|
||||||
|
int PeekPacket(void *Data, int Size);
|
||||||
|
virtual bool Execute();
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef TMsgSocket *PMsgSocket;
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
void Msg_CloseSocket(socket_t FSocket);
|
||||||
|
longword Msg_GetSockAddr(socket_t FSocket);
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
class SocketsLayer
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
#ifdef OS_WINDOWS
|
||||||
|
WSADATA wsaData;
|
||||||
|
#endif
|
||||||
|
public:
|
||||||
|
SocketsLayer();
|
||||||
|
~SocketsLayer();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // snap_msgsock_h
|
152
utils/snap7_src/src/sys/snap_platform.h
Normal file
152
utils/snap7_src/src/sys/snap_platform.h
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
/*=============================================================================|
|
||||||
|
| PROJECT SNAP7 1.4.1 |
|
||||||
|
|==============================================================================|
|
||||||
|
| Copyright (C) 2013, 2015 Davide Nardella |
|
||||||
|
| All rights reserved. |
|
||||||
|
|==============================================================================|
|
||||||
|
| SNAP7 is free software: you can redistribute it and/or modify |
|
||||||
|
| it under the terms of the Lesser GNU General Public License as published by |
|
||||||
|
| the Free Software Foundation, either version 3 of the License, or |
|
||||||
|
| (at your option) any later version. |
|
||||||
|
| |
|
||||||
|
| It means that you can distribute your commercial software linked with |
|
||||||
|
| SNAP7 without the requirement to distribute the source code of your |
|
||||||
|
| application and without the requirement that your application be itself |
|
||||||
|
| distributed under LGPL. |
|
||||||
|
| |
|
||||||
|
| SNAP7 is distributed in the hope that it will be useful, |
|
||||||
|
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||||
|
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
|
| Lesser GNU General Public License for more details. |
|
||||||
|
| |
|
||||||
|
| You should have received a copy of the GNU General Public License and a |
|
||||||
|
| copy of Lesser GNU General Public License along with Snap7. |
|
||||||
|
| If not, see http://www.gnu.org/licenses/ |
|
||||||
|
|=============================================================================*/
|
||||||
|
#ifndef snap_platform_h
|
||||||
|
#define snap_platform_h
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
#if defined (_WIN32)|| defined(_WIN64)|| defined(__WIN32__) || defined(__WINDOWS__)
|
||||||
|
# define OS_WINDOWS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Visual Studio needs this to use the correct time_t size
|
||||||
|
#if defined (_WIN32) && !defined(_WIN64) && !defined(_EMBEDDING_VS2013UP)
|
||||||
|
# define _USE_32BIT_TIME_T
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Linux, BSD and Solaris define "unix", OSX doesn't, even though it derives from BSD
|
||||||
|
#if defined(unix) || defined(__unix__) || defined(__unix)
|
||||||
|
# define PLATFORM_UNIX
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if BSD>=0
|
||||||
|
# define OS_BSD
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __APPLE__
|
||||||
|
# define OS_OSX
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__SVR4) || defined(__svr4__)
|
||||||
|
# define OS_SOLARIS
|
||||||
|
// Thanks to Rolf Stalder now it's possible to use pthreads also for Solaris
|
||||||
|
// In any case the Solaris native threads model is still present and can be
|
||||||
|
// used uncommenting the #define line below.
|
||||||
|
# undef OS_SOLARIS_NATIVE_THREADS
|
||||||
|
// # define OS_SOLARIS_NATIVE_THREADS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PLATFORM_UNIX)
|
||||||
|
# include <unistd.h>
|
||||||
|
# include <sys/param.h>
|
||||||
|
# if defined(_POSIX_VERSION)
|
||||||
|
# define POSIX
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef OS_OSX
|
||||||
|
# include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (!defined (OS_WINDOWS)) && (!defined(PLATFORM_UNIX)) && (!defined(OS_BSD)) && (!defined(OS_OSX))
|
||||||
|
# error platform still unsupported (please add it yourself and report ;-)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Visual C++ not C99 compliant (VS2008--)
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
# if _MSC_VER >= 1600
|
||||||
|
# include <stdint.h> // VS2010++ have it
|
||||||
|
# else
|
||||||
|
typedef signed __int8 int8_t;
|
||||||
|
typedef signed __int16 int16_t;
|
||||||
|
typedef signed __int32 int32_t;
|
||||||
|
typedef signed __int64 int64_t;
|
||||||
|
typedef unsigned __int8 uint8_t;
|
||||||
|
typedef unsigned __int16 uint16_t;
|
||||||
|
typedef unsigned __int32 uint32_t;
|
||||||
|
typedef unsigned __int64 uint64_t;
|
||||||
|
#ifdef _WIN64
|
||||||
|
typedef unsigned __int64 uintptr_t;
|
||||||
|
#else
|
||||||
|
typedef unsigned __int32 uintptr_t;
|
||||||
|
#endif
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# include <stdint.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
#include <cstring>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#ifdef OS_WINDOWS
|
||||||
|
# define WIN32_LEAN_AND_MEAN
|
||||||
|
# include <windows.h>
|
||||||
|
# include <winsock2.h>
|
||||||
|
# include <mmsystem.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef OS_SOLARIS
|
||||||
|
# include <sys/filio.h>
|
||||||
|
# include <cstdlib>
|
||||||
|
# include <string.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PLATFORM_UNIX) || defined(OS_OSX)
|
||||||
|
# include <errno.h>
|
||||||
|
# include <sys/time.h>
|
||||||
|
# include <sys/socket.h>
|
||||||
|
# include <arpa/inet.h>
|
||||||
|
# include <netinet/tcp.h>
|
||||||
|
# include <netinet/in.h>
|
||||||
|
# include <sys/ioctl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef OS_WINDOWS
|
||||||
|
# define EXPORTSPEC extern "C" __declspec ( dllexport )
|
||||||
|
# define S7API __stdcall
|
||||||
|
#else
|
||||||
|
# define EXPORTSPEC extern "C"
|
||||||
|
# define S7API
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Exact length types regardless of platform/processor
|
||||||
|
// We absolute need of them, all structs have an exact size that
|
||||||
|
// must be the same across the processor used 32/64 bit
|
||||||
|
|
||||||
|
// *Use them* if you change/expand the code and avoid long, u_long and so on...
|
||||||
|
|
||||||
|
typedef uint8_t byte;
|
||||||
|
typedef uint16_t word;
|
||||||
|
typedef uint32_t longword;
|
||||||
|
typedef byte *pbyte;
|
||||||
|
typedef word *pword;
|
||||||
|
typedef uintptr_t snap_obj; // multi platform/processor object reference
|
||||||
|
|
||||||
|
#ifndef OS_WINDOWS
|
||||||
|
# define INFINITE 0XFFFFFFFF
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif // snap_platform_h
|
73
utils/snap7_src/src/sys/snap_sysutils.cpp
Normal file
73
utils/snap7_src/src/sys/snap_sysutils.cpp
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
/*=============================================================================|
|
||||||
|
| PROJECT SNAP7 1.3.0 |
|
||||||
|
|==============================================================================|
|
||||||
|
| Copyright (C) 2013, 2015 Davide Nardella |
|
||||||
|
| All rights reserved. |
|
||||||
|
|==============================================================================|
|
||||||
|
| SNAP7 is free software: you can redistribute it and/or modify |
|
||||||
|
| it under the terms of the Lesser GNU General Public License as published by |
|
||||||
|
| the Free Software Foundation, either version 3 of the License, or |
|
||||||
|
| (at your option) any later version. |
|
||||||
|
| |
|
||||||
|
| It means that you can distribute your commercial software linked with |
|
||||||
|
| SNAP7 without the requirement to distribute the source code of your |
|
||||||
|
| application and without the requirement that your application be itself |
|
||||||
|
| distributed under LGPL. |
|
||||||
|
| |
|
||||||
|
| SNAP7 is distributed in the hope that it will be useful, |
|
||||||
|
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||||
|
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
|
| Lesser GNU General Public License for more details. |
|
||||||
|
| |
|
||||||
|
| You should have received a copy of the GNU General Public License and a |
|
||||||
|
| copy of Lesser GNU General Public License along with Snap7. |
|
||||||
|
| If not, see http://www.gnu.org/licenses/ |
|
||||||
|
|=============================================================================*/
|
||||||
|
|
||||||
|
#include "snap_sysutils.h"
|
||||||
|
|
||||||
|
#ifdef OS_OSX
|
||||||
|
int clock_gettime(int clk_id, struct timespec* t)
|
||||||
|
{
|
||||||
|
struct timeval now;
|
||||||
|
int rv = gettimeofday(&now, NULL);
|
||||||
|
if (rv) return rv;
|
||||||
|
t->tv_sec = now.tv_sec;
|
||||||
|
t->tv_nsec = now.tv_usec * 1000;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
longword SysGetTick()
|
||||||
|
{
|
||||||
|
#ifdef OS_WINDOWS
|
||||||
|
return timeGetTime();
|
||||||
|
#else
|
||||||
|
struct timespec ts;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||||
|
return (longword) (ts.tv_sec * 1000) + (ts.tv_nsec / 1000000);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
void SysSleep(longword Delay_ms)
|
||||||
|
{
|
||||||
|
#ifdef OS_WINDOWS
|
||||||
|
Sleep(Delay_ms);
|
||||||
|
#else
|
||||||
|
struct timespec ts;
|
||||||
|
ts.tv_sec = (time_t)(Delay_ms / 1000);
|
||||||
|
ts.tv_nsec =(long)((Delay_ms - ts.tv_sec) * 1000000);
|
||||||
|
nanosleep(&ts, (struct timespec *)0);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
longword DeltaTime(longword &Elapsed)
|
||||||
|
{
|
||||||
|
longword TheTime;
|
||||||
|
TheTime=SysGetTick();
|
||||||
|
// Checks for rollover
|
||||||
|
if (TheTime<Elapsed)
|
||||||
|
Elapsed=0;
|
||||||
|
return TheTime-Elapsed;
|
||||||
|
}
|
39
utils/snap7_src/src/sys/snap_sysutils.h
Normal file
39
utils/snap7_src/src/sys/snap_sysutils.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
/*=============================================================================|
|
||||||
|
| PROJECT SNAP7 1.3.0 |
|
||||||
|
|==============================================================================|
|
||||||
|
| Copyright (C) 2013, 2015 Davide Nardella |
|
||||||
|
| All rights reserved. |
|
||||||
|
|==============================================================================|
|
||||||
|
| SNAP7 is free software: you can redistribute it and/or modify |
|
||||||
|
| it under the terms of the Lesser GNU General Public License as published by |
|
||||||
|
| the Free Software Foundation, either version 3 of the License, or |
|
||||||
|
| (at your option) any later version. |
|
||||||
|
| |
|
||||||
|
| It means that you can distribute your commercial software linked with |
|
||||||
|
| SNAP7 without the requirement to distribute the source code of your |
|
||||||
|
| application and without the requirement that your application be itself |
|
||||||
|
| distributed under LGPL. |
|
||||||
|
| |
|
||||||
|
| SNAP7 is distributed in the hope that it will be useful, |
|
||||||
|
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||||
|
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
|
| Lesser GNU General Public License for more details. |
|
||||||
|
| |
|
||||||
|
| You should have received a copy of the GNU General Public License and a |
|
||||||
|
| copy of Lesser GNU General Public License along with Snap7. |
|
||||||
|
| If not, see http://www.gnu.org/licenses/ |
|
||||||
|
|=============================================================================*/
|
||||||
|
#ifndef snap_sysutils_h
|
||||||
|
#define snap_sysutils_h
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
#include "snap_platform.h"
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
#ifdef OS_OSX
|
||||||
|
# define CLOCK_MONOTONIC 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
longword SysGetTick();
|
||||||
|
void SysSleep(longword Delay_ms);
|
||||||
|
longword DeltaTime(longword &Elapsed);
|
||||||
|
|
||||||
|
#endif // snap_sysutils_h
|
487
utils/snap7_src/src/sys/snap_tcpsrvr.cpp
Normal file
487
utils/snap7_src/src/sys/snap_tcpsrvr.cpp
Normal file
@ -0,0 +1,487 @@
|
|||||||
|
/*=============================================================================|
|
||||||
|
| PROJECT SNAP7 1.3.0 |
|
||||||
|
|==============================================================================|
|
||||||
|
| Copyright (C) 2013, 2015 Davide Nardella |
|
||||||
|
| All rights reserved. |
|
||||||
|
|==============================================================================|
|
||||||
|
| SNAP7 is free software: you can redistribute it and/or modify |
|
||||||
|
| it under the terms of the Lesser GNU General Public License as published by |
|
||||||
|
| the Free Software Foundation, either version 3 of the License, or |
|
||||||
|
| (at your option) any later version. |
|
||||||
|
| |
|
||||||
|
| It means that you can distribute your commercial software linked with |
|
||||||
|
| SNAP7 without the requirement to distribute the source code of your |
|
||||||
|
| application and without the requirement that your application be itself |
|
||||||
|
| distributed under LGPL. |
|
||||||
|
| |
|
||||||
|
| SNAP7 is distributed in the hope that it will be useful, |
|
||||||
|
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||||
|
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
|
| Lesser GNU General Public License for more details. |
|
||||||
|
| |
|
||||||
|
| You should have received a copy of the GNU General Public License and a |
|
||||||
|
| copy of Lesser GNU General Public License along with Snap7. |
|
||||||
|
| If not, see http://www.gnu.org/licenses/ |
|
||||||
|
|=============================================================================*/
|
||||||
|
|
||||||
|
#include "snap_tcpsrvr.h"
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// EVENTS QUEUE
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
TMsgEventQueue::TMsgEventQueue(const int Capacity, const int BlockSize)
|
||||||
|
{
|
||||||
|
FCapacity = Capacity;
|
||||||
|
Max = FCapacity - 1;
|
||||||
|
FBlockSize = BlockSize;
|
||||||
|
Buffer = new byte[FCapacity * FBlockSize];
|
||||||
|
Flush();
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
TMsgEventQueue::~TMsgEventQueue()
|
||||||
|
{
|
||||||
|
delete[] Buffer;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
void TMsgEventQueue::Flush()
|
||||||
|
{
|
||||||
|
IndexIn = 0;
|
||||||
|
IndexOut = 0;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
void TMsgEventQueue::Insert(void *lpdata)
|
||||||
|
{
|
||||||
|
pbyte PBlock;
|
||||||
|
if (!Full())
|
||||||
|
{
|
||||||
|
// Calc offset
|
||||||
|
if (IndexIn < Max) IndexIn++;
|
||||||
|
else IndexIn = 0;
|
||||||
|
PBlock = Buffer + uintptr_t(IndexIn * FBlockSize);
|
||||||
|
memcpy(PBlock, lpdata, FBlockSize);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
bool TMsgEventQueue::Extract(void *lpdata)
|
||||||
|
{
|
||||||
|
int IdxOut;
|
||||||
|
pbyte PBlock;
|
||||||
|
|
||||||
|
if (!Empty())
|
||||||
|
{
|
||||||
|
// stores IndexOut
|
||||||
|
IdxOut = IndexOut;
|
||||||
|
if (IdxOut < Max) IdxOut++;
|
||||||
|
else IdxOut = 0;
|
||||||
|
PBlock = Buffer + uintptr_t(IdxOut * FBlockSize);
|
||||||
|
// moves data
|
||||||
|
memcpy(lpdata, PBlock, FBlockSize);
|
||||||
|
// Updates IndexOut
|
||||||
|
IndexOut = IdxOut;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
bool TMsgEventQueue::Empty()
|
||||||
|
{
|
||||||
|
return (IndexIn == IndexOut);
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
bool TMsgEventQueue::Full()
|
||||||
|
{
|
||||||
|
int IdxOut = IndexOut; // To avoid troubles if IndexOut changes during next line
|
||||||
|
return ( (IdxOut == IndexIn + 1) || ((IndexIn == Max) && (IdxOut == 0)));
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// WORKER THREAD
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
TMsgWorkerThread::TMsgWorkerThread(TMsgSocket *Socket, TCustomMsgServer *Server)
|
||||||
|
{
|
||||||
|
FreeOnTerminate = true;
|
||||||
|
WorkerSocket = Socket;
|
||||||
|
FServer = Server;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
void TMsgWorkerThread::Execute()
|
||||||
|
{
|
||||||
|
bool Exception = false;
|
||||||
|
bool SelfClose = false;
|
||||||
|
// Working loop
|
||||||
|
while (!Terminated && !SelfClose && !Exception && !FServer->Destroying)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!WorkerSocket->Execute()) // False -> End of Activities
|
||||||
|
SelfClose = true;
|
||||||
|
} catch (...)
|
||||||
|
{
|
||||||
|
Exception = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (!FServer->Destroying)
|
||||||
|
{
|
||||||
|
// Exception detected during Worker activity
|
||||||
|
if (Exception)
|
||||||
|
{
|
||||||
|
WorkerSocket->ForceClose();
|
||||||
|
FServer->DoEvent(WorkerSocket->ClientHandle, evcClientException, 0, 0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (SelfClose)
|
||||||
|
{
|
||||||
|
FServer->DoEvent(WorkerSocket->ClientHandle, evcClientDisconnected, 0, 0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
FServer->DoEvent(WorkerSocket->ClientHandle, evcClientTerminated, 0, 0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
delete WorkerSocket;
|
||||||
|
// Delete reference from list
|
||||||
|
FServer->Delete(Index);
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// LISTENER THREAD
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
TMsgListenerThread::TMsgListenerThread(TMsgSocket *Listener, TCustomMsgServer *Server)
|
||||||
|
{
|
||||||
|
FServer = Server;
|
||||||
|
FListener = Listener;
|
||||||
|
FreeOnTerminate = false;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void TMsgListenerThread::Execute()
|
||||||
|
{
|
||||||
|
socket_t Sock;
|
||||||
|
bool Valid;
|
||||||
|
|
||||||
|
while (!Terminated)
|
||||||
|
{
|
||||||
|
if (FListener->CanRead(FListener->WorkInterval))
|
||||||
|
{
|
||||||
|
Sock = FListener->SckAccept(); // in any case we must accept
|
||||||
|
Valid = Sock != INVALID_SOCKET;
|
||||||
|
// check if we are not destroying
|
||||||
|
if ((!Terminated) && (!FServer->Destroying))
|
||||||
|
{
|
||||||
|
if (Valid)
|
||||||
|
FServer->Incoming(Sock);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (Valid)
|
||||||
|
Msg_CloseSocket(Sock);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// TCP SERVER
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
TCustomMsgServer::TCustomMsgServer()
|
||||||
|
{
|
||||||
|
strcpy(FLocalAddress, "0.0.0.0");
|
||||||
|
CSList = new TSnapCriticalSection();
|
||||||
|
CSEvent = new TSnapCriticalSection();
|
||||||
|
FEventQueue = new TMsgEventQueue(MaxEvents, sizeof (TSrvEvent));
|
||||||
|
memset(Workers, 0, sizeof (Workers));
|
||||||
|
for (int i = 0; i < MaxWorkers; i++)
|
||||||
|
Workers[i] = NULL;
|
||||||
|
Status = SrvStopped;
|
||||||
|
EventMask = 0xFFFFFFFF;
|
||||||
|
LogMask = 0xFFFFFFFF;
|
||||||
|
Destroying = false;
|
||||||
|
FLastError = 0;
|
||||||
|
ClientsCount = 0;
|
||||||
|
LocalBind = 0;
|
||||||
|
MaxClients = MaxWorkers;
|
||||||
|
OnEvent = NULL;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
TCustomMsgServer::~TCustomMsgServer()
|
||||||
|
{
|
||||||
|
Destroying = true;
|
||||||
|
Stop();
|
||||||
|
OnEvent = NULL;
|
||||||
|
delete CSList;
|
||||||
|
delete CSEvent;
|
||||||
|
delete FEventQueue;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
void TCustomMsgServer::LockList()
|
||||||
|
{
|
||||||
|
CSList->Enter();
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
void TCustomMsgServer::UnlockList()
|
||||||
|
{
|
||||||
|
CSList->Leave();
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
int TCustomMsgServer::FirstFree()
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < MaxWorkers; i++)
|
||||||
|
{
|
||||||
|
if (Workers[i] == 0)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
int TCustomMsgServer::StartListener()
|
||||||
|
{
|
||||||
|
int Result;
|
||||||
|
// Creates the listener
|
||||||
|
SockListener = new TMsgSocket();
|
||||||
|
strncpy(SockListener->LocalAddress, FLocalAddress, 16);
|
||||||
|
SockListener->LocalPort = LocalPort;
|
||||||
|
// Binds
|
||||||
|
Result = SockListener->SckBind();
|
||||||
|
if (Result == 0)
|
||||||
|
{
|
||||||
|
LocalBind = SockListener->LocalBind;
|
||||||
|
// Listen
|
||||||
|
Result = SockListener->SckListen();
|
||||||
|
if (Result == 0)
|
||||||
|
{
|
||||||
|
// Creates the Listener thread
|
||||||
|
ServerThread = new TMsgListenerThread(SockListener, this);
|
||||||
|
ServerThread->Start();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
delete SockListener;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
delete SockListener;
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
void TCustomMsgServer::TerminateAll()
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
longword Elapsed;
|
||||||
|
bool Timeout;
|
||||||
|
|
||||||
|
if (ClientsCount > 0)
|
||||||
|
{
|
||||||
|
for (c = 0; c < MaxWorkers; c++)
|
||||||
|
{
|
||||||
|
if (Workers[c] != 0)
|
||||||
|
PMsgWorkerThread(Workers[c])->Terminate();
|
||||||
|
}
|
||||||
|
// Wait for closing
|
||||||
|
Elapsed = SysGetTick();
|
||||||
|
Timeout = false;
|
||||||
|
while (!Timeout && (ClientsCount > 0))
|
||||||
|
{
|
||||||
|
Timeout = DeltaTime(Elapsed) > WkTimeout;
|
||||||
|
if (!Timeout)
|
||||||
|
SysSleep(100);
|
||||||
|
};
|
||||||
|
if (ClientsCount > 0)
|
||||||
|
KillAll(); // one o more threads are hanged
|
||||||
|
ClientsCount = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
void TCustomMsgServer::KillAll()
|
||||||
|
{
|
||||||
|
int c, cnt = 0;
|
||||||
|
LockList();
|
||||||
|
for (c = 0; c < MaxWorkers; c++)
|
||||||
|
{
|
||||||
|
if (Workers[c] != 0)
|
||||||
|
try
|
||||||
|
{
|
||||||
|
PMsgWorkerThread(Workers[c])->Kill();
|
||||||
|
PMsgWorkerThread(Workers[c])->WorkerSocket->ForceClose();
|
||||||
|
delete PMsgWorkerThread(Workers[c]);
|
||||||
|
Workers[c] = 0;
|
||||||
|
cnt++;
|
||||||
|
} catch (...)
|
||||||
|
{
|
||||||
|
};
|
||||||
|
}
|
||||||
|
UnlockList();
|
||||||
|
DoEvent(0, evcClientsDropped, 0, cnt, 0, 0, 0);
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
bool TCustomMsgServer::CanAccept(socket_t Socket)
|
||||||
|
{
|
||||||
|
return ((MaxClients == 0) || (ClientsCount < MaxClients));
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
PWorkerSocket TCustomMsgServer::CreateWorkerSocket(socket_t Sock)
|
||||||
|
{
|
||||||
|
PWorkerSocket Result;
|
||||||
|
// Creates a funny default class : a tcp echo worker
|
||||||
|
Result = new TEcoTcpWorker();
|
||||||
|
Result->SetSocket(Sock);
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
void TCustomMsgServer::DoEvent(int Sender, longword Code, word RetCode, word Param1, word Param2, word Param3, word Param4)
|
||||||
|
{
|
||||||
|
TSrvEvent SrvEvent;
|
||||||
|
bool GoLog = (Code & LogMask) != 0;
|
||||||
|
bool GoEvent = (Code & EventMask) != 0;
|
||||||
|
|
||||||
|
if (!Destroying && (GoLog || GoEvent))
|
||||||
|
{
|
||||||
|
CSEvent->Enter();
|
||||||
|
|
||||||
|
time(&SrvEvent.EvtTime);
|
||||||
|
SrvEvent.EvtSender = Sender;
|
||||||
|
SrvEvent.EvtCode = Code;
|
||||||
|
SrvEvent.EvtRetCode = RetCode;
|
||||||
|
SrvEvent.EvtParam1 = Param1;
|
||||||
|
SrvEvent.EvtParam2 = Param2;
|
||||||
|
SrvEvent.EvtParam3 = Param3;
|
||||||
|
SrvEvent.EvtParam4 = Param4;
|
||||||
|
|
||||||
|
if (GoEvent && (OnEvent != NULL))
|
||||||
|
try
|
||||||
|
{ // callback is outside here, we have to shield it
|
||||||
|
OnEvent(FUsrPtr, &SrvEvent, sizeof (TSrvEvent));
|
||||||
|
} catch (...)
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
if (GoLog)
|
||||||
|
FEventQueue->Insert(&SrvEvent);
|
||||||
|
|
||||||
|
CSEvent->Leave();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
void TCustomMsgServer::Delete(int Index)
|
||||||
|
{
|
||||||
|
LockList();
|
||||||
|
Workers[Index] = 0;
|
||||||
|
ClientsCount--;
|
||||||
|
UnlockList();
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
void TCustomMsgServer::Incoming(socket_t Sock)
|
||||||
|
{
|
||||||
|
int idx;
|
||||||
|
PWorkerSocket WorkerSocket;
|
||||||
|
longword ClientHandle = Msg_GetSockAddr(Sock);
|
||||||
|
|
||||||
|
if (CanAccept(Sock))
|
||||||
|
{
|
||||||
|
LockList();
|
||||||
|
// First position available in the thread buffer
|
||||||
|
idx = FirstFree();
|
||||||
|
if (idx >= 0)
|
||||||
|
{
|
||||||
|
// Creates the Worker and assigns it the connected socket
|
||||||
|
WorkerSocket = CreateWorkerSocket(Sock);
|
||||||
|
// Creates the Worker thread
|
||||||
|
Workers[idx] = new TMsgWorkerThread(WorkerSocket, this);
|
||||||
|
PMsgWorkerThread(Workers[idx])->Index = idx;
|
||||||
|
// Update the number
|
||||||
|
ClientsCount++;
|
||||||
|
// And Starts the worker
|
||||||
|
PMsgWorkerThread(Workers[idx])->Start();
|
||||||
|
DoEvent(WorkerSocket->ClientHandle, evcClientAdded, 0, 0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DoEvent(ClientHandle, evcClientNoRoom, 0, 0, 0, 0, 0);
|
||||||
|
Msg_CloseSocket(Sock);
|
||||||
|
}
|
||||||
|
UnlockList();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Msg_CloseSocket(Sock);
|
||||||
|
DoEvent(ClientHandle, evcClientRejected, 0, 0, 0, 0, 0);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
int TCustomMsgServer::Start()
|
||||||
|
{
|
||||||
|
int Result = 0;
|
||||||
|
if (Status != SrvRunning)
|
||||||
|
{
|
||||||
|
Result = StartListener();
|
||||||
|
if (Result != 0)
|
||||||
|
{
|
||||||
|
DoEvent(0, evcListenerCannotStart, Result, 0, 0, 0, 0);
|
||||||
|
Status = SrvError;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DoEvent(0, evcServerStarted, SockListener->ClientHandle, LocalPort, 0, 0, 0);
|
||||||
|
Status = SrvRunning;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
FLastError = Result;
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
int TCustomMsgServer::StartTo(const char *Address, word Port)
|
||||||
|
{
|
||||||
|
strncpy(FLocalAddress, Address, 16);
|
||||||
|
LocalPort = Port;
|
||||||
|
return Start();
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
void TCustomMsgServer::Stop()
|
||||||
|
{
|
||||||
|
if (Status == SrvRunning)
|
||||||
|
{
|
||||||
|
// Kills the listener thread
|
||||||
|
ServerThread->Terminate();
|
||||||
|
if (ServerThread->WaitFor(ThTimeout) != WAIT_OBJECT_0)
|
||||||
|
ServerThread->Kill();
|
||||||
|
delete ServerThread;
|
||||||
|
// Kills the listener
|
||||||
|
delete SockListener;
|
||||||
|
|
||||||
|
// Terminate all client threads
|
||||||
|
TerminateAll();
|
||||||
|
|
||||||
|
Status = SrvStopped;
|
||||||
|
LocalBind = 0;
|
||||||
|
DoEvent(0, evcServerStopped, 0, 0, 0, 0, 0);
|
||||||
|
};
|
||||||
|
FLastError = 0;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
int TCustomMsgServer::SetEventsCallBack(pfn_SrvCallBack PCallBack, void *UsrPtr)
|
||||||
|
{
|
||||||
|
OnEvent = PCallBack;
|
||||||
|
FUsrPtr = UsrPtr;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
bool TCustomMsgServer::PickEvent(void *pEvent)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return FEventQueue->Extract(pEvent);
|
||||||
|
} catch (...)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
bool TCustomMsgServer::EventEmpty()
|
||||||
|
{
|
||||||
|
return FEventQueue->Empty();
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
void TCustomMsgServer::EventsFlush()
|
||||||
|
{
|
||||||
|
CSEvent->Enter();
|
||||||
|
FEventQueue->Flush();
|
||||||
|
CSEvent->Leave();
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
247
utils/snap7_src/src/sys/snap_tcpsrvr.h
Normal file
247
utils/snap7_src/src/sys/snap_tcpsrvr.h
Normal file
@ -0,0 +1,247 @@
|
|||||||
|
/*=============================================================================|
|
||||||
|
| PROJECT SNAP7 1.3.0 |
|
||||||
|
|==============================================================================|
|
||||||
|
| Copyright (C) 2013, 2015 Davide Nardella |
|
||||||
|
| All rights reserved. |
|
||||||
|
|==============================================================================|
|
||||||
|
| SNAP7 is free software: you can redistribute it and/or modify |
|
||||||
|
| it under the terms of the Lesser GNU General Public License as published by |
|
||||||
|
| the Free Software Foundation, either version 3 of the License, or |
|
||||||
|
| (at your option) any later version. |
|
||||||
|
| |
|
||||||
|
| It means that you can distribute your commercial software linked with |
|
||||||
|
| SNAP7 without the requirement to distribute the source code of your |
|
||||||
|
| application and without the requirement that your application be itself |
|
||||||
|
| distributed under LGPL. |
|
||||||
|
| |
|
||||||
|
| SNAP7 is distributed in the hope that it will be useful, |
|
||||||
|
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||||
|
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
|
| Lesser GNU General Public License for more details. |
|
||||||
|
| |
|
||||||
|
| You should have received a copy of the GNU General Public License and a |
|
||||||
|
| copy of Lesser GNU General Public License along with Snap7. |
|
||||||
|
| If not, see http://www.gnu.org/licenses/ |
|
||||||
|
|=============================================================================*/
|
||||||
|
#ifndef snap_tcpsrvr_h
|
||||||
|
#define snap_tcpsrvr_h
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
#include "snap_msgsock.h"
|
||||||
|
#include "snap_threads.h"
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#define MaxWorkers 1024
|
||||||
|
#define MaxEvents 1500
|
||||||
|
|
||||||
|
const int SrvStopped = 0;
|
||||||
|
const int SrvRunning = 1;
|
||||||
|
const int SrvError = 2;
|
||||||
|
|
||||||
|
const longword evcServerStarted = 0x00000001;
|
||||||
|
const longword evcServerStopped = 0x00000002;
|
||||||
|
const longword evcListenerCannotStart = 0x00000004;
|
||||||
|
const longword evcClientAdded = 0x00000008;
|
||||||
|
const longword evcClientRejected = 0x00000010;
|
||||||
|
const longword evcClientNoRoom = 0x00000020;
|
||||||
|
const longword evcClientException = 0x00000040;
|
||||||
|
const longword evcClientDisconnected = 0x00000080;
|
||||||
|
const longword evcClientTerminated = 0x00000100;
|
||||||
|
const longword evcClientsDropped = 0x00000200;
|
||||||
|
const longword evcReserved_00000400 = 0x00000400;
|
||||||
|
const longword evcReserved_00000800 = 0x00000800;
|
||||||
|
const longword evcReserved_00001000 = 0x00001000;
|
||||||
|
const longword evcReserved_00002000 = 0x00002000;
|
||||||
|
const longword evcReserved_00004000 = 0x00004000;
|
||||||
|
const longword evcReserved_00008000 = 0x00008000;
|
||||||
|
|
||||||
|
// Server Interface errors
|
||||||
|
const longword errSrvBase = 0x0000FFFF;
|
||||||
|
const longword errSrvMask = 0xFFFF0000;
|
||||||
|
const longword errSrvCannotStart = 0x00100000;
|
||||||
|
|
||||||
|
const longword ThTimeout = 2000; // Thread timeout
|
||||||
|
const longword WkTimeout = 3000; // Workers termination timeout
|
||||||
|
|
||||||
|
#pragma pack(1)
|
||||||
|
|
||||||
|
typedef struct{
|
||||||
|
time_t EvtTime; // Timestamp
|
||||||
|
int EvtSender; // Sender
|
||||||
|
longword EvtCode; // Event code
|
||||||
|
word EvtRetCode; // Event result
|
||||||
|
word EvtParam1; // Param 1 (if available)
|
||||||
|
word EvtParam2; // Param 2 (if available)
|
||||||
|
word EvtParam3; // Param 3 (if available)
|
||||||
|
word EvtParam4; // Param 4 (if available)
|
||||||
|
}TSrvEvent, *PSrvEvent;
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
typedef void (S7API *pfn_SrvCallBack)(void * usrPtr, PSrvEvent PEvent, int Size);
|
||||||
|
}
|
||||||
|
#pragma pack()
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// EVENTS QUEUE
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
class TMsgEventQueue
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
int IndexIn; // <-- insert index
|
||||||
|
int IndexOut; // --> extract index
|
||||||
|
int Max; // Buffer upper bound [0..Max]
|
||||||
|
int FCapacity; // Queue capacity
|
||||||
|
pbyte Buffer;
|
||||||
|
int FBlockSize;
|
||||||
|
public:
|
||||||
|
TMsgEventQueue(const int Capacity, const int BlockSize);
|
||||||
|
~TMsgEventQueue();
|
||||||
|
void Flush();
|
||||||
|
void Insert(void *lpdata);
|
||||||
|
bool Extract(void *lpdata);
|
||||||
|
bool Empty();
|
||||||
|
bool Full();
|
||||||
|
};
|
||||||
|
typedef TMsgEventQueue *PMsgEventQueue;
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// WORKER THREAD
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
class TCustomMsgServer; // forward declaration
|
||||||
|
|
||||||
|
// It's created when connection is accepted, it will interface with the client.
|
||||||
|
class TMsgWorkerThread : public TSnapThread
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
TCustomMsgServer *FServer;
|
||||||
|
protected:
|
||||||
|
TMsgSocket *WorkerSocket;
|
||||||
|
public:
|
||||||
|
int Index;
|
||||||
|
friend class TCustomMsgServer;
|
||||||
|
TMsgWorkerThread(TMsgSocket *Socket, TCustomMsgServer *Server);
|
||||||
|
void Execute();
|
||||||
|
};
|
||||||
|
typedef TMsgWorkerThread *PMsgWorkerThread;
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// LISTENER THREAD
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// It listens for incoming connection.
|
||||||
|
class TMsgListenerThread : public TSnapThread
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
TMsgSocket *FListener;
|
||||||
|
TCustomMsgServer *FServer;
|
||||||
|
public:
|
||||||
|
TMsgListenerThread(TMsgSocket *Listener, TCustomMsgServer *Server);
|
||||||
|
void Execute();
|
||||||
|
};
|
||||||
|
typedef TMsgListenerThread *PMsgListenerThread;
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// TCP SERVER
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
typedef TMsgSocket *PWorkerSocket;
|
||||||
|
|
||||||
|
class TCustomMsgServer
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
int FLastError;
|
||||||
|
char FLocalAddress[16];
|
||||||
|
// Socket listener
|
||||||
|
PMsgSocket SockListener;
|
||||||
|
// Server listener
|
||||||
|
PMsgListenerThread ServerThread;
|
||||||
|
// Critical section to lock Workers list activities
|
||||||
|
PSnapCriticalSection CSList;
|
||||||
|
// Event queue
|
||||||
|
PMsgEventQueue FEventQueue;
|
||||||
|
// Callback related
|
||||||
|
pfn_SrvCallBack OnEvent;
|
||||||
|
void *FUsrPtr;
|
||||||
|
// private methods
|
||||||
|
int StartListener();
|
||||||
|
void LockList();
|
||||||
|
void UnlockList();
|
||||||
|
int FirstFree();
|
||||||
|
protected:
|
||||||
|
bool Destroying;
|
||||||
|
// Critical section to lock Event activities
|
||||||
|
PSnapCriticalSection CSEvent;
|
||||||
|
// Workers list
|
||||||
|
void *Workers[MaxWorkers];
|
||||||
|
// Terminates all worker threads
|
||||||
|
virtual void TerminateAll();
|
||||||
|
// Kills all worker threads that are unresponsive
|
||||||
|
void KillAll();
|
||||||
|
// if (true the connection is accepted, otherwise the connection
|
||||||
|
// is closed gracefully
|
||||||
|
virtual bool CanAccept(socket_t Socket);
|
||||||
|
// Returns the class of the worker socket, override it for real servers
|
||||||
|
virtual PWorkerSocket CreateWorkerSocket(socket_t Sock);
|
||||||
|
// Handles the event
|
||||||
|
virtual void DoEvent(int Sender, longword Code, word RetCode, word Param1,
|
||||||
|
word Param2, word Param3, word Param4);
|
||||||
|
// Delete the worker from the list (It's invoked by Worker Thread)
|
||||||
|
void Delete(int Index);
|
||||||
|
// Incoming connection (It's invoked by ServerThread, the listener)
|
||||||
|
virtual void Incoming(socket_t Sock);
|
||||||
|
public:
|
||||||
|
friend class TMsgWorkerThread;
|
||||||
|
friend class TMsgListenerThread;
|
||||||
|
word LocalPort;
|
||||||
|
longword LocalBind;
|
||||||
|
longword LogMask;
|
||||||
|
longword EventMask;
|
||||||
|
int Status;
|
||||||
|
int ClientsCount;
|
||||||
|
int MaxClients;
|
||||||
|
TCustomMsgServer();
|
||||||
|
virtual ~TCustomMsgServer();
|
||||||
|
// Starts the server
|
||||||
|
int Start();
|
||||||
|
int StartTo(const char *Address, word Port);
|
||||||
|
// Stops the server
|
||||||
|
void Stop();
|
||||||
|
// Sets Event callback
|
||||||
|
int SetEventsCallBack(pfn_SrvCallBack PCallBack, void *UsrPtr);
|
||||||
|
// Pick an event from the circular queue
|
||||||
|
bool PickEvent(void *pEvent);
|
||||||
|
// Returns true if (the Event queue is empty
|
||||||
|
bool EventEmpty();
|
||||||
|
// Flushes Event queue
|
||||||
|
void EventsFlush();
|
||||||
|
};
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// TCP WORKER
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Default worker class, a simply tcp echo to test the connection and
|
||||||
|
// data I/O to use the server outside the project
|
||||||
|
class TEcoTcpWorker : public TMsgSocket
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool Execute()
|
||||||
|
{
|
||||||
|
byte Buffer[4096];
|
||||||
|
int Size;
|
||||||
|
|
||||||
|
if (CanRead(WorkInterval)) // Small time to avoid time wait during the close
|
||||||
|
{
|
||||||
|
Receive(&Buffer,sizeof(Buffer),Size);
|
||||||
|
if ((LastTcpError==0) && (Size>0))
|
||||||
|
{
|
||||||
|
SendPacket(&Buffer,Size);
|
||||||
|
return LastTcpError==0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
#endif // snap_tcpsrvr_h
|
162
utils/snap7_src/src/sys/snap_threads.cpp
Normal file
162
utils/snap7_src/src/sys/snap_threads.cpp
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
/*=============================================================================|
|
||||||
|
| PROJECT SNAP7 1.3.0 |
|
||||||
|
|==============================================================================|
|
||||||
|
| Copyright (C) 2013, 2015 Davide Nardella |
|
||||||
|
| All rights reserved. |
|
||||||
|
|==============================================================================|
|
||||||
|
| SNAP7 is free software: you can redistribute it and/or modify |
|
||||||
|
| it under the terms of the Lesser GNU General Public License as published by |
|
||||||
|
| the Free Software Foundation, either version 3 of the License, or |
|
||||||
|
| (at your option) any later version. |
|
||||||
|
| |
|
||||||
|
| It means that you can distribute your commercial software linked with |
|
||||||
|
| SNAP7 without the requirement to distribute the source code of your |
|
||||||
|
| application and without the requirement that your application be itself |
|
||||||
|
| distributed under LGPL. |
|
||||||
|
| |
|
||||||
|
| SNAP7 is distributed in the hope that it will be useful, |
|
||||||
|
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||||
|
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
|
| Lesser GNU General Public License for more details. |
|
||||||
|
| |
|
||||||
|
| You should have received a copy of the GNU General Public License and a |
|
||||||
|
| copy of Lesser GNU General Public License along with Snap7. |
|
||||||
|
| If not, see http://www.gnu.org/licenses/ |
|
||||||
|
|=============================================================================*/
|
||||||
|
|
||||||
|
#include "snap_threads.h"
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
#ifdef OS_WINDOWS
|
||||||
|
DWORD WINAPI ThreadProc(LPVOID param)
|
||||||
|
#else
|
||||||
|
|
||||||
|
void* ThreadProc(void* param)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
PSnapThread Thread;
|
||||||
|
// Unix but not Solaris
|
||||||
|
#if (defined(POSIX) || defined(OS_OSX)) && (!defined(OS_SOLARIS_NATIVE_THREADS))
|
||||||
|
int last_type, last_state;
|
||||||
|
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &last_type);
|
||||||
|
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &last_state);
|
||||||
|
#endif
|
||||||
|
Thread = PSnapThread(param);
|
||||||
|
|
||||||
|
if (!Thread->Terminated)
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Thread->Execute();
|
||||||
|
} catch (...)
|
||||||
|
{
|
||||||
|
};
|
||||||
|
Thread->Closed = true;
|
||||||
|
if (Thread->FreeOnTerminate)
|
||||||
|
{
|
||||||
|
delete Thread;
|
||||||
|
};
|
||||||
|
#ifdef OS_WINDOWS
|
||||||
|
ExitThread(0);
|
||||||
|
#endif
|
||||||
|
#if defined(POSIX) && (!defined(OS_SOLARIS_NATIVE_THREADS))
|
||||||
|
pthread_exit((void*)0);
|
||||||
|
#endif
|
||||||
|
#if defined(OS_OSX)
|
||||||
|
pthread_exit((void*)0);
|
||||||
|
#endif
|
||||||
|
#ifdef OS_SOLARIS_NATIVE_THREADS
|
||||||
|
thr_exit((void*)0);
|
||||||
|
#endif
|
||||||
|
return 0; // never reach, only to avoid compiler warning
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
TSnapThread::TSnapThread()
|
||||||
|
{
|
||||||
|
Started = false;
|
||||||
|
Closed=false;
|
||||||
|
Terminated = false;
|
||||||
|
FreeOnTerminate = false;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
TSnapThread::~TSnapThread()
|
||||||
|
{
|
||||||
|
if (Started && !Closed)
|
||||||
|
{
|
||||||
|
Terminate();
|
||||||
|
Join();
|
||||||
|
};
|
||||||
|
#ifdef OS_WINDOWS
|
||||||
|
if (Started)
|
||||||
|
CloseHandle(th);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
void TSnapThread::ThreadCreate()
|
||||||
|
{
|
||||||
|
#ifdef OS_WINDOWS
|
||||||
|
th = CreateThread(0, 0, ThreadProc, this, 0, 0);
|
||||||
|
#endif
|
||||||
|
#if defined(POSIX) && (!defined(OS_SOLARIS_NATIVE_THREADS))
|
||||||
|
pthread_attr_t a;
|
||||||
|
pthread_attr_init(&a);
|
||||||
|
pthread_attr_setdetachstate(&a, PTHREAD_CREATE_DETACHED);
|
||||||
|
pthread_create(&th, &a, &ThreadProc, this);
|
||||||
|
#endif
|
||||||
|
#if defined(OS_OSX)
|
||||||
|
pthread_create(&th, 0, &ThreadProc, this);
|
||||||
|
#endif
|
||||||
|
#ifdef OS_SOLARIS_NATIVE_THREADS
|
||||||
|
thr_create(0, // default stack base
|
||||||
|
0, // default stack size
|
||||||
|
&ThreadProc, // Thread routine
|
||||||
|
this, // argument
|
||||||
|
0,
|
||||||
|
&th);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
void TSnapThread::Start()
|
||||||
|
{
|
||||||
|
if (!Started)
|
||||||
|
{
|
||||||
|
ThreadCreate();
|
||||||
|
Started = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
void TSnapThread::Terminate()
|
||||||
|
{
|
||||||
|
Terminated = true;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
void TSnapThread::Kill()
|
||||||
|
{
|
||||||
|
if (Started && !Closed)
|
||||||
|
{
|
||||||
|
ThreadKill();
|
||||||
|
Closed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
void TSnapThread::Join()
|
||||||
|
{
|
||||||
|
if (Started && !Closed)
|
||||||
|
{
|
||||||
|
ThreadJoin();
|
||||||
|
Closed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
longword TSnapThread::WaitFor(uint64_t Timeout)
|
||||||
|
{
|
||||||
|
if (Started)
|
||||||
|
{
|
||||||
|
if (!Closed)
|
||||||
|
return ThreadWait(Timeout);
|
||||||
|
else
|
||||||
|
return WAIT_OBJECT_0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return WAIT_OBJECT_0;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
45
utils/snap7_src/src/sys/snap_threads.h
Normal file
45
utils/snap7_src/src/sys/snap_threads.h
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/*=============================================================================|
|
||||||
|
| PROJECT SNAP7 1.3.0 |
|
||||||
|
|==============================================================================|
|
||||||
|
| Copyright (C) 2013, 2015 Davide Nardella |
|
||||||
|
| All rights reserved. |
|
||||||
|
|==============================================================================|
|
||||||
|
| SNAP7 is free software: you can redistribute it and/or modify |
|
||||||
|
| it under the terms of the Lesser GNU General Public License as published by |
|
||||||
|
| the Free Software Foundation, either version 3 of the License, or |
|
||||||
|
| (at your option) any later version. |
|
||||||
|
| |
|
||||||
|
| It means that you can distribute your commercial software linked with |
|
||||||
|
| SNAP7 without the requirement to distribute the source code of your |
|
||||||
|
| application and without the requirement that your application be itself |
|
||||||
|
| distributed under LGPL. |
|
||||||
|
| |
|
||||||
|
| SNAP7 is distributed in the hope that it will be useful, |
|
||||||
|
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||||
|
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
|
| Lesser GNU General Public License for more details. |
|
||||||
|
| |
|
||||||
|
| You should have received a copy of the GNU General Public License and a |
|
||||||
|
| copy of Lesser GNU General Public License along with Snap7. |
|
||||||
|
| If not, see http://www.gnu.org/licenses/ |
|
||||||
|
|=============================================================================*/
|
||||||
|
#ifndef snap_threads_h
|
||||||
|
#define snap_threads_h
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
#include "snap_platform.h"
|
||||||
|
|
||||||
|
#ifdef OS_WINDOWS
|
||||||
|
# include "win_threads.h"
|
||||||
|
#endif
|
||||||
|
#if defined(POSIX) && (!defined(OS_SOLARIS_NATIVE_THREADS))
|
||||||
|
# include "unix_threads.h"
|
||||||
|
#endif
|
||||||
|
#ifdef OS_SOLARIS_NATIVE_THREADS
|
||||||
|
# include "sol_threads.h"
|
||||||
|
#endif
|
||||||
|
#if defined(OS_OSX)
|
||||||
|
# include "unix_threads.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
#endif // snap_threads_h
|
208
utils/snap7_src/src/sys/sol_threads.h
Normal file
208
utils/snap7_src/src/sys/sol_threads.h
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
/*=============================================================================|
|
||||||
|
| PROJECT SNAP7 1.3.0 |
|
||||||
|
|==============================================================================|
|
||||||
|
| Copyright (C) 2013, 2015 Davide Nardella |
|
||||||
|
| All rights reserved. |
|
||||||
|
|==============================================================================|
|
||||||
|
| SNAP7 is free software: you can redistribute it and/or modify |
|
||||||
|
| it under the terms of the Lesser GNU General Public License as published by |
|
||||||
|
| the Free Software Foundation, either version 3 of the License, or |
|
||||||
|
| (at your option) any later version. |
|
||||||
|
| |
|
||||||
|
| It means that you can distribute your commercial software linked with |
|
||||||
|
| SNAP7 without the requirement to distribute the source code of your |
|
||||||
|
| application and without the requirement that your application be itself |
|
||||||
|
| distributed under LGPL. |
|
||||||
|
| |
|
||||||
|
| SNAP7 is distributed in the hope that it will be useful, |
|
||||||
|
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||||
|
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
|
| Lesser GNU General Public License for more details. |
|
||||||
|
| |
|
||||||
|
| You should have received a copy of the GNU General Public License and a |
|
||||||
|
| copy of Lesser GNU General Public License along with Snap7. |
|
||||||
|
| If not, see http://www.gnu.org/licenses/ |
|
||||||
|
|==============================================================================|
|
||||||
|
| |
|
||||||
|
| Solaris 11 Threads support |
|
||||||
|
| |
|
||||||
|
|=============================================================================*/
|
||||||
|
#ifndef sol_threads_h
|
||||||
|
#define sol_threads_h
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
#include "snap_platform.h"
|
||||||
|
#include "snap_sysutils.h"
|
||||||
|
#include <thread.h>
|
||||||
|
#include <synch.h>
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class TSnapCriticalSection {
|
||||||
|
private:
|
||||||
|
mutex_t mx;
|
||||||
|
int result;
|
||||||
|
public:
|
||||||
|
|
||||||
|
TSnapCriticalSection() {
|
||||||
|
mutex_init(&mx, USYNC_THREAD, 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
~TSnapCriticalSection() {
|
||||||
|
mutex_destroy(&mx);
|
||||||
|
};
|
||||||
|
|
||||||
|
void Enter() {
|
||||||
|
mutex_lock(&mx);
|
||||||
|
};
|
||||||
|
|
||||||
|
void Leave() {
|
||||||
|
mutex_unlock(&mx);
|
||||||
|
};
|
||||||
|
|
||||||
|
bool TryEnter() {
|
||||||
|
return mutex_trylock(&mx) == 0;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
typedef TSnapCriticalSection *PSnapCriticalSection;
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
const longword WAIT_OBJECT_0 = 0x00000000L;
|
||||||
|
const longword WAIT_ABANDONED = 0x00000080L;
|
||||||
|
const longword WAIT_TIMEOUT = 0x00000102L;
|
||||||
|
const longword WAIT_FAILED = 0xFFFFFFFFL;
|
||||||
|
|
||||||
|
class TSnapEvent {
|
||||||
|
private:
|
||||||
|
cond_t CVariable;
|
||||||
|
mutex_t Mutex;
|
||||||
|
bool AutoReset;
|
||||||
|
bool State;
|
||||||
|
public:
|
||||||
|
|
||||||
|
TSnapEvent(bool ManualReset)
|
||||||
|
{
|
||||||
|
AutoReset = !ManualReset;
|
||||||
|
cond_init(&CVariable, USYNC_THREAD, 0) == 0;
|
||||||
|
mutex_init(&Mutex, USYNC_THREAD, 0);
|
||||||
|
State = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
~TSnapEvent()
|
||||||
|
{
|
||||||
|
cond_destroy(&CVariable);
|
||||||
|
mutex_destroy(&Mutex);
|
||||||
|
};
|
||||||
|
|
||||||
|
void Set()
|
||||||
|
{
|
||||||
|
mutex_lock(&Mutex);
|
||||||
|
State = true;
|
||||||
|
if (AutoReset)
|
||||||
|
cond_signal(&CVariable);
|
||||||
|
else
|
||||||
|
cond_broadcast(&CVariable);
|
||||||
|
mutex_unlock(&Mutex);
|
||||||
|
};
|
||||||
|
|
||||||
|
void Reset()
|
||||||
|
{
|
||||||
|
mutex_lock(&Mutex);
|
||||||
|
State = false;
|
||||||
|
mutex_unlock(&Mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
longword WaitForever()
|
||||||
|
{
|
||||||
|
mutex_lock(&Mutex);
|
||||||
|
while (!State) // <-- to avoid spurious wakeups
|
||||||
|
cond_wait(&CVariable, &Mutex);
|
||||||
|
if (AutoReset)
|
||||||
|
State = false;
|
||||||
|
mutex_unlock(&Mutex);
|
||||||
|
return WAIT_OBJECT_0;
|
||||||
|
};
|
||||||
|
|
||||||
|
longword WaitFor(int64_t Timeout)
|
||||||
|
{
|
||||||
|
longword Result = WAIT_OBJECT_0;
|
||||||
|
if (Timeout == 0)
|
||||||
|
Timeout = 1; // 0 is not allowed
|
||||||
|
|
||||||
|
if (Timeout > 0) {
|
||||||
|
mutex_lock(&Mutex);
|
||||||
|
if (!State) {
|
||||||
|
timespec ts;
|
||||||
|
timeval tv;
|
||||||
|
gettimeofday(&tv, NULL);
|
||||||
|
uint64_t nsecs = ((uint64_t) tv.tv_sec) * 1000000000 +
|
||||||
|
Timeout * 1000000 +
|
||||||
|
((uint64_t) tv.tv_usec) * 1000;
|
||||||
|
ts.tv_sec = nsecs / 1000000000;
|
||||||
|
ts.tv_nsec = (nsecs - ((uint64_t) ts.tv_sec) * 1000000000);
|
||||||
|
do
|
||||||
|
{
|
||||||
|
Result = cond_timedwait(&CVariable, &Mutex, &ts);
|
||||||
|
if (Result == ETIMEDOUT)
|
||||||
|
Result = WAIT_TIMEOUT;
|
||||||
|
}
|
||||||
|
while (Result == 0 && !State);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (AutoReset) // take the ownership
|
||||||
|
State = false;
|
||||||
|
mutex_unlock(&Mutex);
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
else // Timeout<0
|
||||||
|
return WaitForever();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
typedef TSnapEvent *PSnapEvent;
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class TSnapThread {
|
||||||
|
private:
|
||||||
|
thread_t th;
|
||||||
|
bool FCreateSuspended;
|
||||||
|
void ThreadCreate();
|
||||||
|
|
||||||
|
void ThreadJoin()
|
||||||
|
{
|
||||||
|
thr_join(th, 0, 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
void ThreadKill()
|
||||||
|
{
|
||||||
|
thr_kill(th, 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
longword ThreadWait(uint64_t Timeout)
|
||||||
|
{
|
||||||
|
longword Elapsed = SysGetTick();
|
||||||
|
while (!Closed && !(DeltaTime(Elapsed) > Timeout))
|
||||||
|
SysSleep(100);
|
||||||
|
if (Closed)
|
||||||
|
return WAIT_OBJECT_0;
|
||||||
|
else
|
||||||
|
return WAIT_TIMEOUT;
|
||||||
|
};
|
||||||
|
protected:
|
||||||
|
bool Started;
|
||||||
|
public:
|
||||||
|
bool Terminated;
|
||||||
|
bool Closed;
|
||||||
|
bool FreeOnTerminate;
|
||||||
|
TSnapThread();
|
||||||
|
virtual ~TSnapThread();
|
||||||
|
|
||||||
|
virtual void Execute() {
|
||||||
|
};
|
||||||
|
void Start();
|
||||||
|
void Terminate();
|
||||||
|
void Kill();
|
||||||
|
void Join();
|
||||||
|
longword WaitFor(uint64_t Timeout);
|
||||||
|
};
|
||||||
|
typedef TSnapThread *PSnapThread;
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
#endif // sol_threads_h
|
228
utils/snap7_src/src/sys/unix_threads.h
Normal file
228
utils/snap7_src/src/sys/unix_threads.h
Normal file
@ -0,0 +1,228 @@
|
|||||||
|
/*=============================================================================|
|
||||||
|
| PROJECT SNAP7 1.3.0 |
|
||||||
|
|==============================================================================|
|
||||||
|
| Copyright (C) 2013, 2015 Davide Nardella |
|
||||||
|
| All rights reserved. |
|
||||||
|
|==============================================================================|
|
||||||
|
| SNAP7 is free software: you can redistribute it and/or modify |
|
||||||
|
| it under the terms of the Lesser GNU General Public License as published by |
|
||||||
|
| the Free Software Foundation, either version 3 of the License, or |
|
||||||
|
| (at your option) any later version. |
|
||||||
|
| |
|
||||||
|
| It means that you can distribute your commercial software linked with |
|
||||||
|
| SNAP7 without the requirement to distribute the source code of your |
|
||||||
|
| application and without the requirement that your application be itself |
|
||||||
|
| distributed under LGPL. |
|
||||||
|
| |
|
||||||
|
| SNAP7 is distributed in the hope that it will be useful, |
|
||||||
|
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||||
|
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
|
| Lesser GNU General Public License for more details. |
|
||||||
|
| |
|
||||||
|
| You should have received a copy of the GNU General Public License and a |
|
||||||
|
| copy of Lesser GNU General Public License along with Snap7. |
|
||||||
|
| If not, see http://www.gnu.org/licenses/ |
|
||||||
|
|==============================================================================|
|
||||||
|
| |
|
||||||
|
| Posix Threads support (Linux, FreeBSD) |
|
||||||
|
| |
|
||||||
|
|=============================================================================*/
|
||||||
|
#ifndef unix_threads_h
|
||||||
|
#define unix_threads_h
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
#include "snap_platform.h"
|
||||||
|
#include "snap_sysutils.h"
|
||||||
|
#include <semaphore.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class TSnapCriticalSection
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
pthread_mutex_t mx;
|
||||||
|
// int result;
|
||||||
|
public:
|
||||||
|
|
||||||
|
TSnapCriticalSection()
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
|
||||||
|
This would be the best code, but very often it causes a segmentation fault in many
|
||||||
|
unix systems (the problem seems to be pthread_mutexattr_destroy()).
|
||||||
|
So, to avoid problems in future kernel/libc release, we use the "safe" default.
|
||||||
|
|
||||||
|
pthread_mutexattr_t mxAttr;
|
||||||
|
pthread_mutexattr_settype(&mxAttr, PTHREAD_MUTEX_RECURSIVE);
|
||||||
|
pthread_mutex_init(&mx, &mxAttr);
|
||||||
|
pthread_mutexattr_destroy(&mxAttr);
|
||||||
|
|
||||||
|
*/
|
||||||
|
pthread_mutex_init(&mx, 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
~TSnapCriticalSection()
|
||||||
|
{
|
||||||
|
pthread_mutex_destroy(&mx);
|
||||||
|
};
|
||||||
|
|
||||||
|
void Enter()
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&mx);
|
||||||
|
};
|
||||||
|
|
||||||
|
void Leave()
|
||||||
|
{
|
||||||
|
pthread_mutex_unlock(&mx);
|
||||||
|
};
|
||||||
|
|
||||||
|
bool TryEnter()
|
||||||
|
{
|
||||||
|
return pthread_mutex_trylock(&mx) == 0;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
typedef TSnapCriticalSection *PSnapCriticalSection;
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
const longword WAIT_OBJECT_0 = 0x00000000L;
|
||||||
|
const longword WAIT_ABANDONED = 0x00000080L;
|
||||||
|
const longword WAIT_TIMEOUT = 0x00000102L;
|
||||||
|
const longword WAIT_FAILED = 0xFFFFFFFFL;
|
||||||
|
|
||||||
|
class TSnapEvent
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
pthread_cond_t CVariable;
|
||||||
|
pthread_mutex_t Mutex;
|
||||||
|
bool AutoReset;
|
||||||
|
bool State;
|
||||||
|
public:
|
||||||
|
|
||||||
|
TSnapEvent(bool ManualReset)
|
||||||
|
{
|
||||||
|
AutoReset = !ManualReset;
|
||||||
|
if (pthread_cond_init(&CVariable, 0) == 0)
|
||||||
|
pthread_mutex_init(&Mutex, 0);
|
||||||
|
State = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
~TSnapEvent()
|
||||||
|
{
|
||||||
|
pthread_cond_destroy(&CVariable);
|
||||||
|
pthread_mutex_destroy(&Mutex);
|
||||||
|
};
|
||||||
|
|
||||||
|
void Set()
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&Mutex);
|
||||||
|
State = true;
|
||||||
|
if (AutoReset)
|
||||||
|
pthread_cond_signal(&CVariable);
|
||||||
|
else
|
||||||
|
pthread_cond_broadcast(&CVariable);
|
||||||
|
pthread_mutex_unlock(&Mutex);
|
||||||
|
};
|
||||||
|
|
||||||
|
void Reset()
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&Mutex);
|
||||||
|
State = false;
|
||||||
|
pthread_mutex_unlock(&Mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
longword WaitForever()
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&Mutex);
|
||||||
|
while (!State) // <-- to avoid spurious wakeups
|
||||||
|
pthread_cond_wait(&CVariable, &Mutex);
|
||||||
|
if (AutoReset)
|
||||||
|
State = false;
|
||||||
|
pthread_mutex_unlock(&Mutex);
|
||||||
|
return WAIT_OBJECT_0;
|
||||||
|
};
|
||||||
|
|
||||||
|
longword WaitFor(int64_t Timeout)
|
||||||
|
{
|
||||||
|
longword Result = WAIT_OBJECT_0;
|
||||||
|
if (Timeout == 0)
|
||||||
|
Timeout = 1; // 0 is not allowed
|
||||||
|
|
||||||
|
if (Timeout > 0)
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&Mutex);
|
||||||
|
if (!State)
|
||||||
|
{
|
||||||
|
timespec ts;
|
||||||
|
timeval tv;
|
||||||
|
gettimeofday(&tv, NULL);
|
||||||
|
uint64_t nsecs = ((uint64_t) tv.tv_sec) * 1000000000 +
|
||||||
|
Timeout * 1000000 +
|
||||||
|
((uint64_t) tv.tv_usec) * 1000;
|
||||||
|
ts.tv_sec = nsecs / 1000000000;
|
||||||
|
ts.tv_nsec = (nsecs - ((uint64_t) ts.tv_sec) * 1000000000);
|
||||||
|
do {
|
||||||
|
Result = pthread_cond_timedwait(&CVariable, &Mutex, &ts);
|
||||||
|
if (Result == ETIMEDOUT)
|
||||||
|
Result = WAIT_TIMEOUT;
|
||||||
|
} while (Result == 0 && !State);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (AutoReset) // take the ownership
|
||||||
|
State = false;
|
||||||
|
pthread_mutex_unlock(&Mutex);
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
else // Timeout<0
|
||||||
|
return WaitForever();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
typedef TSnapEvent *PSnapEvent;
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
class TSnapThread
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
pthread_t th;
|
||||||
|
bool FCreateSuspended;
|
||||||
|
void ThreadCreate();
|
||||||
|
|
||||||
|
void ThreadJoin()
|
||||||
|
{
|
||||||
|
pthread_join(th, 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
void ThreadKill()
|
||||||
|
{
|
||||||
|
pthread_cancel(th);
|
||||||
|
};
|
||||||
|
|
||||||
|
longword ThreadWait(uint64_t Timeout)
|
||||||
|
{
|
||||||
|
longword Elapsed = SysGetTick();
|
||||||
|
while (!Closed && !(DeltaTime(Elapsed) > Timeout))
|
||||||
|
SysSleep(100);
|
||||||
|
if (Closed)
|
||||||
|
return WAIT_OBJECT_0;
|
||||||
|
else
|
||||||
|
return WAIT_TIMEOUT;
|
||||||
|
};
|
||||||
|
protected:
|
||||||
|
bool Started;
|
||||||
|
public:
|
||||||
|
bool Terminated;
|
||||||
|
bool Closed;
|
||||||
|
bool FreeOnTerminate;
|
||||||
|
TSnapThread();
|
||||||
|
virtual ~TSnapThread();
|
||||||
|
|
||||||
|
virtual void Execute()
|
||||||
|
{
|
||||||
|
};
|
||||||
|
void Start();
|
||||||
|
void Terminate();
|
||||||
|
void Kill();
|
||||||
|
void Join();
|
||||||
|
longword WaitFor(uint64_t Timeout);
|
||||||
|
};
|
||||||
|
typedef TSnapThread *PSnapThread;
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
#endif // unix_threads_h
|
159
utils/snap7_src/src/sys/win_threads.h
Normal file
159
utils/snap7_src/src/sys/win_threads.h
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
/*=============================================================================|
|
||||||
|
| PROJECT SNAP7 1.3.0 |
|
||||||
|
|==============================================================================|
|
||||||
|
| Copyright (C) 2013, 2015 Davide Nardella |
|
||||||
|
| All rights reserved. |
|
||||||
|
|==============================================================================|
|
||||||
|
| SNAP7 is free software: you can redistribute it and/or modify |
|
||||||
|
| it under the terms of the Lesser GNU General Public License as published by |
|
||||||
|
| the Free Software Foundation, either version 3 of the License, or |
|
||||||
|
| (at your option) any later version. |
|
||||||
|
| |
|
||||||
|
| It means that you can distribute your commercial software linked with |
|
||||||
|
| SNAP7 without the requirement to distribute the source code of your |
|
||||||
|
| application and without the requirement that your application be itself |
|
||||||
|
| distributed under LGPL. |
|
||||||
|
| |
|
||||||
|
| SNAP7 is distributed in the hope that it will be useful, |
|
||||||
|
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||||
|
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
|
| Lesser GNU General Public License for more details. |
|
||||||
|
| |
|
||||||
|
| You should have received a copy of the GNU General Public License and a |
|
||||||
|
| copy of Lesser GNU General Public License along with Snap7. |
|
||||||
|
| If not, see http://www.gnu.org/licenses/ |
|
||||||
|
|==============================================================================|
|
||||||
|
| |
|
||||||
|
| Windows Threads support (Windows, ReactOS) |
|
||||||
|
| |
|
||||||
|
|=============================================================================*/
|
||||||
|
#ifndef win_threads_h
|
||||||
|
#define win_threads_h
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
#include "snap_platform.h"
|
||||||
|
#include "snap_sysutils.h"
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class TSnapCriticalSection
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
CRITICAL_SECTION cs;
|
||||||
|
public:
|
||||||
|
|
||||||
|
TSnapCriticalSection()
|
||||||
|
{
|
||||||
|
InitializeCriticalSection(&cs);
|
||||||
|
};
|
||||||
|
|
||||||
|
~TSnapCriticalSection()
|
||||||
|
{
|
||||||
|
DeleteCriticalSection(&cs);
|
||||||
|
};
|
||||||
|
|
||||||
|
void Enter()
|
||||||
|
{
|
||||||
|
EnterCriticalSection(&cs);
|
||||||
|
};
|
||||||
|
|
||||||
|
void Leave()
|
||||||
|
{
|
||||||
|
LeaveCriticalSection(&cs);
|
||||||
|
};
|
||||||
|
|
||||||
|
bool TryEnter()
|
||||||
|
{
|
||||||
|
return (TryEnterCriticalSection(&cs) != 0);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
typedef TSnapCriticalSection *PSnapCriticalSection;
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class TSnapEvent
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
HANDLE Event;
|
||||||
|
public:
|
||||||
|
|
||||||
|
TSnapEvent(bool ManualReset)
|
||||||
|
{
|
||||||
|
Event = CreateEvent(0, ManualReset, false, 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
~TSnapEvent()
|
||||||
|
{
|
||||||
|
if (Event != 0)
|
||||||
|
CloseHandle(Event);
|
||||||
|
};
|
||||||
|
|
||||||
|
void Set()
|
||||||
|
{
|
||||||
|
if (Event != 0)
|
||||||
|
SetEvent(Event);
|
||||||
|
};
|
||||||
|
|
||||||
|
void Reset()
|
||||||
|
{
|
||||||
|
if (Event != 0)
|
||||||
|
ResetEvent(Event);
|
||||||
|
};
|
||||||
|
|
||||||
|
longword WaitForever()
|
||||||
|
{
|
||||||
|
if (Event != 0)
|
||||||
|
return WaitForSingleObject(Event, INFINITE);
|
||||||
|
else
|
||||||
|
return WAIT_FAILED;
|
||||||
|
};
|
||||||
|
|
||||||
|
longword WaitFor(int64_t Timeout) {
|
||||||
|
if (Event != 0)
|
||||||
|
return WaitForSingleObject(Event, DWORD(Timeout));
|
||||||
|
else
|
||||||
|
return WAIT_FAILED;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
typedef TSnapEvent *PSnapEvent;
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class TSnapThread {
|
||||||
|
private:
|
||||||
|
HANDLE th;
|
||||||
|
bool FCreateSuspended;
|
||||||
|
void ThreadCreate();
|
||||||
|
|
||||||
|
void ThreadJoin()
|
||||||
|
{
|
||||||
|
WaitForSingleObject(th, INFINITE);
|
||||||
|
};
|
||||||
|
|
||||||
|
void ThreadKill()
|
||||||
|
{
|
||||||
|
TerminateThread(th, 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
longword ThreadWait(uint64_t Timeout)
|
||||||
|
{
|
||||||
|
return WaitForSingleObject(th, DWORD(Timeout));
|
||||||
|
};
|
||||||
|
protected:
|
||||||
|
bool Started;
|
||||||
|
public:
|
||||||
|
bool Terminated;
|
||||||
|
bool Closed;
|
||||||
|
bool FreeOnTerminate;
|
||||||
|
TSnapThread();
|
||||||
|
virtual ~TSnapThread();
|
||||||
|
|
||||||
|
virtual void Execute()
|
||||||
|
{
|
||||||
|
};
|
||||||
|
void Start();
|
||||||
|
void Terminate();
|
||||||
|
void Kill();
|
||||||
|
void Join();
|
||||||
|
longword WaitFor(uint64_t Timeout);
|
||||||
|
};
|
||||||
|
typedef TSnapThread *PSnapThread;
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
#endif // win_threads_h
|
Loading…
x
Reference in New Issue
Block a user