]> git.proxmox.com Git - ceph.git/blame - ceph/src/spdk/test/rpc_client/rpc_client_test.c
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / spdk / test / rpc_client / rpc_client_test.c
CommitLineData
11fdf7f2
TL
1/*-
2 * BSD LICENSE
3 *
4 * Copyright (c) Intel Corporation.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * * Neither the name of Intel Corporation nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#include "spdk/stdinc.h"
35#include "spdk/event.h"
36#include "spdk/jsonrpc.h"
9f95a23c
TL
37#include "spdk/util.h"
38#include "spdk/rpc.h"
39
11fdf7f2
TL
40
41#define RPC_MAX_METHODS 200
9f95a23c 42#define JOIN_TIMEOUT_S 1
11fdf7f2
TL
43
44static const char *g_rpcsock_addr = SPDK_DEFAULT_RPC_ADDR;
45static int g_addr_family = AF_UNIX;
46
47#define RPC_MAX_METHODS 200
48
49struct get_jsonrpc_methods_resp {
50 char *method_names[RPC_MAX_METHODS];
51 size_t method_num;
52};
53
54static int
9f95a23c 55_rpc_client_wait_for_response(struct spdk_jsonrpc_client *client)
11fdf7f2 56{
9f95a23c
TL
57 int rc;
58
59 do {
60 rc = spdk_jsonrpc_client_poll(client, 1);
61 } while (rc == 0 || rc == -ENOTCONN);
62
63 if (rc <= 0) {
64 SPDK_ERRLOG("Failed to get response: %d\n", rc);
65 }
66
67 return rc;
68}
11fdf7f2 69
9f95a23c
TL
70static int
71get_jsonrpc_method_json_parser(struct get_jsonrpc_methods_resp *resp,
72 const struct spdk_json_val *result)
73{
11fdf7f2
TL
74 return spdk_json_decode_array(result, spdk_json_decode_string, resp->method_names,
75 RPC_MAX_METHODS, &resp->method_num, sizeof(char *));
76}
77
78static int
79spdk_jsonrpc_client_check_rpc_method(struct spdk_jsonrpc_client *client, char *method_name)
80{
81 int rc, i;
9f95a23c 82 struct spdk_jsonrpc_client_response *json_resp = NULL;
11fdf7f2
TL
83 struct get_jsonrpc_methods_resp resp = {};
84 struct spdk_json_write_ctx *w;
85 struct spdk_jsonrpc_client_request *request;
86
87 request = spdk_jsonrpc_client_create_request();
88 if (request == NULL) {
89 return -ENOMEM;
90 }
91
9f95a23c 92 w = spdk_jsonrpc_begin_request(request, 1, "rpc_get_methods");
11fdf7f2
TL
93 spdk_jsonrpc_end_request(request, w);
94 spdk_jsonrpc_client_send_request(client, request);
11fdf7f2 95
9f95a23c
TL
96 rc = _rpc_client_wait_for_response(client);
97 if (rc <= 0) {
98 goto out;
99 }
100
101 json_resp = spdk_jsonrpc_client_get_response(client);
102 if (json_resp == NULL) {
103 SPDK_ERRLOG("spdk_jsonrpc_client_get_response() failed\n");
104 rc = -1;
105 goto out;
106
107 }
108
109 /* Check for error response */
110 if (json_resp->error != NULL) {
111 SPDK_ERRLOG("Unexpected error response\n");
112 rc = -1;
113 goto out;
114 }
11fdf7f2 115
9f95a23c
TL
116 assert(json_resp->result);
117
118 rc = get_jsonrpc_method_json_parser(&resp, json_resp->result);
11fdf7f2 119 if (rc) {
9f95a23c 120 SPDK_ERRLOG("get_jsonrpc_method_json_parser() failed\n");
11fdf7f2
TL
121 goto out;
122 }
123
124 for (i = 0; i < (int)resp.method_num; i++) {
125 if (strcmp(method_name, resp.method_names[i]) == 0) {
126 rc = 0;
127 goto out;
128 }
129 }
130
131 rc = -1;
9f95a23c 132 SPDK_ERRLOG("Method '%s' not found in response\n", method_name);
11fdf7f2
TL
133
134out:
135 for (i = 0; i < (int)resp.method_num; i++) {
136 SPDK_NOTICELOG("%s\n", resp.method_names[i]);
137 free(resp.method_names[i]);
138 }
139
9f95a23c 140 spdk_jsonrpc_client_free_response(json_resp);
11fdf7f2
TL
141 return rc;
142}
143
f67539c2
TL
144static int
145spdk_jsonrpc_client_check_null_params_method(struct spdk_jsonrpc_client *client)
146{
147 int rc;
148 bool res = false;
149 struct spdk_jsonrpc_client_response *json_resp = NULL;
150 struct spdk_json_write_ctx *w;
151 struct spdk_jsonrpc_client_request *request;
152
153 request = spdk_jsonrpc_client_create_request();
154 if (request == NULL) {
155 return -ENOMEM;
156 }
157
158 w = spdk_jsonrpc_begin_request(request, 1, "test_null_params");
159 spdk_json_write_name(w, "params");
160 spdk_json_write_null(w);
161 spdk_jsonrpc_end_request(request, w);
162 spdk_jsonrpc_client_send_request(client, request);
163
164 rc = _rpc_client_wait_for_response(client);
165 if (rc <= 0) {
166 goto out;
167 }
168
169 json_resp = spdk_jsonrpc_client_get_response(client);
170 if (json_resp == NULL) {
171 SPDK_ERRLOG("spdk_jsonrpc_client_get_response() failed\n");
172 rc = -1;
173 goto out;
174
175 }
176
177 /* Check for error response */
178 if (json_resp->error != NULL) {
179 SPDK_ERRLOG("Unexpected error response\n");
180 rc = -1;
181 goto out;
182 }
183
184 assert(json_resp->result);
185
186 if (spdk_json_decode_bool(json_resp->result, &res) != 0 || res != true) {
187 SPDK_ERRLOG("Response is not a boolean or it is not 'true'\n");
188 rc = -EINVAL;
189 goto out;
190 } else {
191 rc = 0;
192 }
193
194out:
195 spdk_jsonrpc_client_free_response(json_resp);
196 return rc;
197}
198
9f95a23c
TL
199static void
200rpc_test_method_startup(struct spdk_jsonrpc_request *request, const struct spdk_json_val *params)
201{
202 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
203 "rpc_test_method_startup(): Method body not implemented");
204}
205SPDK_RPC_REGISTER("test_method_startup", rpc_test_method_startup, SPDK_RPC_STARTUP)
206
207static void
208rpc_test_method_runtime(struct spdk_jsonrpc_request *request, const struct spdk_json_val *params)
209{
210 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
211 "rpc_test_method_runtime(): Method body not implemented");
212}
213SPDK_RPC_REGISTER("test_method_runtime", rpc_test_method_runtime, SPDK_RPC_RUNTIME)
214
f67539c2
TL
215static void
216rpc_test_method_null_params(struct spdk_jsonrpc_request *request,
217 const struct spdk_json_val *params)
218{
219 struct spdk_json_write_ctx *w;
220
221 if (params != NULL) {
222 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
223 "rpc_test_method_null_params(): Parameters are not NULL");
224 return;
225 }
226 w = spdk_jsonrpc_begin_result(request);
227 assert(w != NULL);
228 spdk_json_write_bool(w, true);
229 spdk_jsonrpc_end_result(request, w);
230}
231SPDK_RPC_REGISTER("test_null_params", rpc_test_method_null_params, SPDK_RPC_RUNTIME)
232
9f95a23c
TL
233static bool g_conn_close_detected;
234
235static void
236rpc_test_conn_close_cb(struct spdk_jsonrpc_server_conn *conn, void *ctx)
11fdf7f2 237{
9f95a23c
TL
238 assert((intptr_t)ctx == 42);
239 g_conn_close_detected = true;
240}
241
242static void
243rpc_hook_conn_close(struct spdk_jsonrpc_request *request, const struct spdk_json_val *params)
244{
245 struct spdk_jsonrpc_server_conn *conn = spdk_jsonrpc_get_conn(request);
246 struct spdk_json_write_ctx *w;
11fdf7f2 247 int rc;
9f95a23c
TL
248
249 rc = spdk_jsonrpc_conn_add_close_cb(conn, rpc_test_conn_close_cb, (void *)(intptr_t)(42));
250 if (rc != 0) {
251
252 rc = spdk_jsonrpc_conn_add_close_cb(conn, rpc_test_conn_close_cb, (void *)(intptr_t)(42));
253 assert(rc == -ENOSPC);
254 }
255
256 rc = spdk_jsonrpc_conn_add_close_cb(conn, rpc_test_conn_close_cb, (void *)(intptr_t)(42));
257 if (rc != -EEXIST) {
258 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
259 "rpc_test_method_conn_close_detect(): rc != -EEXIST");
260 return;
261 }
262
263 rc = spdk_jsonrpc_conn_add_close_cb(conn, rpc_test_conn_close_cb, (void *)(intptr_t)(43));
264 if (rc != -ENOSPC) {
265 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
266 "rpc_test_method_conn_close_detect(): rc != -ENOSPC");
267 return;
268 }
269
270 w = spdk_jsonrpc_begin_result(request);
271 assert(w != NULL);
272 spdk_json_write_bool(w, true);
273 spdk_jsonrpc_end_result(request, w);
274
275}
276SPDK_RPC_REGISTER("hook_conn_close", rpc_hook_conn_close, SPDK_RPC_RUNTIME | SPDK_RPC_STARTUP)
277
278static int
279spdk_jsonrpc_client_hook_conn_close(struct spdk_jsonrpc_client *client)
280{
281 int rc;
282 bool res = false;
283 struct spdk_jsonrpc_client_response *json_resp = NULL;
284 struct spdk_json_write_ctx *w;
285 struct spdk_jsonrpc_client_request *request;
286
287 request = spdk_jsonrpc_client_create_request();
288 if (request == NULL) {
289 return -ENOMEM;
290 }
291
292 w = spdk_jsonrpc_begin_request(request, 1, "hook_conn_close");
293 spdk_jsonrpc_end_request(request, w);
294 spdk_jsonrpc_client_send_request(client, request);
295
296 rc = _rpc_client_wait_for_response(client);
297 if (rc <= 0) {
298 goto out;
299 }
300
301 json_resp = spdk_jsonrpc_client_get_response(client);
302 if (json_resp == NULL) {
303 SPDK_ERRLOG("spdk_jsonrpc_client_get_response() failed\n");
304 rc = -errno;
305 goto out;
306
307 }
308
309 /* Check for error response */
310 if (json_resp->error != NULL) {
f67539c2 311 SPDK_ERRLOG("Unexpected error response: %.*s\n", json_resp->error->len,
9f95a23c
TL
312 (char *)json_resp->error->start);
313 rc = -EIO;
314 goto out;
315 }
316
317 assert(json_resp->result);
318 if (spdk_json_decode_bool(json_resp->result, &res) != 0 || res != true) {
319 SPDK_ERRLOG("Response is not and boolean or if not 'true'\n");
320 rc = -EINVAL;
321 goto out;
322 }
323
324 rc = 0;
325out:
326 spdk_jsonrpc_client_free_response(json_resp);
327 return rc;
328}
329
9f95a23c
TL
330volatile int g_rpc_server_th_stop;
331static sem_t g_rpc_server_th_listening;
9f95a23c
TL
332
333static void *
334rpc_server_th(void *arg)
335{
336 int rc;
337
338 rc = spdk_rpc_listen(g_rpcsock_addr);
339 if (rc) {
340 fprintf(stderr, "spdk_rpc_listen() failed: %d\n", rc);
f67539c2 341 sem_post(&g_rpc_server_th_listening);
9f95a23c
TL
342 goto out;
343 }
344
345 sem_post(&g_rpc_server_th_listening);
346
347 while (!g_rpc_server_th_stop) {
348 spdk_rpc_accept();
349 usleep(50);
350 }
351
352 spdk_rpc_close();
353out:
9f95a23c
TL
354 return (void *)(intptr_t)rc;
355}
356
9f95a23c
TL
357static void *
358rpc_client_th(void *arg)
359{
360 struct spdk_jsonrpc_client *client = NULL;
361 char *method_name = "rpc_get_methods";
362 int rc;
363
364
f67539c2 365 rc = sem_wait(&g_rpc_server_th_listening);
9f95a23c
TL
366 if (rc == -1) {
367 fprintf(stderr, "Timeout waiting for server thread to start listening: rc=%d errno=%d\n", rc,
368 errno);
369 goto out;
370 }
11fdf7f2
TL
371
372 client = spdk_jsonrpc_client_connect(g_rpcsock_addr, g_addr_family);
373 if (!client) {
9f95a23c
TL
374 fprintf(stderr, "spdk_jsonrpc_client_connect() failed: %d\n", errno);
375 rc = -1;
376 goto out;
11fdf7f2
TL
377 }
378
379 rc = spdk_jsonrpc_client_check_rpc_method(client, method_name);
9f95a23c
TL
380 if (rc) {
381 fprintf(stderr, "spdk_jsonrpc_client_check_rpc_method() failed: rc=%d errno=%d\n", rc, errno);
382 goto out;
383 }
384
f67539c2
TL
385 rc = spdk_jsonrpc_client_check_null_params_method(client);
386 if (rc) {
387 fprintf(stderr, "spdk_jsonrpc_client_null_params_method() failed: rc=%d errno=%d\n", rc, errno);
388 goto out;
389 }
390
9f95a23c
TL
391 rc = spdk_jsonrpc_client_hook_conn_close(client);
392 if (rc) {
393 fprintf(stderr, "spdk_jsonrpc_client_hook_conn_close() failed: rc=%d errno=%d\n", rc, errno);
394 goto out;
395 }
396
397out:
398 if (client) {
399 spdk_jsonrpc_client_close(client);
400 }
401
9f95a23c
TL
402 return (void *)(intptr_t)rc;
403}
404
405int main(int argc, char **argv)
406{
407 pthread_t srv_tid, client_tid;
408 int srv_tid_valid;
409 int client_tid_valid = -1;
410 intptr_t th_rc = INTPTR_MIN;
411 int rc = 0, err_cnt = 0;
412
413 sem_init(&g_rpc_server_th_listening, 0, 0);
9f95a23c
TL
414
415 srv_tid_valid = pthread_create(&srv_tid, NULL, rpc_server_th, NULL);
416 if (srv_tid_valid != 0) {
417 fprintf(stderr, "pthread_create() failed to create server thread: %d\n", srv_tid_valid);
418 goto out;
419 }
420
421 client_tid_valid = pthread_create(&client_tid, NULL, rpc_client_th, NULL);
422 if (client_tid_valid != 0) {
423 fprintf(stderr, "pthread_create(): failed to create client thread: %d\n", client_tid_valid);
424 goto out;
425 }
426
427out:
428 if (client_tid_valid == 0) {
9f95a23c
TL
429 rc = pthread_join(client_tid, (void **)&th_rc);
430 if (rc) {
f67539c2 431 fprintf(stderr, "pthread_join() on client thread failed (rc: %d)\n", rc);
9f95a23c
TL
432 err_cnt++;
433 } else if (th_rc) {
f67539c2 434 fprintf(stderr, "client thread failed reported failure(thread rc: %d)\n", (int)th_rc);
9f95a23c
TL
435 err_cnt++;
436 }
437 }
438
439 g_rpc_server_th_stop = 1;
440
441 if (srv_tid_valid == 0) {
9f95a23c
TL
442 rc = pthread_join(srv_tid, (void **)&th_rc);
443 if (rc) {
f67539c2 444 fprintf(stderr, "pthread_join() on server thread failed (rc: %d)\n", rc);
9f95a23c
TL
445 err_cnt++;
446 } else if (th_rc) {
f67539c2 447 fprintf(stderr, "server thread failed reported failure(thread rc: %d)\n", (int)th_rc);
9f95a23c
TL
448 err_cnt++;
449 }
450 }
451
452 if (g_conn_close_detected == false) {
453 fprintf(stderr, "Connection close not detected\n");
454 err_cnt++;
455 }
11fdf7f2 456
9f95a23c 457 sem_destroy(&g_rpc_server_th_listening);
11fdf7f2 458
9f95a23c
TL
459 fprintf(stderr, "%s\n", err_cnt == 0 ? "OK" : "FAILED");
460 return err_cnt ? EXIT_FAILURE : 0;
11fdf7f2 461}