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>
