4 * Copyright (c) Intel Corporation.
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"
45 #define RPC_DEFAULT_PORT "5260"
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;
51 static struct spdk_jsonrpc_server
*g_jsonrpc_server
= NULL
;
52 static uint32_t g_rpc_state
;
54 struct spdk_rpc_method
{
56 spdk_rpc_method_handler func
;
57 SLIST_ENTRY(spdk_rpc_method
) slist
;
61 static SLIST_HEAD(, spdk_rpc_method
) g_rpc_methods
= SLIST_HEAD_INITIALIZER(g_rpc_methods
);
64 spdk_rpc_set_state(uint32_t state
)
70 spdk_jsonrpc_handler(struct spdk_jsonrpc_request
*request
,
71 const struct spdk_json_val
*method
,
72 const struct spdk_json_val
*params
)
74 struct spdk_rpc_method
*m
;
76 assert(method
!= NULL
);
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
);
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
);
92 spdk_jsonrpc_send_error_response(request
, SPDK_JSONRPC_ERROR_METHOD_NOT_FOUND
, "Method not found");
96 spdk_rpc_listen(const char *listen_addr
)
98 struct addrinfo hints
;
101 memset(&g_rpc_listen_addr_unix
, 0, sizeof(g_rpc_listen_addr_unix
));
103 if (listen_addr
[0] == '/') {
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
),
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';
116 snprintf(g_rpc_lock_path
, sizeof(g_rpc_lock_path
), "%s.lock",
117 g_rpc_listen_addr_unix
.sun_path
);
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
));
126 rc
= flock(g_rpc_lock_fd
, LOCK_EX
| LOCK_NB
);
128 SPDK_ERRLOG("RPC Unix domain socket path %s in use. Specify another.\n",
129 g_rpc_listen_addr_unix
.sun_path
);
134 * Since we acquired the lock, it is safe to delete the Unix socket file
135 * if it still exists from a previous process.
137 unlink(g_rpc_listen_addr_unix
.sun_path
);
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
);
146 unlink(g_rpc_lock_path
);
147 g_rpc_lock_path
[0] = '\0';
153 tmp
= strdup(listen_addr
);
155 SPDK_ERRLOG("Out of memory\n");
159 if (spdk_parse_ip_addr(tmp
, &host
, &port
) < 0) {
161 SPDK_ERRLOG("Invalid listen address '%s'\n", listen_addr
);
166 port
= RPC_DEFAULT_PORT
;
169 memset(&hints
, 0, sizeof(hints
));
170 hints
.ai_family
= AF_UNSPEC
;
171 hints
.ai_socktype
= SOCK_STREAM
;
172 hints
.ai_protocol
= IPPROTO_TCP
;
174 if (getaddrinfo(host
, port
, &hints
, &res
) != 0) {
176 SPDK_ERRLOG("Unable to look up RPC listen address '%s'\n", listen_addr
);
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
);
188 if (g_jsonrpc_server
== NULL
) {
189 SPDK_ERRLOG("spdk_jsonrpc_server_listen() failed\n");
197 spdk_rpc_accept(void)
199 spdk_jsonrpc_server_poll(g_jsonrpc_server
);
203 spdk_rpc_register_method(const char *method
, spdk_rpc_method_handler func
, uint32_t state_mask
)
205 struct spdk_rpc_method
*m
;
207 m
= calloc(1, sizeof(struct spdk_rpc_method
));
210 m
->name
= strdup(method
);
211 assert(m
->name
!= NULL
);
214 m
->state_mask
= state_mask
;
216 /* TODO: use a hash table or sorted list */
217 SLIST_INSERT_HEAD(&g_rpc_methods
, m
, slist
);
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
);
229 spdk_jsonrpc_server_shutdown(g_jsonrpc_server
);
230 g_jsonrpc_server
= NULL
;
232 if (g_rpc_lock_fd
!= -1) {
233 close(g_rpc_lock_fd
);
237 if (g_rpc_lock_path
[0]) {
238 unlink(g_rpc_lock_path
);
239 g_rpc_lock_path
[0] = '\0';
244 struct rpc_get_rpc_methods
{
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},
253 spdk_rpc_get_rpc_methods(struct spdk_jsonrpc_request
*request
,
254 const struct spdk_json_val
*params
)
256 struct rpc_get_rpc_methods req
= {};
257 struct spdk_json_write_ctx
*w
;
258 struct spdk_rpc_method
*m
;
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");
270 w
= spdk_jsonrpc_begin_result(request
);
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
)) {
280 spdk_json_write_string(w
, m
->name
);
282 spdk_json_write_array_end(w
);
283 spdk_jsonrpc_end_result(request
, w
);
285 SPDK_RPC_REGISTER("get_rpc_methods", spdk_rpc_get_rpc_methods
, SPDK_RPC_STARTUP
| SPDK_RPC_RUNTIME
)