xref: /spdk/lib/rpc/rpc.c (revision bb488d2829a9b7863daab45917dd2174905cc0ae)
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 <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 
55 struct spdk_rpc_method {
56 	const char *name;
57 	spdk_rpc_method_handler func;
58 	SLIST_ENTRY(spdk_rpc_method) slist;
59 	uint32_t state_mask;
60 };
61 
62 static SLIST_HEAD(, spdk_rpc_method) g_rpc_methods = SLIST_HEAD_INITIALIZER(g_rpc_methods);
63 
64 void
65 spdk_rpc_set_state(uint32_t state)
66 {
67 	g_rpc_state = state;
68 }
69 
70 uint32_t
71 spdk_rpc_get_state(void)
72 {
73 	return g_rpc_state;
74 }
75 
76 static void
77 spdk_jsonrpc_handler(struct spdk_jsonrpc_request *request,
78 		     const struct spdk_json_val *method,
79 		     const struct spdk_json_val *params)
80 {
81 	struct spdk_rpc_method *m;
82 
83 	assert(method != NULL);
84 
85 	SLIST_FOREACH(m, &g_rpc_methods, slist) {
86 		if (spdk_json_strequal(method, m->name)) {
87 			if ((m->state_mask & g_rpc_state) == g_rpc_state) {
88 				m->func(request, params);
89 			} else {
90 				spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_STATE,
91 								     "Method is allowed in any state in the mask (%"PRIx32"),"
92 								     " but current state is (%"PRIx32")",
93 								     m->state_mask, g_rpc_state);
94 			}
95 			return;
96 		}
97 	}
98 
99 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_METHOD_NOT_FOUND, "Method not found");
100 }
101 
102 int
103 spdk_rpc_listen(const char *listen_addr)
104 {
105 	struct addrinfo		hints;
106 	struct addrinfo		*res;
107 
108 	memset(&g_rpc_listen_addr_unix, 0, sizeof(g_rpc_listen_addr_unix));
109 
110 	if (listen_addr[0] == '/') {
111 		int rc;
112 
113 		g_rpc_listen_addr_unix.sun_family = AF_UNIX;
114 		rc = snprintf(g_rpc_listen_addr_unix.sun_path,
115 			      sizeof(g_rpc_listen_addr_unix.sun_path),
116 			      "%s", listen_addr);
117 		if (rc < 0 || (size_t)rc >= sizeof(g_rpc_listen_addr_unix.sun_path)) {
118 			SPDK_ERRLOG("RPC Listen address Unix socket path too long\n");
119 			g_rpc_listen_addr_unix.sun_path[0] = '\0';
120 			return -1;
121 		}
122 
123 		snprintf(g_rpc_lock_path, sizeof(g_rpc_lock_path), "%s.lock",
124 			 g_rpc_listen_addr_unix.sun_path);
125 
126 		g_rpc_lock_fd = open(g_rpc_lock_path, O_RDONLY | O_CREAT, 0600);
127 		if (g_rpc_lock_fd == -1) {
128 			SPDK_ERRLOG("Cannot open lock file %s: %s\n",
129 				    g_rpc_lock_path, spdk_strerror(errno));
130 			return -1;
131 		}
132 
133 		rc = flock(g_rpc_lock_fd, LOCK_EX | LOCK_NB);
134 		if (rc != 0) {
135 			SPDK_ERRLOG("RPC Unix domain socket path %s in use. Specify another.\n",
136 				    g_rpc_listen_addr_unix.sun_path);
137 			return -1;
138 		}
139 
140 		/*
141 		 * Since we acquired the lock, it is safe to delete the Unix socket file
142 		 * if it still exists from a previous process.
143 		 */
144 		unlink(g_rpc_listen_addr_unix.sun_path);
145 
146 		g_jsonrpc_server = spdk_jsonrpc_server_listen(AF_UNIX, 0,
147 				   (struct sockaddr *)&g_rpc_listen_addr_unix,
148 				   sizeof(g_rpc_listen_addr_unix),
149 				   spdk_jsonrpc_handler);
150 		if (g_jsonrpc_server == NULL) {
151 			close(g_rpc_lock_fd);
152 			g_rpc_lock_fd = -1;
153 			unlink(g_rpc_lock_path);
154 			g_rpc_lock_path[0] = '\0';
155 		}
156 	} else {
157 		char *tmp;
158 		char *host, *port;
159 
160 		tmp = strdup(listen_addr);
161 		if (!tmp) {
162 			SPDK_ERRLOG("Out of memory\n");
163 			return -1;
164 		}
165 
166 		if (spdk_parse_ip_addr(tmp, &host, &port) < 0) {
167 			free(tmp);
168 			SPDK_ERRLOG("Invalid listen address '%s'\n", listen_addr);
169 			return -1;
170 		}
171 
172 		if (port == NULL) {
173 			port = RPC_DEFAULT_PORT;
174 		}
175 
176 		memset(&hints, 0, sizeof(hints));
177 		hints.ai_family = AF_UNSPEC;
178 		hints.ai_socktype = SOCK_STREAM;
179 		hints.ai_protocol = IPPROTO_TCP;
180 
181 		if (getaddrinfo(host, port, &hints, &res) != 0) {
182 			free(tmp);
183 			SPDK_ERRLOG("Unable to look up RPC listen address '%s'\n", listen_addr);
184 			return -1;
185 		}
186 
187 		g_jsonrpc_server = spdk_jsonrpc_server_listen(res->ai_family, res->ai_protocol,
188 				   res->ai_addr, res->ai_addrlen,
189 				   spdk_jsonrpc_handler);
190 
191 		freeaddrinfo(res);
192 		free(tmp);
193 	}
194 
195 	if (g_jsonrpc_server == NULL) {
196 		SPDK_ERRLOG("spdk_jsonrpc_server_listen() failed\n");
197 		return -1;
198 	}
199 
200 	return 0;
201 }
202 
203 void
204 spdk_rpc_accept(void)
205 {
206 	spdk_jsonrpc_server_poll(g_jsonrpc_server);
207 }
208 
209 void
210 spdk_rpc_register_method(const char *method, spdk_rpc_method_handler func, uint32_t state_mask)
211 {
212 	struct spdk_rpc_method *m;
213 
214 	m = calloc(1, sizeof(struct spdk_rpc_method));
215 	assert(m != NULL);
216 
217 	m->name = strdup(method);
218 	assert(m->name != NULL);
219 
220 	m->func = func;
221 	m->state_mask = state_mask;
222 
223 	/* TODO: use a hash table or sorted list */
224 	SLIST_INSERT_HEAD(&g_rpc_methods, m, slist);
225 }
226 
227 int
228 spdk_rpc_is_method_allowed(const char *method, uint32_t state_mask)
229 {
230 	struct spdk_rpc_method *m;
231 
232 	SLIST_FOREACH(m, &g_rpc_methods, slist) {
233 		if (strcmp(m->name, method) != 0) {
234 			continue;
235 		}
236 
237 		if ((m->state_mask & state_mask) == state_mask) {
238 			return 0;
239 		} else {
240 			return -EPERM;
241 		}
242 	}
243 
244 	return -ENOENT;
245 }
246 
247 void
248 spdk_rpc_close(void)
249 {
250 	if (g_jsonrpc_server) {
251 		if (g_rpc_listen_addr_unix.sun_path[0]) {
252 			/* Delete the Unix socket file */
253 			unlink(g_rpc_listen_addr_unix.sun_path);
254 		}
255 
256 		spdk_jsonrpc_server_shutdown(g_jsonrpc_server);
257 		g_jsonrpc_server = NULL;
258 
259 		if (g_rpc_lock_fd != -1) {
260 			close(g_rpc_lock_fd);
261 			g_rpc_lock_fd = -1;
262 		}
263 
264 		if (g_rpc_lock_path[0]) {
265 			unlink(g_rpc_lock_path);
266 			g_rpc_lock_path[0] = '\0';
267 		}
268 	}
269 }
270 
271 struct rpc_get_rpc_methods {
272 	bool current;
273 };
274 
275 static const struct spdk_json_object_decoder rpc_get_rpc_methods_decoders[] = {
276 	{"current", offsetof(struct rpc_get_rpc_methods, current), spdk_json_decode_bool, true},
277 };
278 
279 static void
280 spdk_rpc_get_rpc_methods(struct spdk_jsonrpc_request *request,
281 			 const struct spdk_json_val *params)
282 {
283 	struct rpc_get_rpc_methods req = {};
284 	struct spdk_json_write_ctx *w;
285 	struct spdk_rpc_method *m;
286 
287 	if (params != NULL) {
288 		if (spdk_json_decode_object(params, rpc_get_rpc_methods_decoders,
289 					    SPDK_COUNTOF(rpc_get_rpc_methods_decoders), &req)) {
290 			SPDK_ERRLOG("spdk_json_decode_object failed\n");
291 			spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
292 							 "Invalid parameters");
293 			return;
294 		}
295 	}
296 
297 	w = spdk_jsonrpc_begin_result(request);
298 	if (w == NULL) {
299 		return;
300 	}
301 
302 	spdk_json_write_array_begin(w);
303 	SLIST_FOREACH(m, &g_rpc_methods, slist) {
304 		if (req.current && ((m->state_mask & g_rpc_state) != g_rpc_state)) {
305 			continue;
306 		}
307 		spdk_json_write_string(w, m->name);
308 	}
309 	spdk_json_write_array_end(w);
310 	spdk_jsonrpc_end_result(request, w);
311 }
312 SPDK_RPC_REGISTER("get_rpc_methods", spdk_rpc_get_rpc_methods, SPDK_RPC_STARTUP | SPDK_RPC_RUNTIME)
313 
314 static void
315 spdk_rpc_get_version(struct spdk_jsonrpc_request *request, const struct spdk_json_val *params)
316 {
317 	struct spdk_json_write_ctx *w;
318 
319 	if (params != NULL) {
320 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
321 						 "get_spdk_version method requires no parameters");
322 	}
323 
324 	w = spdk_jsonrpc_begin_result(request);
325 	if (w == NULL) {
326 		return;
327 	}
328 
329 	spdk_json_write_object_begin(w);
330 
331 	spdk_json_write_named_string_fmt(w, "version", "%s", SPDK_VERSION_STRING);
332 
333 	spdk_json_write_named_object_begin(w, "fields");
334 	spdk_json_write_named_uint32(w, "major", SPDK_VERSION_MAJOR);
335 	spdk_json_write_named_uint32(w, "minor", SPDK_VERSION_MINOR);
336 
337 	spdk_json_write_named_uint32(w, "patch", SPDK_VERSION_PATCH);
338 
339 	spdk_json_write_named_string_fmt(w, "suffix", "%s", SPDK_VERSION_SUFFIX);
340 
341 	spdk_json_write_object_end(w);
342 
343 	spdk_json_write_object_end(w);
344 
345 	spdk_jsonrpc_end_result(request, w);
346 }
347 SPDK_RPC_REGISTER("get_spdk_version", spdk_rpc_get_version, SPDK_RPC_STARTUP | SPDK_RPC_RUNTIME)
348