xref: /spdk/lib/jsonrpc/jsonrpc_server_tcp.c (revision 2fb672af968d9495a388262bd76f63c74b347af1)
1488570ebSJim Harris /*   SPDX-License-Identifier: BSD-3-Clause
2a6dbe372Spaul luse  *   Copyright (C) 2016 Intel Corporation.
3376d117cSDaniel Verkamp  *   All rights reserved.
4376d117cSDaniel Verkamp  */
5376d117cSDaniel Verkamp 
6376d117cSDaniel Verkamp #include "jsonrpc_internal.h"
74d43844fSSeth Howell #include "spdk/string.h"
85b1b3ddfSPawel Wodkowski #include "spdk/util.h"
9376d117cSDaniel Verkamp 
10376d117cSDaniel Verkamp struct spdk_jsonrpc_server *
spdk_jsonrpc_server_listen(int domain,int protocol,struct sockaddr * listen_addr,socklen_t addrlen,spdk_jsonrpc_handle_request_fn handle_request)11e6d1a5acSDaniel Verkamp spdk_jsonrpc_server_listen(int domain, int protocol,
12e6d1a5acSDaniel Verkamp 			   struct sockaddr *listen_addr, socklen_t addrlen,
13376d117cSDaniel Verkamp 			   spdk_jsonrpc_handle_request_fn handle_request)
14376d117cSDaniel Verkamp {
15376d117cSDaniel Verkamp 	struct spdk_jsonrpc_server *server;
1632999ab9SJim Harris 	int rc, val, i;
17376d117cSDaniel Verkamp 
18376d117cSDaniel Verkamp 	server = calloc(1, sizeof(struct spdk_jsonrpc_server));
19376d117cSDaniel Verkamp 	if (server == NULL) {
20376d117cSDaniel Verkamp 		return NULL;
21376d117cSDaniel Verkamp 	}
22376d117cSDaniel Verkamp 
2301a9118dSPawel Wodkowski 	TAILQ_INIT(&server->free_conns);
2401a9118dSPawel Wodkowski 	TAILQ_INIT(&server->conns);
2501a9118dSPawel Wodkowski 
2601a9118dSPawel Wodkowski 	for (i = 0; i < SPDK_JSONRPC_MAX_CONNS; i++) {
2701a9118dSPawel Wodkowski 		TAILQ_INSERT_TAIL(&server->free_conns, &server->conns_array[i], link);
2801a9118dSPawel Wodkowski 	}
2901a9118dSPawel Wodkowski 
30376d117cSDaniel Verkamp 	server->handle_request = handle_request;
31376d117cSDaniel Verkamp 
32e450b8e7Szhaoshushu.zss 	server->sockfd = socket(domain, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, protocol);
33376d117cSDaniel Verkamp 	if (server->sockfd < 0) {
34376d117cSDaniel Verkamp 		SPDK_ERRLOG("socket() failed\n");
35376d117cSDaniel Verkamp 		free(server);
36376d117cSDaniel Verkamp 		return NULL;
37376d117cSDaniel Verkamp 	}
38376d117cSDaniel Verkamp 
39376d117cSDaniel Verkamp 	val = 1;
4058549382SGangCao 	rc = setsockopt(server->sockfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
4158549382SGangCao 	if (rc != 0) {
4258549382SGangCao 		SPDK_ERRLOG("could not set SO_REUSEADDR sock option: %s\n", spdk_strerror(errno));
4358549382SGangCao 		close(server->sockfd);
4458549382SGangCao 		free(server);
4558549382SGangCao 		return NULL;
4658549382SGangCao 	}
47376d117cSDaniel Verkamp 
48376d117cSDaniel Verkamp 	rc = bind(server->sockfd, listen_addr, addrlen);
49376d117cSDaniel Verkamp 	if (rc != 0) {
50891c12a6SPawel Wodkowski 		SPDK_ERRLOG("could not bind JSON-RPC server: %s\n", spdk_strerror(errno));
51376d117cSDaniel Verkamp 		close(server->sockfd);
52376d117cSDaniel Verkamp 		free(server);
53376d117cSDaniel Verkamp 		return NULL;
54376d117cSDaniel Verkamp 	}
55376d117cSDaniel Verkamp 
56376d117cSDaniel Verkamp 	rc = listen(server->sockfd, 512);
57376d117cSDaniel Verkamp 	if (rc != 0) {
58376d117cSDaniel Verkamp 		SPDK_ERRLOG("listen() failed, errno = %d\n", errno);
59376d117cSDaniel Verkamp 		close(server->sockfd);
60376d117cSDaniel Verkamp 		free(server);
61376d117cSDaniel Verkamp 		return NULL;
62376d117cSDaniel Verkamp 	}
63376d117cSDaniel Verkamp 
64376d117cSDaniel Verkamp 	return server;
65376d117cSDaniel Verkamp }
66376d117cSDaniel Verkamp 
6717c006a7Syidong0635 static struct spdk_jsonrpc_request *
jsonrpc_server_dequeue_request(struct spdk_jsonrpc_server_conn * conn)680be5557cSSeth Howell jsonrpc_server_dequeue_request(struct spdk_jsonrpc_server_conn *conn)
6917c006a7Syidong0635 {
7017c006a7Syidong0635 	struct spdk_jsonrpc_request *request = NULL;
7117c006a7Syidong0635 
7217c006a7Syidong0635 	pthread_spin_lock(&conn->queue_lock);
7317c006a7Syidong0635 	request = STAILQ_FIRST(&conn->send_queue);
7417c006a7Syidong0635 	if (request) {
7517c006a7Syidong0635 		STAILQ_REMOVE_HEAD(&conn->send_queue, link);
7617c006a7Syidong0635 	}
7717c006a7Syidong0635 	pthread_spin_unlock(&conn->queue_lock);
7817c006a7Syidong0635 	return request;
7917c006a7Syidong0635 }
8017c006a7Syidong0635 
8117c006a7Syidong0635 static void
jsonrpc_server_free_conn_request(struct spdk_jsonrpc_server_conn * conn)820be5557cSSeth Howell jsonrpc_server_free_conn_request(struct spdk_jsonrpc_server_conn *conn)
8317c006a7Syidong0635 {
8417c006a7Syidong0635 	struct spdk_jsonrpc_request *request;
8517c006a7Syidong0635 
86134590a2SSeth Howell 	jsonrpc_free_request(conn->send_request);
8717c006a7Syidong0635 	conn->send_request = NULL ;
88*2fb672afSKrzysztof Karas 
89*2fb672afSKrzysztof Karas 	pthread_spin_lock(&conn->queue_lock);
90*2fb672afSKrzysztof Karas 	/* There might still be some requests being processed.
91*2fb672afSKrzysztof Karas 	 * We need to tell them that this connection is closed. */
92*2fb672afSKrzysztof Karas 	STAILQ_FOREACH(request, &conn->outstanding_queue, link) {
93*2fb672afSKrzysztof Karas 		request->conn = NULL;
94*2fb672afSKrzysztof Karas 	}
95*2fb672afSKrzysztof Karas 	pthread_spin_unlock(&conn->queue_lock);
96*2fb672afSKrzysztof Karas 
970be5557cSSeth Howell 	while ((request = jsonrpc_server_dequeue_request(conn)) != NULL) {
98134590a2SSeth Howell 		jsonrpc_free_request(request);
9917c006a7Syidong0635 	}
10017c006a7Syidong0635 }
10117c006a7Syidong0635 
102376d117cSDaniel Verkamp static void
jsonrpc_server_conn_close(struct spdk_jsonrpc_server_conn * conn)1030be5557cSSeth Howell jsonrpc_server_conn_close(struct spdk_jsonrpc_server_conn *conn)
104cc740794SDaniel Verkamp {
105cc740794SDaniel Verkamp 	conn->closed = true;
106cc740794SDaniel Verkamp 
107cc740794SDaniel Verkamp 	if (conn->sockfd >= 0) {
1080be5557cSSeth Howell 		jsonrpc_server_free_conn_request(conn);
109cc740794SDaniel Verkamp 		close(conn->sockfd);
110cc740794SDaniel Verkamp 		conn->sockfd = -1;
1115b1b3ddfSPawel Wodkowski 
1125b1b3ddfSPawel Wodkowski 		if (conn->close_cb) {
1135b1b3ddfSPawel Wodkowski 			conn->close_cb(conn, conn->close_cb_ctx);
114cc740794SDaniel Verkamp 		}
115cc740794SDaniel Verkamp 	}
1165b1b3ddfSPawel Wodkowski }
1175b1b3ddfSPawel Wodkowski 
1185b1b3ddfSPawel Wodkowski void
spdk_jsonrpc_server_shutdown(struct spdk_jsonrpc_server * server)1195b1b3ddfSPawel Wodkowski spdk_jsonrpc_server_shutdown(struct spdk_jsonrpc_server *server)
1205b1b3ddfSPawel Wodkowski {
1215b1b3ddfSPawel Wodkowski 	struct spdk_jsonrpc_server_conn *conn;
1225b1b3ddfSPawel Wodkowski 
1235b1b3ddfSPawel Wodkowski 	close(server->sockfd);
1245b1b3ddfSPawel Wodkowski 
1255b1b3ddfSPawel Wodkowski 	TAILQ_FOREACH(conn, &server->conns, link) {
1260be5557cSSeth Howell 		jsonrpc_server_conn_close(conn);
1275b1b3ddfSPawel Wodkowski 	}
1285b1b3ddfSPawel Wodkowski 
1295b1b3ddfSPawel Wodkowski 	free(server);
1305b1b3ddfSPawel Wodkowski }
131cc740794SDaniel Verkamp 
132cc740794SDaniel Verkamp static void
jsonrpc_server_conn_remove(struct spdk_jsonrpc_server_conn * conn)1330be5557cSSeth Howell jsonrpc_server_conn_remove(struct spdk_jsonrpc_server_conn *conn)
134376d117cSDaniel Verkamp {
135376d117cSDaniel Verkamp 	struct spdk_jsonrpc_server *server = conn->server;
136376d117cSDaniel Verkamp 
1370be5557cSSeth Howell 	jsonrpc_server_conn_close(conn);
138376d117cSDaniel Verkamp 
139b066126bSPawel Wodkowski 	pthread_spin_destroy(&conn->queue_lock);
140b066126bSPawel Wodkowski 	assert(STAILQ_EMPTY(&conn->send_queue));
1414e003b67SDaniel Verkamp 
14201a9118dSPawel Wodkowski 	TAILQ_REMOVE(&server->conns, conn, link);
14301a9118dSPawel Wodkowski 	TAILQ_INSERT_HEAD(&server->free_conns, conn, link);
144376d117cSDaniel Verkamp }
145376d117cSDaniel Verkamp 
1465b1b3ddfSPawel Wodkowski int
spdk_jsonrpc_conn_add_close_cb(struct spdk_jsonrpc_server_conn * conn,spdk_jsonrpc_conn_closed_fn cb,void * ctx)1475b1b3ddfSPawel Wodkowski spdk_jsonrpc_conn_add_close_cb(struct spdk_jsonrpc_server_conn *conn,
1485b1b3ddfSPawel Wodkowski 			       spdk_jsonrpc_conn_closed_fn cb, void *ctx)
1495b1b3ddfSPawel Wodkowski {
1505b1b3ddfSPawel Wodkowski 	int rc = 0;
1515b1b3ddfSPawel Wodkowski 
1525b1b3ddfSPawel Wodkowski 	pthread_spin_lock(&conn->queue_lock);
1535b1b3ddfSPawel Wodkowski 	if (conn->close_cb == NULL) {
1545b1b3ddfSPawel Wodkowski 		conn->close_cb = cb;
1555b1b3ddfSPawel Wodkowski 		conn->close_cb_ctx = ctx;
1565b1b3ddfSPawel Wodkowski 	} else {
1575b1b3ddfSPawel Wodkowski 		rc = conn->close_cb == cb && conn->close_cb_ctx == ctx ? -EEXIST : -ENOSPC;
1585b1b3ddfSPawel Wodkowski 	}
1595b1b3ddfSPawel Wodkowski 	pthread_spin_unlock(&conn->queue_lock);
1605b1b3ddfSPawel Wodkowski 
1615b1b3ddfSPawel Wodkowski 	return rc;
1625b1b3ddfSPawel Wodkowski }
1635b1b3ddfSPawel Wodkowski 
1645b1b3ddfSPawel Wodkowski int
spdk_jsonrpc_conn_del_close_cb(struct spdk_jsonrpc_server_conn * conn,spdk_jsonrpc_conn_closed_fn cb,void * ctx)1655b1b3ddfSPawel Wodkowski spdk_jsonrpc_conn_del_close_cb(struct spdk_jsonrpc_server_conn *conn,
1665b1b3ddfSPawel Wodkowski 			       spdk_jsonrpc_conn_closed_fn cb, void *ctx)
1675b1b3ddfSPawel Wodkowski {
1685b1b3ddfSPawel Wodkowski 	int rc = 0;
1695b1b3ddfSPawel Wodkowski 
1705b1b3ddfSPawel Wodkowski 	pthread_spin_lock(&conn->queue_lock);
1715b1b3ddfSPawel Wodkowski 	if (conn->close_cb == NULL || conn->close_cb != cb || conn->close_cb_ctx != ctx) {
1725b1b3ddfSPawel Wodkowski 		rc = -ENOENT;
1735b1b3ddfSPawel Wodkowski 	} else {
1745b1b3ddfSPawel Wodkowski 		conn->close_cb = NULL;
1755b1b3ddfSPawel Wodkowski 	}
1765b1b3ddfSPawel Wodkowski 	pthread_spin_unlock(&conn->queue_lock);
1775b1b3ddfSPawel Wodkowski 
1785b1b3ddfSPawel Wodkowski 	return rc;
1795b1b3ddfSPawel Wodkowski }
1805b1b3ddfSPawel Wodkowski 
181376d117cSDaniel Verkamp static int
jsonrpc_server_accept(struct spdk_jsonrpc_server * server)1820be5557cSSeth Howell jsonrpc_server_accept(struct spdk_jsonrpc_server *server)
183376d117cSDaniel Verkamp {
184376d117cSDaniel Verkamp 	struct spdk_jsonrpc_server_conn *conn;
18501a9118dSPawel Wodkowski 	int rc, flag;
186376d117cSDaniel Verkamp 
187376d117cSDaniel Verkamp 	rc = accept(server->sockfd, NULL, NULL);
188376d117cSDaniel Verkamp 	if (rc >= 0) {
18901a9118dSPawel Wodkowski 		conn = TAILQ_FIRST(&server->free_conns);
19001a9118dSPawel Wodkowski 		assert(conn != NULL);
19101a9118dSPawel Wodkowski 
192376d117cSDaniel Verkamp 		conn->server = server;
193376d117cSDaniel Verkamp 		conn->sockfd = rc;
1944e003b67SDaniel Verkamp 		conn->closed = false;
195376d117cSDaniel Verkamp 		conn->recv_len = 0;
1964e003b67SDaniel Verkamp 		conn->outstanding_requests = 0;
197b066126bSPawel Wodkowski 		STAILQ_INIT(&conn->send_queue);
198*2fb672afSKrzysztof Karas 		STAILQ_INIT(&conn->outstanding_queue);
1994e003b67SDaniel Verkamp 		conn->send_request = NULL;
200376d117cSDaniel Verkamp 
2017192849eSSeth Howell 		if (pthread_spin_init(&conn->queue_lock, PTHREAD_PROCESS_PRIVATE)) {
2027192849eSSeth Howell 			SPDK_ERRLOG("Unable to create queue lock for socket: %d", conn->sockfd);
2037192849eSSeth Howell 			close(conn->sockfd);
2047192849eSSeth Howell 			return -1;
2057192849eSSeth Howell 		}
2067192849eSSeth Howell 
207161a3002STomasz Zawadzki 		flag = fcntl(conn->sockfd, F_GETFL);
208161a3002STomasz Zawadzki 		if (fcntl(conn->sockfd, F_SETFL, flag | O_NONBLOCK) < 0) {
209891c12a6SPawel Wodkowski 			SPDK_ERRLOG("fcntl can't set nonblocking mode for socket, fd: %d (%s)\n",
210891c12a6SPawel Wodkowski 				    conn->sockfd, spdk_strerror(errno));
211376d117cSDaniel Verkamp 			close(conn->sockfd);
2127192849eSSeth Howell 			pthread_spin_destroy(&conn->queue_lock);
213376d117cSDaniel Verkamp 			return -1;
214376d117cSDaniel Verkamp 		}
215376d117cSDaniel Verkamp 
21601a9118dSPawel Wodkowski 		TAILQ_REMOVE(&server->free_conns, conn, link);
21701a9118dSPawel Wodkowski 		TAILQ_INSERT_TAIL(&server->conns, conn, link);
218376d117cSDaniel Verkamp 		return 0;
219376d117cSDaniel Verkamp 	}
220376d117cSDaniel Verkamp 
221376d117cSDaniel Verkamp 	if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
222376d117cSDaniel Verkamp 		return 0;
223376d117cSDaniel Verkamp 	}
224376d117cSDaniel Verkamp 
225376d117cSDaniel Verkamp 	return -1;
226376d117cSDaniel Verkamp }
227376d117cSDaniel Verkamp 
228376d117cSDaniel Verkamp void
jsonrpc_server_handle_request(struct spdk_jsonrpc_request * request,const struct spdk_json_val * method,const struct spdk_json_val * params)229134590a2SSeth Howell jsonrpc_server_handle_request(struct spdk_jsonrpc_request *request,
2302bdec64fSDaniel Verkamp 			      const struct spdk_json_val *method, const struct spdk_json_val *params)
231376d117cSDaniel Verkamp {
2322bdec64fSDaniel Verkamp 	request->conn->server->handle_request(request, method, params);
233376d117cSDaniel Verkamp }
234376d117cSDaniel Verkamp 
235376d117cSDaniel Verkamp void
jsonrpc_server_handle_error(struct spdk_jsonrpc_request * request,int error)236134590a2SSeth Howell jsonrpc_server_handle_error(struct spdk_jsonrpc_request *request, int error)
237376d117cSDaniel Verkamp {
238376d117cSDaniel Verkamp 	const char *msg;
239376d117cSDaniel Verkamp 
240376d117cSDaniel Verkamp 	switch (error) {
241376d117cSDaniel Verkamp 	case SPDK_JSONRPC_ERROR_PARSE_ERROR:
242376d117cSDaniel Verkamp 		msg = "Parse error";
243376d117cSDaniel Verkamp 		break;
244376d117cSDaniel Verkamp 
245376d117cSDaniel Verkamp 	case SPDK_JSONRPC_ERROR_INVALID_REQUEST:
246376d117cSDaniel Verkamp 		msg = "Invalid request";
247376d117cSDaniel Verkamp 		break;
248376d117cSDaniel Verkamp 
249376d117cSDaniel Verkamp 	case SPDK_JSONRPC_ERROR_METHOD_NOT_FOUND:
250376d117cSDaniel Verkamp 		msg = "Method not found";
251376d117cSDaniel Verkamp 		break;
252376d117cSDaniel Verkamp 
253376d117cSDaniel Verkamp 	case SPDK_JSONRPC_ERROR_INVALID_PARAMS:
254376d117cSDaniel Verkamp 		msg = "Invalid parameters";
255376d117cSDaniel Verkamp 		break;
256376d117cSDaniel Verkamp 
257376d117cSDaniel Verkamp 	case SPDK_JSONRPC_ERROR_INTERNAL_ERROR:
258376d117cSDaniel Verkamp 		msg = "Internal error";
259376d117cSDaniel Verkamp 		break;
260376d117cSDaniel Verkamp 
261376d117cSDaniel Verkamp 	default:
262376d117cSDaniel Verkamp 		msg = "Error";
263376d117cSDaniel Verkamp 		break;
264376d117cSDaniel Verkamp 	}
265376d117cSDaniel Verkamp 
2662bdec64fSDaniel Verkamp 	spdk_jsonrpc_send_error_response(request, error, msg);
267376d117cSDaniel Verkamp }
268376d117cSDaniel Verkamp 
269376d117cSDaniel Verkamp static int
jsonrpc_server_conn_recv(struct spdk_jsonrpc_server_conn * conn)2700be5557cSSeth Howell jsonrpc_server_conn_recv(struct spdk_jsonrpc_server_conn *conn)
271376d117cSDaniel Verkamp {
272122a7763SPawel Wodkowski 	ssize_t rc, offset;
273376d117cSDaniel Verkamp 	size_t recv_avail = SPDK_JSONRPC_RECV_BUF_SIZE - conn->recv_len;
274376d117cSDaniel Verkamp 
275376d117cSDaniel Verkamp 	rc = recv(conn->sockfd, conn->recv_buf + conn->recv_len, recv_avail, 0);
276376d117cSDaniel Verkamp 	if (rc == -1) {
277376d117cSDaniel Verkamp 		if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
278376d117cSDaniel Verkamp 			return 0;
279376d117cSDaniel Verkamp 		}
2802172c432STomasz Zawadzki 		SPDK_DEBUGLOG(rpc, "recv() failed: %s\n", spdk_strerror(errno));
281376d117cSDaniel Verkamp 		return -1;
282376d117cSDaniel Verkamp 	}
283376d117cSDaniel Verkamp 
284376d117cSDaniel Verkamp 	if (rc == 0) {
2852172c432STomasz Zawadzki 		SPDK_DEBUGLOG(rpc, "remote closed connection\n");
286bbcb35f5SPawel Wodkowski 		conn->closed = true;
287bbcb35f5SPawel Wodkowski 		return 0;
288376d117cSDaniel Verkamp 	}
289376d117cSDaniel Verkamp 
290376d117cSDaniel Verkamp 	conn->recv_len += rc;
291376d117cSDaniel Verkamp 
292122a7763SPawel Wodkowski 	offset = 0;
293122a7763SPawel Wodkowski 	do {
294134590a2SSeth Howell 		rc = jsonrpc_parse_request(conn, conn->recv_buf + offset, conn->recv_len - offset);
295376d117cSDaniel Verkamp 		if (rc < 0) {
296376d117cSDaniel Verkamp 			SPDK_ERRLOG("jsonrpc parse request failed\n");
297376d117cSDaniel Verkamp 			return -1;
298376d117cSDaniel Verkamp 		}
299376d117cSDaniel Verkamp 
300122a7763SPawel Wodkowski 		offset += rc;
301122a7763SPawel Wodkowski 	} while (rc > 0);
302122a7763SPawel Wodkowski 
303122a7763SPawel Wodkowski 	if (offset > 0) {
304376d117cSDaniel Verkamp 		/*
305122a7763SPawel Wodkowski 		 * Successfully parsed a requests - move any data past the end of the
306122a7763SPawel Wodkowski 		 * parsed requests down to the beginning.
307376d117cSDaniel Verkamp 		 */
308122a7763SPawel Wodkowski 		assert((size_t)offset <= conn->recv_len);
309122a7763SPawel Wodkowski 		memmove(conn->recv_buf, conn->recv_buf + offset, conn->recv_len - offset);
310122a7763SPawel Wodkowski 		conn->recv_len -= offset;
311376d117cSDaniel Verkamp 	}
312376d117cSDaniel Verkamp 
313376d117cSDaniel Verkamp 	return 0;
314376d117cSDaniel Verkamp }
315376d117cSDaniel Verkamp 
3164e003b67SDaniel Verkamp void
jsonrpc_server_send_response(struct spdk_jsonrpc_request * request)317134590a2SSeth Howell jsonrpc_server_send_response(struct spdk_jsonrpc_request *request)
3184e003b67SDaniel Verkamp {
3190f842e86SPawel Wodkowski 	struct spdk_jsonrpc_server_conn *conn = request->conn;
3200f842e86SPawel Wodkowski 
321*2fb672afSKrzysztof Karas 	if (conn == NULL) {
322*2fb672afSKrzysztof Karas 		/* We cannot respond to the request, because the connection is closed. */
323*2fb672afSKrzysztof Karas 		SPDK_WARNLOG("Unable to send response: connection closed.\n");
324*2fb672afSKrzysztof Karas 		jsonrpc_free_request(request);
325*2fb672afSKrzysztof Karas 		return;
326*2fb672afSKrzysztof Karas 	}
327*2fb672afSKrzysztof Karas 
3284e003b67SDaniel Verkamp 	/* Queue the response to be sent */
329b066126bSPawel Wodkowski 	pthread_spin_lock(&conn->queue_lock);
330*2fb672afSKrzysztof Karas 	STAILQ_REMOVE(&conn->outstanding_queue, request, spdk_jsonrpc_request, link);
331b066126bSPawel Wodkowski 	STAILQ_INSERT_TAIL(&conn->send_queue, request, link);
332b066126bSPawel Wodkowski 	pthread_spin_unlock(&conn->queue_lock);
3334e003b67SDaniel Verkamp }
3344e003b67SDaniel Verkamp 
335b066126bSPawel Wodkowski 
336376d117cSDaniel Verkamp static int
jsonrpc_server_conn_send(struct spdk_jsonrpc_server_conn * conn)3370be5557cSSeth Howell jsonrpc_server_conn_send(struct spdk_jsonrpc_server_conn *conn)
338376d117cSDaniel Verkamp {
3394e003b67SDaniel Verkamp 	struct spdk_jsonrpc_request *request;
340376d117cSDaniel Verkamp 	ssize_t rc;
341376d117cSDaniel Verkamp 
3424e003b67SDaniel Verkamp more:
3434e003b67SDaniel Verkamp 	if (conn->outstanding_requests == 0) {
3444e003b67SDaniel Verkamp 		return 0;
3454e003b67SDaniel Verkamp 	}
3464e003b67SDaniel Verkamp 
3474e003b67SDaniel Verkamp 	if (conn->send_request == NULL) {
3480be5557cSSeth Howell 		conn->send_request = jsonrpc_server_dequeue_request(conn);
3494e003b67SDaniel Verkamp 	}
3504e003b67SDaniel Verkamp 
3514e003b67SDaniel Verkamp 	request = conn->send_request;
3524e003b67SDaniel Verkamp 	if (request == NULL) {
3534e003b67SDaniel Verkamp 		/* Nothing to send right now */
3544e003b67SDaniel Verkamp 		return 0;
3554e003b67SDaniel Verkamp 	}
3564e003b67SDaniel Verkamp 
35730b534c9SShuhei Matsumoto 	if (request->send_offset == 0) {
35830b534c9SShuhei Matsumoto 		/* A byte for the null terminator is included in the send buffer. */
35930b534c9SShuhei Matsumoto 		request->send_buf[request->send_len] = '\0';
36030b534c9SShuhei Matsumoto 	}
36130b534c9SShuhei Matsumoto 
3620f842e86SPawel Wodkowski 	if (request->send_len > 0) {
3634e003b67SDaniel Verkamp 		rc = send(conn->sockfd, request->send_buf + request->send_offset,
3644e003b67SDaniel Verkamp 			  request->send_len, 0);
365376d117cSDaniel Verkamp 		if (rc < 0) {
366376d117cSDaniel Verkamp 			if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
367376d117cSDaniel Verkamp 				return 0;
368376d117cSDaniel Verkamp 			}
369376d117cSDaniel Verkamp 
3702172c432STomasz Zawadzki 			SPDK_DEBUGLOG(rpc, "send() failed: %s\n", spdk_strerror(errno));
371376d117cSDaniel Verkamp 			return -1;
372376d117cSDaniel Verkamp 		}
373376d117cSDaniel Verkamp 
3744e003b67SDaniel Verkamp 		request->send_offset += rc;
3754e003b67SDaniel Verkamp 		request->send_len -= rc;
3760f842e86SPawel Wodkowski 	}
3774e003b67SDaniel Verkamp 
3784e003b67SDaniel Verkamp 	if (request->send_len == 0) {
3794e003b67SDaniel Verkamp 		/*
3804e003b67SDaniel Verkamp 		 * Full response has been sent.
3814e003b67SDaniel Verkamp 		 * Free it and set send_request to NULL to move on to the next queued response.
3824e003b67SDaniel Verkamp 		 */
3834e003b67SDaniel Verkamp 		conn->send_request = NULL;
384b3bec079SShuhei Matsumoto 		jsonrpc_complete_request(request);
3854e003b67SDaniel Verkamp 		goto more;
3864e003b67SDaniel Verkamp 	}
387376d117cSDaniel Verkamp 
388376d117cSDaniel Verkamp 	return 0;
389376d117cSDaniel Verkamp }
390376d117cSDaniel Verkamp 
391376d117cSDaniel Verkamp int
spdk_jsonrpc_server_poll(struct spdk_jsonrpc_server * server)392376d117cSDaniel Verkamp spdk_jsonrpc_server_poll(struct spdk_jsonrpc_server *server)
393376d117cSDaniel Verkamp {
39401a9118dSPawel Wodkowski 	int rc;
39501a9118dSPawel Wodkowski 	struct spdk_jsonrpc_server_conn *conn, *conn_tmp;
396376d117cSDaniel Verkamp 
39701a9118dSPawel Wodkowski 	TAILQ_FOREACH_SAFE(conn, &server->conns, link, conn_tmp) {
398bbcb35f5SPawel Wodkowski 		/* If we can't receive and there are no outstanding requests close the connection. */
399bbcb35f5SPawel Wodkowski 		if (conn->closed == true && conn->outstanding_requests == 0) {
4000be5557cSSeth Howell 			jsonrpc_server_conn_close(conn);
401bbcb35f5SPawel Wodkowski 		}
402bbcb35f5SPawel Wodkowski 
40317c006a7Syidong0635 		if (conn->sockfd == -1 && conn->outstanding_requests == 0) {
4040be5557cSSeth Howell 			jsonrpc_server_conn_remove(conn);
4054e003b67SDaniel Verkamp 		}
4064e003b67SDaniel Verkamp 	}
407122e2846SDaniel Verkamp 
408122e2846SDaniel Verkamp 	/* Check listen socket */
40901a9118dSPawel Wodkowski 	if (!TAILQ_EMPTY(&server->free_conns)) {
4100be5557cSSeth Howell 		jsonrpc_server_accept(server);
411122e2846SDaniel Verkamp 	}
412122e2846SDaniel Verkamp 
41301a9118dSPawel Wodkowski 	TAILQ_FOREACH(conn, &server->conns, link) {
414bbcb35f5SPawel Wodkowski 		if (conn->sockfd == -1) {
4151153b8c5SDaniel Verkamp 			continue;
4161153b8c5SDaniel Verkamp 		}
4171153b8c5SDaniel Verkamp 
4180be5557cSSeth Howell 		rc = jsonrpc_server_conn_send(conn);
419376d117cSDaniel Verkamp 		if (rc != 0) {
4200be5557cSSeth Howell 			jsonrpc_server_conn_close(conn);
4214e003b67SDaniel Verkamp 			continue;
422376d117cSDaniel Verkamp 		}
4234e003b67SDaniel Verkamp 
424bbcb35f5SPawel Wodkowski 		if (!conn->closed) {
4250be5557cSSeth Howell 			rc = jsonrpc_server_conn_recv(conn);
426376d117cSDaniel Verkamp 			if (rc != 0) {
4270be5557cSSeth Howell 				jsonrpc_server_conn_close(conn);
428bbcb35f5SPawel Wodkowski 			}
429376d117cSDaniel Verkamp 		}
430376d117cSDaniel Verkamp 	}
4314e003b67SDaniel Verkamp 
432376d117cSDaniel Verkamp 	return 0;
433376d117cSDaniel Verkamp }
434