Re: [fpc-pascal] fpselect does not work on linux

2009-05-10 Thread Rainer Stratmann
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

2009-05-09 Thread 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 ?

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

2009-05-09 Thread Rainer Stratmann
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

2009-05-09 Thread Michael Van Canneyt


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

2009-05-09 Thread Jonas Maebe


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

2009-05-09 Thread Michael Van Canneyt


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

2009-05-09 Thread fpclist
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

2009-05-09 Thread dmitry boyarintsev
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

2009-05-09 Thread Michael Van Canneyt


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

2009-05-09 Thread Rainer Stratmann
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

2009-05-09 Thread Michael Van Canneyt


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