]> git.proxmox.com Git - ceph.git/blob - ceph/src/spdk/lib/rpc/rpc.c
add subtree-ish sources for 12.0.3
[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 <assert.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <sys/select.h>
38 #include <sys/types.h>
39 #include <sys/socket.h>
40 #include <sys/un.h>
41 #include <netinet/in.h>
42 #include <netinet/tcp.h>
43 #include <arpa/inet.h>
44 #include <netdb.h>
45 #include <unistd.h>
46 #include <errno.h>
47 #include <string.h>
48
49 #include "spdk/queue.h"
50 #include "spdk/rpc.h"
51 #include "spdk/env.h"
52 #include "spdk/conf.h"
53 #include "spdk/log.h"
54 #include "spdk/string.h"
55
56 #include "spdk_internal/event.h"
57
58 #define RPC_SELECT_INTERVAL 4000 /* 4ms */
59 #define RPC_DEFAULT_LISTEN_ADDR "127.0.0.1:5260"
60 #define RPC_DEFAULT_PORT "5260"
61
62 static struct sockaddr_un g_rpc_listen_addr_unix = {};
63
64 static struct spdk_poller *g_rpc_poller = NULL;
65
66 static struct spdk_jsonrpc_server *g_jsonrpc_server = NULL;
67
68 struct spdk_rpc_method {
69 const char *name;
70 spdk_rpc_method_handler func;
71 SLIST_ENTRY(spdk_rpc_method) slist;
72 };
73
74 static SLIST_HEAD(, spdk_rpc_method) g_rpc_methods = SLIST_HEAD_INITIALIZER(g_rpc_methods);
75
76 static void
77 spdk_rpc_server_do_work(void *arg)
78 {
79 spdk_jsonrpc_server_poll(g_jsonrpc_server);
80 }
81
82 static int
83 enable_rpc(void)
84 {
85 struct spdk_conf_section *sp;
86
87 sp = spdk_conf_find_section(NULL, "Rpc");
88 if (sp == NULL) {
89 return 0;
90 }
91
92 return spdk_conf_section_get_boolval(sp, "Enable", false);
93 }
94
95 static const char *
96 rpc_get_listen_addr(void)
97 {
98 struct spdk_conf_section *sp;
99 const char *val;
100
101 sp = spdk_conf_find_section(NULL, "Rpc");
102 if (sp == NULL) {
103 return 0;
104 }
105
106 val = spdk_conf_section_get_val(sp, "Listen");
107 if (val == NULL) {
108 val = RPC_DEFAULT_LISTEN_ADDR;
109 }
110
111 return val;
112 }
113
114 void
115 spdk_rpc_register_method(const char *method, spdk_rpc_method_handler func)
116 {
117 struct spdk_rpc_method *m;
118
119 m = calloc(1, sizeof(struct spdk_rpc_method));
120 assert(m != NULL);
121
122 m->name = strdup(method);
123 assert(m->name != NULL);
124
125 m->func = func;
126
127 /* TODO: use a hash table or sorted list */
128 SLIST_INSERT_HEAD(&g_rpc_methods, m, slist);
129 }
130
131 static void
132 spdk_jsonrpc_handler(
133 struct spdk_jsonrpc_server_conn *conn,
134 const struct spdk_json_val *method,
135 const struct spdk_json_val *params,
136 const struct spdk_json_val *id)
137 {
138 struct spdk_rpc_method *m;
139
140 assert(method != NULL);
141
142 SLIST_FOREACH(m, &g_rpc_methods, slist) {
143 if (spdk_json_strequal(method, m->name)) {
144 m->func(conn, params, id);
145 return;
146 }
147 }
148
149 spdk_jsonrpc_send_error_response(conn, id, SPDK_JSONRPC_ERROR_METHOD_NOT_FOUND, "Method not found");
150 }
151
152 static void
153 spdk_rpc_setup(void *arg)
154 {
155 struct addrinfo hints;
156 struct addrinfo *res;
157 const char *listen_addr;
158
159 memset(&g_rpc_listen_addr_unix, 0, sizeof(g_rpc_listen_addr_unix));
160
161 /* Unregister the one-shot setup poller */
162 spdk_poller_unregister(&g_rpc_poller, NULL);
163
164 if (!enable_rpc()) {
165 return;
166 }
167
168 listen_addr = rpc_get_listen_addr();
169 if (!listen_addr) {
170 return;
171 }
172
173 if (listen_addr[0] == '/') {
174 int rc;
175
176 g_rpc_listen_addr_unix.sun_family = AF_UNIX;
177 rc = snprintf(g_rpc_listen_addr_unix.sun_path,
178 sizeof(g_rpc_listen_addr_unix.sun_path),
179 "%s", listen_addr);
180 if (rc < 0 || (size_t)rc >= sizeof(g_rpc_listen_addr_unix.sun_path)) {
181 SPDK_ERRLOG("RPC Listen address Unix socket path too long\n");
182 g_rpc_listen_addr_unix.sun_path[0] = '\0';
183 return;
184 }
185
186 unlink(g_rpc_listen_addr_unix.sun_path);
187
188 g_jsonrpc_server = spdk_jsonrpc_server_listen(AF_UNIX, 0,
189 (struct sockaddr *)&g_rpc_listen_addr_unix,
190 sizeof(g_rpc_listen_addr_unix),
191 spdk_jsonrpc_handler);
192 } else {
193 char *tmp;
194 char *host, *port;
195
196 tmp = strdup(listen_addr);
197 if (!tmp) {
198 SPDK_ERRLOG("Out of memory\n");
199 return;
200 }
201
202 if (spdk_parse_ip_addr(tmp, &host, &port) < 0) {
203 free(tmp);
204 SPDK_ERRLOG("Invalid listen address '%s'\n", listen_addr);
205 return;
206 }
207
208 if (port == NULL) {
209 port = RPC_DEFAULT_PORT;
210 }
211
212 memset(&hints, 0, sizeof(hints));
213 hints.ai_family = AF_UNSPEC;
214 hints.ai_socktype = SOCK_STREAM;
215 hints.ai_protocol = IPPROTO_TCP;
216
217 if (getaddrinfo(host, port, &hints, &res) != 0) {
218 free(tmp);
219 SPDK_ERRLOG("Unable to look up RPC listen address '%s'\n", listen_addr);
220 return;
221 }
222
223 g_jsonrpc_server = spdk_jsonrpc_server_listen(res->ai_family, res->ai_protocol,
224 res->ai_addr, res->ai_addrlen,
225 spdk_jsonrpc_handler);
226
227 freeaddrinfo(res);
228 free(tmp);
229 }
230
231 if (g_jsonrpc_server == NULL) {
232 SPDK_ERRLOG("spdk_jsonrpc_server_listen() failed\n");
233 return;
234 }
235
236 /* Register the periodic rpc_server_do_work */
237 spdk_poller_register(&g_rpc_poller, spdk_rpc_server_do_work, NULL, spdk_env_get_current_core(),
238 RPC_SELECT_INTERVAL);
239 }
240
241 static int
242 spdk_rpc_initialize(void)
243 {
244 /*
245 * Defer setup of the RPC service until the reactor has started. This
246 * allows us to detect the RPC listen socket as a suitable proxy for determining
247 * when the SPDK application has finished initialization and ready for logins
248 * or RPC commands.
249 */
250 spdk_poller_register(&g_rpc_poller, spdk_rpc_setup, NULL, spdk_env_get_current_core(), 0);
251 return 0;
252 }
253
254 static int
255 spdk_rpc_finish(void)
256 {
257 if (g_rpc_listen_addr_unix.sun_path[0]) {
258 /* Delete the Unix socket file */
259 unlink(g_rpc_listen_addr_unix.sun_path);
260 }
261
262 spdk_poller_unregister(&g_rpc_poller, NULL);
263
264 if (g_jsonrpc_server) {
265 spdk_jsonrpc_server_shutdown(g_jsonrpc_server);
266 }
267
268 return 0;
269 }
270
271 static void
272 spdk_rpc_config_text(FILE *fp)
273 {
274 fprintf(fp,
275 "\n"
276 "[Rpc]\n"
277 " # Defines whether to enable configuration via RPC.\n"
278 " # Default is disabled. Note that the RPC interface is not\n"
279 " # authenticated, so users should be careful about enabling\n"
280 " # RPC in non-trusted environments.\n"
281 " Enable %s\n"
282 " # Listen address for the RPC service.\n"
283 " # May be an IP address or an absolute path to a Unix socket.\n"
284 " Listen %s\n",
285 enable_rpc() ? "Yes" : "No", rpc_get_listen_addr());
286 }
287
288 SPDK_SUBSYSTEM_REGISTER(spdk_rpc, spdk_rpc_initialize, spdk_rpc_finish, spdk_rpc_config_text)