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 36 #include "spdk/queue.h" 37 #include "spdk/rpc.h" 38 #include "spdk/env.h" 39 #include "spdk/conf.h" 40 #include "spdk/log.h" 41 #include "spdk/string.h" 42 43 #include "spdk_internal/event.h" 44 45 #define RPC_SELECT_INTERVAL 4000 /* 4ms */ 46 #define RPC_DEFAULT_LISTEN_ADDR "127.0.0.1:5260" 47 #define RPC_DEFAULT_PORT "5260" 48 49 static struct sockaddr_un g_rpc_listen_addr_unix = {}; 50 51 static struct spdk_poller *g_rpc_poller = NULL; 52 53 static struct spdk_jsonrpc_server *g_jsonrpc_server = NULL; 54 55 struct spdk_rpc_method { 56 const char *name; 57 spdk_rpc_method_handler func; 58 SLIST_ENTRY(spdk_rpc_method) slist; 59 }; 60 61 static SLIST_HEAD(, spdk_rpc_method) g_rpc_methods = SLIST_HEAD_INITIALIZER(g_rpc_methods); 62 63 static void 64 spdk_rpc_server_do_work(void *arg) 65 { 66 spdk_jsonrpc_server_poll(g_jsonrpc_server); 67 } 68 69 static int 70 enable_rpc(void) 71 { 72 struct spdk_conf_section *sp; 73 74 sp = spdk_conf_find_section(NULL, "Rpc"); 75 if (sp == NULL) { 76 return 0; 77 } 78 79 return spdk_conf_section_get_boolval(sp, "Enable", false); 80 } 81 82 static const char * 83 rpc_get_listen_addr(void) 84 { 85 struct spdk_conf_section *sp; 86 const char *val; 87 88 sp = spdk_conf_find_section(NULL, "Rpc"); 89 if (sp == NULL) { 90 return 0; 91 } 92 93 val = spdk_conf_section_get_val(sp, "Listen"); 94 if (val == NULL) { 95 val = RPC_DEFAULT_LISTEN_ADDR; 96 } 97 98 return val; 99 } 100 101 void 102 spdk_rpc_register_method(const char *method, spdk_rpc_method_handler func) 103 { 104 struct spdk_rpc_method *m; 105 106 m = calloc(1, sizeof(struct spdk_rpc_method)); 107 assert(m != NULL); 108 109 m->name = strdup(method); 110 assert(m->name != NULL); 111 112 m->func = func; 113 114 /* TODO: use a hash table or sorted list */ 115 SLIST_INSERT_HEAD(&g_rpc_methods, m, slist); 116 } 117 118 static void 119 spdk_jsonrpc_handler( 120 struct spdk_jsonrpc_server_conn *conn, 121 const struct spdk_json_val *method, 122 const struct spdk_json_val *params, 123 const struct spdk_json_val *id) 124 { 125 struct spdk_rpc_method *m; 126 127 assert(method != NULL); 128 129 SLIST_FOREACH(m, &g_rpc_methods, slist) { 130 if (spdk_json_strequal(method, m->name)) { 131 m->func(conn, params, id); 132 return; 133 } 134 } 135 136 spdk_jsonrpc_send_error_response(conn, id, SPDK_JSONRPC_ERROR_METHOD_NOT_FOUND, "Method not found"); 137 } 138 139 static void 140 spdk_rpc_setup(void *arg) 141 { 142 struct addrinfo hints; 143 struct addrinfo *res; 144 const char *listen_addr; 145 146 memset(&g_rpc_listen_addr_unix, 0, sizeof(g_rpc_listen_addr_unix)); 147 148 /* Unregister the one-shot setup poller */ 149 spdk_poller_unregister(&g_rpc_poller, NULL); 150 151 if (!enable_rpc()) { 152 return; 153 } 154 155 listen_addr = rpc_get_listen_addr(); 156 if (!listen_addr) { 157 return; 158 } 159 160 if (listen_addr[0] == '/') { 161 int rc; 162 163 g_rpc_listen_addr_unix.sun_family = AF_UNIX; 164 rc = snprintf(g_rpc_listen_addr_unix.sun_path, 165 sizeof(g_rpc_listen_addr_unix.sun_path), 166 "%s", listen_addr); 167 if (rc < 0 || (size_t)rc >= sizeof(g_rpc_listen_addr_unix.sun_path)) { 168 SPDK_ERRLOG("RPC Listen address Unix socket path too long\n"); 169 g_rpc_listen_addr_unix.sun_path[0] = '\0'; 170 return; 171 } 172 173 unlink(g_rpc_listen_addr_unix.sun_path); 174 175 g_jsonrpc_server = spdk_jsonrpc_server_listen(AF_UNIX, 0, 176 (struct sockaddr *)&g_rpc_listen_addr_unix, 177 sizeof(g_rpc_listen_addr_unix), 178 spdk_jsonrpc_handler); 179 } else { 180 char *tmp; 181 char *host, *port; 182 183 tmp = strdup(listen_addr); 184 if (!tmp) { 185 SPDK_ERRLOG("Out of memory\n"); 186 return; 187 } 188 189 if (spdk_parse_ip_addr(tmp, &host, &port) < 0) { 190 free(tmp); 191 SPDK_ERRLOG("Invalid listen address '%s'\n", listen_addr); 192 return; 193 } 194 195 if (port == NULL) { 196 port = RPC_DEFAULT_PORT; 197 } 198 199 memset(&hints, 0, sizeof(hints)); 200 hints.ai_family = AF_UNSPEC; 201 hints.ai_socktype = SOCK_STREAM; 202 hints.ai_protocol = IPPROTO_TCP; 203 204 if (getaddrinfo(host, port, &hints, &res) != 0) { 205 free(tmp); 206 SPDK_ERRLOG("Unable to look up RPC listen address '%s'\n", listen_addr); 207 return; 208 } 209 210 g_jsonrpc_server = spdk_jsonrpc_server_listen(res->ai_family, res->ai_protocol, 211 res->ai_addr, res->ai_addrlen, 212 spdk_jsonrpc_handler); 213 214 freeaddrinfo(res); 215 free(tmp); 216 } 217 218 if (g_jsonrpc_server == NULL) { 219 SPDK_ERRLOG("spdk_jsonrpc_server_listen() failed\n"); 220 return; 221 } 222 223 /* Register the periodic rpc_server_do_work */ 224 spdk_poller_register(&g_rpc_poller, spdk_rpc_server_do_work, NULL, spdk_env_get_current_core(), 225 RPC_SELECT_INTERVAL); 226 } 227 228 static int 229 spdk_rpc_initialize(void) 230 { 231 /* 232 * Defer setup of the RPC service until the reactor has started. This 233 * allows us to detect the RPC listen socket as a suitable proxy for determining 234 * when the SPDK application has finished initialization and ready for logins 235 * or RPC commands. 236 */ 237 spdk_poller_register(&g_rpc_poller, spdk_rpc_setup, NULL, spdk_env_get_current_core(), 0); 238 return 0; 239 } 240 241 static int 242 spdk_rpc_finish(void) 243 { 244 if (g_rpc_listen_addr_unix.sun_path[0]) { 245 /* Delete the Unix socket file */ 246 unlink(g_rpc_listen_addr_unix.sun_path); 247 } 248 249 spdk_poller_unregister(&g_rpc_poller, NULL); 250 251 if (g_jsonrpc_server) { 252 spdk_jsonrpc_server_shutdown(g_jsonrpc_server); 253 } 254 255 return 0; 256 } 257 258 static void 259 spdk_rpc_config_text(FILE *fp) 260 { 261 fprintf(fp, 262 "\n" 263 "[Rpc]\n" 264 " # Defines whether to enable configuration via RPC.\n" 265 " # Default is disabled. Note that the RPC interface is not\n" 266 " # authenticated, so users should be careful about enabling\n" 267 " # RPC in non-trusted environments.\n" 268 " Enable %s\n" 269 " # Listen address for the RPC service.\n" 270 " # May be an IP address or an absolute path to a Unix socket.\n" 271 " Listen %s\n", 272 enable_rpc() ? "Yes" : "No", rpc_get_listen_addr()); 273 } 274 275 SPDK_SUBSYSTEM_REGISTER(spdk_rpc, spdk_rpc_initialize, spdk_rpc_finish, spdk_rpc_config_text) 276