401 lines
10 KiB
Plaintext
401 lines
10 KiB
Plaintext
|
{
|
||
|
$Project$
|
||
|
$Workfile$
|
||
|
$Revision$
|
||
|
$DateUTC$
|
||
|
$Id$
|
||
|
|
||
|
This file is part of the Indy (Internet Direct) project, and is offered
|
||
|
under the dual-licensing agreement described on the Indy website.
|
||
|
(http://www.indyproject.org/)
|
||
|
|
||
|
Copyright:
|
||
|
(c) 1993-2005, Chad Z. Hower and the Indy Pit Crew. All rights reserved.
|
||
|
}
|
||
|
{
|
||
|
$Log$
|
||
|
}
|
||
|
{
|
||
|
Rev 1.0 11/13/2002 08:03:48 AM JPMugaas
|
||
|
}
|
||
|
|
||
|
unit IdTunnelCommon;
|
||
|
|
||
|
{*
|
||
|
Indy Tunnel components module
|
||
|
Copyright (C) 1999, 2000, 2001 Gregor Ibic (gregor.ibic@intelicom.si)
|
||
|
Intelicom d.o.o., www.intelicom.si
|
||
|
This component is published under same license like Indy package.
|
||
|
|
||
|
This package is a TCP Tunnel implementation written
|
||
|
by Gregor Ibic (gregor.ibic@intelicom.si).
|
||
|
|
||
|
|
||
|
This notice may not be removed or altered from any source
|
||
|
distribution.
|
||
|
|
||
|
// MAJOR CHANGES
|
||
|
05-January-20001
|
||
|
GI: Major code reorganization and polishing
|
||
|
31-May-2000
|
||
|
GI TunnelHeaders eliminated. Some other code jugling.
|
||
|
29-May-2000
|
||
|
GI Components split in several files to be more compliant
|
||
|
with Indy coding standards.
|
||
|
It consists of:
|
||
|
- IdTunnelHeaders
|
||
|
- IdTunnelCommon
|
||
|
- IdTunnelMaster
|
||
|
- IdTunnelSlave
|
||
|
24-May-2000
|
||
|
GI: Turbo translation mode finished (01:24). It works!
|
||
|
Will draw icons in the morning.
|
||
|
23-May-2000
|
||
|
GI: Turbo translation mode to Indy standard started by
|
||
|
Gregor Ibic (hehe) (now is 23:15)
|
||
|
|
||
|
*}
|
||
|
|
||
|
interface
|
||
|
{$i IdCompilerDefines.inc}
|
||
|
|
||
|
uses
|
||
|
SysUtils, Classes, SyncObjs,
|
||
|
IdException,
|
||
|
IdHashCRC,
|
||
|
IdStack,
|
||
|
IdCoder, IdResourceStrings,
|
||
|
IdTCPServer;
|
||
|
|
||
|
|
||
|
const
|
||
|
BUFFERLEN = $4000;
|
||
|
|
||
|
// Statistics constants
|
||
|
NumberOfConnectionsType = 1;
|
||
|
NumberOfPacketsType = 2;
|
||
|
CompressionRatioType = 3;
|
||
|
CompressedBytesType = 4;
|
||
|
BytesReadType = 5;
|
||
|
BytesWriteType = 6;
|
||
|
NumberOfClientsType = 7;
|
||
|
NumberOfSlavesType = 8;
|
||
|
NumberOfServicesType = 9;
|
||
|
|
||
|
// Message types
|
||
|
tmError = 0;
|
||
|
tmData = 1;
|
||
|
tmDisconnect = 2;
|
||
|
tmConnect = 3;
|
||
|
tmCustom = 99;
|
||
|
|
||
|
|
||
|
type
|
||
|
TIdStatisticsOperation = (soIncrease,
|
||
|
soDecrease
|
||
|
);
|
||
|
|
||
|
TIdHeader = record
|
||
|
CRC16: Word;
|
||
|
MsgType: Word;
|
||
|
MsgLen: Word;
|
||
|
UserId: Word;
|
||
|
Port: Word;
|
||
|
IpAddr: TIdInAddr;
|
||
|
end;
|
||
|
|
||
|
TReceiver = class(TObject)
|
||
|
private
|
||
|
fiPrenosLen: LongInt;
|
||
|
fiMsgLen: LongInt;
|
||
|
fsData: String;
|
||
|
fbNewMessage: Boolean;
|
||
|
fCRCFailed: Boolean;
|
||
|
Locker: TCriticalSection;
|
||
|
CRC16Calculator: TIdHashCRC16;
|
||
|
function FNewMessage: Boolean;
|
||
|
procedure SetData(const Value: string);
|
||
|
public
|
||
|
pBuffer: PChar;
|
||
|
HeaderLen: Integer;
|
||
|
Header: TIdHeader;
|
||
|
MsgLen: Word;
|
||
|
TypeDetected: Boolean;
|
||
|
Msg: PChar;
|
||
|
property Data: String read fsData write SetData;
|
||
|
property NewMessage: Boolean read FNewMessage;
|
||
|
property CRCFailed: Boolean read fCRCFailed;
|
||
|
procedure ShiftData;
|
||
|
constructor Create;
|
||
|
destructor Destroy; override;
|
||
|
end;
|
||
|
|
||
|
|
||
|
TSender = class(TObject)
|
||
|
public
|
||
|
Header: TIdHeader;
|
||
|
DataLen: Word;
|
||
|
HeaderLen: Integer;
|
||
|
pMsg: PChar;
|
||
|
Locker: TCriticalSection;
|
||
|
CRC16Calculator: TIdHashCRC16;
|
||
|
public
|
||
|
Msg: String;
|
||
|
procedure PrepareMsg(var Header: TIdHeader;
|
||
|
buffer: PChar; buflen: Integer);
|
||
|
constructor Create;
|
||
|
destructor Destroy; override;
|
||
|
end;
|
||
|
//
|
||
|
// END Communication classes
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
// Logging class
|
||
|
//
|
||
|
TLogger = class(TObject)
|
||
|
private
|
||
|
OnlyOneThread: TCriticalSection; // Some locking code
|
||
|
fLogFile: TextFile; // Debug Log File
|
||
|
fbActive: Boolean;
|
||
|
public
|
||
|
property Active: Boolean read fbActive Default False;
|
||
|
procedure LogEvent(Msg: String);
|
||
|
constructor Create(LogFileName: String);
|
||
|
destructor Destroy; override;
|
||
|
end;
|
||
|
//
|
||
|
// Logging class
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
|
||
|
TSendMsgEvent = procedure(Thread: TIdPeerThread; var CustomMsg: String) of object;
|
||
|
TSendTrnEvent = procedure(Thread: TIdPeerThread; var Header: TIdHeader; var CustomMsg: String) of object;
|
||
|
TSendTrnEventC = procedure(var Header: TIdHeader; var CustomMsg: String) of object;
|
||
|
TTunnelEventC = procedure(Receiver: TReceiver) of object;
|
||
|
TSendMsgEventC = procedure(var CustomMsg: String) of object;
|
||
|
// TTunnelEvent = procedure(Thread: TSlaveThread) of object;
|
||
|
|
||
|
EIdTunnelException = class(EIdException);
|
||
|
EIdTunnelTransformErrorBeforeSend = class(EIdTunnelException);
|
||
|
EIdTunnelTransformError = class(EIdTunnelException);
|
||
|
EIdTunnelConnectToMasterFailed = class(EIdTunnelException);
|
||
|
EIdTunnelDontAllowConnections = class(EIdTunnelException);
|
||
|
EIdTunnelCRCFailed = class(EIdTunnelException);
|
||
|
EIdTunnelMessageTypeRecognitionError = class(EIdTunnelException);
|
||
|
EIdTunnelMessageHandlingFailed = class(EIdTunnelException);
|
||
|
EIdTunnelInterpretationOfMessageFailed = class(EIdTunnelException);
|
||
|
EIdTunnelCustomMessageInterpretationFailure = class(EIdTunnelException);
|
||
|
|
||
|
implementation
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
// Communication classes
|
||
|
//
|
||
|
constructor TSender.Create;
|
||
|
begin
|
||
|
inherited;
|
||
|
Locker := TCriticalSection.Create;
|
||
|
CRC16Calculator := TIdHashCRC16.Create;
|
||
|
HeaderLen := SizeOf(TIdHeader);
|
||
|
GetMem(pMsg, BUFFERLEN);
|
||
|
end;
|
||
|
|
||
|
destructor TSender.Destroy;
|
||
|
begin
|
||
|
FreeMem(pMsg, BUFFERLEN);
|
||
|
Locker.Free;
|
||
|
CRC16Calculator.Free;
|
||
|
inherited;
|
||
|
end;
|
||
|
|
||
|
procedure TSender.PrepareMsg(var Header: TIdHeader;
|
||
|
buffer: PChar; buflen: Integer);
|
||
|
begin
|
||
|
Locker.Enter;
|
||
|
try
|
||
|
//Header.MsgType := mType;
|
||
|
Header.CRC16 := CRC16Calculator.HashValue(buffer^);
|
||
|
Header.MsgLen := Headerlen + bufLen;
|
||
|
//Header.UserId := mUser;
|
||
|
//Header.Port := Port;
|
||
|
//Header.IpAddr := IPAddr;
|
||
|
Move(Header, pMsg^, Headerlen);
|
||
|
Move(buffer^, (pMsg + Headerlen)^, bufLen);
|
||
|
SetLength(Msg, Header.MsgLen);
|
||
|
SetString(Msg, pMsg, Header.MsgLen);
|
||
|
finally
|
||
|
Locker.Leave;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
|
||
|
|
||
|
constructor TReceiver.Create;
|
||
|
begin
|
||
|
inherited;
|
||
|
Locker := TCriticalSection.Create;
|
||
|
CRC16Calculator := TIdHashCRC16.Create;
|
||
|
fiPrenosLen := 0;
|
||
|
fsData := ''; {Do not Localize}
|
||
|
fiMsgLen := 0;
|
||
|
HeaderLen := SizeOf(TIdHeader);
|
||
|
GetMem(pBuffer, BUFFERLEN);
|
||
|
GetMem(Msg, BUFFERLEN);
|
||
|
end;
|
||
|
|
||
|
|
||
|
destructor TReceiver.Destroy;
|
||
|
begin
|
||
|
FreeMem(pBuffer, BUFFERLEN);
|
||
|
FreeMem(Msg, BUFFERLEN);
|
||
|
Locker.Free;
|
||
|
CRC16Calculator.Free;
|
||
|
inherited;
|
||
|
end;
|
||
|
|
||
|
function TReceiver.FNewMessage: Boolean;
|
||
|
begin
|
||
|
Result := fbNewMessage;
|
||
|
end;
|
||
|
|
||
|
procedure TReceiver.SetData(const Value: string);
|
||
|
var
|
||
|
CRC16: Word;
|
||
|
begin
|
||
|
Locker.Enter;
|
||
|
try
|
||
|
try
|
||
|
fsData := Value;
|
||
|
fiMsgLen := Length(fsData);
|
||
|
if fiMsgLen > 0 then begin
|
||
|
Move(fsData[1], (pBuffer + fiPrenosLen)^, fiMsgLen);
|
||
|
fiPrenosLen := fiPrenosLen + fiMsgLen;
|
||
|
if (fiPrenosLen >= HeaderLen) then begin
|
||
|
// copy the header
|
||
|
Move(pBuffer^, Header, HeaderLen);
|
||
|
TypeDetected := True;
|
||
|
// do we have enough data for the entire message
|
||
|
if Header.MsgLen <= fiPrenosLen then begin
|
||
|
MsgLen := Header.MsgLen - HeaderLen;
|
||
|
Move((pBuffer+HeaderLen)^, Msg^, MsgLen);
|
||
|
// Calculate the crc code
|
||
|
CRC16 := CRC16Calculator.HashValue(Msg^);
|
||
|
if CRC16 <> Header.CRC16 then begin
|
||
|
fCRCFailed := True;
|
||
|
end
|
||
|
else begin
|
||
|
fCRCFailed := False;
|
||
|
end;
|
||
|
fbNewMessage := True;
|
||
|
end
|
||
|
else begin
|
||
|
fbNewMessage := False;
|
||
|
end;
|
||
|
end
|
||
|
else begin
|
||
|
TypeDetected := False;
|
||
|
end;
|
||
|
end
|
||
|
else begin
|
||
|
fbNewMessage := False;
|
||
|
TypeDetected := False;
|
||
|
end;
|
||
|
except
|
||
|
raise;
|
||
|
end;
|
||
|
|
||
|
finally
|
||
|
Locker.Leave;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TReceiver.ShiftData;
|
||
|
var
|
||
|
CRC16: Word;
|
||
|
begin
|
||
|
Locker.Enter;
|
||
|
try
|
||
|
fiPrenosLen := fiPrenosLen - Header.MsgLen;
|
||
|
// check if we have another entire message
|
||
|
if fiPrenosLen > 0 then begin
|
||
|
Move((pBuffer + Header.MsgLen)^, pBuffer^, fiPrenosLen);
|
||
|
end;
|
||
|
|
||
|
// check if we have another entire message
|
||
|
if (fiPrenosLen >= HeaderLen) then begin
|
||
|
// copy the header
|
||
|
Move(pBuffer^, Header, HeaderLen);
|
||
|
TypeDetected := True;
|
||
|
// do we have enough data for the entire message
|
||
|
if Header.MsgLen <= fiPrenosLen then begin
|
||
|
MsgLen := Header.MsgLen - HeaderLen;
|
||
|
Move((pBuffer+HeaderLen)^, Msg^, MsgLen);
|
||
|
// Calculate the crc code
|
||
|
CRC16 := CRC16Calculator.HashValue(Msg^);
|
||
|
if CRC16 <> Header.CRC16 then begin
|
||
|
fCRCFailed := True;
|
||
|
end
|
||
|
else begin
|
||
|
fCRCFailed := False;
|
||
|
end;
|
||
|
fbNewMessage := True;
|
||
|
end
|
||
|
else begin
|
||
|
fbNewMessage := False;
|
||
|
end;
|
||
|
end
|
||
|
else begin
|
||
|
TypeDetected := False;
|
||
|
end;
|
||
|
finally
|
||
|
Locker.Leave;
|
||
|
end;
|
||
|
end;
|
||
|
//
|
||
|
// END Communication classes
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
// Logging class
|
||
|
//
|
||
|
constructor TLogger.Create(LogFileName: String);
|
||
|
begin
|
||
|
fbActive := False;
|
||
|
OnlyOneThread := TCriticalSection.Create;
|
||
|
try
|
||
|
AssignFile(fLogFile, LogFileName);
|
||
|
Rewrite(fLogFile);
|
||
|
fbActive := True;
|
||
|
except
|
||
|
fbActive := False; //self.Destroy; // catch file i/o errors, double create file
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
destructor TLogger.Destroy;
|
||
|
begin
|
||
|
if fbActive then
|
||
|
CloseFile(fLogFile);
|
||
|
OnlyOneThread.Free;
|
||
|
inherited;
|
||
|
end;
|
||
|
|
||
|
procedure TLogger.LogEvent(Msg: String);
|
||
|
begin
|
||
|
OnlyOneThread.Enter;
|
||
|
try
|
||
|
WriteLn(fLogFile, Msg);
|
||
|
Flush(fLogFile);
|
||
|
finally
|
||
|
OnlyOneThread.Leave;
|
||
|
end;
|
||
|
end;
|
||
|
//
|
||
|
// Logging class
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
|
||
|
end.
|