xzfile: lzma_code does not necessarily consume all input.
[nbdkit/ericb.git] / src / connections.c
blob15f416bce4d0eb65d5965d66781e81171bdc5ddc
1 /* nbdkit
2 * Copyright (C) 2013 Red Hat Inc.
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * * Neither the name of Red Hat nor the names of its contributors may be
17 * used to endorse or promote products derived from this software without
18 * specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
27 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
28 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
30 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
34 #include <config.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <stdint.h>
39 #include <inttypes.h>
40 #include <string.h>
41 #include <unistd.h>
42 #include <errno.h>
43 #include <endian.h>
44 #include <sys/types.h>
46 #include <pthread.h>
48 #include "nbdkit-plugin.h"
49 #include "internal.h"
50 #include "protocol.h"
52 /* Maximum read or write request that we will handle. */
53 #define MAX_REQUEST_SIZE (64 * 1024 * 1024)
55 static struct connection *new_connection (int sockin, int sockout);
56 static void free_connection (struct connection *conn);
57 static int negotiate_handshake (struct connection *conn);
58 static int recv_request_send_reply (struct connection *conn);
60 static int
61 _handle_single_connection (int sockin, int sockout)
63 int r;
64 struct connection *conn = new_connection (sockin, sockout);
66 if (!conn)
67 goto err;
69 if (plugin_open (conn, readonly) == -1)
70 goto err;
72 tls_set_name (plugin_name ());
74 /* Handshake. */
75 if (negotiate_handshake (conn) == -1)
76 goto err;
78 /* Process requests. XXX Allow these to be dispatched in parallel using
79 * a thread pool.
81 while (!quit) {
82 r = recv_request_send_reply (conn);
83 if (r == -1)
84 goto err;
85 if (r == 0)
86 break;
89 free_connection (conn);
90 return 0;
92 err:
93 free_connection (conn);
94 return -1;
97 int
98 handle_single_connection (int sockin, int sockout)
100 int r;
102 plugin_lock_connection ();
103 r = _handle_single_connection (sockin, sockout);
104 plugin_unlock_connection ();
106 return r;
109 static struct connection *
110 new_connection (int sockin, int sockout)
112 struct connection *conn;
114 conn = calloc (1, sizeof *conn);
115 if (conn == NULL) {
116 perror ("malloc");
117 return NULL;
120 conn->sockin = sockin;
121 conn->sockout = sockout;
122 pthread_mutex_init (&conn->request_lock, NULL);
124 return conn;
127 static void
128 free_connection (struct connection *conn)
130 if (!conn)
131 return;
133 if (conn->sockin >= 0)
134 close (conn->sockin);
135 if (conn->sockout >= 0 && conn->sockin != conn->sockout)
136 close (conn->sockout);
138 pthread_mutex_destroy (&conn->request_lock);
140 if (conn->handle)
141 plugin_close (conn);
143 free (conn);
146 /* XXX Note because we don't support multiple plugins or export names,
147 * we are using the old-style handshake. This will be fixed.
149 static int
150 _negotiate_handshake (struct connection *conn)
152 struct old_handshake handshake;
153 int64_t r;
154 uint64_t exportsize;
155 uint16_t gflags, eflags;
156 int fl;
158 r = plugin_get_size (conn);
159 if (r == -1)
160 return -1;
161 if (r < 0) {
162 nbdkit_error (".get_size function returned invalid value "
163 "(%" PRIi64 ")", r);
164 return -1;
166 exportsize = (uint64_t) r;
167 conn->exportsize = exportsize;
169 gflags = 0;
170 eflags = NBD_FLAG_HAS_FLAGS;
172 fl = plugin_can_write (conn);
173 if (fl == -1)
174 return -1;
175 if (readonly || !fl) {
176 eflags |= NBD_FLAG_READ_ONLY;
177 conn->readonly = 1;
180 fl = plugin_can_flush (conn);
181 if (fl == -1)
182 return -1;
183 if (fl) {
184 eflags |= NBD_FLAG_SEND_FLUSH | NBD_FLAG_SEND_FUA;
185 conn->can_flush = 1;
188 fl = plugin_is_rotational (conn);
189 if (fl == -1)
190 return -1;
191 if (fl) {
192 eflags |= NBD_FLAG_ROTATIONAL;
193 conn->is_rotational = 1;
196 fl = plugin_can_trim (conn);
197 if (fl == -1)
198 return -1;
199 if (fl) {
200 eflags |= NBD_FLAG_SEND_TRIM;
201 conn->can_trim = 1;
204 debug ("flags: global 0x%x export 0x%x", gflags, eflags);
206 memset (&handshake, 0, sizeof handshake);
207 memcpy (handshake.nbdmagic, "NBDMAGIC", 8);
208 handshake.version = htobe64 (OLD_VERSION);
209 handshake.exportsize = htobe64 (exportsize);
210 handshake.gflags = htobe16 (gflags);
211 handshake.eflags = htobe16 (eflags);
213 if (xwrite (conn->sockout, &handshake, sizeof handshake) == -1) {
214 nbdkit_error ("write: %m");
215 return -1;
218 return 0;
221 static int
222 negotiate_handshake (struct connection *conn)
224 int r;
226 plugin_lock_request (conn);
227 r = _negotiate_handshake (conn);
228 plugin_unlock_request (conn);
230 return r;
233 static int
234 valid_range (struct connection *conn, uint64_t offset, uint32_t count)
236 uint64_t exportsize = conn->exportsize;
238 return count > 0 && offset <= exportsize && offset + count <= exportsize;
241 static int
242 validate_request (struct connection *conn,
243 uint32_t cmd, uint32_t flags, uint64_t offset, uint32_t count,
244 uint32_t *error)
246 int r;
248 /* Validate cmd, offset, count. */
249 switch (cmd) {
250 case NBD_CMD_READ:
251 case NBD_CMD_WRITE:
252 case NBD_CMD_TRIM:
253 r = valid_range (conn, offset, count);
254 if (r == -1)
255 return -1;
256 if (r == 0) {
257 /* XXX Allow writes to extend the disk? */
258 nbdkit_error ("invalid request: offset and length are out of range");
259 *error = EIO;
260 return 0;
262 break;
264 case NBD_CMD_FLUSH:
265 if (offset != 0 || count != 0) {
266 nbdkit_error ("invalid flush request: expecting offset and length == 0");
267 *error = EINVAL;
268 return 0;
270 break;
272 default:
273 nbdkit_error ("invalid request: unknown command (%" PRIu32 ") ignored",
274 cmd);
275 *error = EINVAL;
276 return 0;
279 /* Refuse over-large read and write requests. */
280 if ((cmd == NBD_CMD_WRITE || cmd == NBD_CMD_READ) &&
281 count > MAX_REQUEST_SIZE) {
282 nbdkit_error ("invalid request: data request is too large (%" PRIu32
283 " > %d)", count, MAX_REQUEST_SIZE);
284 *error = ENOMEM;
285 return 0;
288 /* Readonly connection? */
289 if (conn->readonly &&
290 (cmd == NBD_CMD_WRITE || cmd == NBD_CMD_FLUSH ||
291 cmd == NBD_CMD_TRIM)) {
292 nbdkit_error ("invalid request: write request on readonly connection");
293 *error = EROFS;
294 return 0;
297 /* Flush allowed? */
298 if (!conn->can_flush && cmd == NBD_CMD_FLUSH) {
299 nbdkit_error ("invalid request: flush operation not supported");
300 *error = EINVAL;
301 return 0;
304 /* Trim allowed? */
305 if (!conn->can_trim && cmd == NBD_CMD_TRIM) {
306 nbdkit_error ("invalid request: trim operation not supported");
307 *error = EINVAL;
308 return 0;
311 return 1; /* Commands validates. */
314 /* This is called with the request lock held to actually execute the
315 * request (by calling the plugin). Note that the request fields have
316 * been validated already in 'validate_request' so we don't have to
317 * check them again. 'buf' is either the data to be written or the
318 * data to be returned, and points to a buffer of size 'count' bytes.
320 * Only returns -1 if there is a fatal error and the connection cannot
321 * continue.
323 * On read/write errors, sets *error to errno (or EIO if errno is not
324 * set) and returns 0.
326 static int
327 _handle_request (struct connection *conn,
328 uint32_t cmd, uint32_t flags, uint64_t offset, uint32_t count,
329 void *buf,
330 uint32_t *error)
332 bool flush_after_command;
333 int r;
335 /* Flush after command performed? */
336 flush_after_command = (flags & NBD_CMD_FLAG_FUA) != 0;
337 if (!conn->can_flush || conn->readonly)
338 flush_after_command = false;
340 switch (cmd) {
341 case NBD_CMD_READ:
342 r = plugin_pread (conn, buf, count, offset);
343 if (r == -1) {
344 *error = errno ? errno : EIO;
345 return 0;
347 break;
349 case NBD_CMD_WRITE:
350 r = plugin_pwrite (conn, buf, count, offset);
351 if (r == -1) {
352 *error = errno ? errno : EIO;
353 return 0;
355 break;
357 case NBD_CMD_FLUSH:
358 r = plugin_flush (conn);
359 if (r == -1) {
360 *error = errno ? errno : EIO;
361 return 0;
363 break;
365 case NBD_CMD_TRIM:
366 r = plugin_trim (conn, count, offset);
367 if (r == -1) {
368 *error = errno ? errno : EIO;
369 return 0;
371 break;
373 default:
374 abort ();
377 if (flush_after_command) {
378 r = plugin_flush (conn);
379 if (r == -1) {
380 *error = errno ? errno : EIO;
381 return 0;
385 return 0;
388 static int
389 handle_request (struct connection *conn,
390 uint32_t cmd, uint32_t flags, uint64_t offset, uint32_t count,
391 void *buf,
392 uint32_t *error)
394 int r;
396 plugin_lock_request (conn);
397 r = _handle_request (conn, cmd, flags, offset, count, buf, error);
398 plugin_unlock_request (conn);
400 return r;
403 static void
404 skip_over_write_buffer (int sock, size_t count)
406 char buf[BUFSIZ];
407 ssize_t r;
409 while (count > 0) {
410 r = read (sock, buf, count > BUFSIZ ? BUFSIZ : count);
411 if (r == -1) {
412 nbdkit_error ("skipping write buffer: %m");
413 return;
415 if (r == 0)
416 return;
417 count -= r;
421 static int
422 recv_request_send_reply (struct connection *conn)
424 int r;
425 struct request request;
426 struct reply reply;
427 uint32_t magic, cmd, flags, count, error = 0;
428 uint64_t offset;
429 CLEANUP_FREE char *buf = NULL;
431 /* Read the request packet. */
432 r = xread (conn->sockin, &request, sizeof request);
433 if (r == -1) {
434 nbdkit_error ("read request: %m");
435 return -1;
437 if (r == 0) {
438 debug ("client closed input socket, closing connection");
439 return 0; /* disconnect */
442 magic = be32toh (request.magic);
443 if (magic != NBD_REQUEST_MAGIC) {
444 nbdkit_error ("invalid request: 'magic' field is incorrect (0x%x)", magic);
445 return -1;
448 cmd = be32toh (request.type);
449 flags = cmd;
450 cmd &= NBD_CMD_MASK_COMMAND;
452 offset = be64toh (request.offset);
453 count = be32toh (request.count);
455 if (cmd == NBD_CMD_DISC) {
456 debug ("client sent disconnect command, closing connection");
457 return 0; /* disconnect */
460 /* Validate the request. */
461 r = validate_request (conn, cmd, flags, offset, count, &error);
462 if (r == -1)
463 return -1;
464 if (r == 0) { /* request not valid */
465 if (cmd == NBD_CMD_WRITE)
466 skip_over_write_buffer (conn->sockin, count);
467 goto send_reply;
470 /* Allocate the data buffer used for either read or write requests. */
471 if (cmd == NBD_CMD_READ || cmd == NBD_CMD_WRITE) {
472 buf = malloc (count);
473 if (buf == NULL) {
474 perror ("malloc");
475 error = ENOMEM;
476 if (cmd == NBD_CMD_WRITE)
477 skip_over_write_buffer (conn->sockin, count);
478 goto send_reply;
482 /* Receive the write data buffer. */
483 if (cmd == NBD_CMD_WRITE) {
484 r = xread (conn->sockin, buf, count);
485 if (r == -1) {
486 nbdkit_error ("read data: %m");
487 return -1;
489 if (r == 0) {
490 debug ("client closed input unexpectedly, closing connection");
491 return 0; /* disconnect */
495 /* Perform the request. Only this part happens inside the request lock. */
496 r = handle_request (conn, cmd, flags, offset, count, buf, &error);
497 if (r == -1)
498 return -1;
500 /* Send the reply packet. */
501 send_reply:
502 reply.magic = htobe32 (NBD_REPLY_MAGIC);
503 reply.handle = request.handle;
504 reply.error = htobe32 (error);
506 r = xwrite (conn->sockout, &reply, sizeof reply);
507 if (r == -1) {
508 nbdkit_error ("write reply: %m");
509 return -1;
512 /* Send the read data buffer. */
513 if (cmd == NBD_CMD_READ) {
514 r = xwrite (conn->sockout, buf, count);
515 if (r == -1) {
516 nbdkit_error ("write data: %m");
517 return -1;
521 return 1; /* command processed ok */