xref: /spdk/lib/rpc/rpc.c (revision 307b8c112ffd90a26d53dd15fad67bd9038ef526)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (c) Intel Corporation. All rights reserved.
3  *   Copyright (c) 2019 Mellanox Technologies LTD. All rights reserved.
4  *   Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
5  */
6 
7 #include <sys/file.h>
8 
9 #include "spdk/stdinc.h"
10 
11 #include "spdk/queue.h"
12 #include "spdk/rpc.h"
13 #include "spdk/env.h"
14 #include "spdk/log.h"
15 #include "spdk/string.h"
16 #include "spdk/util.h"
17 #include "spdk/version.h"
18 
19 static struct sockaddr_un g_rpc_listen_addr_unix = {};
20 static char g_rpc_lock_path[sizeof(g_rpc_listen_addr_unix.sun_path) + sizeof(".lock")];
21 static int g_rpc_lock_fd = -1;
22 
23 static struct spdk_jsonrpc_server *g_jsonrpc_server = NULL;
24 static uint32_t g_rpc_state;
25 static bool g_rpcs_correct = true;
26 
27 struct spdk_rpc_method {
28 	const char *name;
29 	spdk_rpc_method_handler func;
30 	SLIST_ENTRY(spdk_rpc_method) slist;
31 	uint32_t state_mask;
32 	bool is_deprecated;
33 	struct spdk_rpc_method *is_alias_of;
34 	bool deprecation_warning_printed;
35 };
36 
37 static SLIST_HEAD(, spdk_rpc_method) g_rpc_methods = SLIST_HEAD_INITIALIZER(g_rpc_methods);
38 
39 void
40 spdk_rpc_set_state(uint32_t state)
41 {
42 	g_rpc_state = state;
43 }
44 
45 uint32_t
46 spdk_rpc_get_state(void)
47 {
48 	return g_rpc_state;
49 }
50 
51 static struct spdk_rpc_method *
52 _get_rpc_method(const struct spdk_json_val *method)
53 {
54 	struct spdk_rpc_method *m;
55 
56 	SLIST_FOREACH(m, &g_rpc_methods, slist) {
57 		if (spdk_json_strequal(method, m->name)) {
58 			return m;
59 		}
60 	}
61 
62 	return NULL;
63 }
64 
65 static struct spdk_rpc_method *
66 _get_rpc_method_raw(const char *method)
67 {
68 	struct spdk_json_val method_val;
69 
70 	method_val.type = SPDK_JSON_VAL_STRING;
71 	method_val.len = strlen(method);
72 	method_val.start = (char *)method;
73 
74 	return _get_rpc_method(&method_val);
75 }
76 
77 static void
78 jsonrpc_handler(struct spdk_jsonrpc_request *request,
79 		const struct spdk_json_val *method,
80 		const struct spdk_json_val *params)
81 {
82 	struct spdk_rpc_method *m;
83 
84 	assert(method != NULL);
85 
86 	m = _get_rpc_method(method);
87 	if (m == NULL) {
88 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_METHOD_NOT_FOUND, "Method not found");
89 		return;
90 	}
91 
92 	if (m->is_alias_of != NULL) {
93 		if (m->is_deprecated && !m->deprecation_warning_printed) {
94 			SPDK_WARNLOG("RPC method %s is deprecated.  Use %s instead.\n", m->name, m->is_alias_of->name);
95 			m->deprecation_warning_printed = true;
96 		}
97 		m = m->is_alias_of;
98 	}
99 
100 	if ((m->state_mask & g_rpc_state) == g_rpc_state) {
101 		m->func(request, params);
102 	} else {
103 		if (g_rpc_state == SPDK_RPC_STARTUP) {
104 			spdk_jsonrpc_send_error_response_fmt(request,
105 							     SPDK_JSONRPC_ERROR_INVALID_STATE,
106 							     "Method may only be called after "
107 							     "framework is initialized "
108 							     "using framework_start_init RPC.");
109 		} else {
110 			spdk_jsonrpc_send_error_response_fmt(request,
111 							     SPDK_JSONRPC_ERROR_INVALID_STATE,
112 							     "Method may only be called before "
113 							     "framework is initialized. "
114 							     "Use --wait-for-rpc command line "
115 							     "parameter and then issue this RPC "
116 							     "before the framework_start_init RPC.");
117 		}
118 	}
119 }
120 
121 int
122 spdk_rpc_listen(const char *listen_addr)
123 {
124 	int rc;
125 
126 	memset(&g_rpc_listen_addr_unix, 0, sizeof(g_rpc_listen_addr_unix));
127 
128 	g_rpc_listen_addr_unix.sun_family = AF_UNIX;
129 	rc = snprintf(g_rpc_listen_addr_unix.sun_path,
130 		      sizeof(g_rpc_listen_addr_unix.sun_path),
131 		      "%s", listen_addr);
132 	if (rc < 0 || (size_t)rc >= sizeof(g_rpc_listen_addr_unix.sun_path)) {
133 		SPDK_ERRLOG("RPC Listen address Unix socket path too long\n");
134 		g_rpc_listen_addr_unix.sun_path[0] = '\0';
135 		return -1;
136 	}
137 
138 	rc = snprintf(g_rpc_lock_path, sizeof(g_rpc_lock_path), "%s.lock",
139 		      g_rpc_listen_addr_unix.sun_path);
140 	if (rc < 0 || (size_t)rc >= sizeof(g_rpc_lock_path)) {
141 		SPDK_ERRLOG("RPC lock path too long\n");
142 		g_rpc_listen_addr_unix.sun_path[0] = '\0';
143 		g_rpc_lock_path[0] = '\0';
144 		return -1;
145 	}
146 
147 	g_rpc_lock_fd = open(g_rpc_lock_path, O_RDONLY | O_CREAT, 0600);
148 	if (g_rpc_lock_fd == -1) {
149 		SPDK_ERRLOG("Cannot open lock file %s: %s\n",
150 			    g_rpc_lock_path, spdk_strerror(errno));
151 		g_rpc_listen_addr_unix.sun_path[0] = '\0';
152 		g_rpc_lock_path[0] = '\0';
153 		return -1;
154 	}
155 
156 	rc = flock(g_rpc_lock_fd, LOCK_EX | LOCK_NB);
157 	if (rc != 0) {
158 		SPDK_ERRLOG("RPC Unix domain socket path %s in use. Specify another.\n",
159 			    g_rpc_listen_addr_unix.sun_path);
160 		g_rpc_listen_addr_unix.sun_path[0] = '\0';
161 		g_rpc_lock_path[0] = '\0';
162 		return -1;
163 	}
164 
165 	/*
166 	 * Since we acquired the lock, it is safe to delete the Unix socket file
167 	 * if it still exists from a previous process.
168 	 */
169 	unlink(g_rpc_listen_addr_unix.sun_path);
170 
171 	g_jsonrpc_server = spdk_jsonrpc_server_listen(AF_UNIX, 0,
172 			   (struct sockaddr *)&g_rpc_listen_addr_unix,
173 			   sizeof(g_rpc_listen_addr_unix),
174 			   jsonrpc_handler);
175 	if (g_jsonrpc_server == NULL) {
176 		SPDK_ERRLOG("spdk_jsonrpc_server_listen() failed\n");
177 		close(g_rpc_lock_fd);
178 		g_rpc_lock_fd = -1;
179 		unlink(g_rpc_lock_path);
180 		g_rpc_lock_path[0] = '\0';
181 		return -1;
182 	}
183 
184 	return 0;
185 }
186 
187 void
188 spdk_rpc_accept(void)
189 {
190 	spdk_jsonrpc_server_poll(g_jsonrpc_server);
191 }
192 
193 void
194 spdk_rpc_register_method(const char *method, spdk_rpc_method_handler func, uint32_t state_mask)
195 {
196 	struct spdk_rpc_method *m;
197 
198 	m = _get_rpc_method_raw(method);
199 	if (m != NULL) {
200 		SPDK_ERRLOG("duplicate RPC %s registered...\n", method);
201 		g_rpcs_correct = false;
202 		return;
203 	}
204 
205 	m = calloc(1, sizeof(struct spdk_rpc_method));
206 	assert(m != NULL);
207 
208 	m->name = strdup(method);
209 	assert(m->name != NULL);
210 
211 	m->func = func;
212 	m->state_mask = state_mask;
213 
214 	/* TODO: use a hash table or sorted list */
215 	SLIST_INSERT_HEAD(&g_rpc_methods, m, slist);
216 }
217 
218 void
219 spdk_rpc_register_alias_deprecated(const char *method, const char *alias)
220 {
221 	struct spdk_rpc_method *m, *base;
222 
223 	base = _get_rpc_method_raw(method);
224 	if (base == NULL) {
225 		SPDK_ERRLOG("cannot create alias %s - method %s does not exist\n",
226 			    alias, method);
227 		g_rpcs_correct = false;
228 		return;
229 	}
230 
231 	if (base->is_alias_of != NULL) {
232 		SPDK_ERRLOG("cannot create alias %s of alias %s\n", alias, method);
233 		g_rpcs_correct = false;
234 		return;
235 	}
236 
237 	m = calloc(1, sizeof(struct spdk_rpc_method));
238 	assert(m != NULL);
239 
240 	m->name = strdup(alias);
241 	assert(m->name != NULL);
242 
243 	m->is_alias_of = base;
244 	m->is_deprecated = true;
245 	m->state_mask = base->state_mask;
246 
247 	/* TODO: use a hash table or sorted list */
248 	SLIST_INSERT_HEAD(&g_rpc_methods, m, slist);
249 }
250 
251 bool
252 spdk_rpc_verify_methods(void)
253 {
254 	return g_rpcs_correct;
255 }
256 
257 int
258 spdk_rpc_is_method_allowed(const char *method, uint32_t state_mask)
259 {
260 	struct spdk_rpc_method *m;
261 
262 	SLIST_FOREACH(m, &g_rpc_methods, slist) {
263 		if (strcmp(m->name, method) != 0) {
264 			continue;
265 		}
266 
267 		if ((m->state_mask & state_mask) == state_mask) {
268 			return 0;
269 		} else {
270 			return -EPERM;
271 		}
272 	}
273 
274 	return -ENOENT;
275 }
276 
277 int
278 spdk_rpc_get_method_state_mask(const char *method, uint32_t *state_mask)
279 {
280 	struct spdk_rpc_method *m;
281 
282 	SLIST_FOREACH(m, &g_rpc_methods, slist) {
283 		if (strcmp(m->name, method) == 0) {
284 			*state_mask = m->state_mask;
285 			return 0;
286 		}
287 	}
288 
289 	return -ENOENT;
290 }
291 
292 void
293 spdk_rpc_close(void)
294 {
295 	if (g_jsonrpc_server) {
296 		if (g_rpc_listen_addr_unix.sun_path[0]) {
297 			/* Delete the Unix socket file */
298 			unlink(g_rpc_listen_addr_unix.sun_path);
299 			g_rpc_listen_addr_unix.sun_path[0] = '\0';
300 		}
301 
302 		spdk_jsonrpc_server_shutdown(g_jsonrpc_server);
303 		g_jsonrpc_server = NULL;
304 
305 		if (g_rpc_lock_fd != -1) {
306 			close(g_rpc_lock_fd);
307 			g_rpc_lock_fd = -1;
308 		}
309 
310 		if (g_rpc_lock_path[0]) {
311 			unlink(g_rpc_lock_path);
312 			g_rpc_lock_path[0] = '\0';
313 		}
314 	}
315 }
316 
317 struct rpc_get_methods {
318 	bool current;
319 	bool include_aliases;
320 };
321 
322 static const struct spdk_json_object_decoder rpc_get_methods_decoders[] = {
323 	{"current", offsetof(struct rpc_get_methods, current), spdk_json_decode_bool, true},
324 	{"include_aliases", offsetof(struct rpc_get_methods, include_aliases), spdk_json_decode_bool, true},
325 };
326 
327 static void
328 rpc_get_methods(struct spdk_jsonrpc_request *request, const struct spdk_json_val *params)
329 {
330 	struct rpc_get_methods req = {};
331 	struct spdk_json_write_ctx *w;
332 	struct spdk_rpc_method *m;
333 
334 	if (params != NULL) {
335 		if (spdk_json_decode_object(params, rpc_get_methods_decoders,
336 					    SPDK_COUNTOF(rpc_get_methods_decoders), &req)) {
337 			SPDK_ERRLOG("spdk_json_decode_object failed\n");
338 			spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
339 							 "Invalid parameters");
340 			return;
341 		}
342 	}
343 
344 	w = spdk_jsonrpc_begin_result(request);
345 	spdk_json_write_array_begin(w);
346 	SLIST_FOREACH(m, &g_rpc_methods, slist) {
347 		if (m->is_alias_of != NULL && !req.include_aliases) {
348 			continue;
349 		}
350 		if (req.current && ((m->state_mask & g_rpc_state) != g_rpc_state)) {
351 			continue;
352 		}
353 		spdk_json_write_string(w, m->name);
354 	}
355 	spdk_json_write_array_end(w);
356 	spdk_jsonrpc_end_result(request, w);
357 }
358 SPDK_RPC_REGISTER("rpc_get_methods", rpc_get_methods, SPDK_RPC_STARTUP | SPDK_RPC_RUNTIME)
359 
360 static void
361 rpc_spdk_get_version(struct spdk_jsonrpc_request *request, const struct spdk_json_val *params)
362 {
363 	struct spdk_json_write_ctx *w;
364 
365 	if (params != NULL) {
366 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
367 						 "spdk_get_version method requires no parameters");
368 		return;
369 	}
370 
371 	w = spdk_jsonrpc_begin_result(request);
372 	spdk_json_write_object_begin(w);
373 
374 	spdk_json_write_named_string_fmt(w, "version", "%s", SPDK_VERSION_STRING);
375 	spdk_json_write_named_object_begin(w, "fields");
376 	spdk_json_write_named_uint32(w, "major", SPDK_VERSION_MAJOR);
377 	spdk_json_write_named_uint32(w, "minor", SPDK_VERSION_MINOR);
378 	spdk_json_write_named_uint32(w, "patch", SPDK_VERSION_PATCH);
379 	spdk_json_write_named_string_fmt(w, "suffix", "%s", SPDK_VERSION_SUFFIX);
380 #ifdef SPDK_GIT_COMMIT
381 	spdk_json_write_named_string_fmt(w, "commit", "%s", SPDK_GIT_COMMIT_STRING);
382 #endif
383 	spdk_json_write_object_end(w);
384 
385 	spdk_json_write_object_end(w);
386 	spdk_jsonrpc_end_result(request, w);
387 }
388 SPDK_RPC_REGISTER("spdk_get_version", rpc_spdk_get_version,
389 		  SPDK_RPC_STARTUP | SPDK_RPC_RUNTIME)
390