starpc 0.52.1 → 0.52.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -8
- package/dist/srpc/client-rpc.d.ts +1 -0
- package/dist/srpc/client-rpc.js +9 -0
- package/dist/srpc/client-rpc.test.d.ts +1 -0
- package/dist/srpc/client-rpc.test.js +50 -0
- package/dist/srpc/common-rpc.d.ts +5 -0
- package/dist/srpc/common-rpc.js +37 -8
- package/dist/srpc/errors.d.ts +2 -0
- package/dist/srpc/errors.js +14 -0
- package/dist/srpc/index.d.ts +1 -1
- package/dist/srpc/index.js +1 -1
- package/echo/Cargo.toml +8 -0
- package/echo/echo_e2e_test.cpp +542 -985
- package/echo/echo_srpc.pb.cpp +3 -5
- package/echo/echo_srpc.pb.go +6 -9
- package/echo/echo_srpc.pb.hpp +23 -3
- package/echo/echo_srpc.pb.rs +61 -26
- package/echo/echo_srpc.py +4 -1
- package/echo/half_close_test.rs +178 -0
- package/echo/integration_server.rs +14 -21
- package/echo/main.rs +28 -48
- package/go.mod +1 -1
- package/go.sum +2 -18
- package/integration/cross-language/cpp-client.cpp +446 -402
- package/integration/cross-language/cpp-pipe-server.cpp +139 -0
- package/integration/cross-language/cpp-pipe_test.go +114 -0
- package/integration/cross-language/cpp-server.cpp +222 -186
- package/mock/mock_srpc.pb.cpp +1 -1
- package/mock/mock_srpc.pb.hpp +1 -1
- package/mock/mock_srpc.pb.rs +10 -9
- package/package.json +1 -1
- package/srpc/CMakeLists.txt +3 -58
- package/srpc/README-cpp.md +69 -0
- package/srpc/accept.go +10 -4
- package/srpc/accept_test.go +25 -0
- package/srpc/build.rs +129 -34
- package/srpc/client-half-close_test.go +152 -0
- package/srpc/client-invoker.go +32 -42
- package/srpc/client-invoker_test.go +53 -0
- package/srpc/client-rpc.cpp +65 -80
- package/srpc/client-rpc.go +32 -33
- package/srpc/client-rpc.hpp +52 -38
- package/srpc/client-rpc.test.ts +67 -0
- package/srpc/client-rpc.ts +10 -0
- package/srpc/client-rpc_test.go +76 -0
- package/srpc/client.cpp +99 -87
- package/srpc/client.hpp +46 -35
- package/srpc/client.rs +78 -38
- package/srpc/client_half_close_test.cc +331 -0
- package/srpc/client_invoker.rs +75 -0
- package/srpc/common-rpc.cpp +186 -146
- package/srpc/common-rpc.go +5 -4
- package/srpc/common-rpc.hpp +119 -89
- package/srpc/common-rpc.ts +43 -8
- package/srpc/common-rpc_test.go +23 -0
- package/srpc/error.rs +19 -2
- package/srpc/errors.hpp +80 -50
- package/srpc/errors.ts +16 -0
- package/srpc/handler.hpp +9 -7
- package/srpc/handler.rs +7 -45
- package/srpc/index.ts +2 -0
- package/srpc/invoker.hpp +82 -55
- package/srpc/invoker.rs +14 -52
- package/srpc/lib.rs +2 -0
- package/srpc/message.hpp +17 -12
- package/srpc/msg-stream.go +1 -0
- package/srpc/msg-stream.hpp +108 -61
- package/srpc/mux.cpp +84 -84
- package/srpc/mux.hpp +48 -38
- package/srpc/mux.rs +4 -4
- package/srpc/net.go +12 -3
- package/srpc/packet.cpp +60 -58
- package/srpc/packet.hpp +35 -20
- package/srpc/packet.rs +8 -27
- package/srpc/rpc.rs +332 -115
- package/srpc/rpc_lifecycle_test.cc +333 -0
- package/srpc/server-cancel_test.go +39 -0
- package/srpc/server-rpc.cpp +83 -73
- package/srpc/server-rpc.go +21 -19
- package/srpc/server-rpc.hpp +56 -37
- package/srpc/server.rs +76 -131
- package/srpc/starpc.hpp +4 -2
- package/srpc/stream.go +4 -0
- package/srpc/stream.hpp +95 -34
- package/srpc/stream.rs +7 -2
- package/srpc/testing.rs +11 -66
- package/srpc/transport.rs +21 -71
- package/srpc/websocket.rs +106 -57
- package/srpc/writer.hpp +46 -32
- package/srpc/yamux.rs +82 -26
- package/srpc/tests/integration_test.rs +0 -495
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
//go:build deps_only
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
/*
|
|
4
|
+
* C++ TCP integration client for cross-language testing: it connects to a
|
|
5
|
+
* TCP server and runs the echo test suite over length-prefixed packets.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
#include "echo/echo_srpc.pb.hpp"
|
|
9
|
+
#include "srpc/rpcproto.pb.h"
|
|
10
|
+
#include "srpc/starpc.hpp"
|
|
5
11
|
|
|
6
12
|
#include <arpa/inet.h>
|
|
7
13
|
#include <atomic>
|
|
@@ -15,434 +21,472 @@
|
|
|
15
21
|
#include <thread>
|
|
16
22
|
#include <unistd.h>
|
|
17
23
|
|
|
18
|
-
#include "echo/echo_srpc.pb.hpp"
|
|
19
|
-
#include "srpc/rpcproto.pb.h"
|
|
20
|
-
#include "srpc/starpc.hpp"
|
|
21
|
-
|
|
22
24
|
namespace {
|
|
23
25
|
|
|
24
|
-
const char *
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
bool ReadFull(int fd, void *buf, size_t n)
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
26
|
+
const char *test_body = "hello world via starpc cross-language e2e test";
|
|
27
|
+
|
|
28
|
+
/* ReadFull reads exactly n bytes from fd, reporting short reads as false. */
|
|
29
|
+
bool ReadFull(int fd, void *buf, size_t n)
|
|
30
|
+
{
|
|
31
|
+
size_t total = 0;
|
|
32
|
+
while (total < n) {
|
|
33
|
+
ssize_t r =
|
|
34
|
+
read(fd, static_cast<char *>(buf) + total, n - total);
|
|
35
|
+
if (r <= 0)
|
|
36
|
+
return false;
|
|
37
|
+
total += r;
|
|
38
|
+
}
|
|
39
|
+
return true;
|
|
36
40
|
}
|
|
37
41
|
|
|
38
|
-
|
|
39
|
-
bool WriteFull(int fd, const void *buf, size_t n)
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
42
|
+
/* WriteFull writes exactly n bytes to fd, reporting short writes as false. */
|
|
43
|
+
bool WriteFull(int fd, const void *buf, size_t n)
|
|
44
|
+
{
|
|
45
|
+
size_t total = 0;
|
|
46
|
+
while (total < n) {
|
|
47
|
+
ssize_t w = write(fd, static_cast<const char *>(buf) + total,
|
|
48
|
+
n - total);
|
|
49
|
+
if (w <= 0)
|
|
50
|
+
return false;
|
|
51
|
+
total += w;
|
|
52
|
+
}
|
|
53
|
+
return true;
|
|
48
54
|
}
|
|
49
55
|
|
|
50
|
-
|
|
56
|
+
/*
|
|
57
|
+
* TcpPacketWriter writes length-prefixed packets to a TCP socket. The fd is
|
|
58
|
+
* borrowed and closed by the test, not the writer.
|
|
59
|
+
*/
|
|
51
60
|
class TcpPacketWriter : public starpc::PacketWriter {
|
|
52
61
|
public:
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
62
|
+
explicit TcpPacketWriter(int fd)
|
|
63
|
+
: fd(fd)
|
|
64
|
+
{
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
starpc::Error WritePacket(const srpc::Packet &pkt) override
|
|
68
|
+
{
|
|
69
|
+
std::lock_guard<std::mutex> lock(mu);
|
|
70
|
+
|
|
71
|
+
std::string data;
|
|
72
|
+
if (!pkt.SerializeToString(&data))
|
|
73
|
+
return starpc::Error::InvalidMessage;
|
|
74
|
+
|
|
75
|
+
/* The length prefix is a little-endian uint32. */
|
|
76
|
+
uint32_t len = static_cast<uint32_t>(data.size());
|
|
77
|
+
if (!WriteFull(fd, &len, 4))
|
|
78
|
+
return starpc::Error::EOF_;
|
|
79
|
+
if (!WriteFull(fd, data.data(), data.size()))
|
|
80
|
+
return starpc::Error::EOF_;
|
|
81
|
+
return starpc::Error::OK;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
starpc::Error Close() override
|
|
85
|
+
{
|
|
86
|
+
shutdown(fd, SHUT_WR);
|
|
87
|
+
return starpc::Error::OK;
|
|
88
|
+
}
|
|
73
89
|
|
|
74
90
|
private:
|
|
75
|
-
|
|
76
|
-
|
|
91
|
+
int fd;
|
|
92
|
+
std::mutex mu;
|
|
77
93
|
};
|
|
78
94
|
|
|
79
|
-
|
|
80
|
-
int TcpConnect(const std::string &host, int port)
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
95
|
+
/* TcpConnect opens a connection to host:port, or -1 on failure. */
|
|
96
|
+
int TcpConnect(const std::string &host, int port)
|
|
97
|
+
{
|
|
98
|
+
int fd = socket(AF_INET, SOCK_STREAM, 0);
|
|
99
|
+
if (fd < 0)
|
|
100
|
+
return -1;
|
|
101
|
+
|
|
102
|
+
struct sockaddr_in addr{};
|
|
103
|
+
addr.sin_family = AF_INET;
|
|
104
|
+
addr.sin_port = htons(port);
|
|
105
|
+
inet_pton(AF_INET, host.c_str(), &addr.sin_addr);
|
|
106
|
+
|
|
107
|
+
if (connect(fd, reinterpret_cast<struct sockaddr *>(&addr),
|
|
108
|
+
sizeof(addr)) < 0) {
|
|
109
|
+
close(fd);
|
|
110
|
+
return -1;
|
|
111
|
+
}
|
|
112
|
+
return fd;
|
|
96
113
|
}
|
|
97
114
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
+
/*
|
|
116
|
+
* ReadPacketLoop reads length-prefixed packets and feeds them to rpc until
|
|
117
|
+
* done is set, the socket ends, or the call fails.
|
|
118
|
+
*/
|
|
119
|
+
void ReadPacketLoop(int fd, starpc::ClientRPC *rpc, std::atomic<bool> *done)
|
|
120
|
+
{
|
|
121
|
+
while (!done->load()) {
|
|
122
|
+
uint32_t len = 0;
|
|
123
|
+
if (!ReadFull(fd, &len, 4)) {
|
|
124
|
+
rpc->HandleStreamClose(starpc::Error::EOF_);
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
std::string data(len, '\0');
|
|
128
|
+
if (!ReadFull(fd, data.data(), len)) {
|
|
129
|
+
rpc->HandleStreamClose(starpc::Error::EOF_);
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
starpc::Error err = rpc->HandlePacketData(data);
|
|
133
|
+
if (err != starpc::Error::OK)
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
115
136
|
}
|
|
116
137
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
138
|
+
/*
|
|
139
|
+
* CleanupConn shuts the socket down, joins the reader thread, then closes
|
|
140
|
+
* the fd. The join order avoids an fd reuse race with the reader.
|
|
141
|
+
*/
|
|
142
|
+
void CleanupConn(int fd, std::atomic<bool> &done, std::thread &reader)
|
|
143
|
+
{
|
|
144
|
+
done.store(true);
|
|
145
|
+
shutdown(fd, SHUT_RDWR);
|
|
146
|
+
reader.join();
|
|
147
|
+
close(fd);
|
|
124
148
|
}
|
|
125
149
|
|
|
126
|
-
|
|
127
|
-
bool ParseAddr(const std::string &addr, std::string *host, int *port)
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
150
|
+
/* ParseAddr splits "host:port" into host and port. */
|
|
151
|
+
bool ParseAddr(const std::string &addr, std::string *host, int *port)
|
|
152
|
+
{
|
|
153
|
+
auto pos = addr.rfind(':');
|
|
154
|
+
if (pos == std::string::npos)
|
|
155
|
+
return false;
|
|
156
|
+
*host = addr.substr(0, pos);
|
|
157
|
+
*port = std::stoi(addr.substr(pos + 1));
|
|
158
|
+
return true;
|
|
134
159
|
}
|
|
135
160
|
|
|
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
|
-
|
|
161
|
+
/* TestUnary pins one unary request/reply over TCP. */
|
|
162
|
+
bool TestUnary(const std::string &host, int port)
|
|
163
|
+
{
|
|
164
|
+
std::cout << "Testing Unary RPC... " << std::flush;
|
|
165
|
+
|
|
166
|
+
int fd = TcpConnect(host, port);
|
|
167
|
+
if (fd < 0) {
|
|
168
|
+
std::cerr << "FAILED: connect" << std::endl;
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
auto rpc = starpc::NewClientRPC("echo.Echoer", "Echo");
|
|
173
|
+
auto writer = std::make_unique<TcpPacketWriter>(fd);
|
|
174
|
+
|
|
175
|
+
std::atomic<bool> done{false};
|
|
176
|
+
std::thread reader(ReadPacketLoop, fd, rpc.get(), &done);
|
|
177
|
+
|
|
178
|
+
echo::EchoMsg req;
|
|
179
|
+
req.set_body(test_body);
|
|
180
|
+
std::string req_data;
|
|
181
|
+
req.SerializeToString(&req_data);
|
|
182
|
+
|
|
183
|
+
starpc::Error err = rpc->Start(writer.get(), true, req_data);
|
|
184
|
+
if (err != starpc::Error::OK) {
|
|
185
|
+
std::cerr << "FAILED: start: " << starpc::ErrorString(err)
|
|
186
|
+
<< std::endl;
|
|
187
|
+
CleanupConn(fd, done, reader);
|
|
188
|
+
return false;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
std::string resp_data;
|
|
192
|
+
err = rpc->ReadOne(&resp_data);
|
|
193
|
+
if (err != starpc::Error::OK) {
|
|
194
|
+
std::cerr << "FAILED: read: " << starpc::ErrorString(err)
|
|
195
|
+
<< std::endl;
|
|
196
|
+
rpc->Close();
|
|
197
|
+
CleanupConn(fd, done, reader);
|
|
198
|
+
return false;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
echo::EchoMsg resp;
|
|
202
|
+
if (!resp.ParseFromString(resp_data) || resp.body() != test_body) {
|
|
203
|
+
std::cerr << "FAILED: body mismatch" << std::endl;
|
|
204
|
+
rpc->Close();
|
|
205
|
+
CleanupConn(fd, done, reader);
|
|
206
|
+
return false;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
rpc->Close();
|
|
210
|
+
CleanupConn(fd, done, reader);
|
|
211
|
+
|
|
212
|
+
std::cout << "PASSED" << std::endl;
|
|
213
|
+
return true;
|
|
185
214
|
}
|
|
186
215
|
|
|
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
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
216
|
+
/* TestServerStream pins five streamed responses over TCP. */
|
|
217
|
+
bool TestServerStream(const std::string &host, int port)
|
|
218
|
+
{
|
|
219
|
+
std::cout << "Testing ServerStream RPC... " << std::flush;
|
|
220
|
+
|
|
221
|
+
int fd = TcpConnect(host, port);
|
|
222
|
+
if (fd < 0) {
|
|
223
|
+
std::cerr << "FAILED: connect" << std::endl;
|
|
224
|
+
return false;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
auto rpc = starpc::NewClientRPC("echo.Echoer", "EchoServerStream");
|
|
228
|
+
auto writer = std::make_unique<TcpPacketWriter>(fd);
|
|
229
|
+
|
|
230
|
+
std::atomic<bool> done{false};
|
|
231
|
+
std::thread reader(ReadPacketLoop, fd, rpc.get(), &done);
|
|
232
|
+
|
|
233
|
+
echo::EchoMsg req;
|
|
234
|
+
req.set_body(test_body);
|
|
235
|
+
std::string req_data;
|
|
236
|
+
req.SerializeToString(&req_data);
|
|
237
|
+
|
|
238
|
+
starpc::Error err = rpc->Start(writer.get(), true, req_data);
|
|
239
|
+
if (err != starpc::Error::OK) {
|
|
240
|
+
std::cerr << "FAILED: start" << std::endl;
|
|
241
|
+
CleanupConn(fd, done, reader);
|
|
242
|
+
return false;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
int received = 0;
|
|
246
|
+
for (int i = 0; i < 5; i++) {
|
|
247
|
+
std::string resp_data;
|
|
248
|
+
err = rpc->ReadOne(&resp_data);
|
|
249
|
+
if (err != starpc::Error::OK) {
|
|
250
|
+
std::cerr << "FAILED: read " << i << ": "
|
|
251
|
+
<< starpc::ErrorString(err) << std::endl;
|
|
252
|
+
rpc->Close();
|
|
253
|
+
CleanupConn(fd, done, reader);
|
|
254
|
+
return false;
|
|
255
|
+
}
|
|
256
|
+
echo::EchoMsg resp;
|
|
257
|
+
if (!resp.ParseFromString(resp_data) ||
|
|
258
|
+
resp.body() != test_body) {
|
|
259
|
+
std::cerr << "FAILED: body mismatch at " << i
|
|
260
|
+
<< std::endl;
|
|
261
|
+
rpc->Close();
|
|
262
|
+
CleanupConn(fd, done, reader);
|
|
263
|
+
return false;
|
|
264
|
+
}
|
|
265
|
+
received++;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
rpc->Close();
|
|
269
|
+
CleanupConn(fd, done, reader);
|
|
270
|
+
|
|
271
|
+
if (received != 5) {
|
|
272
|
+
std::cerr << "FAILED: expected 5, got " << received
|
|
273
|
+
<< std::endl;
|
|
274
|
+
return false;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
std::cout << "PASSED" << std::endl;
|
|
278
|
+
return true;
|
|
245
279
|
}
|
|
246
280
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
281
|
+
/* TestClientStream pins one reply to a streamed request over TCP. */
|
|
282
|
+
bool TestClientStream(const std::string &host, int port)
|
|
283
|
+
{
|
|
284
|
+
std::cout << "Testing ClientStream RPC... " << std::flush;
|
|
285
|
+
|
|
286
|
+
int fd = TcpConnect(host, port);
|
|
287
|
+
if (fd < 0) {
|
|
288
|
+
std::cerr << "FAILED: connect" << std::endl;
|
|
289
|
+
return false;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
auto rpc = starpc::NewClientRPC("echo.Echoer", "EchoClientStream");
|
|
293
|
+
auto writer = std::make_unique<TcpPacketWriter>(fd);
|
|
294
|
+
|
|
295
|
+
std::atomic<bool> done{false};
|
|
296
|
+
std::thread reader(ReadPacketLoop, fd, rpc.get(), &done);
|
|
297
|
+
|
|
298
|
+
starpc::Error err = rpc->Start(writer.get(), false, "");
|
|
299
|
+
if (err != starpc::Error::OK) {
|
|
300
|
+
std::cerr << "FAILED: start" << std::endl;
|
|
301
|
+
CleanupConn(fd, done, reader);
|
|
302
|
+
return false;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
echo::EchoMsg req;
|
|
306
|
+
req.set_body(test_body);
|
|
307
|
+
std::string req_data;
|
|
308
|
+
req.SerializeToString(&req_data);
|
|
309
|
+
|
|
310
|
+
err = rpc->WriteCallData(req_data, false, false, starpc::Error::OK);
|
|
311
|
+
if (err != starpc::Error::OK) {
|
|
312
|
+
std::cerr << "FAILED: write" << std::endl;
|
|
313
|
+
CleanupConn(fd, done, reader);
|
|
314
|
+
return false;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
err = rpc->WriteCallData("", false, true, starpc::Error::OK);
|
|
318
|
+
if (err != starpc::Error::OK) {
|
|
319
|
+
std::cerr << "FAILED: close send" << std::endl;
|
|
320
|
+
CleanupConn(fd, done, reader);
|
|
321
|
+
return false;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
std::string resp_data;
|
|
325
|
+
err = rpc->ReadOne(&resp_data);
|
|
326
|
+
if (err != starpc::Error::OK) {
|
|
327
|
+
std::cerr << "FAILED: read: " << starpc::ErrorString(err)
|
|
328
|
+
<< std::endl;
|
|
329
|
+
rpc->Close();
|
|
330
|
+
CleanupConn(fd, done, reader);
|
|
331
|
+
return false;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
echo::EchoMsg resp;
|
|
335
|
+
if (!resp.ParseFromString(resp_data) || resp.body() != test_body) {
|
|
336
|
+
std::cerr << "FAILED: body mismatch" << std::endl;
|
|
337
|
+
rpc->Close();
|
|
338
|
+
CleanupConn(fd, done, reader);
|
|
339
|
+
return false;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
rpc->Close();
|
|
343
|
+
CleanupConn(fd, done, reader);
|
|
344
|
+
|
|
345
|
+
std::cout << "PASSED" << std::endl;
|
|
346
|
+
return true;
|
|
310
347
|
}
|
|
311
348
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
349
|
+
/* TestBidiStream pins echo replies to each sent message over TCP. */
|
|
350
|
+
bool TestBidiStream(const std::string &host, int port)
|
|
351
|
+
{
|
|
352
|
+
std::cout << "Testing BidiStream RPC... " << std::flush;
|
|
353
|
+
|
|
354
|
+
int fd = TcpConnect(host, port);
|
|
355
|
+
if (fd < 0) {
|
|
356
|
+
std::cerr << "FAILED: connect" << std::endl;
|
|
357
|
+
return false;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
auto rpc = starpc::NewClientRPC("echo.Echoer", "EchoBidiStream");
|
|
361
|
+
auto writer = std::make_unique<TcpPacketWriter>(fd);
|
|
362
|
+
|
|
363
|
+
std::atomic<bool> done{false};
|
|
364
|
+
std::thread reader(ReadPacketLoop, fd, rpc.get(), &done);
|
|
365
|
+
|
|
366
|
+
starpc::Error err = rpc->Start(writer.get(), false, "");
|
|
367
|
+
if (err != starpc::Error::OK) {
|
|
368
|
+
std::cerr << "FAILED: start" << std::endl;
|
|
369
|
+
CleanupConn(fd, done, reader);
|
|
370
|
+
return false;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/* Receive initial "hello from server" message. */
|
|
374
|
+
std::string init_data;
|
|
375
|
+
err = rpc->ReadOne(&init_data);
|
|
376
|
+
if (err != starpc::Error::OK) {
|
|
377
|
+
std::cerr << "FAILED: read init: " << starpc::ErrorString(err)
|
|
378
|
+
<< std::endl;
|
|
379
|
+
rpc->Close();
|
|
380
|
+
CleanupConn(fd, done, reader);
|
|
381
|
+
return false;
|
|
382
|
+
}
|
|
383
|
+
echo::EchoMsg init_msg;
|
|
384
|
+
if (!init_msg.ParseFromString(init_data) ||
|
|
385
|
+
init_msg.body() != "hello from server") {
|
|
386
|
+
std::cerr << "FAILED: init body mismatch: '" << init_msg.body()
|
|
387
|
+
<< "'" << std::endl;
|
|
388
|
+
rpc->Close();
|
|
389
|
+
CleanupConn(fd, done, reader);
|
|
390
|
+
return false;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/* Send a message and expect echo. */
|
|
394
|
+
echo::EchoMsg req;
|
|
395
|
+
req.set_body(test_body);
|
|
396
|
+
std::string req_data;
|
|
397
|
+
req.SerializeToString(&req_data);
|
|
398
|
+
|
|
399
|
+
err = rpc->WriteCallData(req_data, false, false, starpc::Error::OK);
|
|
400
|
+
if (err != starpc::Error::OK) {
|
|
401
|
+
std::cerr << "FAILED: write" << std::endl;
|
|
402
|
+
rpc->Close();
|
|
403
|
+
CleanupConn(fd, done, reader);
|
|
404
|
+
return false;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
std::string resp_data;
|
|
408
|
+
err = rpc->ReadOne(&resp_data);
|
|
409
|
+
if (err != starpc::Error::OK) {
|
|
410
|
+
std::cerr << "FAILED: read echo: " << starpc::ErrorString(err)
|
|
411
|
+
<< std::endl;
|
|
412
|
+
rpc->Close();
|
|
413
|
+
CleanupConn(fd, done, reader);
|
|
414
|
+
return false;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
echo::EchoMsg resp;
|
|
418
|
+
if (!resp.ParseFromString(resp_data) || resp.body() != test_body) {
|
|
419
|
+
std::cerr << "FAILED: echo body mismatch" << std::endl;
|
|
420
|
+
rpc->Close();
|
|
421
|
+
CleanupConn(fd, done, reader);
|
|
422
|
+
return false;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/* Close send. */
|
|
426
|
+
err = rpc->WriteCallData("", false, true, starpc::Error::OK);
|
|
427
|
+
if (err != starpc::Error::OK) {
|
|
428
|
+
std::cerr << "FAILED: close send" << std::endl;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
rpc->Close();
|
|
432
|
+
CleanupConn(fd, done, reader);
|
|
433
|
+
|
|
434
|
+
std::cout << "PASSED" << std::endl;
|
|
435
|
+
return true;
|
|
395
436
|
}
|
|
396
437
|
|
|
397
438
|
} // namespace
|
|
398
439
|
|
|
399
|
-
int main(int argc, char *argv[])
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
440
|
+
int main(int argc, char *argv[])
|
|
441
|
+
{
|
|
442
|
+
/*
|
|
443
|
+
* Ignore SIGPIPE so writing to a closed socket returns EPIPE instead
|
|
444
|
+
* of killing the process: the server may close its side before the
|
|
445
|
+
* cleanup packets are sent.
|
|
446
|
+
*/
|
|
447
|
+
signal(SIGPIPE, SIG_IGN);
|
|
448
|
+
|
|
449
|
+
if (argc < 2) {
|
|
450
|
+
std::cerr << "usage: cpp-client <host:port>" << std::endl;
|
|
451
|
+
return 1;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
std::string host;
|
|
455
|
+
int port;
|
|
456
|
+
if (!ParseAddr(argv[1], &host, &port)) {
|
|
457
|
+
std::cerr << "invalid address: " << argv[1] << std::endl;
|
|
458
|
+
return 1;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
std::cout << "=== starpc C++ Cross-Language Client ===" << std::endl;
|
|
462
|
+
|
|
463
|
+
int passed = 0, failed = 0;
|
|
464
|
+
|
|
465
|
+
if (TestUnary(host, port))
|
|
466
|
+
passed++;
|
|
467
|
+
else
|
|
468
|
+
failed++;
|
|
469
|
+
if (TestServerStream(host, port))
|
|
470
|
+
passed++;
|
|
471
|
+
else
|
|
472
|
+
failed++;
|
|
473
|
+
if (TestClientStream(host, port))
|
|
474
|
+
passed++;
|
|
475
|
+
else
|
|
476
|
+
failed++;
|
|
477
|
+
if (TestBidiStream(host, port))
|
|
478
|
+
passed++;
|
|
479
|
+
else
|
|
480
|
+
failed++;
|
|
481
|
+
|
|
482
|
+
std::cout << std::endl
|
|
483
|
+
<< "Results: " << passed << " passed, " << failed << " failed"
|
|
484
|
+
<< std::endl;
|
|
485
|
+
|
|
486
|
+
if (failed > 0) {
|
|
487
|
+
std::cout << "FAILED" << std::endl;
|
|
488
|
+
return 1;
|
|
489
|
+
}
|
|
490
|
+
std::cout << "All tests passed." << std::endl;
|
|
491
|
+
return 0;
|
|
448
492
|
}
|