select() works with NULL timeval, doesn't otherwise

select() works with NULL timeval, doesn't otherwise

Post by psufu » Sun, 23 Jun 2002 04:00:44



Hello,

Allow me to explain my full problem.  Hopefully you'll agree that
select() is the way to go and possibly shed some light on why it isn't
working.

I have a process that, when started, listens for incoming connections.
 If someone connects to the process, it starts up a few other
processes and goes about listening for another connection.  All of
this works fine (I used a blocking socket for all of it).  But I now
need the process to kill itself when the user logs off.  After much
surfing of this usegroup and the internet, I've realized that I need a
non-blocking socket for the accept() call so that I can loop and
occasionally test to see if the parent process has been killed (which
would be the shell, and then I'd kill the program itself).  The SIGHUP
signal isn't an option because it doesn't send it to my process when
it's running in the background.

All right, so there's my goal.  Now, I figure what I'll do is use a
non-blocking socket, loop using select() with a timeout value so that
I'd be testing to see if the process should commit suicide every X
seconds.  I've gotten the code down, but here's my problem.  I start
up the program (call it the console) and when I go to start the other
program (which will connect to the console) it doesn't work, the
console never realizes a connection is being attempted.  It does work,
however, if my timeout value is NULL.  Here's my code for accepting a
connection:

  fcntl(ListenSocket, F_SETFL, O_NONBLOCK);

  fd_set set;
  FD_ZERO(&set);
  FD_SET(ListenSocket, &set);

  struct timeval tv;

  for (;;)
  {
    tv.tv_sec  = 5;
    tv.tv_usec = 0;

    int retval;

    // works fine if &tv is replaced with NULL
    if ((retval = select(ListenSocket+1, &set, &set, NULL, &tv))>0)
    {
      sockaddr_in sinRemote;
      int nAddrSize = sizeof(sinRemote);

      Socket = accept(ListenSocket, (sockaddr*)&sinRemote, (socklen_t
* &nAddrSize);
      if (Socket==-1)
      {
        if (errno==EWOULDBLOCK)
        {
          continue;
        }
        else
        {
          return 0;
        }
      }
      else
      {
        fcntl(ListenSocket, F_SETFL, 0);
        return 1;
      }
    }
    else if (retval==0)
    {
      // This is where i'd check to see if the user has logged out
      continue;
    }
    else
    {
      return 0;
    }
  }

  return 0;

 
 
 

select() works with NULL timeval, doesn't otherwise

Post by SledgeH » Sun, 23 Jun 2002 04:25:26



>Hello,

>Allow me to explain my full problem.  Hopefully you'll agree that
>select() is the way to go and possibly shed some light on why it isn't
>working.

>I have a process that, when started, listens for incoming connections.
> If someone connects to the process, it starts up a few other
>processes and goes about listening for another connection.  All of
>this works fine (I used a blocking socket for all of it).  But I now
>need the process to kill itself when the user logs off.  After much
>surfing of this usegroup and the internet, I've realized that I need a
>non-blocking socket for the accept() call so that I can loop and
>occasionally test to see if the parent process has been killed (which
>would be the shell, and then I'd kill the program itself).  The SIGHUP
>signal isn't an option because it doesn't send it to my process when
>it's running in the background.

>All right, so there's my goal.  Now, I figure what I'll do is use a
>non-blocking socket, loop using select() with a timeout value so that
>I'd be testing to see if the process should commit suicide every X
>seconds.  I've gotten the code down, but here's my problem.  I start
>up the program (call it the console) and when I go to start the other
>program (which will connect to the console) it doesn't work, the
>console never realizes a connection is being attempted.  It does work,
>however, if my timeout value is NULL.  Here's my code for accepting a
>connection:

you should be able to do it with a blocking socket too... only accept
the connection when select says it is ready...

your problem is that set will be emptied when the select times out
once...
you must FD_SET the listensocket everytime before you enter the select
call..

the code would be

for (;;) {
  struct timeval tv;
  fd_set set;
  /*make siure the set is setup correctly before enterngg the select call*/
  FD_ZERO(&set);
  FD_SET(ListenSocket, &set);

  if ((retval = select(ListenSocket+1, &set, NULL, NULL, &tv))==-1) {
     return 0;
  }
  if (FD_ISSET(ListenSocket, &set)) {
     /*you only get here when the accept will not block and a new
       connection is available*/
     sockaddr_in sinRemote;
     int nAddrSize = sizeof(sinRemote);

     Socket = accept(ListenSocket,
                        (sockaddr*)&sinRemote,
                        (socklen_t * &nAddrSize));
     if (Socket==-1) {
        perror("accept");
        return 0;
     }
   } else {
     /*do you log out stuff here*/
   }

Quote:}

however I'm not sure what you all mean with logged out etc.. so maybe
there are event better ways to check for this.

Hope this helps....

Sledge

- Show quoted text -

Quote:>  fcntl(ListenSocket, F_SETFL, O_NONBLOCK);

>  fd_set set;
>  FD_ZERO(&set);
>  FD_SET(ListenSocket, &set);

>  struct timeval tv;

>  for (;;)
>  {
>    tv.tv_sec  = 5;
>    tv.tv_usec = 0;

>    int retval;

>    // works fine if &tv is replaced with NULL
>    if ((retval = select(ListenSocket+1, &set, &set, NULL, &tv))>0)
>    {
>      sockaddr_in sinRemote;
>      int nAddrSize = sizeof(sinRemote);

>      Socket = accept(ListenSocket, (sockaddr*)&sinRemote, (socklen_t
>* &nAddrSize);
>      if (Socket==-1)
>      {
>        if (errno==EWOULDBLOCK)
>        {
>          continue;
>        }
>        else
>        {
>          return 0;
>        }
>      }
>      else
>      {
>        fcntl(ListenSocket, F_SETFL, 0);
>        return 1;
>      }
>    }
>    else if (retval==0)
>    {
>      // This is where i'd check to see if the user has logged out
>      continue;
>    }
>    else
>    {
>      return 0;
>    }
>  }

>  return 0;

--
Remove .is.the.coolest to mail me

 
 
 

select() works with NULL timeval, doesn't otherwise

Post by Brian Hanse » Sun, 23 Jun 2002 04:25:38


I figured it out, thanks anyways.  I had to put the FD_ZERO and FD_SET
macros inside the loop.  Thanks,

Brian


 
 
 

select() works with NULL timeval, doesn't otherwise

Post by Tobias Oe » Sun, 23 Jun 2002 04:31:04





>>Hello,

>>Allow me to explain my full problem.  Hopefully you'll agree that
>>select() is the way to go and possibly shed some light on why it isn't
>>working.

>>I have a process that, when started, listens for incoming connections.
>> If someone connects to the process, it starts up a few other
>>processes and goes about listening for another connection.  All of
>>this works fine (I used a blocking socket for all of it).  But I now
>>need the process to kill itself when the user logs off.  After much
>>surfing of this usegroup and the internet, I've realized that I need a
>>non-blocking socket for the accept() call so that I can loop and
>>occasionally test to see if the parent process has been killed (which
>>would be the shell, and then I'd kill the program itself).  The SIGHUP
>>signal isn't an option because it doesn't send it to my process when
>>it's running in the background.

>>All right, so there's my goal.  Now, I figure what I'll do is use a
>>non-blocking socket, loop using select() with a timeout value so that
>>I'd be testing to see if the process should commit suicide every X
>>seconds.  I've gotten the code down, but here's my problem.  I start
>>up the program (call it the console) and when I go to start the other
>>program (which will connect to the console) it doesn't work, the
>>console never realizes a connection is being attempted.  It does work,
>>however, if my timeout value is NULL.  Here's my code for accepting a
>>connection:

> you should be able to do it with a blocking socket too... only accept
> the connection when select says it is ready...

I thought the same but you may run into a race condition. From my accept man
page:

There  may not always be a connection waiting after a SIGIO is delivered or
select(2) or poll(2) return a readability event because the connection
might have been  removed  by  an  asynchronous network  error  or  another  
thread before accept is called.  If this happens then the call will
block waiting for the next connection to arrive.  To ensure that accept
never blocks, the passed socket s needs to have the O_NONBLOCK flag set
(see socket(7)).

Tobias.

- Show quoted text -

Quote:> your problem is that set will be emptied when the select times out
> once...
> you must FD_SET the listensocket everytime before you enter the select
> call..

> the code would be

> for (;;) {
>   struct timeval tv;
>   fd_set set;
>   /*make siure the set is setup correctly before enterngg the select
>   call*/ FD_ZERO(&set);
>   FD_SET(ListenSocket, &set);

>   if ((retval = select(ListenSocket+1, &set, NULL, NULL, &tv))==-1) {
>      return 0;
>   }
>   if (FD_ISSET(ListenSocket, &set)) {
>      /*you only get here when the accept will not block and a new
>        connection is available*/
>      sockaddr_in sinRemote;
>      int nAddrSize = sizeof(sinRemote);

>      Socket = accept(ListenSocket,
> (sockaddr*)&sinRemote,
> (socklen_t * &nAddrSize));
>      if (Socket==-1) {
>         perror("accept");
>         return 0;
>      }
>    } else {
>      /*do you log out stuff here*/
>    }
> }

> however I'm not sure what you all mean with logged out etc.. so maybe
> there are event better ways to check for this.

> Hope this helps....

> Sledge

>>  fcntl(ListenSocket, F_SETFL, O_NONBLOCK);

>>  fd_set set;
>>  FD_ZERO(&set);
>>  FD_SET(ListenSocket, &set);

>>  struct timeval tv;

>>  for (;;)
>>  {
>>    tv.tv_sec  = 5;
>>    tv.tv_usec = 0;

>>    int retval;

>>    // works fine if &tv is replaced with NULL
>>    if ((retval = select(ListenSocket+1, &set, &set, NULL, &tv))>0)
>>    {
>>      sockaddr_in sinRemote;
>>      int nAddrSize = sizeof(sinRemote);

>>      Socket = accept(ListenSocket, (sockaddr*)&sinRemote, (socklen_t
>>* &nAddrSize);
>>      if (Socket==-1)
>>      {
>>        if (errno==EWOULDBLOCK)
>>        {
>>          continue;
>>        }
>>        else
>>        {
>>          return 0;
>>        }
>>      }
>>      else
>>      {
>>        fcntl(ListenSocket, F_SETFL, 0);
>>        return 1;
>>      }
>>    }
>>    else if (retval==0)
>>    {
>>      // This is where i'd check to see if the user has logged out
>>      continue;
>>    }
>>    else
>>    {
>>      return 0;
>>    }
>>  }

>>  return 0;

--
unix http://www.faqs.org/faqs/by-newsgroup/comp/comp.unix.programmer.html
clc http://www.eskimo.com/~scs/C-faq/top.html
fclc (french): http://www.isty-info.uvsq.fr/~rumeau/fclc/
 
 
 

select() works with NULL timeval, doesn't otherwise

Post by David Schwart » Mon, 24 Jun 2002 02:55:01



> you should be able to do it with a blocking socket too... only accept
> the connection when select says it is ready...

        If you do that, what happens if the other end breaks the connection
before you can 'accept' it but after 'select' returns?

        DS

 
 
 

select() works with NULL timeval, doesn't otherwise

Post by Casper H.S. Di » Mon, 24 Jun 2002 18:33:06




>> you should be able to do it with a blocking socket too... only accept
>> the connection when select says it is ready...
>    If you do that, what happens if the other end breaks the connection
>before you can 'accept' it but after 'select' returns?

Depends on the OS: in Solaris it currently causes a failure from accept()
in order to prevent programs from blocking.  (With all the portscanning on
the internet, that is a useful feature)

Casper
--
Expressed in this posting are my opinions.  They are in no way related
to opinions held by my employer, Sun Microsystems.
Statements on Sun products included here are not gospel and may
be fiction rather than truth.

 
 
 

1. /dev/null doesn't do the right thing with select??

In linux version 1.1.47, the select system call on /dev/null always
returns 0 for readfds and writefds.  I'm no Posix wizard, but this
doesn't seem quite right.  Select should return 0 if a read or write
on the fd will block, which of course /dev/null never does.  The fix
in the kernel is obvious.

Has this bug been fixed in a newer version of the kernel?  If not,
who/how does something like this get fixed?  I'm new to this list so
I'm not familiar with whatever procedures happen to be in place.

        -Cliff

2. - Upgrading Apache

3. TOSS_OUTPUT=' >/dev/null' doesn't work

4. personal laserwriter nt

5. Re. bffcreate -X doesn't work Re: bffcreate -X Doesn't Work

6. Windows Client Access to FreeBSD File Server

7. Help cslip doesn't work with 2 linux boxes and null-modem

8. X session terminating after approx 2 hours.

9. null modem and slip doesn't work on 1.1.80?

10. select (cut and paste) doesn't work with my mouse

11. Veritas Visual Administrator: multiple select doesn't work

12. 2.2 select() on UDP Socket doesn't work as expected