1 // Copyright 2018 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.
4 
5 #ifndef PLATFORM_IMPL_UDP_SOCKET_POSIX_H_
6 #define PLATFORM_IMPL_UDP_SOCKET_POSIX_H_
7 
8 #include "absl/types/optional.h"
9 #include "platform/api/udp_socket.h"
10 #include "platform/base/macros.h"
11 #include "platform/impl/platform_client_posix.h"
12 #include "platform/impl/socket_handle_posix.h"
13 #include "util/weak_ptr.h"
14 
15 namespace openscreen {
16 
17 class UdpSocketReaderPosix;
18 
19 // Threading: All public methods must be called on the same thread--the one
20 // executing the TaskRunner. All non-public methods, except ReceiveMessage(),
21 // are also assumed to be called on that thread.
22 class UdpSocketPosix : public UdpSocket {
23  public:
24   // Creates a new UdpSocketPosix. The provided client and task_runner must
25   // exist for the duration of this socket's lifetime.
26   UdpSocketPosix(TaskRunner* task_runner,
27                  Client* client,
28                  SocketHandle handle,
29                  const IPEndpoint& local_endpoint,
30                  PlatformClientPosix* platform_client =
31                      PlatformClientPosix::GetInstance());
32 
33   ~UdpSocketPosix() override;
34 
35   // Implementations of UdpSocket methods.
36   bool IsIPv4() const override;
37   bool IsIPv6() const override;
38   IPEndpoint GetLocalEndpoint() const override;
39   void Bind() override;
40   void SetMulticastOutboundInterface(NetworkInterfaceIndex ifindex) override;
41   void JoinMulticastGroup(const IPAddress& address,
42                           NetworkInterfaceIndex ifindex) override;
43   void SendMessage(const void* data,
44                    size_t length,
45                    const IPEndpoint& dest) override;
46   void SetDscp(DscpMode state) override;
47 
48   const SocketHandle& GetHandle() const;
49 
50  protected:
51   friend class UdpSocketReaderPosix;
52 
53   // Called by UdpSocketReaderPosix to perform a non-blocking read on the socket
54   // and then dispatch the packet to this socket's Client. This method is the
55   // only one in this class possibly being called from another thread.
56   void ReceiveMessage();
57 
58  private:
59   // Helper to close the socket if |error| is fatal, in addition to dispatching
60   // an Error to the |client_|.
61   void OnError(Error::Code error);
62 
is_closed()63   bool is_closed() const { return handle_.fd < 0; }
64   void Close();
65 
66   // Task runner to use for queuing |client_| callbacks.
67   TaskRunner* const task_runner_;
68 
69   // Client to use for callbacks. This can be nullptr if the user does not want
70   // any callbacks (for example, in the send-only case).
71   Client* const client_;
72 
73   // Holds the POSIX file descriptor, or -1 if the socket is closed.
74   SocketHandle handle_;
75 
76   // Cached value of current local endpoint. This can change (e.g., when the
77   // operating system auto-assigns a free local port when Bind() is called). If
78   // the port is zero, getsockname() is called to try to resolve it. Once the
79   // port is non-zero, it is assumed never to change again.
80   mutable IPEndpoint local_endpoint_;
81 
82   WeakPtrFactory<UdpSocketPosix> weak_factory_{this};
83 
84   PlatformClientPosix* const platform_client_;
85 
86   OSP_DISALLOW_COPY_AND_ASSIGN(UdpSocketPosix);
87 };
88 
89 }  // namespace openscreen
90 
91 #endif  // PLATFORM_IMPL_UDP_SOCKET_POSIX_H_
92