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
= nullptr;
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 QuicPacketCount
* 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 int rc
= setsockopt(fd
, IPPROTO_IP
, IP_PKTINFO
,
74 &get_local_ip
, sizeof(get_local_ip
));
75 if (rc
== 0 && address_family
== AF_INET6
) {
76 rc
= setsockopt(fd
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
,
77 &get_local_ip
, sizeof(get_local_ip
));
83 bool QuicSocketUtils::SetSendBufferSize(int fd
, size_t size
) {
84 if (setsockopt(fd
, SOL_SOCKET
, SO_SNDBUF
, &size
, sizeof(size
)) != 0) {
85 LOG(ERROR
) << "Failed to set socket send size";
92 bool QuicSocketUtils::SetReceiveBufferSize(int fd
, size_t size
) {
93 if (setsockopt(fd
, SOL_SOCKET
, SO_RCVBUF
, &size
, sizeof(size
)) != 0) {
94 LOG(ERROR
) << "Failed to set socket recv size";
101 int QuicSocketUtils::ReadPacket(int fd
, char* buffer
, size_t buf_len
,
102 QuicPacketCount
* dropped_packets
,
103 IPAddressNumber
* self_address
,
104 IPEndPoint
* peer_address
) {
105 DCHECK(peer_address
!= nullptr);
106 const int kSpaceForOverflowAndIp
=
107 CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(in6_pktinfo
));
108 char cbuf
[kSpaceForOverflowAndIp
];
109 memset(cbuf
, 0, arraysize(cbuf
));
111 iovec iov
= {buffer
, buf_len
};
112 struct sockaddr_storage raw_address
;
115 hdr
.msg_name
= &raw_address
;
116 hdr
.msg_namelen
= sizeof(sockaddr_storage
);
121 struct cmsghdr
* cmsg
= (struct cmsghdr
*)cbuf
;
122 cmsg
->cmsg_len
= arraysize(cbuf
);
123 hdr
.msg_control
= cmsg
;
124 hdr
.msg_controllen
= arraysize(cbuf
);
126 int bytes_read
= recvmsg(fd
, &hdr
, 0);
128 // Return before setting dropped packets: if we get EAGAIN, it will
130 if (bytes_read
< 0 && errno
!= 0) {
131 if (errno
!= EAGAIN
) {
132 LOG(ERROR
) << "Error reading " << strerror(errno
);
137 if (dropped_packets
!= nullptr) {
138 GetOverflowFromMsghdr(&hdr
, dropped_packets
);
140 if (self_address
!= nullptr) {
141 *self_address
= QuicSocketUtils::GetAddressFromMsghdr(&hdr
);
144 if (raw_address
.ss_family
== AF_INET
) {
145 CHECK(peer_address
->FromSockAddr(
146 reinterpret_cast<const sockaddr
*>(&raw_address
),
147 sizeof(struct sockaddr_in
)));
148 } else if (raw_address
.ss_family
== AF_INET6
) {
149 CHECK(peer_address
->FromSockAddr(
150 reinterpret_cast<const sockaddr
*>(&raw_address
),
151 sizeof(struct sockaddr_in6
)));
157 size_t QuicSocketUtils::SetIpInfoInCmsg(const IPAddressNumber
& self_address
,
159 if (GetAddressFamily(self_address
) == ADDRESS_FAMILY_IPV4
) {
160 cmsg
->cmsg_len
= CMSG_LEN(sizeof(in_pktinfo
));
161 cmsg
->cmsg_level
= IPPROTO_IP
;
162 cmsg
->cmsg_type
= IP_PKTINFO
;
163 in_pktinfo
* pktinfo
= reinterpret_cast<in_pktinfo
*>(CMSG_DATA(cmsg
));
164 memset(pktinfo
, 0, sizeof(in_pktinfo
));
165 pktinfo
->ipi_ifindex
= 0;
166 memcpy(&pktinfo
->ipi_spec_dst
, &self_address
[0], self_address
.size());
167 return sizeof(in_pktinfo
);
169 cmsg
->cmsg_len
= CMSG_LEN(sizeof(in6_pktinfo
));
170 cmsg
->cmsg_level
= IPPROTO_IPV6
;
171 cmsg
->cmsg_type
= IPV6_PKTINFO
;
172 in6_pktinfo
* pktinfo
= reinterpret_cast<in6_pktinfo
*>(CMSG_DATA(cmsg
));
173 memset(pktinfo
, 0, sizeof(in6_pktinfo
));
174 memcpy(&pktinfo
->ipi6_addr
, &self_address
[0], self_address
.size());
175 return sizeof(in6_pktinfo
);
180 WriteResult
QuicSocketUtils::WritePacket(int fd
,
183 const IPAddressNumber
& self_address
,
184 const IPEndPoint
& peer_address
) {
185 sockaddr_storage raw_address
;
186 socklen_t address_len
= sizeof(raw_address
);
187 CHECK(peer_address
.ToSockAddr(
188 reinterpret_cast<struct sockaddr
*>(&raw_address
),
190 iovec iov
= {const_cast<char*>(buffer
), buf_len
};
193 hdr
.msg_name
= &raw_address
;
194 hdr
.msg_namelen
= address_len
;
199 const int kSpaceForIpv4
= CMSG_SPACE(sizeof(in_pktinfo
));
200 const int kSpaceForIpv6
= CMSG_SPACE(sizeof(in6_pktinfo
));
201 // kSpaceForIp should be big enough to hold both IPv4 and IPv6 packet info.
202 const int kSpaceForIp
=
203 (kSpaceForIpv4
< kSpaceForIpv6
) ? kSpaceForIpv6
: kSpaceForIpv4
;
204 char cbuf
[kSpaceForIp
];
205 if (self_address
.empty()) {
207 hdr
.msg_controllen
= 0;
209 hdr
.msg_control
= cbuf
;
210 hdr
.msg_controllen
= kSpaceForIp
;
211 cmsghdr
* cmsg
= CMSG_FIRSTHDR(&hdr
);
212 SetIpInfoInCmsg(self_address
, cmsg
);
213 hdr
.msg_controllen
= cmsg
->cmsg_len
;
216 int rc
= sendmsg(fd
, &hdr
, 0);
218 return WriteResult(WRITE_STATUS_OK
, rc
);
220 return WriteResult((errno
== EAGAIN
|| errno
== EWOULDBLOCK
) ?
221 WRITE_STATUS_BLOCKED
: WRITE_STATUS_ERROR
, errno
);