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" 37 #include "spdk/util.h" 38 #include "spdk/rpc.h" 39 40 41 #define RPC_MAX_METHODS 200 42 #define JOIN_TIMEOUT_S 1 43 44 static const char *g_rpcsock_addr = SPDK_DEFAULT_RPC_ADDR; 45 static int g_addr_family = AF_UNIX; 46 47 #define RPC_MAX_METHODS 200 48 49 struct get_jsonrpc_methods_resp { 50 char *method_names[RPC_MAX_METHODS]; 51 size_t method_num; 52 }; 53 54 static int 55 get_jsonrpc_method_json_parser(struct get_jsonrpc_methods_resp *resp, 56 const struct spdk_json_val *result) 57 { 58 return spdk_json_decode_array(result, spdk_json_decode_string, resp->method_names, 59 RPC_MAX_METHODS, &resp->method_num, sizeof(char *)); 60 } 61 62 static int 63 spdk_jsonrpc_client_check_rpc_method(struct spdk_jsonrpc_client *client, char *method_name) 64 { 65 int rc, i; 66 struct spdk_jsonrpc_client_response *json_resp = NULL; 67 struct get_jsonrpc_methods_resp resp = {}; 68 struct spdk_json_write_ctx *w; 69 struct spdk_jsonrpc_client_request *request; 70 71 request = spdk_jsonrpc_client_create_request(); 72 if (request == NULL) { 73 return -ENOMEM; 74 } 75 76 w = spdk_jsonrpc_begin_request(request, 1, "get_rpc_methods"); 77 spdk_jsonrpc_end_request(request, w); 78 spdk_jsonrpc_client_send_request(client, request); 79 80 do { 81 rc = spdk_jsonrpc_client_poll(client, 1); 82 } while (rc == 0 || rc == -ENOTCONN); 83 84 if (rc <= 0) { 85 SPDK_ERRLOG("Failed to get response: %d\n", rc); 86 rc = -1; 87 goto out; 88 } 89 90 json_resp = spdk_jsonrpc_client_get_response(client); 91 if (json_resp == NULL) { 92 SPDK_ERRLOG("spdk_jsonrpc_client_get_response() failed\n"); 93 rc = -1; 94 goto out; 95 96 } 97 98 /* Check for error response */ 99 if (json_resp->error != NULL) { 100 SPDK_ERRLOG("Unexpected error response\n"); 101 rc = -1; 102 goto out; 103 } 104 105 assert(json_resp->result); 106 107 rc = get_jsonrpc_method_json_parser(&resp, json_resp->result); 108 if (rc) { 109 SPDK_ERRLOG("get_jsonrpc_method_json_parser() failed\n"); 110 goto out; 111 } 112 113 for (i = 0; i < (int)resp.method_num; i++) { 114 if (strcmp(method_name, resp.method_names[i]) == 0) { 115 rc = 0; 116 goto out; 117 } 118 } 119 120 rc = -1; 121 SPDK_ERRLOG("Method '%s' not found in response\n", method_name); 122 123 out: 124 for (i = 0; i < (int)resp.method_num; i++) { 125 SPDK_NOTICELOG("%s\n", resp.method_names[i]); 126 free(resp.method_names[i]); 127 } 128 129 spdk_jsonrpc_client_free_response(json_resp); 130 return rc; 131 } 132 133 static void 134 rpc_test_method_startup(struct spdk_jsonrpc_request *request, const struct spdk_json_val *params) 135 { 136 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 137 "rpc_test_method_startup(): Method body not implemented"); 138 } 139 SPDK_RPC_REGISTER("test_method_startup", rpc_test_method_startup, SPDK_RPC_STARTUP) 140 141 static void 142 rpc_test_method_runtime(struct spdk_jsonrpc_request *request, const struct spdk_json_val *params) 143 { 144 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 145 "rpc_test_method_runtime(): Method body not implemented"); 146 } 147 SPDK_RPC_REGISTER("test_method_runtime", rpc_test_method_runtime, SPDK_RPC_RUNTIME) 148 149 /* Helper function */ 150 static int 151 _sem_timedwait(sem_t *sem, __time_t sec) 152 { 153 struct timespec timeout; 154 155 clock_gettime(CLOCK_REALTIME, &timeout); 156 timeout.tv_sec += sec; 157 158 return sem_timedwait(sem, &timeout); 159 } 160 161 volatile int g_rpc_server_th_stop; 162 static sem_t g_rpc_server_th_listening; 163 static sem_t g_rpc_server_th_done; 164 165 static void * 166 rpc_server_th(void *arg) 167 { 168 int rc; 169 170 rc = spdk_rpc_listen(g_rpcsock_addr); 171 if (rc) { 172 fprintf(stderr, "spdk_rpc_listen() failed: %d\n", rc); 173 goto out; 174 } 175 176 sem_post(&g_rpc_server_th_listening); 177 178 while (!g_rpc_server_th_stop) { 179 spdk_rpc_accept(); 180 usleep(50); 181 } 182 183 spdk_rpc_close(); 184 out: 185 sem_post(&g_rpc_server_th_done); 186 187 return (void *)(intptr_t)rc; 188 } 189 190 static sem_t g_rpc_client_th_done; 191 192 static void * 193 rpc_client_th(void *arg) 194 { 195 struct spdk_jsonrpc_client *client = NULL; 196 char *method_name = "get_rpc_methods"; 197 int rc; 198 199 200 rc = _sem_timedwait(&g_rpc_server_th_listening, 2); 201 if (rc == -1) { 202 fprintf(stderr, "Timeout waiting for server thread to start listening: %d\n", errno); 203 goto out; 204 } 205 206 client = spdk_jsonrpc_client_connect(g_rpcsock_addr, g_addr_family); 207 if (!client) { 208 fprintf(stderr, "spdk_jsonrpc_client_connect() failed: %d\n", errno); 209 rc = -1; 210 goto out; 211 } 212 213 rc = spdk_jsonrpc_client_check_rpc_method(client, method_name); 214 if (rc) { 215 fprintf(stderr, "spdk_jsonrpc_client_check_rpc_method() failed: %d\n", errno); 216 goto out; 217 } 218 219 out: 220 if (client) { 221 spdk_jsonrpc_client_close(client); 222 } 223 224 sem_post(&g_rpc_client_th_done); 225 return (void *)(intptr_t)rc; 226 } 227 228 int main(int argc, char **argv) 229 { 230 pthread_t srv_tid, client_tid; 231 int srv_tid_valid; 232 int client_tid_valid = -1; 233 int th_rc = INT_MIN; 234 int rc = 0, err_cnt = 0; 235 236 sem_init(&g_rpc_server_th_listening, 0, 0); 237 sem_init(&g_rpc_server_th_done, 0, 0); 238 sem_init(&g_rpc_client_th_done, 0, 0); 239 240 srv_tid_valid = pthread_create(&srv_tid, NULL, rpc_server_th, NULL); 241 if (srv_tid_valid != 0) { 242 fprintf(stderr, "pthread_create() failed to create server thread: %d\n", srv_tid_valid); 243 goto out; 244 } 245 246 client_tid_valid = pthread_create(&client_tid, NULL, rpc_client_th, NULL); 247 if (client_tid_valid != 0) { 248 fprintf(stderr, "pthread_create(): failed to create client thread: %d\n", client_tid_valid); 249 goto out; 250 } 251 252 out: 253 if (client_tid_valid == 0) { 254 rc = _sem_timedwait(&g_rpc_client_th_done, JOIN_TIMEOUT_S); 255 if (rc) { 256 fprintf(stderr, "failed to join client thread (rc: %d)\n", rc); 257 err_cnt++; 258 } 259 260 rc = pthread_join(client_tid, (void **)&th_rc); 261 if (rc) { 262 fprintf(stderr, "pthread_join() on cliennt thread failed (rc: %d)\n", rc); 263 err_cnt++; 264 } else if (th_rc) { 265 fprintf(stderr, "cliennt thread failed reported failure(thread rc: %d)\n", th_rc); 266 err_cnt++; 267 } 268 } 269 270 g_rpc_server_th_stop = 1; 271 272 if (srv_tid_valid == 0) { 273 rc = _sem_timedwait(&g_rpc_server_th_done, JOIN_TIMEOUT_S); 274 if (rc) { 275 fprintf(stderr, "server thread failed to exit in %d sec: (rc: %d)\n", JOIN_TIMEOUT_S, rc); 276 err_cnt++; 277 } 278 279 rc = pthread_join(srv_tid, (void **)&th_rc); 280 if (rc) { 281 fprintf(stderr, "pthread_join() on cliennt thread failed (rc: %d)\n", rc); 282 err_cnt++; 283 } else if (th_rc) { 284 fprintf(stderr, "cliennt thread failed reported failure(thread rc: %d)\n", th_rc); 285 err_cnt++; 286 } 287 } 288 289 sem_destroy(&g_rpc_server_th_listening); 290 sem_destroy(&g_rpc_server_th_done); 291 sem_destroy(&g_rpc_client_th_done); 292 293 fprintf(stderr, "%s\n", err_cnt == 0 ? "OK" : "FAILED"); 294 return err_cnt ? EXIT_FAILURE : 0; 295 } 296