386 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
			
		
		
	
	
			386 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
| {
 | |
|   $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.
 |