mysticbbs/mystic/mis_server.pas

315 lines
7.7 KiB
ObjectPascal
Raw Normal View History

2013-02-15 20:18:11 -08:00
Unit MIS_Server;
2012-02-13 16:53:02 -08:00
{$I M_OPS.PAS}
Interface
Uses
Classes,
m_io_Base,
m_io_Sockets,
2012-02-13 16:53:02 -08:00
MIS_Common,
MIS_NodeData;
Const
MaxStatusText = 20;
2012-02-13 16:53:02 -08:00
Type
TServerManager = Class;
TServerClient = Class;
2013-05-06 17:07:39 -07:00
TServerCreateProc = Function (Manager: TServerManager; Cfg: RecConfig; ND: TNodeData; Client: TIOSocket): TServerClient;
2012-02-13 16:53:02 -08:00
TServerManager = Class(TThread)
Critical : TRTLCriticalSection;
2012-02-13 16:53:02 -08:00
NodeInfo : TNodeData;
Server : TIOSocket;
ServerStatus : TStringList;
StatusUpdated : Boolean;
2012-02-13 16:53:02 -08:00
ClientList : TList;
NewClientProc : TServerCreateProc;
Config : RecConfig;
ClientMax : LongInt;
ClientMaxIPs : LongInt;
ClientRefused : LongInt;
ClientBlocked : LongInt;
ClientTotal : LongInt;
ClientActive : LongInt;
Port : LongInt;
TextPath : String[80];
2013-05-06 17:07:39 -07:00
Constructor Create (Cfg: RecConfig; PortNum: Word; CliMax: Word; ND: TNodeData; CreateProc: TServerCreateProc);
2012-02-27 15:38:09 -08:00
Destructor Destroy; Override;
Procedure Execute; Override;
Procedure Status (Str: String);
2012-02-27 15:38:09 -08:00
Function CheckIP (IP, Mask: String) : Boolean;
Function IsBlockedIP (Var Client: TIOSocket) : Boolean;
Function DuplicateIPs (Var Client: TIOSocket) : Byte;
2012-02-13 16:53:02 -08:00
End;
TServerClient = Class(TThread)
Client : TIOSocket;
2012-02-13 16:53:02 -08:00
Manager : TServerManager;
Constructor Create (Owner: TServerManager; CliSock: TIOSocket);
2012-02-13 16:53:02 -08:00
Destructor Destroy; Override;
End;
Implementation
Uses
m_Strings,
m_DateTime;
2013-05-06 17:07:39 -07:00
Constructor TServerManager.Create (Cfg: RecConfig; PortNum: Word; CliMax: Word; ND: TNodeData; CreateProc: TServerCreateProc);
2012-02-13 16:53:02 -08:00
Var
Count : Byte;
Begin
Inherited Create(False);
InitCriticalSection(Critical);
2012-02-13 16:53:02 -08:00
Port := PortNum;
ClientMax := CliMax;
ClientRefused := 0;
ClientBlocked := 0;
ClientTotal := 0;
ClientActive := 0;
ClientMaxIPs := 1;
NewClientProc := CreateProc;
Server := TIOSocket.Create;
ServerStatus := TStringList.Create;
StatusUpdated := False;
2012-02-13 16:53:02 -08:00
ClientList := TList.Create;
TextPath := Config.DataPath;
NodeInfo := ND;
2013-05-06 17:07:39 -07:00
Config := Cfg;
2012-02-13 16:53:02 -08:00
For Count := 1 to ClientMax Do
ClientList.Add(NIL);
FreeOnTerminate := False;
End;
Function TServerManager.CheckIP (IP, Mask: String) : Boolean;
Var
A : Byte;
Count : Byte;
Str : String;
Str2 : String;
Begin
Result := True;
For Count := 1 to 4 Do Begin
If Count < 4 Then Begin
Str := Copy(IP, 1, Pos('.', IP) - 1);
Str2 := Copy(Mask, 1, Pos('.', Mask) - 1);
Delete (IP, 1, Pos('.', IP));
Delete (Mask, 1, Pos('.', Mask));
End Else Begin
Str := Copy(IP, 1, Length(IP));
Str2 := Copy(Mask, 1, Length(Mask));
End;
For A := 1 to Length(Str) Do
If Str2[A] = '*' Then
Break
Else
If Str[A] <> Str2[A] Then Begin
Result := False;
Break;
End;
If Not Result Then Break;
End;
End;
Function TServerManager.IsBlockedIP (Var Client: TIOSocket) : Boolean;
2012-02-13 16:53:02 -08:00
Var
TF : Text;
Str : String;
Begin
Result := False;
FileMode := 66;
Assign (TF, TextPath + 'badip.txt');
Reset (TF);
If IoResult = 0 Then Begin
While Not Eof(TF) Do Begin
ReadLn (TF, Str);
2012-08-19 13:46:22 -07:00
2012-02-13 16:53:02 -08:00
If CheckIP (Client.PeerIP, Str) Then Begin
Result := True;
Break;
End;
End;
Close (TF);
End;
End;
Function TServerManager.DuplicateIPs (Var Client: TIOSocket) : Byte;
2012-02-13 16:53:02 -08:00
Var
Count : Byte;
Begin
Result := 0;
For Count := 0 to ClientMax - 1 Do
If Assigned(ClientList[Count]) Then Begin
2012-08-19 13:46:22 -07:00
If Client.PeerIP = TServerClient(ClientList[Count]).Client.FPeerIP Then
2012-02-13 16:53:02 -08:00
Inc(Result);
End;
2012-02-13 16:53:02 -08:00
End;
Procedure TServerManager.Status (Str: String);
Var
Res : String;
Begin
If ServerStatus = NIL Then Exit;
EnterCriticalSection(Critical);
Try
If ServerStatus.Count > MaxStatusText Then
ServerStatus.Delete(0);
2013-03-18 22:48:11 -07:00
Res := '(' + Copy(DateDos2Str(CurDateDos, 1), 1, 5) + ' ' + TimeDos2Str(CurDateDos, 0) + ') ' + Str;
If Length(Res) > 74 Then Begin
ServerStatus.Add(Copy(Res, 1, 74));
If ServerStatus.Count > MaxStatusText Then
ServerStatus.Delete(0);
ServerStatus.Add(strRep(' ', 14) + Copy(Res, 75, 255));
End Else
ServerStatus.Add(Res);
Except
{ ignore exceptions here -- happens when socketstatus is NIL}
{ need to review criticals now that they are in FP's RTL}
End;
StatusUpdated := True;
LeaveCriticalSection(Critical);
End;
2012-02-13 16:53:02 -08:00
Procedure TServerManager.Execute;
Var
NewClient : TIOSocket;
2012-02-13 16:53:02 -08:00
Begin
Repeat Until Server <> NIL; // Synchronize with server class
Repeat Until ServerStatus <> NIL; // Syncronize with status class
2012-02-13 16:53:02 -08:00
2013-05-06 17:07:39 -07:00
Server.WaitInit(Config.inetInterface, Port);
2012-02-13 16:53:02 -08:00
If Terminated Then Exit;
If ClientMax = 0 Then
Status('WARNING: At least one server is configured with 0 max clients.');
2012-02-13 16:53:02 -08:00
Status('Opening server socket on port ' + strI2S(Port));
2012-02-13 16:53:02 -08:00
Repeat
NewClient := Server.WaitConnection;
If NewClient = NIL Then Break; // time to shutdown the server...
2012-02-13 16:53:02 -08:00
If (ClientMax > 0) And (ClientActive >= ClientMax) Then Begin
Inc (ClientRefused);
Status ('BUSY: ' + NewClient.PeerIP + ' (' + NewClient.PeerName + ')');
2012-02-13 16:53:02 -08:00
If Not NewClient.WriteFile(TextPath + 'busy.txt') Then NewClient.WriteLine('BUSY');
2012-08-19 13:46:22 -07:00
WaitMS(3000);
2012-02-13 16:53:02 -08:00
NewClient.Free;
End Else
If IsBlockedIP(NewClient) Then Begin
Inc (ClientBlocked);
Status('BLOCK: ' + NewClient.PeerIP + ' (' + NewClient.PeerName + ')');
2012-02-13 16:53:02 -08:00
If Not NewClient.WriteFile(TextPath + 'blocked.txt') Then NewClient.WriteLine('BLOCKED');
2012-08-19 13:46:22 -07:00
WaitMS(3000);
2012-02-13 16:53:02 -08:00
NewClient.Free;
End Else
If (ClientMaxIPs > 0) and (DuplicateIPs(NewClient) >= ClientMaxIPs) Then Begin
2012-02-13 16:53:02 -08:00
Inc (ClientRefused);
Status('MULTI: ' + NewClient.PeerIP + ' (' + NewClient.PeerName + ')');
2012-02-13 16:53:02 -08:00
If Not NewClient.WriteFile(TextPath + 'dupeip.txt') Then NewClient.WriteLine('Only ' + strI2S(ClientMaxIPs) + ' connection(s) per user');
2012-08-19 13:46:22 -07:00
WaitMS(3000);
2012-02-13 16:53:02 -08:00
NewClient.Free;
End Else Begin
Inc (ClientTotal);
Inc (ClientActive);
Status ('Connect: ' + NewClient.PeerIP + ' (' + NewClient.PeerName + ')');
2012-02-13 16:53:02 -08:00
NewClientProc(Self, Config, NodeInfo, NewClient);
End;
Until Terminated;
Status ('Shutting down server...');
2012-02-13 16:53:02 -08:00
End;
Destructor TServerManager.Destroy;
Var
Count : LongInt;
Angry : Byte;
Begin
Angry := 20; // about 5 seconds before we get mad at thread...
ClientList.Pack;
While (ClientList.Count > 0) and (Angry > 0) Do Begin
For Count := 0 To ClientList.Count - 1 Do
If ClientList[Count] <> NIL Then Begin
TServerClient(ClientList[Count]).Client.Disconnect;
TServerClient(ClientList[Count]).Terminate;
End;
WaitMS(250);
Dec (Angry);
ClientList.Pack;
End;
DoneCriticalSection(Critical);
2012-02-13 16:53:02 -08:00
ClientList.Free;
ServerStatus.Free;
2012-02-13 16:53:02 -08:00
Server.Free;
Inherited Destroy;
End;
Constructor TServerClient.Create (Owner: TServerManager; CliSock: TIOSocket);
2012-02-13 16:53:02 -08:00
Var
Count : Byte;
Begin
Manager := Owner;
Client := CliSock;
For Count := 0 to Manager.ClientMax - 1 Do
If Manager.ClientList[Count] = NIL Then Begin
Manager.ClientList[Count] := Self;
Break;
End;
Inherited Create(False);
FreeOnTerminate := True;
End;
Destructor TServerClient.Destroy;
Begin
Client.Free;
Manager.ClientList[Manager.ClientList.IndexOf(Self)] := NIL;
If Manager.Server <> NIL Then
Manager.StatusUpdated := True;
2012-02-13 16:53:02 -08:00
Dec (Manager.ClientActive);
Inherited Destroy;
End;
End.