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