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