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