Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/lib9p/connection.c
39475 views
1
/*
2
* Copyright 2016 Jakub Klama <[email protected]>
3
* All rights reserved
4
*
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted providing that the following conditions
7
* are met:
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.
13
*
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.
25
*
26
*/
27
28
#include <stdlib.h>
29
#include <string.h>
30
#include <errno.h>
31
#include <assert.h>
32
#include <sys/queue.h>
33
#include "lib9p.h"
34
#include "lib9p_impl.h"
35
#include "fid.h"
36
#include "hashtable.h"
37
#include "log.h"
38
#include "threadpool.h"
39
#include "backend/backend.h"
40
41
int
42
l9p_server_init(struct l9p_server **serverp, struct l9p_backend *backend)
43
{
44
struct l9p_server *server;
45
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);
50
51
*serverp = server;
52
return (0);
53
}
54
55
int
56
l9p_connection_init(struct l9p_server *server, struct l9p_connection **conn)
57
{
58
struct l9p_connection *newconn;
59
60
assert(server != NULL);
61
assert(conn != NULL);
62
63
newconn = calloc(1, sizeof (*newconn));
64
if (newconn == NULL)
65
return (-1);
66
newconn->lc_server = server;
67
newconn->lc_msize = L9P_DEFAULT_MSIZE;
68
if (l9p_threadpool_init(&newconn->lc_tp, L9P_NUMTHREADS)) {
69
free(newconn);
70
return (-1);
71
}
72
ht_init(&newconn->lc_files, 100);
73
ht_init(&newconn->lc_requests, 100);
74
LIST_INSERT_HEAD(&server->ls_conns, newconn, lc_link);
75
*conn = newconn;
76
77
return (0);
78
}
79
80
void
81
l9p_connection_free(struct l9p_connection *conn)
82
{
83
84
LIST_REMOVE(conn, lc_link);
85
free(conn);
86
}
87
88
void
89
l9p_connection_recv(struct l9p_connection *conn, const struct iovec *iov,
90
const size_t niov, void *aux)
91
{
92
struct l9p_request *req;
93
int error;
94
95
req = l9p_calloc(1, sizeof (struct l9p_request));
96
req->lr_aux = aux;
97
req->lr_conn = conn;
98
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);
102
103
req->lr_resp_msg.lm_mode = L9P_PACK;
104
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);
108
free(req);
109
return;
110
}
111
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);
116
free(req);
117
return;
118
}
119
120
error = conn->lc_lt.lt_get_response_buffer(req,
121
req->lr_resp_msg.lm_iov,
122
&req->lr_resp_msg.lm_niov,
123
conn->lc_lt.lt_aux);
124
if (error) {
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);
128
free(req);
129
return;
130
}
131
132
/*
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).
136
*/
137
l9p_threadpool_run(&conn->lc_tp, req);
138
}
139
140
void
141
l9p_connection_close(struct l9p_connection *conn)
142
{
143
struct ht_iter iter;
144
struct l9p_fid *fid;
145
struct l9p_request *req;
146
147
L9P_LOG(L9P_DEBUG, "waiting for thread pool to shut down");
148
l9p_threadpool_shutdown(&conn->lc_tp);
149
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) {
154
#ifdef notyet
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);
160
} else
161
#endif
162
l9p_respond(req, true, false); /* use no-answer path */
163
ht_remove_at_iter(&iter);
164
}
165
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);
172
free(fid);
173
ht_remove_at_iter(&iter);
174
}
175
176
ht_destroy(&conn->lc_requests);
177
ht_destroy(&conn->lc_files);
178
}
179
180
struct l9p_fid *
181
l9p_connection_alloc_fid(struct l9p_connection *conn, uint32_t fid)
182
{
183
struct l9p_fid *file;
184
185
file = l9p_calloc(1, sizeof (struct l9p_fid));
186
file->lo_fid = fid;
187
/*
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).
192
*/
193
194
if (ht_add(&conn->lc_files, fid, file) != 0) {
195
free(file);
196
return (NULL);
197
}
198
199
return (file);
200
}
201
202
void
203
l9p_connection_remove_fid(struct l9p_connection *conn, struct l9p_fid *fid)
204
{
205
struct l9p_backend *be;
206
207
/* fid should be marked invalid by this point */
208
assert(!l9p_fid_isvalid(fid));
209
210
be = conn->lc_server->ls_backend;
211
be->freefid(be->softc, fid);
212
213
ht_remove(&conn->lc_files, fid->lo_fid);
214
free(fid);
215
}
216
217