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>
9 #include <sys/socket.h>
13 #include "base/basictypes.h"
14 #include "base/logging.h"
15 #include "net/base/net_util.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
= nullptr;
33 if (cmsg
->cmsg_type
== IPV6_PKTINFO
) {
34 in6_pktinfo
* info
= reinterpret_cast<in6_pktinfo
*>CMSG_DATA(cmsg
);
35 addr_data
= reinterpret_cast<const uint8
*>(&info
->ipi6_addr
);
36 len
= sizeof(in6_addr
);
37 } else if (cmsg
->cmsg_type
== IP_PKTINFO
) {
38 in_pktinfo
* info
= reinterpret_cast<in_pktinfo
*>CMSG_DATA(cmsg
);
39 addr_data
= reinterpret_cast<const uint8
*>(&info
->ipi_addr
);
40 len
= sizeof(in_addr
);
44 return IPAddressNumber(addr_data
, addr_data
+ len
);
47 DCHECK(false) << "Unable to get address from msghdr";
48 return IPAddressNumber();
52 bool QuicSocketUtils::GetOverflowFromMsghdr(struct msghdr
* hdr
,
53 QuicPacketCount
* dropped_packets
) {
54 if (hdr
->msg_controllen
> 0) {
56 for (cmsg
= CMSG_FIRSTHDR(hdr
);
58 cmsg
= CMSG_NXTHDR(hdr
, cmsg
)) {
59 if (cmsg
->cmsg_type
== SO_RXQ_OVFL
) {
60 *dropped_packets
= *(reinterpret_cast<int*>CMSG_DATA(cmsg
));
69 int QuicSocketUtils::SetGetAddressInfo(int fd
, int address_family
) {
71 int rc
= setsockopt(fd
, IPPROTO_IP
, IP_PKTINFO
,
72 &get_local_ip
, sizeof(get_local_ip
));
73 if (rc
== 0 && address_family
== AF_INET6
) {
74 rc
= setsockopt(fd
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
,
75 &get_local_ip
, sizeof(get_local_ip
));
81 bool QuicSocketUtils::SetSendBufferSize(int fd
, size_t size
) {
82 if (setsockopt(fd
, SOL_SOCKET
, SO_SNDBUF
, &size
, sizeof(size
)) != 0) {
83 LOG(ERROR
) << "Failed to set socket send size";
90 bool QuicSocketUtils::SetReceiveBufferSize(int fd
, size_t size
) {
91 if (setsockopt(fd
, SOL_SOCKET
, SO_RCVBUF
, &size
, sizeof(size
)) != 0) {
92 LOG(ERROR
) << "Failed to set socket recv size";
99 int QuicSocketUtils::ReadPacket(int fd
, char* buffer
, size_t buf_len
,
100 QuicPacketCount
* dropped_packets
,
101 IPAddressNumber
* self_address
,
102 IPEndPoint
* peer_address
) {
103 DCHECK(peer_address
!= nullptr);
104 const int kSpaceForOverflowAndIp
=
105 CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(in6_pktinfo
));
106 char cbuf
[kSpaceForOverflowAndIp
];
107 memset(cbuf
, 0, arraysize(cbuf
));
109 iovec iov
= {buffer
, buf_len
};
110 struct sockaddr_storage raw_address
;
113 hdr
.msg_name
= &raw_address
;
114 hdr
.msg_namelen
= sizeof(sockaddr_storage
);
119 struct cmsghdr
* cmsg
= (struct cmsghdr
*)cbuf
;
120 cmsg
->cmsg_len
= arraysize(cbuf
);
121 hdr
.msg_control
= cmsg
;
122 hdr
.msg_controllen
= arraysize(cbuf
);
124 int bytes_read
= recvmsg(fd
, &hdr
, 0);
126 // Return before setting dropped packets: if we get EAGAIN, it will
128 if (bytes_read
< 0 && errno
!= 0) {
129 if (errno
!= EAGAIN
) {
130 LOG(ERROR
) << "Error reading " << strerror(errno
);
135 if (dropped_packets
!= nullptr) {
136 GetOverflowFromMsghdr(&hdr
, dropped_packets
);
138 if (self_address
!= nullptr) {
139 *self_address
= QuicSocketUtils::GetAddressFromMsghdr(&hdr
);
142 if (raw_address
.ss_family
== AF_INET
) {
143 CHECK(peer_address
->FromSockAddr(
144 reinterpret_cast<const sockaddr
*>(&raw_address
),
145 sizeof(struct sockaddr_in
)));
146 } else if (raw_address
.ss_family
== AF_INET6
) {
147 CHECK(peer_address
->FromSockAddr(
148 reinterpret_cast<const sockaddr
*>(&raw_address
),
149 sizeof(struct sockaddr_in6
)));
155 size_t QuicSocketUtils::SetIpInfoInCmsg(const IPAddressNumber
& self_address
,
157 if (GetAddressFamily(self_address
) == ADDRESS_FAMILY_IPV4
) {
158 cmsg
->cmsg_len
= CMSG_LEN(sizeof(in_pktinfo
));
159 cmsg
->cmsg_level
= IPPROTO_IP
;
160 cmsg
->cmsg_type
= IP_PKTINFO
;
161 in_pktinfo
* pktinfo
= reinterpret_cast<in_pktinfo
*>(CMSG_DATA(cmsg
));
162 memset(pktinfo
, 0, sizeof(in_pktinfo
));
163 pktinfo
->ipi_ifindex
= 0;
164 memcpy(&pktinfo
->ipi_spec_dst
, &self_address
[0], self_address
.size());
165 return sizeof(in_pktinfo
);
167 cmsg
->cmsg_len
= CMSG_LEN(sizeof(in6_pktinfo
));
168 cmsg
->cmsg_level
= IPPROTO_IPV6
;
169 cmsg
->cmsg_type
= IPV6_PKTINFO
;
170 in6_pktinfo
* pktinfo
= reinterpret_cast<in6_pktinfo
*>(CMSG_DATA(cmsg
));
171 memset(pktinfo
, 0, sizeof(in6_pktinfo
));
172 memcpy(&pktinfo
->ipi6_addr
, &self_address
[0], self_address
.size());
173 return sizeof(in6_pktinfo
);
178 WriteResult
QuicSocketUtils::WritePacket(int fd
,
181 const IPAddressNumber
& self_address
,
182 const IPEndPoint
& peer_address
) {
183 sockaddr_storage raw_address
;
184 socklen_t address_len
= sizeof(raw_address
);
185 CHECK(peer_address
.ToSockAddr(
186 reinterpret_cast<struct sockaddr
*>(&raw_address
),
188 iovec iov
= {const_cast<char*>(buffer
), buf_len
};
191 hdr
.msg_name
= &raw_address
;
192 hdr
.msg_namelen
= address_len
;
197 const int kSpaceForIpv4
= CMSG_SPACE(sizeof(in_pktinfo
));
198 const int kSpaceForIpv6
= CMSG_SPACE(sizeof(in6_pktinfo
));
199 // kSpaceForIp should be big enough to hold both IPv4 and IPv6 packet info.
200 const int kSpaceForIp
=
201 (kSpaceForIpv4
< kSpaceForIpv6
) ? kSpaceForIpv6
: kSpaceForIpv4
;
202 char cbuf
[kSpaceForIp
];
203 if (self_address
.empty()) {
205 hdr
.msg_controllen
= 0;
207 hdr
.msg_control
= cbuf
;
208 hdr
.msg_controllen
= kSpaceForIp
;
209 cmsghdr
* cmsg
= CMSG_FIRSTHDR(&hdr
);
210 SetIpInfoInCmsg(self_address
, cmsg
);
211 hdr
.msg_controllen
= cmsg
->cmsg_len
;
214 int rc
= sendmsg(fd
, &hdr
, 0);
216 return WriteResult(WRITE_STATUS_OK
, rc
);
218 return WriteResult((errno
== EAGAIN
|| errno
== EWOULDBLOCK
) ?
219 WRITE_STATUS_BLOCKED
: WRITE_STATUS_ERROR
, errno
);