blob: cc3db59dfb40b7c477f40c8c5e69eaa8a4150d23 [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>
12
Yuri Wiitala82edd202018-10-31 18:42:58 -070013#include "platform/api/network_interface.h"
Max Yakimakha04362e22019-07-22 17:54:45 -070014#include "platform/api/udp_read_callback.h"
Jordan Baylesa26582d2019-07-10 14:44:58 -070015#include "platform/base/error.h"
16#include "platform/base/ip_address.h"
17#include "platform/base/macros.h"
btolsch9ccfa782018-07-26 00:16:08 -070018
19namespace openscreen {
20namespace platform {
21
Ryan Keanea4dfaa12019-08-19 10:30:20 -070022class TaskRunner;
Yuri Wiitala10dea9f2019-02-04 20:19:17 -080023class UdpSocket;
btolsch9ccfa782018-07-26 00:16:08 -070024
Ryan Keanedeb48b32019-06-28 16:24:40 -070025using UdpSocketUniquePtr = std::unique_ptr<UdpSocket>;
Yuri Wiitalab94f12e2018-10-31 18:28:53 -070026
Yuri Wiitala10dea9f2019-02-04 20:19:17 -080027// An open UDP socket for sending/receiving datagrams to/from either specific
28// endpoints or over IP multicast.
29//
30// Usage: The socket is created and opened by calling the Create() method. This
31// returns a unique pointer that auto-closes/destroys the socket when it goes
32// out-of-scope.
33//
34// Platform implementation note: There must only be one platform-specific
35// implementation of UdpSocket linked into the library/application. For that
36// reason, none of the methods here are declared virtual (i.e., the overhead is
37// pure waste). However, UdpSocket can be subclassed to include all extra
38// private state, such as OS-specific handles. See UdpSocketPosix for a
39// reference implementation.
40class UdpSocket {
41 public:
Ryan Keanedeb48b32019-06-28 16:24:40 -070042 virtual ~UdpSocket();
43
Ryan Keanea4dfaa12019-08-19 10:30:20 -070044 // Client for the UdpSocket class.
45 class Client {
46 public:
47 virtual ~Client() = default;
48
49 // Method called on socket configuration operations when an error occurs.
50 // These specific APIs are:
51 // UdpSocket::Bind()
52 // UdpSocket::SetMulticastOutboundInterface(...)
53 // UdpSocket::JoinMulticastGroup(...)
54 // UdpSocket::SetDscp(...)
55 virtual void OnError(UdpSocket* socket, Error error) = 0;
56
57 // Method called when an error occurs during a SendMessage call.
58 virtual void OnSendError(UdpSocket* socket, Error error) = 0;
59
60 // Method called when a packet is read.
61 virtual void OnRead(UdpSocket* socket, ErrorOr<UdpPacket> packet) = 0;
62 };
63
Ryan Keane8f1c9252019-05-06 11:03:38 -070064 // Constants used to specify how we want packets sent from this socket.
65 enum class DscpMode : uint8_t {
66 // Default value set by the system on creation of a new socket.
67 kUnspecified = 0x0,
68
69 // Mode for Audio only.
70 kAudioOnly = 0xb8,
71
72 // Mode for Audio + Video.
73 kAudioVideo = 0x88,
74
75 // Mode for low priority operations such as trace log data.
76 kLowPriority = 0x20
77 };
78
Yuri Wiitala10dea9f2019-02-04 20:19:17 -080079 using Version = IPAddress::Version;
btolsch9ccfa782018-07-26 00:16:08 -070080
Yuri Wiitalade01e532019-08-06 18:12:02 -070081 // Creates a new, scoped UdpSocket within the IPv4 or IPv6 family.
82 // |local_endpoint| may be zero (see comments for Bind()). This method must be
Ryan Keanea4dfaa12019-08-19 10:30:20 -070083 // defined in the platform-level implementation. All client_ methods called
84 // will be queued on the provided task_runner. For this reason, the provided
85 // task_runner and client must exist for the duration of the created socket's
86 // lifetime.
87 static ErrorOr<UdpSocketUniquePtr> Create(TaskRunner* task_runner,
88 Client* client,
89 const IPEndpoint& local_endpoint);
btolsch9ccfa782018-07-26 00:16:08 -070090
Yuri Wiitala10dea9f2019-02-04 20:19:17 -080091 // Returns true if |socket| belongs to the IPv4/IPv6 address family.
Ryan Keanedeb48b32019-06-28 16:24:40 -070092 virtual bool IsIPv4() const = 0;
93 virtual bool IsIPv6() const = 0;
Yuri Wiitala10dea9f2019-02-04 20:19:17 -080094
Yuri Wiitalade01e532019-08-06 18:12:02 -070095 // Returns the current local endpoint's address and port. Initially, this will
96 // be the same as the value that was passed into Create(). However, it can
97 // later change after certain operations, such as Bind(), are executed.
98 virtual IPEndpoint GetLocalEndpoint() const = 0;
99
100 // Binds to the address specified in the constructor. If the local endpoint's
101 // address is zero, the operating system will bind to all interfaces. If the
102 // local endpoint's port is zero, the operating system will automatically find
103 // a free local port and bind to it. Future calls to local_endpoint() will
104 // reflect the resolved port.
Ryan Keane83e68322019-08-23 14:54:38 -0700105 virtual void Bind() = 0;
Yuri Wiitala10dea9f2019-02-04 20:19:17 -0800106
107 // Sets the device to use for outgoing multicast packets on the socket.
Ryan Keane7e74bdd2019-08-27 08:15:21 -0700108 virtual void SetMulticastOutboundInterface(NetworkInterfaceIndex ifindex) = 0;
Yuri Wiitala10dea9f2019-02-04 20:19:17 -0800109
110 // Joins to the multicast group at the given address, using the specified
111 // interface.
Ryan Keane7e74bdd2019-08-27 08:15:21 -0700112 virtual void JoinMulticastGroup(const IPAddress& address,
113 NetworkInterfaceIndex ifindex) = 0;
Yuri Wiitala10dea9f2019-02-04 20:19:17 -0800114
Yuri Wiitala10dea9f2019-02-04 20:19:17 -0800115 // Sends a message and returns the number of bytes sent, on success.
116 // Error::Code::kAgain might be returned to indicate the operation would
117 // block, which can be expected during normal operation.
Ryan Keane71cacc22019-08-21 13:01:47 -0700118 virtual void SendMessage(const void* data,
119 size_t length,
120 const IPEndpoint& dest) = 0;
Yuri Wiitala10dea9f2019-02-04 20:19:17 -0800121
Ryan Keane8f1c9252019-05-06 11:03:38 -0700122 // Sets the DSCP value to use for all messages sent from this socket.
Ryan Keane7e74bdd2019-08-27 08:15:21 -0700123 virtual void SetDscp(DscpMode state) = 0;
Ryan Keanedeb48b32019-06-28 16:24:40 -0700124
125 // Sets the callback that should be called upon deletion of this socket. This
126 // allows other objects to observe the socket's destructor and act when it is
127 // called.
128 void SetDeletionCallback(std::function<void(UdpSocket*)> callback);
Ryan Keane8f1c9252019-05-06 11:03:38 -0700129
Yuri Wiitala10dea9f2019-02-04 20:19:17 -0800130 protected:
Ryan Keanea4dfaa12019-08-19 10:30:20 -0700131 // Creates a new UdpSocket. The provided client and task_runner must exist for
132 // the duration of this socket's lifetime.
133 UdpSocket(TaskRunner* task_runner, Client* client);
134
Ryan Keane63fbedd2019-08-19 12:33:41 -0700135 // Methods to take care of posting UdpSocket::Client callbacks for client_ to
136 // task_runner_.
Ryan Keane83050af2019-08-26 08:58:09 -0700137 // NOTE: OnError(...) will close the socket in addition toreturning the error.
Ryan Keane63fbedd2019-08-19 12:33:41 -0700138 void OnError(Error error);
139 void OnSendError(Error error);
140 void OnRead(ErrorOr<UdpPacket> read_data);
141
Ryan Keane83050af2019-08-26 08:58:09 -0700142 // Closes an open socket when a non-recoverable error occurs.
143 void CloseIfError(const Error& error);
144
145 // Closes an open socket.
146 // NOTE: Concrete implementations of UdpSocket must call this method in their
147 // destructor.
148 void CloseIfOpen();
149
150 // Returns whether the socket is currently closed.
151 // NOTE: This must be checked before calling any operation on the socket.
152 bool is_closed() { return is_closed_.load(); }
153
Ryan Keane63fbedd2019-08-19 12:33:41 -0700154 private:
Ryan Keane83050af2019-08-26 08:58:09 -0700155 // Closes this socket.
156 // NOTE: This method will only be called once.
157 virtual void Close() {}
158
159 // Atomically keeps track of if the socket is closed, so that threading
160 // across different implementations isn't a problem.
161 std::atomic_bool is_closed_{false};
162
Ryan Keane63fbedd2019-08-19 12:33:41 -0700163 // This callback allows other objects to observe the socket's destructor and
164 // act when it is called.
165 std::function<void(UdpSocket*)> deletion_callback_;
166
Ryan Keanea4dfaa12019-08-19 10:30:20 -0700167 // Client to use for callbacks.
168 // NOTE: client_ can be nullptr if the user does not want any callbacks (for
169 // example, in the send-only case).
170 Client* const client_;
171
172 // Task runner to use for queuing client_ callbacks.
173 TaskRunner* const task_runner_;
Yuri Wiitala10dea9f2019-02-04 20:19:17 -0800174
Jordan Baylesf1e4bb72019-05-01 12:38:39 -0700175 OSP_DISALLOW_COPY_AND_ASSIGN(UdpSocket);
Yuri Wiitala10dea9f2019-02-04 20:19:17 -0800176};
btolsch9ccfa782018-07-26 00:16:08 -0700177
178} // namespace platform
179} // namespace openscreen
180
Jordan Baylesad2d2cd2019-05-22 14:49:40 -0700181#endif // PLATFORM_API_UDP_SOCKET_H_