Turning FNDELAY *off*

Barton E. Schaefer schaefer at ogccse.ogc.edu
Fri Aug 11 09:25:22 AEST 1989


Surely there must be an obvious way to do this, and I'm just missing it.
I'm using DYNIX 3.0.12 on a Sequent Symmetry, but my question applies
to 4.3 BSD as well, as far as I can tell.  I've asked a guru here and
come up empty.

I have a small program which creates a socket [via socket(2)], binds a
name to it [bind(2)], and prepares to receive connections [listen(2)].
I won't go into the details of these calls because they work as expected.
(Miraculous, eh?)  The program then needs to proceed with another task,
checking the socket periodically for connections from a slave program.
The master program cannot block when checking for these connections.

According to the man page for accept(2):

     The call returns -1 on error.  If it succeeds it returns a
     non-negative integer which is a descriptor for the accepted
     socket.

     The accept will fail if:

     [EWOULDBLOCK]       The socket is marked non-blocking and no
                         connections are present to be accepted.

I therefore make the following call, where sd is the descriptor returned
by socket(2):

    if (fcntl(sd, F_SETFL, FNDELAY) < 0) {
	perror("fcntl");
	exit(1);
    }

I note in passing that FNDELAY is defined only for ttys and sockets, but
a socket is what I have, so all should be well.  I don't get an error
return from fcntl(), in any case.  The program then goes about its
business, periodically doing:

    if ((ad = accept(sd, sd_name, sd_size)) < 0) {
	if (errno != EWOULDBLOCK) {
	    perror("accept");
	    exit(1);
	}
    }
    else {
	/* talk to slave via ad */
	/* much detail omitted */
	if (close(ad) < 0) {
	    perror("close");
	    exit(1);
	}
    }

This works fine and I am able to connect to the slave through the new
descriptor ad.

The problem begins when the slave sometimes cannot read data from the
socket as quickly as the master tries to write it.  The new descriptor
ad inherits the FNDELAY attribute from sd, so the master gets an error
from write(2) when the socket fills up.

So, what I would like to do is turn *off* the FNDELAY attribute of the
new descriptor ad and allow the master to do blocking writes.  I don't
care if this also affects sd, because there is never more than one
master-slave connection at a time and I can reset FNDELAY on sd after
closing the connection on ad.  So the question is

    Is there any way to restore blocking read/write on a descriptor?

I am aware that:

     It is possible to select(2) a socket for the purposes of
     doing an accept by selecting it for read.

so it is not strictly necessary to do the fcntl() in the first place,
and I will convert to use select(2) if necessary.  However, it seems
odd to me that FNDELAY is a permanent condition.  My present interim
solution is to note when the error from write() is EWOULDBLOCK, and in
that case go to sleep for second and then try the write again.  This
seems to lose data on rare, nonrepeatable occasions, so a different
solution is required.

Thanks in advance.
-- 
Bart Schaefer           "And if you believe that, you'll believe anything."
                                                            -- DangerMouse
CSNET / Internet                schaefer at cse.ogc.edu
UUCP                            ...{sequent,tektronix,verdix}!ogccse!schaefer



More information about the Comp.unix.questions mailing list