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.
33 #include "spdk/string.h"
34 #include "jsonrpc_internal.h"
36 #define RPC_DEFAULT_PORT "5260"
38 static struct spdk_jsonrpc_client
*
39 _spdk_jsonrpc_client_connect(int domain
, int protocol
,
40 struct sockaddr
*server_addr
, socklen_t addrlen
)
42 struct spdk_jsonrpc_client
*client
;
45 client
= calloc(1, sizeof(struct spdk_jsonrpc_client
));
50 client
->sockfd
= socket(domain
, SOCK_STREAM
, protocol
);
51 if (client
->sockfd
< 0) {
52 SPDK_ERRLOG("socket() failed\n");
57 rc
= connect(client
->sockfd
, server_addr
, addrlen
);
59 SPDK_ERRLOG("could not connet JSON-RPC server: %s\n", spdk_strerror(errno
));
60 close(client
->sockfd
);
65 /* memory malloc for recv-buf */
66 client
->recv_buf
= malloc(SPDK_JSONRPC_SEND_BUF_SIZE_INIT
);
67 if (!client
->recv_buf
) {
68 SPDK_ERRLOG("memory malloc for recv-buf failed\n");
69 close(client
->sockfd
);
73 client
->recv_buf_size
= SPDK_JSONRPC_SEND_BUF_SIZE_INIT
;
78 struct spdk_jsonrpc_client
*
79 spdk_jsonrpc_client_connect(const char *rpc_sock_addr
, int addr_family
)
81 struct spdk_jsonrpc_client
*client
;
83 if (addr_family
== AF_UNIX
) {
84 /* Unix Domain Socket */
85 struct sockaddr_un rpc_sock_addr_unix
= {};
88 rpc_sock_addr_unix
.sun_family
= AF_UNIX
;
89 rc
= snprintf(rpc_sock_addr_unix
.sun_path
,
90 sizeof(rpc_sock_addr_unix
.sun_path
),
92 if (rc
< 0 || (size_t)rc
>= sizeof(rpc_sock_addr_unix
.sun_path
)) {
93 SPDK_ERRLOG("RPC Listen address Unix socket path too long\n");
97 client
= _spdk_jsonrpc_client_connect(AF_UNIX
, 0,
98 (struct sockaddr
*)&rpc_sock_addr_unix
,
99 sizeof(rpc_sock_addr_unix
));
102 struct addrinfo hints
;
103 struct addrinfo
*res
;
107 tmp
= strdup(rpc_sock_addr
);
109 SPDK_ERRLOG("Out of memory\n");
113 if (spdk_parse_ip_addr(tmp
, &host
, &port
) < 0) {
115 SPDK_ERRLOG("Invalid listen address '%s'\n", rpc_sock_addr
);
120 port
= RPC_DEFAULT_PORT
;
123 memset(&hints
, 0, sizeof(hints
));
124 hints
.ai_family
= AF_UNSPEC
;
125 hints
.ai_socktype
= SOCK_STREAM
;
126 hints
.ai_protocol
= IPPROTO_TCP
;
128 if (getaddrinfo(host
, port
, &hints
, &res
) != 0) {
130 SPDK_ERRLOG("Unable to look up RPC connnect address '%s'\n", rpc_sock_addr
);
134 client
= _spdk_jsonrpc_client_connect(res
->ai_family
, res
->ai_protocol
,
135 res
->ai_addr
, res
->ai_addrlen
);
145 spdk_jsonrpc_client_close(struct spdk_jsonrpc_client
*client
)
147 if (client
->sockfd
>= 0) {
148 close(client
->sockfd
);
149 free(client
->recv_buf
);
156 struct spdk_jsonrpc_client_request
*
157 spdk_jsonrpc_client_create_request(void)
159 struct spdk_jsonrpc_client_request
*request
;
161 request
= calloc(1, sizeof(*request
));
162 if (request
== NULL
) {
166 /* memory malloc for send-buf */
167 request
->send_buf
= malloc(SPDK_JSONRPC_SEND_BUF_SIZE_INIT
);
168 if (!request
->send_buf
) {
169 SPDK_ERRLOG("memory malloc for send-buf failed\n");
173 request
->send_buf_size
= SPDK_JSONRPC_SEND_BUF_SIZE_INIT
;
179 spdk_jsonrpc_client_free_request(struct spdk_jsonrpc_client_request
*req
)
186 spdk_jsonrpc_client_send_request(struct spdk_jsonrpc_client
*client
,
187 struct spdk_jsonrpc_client_request
*request
)
191 /* Reset offset in request */
192 request
->send_offset
= 0;
194 while (request
->send_len
> 0) {
195 rc
= send(client
->sockfd
, request
->send_buf
+ request
->send_offset
,
196 request
->send_len
, 0);
198 if (rc
< 0 && errno
== EINTR
) {
205 request
->send_offset
+= rc
;
206 request
->send_len
-= rc
;
213 recv_buf_expand(struct spdk_jsonrpc_client
*client
)
217 if (client
->recv_buf_size
* 2 > SPDK_JSONRPC_SEND_BUF_SIZE_MAX
) {
221 new_buf
= realloc(client
->recv_buf
, client
->recv_buf_size
* 2);
222 if (new_buf
== NULL
) {
223 SPDK_ERRLOG("Resizing recv_buf failed (current size %zu, new size %zu)\n",
224 client
->recv_buf_size
, client
->recv_buf_size
* 2);
228 client
->recv_buf
= new_buf
;
229 client
->recv_buf_size
*= 2;
235 spdk_jsonrpc_client_recv_response(struct spdk_jsonrpc_client
*client
,
236 spdk_jsonrpc_client_response_parser parser_fn
,
241 size_t recv_offset
= 0;
243 client
->parser_fn
= parser_fn
;
244 client
->parser_ctx
= parser_ctx
;
246 recv_avail
= client
->recv_buf_size
;
248 while (recv_avail
> 0) {
249 rc
= recv(client
->sockfd
, client
->recv_buf
+ recv_offset
, recv_avail
, 0);
251 if (errno
== EINTR
) {
256 } else if (rc
== 0) {
263 /* Check to see if we have received a full JSON value. */
264 rc
= spdk_jsonrpc_parse_response(client
, client
->recv_buf
, recv_offset
);
266 /* Successfully parsed response */
268 } else if (rc
!= SPDK_JSON_PARSE_INCOMPLETE
) {
269 SPDK_ERRLOG("jsonrpc parse request failed\n");
273 /* Expand receive buffer if larger one is needed */
274 if (recv_avail
== 0) {
275 rc
= recv_buf_expand(client
);
279 recv_avail
= client
->recv_buf_size
- recv_offset
;