Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2016, Citrix Systems, Inc.
3 : : *
4 : : * All rights reserved.
5 : : *
6 : : * Redistribution and use in source and binary forms, with or without
7 : : * modification, are permitted provided that the following conditions are met:
8 : : *
9 : : * 1. Redistributions of source code must retain the above copyright
10 : : * notice, this list of conditions and the following disclaimer.
11 : : * 2. Redistributions in binary form must reproduce the above copyright
12 : : * notice, this list of conditions and the following disclaimer in the
13 : : * documentation and/or other materials provided with the distribution.
14 : : * 3. Neither the name of the copyright holder nor the names of its
15 : : * contributors may be used to endorse or promote products derived from
16 : : * this software without specific prior written permission.
17 : : *
18 : : * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 : : * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 : : * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 : : * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
22 : : * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 : : * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 : : * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 : : * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26 : : * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 : : * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 : : * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 : : */
30 : :
31 : : #include <errno.h>
32 : : #include <stdio.h>
33 : : #include <fcntl.h>
34 : : #include <unistd.h>
35 : : #include <stdlib.h>
36 : : #include <sys/mman.h>
37 : : #include <sys/socket.h>
38 : : #include <sys/un.h>
39 : : #include <sys/types.h>
40 : : #include <sys/stat.h>
41 : : #include <netdb.h>
42 : : #include <arpa/inet.h>
43 : : #include <netinet/tcp.h>
44 : : #include <netinet/in.h>
45 : : #include "tapdisk.h"
46 : : #include "tapdisk-server.h"
47 : : #include "tapdisk-driver.h"
48 : : #include "tapdisk-interface.h"
49 : : #include "tapdisk-utils.h"
50 : : #include "tapdisk-fdreceiver.h"
51 : : #include "timeout-math.h"
52 : : #include "tapdisk-nbdserver.h"
53 : : #include "tapdisk-protocol-new.h"
54 : : #include "util.h"
55 : :
56 : : #ifdef HAVE_CONFIG_H
57 : : #include "config.h"
58 : : #endif
59 : :
60 : : #define INFO(_f, _a...) tlog_syslog(TLOG_INFO, "nbd: " _f, ##_a)
61 : : #define ERROR(_f, _a...) tlog_syslog(TLOG_WARN, "nbd: " _f, ##_a)
62 : :
63 : : #define N_PASSED_FDS 10
64 : : #define TAPDISK_NBDCLIENT_MAX_PATH_LEN 256
65 : :
66 : : #define MAX_NBD_REQS TAPDISK_DATA_REQUESTS
67 : : #define NBD_TIMEOUT 30
68 : : #define RECV_BUFFER_SIZE 256
69 : :
70 : : static const int CLIENT_USE_OLD_HANDSHAKE = 1;
71 : :
72 : : /*
73 : : * We'll only ever have one nbdclient fd receiver per tapdisk process, so let's
74 : : * just store it here globally. We'll also keep track of the passed fds here
75 : : * too.
76 : : */
77 : :
78 : : struct td_fdreceiver *fdreceiver = NULL;
79 : :
80 : : struct tdnbd_passed_fd {
81 : : char id[40];
82 : : int fd;
83 : : } passed_fds[N_PASSED_FDS];
84 : :
85 : : struct nbd_queued_io {
86 : : char *buffer;
87 : : int len;
88 : : int so_far;
89 : : };
90 : :
91 : : struct td_nbd_request {
92 : : td_request_t treq;
93 : : struct nbd_request nreq;
94 : : int timeout_event;
95 : : int fake;
96 : : struct nbd_queued_io header;
97 : : struct nbd_queued_io body; /* in or out, depending on whether
98 : : type is read or write. */
99 : : struct list_head queue;
100 : : };
101 : :
102 : : struct tdnbd_data
103 : : {
104 : : int writer_event_id;
105 : : struct list_head sent_reqs;
106 : : struct list_head pending_reqs;
107 : : struct list_head free_reqs;
108 : : struct td_nbd_request requests[MAX_NBD_REQS];
109 : : int nr_free_count;
110 : :
111 : : int reader_event_id;
112 : : struct nbd_reply current_reply;
113 : : struct nbd_queued_io cur_reply_qio;
114 : : struct td_nbd_request *curr_reply_req;
115 : :
116 : : int socket;
117 : : /*
118 : : * TODO tapdisk can talk to an Internet socket or a UNIX domain socket.
119 : : * Try to group struct members accordingly e.g. in a union.
120 : : */
121 : : struct sockaddr_in *remote;
122 : : struct sockaddr_un remote_un;
123 : : char *peer_ip;
124 : : int port;
125 : : char *name;
126 : :
127 : : int flags;
128 : : int closed;
129 : : };
130 : :
131 : : int global_id = 0;
132 : :
133 : : static void disable_write_queue(struct tdnbd_data *prv);
134 : :
135 : :
136 : : /* -- fdreceiver bits and pieces -- */
137 : :
138 : : static void
139 : 0 : tdnbd_stash_passed_fd(int fd, char *msg, void *data)
140 : : {
141 : 0 : int free_index = -1;
142 : : int i;
143 [ # # ]: 0 : for (i = 0; i < N_PASSED_FDS; i++)
144 : : /* Check for unused slot before attempting to compare
145 : : * names so that we never try to compare against the name
146 : : * of an unused slot */
147 [ # # ][ # # ]: 0 : if (passed_fds[i].fd == -1 || strncmp(msg, passed_fds[i].id,
148 : : sizeof(passed_fds[i].id) - 1) == 0) {
149 : : free_index = i;
150 : : break;
151 : : }
152 : :
153 [ # # ]: 0 : if (free_index == -1) {
154 : 0 : ERROR("Error - more than %d fds passed! cannot stash another",
155 : : N_PASSED_FDS);
156 : 0 : close(fd);
157 : 0 : return;
158 : : }
159 : :
160 : : /* There exists a possibility that the FD we are replacing is still
161 : : * open. Unconditionally close it here to avoid leaking FDs. Do not
162 : : * care about errors from close(). */
163 [ # # ]: 0 : if (passed_fds[free_index].fd > -1)
164 : 0 : close(passed_fds[free_index].fd);
165 : :
166 : 0 : passed_fds[free_index].fd = fd;
167 : 0 : safe_strncpy(passed_fds[free_index].id, msg,
168 : : sizeof(passed_fds[free_index].id));
169 : : }
170 : :
171 : : static int
172 : 0 : tdnbd_retrieve_passed_fd(const char *name)
173 : : {
174 : : int fd, i;
175 : :
176 [ # # ]: 0 : for (i = 0; i < N_PASSED_FDS; i++) {
177 [ # # ]: 0 : if (strncmp(name, passed_fds[i].id,
178 : : sizeof(passed_fds[i].id) - 1) == 0) {
179 : 0 : fd = passed_fds[i].fd;
180 : 0 : passed_fds[i].fd = -1;
181 : 0 : return fd;
182 : : }
183 : : }
184 : :
185 : 0 : ERROR("Couldn't find the fd named: %s", name);
186 : :
187 : 0 : return -1;
188 : : }
189 : :
190 : : void
191 : 0 : tdnbd_fdreceiver_start()
192 : : {
193 : : char fdreceiver_path[TAPDISK_NBDCLIENT_MAX_PATH_LEN];
194 : : int i;
195 : :
196 : : /* initialise the passed fds list */
197 [ # # ]: 0 : for (i = 0; i < N_PASSED_FDS; i++)
198 : 0 : passed_fds[i].fd = -1;
199 : :
200 : 0 : snprintf(fdreceiver_path, TAPDISK_NBDCLIENT_MAX_PATH_LEN,
201 : : "%s%d", TAPDISK_NBDCLIENT_LISTEN_SOCK_PATH, getpid());
202 : :
203 : 0 : fdreceiver = td_fdreceiver_start(fdreceiver_path,
204 : : tdnbd_stash_passed_fd, NULL);
205 : :
206 : 0 : }
207 : :
208 : : void
209 : 0 : tdnbd_fdreceiver_stop()
210 : : {
211 [ # # ]: 0 : if (fdreceiver)
212 : 0 : td_fdreceiver_stop(fdreceiver);
213 : 0 : }
214 : :
215 : : static void
216 : 0 : __cancel_req(int i, struct td_nbd_request *pos, int e)
217 : : {
218 : : char handle[9];
219 : 0 : memcpy(handle, pos->nreq.handle, 8);
220 : 0 : handle[8] = 0;
221 : 0 : INFO("Entry %d: handle='%s' type=%d, len=%d: %s",
222 : : i, handle, ntohl(pos->nreq.type), ntohl(pos->nreq.len), strerror(e));
223 : :
224 [ # # ]: 0 : if (pos->timeout_event >= 0) {
225 : 0 : tapdisk_server_unregister_event(pos->timeout_event);
226 : 0 : pos->timeout_event = -1;
227 : : }
228 : :
229 : 0 : td_complete_request(pos->treq, e);
230 : 0 : }
231 : :
232 : : static void
233 : 0 : tdnbd_disable(struct tdnbd_data *prv, int e)
234 : : {
235 : : struct td_nbd_request *pos, *q;
236 : 0 : int i = 0;
237 : :
238 : 0 : INFO("NBD client full-disable");
239 : :
240 : 0 : tapdisk_server_unregister_event(prv->writer_event_id);
241 : 0 : tapdisk_server_unregister_event(prv->reader_event_id);
242 : :
243 : 0 : INFO("NBD client cancelling sent reqs");
244 [ # # ]: 0 : list_for_each_entry_safe(pos, q, &prv->sent_reqs, queue)
245 : 0 : __cancel_req(i++, pos, e);
246 : :
247 : 0 : INFO("NBD client cancelling pending reqs");
248 [ # # ]: 0 : list_for_each_entry_safe(pos, q, &prv->pending_reqs, queue)
249 : 0 : __cancel_req(i++, pos, e);
250 : :
251 : 0 : INFO("Setting closed");
252 : 0 : prv->closed = 3;
253 : 0 : }
254 : :
255 : : /* NBD writer queue */
256 : :
257 : : /* Return code: how much is left to write, or a negative error code */
258 : : static int
259 : 0 : tdnbd_write_some(int fd, struct nbd_queued_io *data)
260 : : {
261 : 0 : int left = data->len - data->so_far;
262 : : int rc;
263 : : char *code;
264 : :
265 [ # # ]: 0 : while (left > 0) {
266 : 0 : rc = send(fd, data->buffer + data->so_far, left, 0);
267 : :
268 [ # # ]: 0 : if (rc == -1) {
269 [ # # ]: 0 : if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
270 : : return left;
271 : :
272 : 0 : code = strerror(errno);
273 [ # # ]: 0 : ERROR("Bad return code %d from send (%s)", rc,
274 : : (code == 0 ? "unknown" : code));
275 : 0 : return rc;
276 : : }
277 : :
278 [ # # ]: 0 : if (rc == 0) {
279 : 0 : ERROR("Server shutdown prematurely in write_some");
280 : 0 : return -1;
281 : : }
282 : :
283 : 0 : left -= rc;
284 : 0 : data->so_far += rc;
285 : : }
286 : :
287 : : return left;
288 : : }
289 : :
290 : : static int
291 : 0 : tdnbd_read_some(int fd, struct nbd_queued_io *data)
292 : : {
293 : 0 : int left = data->len - data->so_far;
294 : : int rc;
295 : : char *code;
296 : :
297 [ # # ]: 0 : while (left > 0) {
298 : 0 : rc = recv(fd, data->buffer + data->so_far, left, 0);
299 : :
300 [ # # ]: 0 : if (rc == -1) {
301 : :
302 [ # # ]: 0 : if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
303 : : return left;
304 : :
305 : 0 : code = strerror(errno);
306 [ # # ]: 0 : ERROR("Bad return code %d from send (%s)", rc,
307 : : (code == 0 ? "unknown" : code));
308 : 0 : return rc;
309 : : }
310 : :
311 [ # # ]: 0 : if (rc == 0) {
312 : 0 : ERROR("Server shutdown prematurely in read_some");
313 : 0 : return -1;
314 : : }
315 : :
316 : 0 : data->so_far += rc;
317 : 0 : left -= rc;
318 : : }
319 : :
320 : : return left;
321 : : }
322 : :
323 : : static void
324 : 0 : tdnbd_writer_cb(event_id_t eb, char mode, void *data)
325 : : {
326 : : struct td_nbd_request *pos, *q;
327 : 0 : struct tdnbd_data *prv = data;
328 : :
329 [ # # ]: 0 : list_for_each_entry_safe(pos, q, &prv->pending_reqs, queue) {
330 [ # # ]: 0 : if (tdnbd_write_some(prv->socket, &pos->header) > 0)
331 : : return;
332 : :
333 [ # # ]: 0 : if (ntohl(pos->nreq.type) == TAPDISK_NBD_CMD_WRITE) {
334 [ # # ]: 0 : if (tdnbd_write_some(prv->socket, &pos->body) > 0)
335 : : return;
336 : : }
337 : :
338 [ # # ]: 0 : if (ntohl(pos->nreq.type) == TAPDISK_NBD_CMD_DISC) {
339 : 0 : INFO("sent close request");
340 : : /*
341 : : * We don't expect a response from a DISC, so move the
342 : : * request back onto the free list
343 : : */
344 : 0 : list_move(&pos->queue, &prv->free_reqs);
345 : 0 : prv->nr_free_count++;
346 : 0 : prv->closed = 2;
347 : : } else {
348 : 0 : list_move(&pos->queue, &prv->sent_reqs);
349 : : }
350 : : }
351 : :
352 : : /* If we're here, we've written everything */
353 : :
354 : 0 : disable_write_queue(prv);
355 : :
356 [ # # ]: 0 : if (prv->closed == 2)
357 : 0 : tdnbd_disable(prv, EIO);
358 : :
359 : : return;
360 : : }
361 : :
362 : : static int
363 : 0 : enable_write_queue(struct tdnbd_data *prv)
364 : : {
365 [ # # ]: 0 : if (prv->writer_event_id >= 0)
366 : : return 0;
367 : :
368 : 0 : prv->writer_event_id =
369 : 0 : tapdisk_server_register_event(SCHEDULER_POLL_WRITE_FD,
370 : : prv->socket,
371 : 0 : TV_ZERO,
372 : : tdnbd_writer_cb,
373 : : prv);
374 : :
375 : 0 : return prv->writer_event_id;
376 : : }
377 : :
378 : : static void
379 : 0 : disable_write_queue(struct tdnbd_data *prv)
380 : : {
381 [ # # ]: 0 : if (prv->writer_event_id < 0)
382 : 0 : return;
383 : :
384 : 0 : tapdisk_server_unregister_event(prv->writer_event_id);
385 : :
386 : 0 : prv->writer_event_id = -1;
387 : : }
388 : :
389 : : static int
390 : 0 : tdnbd_queue_request(struct tdnbd_data *prv, int type, uint64_t offset,
391 : : char *buffer, uint32_t length, td_request_t treq, int fake)
392 : : {
393 [ # # ]: 0 : if (prv->nr_free_count == 0)
394 : : return -EBUSY;
395 : :
396 [ # # ]: 0 : if (prv->closed == 3) {
397 : 0 : td_complete_request(treq, -ETIMEDOUT);
398 : 0 : return -ETIMEDOUT;
399 : : }
400 : :
401 : 0 : struct td_nbd_request *req = list_entry(prv->free_reqs.next,
402 : : struct td_nbd_request, queue);
403 : :
404 : : /* fill in the request */
405 : :
406 : 0 : req->treq = treq;
407 : 0 : int id = global_id++;
408 : 0 : snprintf(req->nreq.handle, 8, "td%05x", id % 0xffff);
409 : :
410 : : /* Don't time the NBD requests out */
411 : 0 : req->timeout_event = -1;
412 : :
413 : 0 : req->nreq.magic = htonl(NBD_REQUEST_MAGIC);
414 : 0 : req->nreq.type = htonl(type);
415 : 0 : req->nreq.from = htonll(offset);
416 : 0 : req->nreq.len = htonl(length);
417 : 0 : req->header.buffer = (char *)&req->nreq;
418 : 0 : req->header.len = sizeof(req->nreq);
419 : 0 : req->header.so_far = 0;
420 : 0 : req->body.buffer = buffer;
421 : 0 : req->body.len = length;
422 : 0 : req->body.so_far = 0;
423 : 0 : req->fake = fake;
424 : :
425 : 0 : list_move_tail(&req->queue, &prv->pending_reqs);
426 : 0 : prv->nr_free_count--;
427 : :
428 [ # # ]: 0 : if (prv->writer_event_id < 0)
429 : 0 : enable_write_queue(prv);
430 : :
431 : : return 0;
432 : : }
433 : :
434 : : /* NBD Reader callback */
435 : :
436 : : static void
437 : 0 : tdnbd_reader_cb(event_id_t eb, char mode, void *data)
438 : : {
439 : : char handle[9];
440 : 0 : int do_disable = 0;
441 : :
442 : : /* Check to see if we're in the middle of reading a response already */
443 : 0 : struct tdnbd_data *prv = data;
444 : 0 : int rc = tdnbd_read_some(prv->socket, &prv->cur_reply_qio);
445 : :
446 [ # # ]: 0 : if (rc < 0) {
447 : 0 : ERROR("Error reading reply header: %d", rc);
448 : 0 : tdnbd_disable(prv, EIO);
449 : 0 : return;
450 : : }
451 : :
452 [ # # ]: 0 : if (rc > 0)
453 : : return; /* need more data */
454 : :
455 : : /* Got a header. */
456 [ # # ]: 0 : if (prv->current_reply.error != 0) {
457 : 0 : ERROR("Error in reply: %d", prv->current_reply.error);
458 : 0 : tdnbd_disable(prv, EIO);
459 : : return;
460 : : }
461 : :
462 : : /* Have we found the request yet? */
463 [ # # ]: 0 : if (prv->curr_reply_req == NULL) {
464 : : struct td_nbd_request *pos, *q;
465 [ # # ]: 0 : list_for_each_entry_safe(pos, q, &prv->sent_reqs, queue) {
466 [ # # ]: 0 : if (memcmp(pos->nreq.handle, prv->current_reply.handle,
467 : : 8) == 0) {
468 : 0 : prv->curr_reply_req = pos;
469 : 0 : break;
470 : : }
471 : : }
472 : :
473 [ # # ]: 0 : if (prv->curr_reply_req == NULL) {
474 : 0 : memcpy(handle, prv->current_reply.handle, 8);
475 : 0 : handle[8] = 0;
476 : :
477 : 0 : ERROR("Couldn't find request corresponding to reply "
478 : : "(reply handle='%s')", handle);
479 : 0 : tdnbd_disable(prv, EIO);
480 : : return;
481 : : }
482 : : }
483 : :
484 [ # # # ]: 0 : switch(ntohl(prv->curr_reply_req->nreq.type)) {
485 : : case TAPDISK_NBD_CMD_READ:
486 : 0 : rc = tdnbd_read_some(prv->socket,
487 : : &prv->curr_reply_req->body);
488 : :
489 [ # # ]: 0 : if (rc < 0) {
490 : 0 : ERROR("Error reading body of request: %d", rc);
491 : 0 : tdnbd_disable(prv, EIO);
492 : : return;
493 : : }
494 : :
495 [ # # ]: 0 : if (rc > 0)
496 : : return; /* need more data */
497 : :
498 : 0 : td_complete_request(prv->curr_reply_req->treq, 0);
499 : :
500 : : break;
501 : : case TAPDISK_NBD_CMD_WRITE:
502 : 0 : td_complete_request(prv->curr_reply_req->treq, 0);
503 : :
504 : : break;
505 : : default:
506 : 0 : ERROR("Unhandled request response: %d",
507 : : ntohl(prv->curr_reply_req->nreq.type));
508 : : do_disable = 1;
509 : : return;
510 : : }
511 : :
512 : : /* remove the state */
513 : 0 : list_move(&prv->curr_reply_req->queue, &prv->free_reqs);
514 : 0 : prv->nr_free_count++;
515 : :
516 : 0 : prv->cur_reply_qio.so_far = 0;
517 [ # # ]: 0 : if (prv->curr_reply_req->timeout_event >= 0) {
518 : 0 : tapdisk_server_unregister_event(
519 : : prv->curr_reply_req->timeout_event);
520 : : }
521 : :
522 : 0 : prv->curr_reply_req = NULL;
523 : :
524 : : /*
525 : : * NB: do this here otherwise we cancel the request that has just been
526 : : * moved
527 : : */
528 : : if (do_disable)
529 : : tdnbd_disable(prv, EIO);
530 : : }
531 : :
532 : : static int
533 : 0 : tdnbd_wait_read(int fd)
534 : : {
535 : : struct timeval select_tv;
536 : : fd_set socks;
537 : : int rc;
538 : :
539 : 0 : FD_ZERO(&socks);
540 [ # # ][ # # ]: 0 : FD_SET(fd, &socks);
541 : 0 : select_tv.tv_sec = 10;
542 : 0 : select_tv.tv_usec = 0;
543 : 0 : rc = select(fd + 1, &socks, NULL, NULL, &select_tv);
544 : 0 : return rc;
545 : : }
546 : :
547 : : int
548 : 0 : negotiate_client_newstyle_options(int sock, td_driver_t *driver)
549 : : {
550 : : int rc;
551 : : struct nbd_new_option new_option;
552 : 0 : char exportname[] = "tapdisk_client"; /* Hard code could make this unique */
553 : 0 : new_option.version = htobe64(NBD_OPT_MAGIC);
554 : 0 : new_option.optlen = htobe32(sizeof(exportname));
555 : 0 : new_option.option = htobe32( NBD_OPT_EXPORT_NAME);
556 : :
557 : : /* Send EXPORTNAME_NAME option request */
558 : 0 : rc = send_fully_or_fail(sock, &new_option, sizeof(new_option));
559 [ # # ]: 0 : if (rc < 0)
560 : : {
561 : 0 : ERROR("Failed to send options to sock");
562 : 0 : close(sock);
563 : 0 : return -1;
564 : : }
565 : : /* Send exportname name */
566 : 0 : rc = send_fully_or_fail(sock, exportname, sizeof(exportname));
567 [ # # ]: 0 : if (rc < 0)
568 : : {
569 : 0 : ERROR("Failed to send export name to sock");
570 : 0 : close(sock);
571 : : return -1;
572 : : }
573 : :
574 : : /* Collect the results in the handshake finished */
575 : : struct nbd_export_name_option_reply handshake_finish;
576 : : static const size_t NO_ZERO_HANDSHAKE_FINISH_SIZE = 10;
577 : 0 : rc = recv_fully_or_fail(sock, &handshake_finish, NO_ZERO_HANDSHAKE_FINISH_SIZE);
578 [ # # ]: 0 : if (rc < 0)
579 : : {
580 : 0 : ERROR("Failed to read handshake from sock");
581 : 0 : close(sock);
582 : : return -1;
583 : : }
584 : :
585 : 0 : driver->info.size = be64toh(handshake_finish.exportsize) >> SECTOR_SHIFT;
586 : 0 : driver->info.sector_size = DEFAULT_SECTOR_SIZE;
587 : 0 : driver->info.info = 0;
588 : :
589 : 0 : rc = fcntl(sock, F_SETFL, O_NONBLOCK);
590 : :
591 [ # # ]: 0 : if (rc != 0) {
592 : 0 : ERROR("Could not set O_NONBLOCK flag");
593 : 0 : close(sock);
594 : : return -1;
595 : : }
596 : :
597 : 0 : INFO("Successfully connected to NBD server");
598 : :
599 : : return 0;
600 : : }
601 : :
602 : : static int
603 : 0 : tdnbd_nbd_negotiate_old(struct tdnbd_data *prv, td_driver_t *driver)
604 : : {
605 : : int rc;
606 : : char buffer[RECV_BUFFER_SIZE];
607 : : uint64_t magic;
608 : : uint64_t size;
609 : : uint32_t flags;
610 : 0 : int padbytes = 124;
611 : 0 : int sock = prv->socket;
612 : :
613 : : /*
614 : : * NBD negotiation protocol:
615 : : *
616 : : * Server sends 'NBDMAGIC'
617 : : * then it sends 0x00420281861253L
618 : : * then it sends a 64 bit bigendian size
619 : : * then it sends a 32 bit bigendian flags
620 : : * then it sends 124 bytes of nothing
621 : : */
622 : :
623 : : /*
624 : : * We need to limit the time we spend in this function as we're still
625 : : * using blocking IO at this point
626 : : */
627 [ # # ]: 0 : if (tdnbd_wait_read(sock) <= 0) {
628 : 0 : ERROR("Timeout in nbd_negotiate");
629 : 0 : close(sock);
630 : 0 : return -1;
631 : : }
632 : :
633 : 0 : rc = recv(sock, buffer, 8, 0);
634 [ # # ]: 0 : if (rc < 8) {
635 : 0 : ERROR("Short read in negotiation(1) (%d)\n", rc);
636 : 0 : close(sock);
637 : : return -1;
638 : : }
639 : :
640 [ # # ]: 0 : if (memcmp(buffer, "NBDMAGIC", 8) != 0) {
641 : 0 : buffer[8] = 0;
642 : 0 : ERROR("Error in NBD negotiation: got '%s'", buffer);
643 : 0 : close(sock);
644 : : return -1;
645 : : }
646 : :
647 [ # # ]: 0 : if (tdnbd_wait_read(sock) <= 0) {
648 : 0 : ERROR("Timeout in nbd_negotiate");
649 : 0 : close(sock);
650 : : return -1;
651 : : }
652 : :
653 : 0 : rc = recv(sock, &magic, sizeof(magic), 0);
654 [ # # ]: 0 : if (rc < 8) {
655 : 0 : ERROR("Short read in negotiation(2) (%d)\n", rc);
656 : :
657 : : return -1;
658 : : }
659 : :
660 [ # # ]: 0 : if (ntohll(magic) != NBD_NEGOTIATION_MAGIC) {
661 : 0 : ERROR("Not enough magic in negotiation(2) (%"PRIu64")\n",
662 : : ntohll(magic));
663 : 0 : close(sock);
664 : : return -1;
665 : : }
666 : :
667 [ # # ]: 0 : if (tdnbd_wait_read(sock) <= 0) {
668 : 0 : ERROR("Timeout in nbd_negotiate");
669 : 0 : close(sock);
670 : : return -1;
671 : : }
672 : :
673 : 0 : rc = recv(sock, &size, sizeof(size), 0);
674 [ # # ]: 0 : if (rc < sizeof(size)) {
675 : 0 : ERROR("Short read in negotiation(3) (%d)\n", rc);
676 : 0 : close(sock);
677 : : return -1;
678 : : }
679 : :
680 : 0 : INFO("Got size: %"PRIu64"", ntohll(size));
681 : :
682 : 0 : driver->info.size = ntohll(size) >> SECTOR_SHIFT;
683 : 0 : driver->info.sector_size = DEFAULT_SECTOR_SIZE;
684 : 0 : driver->info.info = 0;
685 : :
686 [ # # ]: 0 : if (tdnbd_wait_read(sock) <= 0) {
687 : 0 : ERROR("Timeout in nbd_negotiate");
688 : 0 : close(sock);
689 : : return -1;
690 : : }
691 : :
692 : 0 : rc = recv(sock, &flags, sizeof(flags), 0);
693 [ # # ]: 0 : if (rc < sizeof(flags)) {
694 : 0 : ERROR("Short read in negotiation(4) (%d)\n", rc);
695 : 0 : close(sock);
696 : : return -1;
697 : : }
698 : :
699 : 0 : INFO("Got flags: %"PRIu32"", ntohl(flags));
700 : :
701 [ # # ]: 0 : while (padbytes > 0) {
702 [ # # ]: 0 : if (tdnbd_wait_read(sock) <= 0) {
703 : 0 : ERROR("Timeout in nbd_negotiate");
704 : 0 : close(sock);
705 : : return -1;
706 : : }
707 : :
708 : 0 : rc = recv(sock, buffer, padbytes, 0);
709 [ # # ]: 0 : if (rc < 0) {
710 : 0 : ERROR("Bad read in negotiation(5) (%d)\n", rc);
711 : 0 : close(sock);
712 : : return -1;
713 : : }
714 : 0 : padbytes -= rc;
715 : : }
716 : :
717 : 0 : rc = fcntl(sock, F_SETFL, O_NONBLOCK);
718 : :
719 [ # # ]: 0 : if (rc != 0) {
720 : 0 : ERROR("Could not set O_NONBLOCK flag");
721 : 0 : close(sock);
722 : : return -1;
723 : : }
724 : 0 : INFO("Successfully connected to NBD server");
725 : :
726 : : return 0;
727 : : }
728 : :
729 : : static int
730 : 0 : tdnbd_nbd_negotiate_new(struct tdnbd_data *prv, td_driver_t *driver)
731 : : {
732 : : int rc;
733 : : uint64_t magic_version;
734 : : uint16_t gflags;
735 : 0 : uint32_t cflags = htobe32(NBD_FLAG_FIXED_NEWSTYLE | NBD_FLAG_NO_ZEROES);
736 : 0 : int sock = prv->socket;
737 : : char buffer[RECV_BUFFER_SIZE];
738 : :
739 [ # # ]: 0 : if (tdnbd_wait_read(sock) <= 0) {
740 : 0 : ERROR("Timeout in nbd_negotiate");
741 : 0 : close(sock);
742 : 0 : return -1;
743 : : }
744 : :
745 : 0 : rc = recv(sock, buffer, 8, 0);
746 [ # # ]: 0 : if (rc < 8) {
747 : 0 : ERROR("Short read in negotiation(1) (%d)\n", rc);
748 : 0 : close(sock);
749 : : return -1;
750 : : }
751 : :
752 [ # # ]: 0 : if (memcmp(buffer, "NBDMAGIC", 8) != 0) {
753 : 0 : buffer[8] = 0;
754 : 0 : ERROR("Error in NBD negotiation: got '%s'", buffer);
755 : 0 : close(sock);
756 : : return -1;
757 : : }
758 : :
759 [ # # ]: 0 : if (tdnbd_wait_read(sock) <= 0) {
760 : 0 : ERROR("Timeout in nbd_negotiate");
761 : 0 : close(sock);
762 : : return -1;
763 : : }
764 : :
765 : : /* Receive NBD magic_version */
766 : 0 : rc = recv_fully_or_fail(sock, &magic_version, sizeof(magic_version));
767 [ # # ]: 0 : if (rc < 0)
768 : : {
769 : 0 : ERROR("Failed to read magic from sock");
770 : 0 : close(sock);
771 : : return -1;
772 : : }
773 : :
774 [ # # ]: 0 : if (ntohll(magic_version) != NBD_NEW_VERSION) {
775 : 0 : ERROR("Not enough magic in negotiation(2) (%"PRIu64")\n",
776 : : ntohll(magic_version));
777 : 0 : close(sock);
778 : : return -1;
779 : : }
780 : :
781 : : /* Receive NBD flags */
782 : 0 : rc = recv(sock, &gflags, sizeof(gflags), 0);
783 [ # # ]: 0 : if (rc < sizeof(gflags)) {
784 : 0 : ERROR("Short read in negotiation(2) (%d)\n", rc);
785 : :
786 : : return -1;
787 : : }
788 : :
789 : : /* Send back flags*/
790 : 0 : rc = send(sock, &cflags, sizeof(cflags), 0);
791 [ # # ]: 0 : if (rc < sizeof(cflags)) {
792 : 0 : ERROR("Failed to send client flags");
793 : : return -1;
794 : : }
795 : :
796 : 0 : return negotiate_client_newstyle_options(sock, driver);
797 : : }
798 : :
799 : : static int
800 : 0 : tdnbd_nbd_negotiate(struct tdnbd_data *prv, td_driver_t *driver)
801 : : {
802 [ # # ]: 0 : if(CLIENT_USE_OLD_HANDSHAKE && !td_flag_test(driver->state, TD_DRIVER_NEW_NBD)) {
803 : 0 : return tdnbd_nbd_negotiate_old(prv, driver);
804 : : } else {
805 : 0 : return tdnbd_nbd_negotiate_new(prv, driver);
806 : : }
807 : : }
808 : :
809 : : static int
810 : 0 : tdnbd_connect_import_session(struct tdnbd_data *prv, td_driver_t* driver)
811 : : {
812 : : int sock;
813 : 0 : int opt = 1;
814 : : int rc;
815 : :
816 : 0 : sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
817 [ # # ]: 0 : if (sock < 0) {
818 : 0 : ERROR("Could not create socket: %s\n", strerror(errno));
819 : 0 : return -1;
820 : : }
821 : :
822 : 0 : rc = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void *)&opt,
823 : : sizeof(opt));
824 [ # # ]: 0 : if (rc < 0) {
825 : 0 : ERROR("Could not set TCP_NODELAY: %s\n", strerror(errno));
826 : 0 : close(sock);
827 : : return -1;
828 : : }
829 : :
830 : 0 : prv->remote = (struct sockaddr_in *)malloc(
831 : : sizeof(struct sockaddr_in));
832 [ # # ]: 0 : if (!prv->remote) {
833 : 0 : ERROR("struct sockaddr_in malloc failure\n");
834 : 0 : close(sock);
835 : : return -1;
836 : : }
837 : 0 : prv->remote->sin_family = AF_INET;
838 : 0 : rc = inet_pton(AF_INET, prv->peer_ip, &(prv->remote->sin_addr.s_addr));
839 [ # # ]: 0 : if (rc < 0) {
840 : 0 : ERROR("Could not create inaddr: %s\n", strerror(errno));
841 : 0 : free(prv->remote);
842 : 0 : prv->remote = NULL;
843 : 0 : close(sock);
844 : : return -1;
845 : : }
846 [ # # ]: 0 : else if (rc == 0) {
847 : 0 : ERROR("inet_pton parse error\n");
848 : 0 : free(prv->remote);
849 : 0 : prv->remote = NULL;
850 : 0 : close(sock);
851 : : return -1;
852 : : }
853 [ # # ]: 0 : prv->remote->sin_port = htons(prv->port);
854 : :
855 [ # # ]: 0 : if (connect(sock, (struct sockaddr *)prv->remote,
856 : : sizeof(struct sockaddr)) < 0) {
857 : 0 : ERROR("Could not connect to peer: %s\n", strerror(errno));
858 : 0 : free(prv->remote);
859 : 0 : close(sock);
860 : : return -1;
861 : : }
862 : :
863 : 0 : prv->socket = sock;
864 : :
865 : 0 : return tdnbd_nbd_negotiate(prv, driver);
866 : : }
867 : :
868 : : /* -- interface -- */
869 : :
870 : : static int tdnbd_close(td_driver_t*);
871 : :
872 : : static int
873 : 0 : tdnbd_open(td_driver_t* driver, const char* name,
874 : : struct td_vbd_encryption *encryption, td_flag_t flags)
875 : : {
876 : : struct tdnbd_data *prv;
877 : : char peer_ip[256];
878 : : int port;
879 : : int rc;
880 : : int i;
881 : : struct stat buf;
882 : :
883 : 0 : driver->info.sector_size = 512;
884 : 0 : driver->info.info = 0;
885 : :
886 : 0 : prv = (struct tdnbd_data *)driver->data;
887 : : memset(prv, 0, sizeof(struct tdnbd_data));
888 : :
889 : 0 : INFO("Opening nbd export to %s (flags=%x)\n", name, flags);
890 : :
891 : 0 : prv->writer_event_id = -1;
892 : 0 : INIT_LIST_HEAD(&prv->sent_reqs);
893 : 0 : INIT_LIST_HEAD(&prv->pending_reqs);
894 : 0 : INIT_LIST_HEAD(&prv->free_reqs);
895 [ # # ]: 0 : for (i = 0; i < MAX_NBD_REQS; i++) {
896 : 0 : INIT_LIST_HEAD(&prv->requests[i].queue);
897 : 0 : prv->requests[i].timeout_event = -1;
898 : 0 : list_add(&prv->requests[i].queue, &prv->free_reqs);
899 : : }
900 : 0 : prv->nr_free_count = MAX_NBD_REQS;
901 : 0 : prv->cur_reply_qio.buffer = (char *)&prv->current_reply;
902 : 0 : prv->cur_reply_qio.len = sizeof(struct nbd_reply);
903 : :
904 : : bzero(&buf, sizeof(buf));
905 : 0 : rc = stat(name, &buf);
906 [ # # ][ # # ]: 0 : if (!rc && S_ISSOCK(buf.st_mode)) {
907 : 0 : int len = 0;
908 [ # # ]: 0 : if ((prv->socket = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
909 : 0 : ERROR("failed to create UNIX domain socket: %s\n",
910 : : strerror(errno));
911 : 0 : return -1;
912 : : }
913 : 0 : prv->remote_un.sun_family = AF_UNIX;
914 : 0 : safe_strncpy(prv->remote_un.sun_path, name, sizeof(prv->remote_un.sun_path));
915 : 0 : len = strlen(prv->remote_un.sun_path)
916 : : + sizeof(prv->remote_un.sun_family);
917 [ # # ]: 0 : if ((rc = connect(prv->socket, (struct sockaddr*)&prv->remote_un, len)
918 : 0 : == -1)) {
919 : 0 : ERROR("failed to connect to %s: %s\n", name, strerror(errno));
920 : : return -1;
921 : : }
922 : 0 : rc = tdnbd_nbd_negotiate(prv, driver);
923 [ # # ]: 0 : if (rc) {
924 : 0 : ERROR("failed to negotiate with the NBD server\n");
925 : : return -1;
926 : : }
927 : : } else {
928 : 0 : rc = sscanf(name, "%255[^:]:%d", peer_ip, &port);
929 [ # # ]: 0 : if (rc == 2) {
930 : 0 : prv->peer_ip = strdup(peer_ip);
931 [ # # ]: 0 : if (!prv->peer_ip) {
932 : 0 : ERROR("Failure to malloc for NBD destination");
933 : : return -1;
934 : : }
935 : 0 : prv->port = port;
936 : 0 : prv->name = NULL;
937 : 0 : INFO("Export peer=%s port=%d\n", prv->peer_ip, prv->port);
938 [ # # ]: 0 : if (tdnbd_connect_import_session(prv, driver) < 0)
939 : : return -1;
940 : :
941 : : } else {
942 : 0 : prv->socket = tdnbd_retrieve_passed_fd(name);
943 [ # # ]: 0 : if (prv->socket < 0) {
944 : 0 : ERROR("Couldn't find fd named: %s", name);
945 : : return -1;
946 : : }
947 : 0 : INFO("Found passed fd. Connecting...");
948 : 0 : prv->remote = NULL;
949 : 0 : prv->peer_ip = NULL;
950 : 0 : prv->name = strdup(name);
951 : 0 : prv->port = -1;
952 [ # # ]: 0 : if (tdnbd_nbd_negotiate(prv, driver) < 0) {
953 : 0 : ERROR("Failed to negotiate");
954 : : return -1;
955 : : }
956 : : }
957 : : }
958 : :
959 : 0 : prv->reader_event_id =
960 : 0 : tapdisk_server_register_event(SCHEDULER_POLL_READ_FD,
961 : 0 : prv->socket, TV_ZERO,
962 : : tdnbd_reader_cb,
963 : : (void *)prv);
964 : :
965 : 0 : prv->flags = flags;
966 : 0 : prv->closed = 0;
967 : :
968 [ # # ]: 0 : if (flags & TD_OPEN_SECONDARY)
969 : 0 : INFO("Opening in secondary mode: Read requests will be "
970 : : "forwarded");
971 : :
972 : : return 0;
973 : :
974 : : }
975 : :
976 : : static int
977 : 0 : tdnbd_close(td_driver_t* driver)
978 : : {
979 : 0 : struct tdnbd_data *prv = (struct tdnbd_data *)driver->data;
980 : : td_request_t treq;
981 : :
982 : : bzero(&treq, sizeof(treq));
983 : :
984 [ # # ]: 0 : if (prv->closed == 3) {
985 : 0 : INFO("NBD close: already decided that the connection is dead.");
986 [ # # ]: 0 : if (prv->socket >= 0)
987 : 0 : close(prv->socket);
988 : 0 : prv->socket = -1;
989 : 0 : return 0;
990 : : }
991 : :
992 : : /* Send a close packet */
993 : :
994 : 0 : INFO("Sending disconnect request");
995 : 0 : tdnbd_queue_request(prv, TAPDISK_NBD_CMD_DISC, 0, 0, 0, treq, 0);
996 : :
997 : 0 : INFO("Switching socket to blocking IO mode");
998 : 0 : fcntl(prv->socket, F_SETFL, fcntl(prv->socket, F_GETFL) & ~O_NONBLOCK);
999 : :
1000 : 0 : INFO("Writing disconnection request");
1001 : 0 : tdnbd_writer_cb(0, 0, prv);
1002 : :
1003 : 0 : INFO("Written");
1004 : :
1005 [ # # ]: 0 : if (prv->peer_ip) {
1006 : 0 : free(prv->peer_ip);
1007 : 0 : prv->peer_ip = NULL;
1008 : : }
1009 : :
1010 [ # # ]: 0 : if (prv->name) {
1011 : 0 : tdnbd_stash_passed_fd(prv->socket, prv->name, 0);
1012 : 0 : free(prv->name);
1013 : : } else {
1014 [ # # ]: 0 : if (prv->socket >= 0)
1015 : 0 : close(prv->socket);
1016 : 0 : prv->socket = -1;
1017 : : }
1018 : :
1019 : : return 0;
1020 : : }
1021 : :
1022 : : static void
1023 : 0 : tdnbd_queue_read(td_driver_t* driver, td_request_t treq)
1024 : : {
1025 : 0 : struct tdnbd_data *prv = (struct tdnbd_data *)driver->data;
1026 : 0 : int size = treq.secs * driver->info.sector_size;
1027 : 0 : uint64_t offset = treq.sec * (uint64_t)driver->info.sector_size;
1028 : :
1029 [ # # ]: 0 : if (prv->flags & TD_OPEN_SECONDARY)
1030 : 0 : td_forward_request(treq);
1031 : : else
1032 : 0 : tdnbd_queue_request(prv, TAPDISK_NBD_CMD_READ, offset, treq.buf, size,
1033 : : treq, 0);
1034 : 0 : }
1035 : :
1036 : : static void
1037 : 0 : tdnbd_queue_write(td_driver_t* driver, td_request_t treq)
1038 : : {
1039 : 0 : struct tdnbd_data *prv = (struct tdnbd_data *)driver->data;
1040 : 0 : int size = treq.secs * driver->info.sector_size;
1041 : 0 : uint64_t offset = treq.sec * (uint64_t)driver->info.sector_size;
1042 : :
1043 : 0 : tdnbd_queue_request(prv, TAPDISK_NBD_CMD_WRITE,
1044 : 0 : offset, treq.buf, size, treq, 0);
1045 : 0 : }
1046 : :
1047 : : static int
1048 : 0 : tdnbd_get_parent_id(td_driver_t* driver, td_disk_id_t* id)
1049 : : {
1050 : 0 : return TD_NO_PARENT;
1051 : : }
1052 : :
1053 : : static int
1054 : 0 : tdnbd_validate_parent(td_driver_t *driver,
1055 : : td_driver_t *parent, td_flag_t flags)
1056 : : {
1057 : 0 : return -EINVAL;
1058 : : }
1059 : :
1060 : : struct tap_disk tapdisk_nbd = {
1061 : : .disk_type = "tapdisk_nbd",
1062 : : .private_data_size = sizeof(struct tdnbd_data),
1063 : : .flags = 0,
1064 : : .td_open = tdnbd_open,
1065 : : .td_close = tdnbd_close,
1066 : : .td_queue_read = tdnbd_queue_read,
1067 : : .td_queue_write = tdnbd_queue_write,
1068 : : .td_get_parent_id = tdnbd_get_parent_id,
1069 : : .td_validate_parent = tdnbd_validate_parent,
1070 : : };
|