Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 21 Nov 2002 18:36:54 +1100 (EST)
From:      Bruce Evans <bde@zeta.org.au>
To:        jayanth <jayanth@yahoo-inc.com>
Cc:        freebsd-net@FreeBSD.ORG
Subject:   Re: file descriptor flags and socket flags out of sync ?
Message-ID:  <20021121171101.K37954-100000@gamplex.bde.org>
In-Reply-To: <20021120110632.A62938@yahoo-inc.com>

next in thread | previous in thread | raw e-mail | index | archive | help
On Wed, 20 Nov 2002, jayanth wrote:

> Some developers here have encountered a scenario where the file
> descriptor flags and the socket flags seem to be out of sync.
>
> if an application does:
>
> listen(listenfd)
> while (!done) {
>   select()
> 	<-------------------- new connection arrives before fcntl()
>   fcntl(listenfd,O_NONBLOCK)
>   newfd = accept(listenfd,...)
>   fnctl(listenfd,0)   /* make socket blocking */
>   if (newfd & O_NONBLOCK)

Better delete the last line.  newfd doesn't contain any file flags.

> 	/* fd is O_NONBLOCK, but socket is blocking */
> }
>
> At this point socket is blocking because the state
> of the new socket = state of the listen socket only during the connection
> setup phase, not during the accept phase. However, the filedescriptor
> flags are copied during the accept phase. So at this point
> the filedescriptor flags are nonblocking but the socket is actually blocking.

This is related to my pet peeve of keeping the O_NONBLOCK flag in several
places (one of them inadequate) and using the wrong copies.  For sockets,
the per-socket flag is adequate since open() doesn't work on sockets so
there only needs to be one flag per socket, and using the per-socket flag
mostly works right.  For devices that can be opened more than once, a
per-device flag is inadequate since file flags are supposed to be per-open.
Non-broken device drivers use the copy of the file flags passed to their
read/write/ioctl/close/etc functions, but making a copy causes synchronization
problems.  However, accessing the per-file flag from the device layer or
the socket layer would be a layering violation.

> Agreed, that the solution is to have the application set NONBLOCK before
> the listen() call, but it seems incorrect to have the newfd's flags and socket
> state be out of sync.

You could also use "fnctl(newfd, 0)" to sync things for newfd.

> Copying the state of the socket during the accept might lead to a slightly
> different behaviour, but will solve this particular problem.

I think this is the correct fix.  The states are supposed to be consistent.
This is enforced by fcntl() if the file flag state using it.  I think you
can still make a mess by changing the state using ioctl().

Bruce


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-net" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20021121171101.K37954-100000>