forked from luncliff/coroutine
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathvs_net.cpp
More file actions
134 lines (109 loc) · 3.41 KB
/
vs_net.cpp
File metadata and controls
134 lines (109 loc) · 3.41 KB
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
//
// Author : github.com/luncliff (luncliff@gmail.com)
// License : CC BY 4.0
//
#include "./net_test.h"
#include <CppUnitTest.h>
using namespace std;
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
void print_error_message(int ec = WSAGetLastError()) {
auto em = system_category().message(ec);
Logger::WriteMessage(em.c_str());
}
// The library doesn't init/release Windows Socket API
// Its user must do the work. In this case, the user is test code
WSADATA wsa_data{};
TEST_MODULE_INITIALIZE(winsock_init) {
// init version the known version
if (::WSAStartup(MAKEWORD(2, 2), &wsa_data) != NO_ERROR) {
print_error_message();
Assert::Fail();
}
}
TEST_MODULE_CLEANUP(winsock_release) {
// check and release
if (wsa_data.wVersion != 0)
::WSACleanup();
}
int64_t socket_create(const addrinfo& hint) {
auto sd = ::WSASocketW(hint.ai_family, hint.ai_socktype, hint.ai_protocol,
nullptr, 0, WSA_FLAG_OVERLAPPED);
if (sd == INVALID_SOCKET)
print_error_message();
Assert::AreNotEqual(sd, INVALID_SOCKET);
return sd;
}
auto socket_create(const addrinfo& hint, //
size_t count) -> coro::enumerable<int64_t> {
while (count--) {
auto sd = socket_create(hint);
co_yield sd;
}
}
void socket_close(int64_t sd) {
::shutdown(sd, SD_BOTH);
::closesocket(sd);
}
void socket_bind(int64_t sd, endpoint_t& ep) {
socklen_t addrlen = 0;
const auto family = ep.storage.ss_family;
if (family == AF_INET)
addrlen = sizeof(sockaddr_in);
if (family == AF_INET6)
addrlen = sizeof(sockaddr_in6);
// bind socket and address
if (::bind(sd, &ep.addr, addrlen) != NO_ERROR) {
print_error_message();
Assert::Fail();
}
}
void socket_listen(int64_t sd) {
if (::listen(sd, 7) != NO_ERROR) {
print_error_message();
Assert::Fail();
}
}
int64_t socket_connect(int64_t sd, const endpoint_t& remote) {
socklen_t addrlen = 0;
if (remote.addr.sa_family == AF_INET)
addrlen = sizeof(remote.in4);
if (remote.addr.sa_family == AF_INET6)
addrlen = sizeof(remote.in6);
return ::connect(sd, addressof(remote.addr), addrlen);
}
int64_t socket_accept(const int64_t ln, endpoint_t& ep) {
// receiver can check the address family
socklen_t addrlen = sizeof(ep.in6);
return ::accept(ln, addressof(ep.addr), addressof(addrlen));
}
void socket_set_option_nonblock(int64_t sd) {
u_long mode = TRUE;
if (::ioctlsocket(sd, FIONBIO, &mode) != NO_ERROR) {
print_error_message();
Assert::Fail();
}
}
void socket_set_option(int64_t sd, int64_t level, int64_t option,
int64_t value) {
auto ec = ::setsockopt(sd, level, option, (char*)&value, sizeof(value));
if (ec != NO_ERROR) {
print_error_message();
Assert::Fail();
}
}
void socket_set_option_reuse_address(int64_t sd) {
return socket_set_option(sd, SOL_SOCKET, SO_REUSEADDR, true);
}
void socket_set_option_nodelay(int64_t sd) {
return socket_set_option(sd, IPPROTO_TCP, TCP_NODELAY, true);
}
class net_wait_test : public TestClass<net_wait_test> {
TEST_METHOD(net_wait_io_task_yield_nothing) {
auto count = 0u;
for (auto t : wait_io_tasks(10ms)) {
Assert::IsNotNull(t.address());
count += 1;
}
Assert::IsTrue(count == 0);
}
};