1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/tools/quic/quic_socket_utils.h"
8 #include <netinet/in.h>
10 #include <sys/socket.h>
14 #include "base/basictypes.h"
15 #include "base/logging.h"
16 #include "net/quic/quic_protocol.h"
19 #define SO_RXQ_OVFL 40
26 IPAddressNumber
QuicSocketUtils::GetAddressFromMsghdr(struct msghdr
*hdr
) {
27 if (hdr
->msg_controllen
> 0) {
28 for (cmsghdr
* cmsg
= CMSG_FIRSTHDR(hdr
);
30 cmsg
= CMSG_NXTHDR(hdr
, cmsg
)) {
31 const uint8
* addr_data
= NULL
;
33 if (cmsg
->cmsg_type
== IPV6_PKTINFO
) {
34 in6_pktinfo
* info
= reinterpret_cast<in6_pktinfo
*>CMSG_DATA(cmsg
);
35 in6_addr addr
= info
->ipi6_addr
;
36 addr_data
= reinterpret_cast<const uint8
*>(&addr
);
38 } else if (cmsg
->cmsg_type
== IP_PKTINFO
) {
39 in_pktinfo
* info
= reinterpret_cast<in_pktinfo
*>CMSG_DATA(cmsg
);
40 in_addr addr
= info
->ipi_addr
;
41 addr_data
= reinterpret_cast<const uint8
*>(&addr
);
46 return IPAddressNumber(addr_data
, addr_data
+ len
);
49 DCHECK(false) << "Unable to get address from msghdr";
50 return IPAddressNumber();
54 bool QuicSocketUtils::GetOverflowFromMsghdr(struct msghdr
*hdr
,
55 uint32
*dropped_packets
) {
56 if (hdr
->msg_controllen
> 0) {
58 for (cmsg
= CMSG_FIRSTHDR(hdr
);
60 cmsg
= CMSG_NXTHDR(hdr
, cmsg
)) {
61 if (cmsg
->cmsg_type
== SO_RXQ_OVFL
) {
62 *dropped_packets
= *(reinterpret_cast<int*>CMSG_DATA(cmsg
));
71 int QuicSocketUtils::SetGetAddressInfo(int fd
, int address_family
) {
73 if (address_family
== AF_INET
) {
74 return setsockopt(fd
, IPPROTO_IP
, IP_PKTINFO
,
75 &get_local_ip
, sizeof(get_local_ip
));
77 return setsockopt(fd
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
,
78 &get_local_ip
, sizeof(get_local_ip
));
83 int QuicSocketUtils::ReadPacket(int fd
, char* buffer
, size_t buf_len
,
84 uint32
* dropped_packets
,
85 IPAddressNumber
* self_address
,
86 IPEndPoint
* peer_address
) {
87 CHECK(peer_address
!= NULL
);
88 const int kSpaceForOverflowAndIp
=
89 CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(in6_pktinfo
));
90 char cbuf
[kSpaceForOverflowAndIp
];
91 memset(cbuf
, 0, arraysize(cbuf
));
93 iovec iov
= {buffer
, buf_len
};
94 struct sockaddr_storage raw_address
;
97 hdr
.msg_name
= &raw_address
;
98 hdr
.msg_namelen
= sizeof(sockaddr_storage
);
103 struct cmsghdr
*cmsg
= (struct cmsghdr
*) cbuf
;
104 cmsg
->cmsg_len
= arraysize(cbuf
);
105 hdr
.msg_control
= cmsg
;
106 hdr
.msg_controllen
= arraysize(cbuf
);
108 int bytes_read
= recvmsg(fd
, &hdr
, 0);
110 // Return before setting dropped packets: if we get EAGAIN, it will
112 if (bytes_read
< 0 && errno
!= 0) {
113 if (errno
!= EAGAIN
) {
114 LOG(ERROR
) << "Error reading " << strerror(errno
);
119 if (dropped_packets
!= NULL
) {
120 GetOverflowFromMsghdr(&hdr
, dropped_packets
);
122 if (self_address
!= NULL
) {
123 *self_address
= QuicSocketUtils::GetAddressFromMsghdr(&hdr
);
126 if (raw_address
.ss_family
== AF_INET
) {
127 CHECK(peer_address
->FromSockAddr(
128 reinterpret_cast<const sockaddr
*>(&raw_address
),
129 sizeof(struct sockaddr_in
)));
130 } else if (raw_address
.ss_family
== AF_INET6
) {
131 CHECK(peer_address
->FromSockAddr(
132 reinterpret_cast<const sockaddr
*>(&raw_address
),
133 sizeof(struct sockaddr_in6
)));
140 WriteResult
QuicSocketUtils::WritePacket(int fd
,
143 const IPAddressNumber
& self_address
,
144 const IPEndPoint
& peer_address
) {
145 sockaddr_storage raw_address
;
146 socklen_t address_len
= sizeof(raw_address
);
147 CHECK(peer_address
.ToSockAddr(
148 reinterpret_cast<struct sockaddr
*>(&raw_address
),
150 iovec iov
= {const_cast<char*>(buffer
), buf_len
};
153 hdr
.msg_name
= &raw_address
;
154 hdr
.msg_namelen
= address_len
;
159 const int kSpaceForIpv4
= CMSG_SPACE(sizeof(in_pktinfo
));
160 const int kSpaceForIpv6
= CMSG_SPACE(sizeof(in6_pktinfo
));
161 // kSpaceForIp should be big enough to hold both IPv4 and IPv6 packet info.
162 const int kSpaceForIp
=
163 (kSpaceForIpv4
< kSpaceForIpv6
) ? kSpaceForIpv6
: kSpaceForIpv4
;
164 char cbuf
[kSpaceForIp
];
165 if (self_address
.empty()) {
167 hdr
.msg_controllen
= 0;
168 } else if (GetAddressFamily(self_address
) == ADDRESS_FAMILY_IPV4
) {
169 hdr
.msg_control
= cbuf
;
170 hdr
.msg_controllen
= kSpaceForIp
;
171 cmsghdr
* cmsg
= CMSG_FIRSTHDR(&hdr
);
173 cmsg
->cmsg_len
= CMSG_LEN(sizeof(in_pktinfo
));
174 cmsg
->cmsg_level
= IPPROTO_IP
;
175 cmsg
->cmsg_type
= IP_PKTINFO
;
176 in_pktinfo
* pktinfo
= reinterpret_cast<in_pktinfo
*>(CMSG_DATA(cmsg
));
177 memset(pktinfo
, 0, sizeof(in_pktinfo
));
178 pktinfo
->ipi_ifindex
= 0;
179 memcpy(&pktinfo
->ipi_spec_dst
, &self_address
[0], self_address
.size());
180 hdr
.msg_controllen
= cmsg
->cmsg_len
;
182 hdr
.msg_control
= cbuf
;
183 hdr
.msg_controllen
= kSpaceForIp
;
184 cmsghdr
* cmsg
= CMSG_FIRSTHDR(&hdr
);
186 cmsg
->cmsg_len
= CMSG_LEN(sizeof(in6_pktinfo
));
187 cmsg
->cmsg_level
= IPPROTO_IPV6
;
188 cmsg
->cmsg_type
= IPV6_PKTINFO
;
189 in6_pktinfo
* pktinfo
= reinterpret_cast<in6_pktinfo
*>(CMSG_DATA(cmsg
));
190 memset(pktinfo
, 0, sizeof(in6_pktinfo
));
191 memcpy(&pktinfo
->ipi6_addr
, &self_address
[0], self_address
.size());
192 hdr
.msg_controllen
= cmsg
->cmsg_len
;
195 int rc
= sendmsg(fd
, &hdr
, 0);
197 return WriteResult(WRITE_STATUS_OK
, rc
);
199 return WriteResult((errno
== EAGAIN
|| errno
== EWOULDBLOCK
) ?
200 WRITE_STATUS_BLOCKED
: WRITE_STATUS_ERROR
, errno
);