[ Team LiB ] |
23.3 Partial DeliveryPartial 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 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 buffer12–15 If the function's static buffer has not been allocated, allocate it and set up the state associated with it. Read message16–18 Read in the first message using the sctp_recvmsg function. Handle initial read error19–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 message23–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 buffer25–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 data35–36 Gather more data with the sctp_recvmsg function. Move forward37–38 The function increments the buffer index and goes back to test if it has read all of the message. At loop end39–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 message29–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 something31–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 ] |