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/logging.h"
17 #define SO_RXQ_OVFL 40
24 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
= reinterpret_cast<const uint8
*>CMSG_DATA(cmsg
);
32 if (cmsg
->cmsg_type
== IPV6_PKTINFO
) {
33 len
= sizeof(in6_pktinfo
);
34 } else if (cmsg
->cmsg_type
== IP_PKTINFO
) {
35 len
= sizeof(in_pktinfo
);
37 ret
.assign(addr_data
, addr_data
+ len
);
45 bool QuicSocketUtils::GetOverflowFromMsghdr(struct msghdr
*hdr
,
46 int *dropped_packets
) {
47 if (hdr
->msg_controllen
> 0) {
49 for (cmsg
= CMSG_FIRSTHDR(hdr
);
51 cmsg
= CMSG_NXTHDR(hdr
, cmsg
)) {
52 if (cmsg
->cmsg_type
== SO_RXQ_OVFL
) {
53 *dropped_packets
= *(reinterpret_cast<int*>CMSG_DATA(cmsg
));
62 int QuicSocketUtils::SetGetAddressInfo(int fd
, int address_family
) {
64 if (address_family
== AF_INET
) {
65 return setsockopt(fd
, IPPROTO_IP
, IP_PKTINFO
,
66 &get_local_ip
, sizeof(get_local_ip
));
68 return setsockopt(fd
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
,
69 &get_local_ip
, sizeof(get_local_ip
));
74 int QuicSocketUtils::ReadPacket(int fd
, char* buffer
, size_t buf_len
,
76 IPAddressNumber
* self_address
,
77 IPEndPoint
* peer_address
) {
78 CHECK(peer_address
!= NULL
);
79 const int kSpaceForOverflowAndIp
=
80 CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(in6_pktinfo
));
81 char cbuf
[kSpaceForOverflowAndIp
];
82 memset(cbuf
, 0, arraysize(cbuf
));
84 iovec iov
= {buffer
, buf_len
};
85 struct sockaddr_storage raw_address
;
88 hdr
.msg_name
= &raw_address
;
89 hdr
.msg_namelen
= sizeof(sockaddr_storage
);
94 struct cmsghdr
*cmsg
= (struct cmsghdr
*) cbuf
;
95 cmsg
->cmsg_len
= arraysize(cbuf
);
96 hdr
.msg_control
= cmsg
;
97 hdr
.msg_controllen
= arraysize(cbuf
);
99 int bytes_read
= recvmsg(fd
, &hdr
, 0);
101 // Return before setting dropped packets: if we get EAGAIN, it will
103 if (bytes_read
< 0 && errno
!= 0) {
104 if (errno
!= EAGAIN
) {
105 LOG(ERROR
) << "Error reading " << strerror(errno
);
110 if (dropped_packets
!= NULL
) {
111 GetOverflowFromMsghdr(&hdr
, dropped_packets
);
113 if (self_address
!= NULL
) {
114 *self_address
= QuicSocketUtils::GetAddressFromMsghdr(&hdr
);
117 if (raw_address
.ss_family
== AF_INET
) {
118 CHECK(peer_address
->FromSockAddr(
119 reinterpret_cast<const sockaddr
*>(&raw_address
),
120 sizeof(struct sockaddr_in
)));
121 } else if (raw_address
.ss_family
== AF_INET6
) {
122 CHECK(peer_address
->FromSockAddr(
123 reinterpret_cast<const sockaddr
*>(&raw_address
),
124 sizeof(struct sockaddr_in6
)));
131 int QuicSocketUtils::WritePacket(int fd
, const char* buffer
, size_t buf_len
,
132 const IPAddressNumber
& self_address
,
133 const IPEndPoint
& peer_address
,
135 sockaddr_storage raw_address
;
136 socklen_t address_len
= sizeof(raw_address
);
137 CHECK(peer_address
.ToSockAddr(
138 reinterpret_cast<struct sockaddr
*>(&raw_address
),
140 iovec iov
= {const_cast<char*>(buffer
), buf_len
};
143 hdr
.msg_name
= &raw_address
;
144 hdr
.msg_namelen
= address_len
;
149 const int kSpaceForIpv4
= CMSG_SPACE(sizeof(in_pktinfo
));
150 const int kSpaceForIpv6
= CMSG_SPACE(sizeof(in6_pktinfo
));
151 // kSpaceForIp should be big enough to hold both IPv4 and IPv6 packet info.
152 const int kSpaceForIp
=
153 (kSpaceForIpv4
< kSpaceForIpv6
) ? kSpaceForIpv6
: kSpaceForIpv4
;
154 char cbuf
[kSpaceForIp
];
155 if (self_address
.empty()) {
157 hdr
.msg_controllen
= 0;
158 } else if (GetAddressFamily(self_address
) == ADDRESS_FAMILY_IPV4
) {
159 hdr
.msg_control
= cbuf
;
160 hdr
.msg_controllen
= kSpaceForIp
;
161 cmsghdr
* cmsg
= CMSG_FIRSTHDR(&hdr
);
163 cmsg
->cmsg_len
= CMSG_LEN(sizeof(in_pktinfo
));
164 cmsg
->cmsg_level
= IPPROTO_IP
;
165 cmsg
->cmsg_type
= IP_PKTINFO
;
166 in_pktinfo
* pktinfo
= reinterpret_cast<in_pktinfo
*>(CMSG_DATA(cmsg
));
167 memset(pktinfo
, 0, sizeof(in_pktinfo
));
168 pktinfo
->ipi_ifindex
= 0;
169 memcpy(&pktinfo
->ipi_spec_dst
, &self_address
[0], self_address
.size());
170 hdr
.msg_controllen
= cmsg
->cmsg_len
;
172 hdr
.msg_control
= cbuf
;
173 hdr
.msg_controllen
= kSpaceForIp
;
174 cmsghdr
* cmsg
= CMSG_FIRSTHDR(&hdr
);
176 cmsg
->cmsg_len
= CMSG_LEN(sizeof(in6_pktinfo
));
177 cmsg
->cmsg_level
= IPPROTO_IPV6
;
178 cmsg
->cmsg_type
= IPV6_PKTINFO
;
179 in6_pktinfo
* pktinfo
= reinterpret_cast<in6_pktinfo
*>(CMSG_DATA(cmsg
));
180 memset(pktinfo
, 0, sizeof(in6_pktinfo
));
181 memcpy(&pktinfo
->ipi6_addr
, &self_address
[0], self_address
.size());
182 hdr
.msg_controllen
= cmsg
->cmsg_len
;
185 int rc
= sendmsg(fd
, &hdr
, 0);
186 *error
= (rc
>= 0) ? 0 : errno
;