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