Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2018 Intel Corporation.
3 : : * All rights reserved.
4 : : */
5 : :
6 : : #include "spdk/stdinc.h"
7 : : #include "spdk/event.h"
8 : : #include "spdk/jsonrpc.h"
9 : : #include "spdk/util.h"
10 : : #include "spdk/rpc.h"
11 : :
12 : :
13 : : #define RPC_MAX_METHODS 200
14 : : #define JOIN_TIMEOUT_S 1
15 : :
16 : : static const char *g_rpcsock_addr = SPDK_DEFAULT_RPC_ADDR;
17 : : static int g_addr_family = AF_UNIX;
18 : :
19 : : #define RPC_MAX_METHODS 200
20 : :
21 : : struct get_jsonrpc_methods_resp {
22 : : char *method_names[RPC_MAX_METHODS];
23 : : size_t method_num;
24 : : };
25 : :
26 : : static int
27 : 2588 : _rpc_client_wait_for_response(struct spdk_jsonrpc_client *client)
28 : : {
29 : : int rc;
30 : :
31 : : do {
32 : 9923 : rc = spdk_jsonrpc_client_poll(client, 1);
33 [ + + - + ]: 9923 : } while (rc == 0 || rc == -ENOTCONN);
34 : :
35 [ - + ]: 63 : if (rc <= 0) {
36 : 0 : SPDK_ERRLOG("Failed to get response: %d\n", rc);
37 : : }
38 : :
39 : 63 : return rc;
40 : : }
41 : :
42 : : static int
43 : 21 : get_jsonrpc_method_json_parser(struct get_jsonrpc_methods_resp *resp,
44 : : const struct spdk_json_val *result)
45 : : {
46 : 21 : return spdk_json_decode_array(result, spdk_json_decode_string, resp->method_names,
47 : : RPC_MAX_METHODS, &resp->method_num, sizeof(char *));
48 : : }
49 : :
50 : : static int
51 : 21 : spdk_jsonrpc_client_check_rpc_method(struct spdk_jsonrpc_client *client, char *method_name)
52 : : {
53 : : int rc, i;
54 : 21 : struct spdk_jsonrpc_client_response *json_resp = NULL;
55 : 21 : struct get_jsonrpc_methods_resp resp = {};
56 : : struct spdk_json_write_ctx *w;
57 : : struct spdk_jsonrpc_client_request *request;
58 : :
59 : 21 : request = spdk_jsonrpc_client_create_request();
60 [ - + ]: 21 : if (request == NULL) {
61 : 0 : return -ENOMEM;
62 : : }
63 : :
64 : 21 : w = spdk_jsonrpc_begin_request(request, 1, "rpc_get_methods");
65 : 21 : spdk_jsonrpc_end_request(request, w);
66 : 21 : spdk_jsonrpc_client_send_request(client, request);
67 : :
68 : 21 : rc = _rpc_client_wait_for_response(client);
69 [ - + ]: 21 : if (rc <= 0) {
70 : 0 : goto out;
71 : : }
72 : :
73 : 21 : json_resp = spdk_jsonrpc_client_get_response(client);
74 [ - + ]: 21 : if (json_resp == NULL) {
75 : 0 : SPDK_ERRLOG("spdk_jsonrpc_client_get_response() failed\n");
76 : 0 : rc = -1;
77 : 0 : goto out;
78 : :
79 : : }
80 : :
81 : : /* Check for error response */
82 [ - + ]: 21 : if (json_resp->error != NULL) {
83 : 0 : SPDK_ERRLOG("Unexpected error response\n");
84 : 0 : rc = -1;
85 : 0 : goto out;
86 : : }
87 : :
88 [ - + ]: 21 : assert(json_resp->result);
89 : :
90 : 21 : rc = get_jsonrpc_method_json_parser(&resp, json_resp->result);
91 [ - + ]: 21 : if (rc) {
92 : 0 : SPDK_ERRLOG("get_jsonrpc_method_json_parser() failed\n");
93 : 0 : goto out;
94 : : }
95 : :
96 [ + - ]: 110 : for (i = 0; i < (int)resp.method_num; i++) {
97 [ + + - + : 110 : if (strcmp(method_name, resp.method_names[i]) == 0) {
+ + ]
98 : 21 : rc = 0;
99 : 21 : goto out;
100 : : }
101 : : }
102 : :
103 : 0 : rc = -1;
104 : 0 : SPDK_ERRLOG("Method '%s' not found in response\n", method_name);
105 : :
106 : 21 : out:
107 [ + + ]: 147 : for (i = 0; i < (int)resp.method_num; i++) {
108 : 126 : SPDK_NOTICELOG("%s\n", resp.method_names[i]);
109 : 126 : free(resp.method_names[i]);
110 : : }
111 : :
112 : 21 : spdk_jsonrpc_client_free_response(json_resp);
113 : 21 : return rc;
114 : : }
115 : :
116 : : static int
117 : 21 : spdk_jsonrpc_client_check_null_params_method(struct spdk_jsonrpc_client *client)
118 : : {
119 : : int rc;
120 : 21 : bool res = false;
121 : 21 : struct spdk_jsonrpc_client_response *json_resp = NULL;
122 : : struct spdk_json_write_ctx *w;
123 : : struct spdk_jsonrpc_client_request *request;
124 : :
125 : 21 : request = spdk_jsonrpc_client_create_request();
126 [ - + ]: 21 : if (request == NULL) {
127 : 0 : return -ENOMEM;
128 : : }
129 : :
130 : 21 : w = spdk_jsonrpc_begin_request(request, 1, "test_null_params");
131 : 21 : spdk_json_write_name(w, "params");
132 : 21 : spdk_json_write_null(w);
133 : 21 : spdk_jsonrpc_end_request(request, w);
134 : 21 : spdk_jsonrpc_client_send_request(client, request);
135 : :
136 : 21 : rc = _rpc_client_wait_for_response(client);
137 [ - + ]: 21 : if (rc <= 0) {
138 : 0 : goto out;
139 : : }
140 : :
141 : 21 : json_resp = spdk_jsonrpc_client_get_response(client);
142 [ - + ]: 21 : if (json_resp == NULL) {
143 : 0 : SPDK_ERRLOG("spdk_jsonrpc_client_get_response() failed\n");
144 : 0 : rc = -1;
145 : 0 : goto out;
146 : :
147 : : }
148 : :
149 : : /* Check for error response */
150 [ - + ]: 21 : if (json_resp->error != NULL) {
151 : 0 : SPDK_ERRLOG("Unexpected error response\n");
152 : 0 : rc = -1;
153 : 0 : goto out;
154 : : }
155 : :
156 [ - + ]: 21 : assert(json_resp->result);
157 : :
158 [ + - - + : 21 : if (spdk_json_decode_bool(json_resp->result, &res) != 0 || res != true) {
- + ]
159 : 0 : SPDK_ERRLOG("Response is not a boolean or it is not 'true'\n");
160 : 0 : rc = -EINVAL;
161 : 0 : goto out;
162 : : } else {
163 : 21 : rc = 0;
164 : : }
165 : :
166 : 21 : out:
167 : 21 : spdk_jsonrpc_client_free_response(json_resp);
168 : 21 : return rc;
169 : : }
170 : :
171 : : static void
172 : 0 : rpc_test_method_startup(struct spdk_jsonrpc_request *request, const struct spdk_json_val *params)
173 : : {
174 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
175 : : "rpc_test_method_startup(): Method body not implemented");
176 : 0 : }
177 : 21 : SPDK_RPC_REGISTER("test_method_startup", rpc_test_method_startup, SPDK_RPC_STARTUP)
178 : :
179 : : static void
180 : 0 : rpc_test_method_runtime(struct spdk_jsonrpc_request *request, const struct spdk_json_val *params)
181 : : {
182 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
183 : : "rpc_test_method_runtime(): Method body not implemented");
184 : 0 : }
185 : 21 : SPDK_RPC_REGISTER("test_method_runtime", rpc_test_method_runtime, SPDK_RPC_RUNTIME)
186 : :
187 : : static void
188 : 21 : rpc_test_method_null_params(struct spdk_jsonrpc_request *request,
189 : : const struct spdk_json_val *params)
190 : : {
191 [ - + ]: 21 : if (params != NULL) {
192 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
193 : : "rpc_test_method_null_params(): Parameters are not NULL");
194 : 0 : return;
195 : : }
196 : :
197 : 21 : spdk_jsonrpc_send_bool_response(request, true);
198 : : }
199 : 21 : SPDK_RPC_REGISTER("test_null_params", rpc_test_method_null_params,
200 : : SPDK_RPC_STARTUP | SPDK_RPC_RUNTIME)
201 : :
202 : : static bool g_conn_close_detected;
203 : :
204 : : static void
205 : 21 : rpc_test_conn_close_cb(struct spdk_jsonrpc_server_conn *conn, void *ctx)
206 : : {
207 [ - + ]: 21 : assert((intptr_t)ctx == 42);
208 : 21 : g_conn_close_detected = true;
209 : 21 : }
210 : :
211 : : static void
212 : 21 : rpc_hook_conn_close(struct spdk_jsonrpc_request *request, const struct spdk_json_val *params)
213 : : {
214 : 21 : struct spdk_jsonrpc_server_conn *conn = spdk_jsonrpc_get_conn(request);
215 : : int rc;
216 : :
217 : 21 : rc = spdk_jsonrpc_conn_add_close_cb(conn, rpc_test_conn_close_cb, (void *)(intptr_t)(42));
218 [ - + ]: 21 : if (rc != 0) {
219 : :
220 : 0 : rc = spdk_jsonrpc_conn_add_close_cb(conn, rpc_test_conn_close_cb, (void *)(intptr_t)(42));
221 [ # # ]: 0 : assert(rc == -ENOSPC);
222 : : }
223 : :
224 : 21 : rc = spdk_jsonrpc_conn_add_close_cb(conn, rpc_test_conn_close_cb, (void *)(intptr_t)(42));
225 [ - + ]: 21 : if (rc != -EEXIST) {
226 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
227 : : "rpc_test_method_conn_close_detect(): rc != -EEXIST");
228 : 0 : return;
229 : : }
230 : :
231 : 21 : rc = spdk_jsonrpc_conn_add_close_cb(conn, rpc_test_conn_close_cb, (void *)(intptr_t)(43));
232 [ - + ]: 21 : if (rc != -ENOSPC) {
233 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
234 : : "rpc_test_method_conn_close_detect(): rc != -ENOSPC");
235 : 0 : return;
236 : : }
237 : :
238 : 21 : spdk_jsonrpc_send_bool_response(request, true);
239 : : }
240 : 21 : SPDK_RPC_REGISTER("hook_conn_close", rpc_hook_conn_close, SPDK_RPC_RUNTIME | SPDK_RPC_STARTUP)
241 : :
242 : : static int
243 : 21 : spdk_jsonrpc_client_hook_conn_close(struct spdk_jsonrpc_client *client)
244 : : {
245 : : int rc;
246 : 21 : bool res = false;
247 : 21 : struct spdk_jsonrpc_client_response *json_resp = NULL;
248 : : struct spdk_json_write_ctx *w;
249 : : struct spdk_jsonrpc_client_request *request;
250 : :
251 : 21 : request = spdk_jsonrpc_client_create_request();
252 [ - + ]: 21 : if (request == NULL) {
253 : 0 : return -ENOMEM;
254 : : }
255 : :
256 : 21 : w = spdk_jsonrpc_begin_request(request, 1, "hook_conn_close");
257 : 21 : spdk_jsonrpc_end_request(request, w);
258 : 21 : spdk_jsonrpc_client_send_request(client, request);
259 : :
260 : 21 : rc = _rpc_client_wait_for_response(client);
261 [ - + ]: 21 : if (rc <= 0) {
262 : 0 : goto out;
263 : : }
264 : :
265 : 21 : json_resp = spdk_jsonrpc_client_get_response(client);
266 [ - + ]: 21 : if (json_resp == NULL) {
267 : 0 : SPDK_ERRLOG("spdk_jsonrpc_client_get_response() failed\n");
268 : 0 : rc = -errno;
269 : 0 : goto out;
270 : :
271 : : }
272 : :
273 : : /* Check for error response */
274 [ - + ]: 21 : if (json_resp->error != NULL) {
275 : 0 : SPDK_ERRLOG("Unexpected error response: %.*s\n", json_resp->error->len,
276 : : (char *)json_resp->error->start);
277 : 0 : rc = -EIO;
278 : 0 : goto out;
279 : : }
280 : :
281 [ - + ]: 21 : assert(json_resp->result);
282 [ + - - + : 21 : if (spdk_json_decode_bool(json_resp->result, &res) != 0 || res != true) {
- + ]
283 : 0 : SPDK_ERRLOG("Response is not and boolean or if not 'true'\n");
284 : 0 : rc = -EINVAL;
285 : 0 : goto out;
286 : : }
287 : :
288 : 21 : rc = 0;
289 : 21 : out:
290 : 21 : spdk_jsonrpc_client_free_response(json_resp);
291 : 21 : return rc;
292 : : }
293 : :
294 : : volatile int g_rpc_server_th_stop;
295 : : static sem_t g_rpc_server_th_listening;
296 : :
297 : : static void *
298 : 21 : rpc_server_th(void *arg)
299 : : {
300 : : int rc;
301 : :
302 : 21 : rc = spdk_rpc_listen(g_rpcsock_addr);
303 [ - + ]: 21 : if (rc) {
304 [ # # # # ]: 0 : fprintf(stderr, "spdk_rpc_listen() failed: %d\n", rc);
305 [ # # ]: 0 : sem_post(&g_rpc_server_th_listening);
306 : 0 : goto out;
307 : : }
308 : :
309 [ - + ]: 21 : sem_post(&g_rpc_server_th_listening);
310 : :
311 [ + + ]: 276 : while (!g_rpc_server_th_stop) {
312 : 255 : spdk_rpc_accept();
313 : 255 : usleep(50);
314 : : }
315 : :
316 : 21 : spdk_rpc_close();
317 : 21 : out:
318 : 21 : return (void *)(intptr_t)rc;
319 : : }
320 : :
321 : : static void *
322 : 21 : rpc_client_th(void *arg)
323 : : {
324 : 21 : struct spdk_jsonrpc_client *client = NULL;
325 : 21 : char *method_name = "rpc_get_methods";
326 : : int rc;
327 : :
328 : :
329 : 21 : rc = sem_wait(&g_rpc_server_th_listening);
330 [ - + ]: 21 : if (rc == -1) {
331 [ # # ]: 0 : fprintf(stderr, "Timeout waiting for server thread to start listening: rc=%d errno=%d\n", rc,
332 : 0 : errno);
333 : 0 : goto out;
334 : : }
335 : :
336 : 21 : client = spdk_jsonrpc_client_connect(g_rpcsock_addr, g_addr_family);
337 [ - + ]: 21 : if (!client) {
338 [ # # ]: 0 : fprintf(stderr, "spdk_jsonrpc_client_connect() failed: %d\n", errno);
339 : 0 : rc = -1;
340 : 0 : goto out;
341 : : }
342 : :
343 : 21 : rc = spdk_jsonrpc_client_check_rpc_method(client, method_name);
344 [ - + ]: 21 : if (rc) {
345 [ # # ]: 0 : fprintf(stderr, "spdk_jsonrpc_client_check_rpc_method() failed: rc=%d errno=%d\n", rc, errno);
346 : 0 : goto out;
347 : : }
348 : :
349 : 21 : rc = spdk_jsonrpc_client_check_null_params_method(client);
350 [ - + ]: 21 : if (rc) {
351 [ # # ]: 0 : fprintf(stderr, "spdk_jsonrpc_client_null_params_method() failed: rc=%d errno=%d\n", rc, errno);
352 : 0 : goto out;
353 : : }
354 : :
355 : 21 : rc = spdk_jsonrpc_client_hook_conn_close(client);
356 [ + - ]: 21 : if (rc) {
357 [ # # ]: 0 : fprintf(stderr, "spdk_jsonrpc_client_hook_conn_close() failed: rc=%d errno=%d\n", rc, errno);
358 : 0 : goto out;
359 : : }
360 : :
361 : 21 : out:
362 [ + - ]: 21 : if (client) {
363 : 21 : spdk_jsonrpc_client_close(client);
364 : : }
365 : :
366 : 21 : return (void *)(intptr_t)rc;
367 : : }
368 : :
369 : : int
370 : 21 : main(int argc, char **argv)
371 : : {
372 : 10 : pthread_t srv_tid, client_tid;
373 : : int srv_tid_valid;
374 : 21 : int client_tid_valid = -1;
375 : 21 : intptr_t th_rc = INTPTR_MIN;
376 : 21 : int rc = 0, err_cnt = 0;
377 : :
378 [ - + ]: 21 : sem_init(&g_rpc_server_th_listening, 0, 0);
379 : :
380 [ - + - + ]: 21 : srv_tid_valid = pthread_create(&srv_tid, NULL, rpc_server_th, NULL);
381 [ - + ]: 21 : if (srv_tid_valid != 0) {
382 [ # # # # ]: 0 : fprintf(stderr, "pthread_create() failed to create server thread: %d\n", srv_tid_valid);
383 : 0 : goto out;
384 : : }
385 : :
386 [ - + - + ]: 21 : client_tid_valid = pthread_create(&client_tid, NULL, rpc_client_th, NULL);
387 [ + - ]: 21 : if (client_tid_valid != 0) {
388 [ # # # # ]: 0 : fprintf(stderr, "pthread_create(): failed to create client thread: %d\n", client_tid_valid);
389 : 0 : goto out;
390 : : }
391 : :
392 : 21 : out:
393 [ + - ]: 21 : if (client_tid_valid == 0) {
394 : 21 : rc = pthread_join(client_tid, (void **)&th_rc);
395 [ - + ]: 21 : if (rc) {
396 [ # # # # ]: 0 : fprintf(stderr, "pthread_join() on client thread failed (rc: %d)\n", rc);
397 : 0 : err_cnt++;
398 [ - + ]: 21 : } else if (th_rc) {
399 [ # # # # ]: 0 : fprintf(stderr, "client thread failed reported failure(thread rc: %d)\n", (int)th_rc);
400 : 0 : err_cnt++;
401 : : }
402 : : }
403 : :
404 : 21 : g_rpc_server_th_stop = 1;
405 : :
406 [ + - ]: 21 : if (srv_tid_valid == 0) {
407 : 21 : rc = pthread_join(srv_tid, (void **)&th_rc);
408 [ - + ]: 21 : if (rc) {
409 [ # # # # ]: 0 : fprintf(stderr, "pthread_join() on server thread failed (rc: %d)\n", rc);
410 : 0 : err_cnt++;
411 [ - + ]: 21 : } else if (th_rc) {
412 [ # # # # ]: 0 : fprintf(stderr, "server thread failed reported failure(thread rc: %d)\n", (int)th_rc);
413 : 0 : err_cnt++;
414 : : }
415 : : }
416 : :
417 [ - + - + ]: 21 : if (g_conn_close_detected == false) {
418 [ # # # # ]: 0 : fprintf(stderr, "Connection close not detected\n");
419 : 0 : err_cnt++;
420 : : }
421 : :
422 [ - + ]: 21 : sem_destroy(&g_rpc_server_th_listening);
423 : :
424 [ + - - + : 21 : fprintf(stderr, "%s\n", err_cnt == 0 ? "OK" : "FAILED");
- + ]
425 : 21 : return err_cnt ? EXIT_FAILURE : 0;
426 : : }
|