FearDC 1 Posted January 28, 2024 I need to perform simple TCP socket peek during Indy server event. To do this I use recv(), but it stays blocking forever if I don't receive required data, not allowing any further server <> client communication. procedure OnServerBeforeConnect(AContext: TIdContext); var mPeek: Array [0..1] of AnsiChar; mTime, mRes: Integer; begin { // returns error -1 mTime := 5; mRes := SetSockOpt(AContext.Binding.Handle, SOL_SOCKET, SO_RCVTIMEO, mTime, SizeOf(mTime)); } { // nothing happens AContext.Binding.SetSockOpt(Id_SOL_SOCKET, Id_SO_RCVTIMEO, 5); } // hangs forever if (Recv(AContext.Binding.Handle, mPeek, 2, MSG_PEEK) = 2) and (mPeek[0] = #22) and (mPeek[1] = #03) then TIdSSLIOHandlerSocketOpenSSL(AContext.Connection.IOHandler).PassThrough := False; end; On Windows this works just fine, setting SO_RCVTIMEO helps to exit recv() even if needed data is not received. Please help. Regards. Share this post Link to post
Virgo 18 Posted January 29, 2024 What SetSockOpt are you using? In Linux SO_RCVTIMEO parameter is supposed to be a pointer to timeval record. Not Int. Share this post Link to post
FearDC 1 Posted January 29, 2024 SetSockOpt from Posix.SysSocket/SysSocketAPI.inc The second one is Indys built-in. I know that Posix wants a time struct, but how to do that in Delphi? Regards. Share this post Link to post
Virgo 18 Posted January 29, 2024 Unfortunately I do not have Delphi version new enough. But maybe there is an overloaded version, that allows required parameters? Indy own TIdSocketHandle.SetScokOpot also has AOptVal:Integer... But GStack.SetSocketOption seems to have required version. Share this post Link to post
FearDC 1 Posted January 29, 2024 (edited) Finally got it working. type TTimeVal = record tv_sec, tv_usec: LongInt; end; var mTime: TTimeVal; mRes: Integer; begin mTime.tv_sec := 5; mTime.tv_usec := 0; // returns 0 - no error mRes := Posix.SysSocket.SetSockOpt(AContext.Binding.Handle, SOL_SOCKET, SO_RCVTIMEO, &mTime, SizeOf(TTimeVal)); Thank you for hints @Virgo. Edited January 29, 2024 by FearDC Share this post Link to post
Remy Lebeau 1472 Posted January 29, 2024 (edited) 2 hours ago, FearDC said: var mTime: TTimeVal; mRes: Integer; begin mTime.tv_sec := 5; mTime.tv_usec := 0; // returns 0 - no error mRes := Posix.SysSocket.SetSockOpt(AContext.Binding.Handle, SOL_SOCKET, SO_RCVTIMEO, &mTime, SizeOf(TTimeVal)); Indy's TIdSocketHandle class does not have a SetSockOpt() overload for non-integer inputs, but its TIdStackBSDBase class does (for BSD-based socket stacks, like Linux and Windows): uses ..., IdStackBSDBase; GBSDStack.SetSocketOption(AContext.Binding.Handle, Id_SOL_SOCKET, Id_SO_RCVTIMEO, mTime, SizeOf(TTimeVal)); I probably need to update Indy to expose this overload in TIdSocketHandle and TIdStack for easier use. Edited January 29, 2024 by Remy Lebeau Share this post Link to post
FearDC 1 Posted January 30, 2024 Oh, cool. Does IdStackBSDBase have recv() too? Share this post Link to post
Remy Lebeau 1472 Posted January 30, 2024 (edited) 9 hours ago, FearDC said: Oh, cool. Does IdStackBSDBase have recv() too? It has the public Receive() method inherited from TIdStack, but that takes only a socket handle and a TIdBytes as parameters. I assume you want access to the flags parameter of recv()? For that, you can use the protected TIdStackBSDBase.WSRecv() method. type TIdStackBSDBaseAccess = class(TIdStackBSDBase) end; TIdStackBSDBaseAccess(GBSDStack).WSRecv(AContext.Binding.Handle, buffer, length, MSG_PEEK); Edited January 30, 2024 by Remy Lebeau Share this post Link to post