]> git.proxmox.com Git - ceph.git/blob - ceph/src/spdk/lib/rpc/rpc.c
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / spdk / lib / rpc / rpc.c
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 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)