forked from youtube/cobalt
-
Notifications
You must be signed in to change notification settings - Fork 0
/
socket_helpers.h
226 lines (196 loc) · 8.61 KB
/
socket_helpers.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
// Copyright 2015 The Cobalt Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef STARBOARD_NPLB_SOCKET_HELPERS_H_
#define STARBOARD_NPLB_SOCKET_HELPERS_H_
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "starboard/common/socket.h"
#include "starboard/socket_waiter.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace starboard {
namespace nplb {
const int64_t kSocketTimeout = 200'000; // 200ms
// Returns true if the given address is the unspecified address (all zeros),
// supporting both address types.
bool IsUnspecified(const SbSocketAddress* address);
// Returns true if the given address is the localhost address, supporting both
// address types.
bool IsLocalhost(const SbSocketAddress* address);
// Returns a valid port number that can be bound to for use in nplb tests.
// This will always return the same port number.
int GetPortNumberForTests();
// Creates a TCP/IP server socket (sets Reuse Address option).
SbSocket CreateServerTcpSocket(SbSocketAddressType address_type);
std::unique_ptr<Socket> CreateServerTcpSocketWrapped(
SbSocketAddressType address_type);
// Creates a TCP/IP socket bound to all interfaces on the given port.
SbSocket CreateBoundTcpSocket(SbSocketAddressType address_type, int port);
std::unique_ptr<Socket> CreateBoundTcpSocketWrapped(
SbSocketAddressType address_type,
int port);
// Creates a TCP/IP socket listening on all interfaces on the given port.
SbSocket CreateListeningTcpSocket(SbSocketAddressType address_type, int port);
std::unique_ptr<Socket> CreateListeningTcpSocketWrapped(
SbSocketAddressType address_type,
int port);
// Tries to accept a new connection from the given listening socket by checking,
// yielding, and retrying for up to timeout. Returns kSbSocketInvalid if no
// socket has been accepted in the given time.
SbSocket AcceptBySpinning(SbSocket listen_socket, int64_t timeout);
std::unique_ptr<Socket> AcceptBySpinning(Socket* listen_socket,
int64_t timeout);
// Writes the given data to socket, spinning until success or error.
bool WriteBySpinning(SbSocket socket,
const char* data,
int data_size,
int64_t timeout);
bool WriteBySpinning(Socket* socket,
const char* data,
int data_size,
int64_t timeout);
// Reads the given amount of data from socket, spinning until success or error.
bool ReadBySpinning(SbSocket socket,
char* out_data,
int data_size,
int64_t timeout);
bool ReadBySpinning(Socket* socket,
char* out_data,
int data_size,
int64_t timeout);
// Transfers data between the two connected local sockets, spinning until |size|
// has been transferred, or an error occurs.
int Transfer(SbSocket receive_socket,
char* out_data,
SbSocket send_socket,
const char* send_data,
int size);
int Transfer(Socket* receive_socket,
char* out_data,
Socket* send_socket,
const char* send_data,
int size);
struct ConnectedTrio {
ConnectedTrio()
: listen_socket(kSbSocketInvalid),
client_socket(kSbSocketInvalid),
server_socket(kSbSocketInvalid) {}
ConnectedTrio(SbSocket listen_socket,
SbSocket client_socket,
SbSocket server_socket)
: listen_socket(listen_socket),
client_socket(client_socket),
server_socket(server_socket) {}
SbSocket listen_socket;
SbSocket client_socket;
SbSocket server_socket;
};
struct ConnectedTrioWrapped {
ConnectedTrioWrapped() {}
ConnectedTrioWrapped(std::unique_ptr<Socket> listen_socket,
std::unique_ptr<Socket> client_socket,
std::unique_ptr<Socket> server_socket)
: listen_socket(std::move(listen_socket)),
client_socket(std::move(client_socket)),
server_socket(std::move(server_socket)) {}
std::unique_ptr<Socket> listen_socket;
std::unique_ptr<Socket> client_socket;
std::unique_ptr<Socket> server_socket;
};
// Creates and returns 3 TCP/IP sockets, a connected client and server, and a
// listener on the given port. If anything fails, adds a failure and returns
// three invalid sockets.
ConnectedTrio CreateAndConnect(SbSocketAddressType server_address_type,
SbSocketAddressType client_address_type,
int port,
int64_t timeout);
std::unique_ptr<ConnectedTrioWrapped> CreateAndConnectWrapped(
SbSocketAddressType server_address_type,
SbSocketAddressType client_address_type,
int port,
int64_t timeout);
// Waits on the given waiter, and returns the elapsed time in microseconds.
int64_t TimedWait(SbSocketWaiter waiter);
// Waits on the given waiter, and returns the elapsed time in microseconds.
int64_t TimedWaitTimed(SbSocketWaiter waiter, int64_t timeout);
// Waits on the given waiter, and checks that it blocked between
// [lower_usec, upper_usec).
static inline void WaitShouldBlockBetween(SbSocketWaiter waiter,
int64_t lower_usec,
int64_t upper_usec) {
int64_t time = TimedWait(waiter);
EXPECT_GT(upper_usec, time);
EXPECT_LE(lower_usec, time);
}
// Waits on the given waiter, and checks that it did not block for very long.
static inline void WaitShouldNotBlock(SbSocketWaiter waiter) {
WaitShouldBlockBetween(waiter, 0, kSocketTimeout);
}
// Waits on the given waiter, and checks that it did not block for the given
// timeout.
static inline void TimedWaitShouldNotBlock(SbSocketWaiter waiter,
int64_t timeout) {
EXPECT_GT(timeout, TimedWaitTimed(waiter, timeout));
}
// Waits on the given waiter, and checks that it did block for at least the
// given timeout.
static inline void TimedWaitShouldBlock(SbSocketWaiter waiter,
int64_t timeout) {
EXPECT_LE(timeout, TimedWaitTimed(waiter, timeout));
}
// Socket operations may return specific (e.g. kSbSocketErrorConnectionReset) or
// general (e.g. kSbSocketErrorFailed) error codes, and while in some cases
// it may be important that we obtain a specific error message, in other cases
// it will just be used as a hint and so these methods are provided to make
// it easy to test against specific or general errors.
static inline bool SocketErrorIn(
SbSocketError error,
const std::vector<SbSocketError>& expected_set) {
for (size_t i = 0; i < expected_set.size(); ++i) {
if (expected_set[i] == error) {
return true;
}
}
return false;
}
#define EXPECT_SB_SOCKET_ERROR_IN(error, ...) \
do { \
EXPECT_TRUE(SocketErrorIn(error, {__VA_ARGS__})) \
<< "With " #error " = " << error; \
} while (false)
#define EXPECT_SB_SOCKET_ERROR_IS_ERROR(error) \
do { \
EXPECT_FALSE(SocketErrorIn(error, {kSbSocketOk, kSbSocketPending})) \
<< "With " #error " = " << error; \
} while (false)
#if !defined(COBALT_BUILD_TYPE_GOLD)
std::string GetSbSocketAddressTypeName(
::testing::TestParamInfo<SbSocketAddressType> info);
std::string GetSbSocketAddressTypePairName(
::testing::TestParamInfo<
std::pair<SbSocketAddressType, SbSocketAddressType>> info);
std::string GetSbSocketAddressTypeFilterPairName(
::testing::TestParamInfo<
std::pair<SbSocketAddressType, SbSocketResolveFilter>> info);
std::string GetSbSocketFilterAddressTypePairName(
::testing::TestParamInfo<
std::pair<SbSocketResolveFilter, SbSocketAddressType>> info);
std::string GetSbSocketAddressTypeProtocolPairName(
::testing::TestParamInfo<std::pair<SbSocketAddressType, SbSocketProtocol>>
info);
#endif // #if !defined(COBALT_BUILD_TYPE_GOLD)
} // namespace nplb
} // namespace starboard
#endif // STARBOARD_NPLB_SOCKET_HELPERS_H_