[ Team LiB ] Previous Section Next Section

23.10 Peeling Off an Association

We have been focusing on the one-to-many-style interface provided by SCTP. This interface has several advantages over the more classic one-to-one style:

  • There is only one file descriptor to maintain.

  • It allows us to write a simple iterative server.

  • It lets an application send data on the third and fourth packet of the four-way handshake by using sendmsg or sctp_sendmsg to implicitly establish the connection.

  • There is no need to track transport state. In other words, the application just does a receive call on the socket descriptor and does not need to do any of the traditional connect or accept function calls before receiving messages.

However, there is one major drawback to this style. It makes it difficult to build a concurrent server (either using threads or by forking children). This drawback has brought about the addition of the sctp_peeloff function. sctp_peeloff takes a one-to-many socket descriptor and an association ID and returns a new socket descriptor with just that association (plus any queued notifications and data on that association) attached in a one-to-one style. The original socket remains open, and any other associations represented by the one-to-many socket are left unaffected.

This socket can then be handed off to either a thread or a child process to execute a concurrent server. Figure 23.15 illustrates a further modification to our server that processes the first message of a client, extracts the client socket descriptor using sctp_peeloff, forks a child, and calls our original TCP str_echo function introduced in Section 5.3. We use the address of the received message to call our function that gets us the association ID (Section 23.8). The association ID is also available in sri.sinfo_assoc_id; we show this method of determining the association ID from the IP address to illustrate another method. After forking the child, our server loops back to process the next message.

Figure 23.15 A concurrent SCTP server.

sctp/sctpserv_fork.c

23     for ( ; ; ) {
24         len = sizeof(struct sockaddr_in);
25         rd_sz = Sctp_recvmsg(sock_fd, readbuf, sizeof(readbuf),
26                              (SA *) &cliaddr, &len, &sri, &msg_flags);
27         Sctp_sendmsg(sock_fd, readbuf, rd_sz,
28                      (SA *) &cliaddr, len,
29                      sri.sinfo_ppid,
30                      sri.sinfo_flags, sri.sinfo_stream, 0, 0);
31         assoc = sctp_address_to_associd(sock_fd, (SA *) &cliaddr, len);
32         if ((int) assoc == 0) {
33             err_ret("Can't get association id");
34             continue;
35         }
36         connfd = sctp_peeloff(sock_fd, assoc);
37         if (connfd == -1) {
38             err_ret("sctp_peeloff fails");
39             continue;
40         }
41         if ( (childpid = fork()) == 0) {
42             Close(sock_fd);
43             str_echo(connfd);
44             exit(0);
45         } else {
46             Close(connfd);
47         }
48   }

Receive and process first message from client

26–30 The server receives and processes the first message a client sends.

Translate address to association ID

31–35 The server next uses our function from Figure 23.13 to translate the address to an association ID. If for some reason the server cannot get an association ID, it skips this attempt to fork a child and instead will try with the next message.

Extract association

36–40 The server extracts the association into its own socket descriptor with sctp_peeloff. This results in a one-to-one socket that can be passed to our earlier TCP version of str_echo.

Delegate work to child

41–47 The server forks a child and lets the child perform all future work on this new socket descriptor.

    [ Team LiB ] Previous Section Next Section