1 /*
2 * Copyright (C) 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <platform/api/udp_socket.h>
18
19 #include <sstream>
20 #include <string>
21
22 #include <android-base/logging.h>
23 #include <discovery/mdns/public/mdns_constants.h>
24
25 #include "adb_unique_fd.h"
26 #include "adb_utils.h"
27 #include "fdevent/fdevent.h"
28 #include "sysdeps.h"
29
30 //#define DEBUG_UDP
31
IsPowerOf2(uint32_t x)32 constexpr bool IsPowerOf2(uint32_t x) {
33 return (x > 0) && ((x & (x - 1)) == 0);
34 }
35
36 static_assert(IsPowerOf2(alignof(adb_cmsghdr)), "std::align requires power-of-2 alignment");
37
38 // For windows, winuser.h defines a SendMessage macro that causes compilation issues.
39 #ifdef _WIN32
40 #ifdef SendMessage
41 #undef SendMessage
42 #endif
43 #endif
44 namespace openscreen {
45
46 namespace {
47
48 #ifdef _WIN32
49 using IPv4NetworkInterfaceIndex = decltype(ip_mreq().imr_interface.s_addr);
50 #else
51 using IPv4NetworkInterfaceIndex = decltype(ip_mreqn().imr_ifindex);
52 #endif
53 using IPv6NetworkInterfaceIndex = decltype(ipv6_mreq().ipv6mr_interface);
54
55 // Examine |posix_errno| to determine whether the specific cause of a failure
56 // was transient or hard, and return the appropriate error response.
ChooseError(decltype(errno) posix_errno,Error::Code hard_error_code)57 Error ChooseError(decltype(errno) posix_errno, Error::Code hard_error_code) {
58 if (posix_errno == EAGAIN || posix_errno == EWOULDBLOCK || posix_errno == ENOBUFS) {
59 return Error(Error::Code::kAgain, strerror(errno));
60 }
61 return Error(hard_error_code, strerror(errno));
62 }
63
GetIPAddressFromSockAddr(const sockaddr_in & sa)64 IPAddress GetIPAddressFromSockAddr(const sockaddr_in& sa) {
65 static_assert(IPAddress::kV4Size == sizeof(sa.sin_addr.s_addr), "IPv4 address size mismatch.");
66 return IPAddress(IPAddress::Version::kV4,
67 reinterpret_cast<const uint8_t*>(&sa.sin_addr.s_addr));
68 }
69
GetIPAddressFromPktInfo(const in_pktinfo & pktinfo)70 IPAddress GetIPAddressFromPktInfo(const in_pktinfo& pktinfo) {
71 static_assert(IPAddress::kV4Size == sizeof(pktinfo.ipi_addr), "IPv4 address size mismatch.");
72 return IPAddress(IPAddress::Version::kV4, reinterpret_cast<const uint8_t*>(&pktinfo.ipi_addr));
73 }
74
GetPortFromFromSockAddr(const sockaddr_in & sa)75 uint16_t GetPortFromFromSockAddr(const sockaddr_in& sa) {
76 return ntohs(sa.sin_port);
77 }
78
GetIPAddressFromSockAddr(const sockaddr_in6 & sa)79 IPAddress GetIPAddressFromSockAddr(const sockaddr_in6& sa) {
80 return IPAddress(IPAddress::Version::kV6, sa.sin6_addr.s6_addr);
81 }
82
GetIPAddressFromPktInfo(const in6_pktinfo & pktinfo)83 IPAddress GetIPAddressFromPktInfo(const in6_pktinfo& pktinfo) {
84 return IPAddress(IPAddress::Version::kV6, pktinfo.ipi6_addr.s6_addr);
85 }
86
GetPortFromFromSockAddr(const sockaddr_in6 & sa)87 uint16_t GetPortFromFromSockAddr(const sockaddr_in6& sa) {
88 return ntohs(sa.sin6_port);
89 }
90
91 template <class PktInfoType>
92 bool IsPacketInfo(adb_cmsghdr* cmh);
93
94 template <>
IsPacketInfo(adb_cmsghdr * cmh)95 bool IsPacketInfo<in_pktinfo>(adb_cmsghdr* cmh) {
96 return cmh->cmsg_level == IPPROTO_IP && cmh->cmsg_type == IP_PKTINFO;
97 }
98
99 template <>
IsPacketInfo(adb_cmsghdr * cmh)100 bool IsPacketInfo<in6_pktinfo>(adb_cmsghdr* cmh) {
101 return cmh->cmsg_level == IPPROTO_IPV6 && cmh->cmsg_type == IPV6_PKTINFO;
102 }
103
104 template <class SockAddrType, class PktInfoType>
ReceiveMessageInternal(borrowed_fd fd,UdpPacket * packet)105 Error ReceiveMessageInternal(borrowed_fd fd, UdpPacket* packet) {
106 SockAddrType sa;
107 adb_iovec iov;
108 iov.iov_len = packet->size();
109 iov.iov_base = packet->data();
110 alignas(alignof(adb_cmsghdr)) uint8_t control_buffer[1024];
111 adb_msghdr msg;
112 msg.msg_name = &sa;
113 msg.msg_namelen = sizeof(sa);
114 msg.msg_iov = &iov;
115 msg.msg_iovlen = 1;
116 msg.msg_control = control_buffer;
117 msg.msg_controllen = sizeof(control_buffer);
118 msg.msg_flags = 0;
119
120 ssize_t bytes_received = adb_recvmsg(fd, &msg, 0);
121 if (bytes_received == -1) {
122 return ChooseError(errno, Error::Code::kSocketReadFailure);
123 }
124
125 CHECK_EQ(static_cast<size_t>(bytes_received), packet->size());
126
127 IPEndpoint source_endpoint = {.address = GetIPAddressFromSockAddr(sa),
128 .port = GetPortFromFromSockAddr(sa)};
129 packet->set_source(std::move(source_endpoint));
130
131 // For multicast sockets, the packet's original destination address may be
132 // the host address (since we called bind()) but it may also be a
133 // multicast address. This may be relevant for handling multicast data;
134 // specifically, mDNSResponder requires this information to work properly.
135
136 socklen_t sa_len = sizeof(sa);
137 if (((msg.msg_flags & MSG_CTRUNC) != 0) ||
138 (adb_getsockname(fd, reinterpret_cast<sockaddr*>(&sa), &sa_len) == -1)) {
139 return Error::Code::kNone;
140 }
141 for (adb_cmsghdr* cmh = adb_CMSG_FIRSTHDR(&msg); cmh; cmh = adb_CMSG_NXTHDR(&msg, cmh)) {
142 if (IsPacketInfo<PktInfoType>(cmh)) {
143 PktInfoType* pktinfo = reinterpret_cast<PktInfoType*>(adb_CMSG_DATA(cmh));
144 IPEndpoint destination_endpoint = {.address = GetIPAddressFromPktInfo(*pktinfo),
145 .port = GetPortFromFromSockAddr(sa)};
146 packet->set_destination(destination_endpoint);
147 break;
148 }
149 }
150 return Error::Code::kNone;
151 }
152 // An open UDP socket for sending/receiving datagrams to/from either specific
153 // endpoints or over IP multicast.
154 //
155 // Usage: The socket is created and opened by calling the Create() method. This
156 // returns a unique pointer that auto-closes/destroys the socket when it goes
157 // out-of-scope.
158 class AdbUdpSocket : public UdpSocket {
159 public:
AdbUdpSocket(UdpSocket::Client * client,const IPEndpoint & local_endpoint,unique_fd fd)160 explicit AdbUdpSocket(UdpSocket::Client* client, const IPEndpoint& local_endpoint, unique_fd fd)
161 : client_(client), local_endpoint_(local_endpoint), fd_(std::move(fd)) {
162 CHECK(client_);
163 CHECK(local_endpoint_.address.IsV4() || local_endpoint_.address.IsV6());
164 fde_ = fdevent_create(fd_.get(), OnFdeventResult, this);
165 if (!fde_) {
166 LOG(FATAL) << "Unable to create fdevent";
167 return;
168 }
169 fdevent_set(fde_, FDE_READ);
170 LOG(INFO) << __func__ << " fd=" << fd_.get();
171 }
172
~AdbUdpSocket()173 ~AdbUdpSocket() override {
174 if (fde_) {
175 fdevent_destroy(fde_);
176 }
177 }
178
179 // Returns true if |socket| belongs to the IPv4/IPv6 address family.
IsIPv4() const180 bool IsIPv4() const override { return local_endpoint_.address.IsV4(); }
IsIPv6() const181 bool IsIPv6() const override { return local_endpoint_.address.IsV6(); }
182
183 // Returns the current local endpoint's address and port. Initially, this will
184 // be the same as the value that was passed into Create(). However, it can
185 // later change after certain operations, such as Bind(), are executed.
GetLocalEndpoint() const186 IPEndpoint GetLocalEndpoint() const override {
187 if (local_endpoint_.port == 0) {
188 // Note: If the getsockname() call fails, just assume that's because the
189 // socket isn't bound yet. In this case, leave the original value in-place.
190 switch (local_endpoint_.address.version()) {
191 case UdpSocket::Version::kV4: {
192 struct sockaddr_in address;
193 socklen_t address_len = sizeof(address);
194 if (adb_getsockname(fd_, reinterpret_cast<struct sockaddr*>(&address),
195 &address_len) == 0) {
196 CHECK_EQ(address.sin_family, AF_INET);
197 local_endpoint_.address =
198 IPAddress(IPAddress::Version::kV4,
199 reinterpret_cast<uint8_t*>(&address.sin_addr.s_addr));
200 local_endpoint_.port = ntohs(address.sin_port);
201 }
202 break;
203 }
204
205 case UdpSocket::Version::kV6: {
206 struct sockaddr_in6 address;
207 socklen_t address_len = sizeof(address);
208 if (adb_getsockname(fd_, reinterpret_cast<struct sockaddr*>(&address),
209 &address_len) == 0) {
210 CHECK_EQ(address.sin6_family, AF_INET6);
211 local_endpoint_.address =
212 IPAddress(IPAddress::Version::kV6,
213 reinterpret_cast<uint8_t*>(&address.sin6_addr));
214 local_endpoint_.port = ntohs(address.sin6_port);
215 }
216 break;
217 }
218 }
219 }
220
221 return local_endpoint_;
222 }
223
224 // Binds to the address specified in the constructor. If the local endpoint's
225 // address is zero, the operating system will bind to all interfaces. If the
226 // local endpoint's port is zero, the operating system will automatically find
227 // a free local port and bind to it. Future calls to GetLocalEndpoint() will
228 // reflect the resolved port.
229 //
230 // TODO: openscreen does some chromium compat thing where it calls Bind() before
231 // SetMulticastOutboundInterface(), because chromium alreadys sets IP_MULTICAST_IF internally
232 // before calling Bind(). So we currently wait for the SetMulticastOutboundInterface() call from
233 // the osp-discovery code before actually binding. Note that this means AdbUdpSocket is not for
234 // the general use-case of udp sockets.
Bind()235 void Bind() override {
236 if (mdns_ifindex_) {
237 // TODO: move MdnsBind() code back into here once osp-discovery calls Bind() after
238 // SetMulticastOutboundInterface().
239 LOG(FATAL) << "osp-discovery called Bind() after SetMulticastOutboundInterface()!";
240 } else {
241 // mdns impl will only call SetMulticastOutboundInterface and JoinMulticastGroup after
242 // bind is successful.
243 client_->OnBound(this);
244 }
245 }
246
SetIPV4MulticastProperties(std::optional<IPAddress> local_ipv4,std::optional<IPAddress> multiaddr_ipv4,ip_mreq * result)247 static void SetIPV4MulticastProperties(std::optional<IPAddress> local_ipv4,
248 std::optional<IPAddress> multiaddr_ipv4,
249 ip_mreq* result) {
250 CHECK(result);
251 static_assert(sizeof(result->imr_multiaddr) == 4u, "IPv4 address requires exactly 4 bytes");
252 static_assert(sizeof(result->imr_interface) == 4u, "IPv4 address requires exactly 4 bytes");
253
254 *result = {};
255 if (local_ipv4) {
256 local_ipv4->CopyToV4(reinterpret_cast<uint8_t*>(&result->imr_interface.s_addr));
257 }
258
259 if (multiaddr_ipv4) {
260 multiaddr_ipv4->CopyToV4(reinterpret_cast<uint8_t*>(&result->imr_multiaddr));
261 }
262 }
263
264 // Sets the device to use for outgoing multicast packets on the socket.
SetMulticastOutboundInterface(NetworkInterfaceIndex ifindex)265 void SetMulticastOutboundInterface(NetworkInterfaceIndex ifindex) override {
266 if (!fd_.ok()) {
267 OnError(Error::Code::kSocketClosedFailure);
268 return;
269 }
270
271 // TODO: remove once osp-discovery calls Bind() after SetMulticastOutboundInterface().
272 *mdns_ifindex_ = ifindex;
273
274 LOG(INFO) << "SetMulticastOutboundInterface for index=" << ifindex;
275 switch (local_endpoint_.address.version()) {
276 case UdpSocket::Version::kV4: {
277 struct ip_mreq multicast_properties = {};
278 SetIPV4MulticastProperties(local_endpoint_.address, std::nullopt,
279 &multicast_properties);
280 #ifdef DEBUG_UDP
281 struct in_addr default_addr;
282 unsigned int buf_size = sizeof(default_addr);
283 if (getsockopt(fd_.get(), IPPROTO_IP, IP_MULTICAST_IF, &default_addr, &buf_size) !=
284 -1) {
285 const auto default_ip =
286 IPAddress(IPAddress::Version::kV4,
287 reinterpret_cast<const uint8_t*>(&default_addr.s_addr));
288 LOG(INFO) << "BEFORE IP_MULTICAST_IF: default multicast addr=" << default_ip;
289 }
290 #endif // DEBUG_UDP
291 if (adb_setsockopt(fd_, IPPROTO_IP, IP_MULTICAST_IF, &multicast_properties,
292 sizeof(multicast_properties)) == -1) {
293 OnError(Error::Code::kSocketOptionSettingFailure);
294 PLOG(ERROR) << "adb_setsockopt() failed";
295 return;
296 }
297 #ifdef DEBUG_UDP
298 #ifndef _WIN32
299 buf_size = sizeof(default_addr);
300 if (getsockopt(fd_.get(), IPPROTO_IP, IP_MULTICAST_IF, &default_addr, &buf_size) !=
301 -1) {
302 const auto default_ip =
303 IPAddress(IPAddress::Version::kV4,
304 reinterpret_cast<const uint8_t*>(&default_addr.s_addr));
305 LOG(INFO) << "AFTER IP_MULTICAST_IF: default multicast addr=" << default_ip;
306 }
307 #endif // !_WIN32
308 #endif // DEBUG_UDP
309 break;
310 }
311 case UdpSocket::Version::kV6: {
312 const auto index = static_cast<IPv6NetworkInterfaceIndex>(ifindex);
313 if (adb_setsockopt(fd_, IPPROTO_IPV6, IPV6_MULTICAST_IF, &index, sizeof(index)) ==
314 -1) {
315 OnError(Error::Code::kSocketOptionSettingFailure);
316 PLOG(ERROR) << "adb_setsockopt() failed";
317 return;
318 }
319 break;
320 }
321 }
322
323 // TODO: remove once osp-discovery calls Bind() after SetMulticastOutboundInterface().
324 MdnsBind(ifindex);
325 }
326
327 // Joins to the multicast group at the given address, using the specified
328 // interface.
JoinMulticastGroup(const IPAddress & address,NetworkInterfaceIndex ifindex)329 void JoinMulticastGroup(const IPAddress& address, NetworkInterfaceIndex ifindex) override {
330 if (!fd_.ok()) {
331 OnError(Error::Code::kSocketClosedFailure);
332 return;
333 }
334
335 switch (local_endpoint_.address.version()) {
336 case UdpSocket::Version::kV4: {
337 // Passed as data to setsockopt(). 1 means return IP_PKTINFO control data
338 // in recvmsg() calls.
339 const int enable_pktinfo = 1;
340 if (adb_setsockopt(fd_, IPPROTO_IP, IP_PKTINFO, &enable_pktinfo,
341 sizeof(enable_pktinfo)) == -1) {
342 OnError(Error::Code::kSocketOptionSettingFailure);
343 LOG(ERROR) << "adb_setsockopt failed";
344 return;
345 }
346 struct ip_mreq multicast_properties;
347 SetIPV4MulticastProperties(local_endpoint_.address, address, &multicast_properties);
348 if (adb_setsockopt(fd_, IPPROTO_IP, IP_ADD_MEMBERSHIP, &multicast_properties,
349 sizeof(multicast_properties)) == -1) {
350 OnError(Error::Code::kSocketOptionSettingFailure);
351 LOG(ERROR) << "adb_setsockopt failed";
352 return;
353 }
354 return;
355 }
356
357 case UdpSocket::Version::kV6: {
358 // Passed as data to setsockopt(). 1 means return IPV6_PKTINFO control
359 // data in recvmsg() calls.
360 const int enable_pktinfo = 1;
361 #ifdef _WIN32
362 if (adb_setsockopt(fd_, IPPROTO_IPV6, IPV6_PKTINFO, &enable_pktinfo,
363 sizeof(enable_pktinfo)) == -1) {
364 #else
365 if (adb_setsockopt(fd_, IPPROTO_IPV6, IPV6_RECVPKTINFO, &enable_pktinfo,
366 sizeof(enable_pktinfo)) == -1) {
367 #endif
368 OnError(Error::Code::kSocketOptionSettingFailure);
369 LOG(ERROR) << "adb_setsockopt failed";
370 return;
371 }
372 struct ipv6_mreq multicast_properties = {
373 .ipv6mr_multiaddr = {},
374 .ipv6mr_interface = static_cast<IPv6NetworkInterfaceIndex>(ifindex),
375 };
376 static_assert(sizeof(multicast_properties.ipv6mr_multiaddr) == 16u,
377 "IPv6 address requires exactly 16 bytes");
378 address.CopyToV6(
379 reinterpret_cast<uint8_t*>(&multicast_properties.ipv6mr_multiaddr));
380 // Portability note: All platforms support IPV6_JOIN_GROUP, which is
381 // synonymous with IPV6_ADD_MEMBERSHIP.
382 if (adb_setsockopt(fd_, IPPROTO_IPV6, IPV6_JOIN_GROUP, &multicast_properties,
383 sizeof(multicast_properties)) == -1) {
384 OnError(Error::Code::kSocketOptionSettingFailure);
385 LOG(ERROR) << "adb_setsockopt failed";
386 return;
387 }
388 return;
389 }
390 }
391 }
392
393 // Sends a message. If the message is not sent, Client::OnSendError() will be
394 // called to indicate this. Error::Code::kAgain indicates the operation would
395 // block, which can be expected during normal operation.
396 virtual void SendMessage(const void* data, size_t length, const IPEndpoint& dest) override {
397 if (!fd_.ok()) {
398 client_->OnSendError(this, Error::Code::kSocketClosedFailure);
399 return;
400 }
401
402 LOG(INFO) << "SendMessage ip=" << dest.ToString();
403 adb_iovec iov;
404 iov.iov_len = length;
405 iov.iov_base = const_cast<void*>(data);
406
407 adb_msghdr msg;
408 msg.msg_iov = &iov;
409 msg.msg_iovlen = 1;
410 msg.msg_control = nullptr;
411 msg.msg_controllen = 0;
412 msg.msg_flags = 0;
413
414 ssize_t num_bytes_sent = -2;
415 switch (local_endpoint_.address.version()) {
416 case UdpSocket::Version::kV4: {
417 struct sockaddr_in sa = {};
418 sa.sin_family = AF_INET;
419 sa.sin_port = htons(dest.port);
420 dest.address.CopyToV4(reinterpret_cast<uint8_t*>(&sa.sin_addr.s_addr));
421 msg.msg_name = &sa;
422 msg.msg_namelen = sizeof(sa);
423 num_bytes_sent = adb_sendmsg(fd_, &msg, 0);
424 break;
425 }
426
427 case UdpSocket::Version::kV6: {
428 struct sockaddr_in6 sa = {};
429 sa.sin6_family = AF_INET6;
430 sa.sin6_flowinfo = 0;
431 sa.sin6_scope_id = 0;
432 sa.sin6_port = htons(dest.port);
433 dest.address.CopyToV6(reinterpret_cast<uint8_t*>(&sa.sin6_addr.s6_addr));
434 msg.msg_name = &sa;
435 msg.msg_namelen = sizeof(sa);
436 num_bytes_sent = adb_sendmsg(fd_, &msg, 0);
437 break;
438 }
439 }
440
441 if (num_bytes_sent == -1) {
442 client_->OnSendError(this, ChooseError(errno, Error::Code::kSocketSendFailure));
443 return;
444 }
445
446 // Validity-check: UDP datagram sendmsg() is all or nothing.
447 CHECK_EQ(static_cast<size_t>(num_bytes_sent), length);
448 }
449
450 // Sets the DSCP value to use for all messages sent from this socket.
451 void SetDscp(DscpMode state) override {
452 #ifdef _WIN32
453 // TODO: this method doesn't seem to be used anywhere in the openscreen code, so
454 // ignoring implementation for now.
455 // Windows 10 seems to ignore setsockopt IP_TOS, so need to use Win APIs instead.
456 LOG(FATAL) << "NOT IMPLEMENTED";
457 #else // !_WIN32
458 if (!fd_.ok()) {
459 OnError(Error::Code::kSocketClosedFailure);
460 return;
461 }
462
463 constexpr auto kSettingLevel = IPPROTO_IP;
464 uint8_t code_array[1] = {static_cast<uint8_t>(state)};
465 auto code = adb_setsockopt(fd_, kSettingLevel, IP_TOS, code_array, sizeof(uint8_t));
466
467 if (code == EBADF || code == ENOTSOCK || code == EFAULT) {
468 OnError(Error::Code::kSocketOptionSettingFailure);
469 LOG(WARNING) << "BAD SOCKET PROVIDED. CODE: " << code;
470 return;
471 } else if (code == EINVAL) {
472 OnError(Error::Code::kSocketOptionSettingFailure);
473 LOG(WARNING) << "INVALID DSCP INFO PROVIDED";
474 return;
475 } else if (code == ENOPROTOOPT) {
476 OnError(Error::Code::kSocketOptionSettingFailure);
477 LOG(WARNING) << "INVALID DSCP SETTING LEVEL PROVIDED: " << kSettingLevel;
478 return;
479 }
480 #endif // _WIN32
481 }
482
483 private:
484 // TODO: Move back into public Bind() call once osp-discovery code calls Bind() after
485 // SetMulticastOutboundInterface().
486 void MdnsBind(NetworkInterfaceIndex ifindex) {
487 if (!fd_.ok()) {
488 OnError(Error::Code::kSocketClosedFailure);
489 LOG(ERROR) << "Bind() failed. Socket is closed.";
490 return;
491 }
492
493 // This is effectively a boolean passed to setsockopt() to allow a future
494 // bind() on the same socket to succeed, even if the address is already in
495 // use. This is pretty much universally the desired behavior.
496 const int reuse = 1;
497 if (adb_setsockopt(fd_, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1) {
498 OnError(Error::Code::kSocketOptionSettingFailure);
499 LOG(WARNING) << "Failed to set SO_REUSEADDR";
500 return;
501 }
502
503 #if defined(__APPLE__)
504 // On Mac, SO_REUSEADDR is not enough to allow a bind() on a reusable multicast socket.
505 // We need to also set the option SO_REUSEPORT.
506 if (adb_setsockopt(fd_, SOL_SOCKET, SO_REUSEPORT, &reuse, sizeof(reuse)) == -1) {
507 OnError(Error::Code::kSocketOptionSettingFailure);
508 LOG(WARNING) << "Failed to set SO_REUSEPORT";
509 return;
510 }
511 #endif
512
513 switch (local_endpoint_.address.version()) {
514 case UdpSocket::Version::kV4: {
515 struct sockaddr_in address = {};
516 address.sin_family = AF_INET;
517 address.sin_port = htons(local_endpoint_.port);
518 // MUST bind to ADDR_ANY to send and receive multicast messages.
519 address.sin_addr.s_addr = INADDR_ANY;
520 if (adb_bind(fd_, reinterpret_cast<struct sockaddr*>(&address), sizeof(address)) ==
521 -1) {
522 OnError(Error::Code::kSocketBindFailure);
523 PLOG(ERROR) << "adb_bind failed";
524 return;
525 }
526
527 // Get the resolved address/port
528 sockaddr_in sa;
529 socklen_t sa_len = sizeof(sa);
530 if (adb_getsockname(fd_, reinterpret_cast<sockaddr*>(&sa), &sa_len) != -1) {
531 local_endpoint_.address = GetIPAddressFromSockAddr(sa);
532 local_endpoint_.port = GetPortFromFromSockAddr(sa);
533 LOG(INFO) << "bind endpoint=" << local_endpoint_;
534 }
535 return;
536 }
537 case UdpSocket::Version::kV6: {
538 struct sockaddr_in6 address = {};
539 address.sin6_family = AF_INET6;
540 address.sin6_flowinfo = 0;
541 address.sin6_port = htons(local_endpoint_.port);
542 // MUST bind to ADDR_ANY and scope_id unset to send and receive multicast messages.
543 address.sin6_addr = in6addr_any;
544 address.sin6_scope_id = 0;
545 if (adb_bind(fd_, reinterpret_cast<struct sockaddr*>(&address), sizeof(address)) ==
546 -1) {
547 OnError(Error::Code::kSocketBindFailure);
548 PLOG(ERROR) << "adb_bind failed";
549 return;
550 }
551
552 // Get the resolved address/port
553 sockaddr_in6 sa;
554 socklen_t sa_len = sizeof(sa);
555 if (adb_getsockname(fd_, reinterpret_cast<sockaddr*>(&sa), &sa_len) != -1) {
556 local_endpoint_.address = GetIPAddressFromSockAddr(sa);
557 local_endpoint_.port = GetPortFromFromSockAddr(sa);
558 LOG(INFO) << "bind endpoint=" << local_endpoint_
559 << " scope_id=" << sa.sin6_scope_id;
560 }
561 return;
562 }
563 default:
564 LOG(FATAL) << "Invalid domain";
565 break;
566 }
567 }
568
569 // Called by fdevent handler when data is available.
570 void ReceiveMessage() {
571 if (!fd_.ok()) {
572 client_->OnRead(this, Error::Code::kSocketClosedFailure);
573 return;
574 }
575
576 const auto bytes_available = network_peek(fd_);
577 if (!bytes_available.has_value()) {
578 client_->OnRead(this, ChooseError(errno, Error::Code::kSocketReadFailure));
579 return;
580 }
581
582 UdpPacket packet(*bytes_available);
583 packet.set_socket(this);
584 Error result = Error::Code::kUnknownError;
585 switch (local_endpoint_.address.version()) {
586 case UdpSocket::Version::kV4: {
587 result = ReceiveMessageInternal<sockaddr_in, in_pktinfo>(fd_, &packet);
588 break;
589 }
590 case UdpSocket::Version::kV6: {
591 result = ReceiveMessageInternal<sockaddr_in6, in6_pktinfo>(fd_, &packet);
592 break;
593 }
594 default: {
595 LOG(FATAL) << "Invalid domain";
596 break;
597 }
598 }
599
600 client_->OnRead(this, result.ok() ? ErrorOr<UdpPacket>(std::move(packet))
601 : ErrorOr<UdpPacket>(std::move(result)));
602 }
603
604 void OnError(Error::Code error_code) {
605 // Close the socket unless the error code represents a transient condition.
606 if (error_code != Error::Code::kNone && error_code != Error::Code::kAgain) {
607 if (fde_) {
608 fdevent_destroy(fde_);
609 fde_ = nullptr;
610 }
611 }
612
613 std::stringstream stream;
614 stream << "endpoint: " << local_endpoint_;
615 client_->OnError(this, Error(error_code, stream.str()));
616 }
617
618 static void OnFdeventResult(int fd, unsigned ev, void* opaque) {
619 AdbUdpSocket* s = reinterpret_cast<AdbUdpSocket*>(opaque);
620 if (ev & FDE_READ) {
621 s->ReceiveMessage();
622 }
623 }
624
625 Client* const client_;
626 mutable IPEndpoint local_endpoint_;
627 unique_fd fd_;
628 fdevent* fde_ = nullptr;
629 std::optional<NetworkInterfaceIndex> mdns_ifindex_;
630 };
631
632 } // namespace
633
634 // Implementation of openscreen's platform APIs for udp_socket.h
635 // static
Create(TaskRunner * task_runner,UdpSocket::Client * client,const IPEndpoint & local_endpoint)636 ErrorOr<std::unique_ptr<UdpSocket>> UdpSocket::Create(TaskRunner* task_runner,
637 UdpSocket::Client* client,
638 const IPEndpoint& local_endpoint) {
639 // |task_runner| is not used in adb's udp implementation because everything is going through the
640 // fdevent thread when we register the fd.
641 std::string err;
642 std::stringstream ip_addr_ss;
643 ip_addr_ss << local_endpoint.address;
644
645 int domain;
646 switch (local_endpoint.address.version()) {
647 case Version::kV4:
648 domain = AF_INET;
649 break;
650 case Version::kV6:
651 domain = AF_INET6;
652 break;
653 default:
654 LOG(FATAL) << "Invalid domain";
655 return Error::Code::kInitializationFailure;
656 }
657
658 unique_fd fd(adb_socket(domain, SOCK_DGRAM, 0));
659 if (!fd.ok()) {
660 PLOG(ERROR) << "Failed to create udp socket";
661 return Error::Code::kInitializationFailure;
662 }
663
664 if (!set_file_block_mode(fd, false)) {
665 PLOG(ERROR) << "Failed to set non-block mode on fd";
666 return Error::Code::kInitializationFailure;
667 }
668
669 LOG(INFO) << "UDP socket created for " << local_endpoint;
670 std::unique_ptr<UdpSocket> udp_socket(new AdbUdpSocket(client, local_endpoint, std::move(fd)));
671 return udp_socket;
672 }
673
674 } // namespace openscreen
675