xref: /spdk/lib/rpc/rpc.c (revision b961d9cc12de49251d135307eaa05ec0fc9dd2fa)
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