Unix Network Programming Episode 91

Both functions package most arguments into a msghdr structure.

struct msghdr {
	void *msg_name; /* protocol address */
	socklen_t msg_namelen; /* size of protocol address */
	struct iovec *msg_iov; /* scatter/gather array */
	int msg_iovlen; /* # elements in msg_iov */
	void *msg_control; /* ancillary data (cmsghdr struct) */
	socklen_t msg_controllen; /* length of ancillary data */
	int msg_flags; /* flags returned by recvmsg() */
};

The msghdr structure that we show is the one specified in POSIX. Some systems still use an older msghdr structure that originated with 4.2BSD. This older structure does not have the msg_flags member, and the msg_control and msg_controllen members are named msg_accrights and msg_accrightslen. The newer form of the msghdr structure is often available using conditional compilation flags.

With recvmsg and sendmsg, we must distinguish between two flag variables: the flags argument, which is passed by value, and the msg_flags member of the msghdr structure, which is passed by reference (since the address of the structure is passed to the function).

  • The msg_flags member is used only by recvmsg. When recvmsg is called, the flags argument is copied into the msg_flags member (p. 502 of TCPv2) and this value is used by the kernel to drive its receive processing. This value is then updated based on the result of recvmsg.
  • The msg_flags member is ignored by sendmsg because this function uses the flags argument to drive its output processing. This means if we want to set the MSG_DONTWAIT flag in a call to sendmsg, we set the flags argument to this value; setting the msg_flags member to this value has no effect.

Figure 14.8 shows a msghdr structure and the various information it points to. We assume in this figure that the process is about to call recvmsg for a UDP socket.

We next assume that a 170-byte UDP datagram arrives from 192.6.38.100, port 2000, destined for our UDP socket with a destination IP address of 206.168.112.96. Figure 14.9 shows all the information in the msghdr structure when recvmsg returns.

The shaded fields are modified by recvmsg. The following items have changed from Figure 14.8 to Figure 14.9:

  • The buffer pointed to by msg_name has been filled in as an Internet socket address structure, containing the source IP address and source UDP port from the received datagram.
  • msg_namelen, a value-result argument, is updated with the amount of data stored in msg_name. Nothing changes since its value before the call was 16 and its value when recvmsg returns is also 16.
  • The first 100 bytes of data are stored in the first buffer; the next 60 bytes are stored in the second buffer; and the final 10 bytes are stored in the third buffer. The last 70 bytes of the final buffer are not modified. The return value of the recvmsg function is the size of the datagram, 170.
  • The buffer pointed to by msg_control is filled in as a cmsghdr structure. (We will say more about ancillary data in Section 14.6(See 9.3.6) and more about this particular socket option in Section 22.2(See 9.11.2).) The cmsg_len is 16; cmsg_level is IPPROTO_IP; cmsg_type is IP_RECVDSTADDR; and the next 4 bytes contain the destination IP address from the received UDP datagram. The final 4 bytes of the 20-byte buffer we supplied to hold the ancillary data are not modified.
  • The msg_controllen member is updated with the actual amount of ancillary data that was stored. It is also a value-result argument and its result on return is 16.
  • The msg_flags member is updated by recvmsg, but there are no flags to return to the process.
Ancillary Data

Ancillary data can be sent and received using the msg_control and msg_controllen members of the msghdr structure with the sendmsg and recvmsg functions. Another term for ancillary data is control information.

Ancillary data consists of one or more ancillary data objects, each one beginning with a cmsghdr structure, defined by including <sys/socket.h>.

struct cmsghdr {
	socklen_t cmsg_len; /* length in bytes, including this structure */
	int cmsg_level; /* originating protocol */
	int cmsg_type; /* protocol-specific type */
	/* followed by unsigned char cmsg_data[] */
};

Since the ancillary data returned by recvmsg can contain any number of ancillary data objects, and to hide the possible padding from the application, the following five macros are defined by including the <sys/socket.h> header to simplify the processing of the ancillary data:

#include <sys/socket.h>
#include <sys/param.h> /* for ALIGN macro on many implementations */

struct cmsghdr *CMSG_FIRSTHDR(struct msghdr *mhdrptr) ;
Returns: pointer to first cmsghdr structure or NULL if no ancillary data

struct cmsghdr *CMSG_NXTHDR(struct msghdr *mhdrptr, struct cmsghdr *cmsgptr) ;
Returns: pointer to next cmsghdr structure or NULL if no more ancillary data objects

unsigned char *CMSG_DATA(struct cmsghdr *cmsgptr) ;
Returns: pointer to first byte of data associated with cmsghdr structure

unsigned int CMSG_LEN(unsigned int length) ;
Returns: value to store in cmsg_len given the amount of data

unsigned int CMSG_SPACE(unsigned int length) ;
Returns: total size of an ancillary data object given the amount of data

These macros would be used in the following pseudocode:

struct msghdr msg;
struct cmsghdr *cmsgptr;
/* fill in msg structure */
/* call recvmsg() */
for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL;
	cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) {
		if (cmsgptr->cmsg_level == ... &&
		cmsgptr->cmsg_type == ... ) {
		u_char *ptr;
		ptr = CMSG_DATA(cmsgptr);
		/* process data pointed to by ptr */
	}
}
  • 8
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值