restemplate/indy/Core/IdUDPBase.pas

386 lines
12 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 11/12/2004 11:30:18 AM JPMugaas
Expansions for IPv6.
Rev 1.14 11/11/04 12:05:32 PM RLebeau
Updated ReceiveBuffer() to set AMSec to IdTimeoutInfinite when the
ReceiveTimeout property is 0
Rev 1.13 11/7/2004 11:33:30 PM JPMugaas
Now uses Connect, Disconnect, Send, and Receive similarly to the TCP Clients.
This should prevent unneeded DNS name to IP address conversions that SendTo
was doing.
Rev 1.12 7/21/04 3:33:10 PM RLebeau
Updated TIdUDPBase.ReceiveString() to use new BytesToString() parameters
Rev 1.11 09/06/2004 00:29:56 CCostelloe
Kylix 3 patch
Rev 1.10 2004.02.03 4:17:00 PM czhower
For unit name changes.
Rev 1.9 21.1.2004 ã. 12:31:00 DBondzhev
Fix for Indy source. Workaround for dccil bug
now it can be compiled using Compile instead of build
Rev 1.7 10/26/2003 12:30:18 PM BGooijen
DotNet
Rev 1.6 10/24/2003 5:18:36 PM BGooijen
Removed boolean shortcutting from .GetActive
Rev 1.5 10/22/2003 04:40:58 PM JPMugaas
Should compile with some restored functionality. Still not finished.
Rev 1.4 10/19/2003 9:34:30 PM BGooijen
SetSocketOption
Rev 1.3 2003.10.11 9:58:48 PM czhower
Started on some todos
Rev 1.2 2003.10.11 5:52:10 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:08 PM czhower
Stack split for DotNet
Rev 1.0 11/13/2002 09:02:06 AM JPMugaas
}
unit IdUDPBase;
interface
{$I IdCompilerDefines.inc}
//here to flip FPC into Delphi mode
uses
IdComponent,
IdGlobal,
IdException,
IdSocketHandle;
(*$HPPEMIT '#if defined(_VCL_ALIAS_RECORDS)' *)
(*$HPPEMIT '#if !defined(UNICODE)' *)
(*$HPPEMIT '#pragma alias "@Idudpbase@TIdUDPBase@SetPortA$qqrxus"="@Idudpbase@TIdUDPBase@SetPort$qqrxus"' *)
(*$HPPEMIT '#else' *)
(*$HPPEMIT '#pragma alias "@Idudpbase@TIdUDPBase@SetPortW$qqrxus"="@Idudpbase@TIdUDPBase@SetPort$qqrxus"' *)
(*$HPPEMIT '#endif' *)
(*$HPPEMIT '#endif' *)
const
ID_UDP_BUFFERSIZE = 8192;
type
TIdUDPBase = class(TIdComponent)
protected
FBinding: TIdSocketHandle;
FBufferSize: Integer;
FDsgnActive: Boolean;
FHost: String;
FPort: TIdPort;
FReceiveTimeout: Integer;
FReuseSocket: TIdReuseSocket;
FIPVersion: TIdIPVersion;
//
FBroadcastEnabled: Boolean;
procedure BroadcastEnabledChanged; dynamic;
procedure CloseBinding; virtual;
function GetActive: Boolean; virtual;
procedure InitComponent; override;
procedure SetActive(const Value: Boolean);
procedure SetBroadcastEnabled(const AValue: Boolean);
function GetBinding: TIdSocketHandle; virtual; abstract;
procedure Loaded; override;
function GetIPVersion: TIdIPVersion; virtual;
procedure SetIPVersion(const AValue: TIdIPVersion); virtual;
function GetHost : String; virtual;
procedure SetHost(const AValue : String); virtual;
function GetPort : TIdPort; virtual;
procedure SetPort(const AValue : TIdPort); virtual;
property Host: string read GetHost write SetHost;
property Port: TIdPort read GetPort write SetPort;
public
destructor Destroy; override;
//
property Binding: TIdSocketHandle read GetBinding;
procedure Broadcast(const AData: string; const APort: TIdPort; const AIP: String = '';
AByteEncoding: IIdTextEncoding = nil
{$IFDEF STRING_IS_ANSI}; ASrcEncoding: IIdTextEncoding = nil{$ENDIF}
); overload;
procedure Broadcast(const AData: TIdBytes; const APort: TIdPort; const AIP: String = ''); overload;
function ReceiveBuffer(var ABuffer : TIdBytes; var VPeerIP: string; var VPeerPort: TIdPort;
AMSec: Integer = IdTimeoutDefault): integer; overload; virtual;
function ReceiveBuffer(var ABuffer : TIdBytes; var VPeerIP: string; var VPeerPort: TIdPort;
var VIPVersion: TIdIPVersion; const AMSec: Integer = IdTimeoutDefault): integer; overload; virtual;
function ReceiveBuffer(var ABuffer : TIdBytes;
const AMSec: Integer = IdTimeoutDefault): Integer; overload; virtual;
function ReceiveString(const AMSec: Integer = IdTimeoutDefault; AByteEncoding: IIdTextEncoding = nil
{$IFDEF STRING_IS_ANSI}; ADestEncoding: IIdTextEncoding = nil{$ENDIF}
): string; overload;
function ReceiveString(var VPeerIP: string; var VPeerPort: TIdPort;
const AMSec: Integer = IdTimeoutDefault; AByteEncoding: IIdTextEncoding = nil
{$IFDEF STRING_IS_ANSI}; ADestEncoding: IIdTextEncoding = nil{$ENDIF}
): string; overload;
procedure Send(const AHost: string; const APort: TIdPort; const AData: string;
AByteEncoding: IIdTextEncoding = nil
{$IFDEF STRING_IS_ANSI}; ASrcEncoding: IIdTextEncoding = nil{$ENDIF}
);
procedure SendBuffer(const AHost: string; const APort: TIdPort; const AIPVersion: TIdIPVersion; const ABuffer : TIdBytes); overload; virtual;
procedure SendBuffer(const AHost: string; const APort: TIdPort; const ABuffer: TIdBytes); overload; virtual;
//
property ReceiveTimeout: Integer read FReceiveTimeout write FReceiveTimeout default IdTimeoutInfinite;
property ReuseSocket: TIdReuseSocket read FReuseSocket write FReuseSocket default rsOSDependent;
published
property Active: Boolean read GetActive write SetActive Default False;
property BufferSize: Integer read FBufferSize write FBufferSize default ID_UDP_BUFFERSIZE;
property BroadcastEnabled: Boolean read FBroadcastEnabled
write SetBroadcastEnabled default False;
property IPVersion: TIdIPVersion read GetIPVersion write SetIPVersion default ID_DEFAULT_IP_VERSION;
end;
EIdUDPException = Class(EIdException);
EIdUDPReceiveErrorZeroBytes = class(EIdUDPException);
implementation
uses
IdStackConsts, IdStack, SysUtils;
{ TIdUDPBase }
procedure TIdUDPBase.Broadcast(const AData: string; const APort: TIdPort;
const AIP: String = ''; AByteEncoding: IIdTextEncoding = nil
{$IFDEF STRING_IS_ANSI}; ASrcEncoding: IIdTextEncoding = nil{$ENDIF});
begin
Binding.Broadcast(AData, APort, AIP, AByteEncoding{$IFDEF STRING_IS_ANSI}, ASrcEncoding{$ENDIF});
end;
procedure TIdUDPBase.Broadcast(const AData: TIdBytes; const APort: TIdPort;
const AIP: String = '');
begin
Binding.Broadcast(AData, APort, AIP);
end;
procedure TIdUDPBase.BroadcastEnabledChanged;
begin
if Assigned(FBinding) then begin
FBinding.BroadcastEnabled := BroadcastEnabled;
end;
end;
procedure TIdUDPBase.CloseBinding;
begin
FreeAndNil(FBinding);
end;
destructor TIdUDPBase.Destroy;
begin
Active := False;
//double check that binding gets freed.
//sometimes possible that binding is allocated, but active=false
CloseBinding;
inherited Destroy;
end;
function TIdUDPBase.GetActive: Boolean;
begin
Result := FDsgnActive;
if not Result then begin
if Assigned(FBinding) then begin
Result := FBinding.HandleAllocated;
end;
end;
end;
function TIdUDPBase.GetHost: String;
begin
Result := FHost;
end;
function TIdUDPBase.GetIPVersion: TIdIPVersion;
begin
Result := FIPVersion;
end;
function TIdUDPBase.GetPort: TIdPort;
begin
Result := FPort;
end;
procedure TIdUDPBase.InitComponent;
begin
inherited InitComponent;
BufferSize := ID_UDP_BUFFERSIZE;
FReceiveTimeout := IdTimeoutInfinite;
FReuseSocket := rsOSDependent;
FIPVersion := ID_DEFAULT_IP_VERSION;
end;
procedure TIdUDPBase.Loaded;
var
b: Boolean;
begin
inherited Loaded;
b := FDsgnActive;
FDsgnActive := False;
Active := b;
end;
function TIdUDPBase.ReceiveBuffer(var ABuffer : TIdBytes;
const AMSec: Integer = IdTimeoutDefault): Integer;
var
VoidIP: string;
VoidPort: TIdPort;
VoidIPVer: TIdIPVersion;
begin
Result := ReceiveBuffer(ABuffer, VoidIP, VoidPort, VoidIPVer, AMSec);
end;
function TIdUDPBase.ReceiveBuffer(var ABuffer : TIdBytes;
var VPeerIP: string; var VPeerPort: TIdPort;
AMSec: Integer = IdTimeoutDefault): integer;
var
VoidIPVer : TIdIPVersion;
begin
Result := ReceiveBuffer(ABuffer, VPeerIP, VPeerPort, VoidIPVer, AMSec);
// GBSDStack.CheckForSocketError(Result);
end;
function TIdUDPBase.ReceiveBuffer(var ABuffer : TIdBytes;
var VPeerIP: string; var VPeerPort: TIdPort; var VIPVersion: TIdIPVersion;
const AMSec: Integer = IdTimeoutDefault): integer;
var
LMSec : Integer;
begin
if AMSec = IdTimeoutDefault then begin
if ReceiveTimeOut = 0 then begin
LMSec := IdTimeoutInfinite;
end else begin
LMSec := ReceiveTimeOut;
end;
end else begin
LMSec := AMSec;
end;
if not Binding.Readable(LMSec) then begin
Result := 0;
VPeerIP := ''; {Do not Localize}
VPeerPort := 0;
Exit;
end;
Result := Binding.RecvFrom(ABuffer, VPeerIP, VPeerPort, VIPVersion);
end;
function TIdUDPBase.ReceiveString(var VPeerIP: string; var VPeerPort: TIdPort;
const AMSec: Integer = IdTimeoutDefault; AByteEncoding: IIdTextEncoding = nil
{$IFDEF STRING_IS_ANSI}; ADestEncoding: IIdTextEncoding = nil{$ENDIF}
): string;
var
i: Integer;
LBuffer : TIdBytes;
begin
SetLength(LBuffer, BufferSize);
i := ReceiveBuffer(LBuffer, VPeerIP, VPeerPort, AMSec);
Result := BytesToString(LBuffer, 0, i, AByteEncoding{$IFDEF STRING_IS_ANSI}, ADestEncoding{$ENDIF});
end;
function TIdUDPBase.ReceiveString(const AMSec: Integer = IdTimeoutDefault;
AByteEncoding: IIdTextEncoding = nil
{$IFDEF STRING_IS_ANSI}; ADestEncoding: IIdTextEncoding = nil{$ENDIF}): string;
var
VoidIP: string;
VoidPort: TIdPort;
begin
Result := ReceiveString(VoidIP, VoidPort, AMSec, AByteEncoding{$IFDEF STRING_IS_ANSI}, ADestEncoding{$ENDIF});
end;
procedure TIdUDPBase.Send(const AHost: string; const APort: TIdPort; const AData: string;
AByteEncoding: IIdTextEncoding = nil
{$IFDEF STRING_IS_ANSI}; ASrcEncoding: IIdTextEncoding = nil{$ENDIF}
);
begin
SendBuffer(AHost, APort, ToBytes(AData, AByteEncoding{$IFDEF STRING_IS_ANSI}, ASrcEncoding{$ENDIF}));
end;
procedure TIdUDPBase.SendBuffer(const AHost: string; const APort: TIdPort; const ABuffer: TIdBytes);
begin
SendBuffer(AHost, APort, IPVersion, ABuffer);
end;
procedure TIdUDPBase.SendBuffer(const AHost: string; const APort: TIdPort;
const AIPVersion: TIdIPVersion; const ABuffer: TIdBytes);
var
LIP : String;
begin
LIP := GStack.ResolveHost(AHost, AIPVersion);
Binding.SendTo(LIP, APort, ABuffer,AIPVersion);
end;
procedure TIdUDPBase.SetActive(const Value: Boolean);
begin
if Active <> Value then begin
if not (IsDesignTime or IsLoading) then begin
if Value then begin
GetBinding;
end
else begin
CloseBinding;
end;
end
else begin // don't activate at designtime (or during loading of properties) {Do not Localize}
FDsgnActive := Value;
end;
end;
end;
procedure TIdUDPBase.SetBroadcastEnabled(const AValue: Boolean);
begin
if FBroadCastEnabled <> AValue then begin
FBroadcastEnabled := AValue;
if Active then begin
BroadcastEnabledChanged;
end;
end;
end;
procedure TIdUDPBase.SetHost(const AValue: String);
begin
FHost := Avalue;
end;
procedure TIdUDPBase.SetIPVersion(const AValue: TIdIPVersion);
begin
FIPVersion := AValue;
end;
procedure TIdUDPBase.SetPort(const AValue: TIdPort);
begin
FPort := AValue;
end;
end.