Closed Bug 17223 Opened 25 years ago Closed 24 years ago

Support the flags argument to PR_Recv, PR_Send, PR_RecvFrom, and PR_SendTo

Categories

(NSPR :: NSPR, defect, P3)

defect

Tracking

(Not tracked)

RESOLVED FIXED

People

(Reporter: wtc, Assigned: wtc)

Details

Right now the flags argument to PR_Recv, PR_Send, PR_RecvFrom, and PR_SendTo is not supported and must be 0. Some NSPR clients have requested that the MSG_PEEK flag for recv be supported. We also want to find out what other flags can be supported. I suspect that the reason we decided to not support the flags argument is that in our NT version, PR_Recv is implemented by an overlapped ReadFile call, which doesn't support the MSG_PEEK flag of recv. It is not clear whether recv(MSG_PEEK) works on a socket associated with an I/O completion port.
Status: NEW → ASSIGNED
UNIX98 specifies the following flags: - recv, recvfrom: MSG_PEEK, MSG_OOB, MSG_WAITALL - send, sendto: MSG_EOR, MSG_OOB Winsock specifies the following flags: - recv, recvfrom: MSG_PEEK, MSG_OOB - send, sendto: MSG_DONTROUTE, MSG_OOB So it seems that the flags that are universally supported by the native socket interfaces are: - recv, recvfrom: MSG_PEEK, MSG_OOB - send, sendto: MSG_OOB The NT-only version of NSPR may have trouble supporting these flags because PR_Recv and PR_Send are implemented using the Win32 ReadFile and WriteFile functions, which don't support the MSG_PEEK and MSG_OOB flags or their equivalents. We use ReadFile and WriteFile instead of recv send because we do overlapped I/O on the sockets. Winsock2's WSARecv and WSASend support flags and overlapped I/O. However, some of our sockets may be accepted by an AcceptEx call; this kind of sockets cannot be passed to WSARecv and WSASend. Moreover, the MSG_PEEK flag of WSARecv is not valid for overlapped sockets, according to Microsoft documentation. So WSARecv and WSASend are out of the question.
For the records, OpenVMS supports: - recv, recvfrom: MSG_PEEK, MSG_OOB - send, sendto: MSG_OOB
Status: ASSIGNED → RESOLVED
Closed: 25 years ago
Resolution: --- → WONTFIX
Resolved the bug as WONFIX due to the limitation of our implementation on NT.
We will look into supporting the PR_MSG_PEEK flag for PR_Recv in NSPR 4.1. On Windows NT or other platforms that don't support the BSD socket MSG_PEEK flag, we will emulate PR_MSG_PEEK by buffering received data in PRFileDesc.
Status: RESOLVED → REOPENED
Resolution: WONTFIX → ---
Target Milestone: --- → 4.1
Status: REOPENED → ASSIGNED
I added the PR_MSG_PEEK flag (with same value as MSG_PEEK) for PR_Recv(). On platforms that don't natively support MSG_PEEK (e.g., Windows NT's overlapped mode sockets and Mac OS OpenTransport), we will need to emulate it with a buffer in the NSPR layer. The tricky part is to manage the size of this buffer. Nelson, you said you have an idea of how to emulate PR_MSG_PEEK. Could you outline the design? This is the design I came up with for the emulation of PR_MSG_PEEK. Initially, a PRFileDesc does not have a peek buffer. The peek buffer is allocated the first time we peek in the file descriptor. PR_Recv(sock, buf, amount, PR_MSG_PEEK, timeout) would be implemented as follows: if (peek buffer doesn't exist) { allocate peek buffer of size 'amount'; read data into the peek buffer; } else { /* peek buffer exists */ if (peek buffer is empty) { if (peek buffer size < amount) { reallocate peek buffer of size 'amount'; } read data into peek buffer; } } copy data into output buffer; PR_Recv(sock, buf, amount, 0, timeout) would be implemented as follows: if (peek buffer exists and contains data) { int n = min(amount, #bytes in peek buffer); consume n bytes of data in peek buffer and copy them to output buffer; } else { read data into output buffer; } One drawback of this design is that if the peek buffer already contains data, we will return those data immediately without attempting to find out if there are more data in the file descriptor. So we may return fewer data than there actually are, which should be okay because PR_Recv() is not required to return as many bytes as requested. If it is necessary to return as many bytes as possible, we can call ioctl(FIONREAD) to find out if the socket has more data, and read the socket only if the socket has more data. This is to prevent blocking because by definition PR_Recv() should return immediately if there are data available (including data in the peek buffer).
SSL's general algorithm for PR_Recv is: if (no data is already available to be read) { read in (and decrypt) the next SSL application data record, blocking if necessary } Copy out available data, the lesser of the amount available and the amount requested. If the PEEK flag is not set, reduce the amount available by the amount just copied out. return the amount copied out. Note that application data records are bounded to 32K for SSL2 and 16K for SSL3 and TLS. So, the maximum amount available from a single PR_Recv call on an SSL socket will be no more than 32KB.
I implemented the PR_MSG_PEEK flag for PR_Recv() for BeOS, Mac OS, OS/2, and Windows. On BeOS, Mac OS, and NT, PR_MSG_PEEK is emulated with a peek buffer in a NSPR file descriptor. If PR_MSG_PEEK is emulated (i.e., the macro _PR_HAVE_PEEK_BUFFER is defined), PR_Recv, PR_Available, and PR_Available64 depend on the peek buffer. The algorithm is described as follows. If there is data in the peek buffer, PR_Available and PR_Available64 return the number of bytes of data in the peek buffer. PR_Recv copies the lesser of the amount available and the amount requested from the peek buffer to the output buffer. If PR_MSG_PEEK is not specified, the bytes copied out are consumed from the peek buffer. If the peek buffer is not created yet or there is no data in the peek buffer, PR_Available and PR_Available64 call ioctl(FIONREAD) on the native socket to obtain the amount of data available. If PR_MSG_PEEK is specified, PR_Recv reads data from the native socket into the output buffer and then copies the data into the peek buffer. The size of the peek buffer does not exceed a maximum defined by the macro _PR_PEEK_BUFFER_MAX. On NT, only overlapped mode sockets need to emulate PR_MSG_PEEK. So I use the macro _PR_FD_NEED_EMULATE_MSG_PEEK(fd) to determine whether the fd needs to emulate PR_MSG_PEEK. On platforms where all fd's need to emulate PR_MSG_PEEK (such as BeOS and Mac OS), _PR_FD_NEED_EMULATE_MSG_PEEK(fd) is simply defined as 1.
I fixed a mistake that I found when I compiled on Mac. /cvsroot/mozilla/nsprpub/pr/src/io/prsocket.c, revision 3.42
There is a test case (peek.c) for the PR_MSG_PEEK flag for PR_Recv. It probably could be improved. Marked the bug fixed.
Status: ASSIGNED → RESOLVED
Closed: 25 years ago24 years ago
Resolution: --- → FIXED
You need to log in before you can comment on or make changes to this bug.