ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent-MP/MP/Transport.pm
(Generate patch)

Comparing AnyEvent-MP/MP/Transport.pm (file contents):
Revision 1.8 by root, Mon Aug 3 14:58:13 2009 UTC vs.
Revision 1.26 by root, Sat Aug 8 21:56:29 2009 UTC

1=head1 NAME 1=head1 NAME
2 2
3AnyEvent::MP::Transport - actual transport protocol 3AnyEvent::MP::Transport - actual transport protocol handler
4 4
5=head1 SYNOPSIS 5=head1 SYNOPSIS
6 6
7 use AnyEvent::MP::Transport; 7 use AnyEvent::MP::Transport;
8 8
9=head1 DESCRIPTION 9=head1 DESCRIPTION
10 10
11This is the superclass for MP transports, most of which is considered an 11This implements the actual transport protocol for MP (it represents a
12implementation detail. 12single link), most of which is considered an implementation detail.
13 13
14See the "PROTOCOL" section below if you want to write another client for 14See the "PROTOCOL" section below if you want to write another client for
15this protocol. 15this protocol.
16 16
17=head1 FUNCTIONS/METHODS 17=head1 FUNCTIONS/METHODS
27use Scalar::Util; 27use Scalar::Util;
28use MIME::Base64 (); 28use MIME::Base64 ();
29use Storable (); 29use Storable ();
30use JSON::XS (); 30use JSON::XS ();
31 31
32use Digest::MD6 ();
33use Digest::HMAC_MD6 ();
34
32use AE (); 35use AE ();
33use AnyEvent::Socket (); 36use AnyEvent::Socket ();
34use AnyEvent::Handle (); 37use AnyEvent::Handle ();
35 38
36use base Exporter::; 39use base Exporter::;
43Creates a listener on the given host/port using 46Creates a listener on the given host/port using
44C<AnyEvent::Socket::tcp_server>. 47C<AnyEvent::Socket::tcp_server>.
45 48
46See C<new>, below, for constructor arguments. 49See C<new>, below, for constructor arguments.
47 50
48Defaults for peerhost, peerport, fh and tls are provided. 51Defaults for peerhost, peerport and fh are provided.
49 52
50=cut 53=cut
51 54
52sub mp_server($$@) { 55sub mp_server($$@) {
53 my $cb = pop; 56 my $cb = pop;
58 61
59 $cb->(new AnyEvent::MP::Transport 62 $cb->(new AnyEvent::MP::Transport
60 fh => $fh, 63 fh => $fh,
61 peerhost => $host, 64 peerhost => $host,
62 peerport => $port, 65 peerport => $port,
63 tls => "accept",
64 @args, 66 @args,
65 ); 67 );
66 } 68 }
67} 69}
68 70
82 $cb->(new AnyEvent::MP::Transport 84 $cb->(new AnyEvent::MP::Transport
83 fh => $fh, 85 fh => $fh,
84 peername => $host, 86 peername => $host,
85 peerhost => $nhost, 87 peerhost => $nhost,
86 peerport => $nport, 88 peerport => $nport,
87 tls => "accept",
88 @args, 89 @args,
89 ); 90 );
90 } 91 }
91} 92}
92 93
105 on_eof => sub { clean-close-callback }, 106 on_eof => sub { clean-close-callback },
106 on_connect => sub { successful-connect-callback }, 107 on_connect => sub { successful-connect-callback },
107 greeting => { key => value }, 108 greeting => { key => value },
108 109
109 # tls support 110 # tls support
110 tls => "accept|connect",
111 tls_ctx => AnyEvent::TLS, 111 tls_ctx => AnyEvent::TLS,
112 peername => $peername, # for verification 112 peername => $peername, # for verification
113 ; 113 ;
114 114
115=cut 115=cut
116 116
117our @FRAMINGS = qw(json storable); # the framing types we accept and send, in order of preference 117our @FRAMINGS = qw(json storable); # the framing types we accept and send, in order of preference
118our @AUTH_SND = qw(hmac_md6_64_256); # auth types we send 118our @AUTH_SND = qw(hmac_md6_64_256); # auth types we send
119our @AUTH_RCV = (@AUTH_SND, qw(hex_secret)); # auth types we accept 119our @AUTH_RCV = (@AUTH_SND, qw(cleartext)); # auth types we accept
120 120
121#AnyEvent::Handle::register_write_type mp_record => sub { 121#AnyEvent::Handle::register_write_type mp_record => sub {
122#}; 122#};
123 123
124sub new { 124sub new {
129 $self->{queue} = []; 129 $self->{queue} = [];
130 130
131 { 131 {
132 Scalar::Util::weaken (my $self = $self); 132 Scalar::Util::weaken (my $self = $self);
133 133
134 if (exists $arg{connect}) {
135 $arg{tls_ctx} ||= { sslv2 => 0, sslv3 => 0, tlsv1 => 1, verify => 1 };
136 }
137
138 $arg{secret} = AnyEvent::MP::Base::default_secret () 134 $arg{secret} = AnyEvent::MP::Base::default_secret ()
139 unless exists $arg{secret}; 135 unless exists $arg{secret};
140 136
137 $arg{timeout} = 3#d#
138 unless exists $arg{timeout};
139
140 my $secret = $arg{secret};
141
142 if ($secret =~ /-----BEGIN RSA PRIVATE KEY-----.*-----END RSA PRIVATE KEY-----.*-----BEGIN CERTIFICATE-----.*-----END CERTIFICATE-----/s) {
143 # assume TLS mode
144 $arg{tls_ctx} = {
145 sslv2 => 0,
146 sslv3 => 0,
147 tlsv1 => 1,
148 verify => 1,
149 cert => $secret,
150 ca_cert => $secret,
151 verify_require_client_cert => 1,
152 };
153 }
154
141 $self->{hdl} = new AnyEvent::Handle 155 $self->{hdl} = new AnyEvent::Handle
142 fh => delete $arg{fh}, 156 fh => delete $arg{fh},
143 rbuf_max => 64 * 1024,
144 autocork => 1, 157 autocork => 1,
145 no_delay => 1, 158 no_delay => 1,
146 on_error => sub { 159 on_error => sub {
147 $self->error ($_[2]); 160 $self->error ($_[2]);
148 }, 161 },
162 timeout => $AnyEvent::MP::Base::CONNECT_TIMEOUT,
149 peername => delete $arg{peername}, 163 peername => delete $arg{peername},
150 ; 164 ;
151 165
152 my $secret = $arg{secret};
153 my $greeting_kv = $self->{greeting} ||= {}; 166 my $greeting_kv = $self->{greeting} ||= {};
167
168 $self->{local_node} = $AnyEvent::MP::Base::NODE;
169
154 $greeting_kv->{"tls"} = "1.0" 170 $greeting_kv->{"tls"} = "1.0" if $arg{tls_ctx};
155 if $arg{tls_ctx};
156 $greeting_kv->{provider} = "AE-$VERSION"; 171 $greeting_kv->{provider} = "AE-$VERSION";
157 $greeting_kv->{peeraddr} = AnyEvent::Socket::format_hostport $self->{peerhost}, $self->{peerport}; 172 $greeting_kv->{peeraddr} = AnyEvent::Socket::format_hostport $self->{peerhost}, $self->{peerport};
173 $greeting_kv->{timeout} = $arg{timeout};
158 174
159 # send greeting 175 # send greeting
160 my $lgreeting1 = "aemp;$PROTOCOL_VERSION;$PROTOCOL_VERSION" # version, min 176 my $lgreeting1 = "aemp;$PROTOCOL_VERSION"
161 . ";$AnyEvent::MP::Base::UNIQ" 177 . ";$self->{local_node}"
162 . ";$AnyEvent::MP::Base::NODE"
163 . ";" . (join ",", @AUTH_RCV) 178 . ";" . (join ",", @AUTH_RCV)
164 . ";" . (join ",", @FRAMINGS) 179 . ";" . (join ",", @FRAMINGS)
165 . (join "", map ";$_=$greeting_kv->{$_}", keys %$greeting_kv); 180 . (join "", map ";$_=$greeting_kv->{$_}", keys %$greeting_kv);
181
166 my $lgreeting2 = MIME::Base64::encode_base64 AnyEvent::MP::Base::nonce (33), ""; 182 my $lgreeting2 = MIME::Base64::encode_base64 AnyEvent::MP::Base::nonce (33), "";
167 183
168 $self->{hdl}->push_write ("$lgreeting1\012$lgreeting2\012"); 184 $self->{hdl}->push_write ("$lgreeting1\012$lgreeting2\012");
169 185
170 # expect greeting 186 # expect greeting
187 $self->{hdl}->rbuf_max (4 * 1024);
171 $self->{hdl}->push_read (line => sub { 188 $self->{hdl}->push_read (line => sub {
172 my $rgreeting1 = $_[1]; 189 my $rgreeting1 = $_[1];
173 190
174 my ($aemp, $version, $version_min, $uniq, $rnode, $auths, $framings, @kv) = split /;/, $rgreeting1; 191 my ($aemp, $version, $rnode, $auths, $framings, @kv) = split /;/, $rgreeting1;
175 192
176 if ($aemp ne "aemp") { 193 if ($aemp ne "aemp") {
177 return $self->error ("unparsable greeting"); 194 return $self->error ("unparsable greeting");
178 } elsif ($version_min > $PROTOCOL_VERSION) { 195 } elsif ($version != $PROTOCOL_VERSION) {
179 return $self->error ("version mismatch (we: $PROTOCOL_VERSION, they: $version_min .. $version)"); 196 return $self->error ("version mismatch (we: $PROTOCOL_VERSION, they: $version)");
180 } 197 }
181 198
182 my $s_auth; 199 my $s_auth;
183 for my $auth_ (split /,/, $auths) { 200 for my $auth_ (split /,/, $auths) {
184 if (grep $auth_ eq $_, @AUTH_SND) { 201 if (grep $auth_ eq $_, @AUTH_SND) {
201 } 218 }
202 219
203 defined $s_framing 220 defined $s_framing
204 or return $self->error ("$framings: no common framing method supported"); 221 or return $self->error ("$framings: no common framing method supported");
205 222
206 $self->{remote_uniq} = $uniq;
207 $self->{remote_node} = $rnode; 223 $self->{remote_node} = $rnode;
208 224
209 $self->{remote_greeting} = { 225 $self->{remote_greeting} = {
210 map /^([^=]+)(?:=(.*))?/ ? ($1 => $2) : (), 226 map /^([^=]+)(?:=(.*))?/ ? ($1 => $2) : (),
211 @kv 227 @kv
213 229
214 # read nonce 230 # read nonce
215 $self->{hdl}->push_read (line => sub { 231 $self->{hdl}->push_read (line => sub {
216 my $rgreeting2 = $_[1]; 232 my $rgreeting2 = $_[1];
217 233
234 "$lgreeting1\012$lgreeting2" ne "$rgreeting1\012$rgreeting2" # echo attack?
235 or return $self->error ("authentication error, echo attack?");
236
237 my $key = Digest::MD6::md6 $secret;
238 my $lauth;
239
218 if ($self->{tls_ctx} and 1 == int $self->{remote_greeting}{"tls"}) { 240 if ($self->{tls_ctx} and 1 == int $self->{remote_greeting}{tls}) {
219 $self->{tls} = $lgreeting2 lt $rgreeting2 ? "connect" : "accept"; 241 $self->{tls} = $lgreeting2 lt $rgreeting2 ? "connect" : "accept";
220 $self->{hdl}->starttls ($self->{tls}, $self->{tls_ctx}); 242 $self->{hdl}->starttls ($self->{tls}, $self->{tls_ctx});
243 $s_auth = "tls";
244 $lauth = "";
245 } else {
246 # we currently only support hmac_md6_64_256
247 $lauth = Digest::HMAC_MD6::hmac_md6_hex $key, "$lgreeting1\012$lgreeting2\012$rgreeting1\012$rgreeting2\012", 64, 256;
221 } 248 }
222
223 # auth
224 require Digest::MD6;
225 require Digest::HMAC_MD6;
226
227 my $key = Digest::MD6::md6_hex ($secret);
228 my $lauth = Digest::HMAC_MD6::hmac_md6_base64 ($key, "$lgreeting1\012$lgreeting2\012$rgreeting1\012$rgreeting2\012", 64, 256);
229
230 my $rauth =
231 $s_auth eq "hmac_md6_64_256" ? Digest::HMAC_MD6::hmac_md6_base64 ($key, "$rgreeting1\012$rgreeting2\012$lgreeting1\012$lgreeting2\012", 64, 256)
232 : $s_auth eq "hex_secret" ? unpack "H*", $secret
233 : die;
234
235 $lauth ne $rauth # echo attack?
236 or return $self->error ("authentication error");
237 249
238 $self->{hdl}->push_write ("$s_auth;$lauth;$s_framing\012"); 250 $self->{hdl}->push_write ("$s_auth;$lauth;$s_framing\012");
239 251
240 $self->{hdl}->rbuf_max (64); # enough for 44 reply bytes or so 252 # read the authentication response
241 $self->{hdl}->push_read (line => sub { 253 $self->{hdl}->push_read (line => sub {
242 my ($hdl, $rline) = @_; 254 my ($hdl, $rline) = @_;
243 255
244 my ($auth_method, $rauth2, $r_framing) = split /;/, $rline; 256 my ($auth_method, $rauth2, $r_framing) = split /;/, $rline;
257
258 my $rauth =
259 $auth_method eq "hmac_md6_64_256" ? Digest::HMAC_MD6::hmac_md6_hex $key, "$rgreeting1\012$rgreeting2\012$lgreeting1\012$lgreeting2\012", 64, 256
260 : $auth_method eq "cleartext" ? unpack "H*", $secret
261 : $auth_method eq "tls" ? ($self->{tls} ? "" : "\012\012") # \012\012 never matches
262 : return $self->error ("$auth_method: fatal, selected unsupported auth method");
245 263
246 if ($rauth2 ne $rauth) { 264 if ($rauth2 ne $rauth) {
247 return $self->error ("authentication failure/shared secret mismatch"); 265 return $self->error ("authentication failure/shared secret mismatch");
248 } 266 }
249 267
250 $self->{s_framing} = $s_framing; 268 $self->{s_framing} = $s_framing;
251 269
252 $hdl->rbuf_max (undef); 270 $hdl->rbuf_max (undef);
253 my $queue = delete $self->{queue}; # we are connected 271 my $queue = delete $self->{queue}; # we are connected
254 272
273 $self->{hdl}->timeout ($self->{remote_greeting}{timeout});
274
255 $self->connected; 275 $self->connected;
256 276
257 $hdl->push_write ($self->{s_framing} => $_) 277 my $src_node = $self->{node};
278
279 $self->send ($_)
258 for @$queue; 280 for @$queue;
259 281
260 my $rmsg; $rmsg = sub { 282 my $rmsg; $rmsg = sub {
261 $_[0]->push_read ($r_framing => $rmsg); 283 $_[0]->push_read ($r_framing => $rmsg);
262 284
285 local $AnyEvent::MP::Base::SRCNODE = $src_node;
263 AnyEvent::MP::Base::_inject ($_[1]); 286 AnyEvent::MP::Base::_inject (@{ $_[1] });
264 }; 287 };
265 $hdl->push_read ($r_framing => $rmsg); 288 $hdl->push_read ($r_framing => $rmsg);
266 }); 289 });
267 }); 290 });
268 }); 291 });
273 296
274sub error { 297sub error {
275 my ($self, $msg) = @_; 298 my ($self, $msg) = @_;
276 299
277 if ($self->{node} && $self->{node}{transport} == $self) { 300 if ($self->{node} && $self->{node}{transport} == $self) {
301 #TODO: store error, but do not instantly fail
302 $self->{node}->fail (transport_error => $self->{node}{noderef}, $msg);
278 $self->{node}->clr_transport; 303 $self->{node}->clr_transport;
279 } 304 }
280 $AnyEvent::MP::Base::WARN->("$self->{peerhost}:$self->{peerport}: $msg"); 305 $AnyEvent::MP::Base::WARN->("$self->{peerhost}:$self->{peerport}: $msg");
281 $self->destroy; 306 $self->destroy;
282} 307}
283 308
284sub connected { 309sub connected {
285 my ($self) = @_; 310 my ($self) = @_;
286 311
312 if (ref $AnyEvent::MP::Base::SLAVE) {
313 # first connect with a master node
314 my $via = $self->{remote_node};
315 $via =~ s/,/!/g;
316 $AnyEvent::MP::Base::NODE .= "\@$via";
317 $AnyEvent::MP::Base::NODE{$AnyEvent::MP::Base::NODE} = $AnyEvent::MP::Base::NODE{""};
318 $AnyEvent::MP::Base::SLAVE->();
319 }
320
321 if ($self->{local_node} ne $AnyEvent::MP::Base::NODE) {
322 # node changed its name since first greeting
323 $self->send (["", iam => $AnyEvent::MP::Base::NODE]);
324 }
325
287 my $node = AnyEvent::MP::Base::add_node ($self->{remote_node}); 326 my $node = AnyEvent::MP::Base::add_node ($self->{remote_node});
288 Scalar::Util::weaken ($self->{node} = $node); 327 Scalar::Util::weaken ($self->{node} = $node);
289 $node->set_transport ($self); 328 $node->set_transport ($self);
290} 329}
291 330
319The greeting consists of two text lines that are ended by either an ASCII 358The greeting consists of two text lines that are ended by either an ASCII
320CR LF pair, or a single ASCII LF (recommended). 359CR LF pair, or a single ASCII LF (recommended).
321 360
322=head2 GREETING 361=head2 GREETING
323 362
363All the lines until after authentication must not exceed 4kb in length,
364including delimiter. Afterwards there is no limit on the packet size that
365can be received.
366
367=head3 First Greeting Line
368
369Example:
370
371 aemp;0;fec.4a7720fc;127.0.0.1:1235,[::1]:1235;hmac_md6_64_256;json,storable;provider=AE-0.0
372
324The first line contains strings separated (not ended) by C<;> 373The first line contains strings separated (not ended) by C<;>
325characters. The first seven strings are fixed by the protocol, the 374characters. The first even ixtrings are fixed by the protocol, the
326remaining strings are C<KEY=VALUE> pairs. None of them may contain C<;> 375remaining strings are C<KEY=VALUE> pairs. None of them may contain C<;>
327characters themselves. 376characters themselves.
328 377
329The seven fixed strings are: 378The fixed strings are:
330 379
331=over 4 380=over 4
332 381
333=item C<aemp> 382=item protocol identification
334 383
335The constant C<aemp> to identify the protocol. 384The constant C<aemp> to identify the protocol.
336 385
337=item protocol version 386=item protocol version
338 387
339The (maximum) protocol version supported by this end, currently C<0>.
340
341=item minimum protocol version
342
343The minimum protocol version supported by this end, currently C<0>. 388The protocol version supported by this end, currently C<0>. If the
344 389versions don't match then no communication is possible. Minor extensions
345=item a token uniquely identifying the current node instance 390are supposed to be handled through additional key-value pairs.
346
347This is a string that must change between restarts. It usually contains
348things like the current time, the (OS) process id or similar values, but
349no meaning of the contents are assumed.
350 391
351=item the node endpoint descriptors 392=item the node endpoint descriptors
352 393
353for public nodes, this is a comma-separated list of protocol endpoints, 394for public nodes, this is a comma-separated list of protocol endpoints,
354i.e., the noderef. For slave nodes, this is a unique identifier. 395i.e., the noderef. For slave nodes, this is a unique identifier of the
396form C<slave/nonce>.
355 397
356=item the acceptable authentication methods 398=item the acceptable authentication methods
357 399
358A comma-separated list of authentication methods supported by the 400A comma-separated list of authentication methods supported by the
359node. Note that AnyEvent::MP supports a C<hex_secret> authentication 401node. Note that AnyEvent::MP supports a C<hex_secret> authentication
366 408
367A comma-separated list of packet encoding/framign formats understood. The 409A comma-separated list of packet encoding/framign formats understood. The
368receiving side should choose the first framing format it supports for 410receiving side should choose the first framing format it supports for
369sending packets (which might be different from the format it has to accept). 411sending packets (which might be different from the format it has to accept).
370 412
371=cut 413=back
372 414
373The remaining arguments are C<KEY=VALUE> pairs. The following key-value 415The remaining arguments are C<KEY=VALUE> pairs. The following key-value
374pairs are known at this time: 416pairs are known at this time:
375 417
376=over 4 418=over 4
388=item tls=<major>.<minor> 430=item tls=<major>.<minor>
389 431
390Indicates that the other side supports TLS (version should be 1.0) and 432Indicates that the other side supports TLS (version should be 1.0) and
391wishes to do a TLS handshake. 433wishes to do a TLS handshake.
392 434
435=item timeout=<seconds>
436
437The amount of time after which this node should be detected as dead unless
438some data has been received. The node is responsible to send traffic
439reasonably more often than this interval (such as every timeout minus five
440seconds).
441
393=back 442=back
443
444=head3 Second Greeting Line
394 445
395After this greeting line there will be a second line containing a 446After this greeting line there will be a second line containing a
396cryptographic nonce, i.e. random data of high quality. To keep the 447cryptographic nonce, i.e. random data of high quality. To keep the
397protocol text-only, these are usually 32 base64-encoded octets, but 448protocol text-only, these are usually 32 base64-encoded octets, but
398it could be anything that doesn't contain any ASCII CR or ASCII LF 449it could be anything that doesn't contain any ASCII CR or ASCII LF
399characters. 450characters.
400 451
401Example of the two lines of greeting: 452I<< The two nonces B<must> be different, and an aemp implementation
453B<must> check and fail when they are identical >>.
402 454
403 aemp;0;0;e7d.4a76f48f;10.0.0.1:4040;hmac_md6_64_256,hex_secret;json,storable;provider=AE-0.0;peeraddr=127.0.0.1:1235 455Example of a nonce line:
404 XntegV2Guvss0qNn7phCPnoU87xqxV+4Mqm/5y4iQm6a 456
457 p/I122ql7kJR8lumW3lXlXCeBnyDAvz8NQo3x5IFowE4
405 458
406=head2 TLS handshake 459=head2 TLS handshake
407 460
408If, after the handshake, both sides indicate interest in TLS, then the 461I<< If, after the handshake, both sides indicate interest in TLS, then the
409connection I<must> use TLS, or fail. 462connection B<must> use TLS, or fail. >>
410 463
411Both sides compare their nonces, and the side who sent the lower nonce 464Both sides compare their nonces, and the side who sent the lower nonce
412value ("string" comparison on the raw octet values) becomes the client, 465value ("string" comparison on the raw octet values) becomes the client,
413and the one with the higher nonce the server. 466and the one with the higher nonce the server.
414 467
425 478
426=item the authentication method chosen 479=item the authentication method chosen
427 480
428This must be one of the methods offered by the other side in the greeting. 481This must be one of the methods offered by the other side in the greeting.
429 482
483The currently supported authentication methods are:
484
485=over 4
486
487=item cleartext
488
489This is simply the shared secret, lowercase-hex-encoded. This method is of
490course very insecure, unless TLS is used, which is why this module will
491accept, but not generate, cleartext auth replies.
492
493=item hmac_md6_64_256
494
495This method uses an MD6 HMAC with 64 bit blocksize and 256 bit hash. First, the shared secret
496is hashed with MD6:
497
498 key = MD6 (secret)
499
500This secret is then used to generate the "local auth reply", by taking
501the two local greeting lines and the two remote greeting lines (without
502line endings), appending \012 to all of them, concatenating them and
503calculating the MD6 HMAC with the key.
504
505 lauth = HMAC_MD6 key, "lgreeting1\012lgreeting2\012rgreeting1\012rgreeting2\012"
506
507This authentication token is then lowercase-hex-encoded and sent to the
508other side.
509
510Then the remote auth reply is generated using the same method, but local
511and remote greeting lines swapped:
512
513 rauth = HMAC_MD6 key, "rgreeting1\012rgreeting2\012lgreeting1\012lgreeting2\012"
514
515This is the token that is expected from the other side.
516
517=item tls
518
519This type is only valid iff TLS was enabled and the TLS handshake
520was successful. It has no authentication data, as the server/client
521certificate was successfully verified.
522
523Implementations supporting TLS I<must> accept this authentication type.
524
525=back
526
430=item the authentication data 527=item the authentication data
431 528
432The authentication data itself, usually base64 or hex-encoded data. 529The authentication data itself, usually base64 or hex-encoded data, see
530above.
433 531
434=item the framing protocol chosen 532=item the framing protocol chosen
435 533
436This must be one of the framing protocols offered by the other side in the 534This must be one of the framing protocols offered by the other side in the
437greeting. Each side must accept the choice of the other side. 535greeting. Each side must accept the choice of the other side.
438 536
439=back 537=back
440 538
539Example of an authentication reply:
540
541 hmac_md6_64_256;363d5175df38bd9eaddd3f6ca18aa1c0c4aa22f0da245ac638d048398c26b8d3;json
542
441=head2 DATA PHASE 543=head2 DATA PHASE
442 544
443After this, packets get exchanged using the chosen framing protocol. It is 545After this, packets get exchanged using the chosen framing protocol. It is
444quite possible that both sides use a different framing protocol. 546quite possible that both sides use a different framing protocol.
445 547
548=head2 FULL EXAMPLE
549
550This is an actual protocol dump of a handshake, followed by a single data
551packet. The greater than/less than lines indicate the direction of the
552transfer only.
553
554 > aemp;0;nndKd+gn;10.0.0.1:4040;hmac_md6_64_256,cleartext;json,storable;provider=AE-0.0;peeraddr=127.0.0.1:1235
555 > sRG8bbc4TDbkpvH8FTP4HBs87OhepH6VuApoZqXXskuG
556 < aemp;0;nmpKd+gh;127.0.0.1:1235,[::1]:1235;hmac_md6_64_256,cleartext;json,storable;provider=AE-0.0;peeraddr=127.0.0.1:58760
557 < dCEUcL/LJVSTJcx8byEsOzrwhzJYOq+L3YcopA5T6EAo
558 > hmac_md6_64_256;9513d4b258975accfcb2ab7532b83690e9c119a502c612203332a591c7237788;json
559 < hmac_md6_64_256;0298d6ba2240faabb2b2e881cf86b97d70a113ca74a87dc006f9f1e9d3010f90;json
560 > ["","lookup","pinger","10.0.0.1:4040#nndKd+gn.a","resolved"]
561
446=head1 SEE ALSO 562=head1 SEE ALSO
447 563
448L<AnyEvent>. 564L<AnyEvent>.
449 565
450=head1 AUTHOR 566=head1 AUTHOR

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines