The affiliated information can include 0, 1, or more independent affiliated data objects. There is a struct before each object.
Cmsghdr structure. The header is followed by the padding byte and then the object itself. Finally, more bytes may be filled before the next cmsghdr after the affiliated data object. In this chapter, we will
The affiliated data objects to be concerned are file descriptors and certificate structure.
Shows how a buffer that contains ancillary data is organized.
Note the following:
The length of the cmsg_len and cmsg_len () macro values is the same.
The cmsg_space () macro can calculate the required blank space of an affiliated data object.
Msg_controllen is the length of cmsg_space () and is calculated for each affiliated data object.
The control information header is defined by the following C structure:
Struct cmsghdr {
Socklen_t cmsg_len;
Int cmsg_level;
Int cmsg_type;
/* U_char cmsg_data []; */
};
The members are described as follows:
Member description
The Byte Count of the cmsg_len ancillary data, which contains the size of the structure header. This value is calculated by the cmsg_len () Macro.
The cmsg_level value indicates the original protocol level (for example, sol_socket ).
The value cmsg_type indicates the type of the control information (for example, scm_rights ).
The cmsg_data member does not actually exist. It is used to specify the location of the actual additional ancillary data.
The example program used in this chapter only uses the cmsg_level value of sol_socket. In this chapter, we are interested in the following types of control information (cmsg_level = sol_socket ):
Cmsg_level description
The scm_rights data object is a file descriptor.
The scm_credentials data object is a structure containing certificate information.
Introduction cmsg (3) Macro
Due to the complexity of the ancillary data structure, Linux provides a series of C macros to simplify our work. In addition, these macros can be transplanted between different UNIX platforms and some measures have been taken to prevent future changes. These macros are described on the man manual page of cmsg (3). Their overview is as follows:
# Include
Struct cmsghdr * cmsg_firsthdr (struct msghdr * msgh );
Struct cmsghdr * cmsg_nxthdr (struct msghdr * msgh, struct cmsghdr * cmsg );
Size_t cmsg_align (size_t length );
Size_t cmsg_space (size_t length );
Size_t cmsg_len (size_t length );
Void * cmsg_data (struct cmsghdr * cmsg );
Cmsg_len () Macro
This macro accepts the object size we want to place in the attached data buffer as input parameters. If we review a previous introduction, we will find that this macro will calculate the length of the cmsghdr header structure plus the byte length of the required characters. This value is used to set the cmsg_len Member of the cmsghdr object.
The following example demonstrates how to calculate the value of the cmsg_len member if the ancillary data is a file descriptor:
Int FD;/* file descriptor */
Printf ("cmsg_len = % d/N", cmsg_len (sizeof FD ));
Cmsg_space () Macro
This macro is used to calculate the affiliated data and the total white space required by its header. Although the cmsg_len () macro calculates a similar length, the cmsg_len () value does not include possible trailing padding characters. The cmsg_space () macro is very useful for determining the required buffer size, as shown in the following sample code:
Int FD;/* file descriptor */
Char abuf [cmsg_space (sizeof FD)];
In this example, abuf [] declares sufficient buffer space to store the header, the padding byte, the ancillary data itself, and the final padding byte. If there are multiple ancillary data objects in the buffer, you must add multiple cmsg_space () macro calls at the same time to obtain the total space required.
Cmsg_data () Macro
This macro accepts a pointer to the cmsghdr structure. The returned pointer value points to the first byte (if any) of the affiliated data following the header and after the byte filling ). If the pointer mptr points to a header that describes the available ancillary data of the file descriptor, the file descriptor can be obtained using the following code:
Struct cmsgptr * mptr;
Int FD;/* file descriptor */
...
FD = * (int *) cmsg_data (mptr );
Cmsg_align () Macro
This is a Linux expansion macro, not part of the posix.1g standard. Specify a byte length as the input. This macro calculates a new length, which includes the additional Padding Bytes required to maintain alignment.
Cmsg_firsthdr () Macro
This
Returns a struct cmsghdr pointer to the First Affiliated object in the attached data buffer. The input value is to struct.
Msghdr structure pointer (not with struct
Cmsghdr ). This macro will estimate msg_control and msg_controllen members of msghdr to determine whether there are any attached objects in the buffer. However
Then, it calculates the returned pointer.
If no ancillary data object exists, the returned pointer value is null. Otherwise, the Pointer Points to the existing first struct cmsghdr. This macro is used at the beginning of a for loop to start traversing in the affiliated data object.
Cmsg_nxthdr () Macro
Returns the struct cmsghdr pointer of the next affiliated data object. This macro will accept two input parameters:
Pointer to the struct msghdr Structure
Pointer to the current struct cmsghdr
If no ancillary data object exists, the macro returns NULL.
Traverse affiliated data
When receiving an affiliated data, we can use the cmsg_firsthdr () and cmsg_nxthdr () macros to traverse the affiliated data objects. The following sample code shows the common format of the for loop and the corresponding usage of macros:
Struct msghdr msgh;/* message HDR */
Struct cmsghdr * cmsg; 0/* PTR to ancillary HDR */
Int * fd_ptr;/* PTR to file descript .*/
Int inclued_fd;/* the file descriptor */
For (cmsg = cmsg_firsthdr (& msgh); cmsg! = NULL; cmsg = cmsg_nxthdr (& msgh, cmsg )){
If (cmsg-> cmsg_level = sol_socket & cmsg-> cmsg_type = scm_rights ){
Fd_ptr = (int *) cmsg_data (cmsg );
Received_fd = * fd_ptr;
Break;
}
}
If (cmsg = NULL ){
/* Error: No file descriptor Recv 'd */
}
Create affiliated data
The process that sends a file descriptor must use the correct formatted data to create a secondary data buffer. The following code shows the general creation process:
Struct msghdr MSG;/* message header */
Struct cmsghdr * cmsg;/* PTR to ancillary HDR */
Int FD;/* file descriptor to send */
Char Buf [cmsg_space (sizeof FD)];/* ANC. Buf */
Int * fd_ptr;/* PTR to file descriptor */
MSG. msg_control = Buf;
MSG. msg_controllen = sizeof Buf;
Cmsg = cmsg_firsthdr (& MSG );
Cmsg-> cmsg_level = sol_socket;
Cmsg-> cmsg_type = scm_rights;
Cmsg-> cmsg_len = cmsg_len (sizeof FD );
/* Initialize the payload :*/
Fd_ptr = (int *) cmsg_data (cmsg );
* Fd_ptr = FD;
/*
* Sum of the length of all control
* Messages in the buffer:
*/
MSG. msg_controllen = cmsg-> cmsg_len;