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/quic/quic_protocol.h"
18 #define SO_RXQ_OVFL 40
25 IPAddressNumber
QuicSocketUtils::GetAddressFromMsghdr(struct msghdr
* hdr
) {
26 if (hdr
->msg_controllen
> 0) {
27 for (cmsghdr
* cmsg
= CMSG_FIRSTHDR(hdr
);
29 cmsg
= CMSG_NXTHDR(hdr
, cmsg
)) {
30 const uint8
* addr_data
= nullptr;
32 if (cmsg
->cmsg_type
== IPV6_PKTINFO
) {
33 in6_pktinfo
* info
= reinterpret_cast<in6_pktinfo
*>CMSG_DATA(cmsg
);
34 addr_data
= reinterpret_cast<const uint8
*>(&info
->ipi6_addr
);
35 len
= sizeof(in6_addr
);
36 } else if (cmsg
->cmsg_type
== IP_PKTINFO
) {
37 in_pktinfo
* info
= reinterpret_cast<in_pktinfo
*>CMSG_DATA(cmsg
);
38 addr_data
= reinterpret_cast<const uint8
*>(&info
->ipi_addr
);
39 len
= sizeof(in_addr
);
43 return IPAddressNumber(addr_data
, addr_data
+ len
);
46 DCHECK(false) << "Unable to get address from msghdr";
47 return IPAddressNumber();
51 bool QuicSocketUtils::GetOverflowFromMsghdr(struct msghdr
* hdr
,
52 QuicPacketCount
* dropped_packets
) {
53 if (hdr
->msg_controllen
> 0) {
55 for (cmsg
= CMSG_FIRSTHDR(hdr
);
57 cmsg
= CMSG_NXTHDR(hdr
, cmsg
)) {
58 if (cmsg
->cmsg_type
== SO_RXQ_OVFL
) {
59 *dropped_packets
= *(reinterpret_cast<int*>CMSG_DATA(cmsg
));
68 int QuicSocketUtils::SetGetAddressInfo(int fd
, int address_family
) {
70 int rc
= setsockopt(fd
, IPPROTO_IP
, IP_PKTINFO
,
71 &get_local_ip
, sizeof(get_local_ip
));
72 if (rc
== 0 && address_family
== AF_INET6
) {
73 rc
= setsockopt(fd
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
,
74 &get_local_ip
, sizeof(get_local_ip
));
80 bool QuicSocketUtils::SetSendBufferSize(int fd
, size_t size
) {
81 if (setsockopt(fd
, SOL_SOCKET
, SO_SNDBUF
, &size
, sizeof(size
)) != 0) {
82 LOG(ERROR
) << "Failed to set socket send size";
89 bool QuicSocketUtils::SetReceiveBufferSize(int fd
, size_t size
) {
90 if (setsockopt(fd
, SOL_SOCKET
, SO_RCVBUF
, &size
, sizeof(size
)) != 0) {
91 LOG(ERROR
) << "Failed to set socket recv size";
98 int QuicSocketUtils::ReadPacket(int fd
, char* buffer
, size_t buf_len
,
99 QuicPacketCount
* dropped_packets
,
100 IPAddressNumber
* self_address
,
101 IPEndPoint
* peer_address
) {
102 DCHECK(peer_address
!= nullptr);
103 const int kSpaceForOverflowAndIp
=
104 CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(in6_pktinfo
));
105 char cbuf
[kSpaceForOverflowAndIp
];
106 memset(cbuf
, 0, arraysize(cbuf
));
108 iovec iov
= {buffer
, buf_len
};
109 struct sockaddr_storage raw_address
;
112 hdr
.msg_name
= &raw_address
;
113 hdr
.msg_namelen
= sizeof(sockaddr_storage
);
118 struct cmsghdr
* cmsg
= (struct cmsghdr
*)cbuf
;
119 cmsg
->cmsg_len
= arraysize(cbuf
);
120 hdr
.msg_control
= cmsg
;
121 hdr
.msg_controllen
= arraysize(cbuf
);
123 int bytes_read
= recvmsg(fd
, &hdr
, 0);
125 // Return before setting dropped packets: if we get EAGAIN, it will
127 if (bytes_read
< 0 && errno
!= 0) {
128 if (errno
!= EAGAIN
) {
129 LOG(ERROR
) << "Error reading " << strerror(errno
);
134 if (dropped_packets
!= nullptr) {
135 GetOverflowFromMsghdr(&hdr
, dropped_packets
);
137 if (self_address
!= nullptr) {
138 *self_address
= QuicSocketUtils::GetAddressFromMsghdr(&hdr
);
141 if (raw_address
.ss_family
== AF_INET
) {
142 CHECK(peer_address
->FromSockAddr(
143 reinterpret_cast<const sockaddr
*>(&raw_address
),
144 sizeof(struct sockaddr_in
)));
145 } else if (raw_address
.ss_family
== AF_INET6
) {
146 CHECK(peer_address
->FromSockAddr(
147 reinterpret_cast<const sockaddr
*>(&raw_address
),
148 sizeof(struct sockaddr_in6
)));
154 size_t QuicSocketUtils::SetIpInfoInCmsg(const IPAddressNumber
& self_address
,
156 if (GetAddressFamily(self_address
) == ADDRESS_FAMILY_IPV4
) {
157 cmsg
->cmsg_len
= CMSG_LEN(sizeof(in_pktinfo
));
158 cmsg
->cmsg_level
= IPPROTO_IP
;
159 cmsg
->cmsg_type
= IP_PKTINFO
;
160 in_pktinfo
* pktinfo
= reinterpret_cast<in_pktinfo
*>(CMSG_DATA(cmsg
));
161 memset(pktinfo
, 0, sizeof(in_pktinfo
));
162 pktinfo
->ipi_ifindex
= 0;
163 memcpy(&pktinfo
->ipi_spec_dst
, &self_address
[0], self_address
.size());
164 return sizeof(in_pktinfo
);
166 cmsg
->cmsg_len
= CMSG_LEN(sizeof(in6_pktinfo
));
167 cmsg
->cmsg_level
= IPPROTO_IPV6
;
168 cmsg
->cmsg_type
= IPV6_PKTINFO
;
169 in6_pktinfo
* pktinfo
= reinterpret_cast<in6_pktinfo
*>(CMSG_DATA(cmsg
));
170 memset(pktinfo
, 0, sizeof(in6_pktinfo
));
171 memcpy(&pktinfo
->ipi6_addr
, &self_address
[0], self_address
.size());
172 return sizeof(in6_pktinfo
);
177 WriteResult
QuicSocketUtils::WritePacket(int fd
,
180 const IPAddressNumber
& self_address
,
181 const IPEndPoint
& peer_address
) {
182 sockaddr_storage raw_address
;
183 socklen_t address_len
= sizeof(raw_address
);
184 CHECK(peer_address
.ToSockAddr(
185 reinterpret_cast<struct sockaddr
*>(&raw_address
),
187 iovec iov
= {const_cast<char*>(buffer
), buf_len
};
190 hdr
.msg_name
= &raw_address
;
191 hdr
.msg_namelen
= address_len
;
196 const int kSpaceForIpv4
= CMSG_SPACE(sizeof(in_pktinfo
));
197 const int kSpaceForIpv6
= CMSG_SPACE(sizeof(in6_pktinfo
));
198 // kSpaceForIp should be big enough to hold both IPv4 and IPv6 packet info.
199 const int kSpaceForIp
=
200 (kSpaceForIpv4
< kSpaceForIpv6
) ? kSpaceForIpv6
: kSpaceForIpv4
;
201 char cbuf
[kSpaceForIp
];
202 if (self_address
.empty()) {
204 hdr
.msg_controllen
= 0;
206 hdr
.msg_control
= cbuf
;
207 hdr
.msg_controllen
= kSpaceForIp
;
208 cmsghdr
* cmsg
= CMSG_FIRSTHDR(&hdr
);
209 SetIpInfoInCmsg(self_address
, cmsg
);
210 hdr
.msg_controllen
= cmsg
->cmsg_len
;
213 int rc
= sendmsg(fd
, &hdr
, 0);
215 return WriteResult(WRITE_STATUS_OK
, rc
);
217 return WriteResult((errno
== EAGAIN
|| errno
== EWOULDBLOCK
) ?
218 WRITE_STATUS_BLOCKED
: WRITE_STATUS_ERROR
, errno
);