2 * Copyright 2016 Jakub Klama <jceel@FreeBSD.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted providing that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
22 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
23 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/queue.h>
34 #include "lib9p_impl.h"
36 #include "hashtable.h"
38 #include "threadpool.h"
39 #include "backend/backend.h"
42 l9p_server_init(struct l9p_server **serverp, struct l9p_backend *backend)
44 struct l9p_server *server;
46 server = l9p_calloc(1, sizeof (*server));
47 server->ls_max_version = L9P_2000L;
48 server->ls_backend = backend;
49 LIST_INIT(&server->ls_conns);
56 l9p_connection_init(struct l9p_server *server, struct l9p_connection **conn)
58 struct l9p_connection *newconn;
60 assert(server != NULL);
63 newconn = calloc(1, sizeof (*newconn));
66 newconn->lc_server = server;
67 newconn->lc_msize = L9P_DEFAULT_MSIZE;
68 if (l9p_threadpool_init(&newconn->lc_tp, L9P_NUMTHREADS)) {
72 ht_init(&newconn->lc_files, 100);
73 ht_init(&newconn->lc_requests, 100);
74 LIST_INSERT_HEAD(&server->ls_conns, newconn, lc_link);
81 l9p_connection_free(struct l9p_connection *conn)
84 LIST_REMOVE(conn, lc_link);
89 l9p_connection_recv(struct l9p_connection *conn, const struct iovec *iov,
90 const size_t niov, void *aux)
92 struct l9p_request *req;
95 req = l9p_calloc(1, sizeof (struct l9p_request));
99 req->lr_req_msg.lm_mode = L9P_UNPACK;
100 req->lr_req_msg.lm_niov = niov;
101 memcpy(req->lr_req_msg.lm_iov, iov, sizeof (struct iovec) * niov);
103 req->lr_resp_msg.lm_mode = L9P_PACK;
105 if (l9p_pufcall(&req->lr_req_msg, &req->lr_req, conn->lc_version) != 0) {
106 L9P_LOG(L9P_WARNING, "cannot unpack received message");
107 l9p_freefcall(&req->lr_req);
112 if (ht_add(&conn->lc_requests, req->lr_req.hdr.tag, req)) {
113 L9P_LOG(L9P_WARNING, "client reusing outstanding tag %d",
114 req->lr_req.hdr.tag);
115 l9p_freefcall(&req->lr_req);
120 error = conn->lc_lt.lt_get_response_buffer(req,
121 req->lr_resp_msg.lm_iov,
122 &req->lr_resp_msg.lm_niov,
125 L9P_LOG(L9P_WARNING, "cannot obtain buffers for response");
126 ht_remove(&conn->lc_requests, req->lr_req.hdr.tag);
127 l9p_freefcall(&req->lr_req);
133 * NB: it's up to l9p_threadpool_run to decide whether
134 * to queue the work or to run it immediately and wait
135 * (it must do the latter for Tflush requests).
137 l9p_threadpool_run(&conn->lc_tp, req);
141 l9p_connection_close(struct l9p_connection *conn)
145 struct l9p_request *req;
147 L9P_LOG(L9P_DEBUG, "waiting for thread pool to shut down");
148 l9p_threadpool_shutdown(&conn->lc_tp);
150 /* Drain pending requests (if any) */
151 L9P_LOG(L9P_DEBUG, "draining pending requests");
152 ht_iter(&conn->lc_requests, &iter);
153 while ((req = ht_next(&iter)) != NULL) {
155 /* XXX would be good to know if there is anyone listening */
156 if (anyone listening) {
157 /* XXX crude - ops like Tclunk should succeed */
158 req->lr_error = EINTR;
159 l9p_respond(req, false, false);
162 l9p_respond(req, true, false); /* use no-answer path */
163 ht_remove_at_iter(&iter);
166 /* Close opened files (if any) */
167 L9P_LOG(L9P_DEBUG, "closing opened files");
168 ht_iter(&conn->lc_files, &iter);
169 while ((fid = ht_next(&iter)) != NULL) {
170 conn->lc_server->ls_backend->freefid(
171 conn->lc_server->ls_backend->softc, fid);
173 ht_remove_at_iter(&iter);
176 ht_destroy(&conn->lc_requests);
177 ht_destroy(&conn->lc_files);
181 l9p_connection_alloc_fid(struct l9p_connection *conn, uint32_t fid)
183 struct l9p_fid *file;
185 file = l9p_calloc(1, sizeof (struct l9p_fid));
188 * Note that the new fid is not marked valid yet.
189 * The insert here will fail if the fid number is
190 * in use, otherwise we have an invalid fid in the
191 * table (as desired).
194 if (ht_add(&conn->lc_files, fid, file) != 0) {
203 l9p_connection_remove_fid(struct l9p_connection *conn, struct l9p_fid *fid)
205 struct l9p_backend *be;
207 /* fid should be marked invalid by this point */
208 assert(!l9p_fid_isvalid(fid));
210 be = conn->lc_server->ls_backend;
211 be->freefid(be->softc, fid);
213 ht_remove(&conn->lc_files, fid->lo_fid);