FearDC 1 Posted January 28 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 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 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 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 (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 by FearDC Share this post Link to post
Remy Lebeau 1421 Posted January 29 (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 by Remy Lebeau Share this post Link to post
FearDC 1 Posted January 30 Oh, cool. Does IdStackBSDBase have recv() too? Share this post Link to post
Remy Lebeau 1421 Posted January 30 (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 by Remy Lebeau Share this post Link to post