blob: ff9c033bbaa374df0f58f6798917e037d3b6f82f [file] [log] [blame]
btolsch9ccfa782018-07-26 00:16:08 -07001// 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
Jordan Baylesad2d2cd2019-05-22 14:49:40 -07005#ifndef PLATFORM_API_UDP_SOCKET_H_
6#define PLATFORM_API_UDP_SOCKET_H_
btolsch9ccfa782018-07-26 00:16:08 -07007
Ryan Keane83050af2019-08-26 08:58:09 -07008#include <atomic>
Yuri Wiitala10dea9f2019-02-04 20:19:17 -08009#include <cstdint>
Ryan Keanedeb48b32019-06-28 16:24:40 -070010#include <functional>
Yuri Wiitala10dea9f2019-02-04 20:19:17 -080011#include <memory>
Ryan Keane9222e042019-08-27 10:44:13 -070012#include <mutex>
Yuri Wiitala10dea9f2019-02-04 20:19:17 -080013
Yuri Wiitala82edd202018-10-31 18:42:58 -070014#include "platform/api/network_interface.h"
Ryan Keane230920e2019-08-29 13:21:40 -070015#include "platform/api/udp_packet.h"
Jordan Baylesa26582d2019-07-10 14:44:58 -070016#include "platform/base/error.h"
17#include "platform/base/ip_address.h"
18#include "platform/base/macros.h"
btolsch9ccfa782018-07-26 00:16:08 -070019
20namespace openscreen {
21namespace platform {
22
Ryan Keanea4dfaa12019-08-19 10:30:20 -070023class TaskRunner;
Yuri Wiitala10dea9f2019-02-04 20:19:17 -080024class UdpSocket;
btolsch9ccfa782018-07-26 00:16:08 -070025
Ryan Keanedeb48b32019-06-28 16:24:40 -070026using UdpSocketUniquePtr = std::unique_ptr<UdpSocket>;
Yuri Wiitalab94f12e2018-10-31 18:28:53 -070027
Yuri Wiitala10dea9f2019-02-04 20:19:17 -080028// An open UDP socket for sending/receiving datagrams to/from either specific
29// endpoints or over IP multicast.
30//
31// Usage: The socket is created and opened by calling the Create() method. This
32// returns a unique pointer that auto-closes/destroys the socket when it goes
33// out-of-scope.
34//
35// Platform implementation note: There must only be one platform-specific
36// implementation of UdpSocket linked into the library/application. For that
37// reason, none of the methods here are declared virtual (i.e., the overhead is
38// pure waste). However, UdpSocket can be subclassed to include all extra
39// private state, such as OS-specific handles. See UdpSocketPosix for a
40// reference implementation.
41class UdpSocket {
42 public:
Ryan Keanedeb48b32019-06-28 16:24:40 -070043 virtual ~UdpSocket();
44
Ryan Keane9222e042019-08-27 10:44:13 -070045 class LifetimeObserver {
46 public:
47 virtual ~LifetimeObserver() = default;
48
49 // Function to call upon creation of a new UdpSocket.
50 virtual void OnCreate(UdpSocket* socket) = 0;
51
52 // Function to call upon deletion of a UdpSocket.
53 virtual void OnDestroy(UdpSocket* socket) = 0;
54 };
55
Ryan Keanea4dfaa12019-08-19 10:30:20 -070056 // Client for the UdpSocket class.
57 class Client {
58 public:
59 virtual ~Client() = default;
60
61 // Method called on socket configuration operations when an error occurs.
62 // These specific APIs are:
63 // UdpSocket::Bind()
64 // UdpSocket::SetMulticastOutboundInterface(...)
65 // UdpSocket::JoinMulticastGroup(...)
66 // UdpSocket::SetDscp(...)
67 virtual void OnError(UdpSocket* socket, Error error) = 0;
68
69 // Method called when an error occurs during a SendMessage call.
70 virtual void OnSendError(UdpSocket* socket, Error error) = 0;
71
72 // Method called when a packet is read.
73 virtual void OnRead(UdpSocket* socket, ErrorOr<UdpPacket> packet) = 0;
74 };
75
Ryan Keane8f1c9252019-05-06 11:03:38 -070076 // Constants used to specify how we want packets sent from this socket.
77 enum class DscpMode : uint8_t {
78 // Default value set by the system on creation of a new socket.
79 kUnspecified = 0x0,
80
81 // Mode for Audio only.
82 kAudioOnly = 0xb8,
83
84 // Mode for Audio + Video.
85 kAudioVideo = 0x88,
86
87 // Mode for low priority operations such as trace log data.
88 kLowPriority = 0x20
89 };
90
Ryan Keane9222e042019-08-27 10:44:13 -070091 // The LifetimeObserver set here must exist during ANY future UdpSocket
92 // creations. SetLifetimeObserver(nullptr) must be called before any future
93 // socket creations on destructions after the observer is destroyed
94 static void SetLifetimeObserver(LifetimeObserver* observer);
95
Yuri Wiitala10dea9f2019-02-04 20:19:17 -080096 using Version = IPAddress::Version;
btolsch9ccfa782018-07-26 00:16:08 -070097
Yuri Wiitalade01e532019-08-06 18:12:02 -070098 // Creates a new, scoped UdpSocket within the IPv4 or IPv6 family.
99 // |local_endpoint| may be zero (see comments for Bind()). This method must be
Ryan Keanea4dfaa12019-08-19 10:30:20 -0700100 // defined in the platform-level implementation. All client_ methods called
101 // will be queued on the provided task_runner. For this reason, the provided
102 // task_runner and client must exist for the duration of the created socket's
103 // lifetime.
104 static ErrorOr<UdpSocketUniquePtr> Create(TaskRunner* task_runner,
105 Client* client,
106 const IPEndpoint& local_endpoint);
btolsch9ccfa782018-07-26 00:16:08 -0700107
Yuri Wiitala10dea9f2019-02-04 20:19:17 -0800108 // Returns true if |socket| belongs to the IPv4/IPv6 address family.
Ryan Keanedeb48b32019-06-28 16:24:40 -0700109 virtual bool IsIPv4() const = 0;
110 virtual bool IsIPv6() const = 0;
Yuri Wiitala10dea9f2019-02-04 20:19:17 -0800111
Yuri Wiitalade01e532019-08-06 18:12:02 -0700112 // Returns the current local endpoint's address and port. Initially, this will
113 // be the same as the value that was passed into Create(). However, it can
114 // later change after certain operations, such as Bind(), are executed.
115 virtual IPEndpoint GetLocalEndpoint() const = 0;
116
117 // Binds to the address specified in the constructor. If the local endpoint's
118 // address is zero, the operating system will bind to all interfaces. If the
119 // local endpoint's port is zero, the operating system will automatically find
120 // a free local port and bind to it. Future calls to local_endpoint() will
121 // reflect the resolved port.
Ryan Keane83e68322019-08-23 14:54:38 -0700122 virtual void Bind() = 0;
Yuri Wiitala10dea9f2019-02-04 20:19:17 -0800123
124 // Sets the device to use for outgoing multicast packets on the socket.
Ryan Keane7e74bdd2019-08-27 08:15:21 -0700125 virtual void SetMulticastOutboundInterface(NetworkInterfaceIndex ifindex) = 0;
Yuri Wiitala10dea9f2019-02-04 20:19:17 -0800126
127 // Joins to the multicast group at the given address, using the specified
128 // interface.
Ryan Keane7e74bdd2019-08-27 08:15:21 -0700129 virtual void JoinMulticastGroup(const IPAddress& address,
130 NetworkInterfaceIndex ifindex) = 0;
Yuri Wiitala10dea9f2019-02-04 20:19:17 -0800131
Yuri Wiitala10dea9f2019-02-04 20:19:17 -0800132 // Sends a message and returns the number of bytes sent, on success.
133 // Error::Code::kAgain might be returned to indicate the operation would
134 // block, which can be expected during normal operation.
Ryan Keane71cacc22019-08-21 13:01:47 -0700135 virtual void SendMessage(const void* data,
136 size_t length,
137 const IPEndpoint& dest) = 0;
Yuri Wiitala10dea9f2019-02-04 20:19:17 -0800138
Ryan Keane8f1c9252019-05-06 11:03:38 -0700139 // Sets the DSCP value to use for all messages sent from this socket.
Ryan Keane7e74bdd2019-08-27 08:15:21 -0700140 virtual void SetDscp(DscpMode state) = 0;
Ryan Keanedeb48b32019-06-28 16:24:40 -0700141
Yuri Wiitala10dea9f2019-02-04 20:19:17 -0800142 protected:
Ryan Keanea4dfaa12019-08-19 10:30:20 -0700143 // Creates a new UdpSocket. The provided client and task_runner must exist for
144 // the duration of this socket's lifetime.
145 UdpSocket(TaskRunner* task_runner, Client* client);
146
Ryan Keane63fbedd2019-08-19 12:33:41 -0700147 // Methods to take care of posting UdpSocket::Client callbacks for client_ to
148 // task_runner_.
Ryan Keane230920e2019-08-29 13:21:40 -0700149 // NOTE: OnError(...) will close the socket in addition to returning the
150 // error.
Ryan Keane63fbedd2019-08-19 12:33:41 -0700151 void OnError(Error error);
152 void OnSendError(Error error);
153 void OnRead(ErrorOr<UdpPacket> read_data);
154
Ryan Keane83050af2019-08-26 08:58:09 -0700155 // Closes an open socket when a non-recoverable error occurs.
156 void CloseIfError(const Error& error);
157
158 // Closes an open socket.
159 // NOTE: Concrete implementations of UdpSocket must call this method in their
160 // destructor.
161 void CloseIfOpen();
162
163 // Returns whether the socket is currently closed.
164 // NOTE: This must be checked before calling any operation on the socket.
165 bool is_closed() { return is_closed_.load(); }
166
Ryan Keane63fbedd2019-08-19 12:33:41 -0700167 private:
Ryan Keane9222e042019-08-27 10:44:13 -0700168 static std::atomic<LifetimeObserver*> lifetime_observer_;
169
Ryan Keane83050af2019-08-26 08:58:09 -0700170 // Closes this socket.
171 // NOTE: This method will only be called once.
172 virtual void Close() {}
173
174 // Atomically keeps track of if the socket is closed, so that threading
175 // across different implementations isn't a problem.
176 std::atomic_bool is_closed_{false};
177
Ryan Keanea4dfaa12019-08-19 10:30:20 -0700178 // Client to use for callbacks.
179 // NOTE: client_ can be nullptr if the user does not want any callbacks (for
180 // example, in the send-only case).
181 Client* const client_;
182
183 // Task runner to use for queuing client_ callbacks.
184 TaskRunner* const task_runner_;
Yuri Wiitala10dea9f2019-02-04 20:19:17 -0800185
Jordan Baylesf1e4bb72019-05-01 12:38:39 -0700186 OSP_DISALLOW_COPY_AND_ASSIGN(UdpSocket);
Yuri Wiitala10dea9f2019-02-04 20:19:17 -0800187};
btolsch9ccfa782018-07-26 00:16:08 -0700188
189} // namespace platform
190} // namespace openscreen
191
Jordan Baylesad2d2cd2019-05-22 14:49:40 -0700192#endif // PLATFORM_API_UDP_SOCKET_H_