248 lines
9.3 KiB
C++
248 lines
9.3 KiB
C++
/*=============================================================================|
|
|
| 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
|