307 lines
8.4 KiB
Plaintext
307 lines
8.4 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.15 7/9/04 4:26:28 PM RLebeau
|
|
Removed TIdBytes local variable from Send()
|
|
|
|
Rev 1.14 09/06/2004 00:28:00 CCostelloe
|
|
Kylix 3 patch
|
|
|
|
Rev 1.13 4/25/2004 7:54:26 AM JPMugaas
|
|
Fix for AV.
|
|
|
|
Rev 1.12 2/8/2004 12:58:42 PM JPMugaas
|
|
Should now compile in DotNET.
|
|
|
|
Rev 1.11 2004.02.03 4:16:48 PM czhower
|
|
For unit name changes.
|
|
|
|
Rev 1.10 2/1/2004 6:10:14 PM JPMugaas
|
|
Should compile better.
|
|
|
|
Rev 1.9 2/1/2004 4:52:34 PM JPMugaas
|
|
Removed the rest of the Todo; items.
|
|
|
|
Rev 1.8 2004.01.20 10:03:30 PM czhower
|
|
InitComponent
|
|
|
|
Rev 1.7 2004.01.02 9:38:46 PM czhower
|
|
Removed warning
|
|
|
|
Rev 1.6 2003.10.24 10:09:54 AM czhower
|
|
Compiles
|
|
|
|
Rev 1.5 2003.10.20 12:03:08 PM czhower
|
|
Added IdStackBSDBase to make it compile again.
|
|
|
|
Rev 1.4 10/19/2003 10:41:12 PM BGooijen
|
|
Compiles in DotNet and D7 again
|
|
|
|
Rev 1.3 10/19/2003 9:34:28 PM BGooijen
|
|
SetSocketOption
|
|
|
|
Rev 1.2 2003.10.11 5:48:58 PM czhower
|
|
-VCL fixes for servers
|
|
-Chain suport for servers (Super core)
|
|
-Scheduler upgrades
|
|
-Full yarn support
|
|
|
|
Rev 1.1 2003.09.30 1:23:00 PM czhower
|
|
Stack split for DotNet
|
|
|
|
Rev 1.0 11/13/2002 08:45:24 AM JPMugaas
|
|
}
|
|
|
|
unit IdRawBase;
|
|
|
|
interface
|
|
|
|
{
|
|
We need to selectively disable some functionality in DotNET with buffers as
|
|
we don't want to impact anything else such as TIdICMPClient.
|
|
}
|
|
|
|
{$I IdCompilerDefines.inc}
|
|
|
|
uses
|
|
IdComponent, IdGlobal, IdSocketHandle, IdStack,
|
|
{$IFDEF MSWINDOWS}
|
|
IdWship6,
|
|
{$ENDIF}
|
|
IdStackConsts;
|
|
|
|
const
|
|
Id_TIdRawBase_Port = 0;
|
|
Id_TIdRawBase_BufferSize = 8192;
|
|
GReceiveTimeout = 0;
|
|
GFTTL = 128;
|
|
|
|
type
|
|
TIdRawBase = class(TIdComponent)
|
|
protected
|
|
FBinding: TIdSocketHandle;
|
|
FHost: string;
|
|
FPort: TIdPort;
|
|
FReceiveTimeout: integer;
|
|
FProtocol: TIdSocketProtocol;
|
|
FProtocolIPv6 : TIdSocketProtocol;
|
|
FTTL: Integer;
|
|
FPkt : TIdPacketInfo;
|
|
FConnected : Boolean;
|
|
//
|
|
function GetBinding: TIdSocketHandle;
|
|
function GetIPVersion: TIdIPVersion;
|
|
//
|
|
procedure InitComponent; override;
|
|
procedure SetIPVersion(const AValue: TIdIPVersion);
|
|
procedure SetTTL(const Value: Integer);
|
|
procedure SetHost(const AValue : String); virtual;
|
|
//
|
|
// TODO: figure out which ReceiveXXX functions we want
|
|
//
|
|
property IPVersion : TIdIPVersion read GetIPVersion write SetIPVersion;
|
|
//
|
|
property Port: TIdPort read FPort write FPort default Id_TIdRawBase_Port;
|
|
property Protocol: TIdSocketProtocol read FProtocol write FProtocol default Id_IPPROTO_RAW;
|
|
property ProtocolIPv6 : TIdSocketProtocol read FProtocolIPv6 write FProtocolIPv6;
|
|
property TTL: Integer read FTTL write SetTTL default GFTTL;
|
|
|
|
public
|
|
destructor Destroy; override;
|
|
|
|
function ReceiveBuffer(var VBuffer : TIdBytes; ATimeOut: Integer = -1): Integer;
|
|
procedure Send(const AData: string; AByteEncoding: IIdTextEncoding = nil
|
|
{$IFDEF STRING_IS_ANSI}; ASrcEncoding: IIdTextEncoding = nil{$ENDIF}
|
|
); overload; virtual;
|
|
procedure Send(const AData: TIdBytes); overload; virtual;
|
|
procedure Send(const AHost: string; const APort: TIdPort; const AData: string;
|
|
AByteEncoding: IIdTextEncoding = nil
|
|
{$IFDEF STRING_IS_ANSI}; ASrcEncoding: IIdTextEncoding = nil{$ENDIF}
|
|
); overload; virtual;
|
|
procedure Send(const AHost: string; const APort: TIdPort; const ABuffer : TIdBytes); overload; virtual;
|
|
//
|
|
property Binding: TIdSocketHandle read GetBinding;
|
|
property ReceiveTimeout: integer read FReceiveTimeout write FReceiveTimeout Default GReceiveTimeout;
|
|
published
|
|
property Host: string read FHost write SetHost;
|
|
end;
|
|
|
|
|
|
implementation
|
|
|
|
uses
|
|
SysUtils;
|
|
|
|
{ TIdRawBase }
|
|
|
|
destructor TIdRawBase.Destroy;
|
|
begin
|
|
FreeAndNil(FBinding);
|
|
FreeAndNil(FPkt);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TIdRawBase.GetBinding: TIdSocketHandle;
|
|
begin
|
|
if not FBinding.HandleAllocated then begin
|
|
if FBinding.IPVersion = Id_IPv4 then
|
|
begin
|
|
FBinding.AllocateSocket(Id_SOCK_RAW, FProtocol);
|
|
end else
|
|
begin
|
|
FBinding.AllocateSocket(Id_SOCK_RAW, FProtocolIPv6);
|
|
{$IFDEF DOTNET}
|
|
{$IFDEF DOTNET_2_OR_ABOVE}
|
|
{
|
|
Microsoft NET Framework 1.1 may actually have the packetinfo option but that
|
|
will not do you any good because you need a RecvMsg function which is not
|
|
in NET 1.1. NET 2.0 does have a RecvMsg function, BTW.
|
|
}
|
|
//indicate we want packet information with RecvMsg calls
|
|
FBinding.SetSockOpt(Id_SOL_IPv6, Id_IPV6_PKTINFO, 1);
|
|
{$ENDIF}
|
|
{$ELSE}
|
|
//indicate we want packet information with RecvMsg WSARecvMsg calls
|
|
FBinding.SetSockOpt(Id_SOL_IPv6, Id_IPV6_PKTINFO, 1);
|
|
FBinding.SetSockOpt(Id_SOL_IPv6, Id_IPV6_HOPLIMIT, 1);
|
|
{$ENDIF}
|
|
end;
|
|
//set hop limit (or TTL as it was called in IPv4
|
|
FBinding.SetTTL(FTTL);
|
|
end;
|
|
Result := FBinding;
|
|
end;
|
|
|
|
function TIdRawBase.ReceiveBuffer(var VBuffer : TIdBytes; ATimeOut: Integer = -1): Integer;
|
|
var
|
|
LIP : String;
|
|
LPort : TIdPort;
|
|
LIPVersion: TIdIPVersion;
|
|
begin
|
|
Result := 0;
|
|
// TODO: pass flags to recv()
|
|
if ATimeOut < 0 then
|
|
begin
|
|
ATimeOut := FReceiveTimeout;
|
|
end;
|
|
if Length(VBuffer) > 0 then
|
|
begin
|
|
if Binding.Readable(ATimeOut) then begin
|
|
if FBinding.IPVersion = Id_IPv4 then
|
|
begin
|
|
Result := Binding.RecvFrom(VBuffer, LIP, LPort, LIPVersion);
|
|
FPkt.Reset;
|
|
FPkt.SourceIP := LIP;
|
|
FPkt.SourcePort := LPort;
|
|
FPkt.SourceIPVersion := LIPVersion;
|
|
FPkt.DestIPVersion := LIPVersion;
|
|
end else
|
|
begin
|
|
{
|
|
IMPORTANT!!!!
|
|
|
|
Do NOT call GStack.ReceiveMsg unless it is absolutely necessary.
|
|
The reasons are:
|
|
|
|
1) WSARecvMsg is only supported on WindowsXP or later. I think Linux
|
|
might have a RecvMsg function as well but I'm not sure.
|
|
2) GStack.ReceiveMsg is not supported in the Microsoft NET framework 1.1.
|
|
It may be supported in later versions.
|
|
|
|
For IPv4 and raw sockets, it usually isn't because we get the raw header itself.
|
|
|
|
For IPv6 and raw sockets, we call this to get information about the destination
|
|
IP address and hopefully, the TTL (hop count).
|
|
}
|
|
|
|
Result := GStack.ReceiveMsg(Binding.Handle, VBuffer, FPkt);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TIdRawBase.Send(const AHost: string; const APort: TIdPort; const AData: string;
|
|
AByteEncoding: IIdTextEncoding = nil
|
|
{$IFDEF STRING_IS_ANSI}; ASrcEncoding: IIdTextEncoding = nil{$ENDIF}
|
|
);
|
|
begin
|
|
Send(AHost, APort, ToBytes(AData, AByteEncoding{$IFDEF STRING_IS_ANSI}, ASrcEncoding{$ENDIF}));
|
|
end;
|
|
|
|
procedure TIdRawBase.Send(const AData: string;
|
|
AByteEncoding: IIdTextEncoding = nil
|
|
{$IFDEF STRING_IS_ANSI}; ASrcEncoding: IIdTextEncoding = nil{$ENDIF}
|
|
);
|
|
begin
|
|
Send(ToBytes(AData, AByteEncoding{$IFDEF STRING_IS_ANSI}, ASrcEncoding{$ENDIF}));
|
|
end;
|
|
|
|
procedure TIdRawBase.Send(const AData: TIdBytes);
|
|
begin
|
|
Send(Host, Port, AData);
|
|
end;
|
|
|
|
procedure TIdRawBase.Send(const AHost: string; const APort: TIdPort; const ABuffer : TIdBytes);
|
|
var
|
|
LIP : String;
|
|
begin
|
|
LIP := GStack.ResolveHost(AHost, FBinding.IPVersion);
|
|
Binding.SendTo(LIP, APort, ABuffer, FBinding.IPVersion);
|
|
end;
|
|
|
|
procedure TIdRawBase.SetTTL(const Value: Integer);
|
|
begin
|
|
if FTTL <> Value then
|
|
begin
|
|
FTTL := Value;
|
|
if FBinding.HandleAllocated then
|
|
begin
|
|
FBinding.SetTTL(FTTL);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TIdRawBase.InitComponent;
|
|
begin
|
|
inherited InitComponent;
|
|
FBinding := TIdSocketHandle.Create(nil);
|
|
FBinding.IPVersion := Id_IPv4;
|
|
FPkt := TIdPacketInfo.Create;
|
|
ReceiveTimeout := GReceiveTimeout;
|
|
FPort := Id_TIdRawBase_Port;
|
|
FProtocol := Id_IPPROTO_RAW;
|
|
FTTL := GFTTL;
|
|
end;
|
|
|
|
function TIdRawBase.GetIPVersion;
|
|
begin
|
|
Result := FBinding.IPVersion;
|
|
end;
|
|
|
|
procedure TIdRawBase.SetIPVersion(const AValue: TIdIPVersion);
|
|
begin
|
|
FBinding.IPVersion := AValue;
|
|
end;
|
|
|
|
procedure TIdRawBase.SetHost(const AValue: String);
|
|
begin
|
|
FHost := AValue;
|
|
end;
|
|
|
|
end.
|