Re: [fpc-pascal] fpselect does not work on linux
Am Samstag, 9. Mai 2009 20:25 schrieb dmitry boyarintsev: How can I find out if a socket connection in a nonblocking mode is established? according to the man page, you're doing correct path: http://linux.die.net/man/2/connect i did use non-blocking connection for both Linux and OSX, and it did work as described: by selecting sockets for writting. Thought i used infinite wait time. Anyway, could you provide more code, on how do you actually establish a server address (sockaddr structure). I remeber there were some differences in Windows sockaddr structure and Linux sockaddr structure (IIRC, IP byte order is messed-up). With nonblocking sockets it works. Also it works with linux if I call connect again and again (nonblocking) until the result from connect says ok, connected. But I don't know exactly if there is more traffic on the network or internet lines when calling connect often. Windows may produces traffic every time by calling connect I think. But I am not sure. This was the reason why I tried with select to find out if a connection is ok. I tested with longer timeouts, but for me there is the same behaviour. Another way to find out can be to program select in c, put it in a library and then call it from fpc. regards, Rainer var c_connected : boolean; c_socket : integer; inetaddr_client_remote : tsockaddr; implementation const port_program = 12021; procedure memclr( p : pointer ; len : longint ); var x : longint; begin for x := 1 to len do begin byte( p^ ) := 0; inc( p ); end; end; procedure setsockaddr( var sa : tsockaddr ; adr : string ; port : longint ); begin memclr( @sa , sizeof( sa ) ); sa.sin_family := AF_INET; sa.sin_addr := strtonetaddr( adr ); sa.sin_port := htons( port ); end; function my_connect( s : integer ; var ina : tsockaddr ) : boolean; var c : longint; begin c := fpconnect( s , @ina , sizeof( ina ) ); {$ifdef windows} if c = SOCKET_ERROR then begin if wsagetlasterror = WSAEISCONN then c := 0; // ! end; {$endif} result := ( c = 0 ); end; procedure setnonblockingsocket( s : integer ); var nb : dword; n : integer; arg : longint; begin // nonblocking {$ifdef linux} arg := fpfcntl( s , F_GETFL ); if arg = 0 then begin arg := arg or O_NONBLOCK; fpfcntl( s , F_SETFL , arg ); end; {$endif} {$ifdef windows} nb := 1; // 1 = nonblocking, 0 = blocking n := winsock2.ioctlsocket( s , FIONBIO , @nb ); {$endif} end; function is_writable_socket( s : integer ; var error : longint ) : boolean; var fds : tfdset; tv : timeval; valopt : longint = 1; vallen : {$ifdef linux} longword {$else} longint {$endif}; begin result := false; {$ifdef linux} fpfd_zero( fds ); fpfd_set( s , fds ); {$endif} {$ifdef windows} fd_zero( fds ); fd_set( s , fds ); {$endif} tv.tv_sec := 0; tv.tv_usec := 0; // socket+1 , read , write , except , timeout {$ifdef linux} if fpselect( s + 1 , nil , @fds , nil , @tv ) 0 then begin if fpfd_isset( s , fds ) = 1 then begin vallen := sizeof( valopt ); if fpgetsockopt( s , sol_socket , so_error , @valopt , @vallen ) = 0 then begin error := valopt; result := valopt = 0; end; end; end; {$else} if select( s + 1 , nil , @fds , nil , @tv ) 0 then begin if fd_isset( s , fds ) then begin vallen := sizeof( valopt ); if getsockopt( s , sol_socket , so_error , valopt , vallen ) = 0 then begin error := valopt; result := valopt = 0; end; end; end; {$endif} end; function ip_client_start_socket( s : string ) : boolean; begin result := false; setsockaddr( inetaddr_client_remote , s , port_program ); c_socket := fpsocket( PF_INET , SOCK_STREAM , 0 ); if c_socket = 0 then begin setnonblockingsocket( c_socket ); // nonblocking connect call result := my_connect( c_socket , inetaddr_client_remote ); end; // setnonblockingsocket( c_socket ); // blocking connect call, if this is executed later c_connected := false; end; function ip_client_is_connected( var error : longint ) : boolean; begin if not( c_connected ) then c_connected := is_writable_socket( c_socket , error ); result := c_connected; end; procedure ip_client_close_socket; begin if c_socket = 0 then closesocket( c_socket ); c_socket := -1; c_connected := false; end; thanks, dmitry ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] fpselect does not work on linux
On Sat, 9 May 2009, Rainer Stratmann wrote: To find out if a nonblocking socket has connected I use the following piece of code: With windows that works, but with linux I get alwas the result that the socket is writable. function is_writable_socket( sck : integer ) : boolean; var fds : tfdset; tv : timeval; begin {$ifdef linux} fpfd_zero( fds ); fpfd_set( sck , fds ); {$endif} {$ifdef windows} fd_zero( fds ); fd_set( sck , fds ); {$endif} tv.tv_sec := 0; tv.tv_usec := 0; // socket+1 , read , write , except , timeout {$ifdef linux} result := fpselect( sck + 1 , nil , @fds , nil, @tv ) 0; {$else} result := select( sck + 1 , nil , @fds , nil, @tv ) 0; {$endif} end; And why do you think that this is a bug ? Michael. ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] fpselect does not work on linux
Am Samstag, 9. Mai 2009 12:17 schrieb Michael Van Canneyt: On Sat, 9 May 2009, Rainer Stratmann wrote: To find out if a nonblocking socket has connected I use the following piece of code: With windows that works, but with linux I get alwas the result that the socket is writable. function is_writable_socket( sck : integer ) : boolean; var fds : tfdset; tv : timeval; begin {$ifdef linux} fpfd_zero( fds ); fpfd_set( sck , fds ); {$endif} {$ifdef windows} fd_zero( fds ); fd_set( sck , fds ); {$endif} tv.tv_sec := 0; tv.tv_usec := 0; // socket+1 , read , write , except , timeout {$ifdef linux} result := fpselect( sck + 1 , nil , @fds , nil, @tv ) 0; {$else} result := select( sck + 1 , nil , @fds , nil, @tv ) 0; {$endif} end; And why do you think that this is a bug ? I know that the socket I tested is not writable, but the function returns writable... always with linux. It is not working on linux operating system. With windows os that works. Someone else have (had?) exactly the same problem: http://community.freepascal.org:1/bboards/message?message_id=270583forum_id=24083 Rainer Michael. ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] fpselect does not work on linux
On Sat, 9 May 2009, Rainer Stratmann wrote: Am Samstag, 9. Mai 2009 12:17 schrieb Michael Van Canneyt: On Sat, 9 May 2009, Rainer Stratmann wrote: To find out if a nonblocking socket has connected I use the following piece of code: With windows that works, but with linux I get alwas the result that the socket is writable. function is_writable_socket( sck : integer ) : boolean; var fds : tfdset; tv : timeval; begin {$ifdef linux} fpfd_zero( fds ); fpfd_set( sck , fds ); {$endif} {$ifdef windows} fd_zero( fds ); fd_set( sck , fds ); {$endif} tv.tv_sec := 0; tv.tv_usec := 0; // socket+1 , read , write , except , timeout {$ifdef linux} result := fpselect( sck + 1 , nil , @fds , nil, @tv ) 0; {$else} result := select( sck + 1 , nil , @fds , nil, @tv ) 0; {$endif} end; And why do you think that this is a bug ? I know that the socket I tested is not writable, but the function returns writable... always with linux. It is not working on linux operating system. With windows os that works. Someone else have (had?) exactly the same problem: http://community.freepascal.org:1/bboards/message?message_id=270583forum_id=24083 The call functions correctly, IMHO, but the behaviour of the call is not as you expect. Select does *not* tell you if a file descriptor is writeable or readable. It tells you if the read/write operation will block. This is something subtly different. For instance, it reports file descriptor 0 as writable, which is rather strange, since it is read-only, but correct, because the write call will not block. Indeed the write call will return at once with an error condition. This is what the kernel sees (I used strace to test your code with descriptor 0): select(1, NULL, [0], NULL, {0, 0}) = 1 (out [0], left {0, 0}) Which is exactly what I sent. In short, is_writable_socket should be implemented differently, not using select. Michael. ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] fpselect does not work on linux
On 09 May 2009, at 09:38, Rainer Stratmann wrote: To find out if a nonblocking socket has connected I use the following piece of code: With windows that works, but with linux I get alwas the result that the socket is writable. function is_writable_socket( sck : integer ) : boolean; var fds : tfdset; tv : timeval; begin {$ifdef linux} fpfd_zero( fds ); fpfd_set( sck , fds ); {$endif} {$ifdef windows} fd_zero( fds ); fd_set( sck , fds ); {$endif} tv.tv_sec := 0; tv.tv_usec := 0; // socket+1 , read , write , except , timeout {$ifdef linux} result := fpselect( sck + 1 , Where does the + 1 come from? nil , @fds , nil, @tv ) 0; This is probably unrelated to your problem, but you have a bug here. (fp)select can also return EINTR (possibly under Windows as well, I don't know), in which case you have to retry. You need something like this: repeat res:=fpselect( sck + 1 , nil , @fds , nil, @tv ); until (res-1) or (fpgeterrnoESysEIntr); Note that you have to use this construct for many low level unix calls. Check the man pages to see which routines can return EINTR and may need restarting. Jonas ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] fpselect does not work on linux
On Sat, 9 May 2009, Jonas Maebe wrote: On 09 May 2009, at 09:38, Rainer Stratmann wrote: To find out if a nonblocking socket has connected I use the following piece of code: With windows that works, but with linux I get alwas the result that the socket is writable. function is_writable_socket( sck : integer ) : boolean; var fds : tfdset; tv : timeval; begin {$ifdef linux} fpfd_zero( fds ); fpfd_set( sck , fds ); {$endif} {$ifdef windows} fd_zero( fds ); fd_set( sck , fds ); {$endif} tv.tv_sec := 0; tv.tv_usec := 0; // socket+1 , read , write , except , timeout {$ifdef linux} result := fpselect( sck + 1 , Where does the + 1 come from? Man select: nfds is the highest-numbered file descriptor in any of the three sets, plus 1. Michael. ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] fpselect does not work on linux
According to the FPC rtl.pdf version 2.2.2 Doc version 2.1 of June 2008, page 165, states, and I quote: Description:FPSelect checks one of the file descriptors in the FDSets to see if its status changed. //- On Saturday 09 May 2009 12:50:03 Michael Van Canneyt wrote: On Sat, 9 May 2009, Rainer Stratmann wrote: Am Samstag, 9. Mai 2009 12:17 schrieb Michael Van Canneyt: On Sat, 9 May 2009, Rainer Stratmann wrote: To find out if a nonblocking socket has connected I use the following piece of code: With windows that works, but with linux I get alwas the result that the socket is writable. function is_writable_socket( sck : integer ) : boolean; var fds : tfdset; tv : timeval; begin {$ifdef linux} fpfd_zero( fds ); fpfd_set( sck , fds ); {$endif} {$ifdef windows} fd_zero( fds ); fd_set( sck , fds ); {$endif} tv.tv_sec := 0; tv.tv_usec := 0; // socket+1 , read , write , except , timeout {$ifdef linux} result := fpselect( sck + 1 , nil , @fds , nil, @tv ) 0; {$else} result := select( sck + 1 , nil , @fds , nil, @tv ) 0; {$endif} end; And why do you think that this is a bug ? I know that the socket I tested is not writable, but the function returns writable... always with linux. It is not working on linux operating system. With windows os that works. Someone else have (had?) exactly the same problem: http://community.freepascal.org:1/bboards/message?message_id=270583f orum_id=24083 The call functions correctly, IMHO, but the behaviour of the call is not as you expect. Select does *not* tell you if a file descriptor is writeable or readable. It tells you if the read/write operation will block. This is something subtly different. For instance, it reports file descriptor 0 as writable, which is rather strange, since it is read-only, but correct, because the write call will not block. Indeed the write call will return at once with an error condition. This is what the kernel sees (I used strace to test your code with descriptor 0): select(1, NULL, [0], NULL, {0, 0}) = 1 (out [0], left {0, 0}) Which is exactly what I sent. In short, is_writable_socket should be implemented differently, not using select. Michael. ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] fpselect does not work on linux
hello Rainer, do you check the socket's writability by fpFD_ISSET(sck, fds) ? thanks, dmitry ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] fpselect does not work on linux
On Sat, 9 May 2009, fpcl...@silvermono.co.za wrote: According to the FPC rtl.pdf version 2.2.2 Doc version 2.1 of June 2008, page 165, states, and I quote: Description:FPSelect checks one of the file descriptors in the FDSets to see if its status changed. I'll change it to something closer to the actual behaviour. Michael. ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] fpselect does not work on linux
Select does *not* tell you if a file descriptor is writeable or readable. It tells you if the read/write operation will block. This is something subtly different. This is interesting for blocking mode. But since you can switch to nonblocking mode every operation will return immediately. Here are some descriptions I found about select: http://publib.boulder.ibm.com/infocenter/tpfhelp/current/index.jsp?topic=/com.ibm.ztpf-ztpfdf.doc_put.cur/gtpc2/cpp_select.html http://docs.sun.com/app/docs/doc/816-5168/select-3c?a=view http://www.developerweb.net/forum/showthread.php?p=13486 ...The select socket function monitors a list of file descriptors for readability, readiness for writing, and exception pending conditions. Of course if you are in a blocking mode then a call does not block. ...if the select call returns that what we expect. For instance, it reports file descriptor 0 as writable, which is rather strange, since it is read-only, but correct, because the write call will not block. Indeed the write call will return at once with an error condition. This is what the kernel sees (I used strace to test your code with descriptor 0): select(1, NULL, [0], NULL, {0, 0}) = 1 (out [0], left {0, 0}) May be it is better to test it with sockets descriptors. If I get a result that the call will not block (as you say) and then I write data to the descriptor then the program crashes with exitcode 13... Which is exactly what I sent. In short, is_writable_socket should be implemented differently, not using select. How can I find out if a socket connection in a nonblocking mode is established? Michael. Am Samstag, 9. Mai 2009 12:55 schrieb dmitry boyarintsev: hello Rainer, do you check the socket's writability by fpFD_ISSET(sck, fds) ? Yes, before I did it this way, but it was the same behaviour. Windows ok. Linux failed. function is_writable_socket2( s : integer ; var error : longint ) : boolean; var fds : tfdset; tv : timeval; valopt : longint = 1; vallen : {$ifdef linux} longword {$else} longint {$endif}; begin result := false; {$ifdef linux} fpfd_zero( fds ); fpfd_set( s , fds ); {$endif} {$ifdef windows} fd_zero( fds ); fd_set( s , fds ); {$endif} tv.tv_sec := 0; tv.tv_usec := 0; // socket+1 , read , write , except , timeout {$ifdef linux} if fpselect( s + 1 , nil , @fds , nil , @tv ) 0 then begin if fpfd_isset( s , fds ) = 1 then begin vallen := sizeof( valopt ); if fpgetsockopt( s , sol_socket , so_error , @valopt , @vallen ) = 0 then begin error := valopt; result := valopt = 0; end; end; end; {$else} if select( s + 1 , nil , @fds , nil , @tv ) 0 then begin if fd_isset( s , fds ) then begin vallen := sizeof( valopt ); if getsockopt( s , sol_socket , so_error , valopt , vallen ) = 0 then begin error := valopt; result := valopt = 0; end; end; end; {$endif} end; thanks, dmitry ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-pascal Rainer ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] fpselect does not work on linux
On Sat, 9 May 2009, Rainer Stratmann wrote: Select does *not* tell you if a file descriptor is writeable or readable. It tells you if the read/write operation will block. This is something subtly different. This is interesting for blocking mode. But since you can switch to nonblocking mode every operation will return immediately. And therefor every select() call will indicate that all is OK. Here are some descriptions I found about select: http://publib.boulder.ibm.com/infocenter/tpfhelp/current/index.jsp?topic=/com.ibm.ztpf-ztpfdf.doc_put.cur/gtpc2/cpp_select.html http://docs.sun.com/app/docs/doc/816-5168/select-3c?a=view http://www.developerweb.net/forum/showthread.php?p=13486 ...The select socket function monitors a list of file descriptors for readability, readiness for writing, and exception pending conditions. You should check what the linux manpage says. It describes the exact behaviour. Of course if you are in a blocking mode then a call does not block. ...if the select call returns that what we expect. For instance, it reports file descriptor 0 as writable, which is rather strange, since it is read-only, but correct, because the write call will not block. Indeed the write call will return at once with an error condition. This is what the kernel sees (I used strace to test your code with descriptor 0): select(1, NULL, [0], NULL, {0, 0}) = 1 (out [0], left {0, 0}) May be it is better to test it with sockets descriptors. If I get a result that the call will not block (as you say) and then I write data to the descriptor then the program crashes with exitcode 13... Yes, and this is normal: if the socket is not open, you get an error when attempting to write to it - program exits. select() does not say anything about that. In each case, the call functions correctly, because it's simply passed on to the kernel. I verified several cases. Which is exactly what I sent. In short, is_writable_socket should be implemented differently, not using select. How can I find out if a socket connection in a nonblocking mode is established? This, I don't know. Michael.___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-pascal