2
0

IdUDPServer.pas 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. { $HDR$}
  2. {**********************************************************************}
  3. { Unit archived using Team Coherence }
  4. { Team Coherence is Copyright 2002 by Quality Software Components }
  5. { }
  6. { For further information / comments, visit our WEB site at }
  7. { http://www.TeamCoherence.com }
  8. {**********************************************************************}
  9. {}
  10. { $Log: 10411: IdUDPServer.pas
  11. {
  12. { Rev 1.0 2002.11.12 10:59:10 PM czhower
  13. }
  14. unit IdUDPServer;
  15. interface
  16. uses
  17. Classes,
  18. IdComponent, IdException, IdGlobal, IdSocketHandle, IdStackConsts, IdThread, IdUDPBase;
  19. type
  20. TUDPReadEvent = procedure(Sender: TObject; AData: TStream; ABinding: TIdSocketHandle) of object;
  21. TIdUDPServer = class;
  22. TIdUDPListenerThread = class(TIdThread)
  23. protected
  24. IncomingData: TIdSocketHandle;
  25. FAcceptWait: integer;
  26. FBuffer: TMemoryStream;
  27. FBufferSize: integer;
  28. public
  29. FServer: TIdUDPServer;
  30. //
  31. constructor Create(const ABufferSize: integer; Owner: TIdUDPServer); reintroduce;
  32. destructor Destroy; override;
  33. procedure Run; override;
  34. procedure UDPRead;
  35. //
  36. property AcceptWait: integer read FAcceptWait write FAcceptWait;
  37. published
  38. end;
  39. TIdUDPServer = class(TIdUDPBase)
  40. protected
  41. FBindings: TIdSocketHandles;
  42. FCurrentBinding: TIdSocketHandle;
  43. FListenerThread: TIdUDPListenerThread;
  44. FOnUDPRead: TUDPReadEvent;
  45. FThreadedEvent: boolean;
  46. //
  47. function GetDefaultPort: integer;
  48. procedure SetBindings(const Value: TIdSocketHandles);
  49. procedure SetDefaultPort(const AValue: integer);
  50. procedure PacketReceived(AData: TStream; ABinding: TIdSocketHandle);
  51. procedure DoUDPRead(AData: TStream; ABinding: TIdSocketHandle); virtual;
  52. function GetBinding: TIdSocketHandle; override;
  53. procedure CloseBinding; override;
  54. procedure BroadcastEnabledChanged; override;
  55. function GetActive: Boolean; override;
  56. public
  57. constructor Create(axOwner: TComponent); override;
  58. destructor Destroy; override;
  59. //
  60. published
  61. property Bindings: TIdSocketHandles read FBindings write SetBindings;
  62. property DefaultPort: integer read GetDefaultPort write SetDefaultPort;
  63. property OnUDPRead: TUDPReadEvent read FOnUDPRead write FOnUDPRead;
  64. property ThreadedEvent: boolean read FThreadedEvent write FThreadedEvent default False;
  65. end;
  66. EIdUDPServerException = class(EIdUDPException);
  67. implementation
  68. uses
  69. IdResourceStrings, IdStack,
  70. SysUtils;
  71. { TIdUDPServer }
  72. procedure TIdUDPServer.BroadcastEnabledChanged;
  73. var
  74. i: integer;
  75. begin
  76. if Assigned(FCurrentBinding) then begin
  77. for i := 0 to Bindings.Count - 1 do begin
  78. SetBroadcastFlag(BroadcastEnabled, Bindings[i]);
  79. end;
  80. end;
  81. end;
  82. procedure TIdUDPServer.CloseBinding;
  83. var
  84. i: integer;
  85. begin
  86. if Assigned(FCurrentBinding) then begin
  87. // Necessary here - cancels the recvfrom in the listener thread
  88. FListenerThread.Stop;
  89. for i := 0 to Bindings.Count - 1 do begin
  90. Bindings[i].CloseSocket;
  91. end;
  92. FListenerThread.WaitFor;
  93. FreeAndNil(FListenerThread);
  94. FCurrentBinding := nil;
  95. end;
  96. end;
  97. constructor TIdUDPServer.Create(axOwner: TComponent);
  98. begin
  99. inherited;
  100. FBindings := TIdSocketHandles.Create(Self);
  101. end;
  102. destructor TIdUDPServer.Destroy;
  103. begin
  104. Active := False;
  105. FreeAndNil(FBindings);
  106. inherited;
  107. end;
  108. procedure TIdUDPServer.DoUDPRead(AData: TStream; ABinding: TIdSocketHandle);
  109. begin
  110. if assigned(OnUDPRead) then begin
  111. OnUDPRead(Self, AData, ABinding);
  112. end;
  113. end;
  114. function TIdUDPServer.GetActive: Boolean;
  115. begin
  116. // inherited GetActive keeps track of design-time Active property
  117. Result := inherited GetActive or
  118. (Assigned(FCurrentBinding) and FCurrentBinding.HandleAllocated);
  119. end;
  120. function TIdUDPServer.GetBinding: TIdSocketHandle;
  121. var
  122. i: integer;
  123. begin
  124. if not Assigned(FCurrentBinding) then
  125. begin
  126. if Bindings.Count < 1 then begin
  127. Bindings.Add;
  128. end;
  129. for i := 0 to Bindings.Count - 1 do begin
  130. Bindings[i].AllocateSocket(Id_SOCK_DGRAM);
  131. Bindings[i].Bind;
  132. end;
  133. FCurrentBinding := Bindings[0];
  134. FListenerThread := TIdUDPListenerThread.Create(BufferSize, Self);
  135. FListenerThread.Start;
  136. BroadcastEnabledChanged;
  137. end;
  138. Result := FCurrentBinding;
  139. end;
  140. function TIdUDPServer.GetDefaultPort: integer;
  141. begin
  142. result := FBindings.DefaultPort;
  143. end;
  144. procedure TIdUDPServer.PacketReceived(AData: TStream;
  145. ABinding: TIdSocketHandle);
  146. begin
  147. FCurrentBinding := ABinding;
  148. DoUDPRead(AData, ABinding);
  149. end;
  150. procedure TIdUDPServer.SetBindings(const Value: TIdSocketHandles);
  151. begin
  152. FBindings.Assign(Value);
  153. end;
  154. procedure TIdUDPServer.SetDefaultPort(const AValue: integer);
  155. begin
  156. FBindings.DefaultPort := AValue;
  157. end;
  158. { TIdUDPListenerThread }
  159. // TODO: get rid of buffersize arg... there's no reason why this thread can't simply check its owner's buffersize property {Do not Localize}
  160. constructor TIdUDPListenerThread.Create(const ABufferSize: integer; Owner: TIdUDPServer);
  161. begin
  162. inherited Create(True);
  163. FAcceptWait := 1000;
  164. FBuffer := TMemoryStream.Create;
  165. FBufferSize := ABufferSize;
  166. FServer := Owner;
  167. end;
  168. destructor TIdUDPListenerThread.Destroy;
  169. begin
  170. FBuffer.Free;
  171. inherited;
  172. end;
  173. procedure TIdUDPListenerThread.Run;
  174. var
  175. PeerIP: string;
  176. i, PeerPort, ByteCount: Integer;
  177. FReadList: TList;
  178. begin
  179. // fill list of socket handles
  180. FReadList := TList.Create;
  181. try
  182. FReadList.Capacity := FServer.Bindings.Count;
  183. for i := 0 to FServer.Bindings.Count - 1 do begin
  184. FReadList.Add(Pointer(FServer.Bindings[i].Handle));
  185. end;
  186. GStack.WSSelect(FReadList, nil, nil, AcceptWait);
  187. for i := 0 to FReadList.Count - 1 do try
  188. // Doublecheck to see if we've been stopped {Do not Localize}
  189. // Depending on timing - may not reach here if it is in ancestor run when thread is stopped
  190. if not Stopped then begin
  191. IncomingData := FServer.Bindings.BindingByHandle(TIdStackSocketHandle(FReadList[i]));
  192. FBuffer.SetSize(FBufferSize);
  193. ByteCount := GStack.WSRecvFrom(IncomingData.Handle, FBuffer.Memory^, FBufferSize,
  194. 0, PeerIP, PeerPort);
  195. GStack.CheckForSocketError(ByteCount);
  196. FBuffer.SetSize(ByteCount);
  197. //Some streams alter their position on SetSize
  198. FBuffer.Position := 0;
  199. IncomingData.SetPeer(PeerIP, PeerPort);
  200. if FServer.ThreadedEvent then begin
  201. UDPRead;
  202. end else begin
  203. Synchronize(UDPRead);
  204. end;
  205. end;
  206. except // exceptions should be ignored so that other clients can be served in case of a DOS attack
  207. end;
  208. finally
  209. FReadList.Free;
  210. end;
  211. end;
  212. procedure TIdUDPListenerThread.UDPRead;
  213. begin
  214. FServer.PacketReceived(FBuffer, IncomingData);
  215. end;
  216. end.