| 1 |
root |
1.1 |
=head1 NAME |
| 2 |
|
|
|
| 3 |
|
|
Linux::NBD::Server - server (data provider) side of a network block device |
| 4 |
|
|
|
| 5 |
|
|
=head1 SYNOPSIS |
| 6 |
|
|
|
| 7 |
|
|
use Linux::NBD::Server; |
| 8 |
|
|
|
| 9 |
|
|
=head1 DESCRIPTION |
| 10 |
|
|
|
| 11 |
|
|
You must subclass C<Linux::NBD::Server> to get meaningful results. You |
| 12 |
|
|
should overwrite C<req_read> and/or C<req_write>. The default |
| 13 |
|
|
implementations just return EIO. |
| 14 |
|
|
|
| 15 |
|
|
=head1 METHODS |
| 16 |
|
|
|
| 17 |
|
|
=over 4 |
| 18 |
|
|
|
| 19 |
|
|
=cut |
| 20 |
|
|
|
| 21 |
|
|
package Linux::NBD::Server; |
| 22 |
|
|
|
| 23 |
root |
1.4 |
$VERSION = 0.21; |
| 24 |
root |
1.1 |
|
| 25 |
|
|
use Linux::NBD (); |
| 26 |
|
|
|
| 27 |
|
|
use Carp qw(croak); |
| 28 |
|
|
use Errno (); |
| 29 |
|
|
|
| 30 |
|
|
=item $server = new Linux::NBD::Server socket => $fd, ...; |
| 31 |
|
|
|
| 32 |
|
|
Create a new server. All arguments are put into a hashref which is blessed |
| 33 |
|
|
and returned. The only required argument is C<socket> which should be |
| 34 |
|
|
connected to a C<Linux::NBD::Client>. |
| 35 |
|
|
|
| 36 |
|
|
=cut |
| 37 |
|
|
|
| 38 |
|
|
sub new { |
| 39 |
|
|
my $class = shift; |
| 40 |
|
|
bless { @_ }, ref $class || $class; |
| 41 |
|
|
} |
| 42 |
|
|
|
| 43 |
|
|
=item $server->run |
| 44 |
|
|
|
| 45 |
|
|
Enters a server loop, serving requests. Only returns when the socket is closed |
| 46 |
|
|
or a disconnect message is received. |
| 47 |
|
|
|
| 48 |
|
|
If you need non-blocking access your best bet is to use |
| 49 |
|
|
C<$server->one_request>, but note that it still might block to read the |
| 50 |
|
|
write data from the socket. |
| 51 |
|
|
|
| 52 |
|
|
=item $server->one_request |
| 53 |
|
|
|
| 54 |
|
|
Waits for and handles a single request and returns, returning true if no |
| 55 |
|
|
further requests will arrive. |
| 56 |
|
|
|
| 57 |
|
|
=item $server->format_reply ($handle[, $error, [, $data]]) |
| 58 |
|
|
|
| 59 |
|
|
Formats (and returns as a string) a reply message. If the request was a |
| 60 |
|
|
read request and C<$error> is zero (or missing, both meaning no error), |
| 61 |
|
|
you should append the read data to it. |
| 62 |
|
|
|
| 63 |
|
|
If C<$data> is given and C<$error> is zero, it is appended to the string |
| 64 |
|
|
before it is returned. |
| 65 |
|
|
|
| 66 |
|
|
=item $server->reply ($handle[, $error[, $data]]) |
| 67 |
|
|
|
| 68 |
|
|
Formats and sends a reply to the server. |
| 69 |
|
|
|
| 70 |
|
|
=item $server->send ($data) |
| 71 |
|
|
|
| 72 |
|
|
Writes the given data to the client socket. |
| 73 |
|
|
|
| 74 |
root |
1.6 |
=item $server->recv ($bytes) |
| 75 |
root |
1.1 |
|
| 76 |
|
|
Reads the specified number of bytes and returns them. |
| 77 |
|
|
|
| 78 |
|
|
=cut |
| 79 |
|
|
|
| 80 |
|
|
sub run { |
| 81 |
|
|
my $self = shift; |
| 82 |
|
|
|
| 83 |
|
|
1 while not _one_request $self, fileno $self->{socket}; |
| 84 |
|
|
} |
| 85 |
|
|
|
| 86 |
|
|
sub one_request { |
| 87 |
|
|
my $self = shift; |
| 88 |
|
|
|
| 89 |
|
|
_one_request $self, fileno $self->{socket}; |
| 90 |
|
|
} |
| 91 |
|
|
|
| 92 |
|
|
sub format_reply { |
| 93 |
|
|
shift; |
| 94 |
|
|
&_format_reply; |
| 95 |
|
|
} |
| 96 |
|
|
|
| 97 |
|
|
sub reply { |
| 98 |
|
|
my $self = shift; |
| 99 |
|
|
|
| 100 |
|
|
$self->send(&_format_reply); |
| 101 |
|
|
} |
| 102 |
|
|
|
| 103 |
|
|
sub send { |
| 104 |
|
|
syswrite $_[0]->{socket}, $_[1]; |
| 105 |
|
|
} |
| 106 |
|
|
|
| 107 |
|
|
sub recv { |
| 108 |
root |
1.6 |
my ($self, $len) = @_; |
| 109 |
root |
1.1 |
|
| 110 |
root |
1.6 |
my ($buf, $todo); |
| 111 |
|
|
|
| 112 |
|
|
sysread $self->{socket}, $buf, $togo, length $buf |
| 113 |
root |
1.7 |
or die "error or eof while receiving from network: $!" |
| 114 |
root |
1.6 |
while $todo = $len - length $buf; |
| 115 |
|
|
|
| 116 |
|
|
$buf |
| 117 |
root |
1.1 |
} |
| 118 |
|
|
|
| 119 |
root |
1.6 |
=item $server->req_read ($handle, $offset, $length) |
| 120 |
root |
1.1 |
|
| 121 |
|
|
This callback is called for every read request. It should send |
| 122 |
root |
1.6 |
back a reply and the requested number of bytes, e.g.: |
| 123 |
root |
1.1 |
|
| 124 |
|
|
my ($self, $handle, $ofs, $len) = @_; |
| 125 |
|
|
$self->reply($handle, 0, "\xff" x $len); |
| 126 |
|
|
|
| 127 |
root |
1.6 |
=item $server->req_write ($handle, $offset, $length) |
| 128 |
root |
1.1 |
|
| 129 |
|
|
Same as C<req_read>, but you should use C<recv> to read C<$len> bytes from |
| 130 |
|
|
the socket (even if you intend to return an error, of course). |
| 131 |
|
|
|
| 132 |
|
|
my ($self, $handle, $ofs, $len) = @_; |
| 133 |
|
|
my $data = $self->recv($len); |
| 134 |
|
|
$self->reply($handle); |
| 135 |
|
|
|
| 136 |
|
|
=cut |
| 137 |
|
|
|
| 138 |
|
|
sub req_read { |
| 139 |
|
|
my ($self, $handle, $ofs, $len) = @_; |
| 140 |
|
|
|
| 141 |
root |
1.6 |
$self->reply ($handle, 1); |
| 142 |
root |
1.1 |
} |
| 143 |
|
|
|
| 144 |
|
|
sub req_write { |
| 145 |
|
|
my ($self, $handle, $ofs, $len) = @_; |
| 146 |
|
|
|
| 147 |
root |
1.6 |
$self->recv ($len); |
| 148 |
|
|
$self->reply ($handle, 1); |
| 149 |
root |
1.1 |
} |
| 150 |
|
|
|
| 151 |
|
|
1; |
| 152 |
|
|
|
| 153 |
|
|
=back |
| 154 |
|
|
|
| 155 |
root |
1.6 |
=head1 NBD TOOL NEGOTIATION PROTOCOL |
| 156 |
|
|
|
| 157 |
|
|
Standard NBD tools add a handshake phase before starting to serve/send |
| 158 |
|
|
requests. The server-side implementation looks like this: |
| 159 |
|
|
|
| 160 |
|
|
$size = new Math::BigInt $size; |
| 161 |
|
|
my $size_hi = $size->copy->brsft(32)->blsft(32); |
| 162 |
|
|
my $size_lo = $size->copy->bsub($size_hi)->numify; |
| 163 |
|
|
$size_hi = $size_hi->brsft(32)->numify; |
| 164 |
|
|
|
| 165 |
|
|
$s->send ("NBDMAGIC\x00\x00\x42\x02\x81\x86\x12\x53"); |
| 166 |
|
|
$s->send (pack "NN", $size_hi, $size_lo); |
| 167 |
|
|
$s->send ("\x00" x 128); |
| 168 |
|
|
|
| 169 |
|
|
# now serve |
| 170 |
|
|
my $server = new ServerClass socket => $s; |
| 171 |
|
|
$server->run; |
| 172 |
|
|
|
| 173 |
|
|
|
| 174 |
|
|
=head1 BUGS |
| 175 |
|
|
|
| 176 |
|
|
Should support AnyEvent or something similar for non-blocking behaviour. |
| 177 |
|
|
|
| 178 |
root |
1.1 |
=head1 AUTHOR |
| 179 |
|
|
|
| 180 |
root |
1.5 |
Marc Lehmann <schmorp@schmorp.de> |
| 181 |
|
|
http://home.schmorp.de/ |
| 182 |
root |
1.1 |
|
| 183 |
|
|
=cut |
| 184 |
|
|
|