[fpc-pascal] fpselect does not work on linux

Rainer Stratmann RainerStratmann at t-online.de
Sun May 10 12:04:47 CEST 2009


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 at lists.freepascal.org
> http://lists.freepascal.org/mailman/listinfo/fpc-pascal



More information about the fpc-pascal mailing list