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