Stories
Slash Boxes
Comments

Dev.SN ♥ developers

Bewbs

Submission Preview

Apis Like This is Why C Has to Retire

Pending submission by janrinok at 2018-02-28 10:27:38
Software

Story automatically generated by StoryBot Version 0.3.0a (Development).
Storybot ('Arthur T Knackerbracket') is written in Python3

Note: This is the complete story and will need further editing. It may also be covered by Copyright and thus should be acknowledged and quoted rather than printed in its entirety.

FeedSource: [HackerNews] collected from rss-bot logs

Time: 2018-02-27 16:46:49 UTC

Original URL: http://alas.matf.bg.ac.rs/manuals/lspe/snode=153.html [bg.ac.rs] using ISO-8859-1 encoding.

Title: Apis Like This Is Why C Has To Retire

--- --- --- --- --- --- --- Entire Story Below --- --- --- --- --- --- ---

Apis Like This Is Why C Has To Retire

Arthur T Knackerbracket has found the following story [bg.ac.rs]:

The recvmsg(2) and sendmsg(2) functions permit the programmer to send and receive ancillary data. However, this supplementary information is subject to certain format rules. This section will introduce to you the control message header and the macros that the programmer should use to manage this information.

Ancillary information can include zero, one, or more separate ancillary data objects. Each of these objects is preceded by a struct cmsghdr. This header is followed possibly by pad bytes and then the object itself. Finally, the ancillary data object itself might be followed by still more pad bytes before the next cmsghdr follows. In this chapter, the only ancillary data objects that you'll be concerned about will be the file descriptor and a credentials structure.

Note the following additional points about Figure 17.1 [soylentnews.org]:

The value of cmsg_len is equivalent to the length shown as the macro value for CMSG_LEN() in Figure 17.1 [soylentnews.org].

The macro CMSG_SPACE() computes the total necessary space required for one ancillary data object.

The value of msg_controllen is the sum of the CMSG_SPACE() lengths, and is computed for each ancillary data object.

The control message header itself is defined as the following C structure:

The example programs used in this chapter will use only a cmsg_level value of SOL_SOCKET. The control message types that are of interest to you in this chapter are shown in Table 17.4 [soylentnews.org].

Due to the complexity of structuring the ancillary data, a number of C macros were provided to make this easier for you. Additionally, these macros enable much greater portability between different UNIX platforms and provide some insulation against changes that might occur in the future. These macros are described by the man page cmsg(3) and the syn-opsis for them are as follows:

Some of the macros presented in this chapter are not available on other UNIX platforms. For example, FreeBSD UNIX lacks the CMSG_ALIGN(), CMSG_SPACE(), and CMSG_LEN() macros. This should be borne in mind if you are writing code that must compile on other UNIX platforms in addition to Linux.

This macro accepts as an input parameter the size of the object that you want to place into the ancillary data buffer. If you review Figure 17.1 [soylentnews.org], you see that this macro computes the byte length of the cmsghdr header structure plus any pad characters that might be required, added to the length of the data object. This value is used to set the cmsg_len member of the cmsghdr object.

The following example shows how you would compute the value for the cmsg_len member, if the ancillary object is a file descriptor (this example just prints the value):

This macro is used to compute the total space required for the ancillary data object and its header. Although the CMSG_LEN() macro computes a similar length, the CMSG_LEN() value does not include possible trailing pad bytes (refer to Figure 17.1 [soylentnews.org]). The CMSG_SPACE() macro is useful for determining the buffer size requirements, as shown in the following example:

This example declares enough buffer space in abuf[] to hold the header, pad bytes, the ancillary data object itself, and any final pad bytes. If multiple ancillary data objects are being constructed in the buffer, be sure to add multiple CMSG_SPACE() macro calls together to arrive at the total space required.

This macro accepts a pointer to the cmsghdr structure. The pointer value returned points to the first byte of ancillary data that follows the header and pad bytes, if any. If the pointer mptr points to a valid ancillary data message header that describes a file descriptor, the file descriptor can be extracted with the following example code:

This is a Linux extension macro that is not part of the Posix.1g standard. Given a byte length as input, this macro computes a new length, which includes any additional pad bytes that are required to maintain alignment.

This macro is used to return a struct cmsghdr pointer to the first ancillary object within the ancillary data buffer. The input value is the pointer to the struct msghdr structure (do not confuse this with the struct cmsghdr). This macro evaluates the msghdr members msg_control and msg_controllen to determine whether any ancillary objects exist in the buffer. Then, it computes the pointer to be returned.

The pointer value returned is a NULL pointer if there is no ancillary data objects present. Otherwise, the pointer points to the first struct cmsghdr present. This macro is used at the start of a for loop, to start iterating through the ancillary data objects present.

This macro is used to return the struct cmsghdr pointer of the next ancillary data object. This macro accepts two input arguments:

The pointer to the struct msghdr structure

The pointer to the current struct csmghdr

This macro returns a NULL pointer if there is no next ancillary data object.

When ancillary data is received, the CMSG_FIRSTHDR() and CMSG_NEXTHDR() macros are used to iterate through the ancillary data objects. The following example code shows the general form that the for loop and macros should take:

The general procedure is as follows:

The for loop initializes by obtaining the first ancillary data header (struct cmsghdr) using the macro CMSG_FIRSTHDR().

The for loop tests whether the pointer cmsg is NULL. The body of the for loop is executed if this pointer is not NULL.

The if statement applies two tests to the struct cmsghdr header structure: The program is interested only in messages that are at the cmsg_level equal to SOL_SOCKET and is of the message type SCM_RIGHTS. This identifies an ancillary data object that represents a file descriptor.

If the test in step 3 succeeds, the pointer to the file descriptor is stored in pointer variable fd_ptr.

The pointer fd_ptr is then used to extract the file descriptor out of the ancillary data buffer into the variable received_fd.

The control leaves the for loop with the break statement, because the program has located the information it was interested in.

The if statement test that follows the for loop tests the cmsg pointer variable to see whether the ancillary data object was found. If the pointer cmsg is NULL, this indicates the for loop ran until completion without finding the file descriptor. When it is not NULL, this indicates that the break statement was executed, indicating that the file descriptor was indeed extracted.

This covers the general outline for extracting data from an ancillary data buffer.

The process that wants to send a file descriptor must create an ancillary data buffer with the correctly formatted data within it. The following code outlines the general procedure:

The general procedure used is as follows:

The ancillary data buffer was declared to make room to format an ancillary data object (array variable buf[]). Notice that the CMSG_SPACE() macro is used to compute the size of the buffer that is required.

The message header members msg_control and msg_controllen are initialized to point to the ancillary buffer and assign its maximum length, respectively.

The pointer cmsg is initialized to point at the first ancillary data object within the buffer using the CMSG_FIRSTHDR() macro. Note that the input argument to the macro is the pointer to the message header (&msg) and is not the pointer to the ancillary data buffer.

The ancillary data object's header is initialized by setting cmsg->cmsg_level and cmsg->cmsg_type.

The length of the ancillary data object is established by using the CMSG_LEN() macro with the size of the file descriptor as the input value.

The pointer to the file descriptor within the ancillary data buffer is determined by using the CMSG_DATA() macro.

The file descriptor fd is then copied into the ancillary data buffer using the pointer fd_ptr.

Finally, the total ancillary message length is computed and assigned to msg.msg_controllen.

If there is more than one ancillary data object included, you must be sure that msg.msg_controllen is the sum of all of the parts. Additionally, be certain to sum the total requirements needed for the buffer (buf[] in the example shown).


Original Submission