unit UDPPort;

interface

uses
  Windows, Messages, SysUtils, Classes,
  IdBaseComponent, IdAntiFreezeBase, IdAntiFreeze,
  idSocketHandle, IdComponent, IdUDPBase, IdUDPClient, IdUDPServer, IdStack;

type
  TOnDataReceived = procedure(Sender: TObject; const AData: string) of object;

  TUDPPort = class(TComponent)
  private
    { Private declarations }
    FUDPClient: TIdUDPClient;
    FUDPServer: TIdUDPServer;
    FAntiFreeze: TIdAntiFreeze;
    FOnDataReceived: TOnDataReceived;
    FCurIP: string;
    FCurPort: integer;

    function GetLocalPort: integer;
    function GetRemotePort: integer;
    function GetRemoteHost: string;
    function GetActive: boolean;
    procedure SetLocalPort(APort: integer);
    procedure SetRemotePort(APort: integer);
    procedure SetRemoteHost(AHost: string);
    procedure SetActive(OnOff: boolean);

    procedure UDPRead(Sender: TObject; AData: TStream; ABinding: TIdSocketHandle);
    function GetTitle: string;
    function GetLocalHost: string;
  protected
    { Protected declarations }
  public
    { Public declarations }
    constructor Create(AOwner: TComponent); override;
    procedure Send(const AData: string);
    property CurPort: integer read FCurPort;
    property CurIP: string read FCurIP;
    property Title: string read GetTitle;
  published
    { Published declarations }
    property LocalHost: string read GetLocalHost;
    property LocalPort: integer read GetLocalPort write SetLocalPort;
    property RemotePort: integer read GetRemotePort write SetRemotePort;
    property RemoteHost: string read GetRemoteHost write SetRemoteHost;
    property Active: boolean read GetActive write SetActive;
    property OnDataReceived: TOnDataReceived read FOnDataReceived write FOnDataReceived;
  end;

procedure Register;

implementation

{TUDPPort.}
constructor TUDPPort.Create(AOwner: TComponent);
begin
  inherited;
  FAntiFreeze := TIdAntiFreeze.Create(Self);
  with FAntiFreeze do begin
    ApplicationHasPriority := true;
    //IdleTimeout := 250;
    OnlyWhenIdle := false;
  end;
  FUDPClient := TIdUDPClient.Create(Self);
  with FUDPClient do begin
    BroadcastEnabled := true;
    BufferSize := 8192;
    //ReceiveTimeout := 1000;
  end;

  FUDPServer:= TIdUDPServer.Create(Self);
  with FUDPServer do begin
    BroadcastEnabled := true;
    BufferSize := 8192;
    OnUDPRead := UDPRead;//tidudpserver
  end;
end;

procedure TUDPPort.Send(const AData: string);
begin
  FUDPClient.Send(AData);
end;

function TUDPPort.GetLocalPort: integer;
begin
  Result := FUDPServer.DefaultPort; //tidudpserver
end;

procedure TUDPPort.SetLocalPort(APort: integer);
var a: boolean;
begin
  if FUDPServer.DefaultPort <> APort then begin
    a := FUDPServer.Active;
    FUDPServer.Active := false;
    FUDPServer.Bindings.Clear;
    FUDPServer.DefaultPort := APort;
    FUDPServer.Active := a;
  end;
end;

function TUDPPort.GetRemotePort: integer;
begin
  Result := FUDPClient.Port; //tidudpclient
end;

procedure TUDPPort.SetRemotePort(APort: integer);
begin
  FUDPClient.Port := APort;
end;

function TUDPPort.GetRemoteHost: string;
begin
  Result := FUDPClient.Host;
end;

procedure TUDPPort.SetRemoteHost(AHost: string);
begin
  FUDPClient.Host := AHost;
end;

function TUDPPort.GetActive: boolean;
begin
  Result := FUDPServer.Active;
end;

procedure TUDPPort.SetActive(OnOff: boolean);
begin
  FUDPServer.Active := OnOff;//tidudpserver
end;

procedure TUDPPort.UDPRead(Sender: TObject; AData: TStream; ABinding: TIdSocketHandle);
var
  DataStringStream: TStringStream;
//  s: String;
begin
  DataStringStream := TStringStream.Create('');
  try
    DataStringStream.CopyFrom(AData, AData.Size);
    FCurIP := ABinding.PeerIP;
    FCurPort := ABinding.PeerPort;
    if Assigned(FOnDataReceived) then
      FOnDataReceived(Self, DataStringStream.DataString);
    //Log(DataStringStream.DataString, ABinding.PeerIP, IntToStr(ABinding.PeerPort));

    //UDPMemo.Lines.Add('Received "' + DataStringStream.DataString + '" from ' + ABinding.PeerIP + ' on port ' + IntToStr(ABinding.PeerPort));

    //s := 'Replied from ' + UDPServer.LocalName + ' to "' + DataStringStream.DataString + '"';
    //ABinding.SendTo(ABinding.PeerIP, ABinding.PeerPort, s[1], Length(s));

    //s := UDPServer.LocalName + ' OK';
    //ABinding.SendTo(ABinding.PeerIP, ABinding.PeerPort, s[1], length(s));
  finally
    DataStringStream.Free;
  end;
end;

function TUDPPort.GetLocalHost: string;
begin
  Result := GStack.LocalAddress;
end;

function TUDPPort.GetTitle: string;
begin
  Result :=
    'udp://' + LocalHost  + ':' + IntToStr(LocalPort) + '  -> ' +
    RemoteHost + ':' + IntToStr(RemotePort);
end;
{/TUDPPort.}

procedure Register;
begin
  RegisterComponents('NonVis', [TUDPPort]);
end;

end.
