1 /*- 2 * BSD LICENSE 3 * 4 * Copyright (c) Intel Corporation. All rights reserved. 5 * Copyright (c) 2019 Mellanox Technologies LTD. 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 <sys/file.h> 35 36 #include "spdk/stdinc.h" 37 38 #include "spdk/queue.h" 39 #include "spdk/rpc.h" 40 #include "spdk/env.h" 41 #include "spdk/log.h" 42 #include "spdk/string.h" 43 #include "spdk/util.h" 44 #include "spdk/version.h" 45 46 #define RPC_DEFAULT_PORT "5260" 47 48 static struct sockaddr_un g_rpc_listen_addr_unix = {}; 49 static char g_rpc_lock_path[sizeof(g_rpc_listen_addr_unix.sun_path) + sizeof(".lock")]; 50 static int g_rpc_lock_fd = -1; 51 52 static struct spdk_jsonrpc_server *g_jsonrpc_server = NULL; 53 static uint32_t g_rpc_state; 54 static bool g_rpcs_correct = true; 55 56 struct spdk_rpc_method { 57 const char *name; 58 spdk_rpc_method_handler func; 59 SLIST_ENTRY(spdk_rpc_method) slist; 60 uint32_t state_mask; 61 bool is_deprecated; 62 struct spdk_rpc_method *is_alias_of; 63 bool deprecation_warning_printed; 64 }; 65 66 static SLIST_HEAD(, spdk_rpc_method) g_rpc_methods = SLIST_HEAD_INITIALIZER(g_rpc_methods); 67 68 void 69 spdk_rpc_set_state(uint32_t state) 70 { 71 g_rpc_state = state; 72 } 73 74 uint32_t 75 spdk_rpc_get_state(void) 76 { 77 return g_rpc_state; 78 } 79 80 static struct spdk_rpc_method * 81 _get_rpc_method(const struct spdk_json_val *method) 82 { 83 struct spdk_rpc_method *m; 84 85 SLIST_FOREACH(m, &g_rpc_methods, slist) { 86 if (spdk_json_strequal(method, m->name)) { 87 return m; 88 } 89 } 90 91 return NULL; 92 } 93 94 static struct spdk_rpc_method * 95 _get_rpc_method_raw(const char *method) 96 { 97 struct spdk_json_val method_val; 98 99 method_val.type = SPDK_JSON_VAL_STRING; 100 method_val.len = strlen(method); 101 method_val.start = (char *)method; 102 103 return _get_rpc_method(&method_val); 104 } 105 106 static void 107 spdk_jsonrpc_handler(struct spdk_jsonrpc_request *request, 108 const struct spdk_json_val *method, 109 const struct spdk_json_val *params) 110 { 111 struct spdk_rpc_method *m; 112 113 assert(method != NULL); 114 115 m = _get_rpc_method(method); 116 if (m == NULL) { 117 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_METHOD_NOT_FOUND, "Method not found"); 118 return; 119 } 120 121 if (m->is_alias_of != NULL) { 122 if (m->is_deprecated && !m->deprecation_warning_printed) { 123 SPDK_WARNLOG("RPC method %s is deprecated. Use %s instead.\n", m->name, m->is_alias_of->name); 124 m->deprecation_warning_printed = true; 125 } 126 m = m->is_alias_of; 127 } 128 129 if ((m->state_mask & g_rpc_state) == g_rpc_state) { 130 m->func(request, params); 131 } else { 132 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_STATE, 133 "Method is allowed in any state in the mask (%"PRIx32")," 134 " but current state is (%"PRIx32")", 135 m->state_mask, g_rpc_state); 136 } 137 } 138 139 int 140 spdk_rpc_listen(const char *listen_addr) 141 { 142 struct addrinfo hints; 143 struct addrinfo *res; 144 145 memset(&g_rpc_listen_addr_unix, 0, sizeof(g_rpc_listen_addr_unix)); 146 147 if (listen_addr[0] == '/') { 148 int rc; 149 150 g_rpc_listen_addr_unix.sun_family = AF_UNIX; 151 rc = snprintf(g_rpc_listen_addr_unix.sun_path, 152 sizeof(g_rpc_listen_addr_unix.sun_path), 153 "%s", listen_addr); 154 if (rc < 0 || (size_t)rc >= sizeof(g_rpc_listen_addr_unix.sun_path)) { 155 SPDK_ERRLOG("RPC Listen address Unix socket path too long\n"); 156 g_rpc_listen_addr_unix.sun_path[0] = '\0'; 157 return -1; 158 } 159 160 rc = snprintf(g_rpc_lock_path, sizeof(g_rpc_lock_path), "%s.lock", 161 g_rpc_listen_addr_unix.sun_path); 162 if (rc < 0 || (size_t)rc >= sizeof(g_rpc_lock_path)) { 163 SPDK_ERRLOG("RPC lock path too long\n"); 164 g_rpc_listen_addr_unix.sun_path[0] = '\0'; 165 g_rpc_lock_path[0] = '\0'; 166 return -1; 167 } 168 169 g_rpc_lock_fd = open(g_rpc_lock_path, O_RDONLY | O_CREAT, 0600); 170 if (g_rpc_lock_fd == -1) { 171 SPDK_ERRLOG("Cannot open lock file %s: %s\n", 172 g_rpc_lock_path, spdk_strerror(errno)); 173 g_rpc_listen_addr_unix.sun_path[0] = '\0'; 174 g_rpc_lock_path[0] = '\0'; 175 return -1; 176 } 177 178 rc = flock(g_rpc_lock_fd, LOCK_EX | LOCK_NB); 179 if (rc != 0) { 180 SPDK_ERRLOG("RPC Unix domain socket path %s in use. Specify another.\n", 181 g_rpc_listen_addr_unix.sun_path); 182 g_rpc_listen_addr_unix.sun_path[0] = '\0'; 183 g_rpc_lock_path[0] = '\0'; 184 return -1; 185 } 186 187 /* 188 * Since we acquired the lock, it is safe to delete the Unix socket file 189 * if it still exists from a previous process. 190 */ 191 unlink(g_rpc_listen_addr_unix.sun_path); 192 193 g_jsonrpc_server = spdk_jsonrpc_server_listen(AF_UNIX, 0, 194 (struct sockaddr *)&g_rpc_listen_addr_unix, 195 sizeof(g_rpc_listen_addr_unix), 196 spdk_jsonrpc_handler); 197 if (g_jsonrpc_server == NULL) { 198 close(g_rpc_lock_fd); 199 g_rpc_lock_fd = -1; 200 unlink(g_rpc_lock_path); 201 g_rpc_lock_path[0] = '\0'; 202 } 203 } else { 204 char *tmp; 205 char *host, *port; 206 207 tmp = strdup(listen_addr); 208 if (!tmp) { 209 SPDK_ERRLOG("Out of memory\n"); 210 return -1; 211 } 212 213 if (spdk_parse_ip_addr(tmp, &host, &port) < 0) { 214 free(tmp); 215 SPDK_ERRLOG("Invalid listen address '%s'\n", listen_addr); 216 return -1; 217 } 218 219 if (port == NULL) { 220 port = RPC_DEFAULT_PORT; 221 } 222 223 memset(&hints, 0, sizeof(hints)); 224 hints.ai_family = AF_UNSPEC; 225 hints.ai_socktype = SOCK_STREAM; 226 hints.ai_protocol = IPPROTO_TCP; 227 228 if (getaddrinfo(host, port, &hints, &res) != 0) { 229 free(tmp); 230 SPDK_ERRLOG("Unable to look up RPC listen address '%s'\n", listen_addr); 231 return -1; 232 } 233 234 g_jsonrpc_server = spdk_jsonrpc_server_listen(res->ai_family, res->ai_protocol, 235 res->ai_addr, res->ai_addrlen, 236 spdk_jsonrpc_handler); 237 238 freeaddrinfo(res); 239 free(tmp); 240 } 241 242 if (g_jsonrpc_server == NULL) { 243 SPDK_ERRLOG("spdk_jsonrpc_server_listen() failed\n"); 244 return -1; 245 } 246 247 return 0; 248 } 249 250 void 251 spdk_rpc_accept(void) 252 { 253 spdk_jsonrpc_server_poll(g_jsonrpc_server); 254 } 255 256 void 257 spdk_rpc_register_method(const char *method, spdk_rpc_method_handler func, uint32_t state_mask) 258 { 259 struct spdk_rpc_method *m; 260 261 m = _get_rpc_method_raw(method); 262 if (m != NULL) { 263 SPDK_ERRLOG("duplicate RPC %s registered...\n", method); 264 g_rpcs_correct = false; 265 return; 266 } 267 268 m = calloc(1, sizeof(struct spdk_rpc_method)); 269 assert(m != NULL); 270 271 m->name = strdup(method); 272 assert(m->name != NULL); 273 274 m->func = func; 275 m->state_mask = state_mask; 276 277 /* TODO: use a hash table or sorted list */ 278 SLIST_INSERT_HEAD(&g_rpc_methods, m, slist); 279 } 280 281 void 282 spdk_rpc_register_alias_deprecated(const char *method, const char *alias) 283 { 284 struct spdk_rpc_method *m, *base; 285 286 base = _get_rpc_method_raw(method); 287 if (base == NULL) { 288 SPDK_ERRLOG("cannot create alias %s - method %s does not exist\n", 289 alias, method); 290 g_rpcs_correct = false; 291 return; 292 } 293 294 if (base->is_alias_of != NULL) { 295 SPDK_ERRLOG("cannot create alias %s of alias %s\n", alias, method); 296 g_rpcs_correct = false; 297 return; 298 } 299 300 m = calloc(1, sizeof(struct spdk_rpc_method)); 301 assert(m != NULL); 302 303 m->name = strdup(alias); 304 assert(m->name != NULL); 305 306 m->is_alias_of = base; 307 m->is_deprecated = true; 308 m->state_mask = base->state_mask; 309 310 /* TODO: use a hash table or sorted list */ 311 SLIST_INSERT_HEAD(&g_rpc_methods, m, slist); 312 } 313 314 bool 315 spdk_rpc_verify_methods(void) 316 { 317 return g_rpcs_correct; 318 } 319 320 int 321 spdk_rpc_is_method_allowed(const char *method, uint32_t state_mask) 322 { 323 struct spdk_rpc_method *m; 324 325 SLIST_FOREACH(m, &g_rpc_methods, slist) { 326 if (strcmp(m->name, method) != 0) { 327 continue; 328 } 329 330 if ((m->state_mask & state_mask) == state_mask) { 331 return 0; 332 } else { 333 return -EPERM; 334 } 335 } 336 337 return -ENOENT; 338 } 339 340 void 341 spdk_rpc_close(void) 342 { 343 if (g_jsonrpc_server) { 344 if (g_rpc_listen_addr_unix.sun_path[0]) { 345 /* Delete the Unix socket file */ 346 unlink(g_rpc_listen_addr_unix.sun_path); 347 g_rpc_listen_addr_unix.sun_path[0] = '\0'; 348 } 349 350 spdk_jsonrpc_server_shutdown(g_jsonrpc_server); 351 g_jsonrpc_server = NULL; 352 353 if (g_rpc_lock_fd != -1) { 354 close(g_rpc_lock_fd); 355 g_rpc_lock_fd = -1; 356 } 357 358 if (g_rpc_lock_path[0]) { 359 unlink(g_rpc_lock_path); 360 g_rpc_lock_path[0] = '\0'; 361 } 362 } 363 } 364 365 struct rpc_get_methods { 366 bool current; 367 bool include_aliases; 368 }; 369 370 static const struct spdk_json_object_decoder rpc_get_methods_decoders[] = { 371 {"current", offsetof(struct rpc_get_methods, current), spdk_json_decode_bool, true}, 372 {"include_aliases", offsetof(struct rpc_get_methods, include_aliases), spdk_json_decode_bool, true}, 373 }; 374 375 static void 376 spdk_rpc_get_methods(struct spdk_jsonrpc_request *request, const struct spdk_json_val *params) 377 { 378 struct rpc_get_methods req = {}; 379 struct spdk_json_write_ctx *w; 380 struct spdk_rpc_method *m; 381 382 if (params != NULL) { 383 if (spdk_json_decode_object(params, rpc_get_methods_decoders, 384 SPDK_COUNTOF(rpc_get_methods_decoders), &req)) { 385 SPDK_ERRLOG("spdk_json_decode_object failed\n"); 386 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 387 "Invalid parameters"); 388 return; 389 } 390 } 391 392 w = spdk_jsonrpc_begin_result(request); 393 spdk_json_write_array_begin(w); 394 SLIST_FOREACH(m, &g_rpc_methods, slist) { 395 if (m->is_alias_of != NULL && !req.include_aliases) { 396 continue; 397 } 398 if (req.current && ((m->state_mask & g_rpc_state) != g_rpc_state)) { 399 continue; 400 } 401 spdk_json_write_string(w, m->name); 402 } 403 spdk_json_write_array_end(w); 404 spdk_jsonrpc_end_result(request, w); 405 } 406 SPDK_RPC_REGISTER("rpc_get_methods", spdk_rpc_get_methods, SPDK_RPC_STARTUP | SPDK_RPC_RUNTIME) 407 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(rpc_get_methods, get_rpc_methods) 408 409 static void 410 spdk_rpc_spdk_get_version(struct spdk_jsonrpc_request *request, const struct spdk_json_val *params) 411 { 412 struct spdk_json_write_ctx *w; 413 414 if (params != NULL) { 415 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 416 "spdk_get_version method requires no parameters"); 417 return; 418 } 419 420 w = spdk_jsonrpc_begin_result(request); 421 spdk_json_write_object_begin(w); 422 423 spdk_json_write_named_string_fmt(w, "version", "%s", SPDK_VERSION_STRING); 424 spdk_json_write_named_object_begin(w, "fields"); 425 spdk_json_write_named_uint32(w, "major", SPDK_VERSION_MAJOR); 426 spdk_json_write_named_uint32(w, "minor", SPDK_VERSION_MINOR); 427 spdk_json_write_named_uint32(w, "patch", SPDK_VERSION_PATCH); 428 spdk_json_write_named_string_fmt(w, "suffix", "%s", SPDK_VERSION_SUFFIX); 429 #ifdef SPDK_GIT_COMMIT 430 spdk_json_write_named_string_fmt(w, "commit", "%s", SPDK_GIT_COMMIT_STRING); 431 #endif 432 spdk_json_write_object_end(w); 433 434 spdk_json_write_object_end(w); 435 spdk_jsonrpc_end_result(request, w); 436 } 437 SPDK_RPC_REGISTER("spdk_get_version", spdk_rpc_spdk_get_version, 438 SPDK_RPC_STARTUP | SPDK_RPC_RUNTIME) 439 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(spdk_get_version, get_spdk_version) 440