23.3 Partial Delivery
Partial delivery will be used by the SCTP
implementation any time a "large" message is being received, where
"large" means the SCTP stack deems that it does not have the
resources to dedicate to the message. The following considerations
will be made by the receiving SCTP implementation before starting
this API:
-
The amount of buffer space being consumed by the
message must meet or exceed some threshold.
-
The stack can only deliver from the beginning of
the message sequentially up to the first missing piece.
-
Once invoked, no other messages may be made
available for the user until the current message has been
completely received and passed to the user. This means that the
large message blocks all other messages that would normally be
deliverable, including those in other streams.
The KAME implementation of SCTP uses a threshold
of one-half the socket receive buffer. At this writing, the default
receive buffer for the stack is 131,072 bytes. So, without changing
the SO_RCVBUF, a single message must be larger than 65,536
bytes before the partial delivery API will be invoked. To further
extend the new version of the server from Section 10.2, we
write a utility function that wraps the sctp_recvmsg
function call. We then create a modified server to use our new
function. Figure 23.2
shows our wrapper function to handle the partial delivery API.
Prepare static buffer
12鈥?5
If the function's static buffer has not been allocated, allocate it
and set up the state associated with it.
Read message
16鈥?8
Read in the first message using the sctp_recvmsg
function.
Handle initial read error
19鈥?2
If sctp_recvmsg returns an error or an EOF, we pass it
directly back to the caller.
While there is more data for this
message
23鈥?4
While the message flags show that the function has not received a
complete message, collect more data. The function starts by
calculating how much is left in the static buffer.
See if we need to grow static
buffer
25鈥?4
Whenever the function no longer has a minimum amount of room left
in its receive buffer, it must grow the buffer. We do this using
the realloc function to allocate a new buffer of the
current size, plus an increment amount, and copy the old data. If
for some reason the function cannot grow its buffer any more, it
exits with an error.
Receive more data
35鈥?6
Gather more data with the sctp_recvmsg function.
Move forward
37鈥?8
The function increments the buffer index and goes back to test if
it has read all of the message.
At loop end
39鈥?0
When the loop terminates, the function copies the number of bytes
read into the pointer provided by the caller and returns a pointer
to the allocated buffer.
Figure 23.2
Handling the partial delivery API.
sctp/sctp_pdapircv.c
1 #include "unp.h"
2 static uint8_t *sctp_pdapi_readbuf = NULL;
3 static int sctp_pdapi_rdbuf_sz = 0;
4 uint8_t *
5 pdapi_recvmsg(int sock_fd,
6 int *rdlen,
7 SA *from,
8 int *from_len, struct sctp_sndrcvinfo *sri, int *msg_flags)
9 {
10 int rdsz, left, at_in_buf;
11 int frmlen = 0;
12 if (sctp_pdapi_readbuf == NULL) {
13 sctp_pdapi_readbuf = (uint8_t *) Malloc(SCTP_PDAPI_INCR_SZ);
14 sctp_pdapi_rdbuf_sz = SCTP_PDAPI_INCR_SZ;
15 }
16 at_in_buf =
17 Sctp_recvmsg(sock_fd, sctp_pdapi_readbuf, sctp_pdapi_rdbuf_sz, from,
18 from_len, sri, msg_flags);
19 if (at_in_buf < 1) {
20 *rdlen = at_in_buf;
21 return (NULL);
22 }
23 while ((*msg_flags & MSG_EOR) == 0) {
24 left = sctp_pdapi_rdbuf_sz - at_in_buf;
25 if (left < SCTP_PDAPI_NEED_MORE_THRESHOLD) {
26 sctp_pdapi_readbuf =
27 realloc(sctp_pdapi_readbuf,
28 sctp_pdapi_rdbuf_sz + SCTP_PDAPI_INCR_SZ);
29 if (sctp_pdapi_readbuf == NULL) {
30 err_quit("sctp_pdapi ran out of memory");
31 }
32 sctp_pdapi_rdbuf_sz += SCTP_PDAPI_INCR_SZ;
33 left = sctp_pdapi_rdbuf_sz - at_in_buf;
34 }
35 rdsz = Sctp_recvmsg(sock_fd, &sctp_pdapi_readbuf[at_in_buf],
36 left, NULL, &frmlen, NULL, msg_flags);
37 at_in_buf += rdsz;
38 }
39 *rdlen = at_in_buf;
40 return (sctp_pdapi_readbuf);
41 }
We next modify our server in Figure 23.3 so that it uses the new
function.
Read message
29鈥?0
Here the server calls the new partial delivery utility function.
The server calls this after nulling out any old data that may have
been hanging around in the sri variable.
Figure 23.3 Our
server using the partial delivery API.
sctp/sctpserv05.c
26 for ( ; ; ) {
27 len = sizeof(struct sockaddr_in);
28 bzero(&sri, sizeof(sri));
29 readbuf = pdapi_recvmsg(sock_fd, &rd_sz,
30 (SA *) &cliaddr, &len, &sri, &msg_flags);
31 if (readbuf == NULL)
32 continue;
Verify we read something
31鈥?2
Note that now the server must test for NULL to see if the read was
successful. If not, the server just continues.
|