4 * Copyright (c) Intel Corporation. All rights reserved.
5 * Copyright (c) 2019 Mellanox Technologies LTD. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
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.
36 #include "spdk/stdinc.h"
38 #include "spdk/queue.h"
42 #include "spdk/string.h"
43 #include "spdk/util.h"
44 #include "spdk/version.h"
46 static struct sockaddr_un g_rpc_listen_addr_unix
= {};
47 static char g_rpc_lock_path
[sizeof(g_rpc_listen_addr_unix
.sun_path
) + sizeof(".lock")];
48 static int g_rpc_lock_fd
= -1;
50 static struct spdk_jsonrpc_server
*g_jsonrpc_server
= NULL
;
51 static uint32_t g_rpc_state
;
52 static bool g_rpcs_correct
= true;
54 struct spdk_rpc_method
{
56 spdk_rpc_method_handler func
;
57 SLIST_ENTRY(spdk_rpc_method
) slist
;
60 struct spdk_rpc_method
*is_alias_of
;
61 bool deprecation_warning_printed
;
64 static SLIST_HEAD(, spdk_rpc_method
) g_rpc_methods
= SLIST_HEAD_INITIALIZER(g_rpc_methods
);
67 spdk_rpc_set_state(uint32_t state
)
73 spdk_rpc_get_state(void)
78 static struct spdk_rpc_method
*
79 _get_rpc_method(const struct spdk_json_val
*method
)
81 struct spdk_rpc_method
*m
;
83 SLIST_FOREACH(m
, &g_rpc_methods
, slist
) {
84 if (spdk_json_strequal(method
, m
->name
)) {
92 static struct spdk_rpc_method
*
93 _get_rpc_method_raw(const char *method
)
95 struct spdk_json_val method_val
;
97 method_val
.type
= SPDK_JSON_VAL_STRING
;
98 method_val
.len
= strlen(method
);
99 method_val
.start
= (char *)method
;
101 return _get_rpc_method(&method_val
);
105 jsonrpc_handler(struct spdk_jsonrpc_request
*request
,
106 const struct spdk_json_val
*method
,
107 const struct spdk_json_val
*params
)
109 struct spdk_rpc_method
*m
;
111 assert(method
!= NULL
);
113 m
= _get_rpc_method(method
);
115 spdk_jsonrpc_send_error_response(request
, SPDK_JSONRPC_ERROR_METHOD_NOT_FOUND
, "Method not found");
119 if (m
->is_alias_of
!= NULL
) {
120 if (m
->is_deprecated
&& !m
->deprecation_warning_printed
) {
121 SPDK_WARNLOG("RPC method %s is deprecated. Use %s instead.\n", m
->name
, m
->is_alias_of
->name
);
122 m
->deprecation_warning_printed
= true;
127 if ((m
->state_mask
& g_rpc_state
) == g_rpc_state
) {
128 m
->func(request
, params
);
130 spdk_jsonrpc_send_error_response_fmt(request
, SPDK_JSONRPC_ERROR_INVALID_STATE
,
131 "Method is allowed in any state in the mask (%"PRIx32
"),"
132 " but current state is (%"PRIx32
")",
133 m
->state_mask
, g_rpc_state
);
138 spdk_rpc_listen(const char *listen_addr
)
142 memset(&g_rpc_listen_addr_unix
, 0, sizeof(g_rpc_listen_addr_unix
));
144 g_rpc_listen_addr_unix
.sun_family
= AF_UNIX
;
145 rc
= snprintf(g_rpc_listen_addr_unix
.sun_path
,
146 sizeof(g_rpc_listen_addr_unix
.sun_path
),
148 if (rc
< 0 || (size_t)rc
>= sizeof(g_rpc_listen_addr_unix
.sun_path
)) {
149 SPDK_ERRLOG("RPC Listen address Unix socket path too long\n");
150 g_rpc_listen_addr_unix
.sun_path
[0] = '\0';
154 rc
= snprintf(g_rpc_lock_path
, sizeof(g_rpc_lock_path
), "%s.lock",
155 g_rpc_listen_addr_unix
.sun_path
);
156 if (rc
< 0 || (size_t)rc
>= sizeof(g_rpc_lock_path
)) {
157 SPDK_ERRLOG("RPC lock path too long\n");
158 g_rpc_listen_addr_unix
.sun_path
[0] = '\0';
159 g_rpc_lock_path
[0] = '\0';
163 g_rpc_lock_fd
= open(g_rpc_lock_path
, O_RDONLY
| O_CREAT
, 0600);
164 if (g_rpc_lock_fd
== -1) {
165 SPDK_ERRLOG("Cannot open lock file %s: %s\n",
166 g_rpc_lock_path
, spdk_strerror(errno
));
167 g_rpc_listen_addr_unix
.sun_path
[0] = '\0';
168 g_rpc_lock_path
[0] = '\0';
172 rc
= flock(g_rpc_lock_fd
, LOCK_EX
| LOCK_NB
);
174 SPDK_ERRLOG("RPC Unix domain socket path %s in use. Specify another.\n",
175 g_rpc_listen_addr_unix
.sun_path
);
176 g_rpc_listen_addr_unix
.sun_path
[0] = '\0';
177 g_rpc_lock_path
[0] = '\0';
182 * Since we acquired the lock, it is safe to delete the Unix socket file
183 * if it still exists from a previous process.
185 unlink(g_rpc_listen_addr_unix
.sun_path
);
187 g_jsonrpc_server
= spdk_jsonrpc_server_listen(AF_UNIX
, 0,
188 (struct sockaddr
*)&g_rpc_listen_addr_unix
,
189 sizeof(g_rpc_listen_addr_unix
),
191 if (g_jsonrpc_server
== NULL
) {
192 SPDK_ERRLOG("spdk_jsonrpc_server_listen() failed\n");
193 close(g_rpc_lock_fd
);
195 unlink(g_rpc_lock_path
);
196 g_rpc_lock_path
[0] = '\0';
204 spdk_rpc_accept(void)
206 spdk_jsonrpc_server_poll(g_jsonrpc_server
);
210 spdk_rpc_register_method(const char *method
, spdk_rpc_method_handler func
, uint32_t state_mask
)
212 struct spdk_rpc_method
*m
;
214 m
= _get_rpc_method_raw(method
);
216 SPDK_ERRLOG("duplicate RPC %s registered...\n", method
);
217 g_rpcs_correct
= false;
221 m
= calloc(1, sizeof(struct spdk_rpc_method
));
224 m
->name
= strdup(method
);
225 assert(m
->name
!= NULL
);
228 m
->state_mask
= state_mask
;
230 /* TODO: use a hash table or sorted list */
231 SLIST_INSERT_HEAD(&g_rpc_methods
, m
, slist
);
235 spdk_rpc_register_alias_deprecated(const char *method
, const char *alias
)
237 struct spdk_rpc_method
*m
, *base
;
239 base
= _get_rpc_method_raw(method
);
241 SPDK_ERRLOG("cannot create alias %s - method %s does not exist\n",
243 g_rpcs_correct
= false;
247 if (base
->is_alias_of
!= NULL
) {
248 SPDK_ERRLOG("cannot create alias %s of alias %s\n", alias
, method
);
249 g_rpcs_correct
= false;
253 m
= calloc(1, sizeof(struct spdk_rpc_method
));
256 m
->name
= strdup(alias
);
257 assert(m
->name
!= NULL
);
259 m
->is_alias_of
= base
;
260 m
->is_deprecated
= true;
261 m
->state_mask
= base
->state_mask
;
263 /* TODO: use a hash table or sorted list */
264 SLIST_INSERT_HEAD(&g_rpc_methods
, m
, slist
);
268 spdk_rpc_verify_methods(void)
270 return g_rpcs_correct
;
274 spdk_rpc_is_method_allowed(const char *method
, uint32_t state_mask
)
276 struct spdk_rpc_method
*m
;
278 SLIST_FOREACH(m
, &g_rpc_methods
, slist
) {
279 if (strcmp(m
->name
, method
) != 0) {
283 if ((m
->state_mask
& state_mask
) == state_mask
) {
296 if (g_jsonrpc_server
) {
297 if (g_rpc_listen_addr_unix
.sun_path
[0]) {
298 /* Delete the Unix socket file */
299 unlink(g_rpc_listen_addr_unix
.sun_path
);
300 g_rpc_listen_addr_unix
.sun_path
[0] = '\0';
303 spdk_jsonrpc_server_shutdown(g_jsonrpc_server
);
304 g_jsonrpc_server
= NULL
;
306 if (g_rpc_lock_fd
!= -1) {
307 close(g_rpc_lock_fd
);
311 if (g_rpc_lock_path
[0]) {
312 unlink(g_rpc_lock_path
);
313 g_rpc_lock_path
[0] = '\0';
318 struct rpc_get_methods
{
320 bool include_aliases
;
323 static const struct spdk_json_object_decoder rpc_get_methods_decoders
[] = {
324 {"current", offsetof(struct rpc_get_methods
, current
), spdk_json_decode_bool
, true},
325 {"include_aliases", offsetof(struct rpc_get_methods
, include_aliases
), spdk_json_decode_bool
, true},
329 rpc_get_methods(struct spdk_jsonrpc_request
*request
, const struct spdk_json_val
*params
)
331 struct rpc_get_methods req
= {};
332 struct spdk_json_write_ctx
*w
;
333 struct spdk_rpc_method
*m
;
335 if (params
!= NULL
) {
336 if (spdk_json_decode_object(params
, rpc_get_methods_decoders
,
337 SPDK_COUNTOF(rpc_get_methods_decoders
), &req
)) {
338 SPDK_ERRLOG("spdk_json_decode_object failed\n");
339 spdk_jsonrpc_send_error_response(request
, SPDK_JSONRPC_ERROR_INVALID_PARAMS
,
340 "Invalid parameters");
345 w
= spdk_jsonrpc_begin_result(request
);
346 spdk_json_write_array_begin(w
);
347 SLIST_FOREACH(m
, &g_rpc_methods
, slist
) {
348 if (m
->is_alias_of
!= NULL
&& !req
.include_aliases
) {
351 if (req
.current
&& ((m
->state_mask
& g_rpc_state
) != g_rpc_state
)) {
354 spdk_json_write_string(w
, m
->name
);
356 spdk_json_write_array_end(w
);
357 spdk_jsonrpc_end_result(request
, w
);
359 SPDK_RPC_REGISTER("rpc_get_methods", rpc_get_methods
, SPDK_RPC_STARTUP
| SPDK_RPC_RUNTIME
)
360 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(rpc_get_methods
, get_rpc_methods
)
363 rpc_spdk_get_version(struct spdk_jsonrpc_request
*request
, const struct spdk_json_val
*params
)
365 struct spdk_json_write_ctx
*w
;
367 if (params
!= NULL
) {
368 spdk_jsonrpc_send_error_response(request
, SPDK_JSONRPC_ERROR_INVALID_PARAMS
,
369 "spdk_get_version method requires no parameters");
373 w
= spdk_jsonrpc_begin_result(request
);
374 spdk_json_write_object_begin(w
);
376 spdk_json_write_named_string_fmt(w
, "version", "%s", SPDK_VERSION_STRING
);
377 spdk_json_write_named_object_begin(w
, "fields");
378 spdk_json_write_named_uint32(w
, "major", SPDK_VERSION_MAJOR
);
379 spdk_json_write_named_uint32(w
, "minor", SPDK_VERSION_MINOR
);
380 spdk_json_write_named_uint32(w
, "patch", SPDK_VERSION_PATCH
);
381 spdk_json_write_named_string_fmt(w
, "suffix", "%s", SPDK_VERSION_SUFFIX
);
382 #ifdef SPDK_GIT_COMMIT
383 spdk_json_write_named_string_fmt(w
, "commit", "%s", SPDK_GIT_COMMIT_STRING
);
385 spdk_json_write_object_end(w
);
387 spdk_json_write_object_end(w
);
388 spdk_jsonrpc_end_result(request
, w
);
390 SPDK_RPC_REGISTER("spdk_get_version", rpc_spdk_get_version
,
391 SPDK_RPC_STARTUP
| SPDK_RPC_RUNTIME
)
392 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(spdk_get_version
, get_spdk_version
)