IdUDPBase.pas 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. {
  2. $Project$
  3. $Workfile$
  4. $Revision$
  5. $DateUTC$
  6. $Id$
  7. This file is part of the Indy (Internet Direct) project, and is offered
  8. under the dual-licensing agreement described on the Indy website.
  9. (http://www.indyproject.org/)
  10. Copyright:
  11. (c) 1993-2005, Chad Z. Hower and the Indy Pit Crew. All rights reserved.
  12. }
  13. {
  14. $Log$
  15. }
  16. {
  17. Rev 1.15 11/12/2004 11:30:18 AM JPMugaas
  18. Expansions for IPv6.
  19. Rev 1.14 11/11/04 12:05:32 PM RLebeau
  20. Updated ReceiveBuffer() to set AMSec to IdTimeoutInfinite when the
  21. ReceiveTimeout property is 0
  22. Rev 1.13 11/7/2004 11:33:30 PM JPMugaas
  23. Now uses Connect, Disconnect, Send, and Receive similarly to the TCP Clients.
  24. This should prevent unneeded DNS name to IP address conversions that SendTo
  25. was doing.
  26. Rev 1.12 7/21/04 3:33:10 PM RLebeau
  27. Updated TIdUDPBase.ReceiveString() to use new BytesToString() parameters
  28. Rev 1.11 09/06/2004 00:29:56 CCostelloe
  29. Kylix 3 patch
  30. Rev 1.10 2004.02.03 4:17:00 PM czhower
  31. For unit name changes.
  32. Rev 1.9 21.1.2004 ã. 12:31:00 DBondzhev
  33. Fix for Indy source. Workaround for dccil bug
  34. now it can be compiled using Compile instead of build
  35. Rev 1.7 10/26/2003 12:30:18 PM BGooijen
  36. DotNet
  37. Rev 1.6 10/24/2003 5:18:36 PM BGooijen
  38. Removed boolean shortcutting from .GetActive
  39. Rev 1.5 10/22/2003 04:40:58 PM JPMugaas
  40. Should compile with some restored functionality. Still not finished.
  41. Rev 1.4 10/19/2003 9:34:30 PM BGooijen
  42. SetSocketOption
  43. Rev 1.3 2003.10.11 9:58:48 PM czhower
  44. Started on some todos
  45. Rev 1.2 2003.10.11 5:52:10 PM czhower
  46. -VCL fixes for servers
  47. -Chain suport for servers (Super core)
  48. -Scheduler upgrades
  49. -Full yarn support
  50. Rev 1.1 2003.09.30 1:23:08 PM czhower
  51. Stack split for DotNet
  52. Rev 1.0 11/13/2002 09:02:06 AM JPMugaas
  53. }
  54. unit IdUDPBase;
  55. interface
  56. {$I IdCompilerDefines.inc}
  57. //here to flip FPC into Delphi mode
  58. uses
  59. IdComponent,
  60. IdGlobal,
  61. IdException,
  62. IdSocketHandle;
  63. (*$HPPEMIT '#if defined(_VCL_ALIAS_RECORDS)' *)
  64. (*$HPPEMIT '#if !defined(UNICODE)' *)
  65. (*$HPPEMIT '#pragma alias "@Idudpbase@TIdUDPBase@SetPortA$qqrxus"="@Idudpbase@TIdUDPBase@SetPort$qqrxus"' *)
  66. (*$HPPEMIT '#else' *)
  67. (*$HPPEMIT '#pragma alias "@Idudpbase@TIdUDPBase@SetPortW$qqrxus"="@Idudpbase@TIdUDPBase@SetPort$qqrxus"' *)
  68. (*$HPPEMIT '#endif' *)
  69. (*$HPPEMIT '#endif' *)
  70. // TODO: when compiling with bcc64x, use this pragma instead:
  71. // #pragma comment(linker, "/alternatename:<name1>=<name2>")
  72. const
  73. ID_UDP_BUFFERSIZE = 8192;
  74. type
  75. TIdUDPBase = class(TIdComponent)
  76. protected
  77. FBinding: TIdSocketHandle;
  78. FBufferSize: Integer;
  79. FDsgnActive: Boolean;
  80. FHost: String;
  81. FPort: TIdPort;
  82. FReceiveTimeout: Integer;
  83. FReuseSocket: TIdReuseSocket;
  84. FIPVersion: TIdIPVersion;
  85. //
  86. FBroadcastEnabled: Boolean;
  87. procedure BroadcastEnabledChanged; dynamic;
  88. procedure CloseBinding; virtual;
  89. function GetActive: Boolean; virtual;
  90. procedure InitComponent; override;
  91. procedure SetActive(const Value: Boolean);
  92. procedure SetBroadcastEnabled(const AValue: Boolean);
  93. function GetBinding: TIdSocketHandle; virtual; abstract;
  94. procedure Loaded; override;
  95. function GetIPVersion: TIdIPVersion; virtual;
  96. procedure SetIPVersion(const AValue: TIdIPVersion); virtual;
  97. function GetHost : String; virtual;
  98. procedure SetHost(const AValue : String); virtual;
  99. function GetPort : TIdPort; virtual;
  100. procedure SetPort(const AValue : TIdPort); virtual;
  101. property Host: string read GetHost write SetHost;
  102. property Port: TIdPort read GetPort write SetPort;
  103. public
  104. destructor Destroy; override;
  105. //
  106. property Binding: TIdSocketHandle read GetBinding;
  107. procedure Broadcast(const AData: string; const APort: TIdPort; const AIP: String = '';
  108. AByteEncoding: IIdTextEncoding = nil
  109. {$IFDEF STRING_IS_ANSI}; ASrcEncoding: IIdTextEncoding = nil{$ENDIF}
  110. ); overload;
  111. procedure Broadcast(const AData: TIdBytes; const APort: TIdPort; const AIP: String = ''); overload;
  112. function ReceiveBuffer(var ABuffer : TIdBytes; var VPeerIP: string; var VPeerPort: TIdPort;
  113. AMSec: Integer = IdTimeoutDefault): integer; overload; virtual;
  114. function ReceiveBuffer(var ABuffer : TIdBytes; var VPeerIP: string; var VPeerPort: TIdPort;
  115. var VIPVersion: TIdIPVersion; const AMSec: Integer = IdTimeoutDefault): integer; overload; virtual;
  116. function ReceiveBuffer(var ABuffer : TIdBytes;
  117. const AMSec: Integer = IdTimeoutDefault): Integer; overload; virtual;
  118. function ReceiveString(const AMSec: Integer = IdTimeoutDefault; AByteEncoding: IIdTextEncoding = nil
  119. {$IFDEF STRING_IS_ANSI}; ADestEncoding: IIdTextEncoding = nil{$ENDIF}
  120. ): string; overload;
  121. function ReceiveString(var VPeerIP: string; var VPeerPort: TIdPort;
  122. const AMSec: Integer = IdTimeoutDefault; AByteEncoding: IIdTextEncoding = nil
  123. {$IFDEF STRING_IS_ANSI}; ADestEncoding: IIdTextEncoding = nil{$ENDIF}
  124. ): string; overload;
  125. procedure Send(const AHost: string; const APort: TIdPort; const AData: string;
  126. AByteEncoding: IIdTextEncoding = nil
  127. {$IFDEF STRING_IS_ANSI}; ASrcEncoding: IIdTextEncoding = nil{$ENDIF}
  128. );
  129. procedure SendBuffer(const AHost: string; const APort: TIdPort; const AIPVersion: TIdIPVersion; const ABuffer : TIdBytes); overload; virtual;
  130. procedure SendBuffer(const AHost: string; const APort: TIdPort; const ABuffer: TIdBytes); overload; virtual;
  131. //
  132. property ReceiveTimeout: Integer read FReceiveTimeout write FReceiveTimeout default IdTimeoutInfinite;
  133. property ReuseSocket: TIdReuseSocket read FReuseSocket write FReuseSocket default rsOSDependent;
  134. published
  135. property Active: Boolean read GetActive write SetActive Default False;
  136. property BufferSize: Integer read FBufferSize write FBufferSize default ID_UDP_BUFFERSIZE;
  137. property BroadcastEnabled: Boolean read FBroadcastEnabled
  138. write SetBroadcastEnabled default False;
  139. property IPVersion: TIdIPVersion read GetIPVersion write SetIPVersion default ID_DEFAULT_IP_VERSION;
  140. end;
  141. EIdUDPException = Class(EIdException);
  142. EIdUDPReceiveErrorZeroBytes = class(EIdUDPException);
  143. implementation
  144. uses
  145. IdStackConsts, IdStack, SysUtils;
  146. { TIdUDPBase }
  147. procedure TIdUDPBase.Broadcast(const AData: string; const APort: TIdPort;
  148. const AIP: String = ''; AByteEncoding: IIdTextEncoding = nil
  149. {$IFDEF STRING_IS_ANSI}; ASrcEncoding: IIdTextEncoding = nil{$ENDIF});
  150. begin
  151. Binding.Broadcast(AData, APort, AIP, AByteEncoding{$IFDEF STRING_IS_ANSI}, ASrcEncoding{$ENDIF});
  152. end;
  153. procedure TIdUDPBase.Broadcast(const AData: TIdBytes; const APort: TIdPort;
  154. const AIP: String = '');
  155. begin
  156. Binding.Broadcast(AData, APort, AIP);
  157. end;
  158. procedure TIdUDPBase.BroadcastEnabledChanged;
  159. begin
  160. if Assigned(FBinding) then begin
  161. FBinding.BroadcastEnabled := BroadcastEnabled;
  162. end;
  163. end;
  164. procedure TIdUDPBase.CloseBinding;
  165. begin
  166. FreeAndNil(FBinding);
  167. end;
  168. destructor TIdUDPBase.Destroy;
  169. begin
  170. Active := False;
  171. //double check that binding gets freed.
  172. //sometimes possible that binding is allocated, but active=false
  173. CloseBinding;
  174. inherited Destroy;
  175. end;
  176. function TIdUDPBase.GetActive: Boolean;
  177. begin
  178. if IsDesignTime then begin
  179. Result := FDsgnActive;
  180. end else begin
  181. Result := Assigned(FBinding);
  182. if Result then begin
  183. Result := FBinding.HandleAllocated;
  184. end;
  185. end;
  186. end;
  187. function TIdUDPBase.GetHost: String;
  188. begin
  189. Result := FHost;
  190. end;
  191. function TIdUDPBase.GetIPVersion: TIdIPVersion;
  192. begin
  193. Result := FIPVersion;
  194. end;
  195. function TIdUDPBase.GetPort: TIdPort;
  196. begin
  197. Result := FPort;
  198. end;
  199. procedure TIdUDPBase.InitComponent;
  200. begin
  201. inherited InitComponent;
  202. BufferSize := ID_UDP_BUFFERSIZE;
  203. FReceiveTimeout := IdTimeoutInfinite;
  204. FReuseSocket := rsOSDependent;
  205. FIPVersion := ID_DEFAULT_IP_VERSION;
  206. end;
  207. procedure TIdUDPBase.Loaded;
  208. var
  209. b: Boolean;
  210. begin
  211. inherited Loaded;
  212. b := FDsgnActive;
  213. FDsgnActive := False;
  214. Active := b;
  215. end;
  216. function TIdUDPBase.ReceiveBuffer(var ABuffer : TIdBytes;
  217. const AMSec: Integer = IdTimeoutDefault): Integer;
  218. var
  219. VoidIP: string;
  220. VoidPort: TIdPort;
  221. VoidIPVer: TIdIPVersion;
  222. begin
  223. Result := ReceiveBuffer(ABuffer, VoidIP, VoidPort, VoidIPVer, AMSec);
  224. end;
  225. function TIdUDPBase.ReceiveBuffer(var ABuffer : TIdBytes;
  226. var VPeerIP: string; var VPeerPort: TIdPort;
  227. AMSec: Integer = IdTimeoutDefault): integer;
  228. var
  229. VoidIPVer : TIdIPVersion;
  230. begin
  231. Result := ReceiveBuffer(ABuffer, VPeerIP, VPeerPort, VoidIPVer, AMSec);
  232. // GBSDStack.CheckForSocketError(Result);
  233. end;
  234. function TIdUDPBase.ReceiveBuffer(var ABuffer : TIdBytes;
  235. var VPeerIP: string; var VPeerPort: TIdPort; var VIPVersion: TIdIPVersion;
  236. const AMSec: Integer = IdTimeoutDefault): integer;
  237. var
  238. LMSec : Integer;
  239. begin
  240. if AMSec = IdTimeoutDefault then begin
  241. if ReceiveTimeOut = 0 then begin
  242. LMSec := IdTimeoutInfinite;
  243. end else begin
  244. LMSec := ReceiveTimeOut;
  245. end;
  246. end else begin
  247. LMSec := AMSec;
  248. end;
  249. if not Binding.Readable(LMSec) then begin
  250. Result := 0;
  251. VPeerIP := ''; {Do not Localize}
  252. VPeerPort := 0;
  253. Exit;
  254. end;
  255. Result := Binding.RecvFrom(ABuffer, VPeerIP, VPeerPort, VIPVersion);
  256. end;
  257. function TIdUDPBase.ReceiveString(var VPeerIP: string; var VPeerPort: TIdPort;
  258. const AMSec: Integer = IdTimeoutDefault; AByteEncoding: IIdTextEncoding = nil
  259. {$IFDEF STRING_IS_ANSI}; ADestEncoding: IIdTextEncoding = nil{$ENDIF}
  260. ): string;
  261. var
  262. i: Integer;
  263. LBuffer : TIdBytes;
  264. begin
  265. SetLength(LBuffer, BufferSize);
  266. i := ReceiveBuffer(LBuffer, VPeerIP, VPeerPort, AMSec);
  267. Result := BytesToString(LBuffer, 0, i, AByteEncoding{$IFDEF STRING_IS_ANSI}, ADestEncoding{$ENDIF});
  268. end;
  269. function TIdUDPBase.ReceiveString(const AMSec: Integer = IdTimeoutDefault;
  270. AByteEncoding: IIdTextEncoding = nil
  271. {$IFDEF STRING_IS_ANSI}; ADestEncoding: IIdTextEncoding = nil{$ENDIF}): string;
  272. var
  273. VoidIP: string;
  274. VoidPort: TIdPort;
  275. begin
  276. Result := ReceiveString(VoidIP, VoidPort, AMSec, AByteEncoding{$IFDEF STRING_IS_ANSI}, ADestEncoding{$ENDIF});
  277. end;
  278. procedure TIdUDPBase.Send(const AHost: string; const APort: TIdPort; const AData: string;
  279. AByteEncoding: IIdTextEncoding = nil
  280. {$IFDEF STRING_IS_ANSI}; ASrcEncoding: IIdTextEncoding = nil{$ENDIF}
  281. );
  282. begin
  283. SendBuffer(AHost, APort, ToBytes(AData, AByteEncoding{$IFDEF STRING_IS_ANSI}, ASrcEncoding{$ENDIF}));
  284. end;
  285. procedure TIdUDPBase.SendBuffer(const AHost: string; const APort: TIdPort; const ABuffer: TIdBytes);
  286. begin
  287. SendBuffer(AHost, APort, IPVersion, ABuffer);
  288. end;
  289. procedure TIdUDPBase.SendBuffer(const AHost: string; const APort: TIdPort;
  290. const AIPVersion: TIdIPVersion; const ABuffer: TIdBytes);
  291. var
  292. LIP : String;
  293. begin
  294. //TODO: fire OnStatus(hsResolving) event if AHost is not an IP address...
  295. {
  296. if AIPVersion = Id_IPv4 then
  297. begin
  298. if not GStack.IsIP(AHost) then begin
  299. if Assigned(OnStatus) then begin
  300. DoStatus(hsResolving, [AHost]);
  301. end;
  302. LIP := GStack.ResolveHost(AHost, AIPVersion);
  303. end else begin
  304. LIP := AHost;
  305. end;
  306. end
  307. else
  308. begin //IPv6
  309. LIP := MakeCanonicalIPv6Address(AHost);
  310. if LIP = '' then begin //if MakeCanonicalIPv6Address failed, we have a hostname
  311. if Assigned(OnStatus) then begin
  312. DoStatus(hsResolving, [AHost]);
  313. end;
  314. LIP := GStack.ResolveHost(AHost, AIPVersion);
  315. end else begin
  316. LIP := AHost;
  317. end;
  318. end;
  319. }
  320. LIP := GStack.ResolveHost(AHost, AIPVersion);
  321. Binding.SendTo(LIP, APort, ABuffer, AIPVersion);
  322. end;
  323. procedure TIdUDPBase.SetActive(const Value: Boolean);
  324. begin
  325. if IsDesignTime or IsLoading then begin
  326. // don't activate at designtime (or during loading of properties) {Do not Localize}
  327. FDsgnActive := Value;
  328. end
  329. else if Active <> Value then begin
  330. if Value then begin
  331. GetBinding;
  332. end else begin
  333. CloseBinding;
  334. end;
  335. end;
  336. end;
  337. procedure TIdUDPBase.SetBroadcastEnabled(const AValue: Boolean);
  338. begin
  339. if FBroadCastEnabled <> AValue then begin
  340. FBroadcastEnabled := AValue;
  341. if Active then begin
  342. BroadcastEnabledChanged;
  343. end;
  344. end;
  345. end;
  346. procedure TIdUDPBase.SetHost(const AValue: String);
  347. begin
  348. FHost := Avalue;
  349. end;
  350. procedure TIdUDPBase.SetIPVersion(const AValue: TIdIPVersion);
  351. begin
  352. FIPVersion := AValue;
  353. end;
  354. procedure TIdUDPBase.SetPort(const AValue: TIdPort);
  355. begin
  356. FPort := AValue;
  357. end;
  358. end.