How i can limit the connections per ip? i've tried this code how to block unknown clients in indy (Delphi) but if my server is flooded i can't connect. the code from Remy just prevent CPU to use 100% and use more ram. but the connection from flood still alive on tcpserver and i can't connect to server. so my question is, how i can limit the connection before onconnect, something on accept using tcpserver? maybe hook accept function and try limit the connection ?
How i can limit the connections per ip?
You already know the answer to that, as that is exactly what the other code is doing.
if my server is flooded i can't connect.
The purpose of the other code is simply to limit a client IP address to a max of 10 simultaneous connections, not to prevent flooding or lower CPU/RAM usage. You can't stop unwanted clients from connecting to your server, unless you deactivate the server, or set its MaxConnections property. Outside of that, about all you can do is disconnect unwanted clients as soon as possible, which you can do in the server's OnConnect event. But if you are getting flooded, that is going to take time to process, especially if you are continuously locking and unlocking the server's Contexts list, which will end up serializing the server's internal threading.
Flood management really needs to be handled by a firewall or router/load balancer, not in the server app itself. If this is not acceptable to you, then at least on Windows only, an option might be to write a custom TIdServerIOHandlerStack-derived component that overrides the virtual Accept() method to call WinSock's WSAAccept() function, which offers a callback you can use to reject connections before they leave the accept queue, and thus they will not be seen by TIdTCPServer. For example:
type
TMyServerIOHandler = class(TIdServerIOHandlerStack)
public
function Accept(ASocket: TIdSocketHandle; AListenerThread: TIdThread; AYarn: TIdYarn): TIdIOHandler; override;
end;
function MyConditionFunc(lpCallerId, lpCallerData: LPWSABUF; lpSQOS, lpGQOS: LPQOS; lpCalleeId, lpCalleeData: LPWSABUF; g: PGROUP dwCallbackData: DWORD_PTR): Integer; stdcall;
begin
if (the address stored in lpCallerId is blocked) then
Result := CF_REJECT
else
Result := CF_ACCEPT;
end;
type
TIdSocketHandleAccess = class(TIdSocketHandle)
end;
function TMyServerIOHandler.Accept(ASocket: TIdSocketHandle; AListenerThread: TIdThread; AYarn: TIdYarn): TIdIOHandler;
var
LIOHandler: TIdIOHandlerSocket;
LBinding: TIdSocketHandle;
LAcceptedSocket: TIdStackSocketHandle;
begin
Result := nil;
LIOHandler := TIdIOHandlerStack.Create(nil);
try
LIOHandler.Open;
while not AListenerThread.Stopped do
begin
if ASocket.Select(250) then
begin
LBinding := LIOHandler.Binding;
LBinding.Reset;
LAcceptedSocket := WSAAccept(ASocket.Handle, nil, nil, @MyConditionFunc, 0);
if LAcceptedSocket <> Id_INVALID_SOCKET then
begin
TIdSocketHandleAccess(LBinding).SetHandle(LAcceptedSocket);
LBinding.UpdateBindingLocal;
LBinding.UpdateBindingPeer;
LIOHandler.AfterAccept;
Result := LIOHandler;
LIOHandler := nil;
Break;
end;
end;
end;
finally
FreeAndNil(LIOHandler);
end;
end;
Then you can assign an instance of TMyServerIOHandler to the TIdTCPServer.IOHandler property before activating the server.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With