[ Team LiB ] Previous Section Next Section

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–15 If the function's static buffer has not been allocated, allocate it and set up the state associated with it.

Read message

16–18 Read in the first message using the sctp_recvmsg function.

Handle initial read error

19–22 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–24 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–34 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–36 Gather more data with the sctp_recvmsg function.

Move forward

37–38 The function increments the buffer index and goes back to test if it has read all of the message.

At loop end

39–40 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–30 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–32 Note that now the server must test for NULL to see if the read was successful. If not, the server just continues.

    [ Team LiB ] Previous Section Next Section