read(fd, buf, size) after shutdown(fd, SHUT_RD) implementation-defined

read(fd, buf, size) after shutdown(fd, SHUT_RD) implementation-defined

Post by Clayton Weav » Wed, 11 Dec 2002 06:31:57

I notice some missing specification in the documentation on shutdown():

The Linux man page and glibc info page say that shutdown(fd, SHUT_RD)
shuts off "reception" of data on the socket. Single Unix Spec says
"disables further receive operations". That sounds like it applies to the
tcp/ip session, not to the process's ability to read() if the socket
read buffer still has data when shutdown() is called. Neither the man
pages, info pages, or SuS man page say anything about what the
semantics of read() should be after shutdown(fd, SHUT_RD) is called.

The SO_LINGER option only discusses the write() direction: "close() and
shutdown() will block until all data has been written". (I wonder how
O_NONBLOCK works with that, but that's a question for another day).

An ipc tutorial from Berkeley's CSRG, issued when 4.3 bsd was the current bsd
version, says:

  Should a user have no use for any pending data, it may perform a
  "shutdown" on the socket prior to closing it. This call is of the

      shutdown(s, how);

  where "how" is 0 if the user is no longer interested in reading
  data, 1 if no more data will be sent, or 2 if no data is to be
  sent or received.

This appears to simply assume that code is not going to call read()
on the socket after shutdown(fd, SHUT_RD), and so leaves the question
of how the kernel is to respond to such a read() call undefined.
(Joys of an ad-hoc spec defined by the code that first implemented it,
and whose later formalization failed to specify the  semantics of subsequent
file operations on the socket fd after shutdown().)

So I would merely take the position that "results of read(fd, buf, size)
after shutdown(fd, SHUT_RD) has been called are implementation-defined"
(meaning that any given kernel will do something in that situation, but
code cannot expect how one kernel reacts to read() after
shutdown(fd, SHUT_RD) to be portable to other systems or kernel
versions without some formal standard specifying those semantics).

It seems prudent to not rely on the socket's read buffer to still be available
to the process after telling the kernel that you no longer have any
interest in reading from it. Anything the kernel does with the socket's
read buffer after shutdown(fd, SHUT_RD) is unspecified and thus valid
by definition.

How quickly the kernel gets around to actually notifying the remote peer
that the socket is closed for writing is internal to the tcp/ip stack.
"Immediately" would be good, but it is not going to be seen by the reader
that called shutdown() in any case.

Mutliple reader/writer apps that share a socket should still use locks and
"open/closed for i/o flags" (that are checked once a process or thread
holds the lock) to insulate themselves from variations in
(implementation-defined) "i/o after shutdown()" behavior, imho.


Clayton Weaver

"Everyone is ignorant, just about different things."  Will Rogers


1. read(fd, buf, N) fails when N doesn't fit in 32 bits?

A Tru64 5.1 user reports that GNU Diffutils 2.8 doesn't work on his
system because the read(2) system call won't accept a size argument
greater than 2**31 - 1.  His truss output looks like this:

read(6, 0x0000000140015000, 5312561138)         Err#22 Invalid argument

Is there some compile-time option that he can use on Tru64 to work
around this problem?  Or perhaps there's a Tru64 patch that I can
recommend to him?

You can read his original bug report in:

and my proposed workaround in:

This workaround limits the 'read' calls to less than 2**31 bytes, but
I'd prefer a solution that removes that arbitrary limit.  Sorry, I
don't use Tru64 myself, so I'm not well versed in its compile-time
options and patches.

2. adduser

3. <unistd.h>write(fd,buf,len) [write(2)] question...

4. Help

5. Is /dev/fd redundant to /proc/self/fd ?

6. Oppose the SSSCA (government policeware on your PC)

7. g++ fd.getline() and msvc fd.getline()??

8. Diamond 56i PCI modem and RedHat5.1

9. fd 0 == fd 1 when running under inetd?

10. PS2 MCA -> FD MCS-350 SCSI :: Compatible with other FD cards?

11. /dev/fd implementation

12. Yet another /dev/fd driver implementation

13. When call shutdown(), how is socket fd closed?