ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent-MP/MP/Transport.pm
Revision: 1.86
Committed: Sun Aug 28 14:38:28 2016 UTC (7 years, 9 months ago) by root
Branch: MAIN
Changes since 1.85: +1 -1 lines
Log Message:
*** empty log message ***

File Contents

# Content
1 =head1 NAME
2
3 AnyEvent::MP::Transport - actual transport protocol handler
4
5 =head1 SYNOPSIS
6
7 use AnyEvent::MP::Transport;
8
9 =head1 DESCRIPTION
10
11 This module implements (and documents) the actual transport protocol for
12 AEMP.
13
14 See the "PROTOCOL" section below if you want to write another client for
15 this protocol.
16
17 =head1 FUNCTIONS/METHODS
18
19 =over 4
20
21 =cut
22
23 package AnyEvent::MP::Transport;
24
25 use common::sense;
26
27 use Scalar::Util ();
28 use List::Util ();
29 use MIME::Base64 ();
30
31 use JSON::XS ();
32 use Digest::SHA3 ();
33 use Digest::HMAC ();
34
35 use AnyEvent ();
36 use AnyEvent::Socket ();
37 use AnyEvent::Handle 4.92 ();
38
39 use AnyEvent::MP::Config ();
40
41 our $PROTOCOL_VERSION = 1;
42
43 our @HOOK_GREET; # called at connect/accept time
44 our @HOOK_GREETED; # called at greeting1 time
45 our @HOOK_CONNECT; # called at data phase
46 our @HOOK_DESTROY; # called at destroy time
47 our %HOOK_PROTOCOL = (
48 "aemp-dataconn" => sub {
49 require AnyEvent::MP::DataConn;
50 &AnyEvent::MP::DataConn::_inject;
51 },
52 );
53
54 =item $listener = mp_server $host, $port, <constructor-args>
55
56 Creates a listener on the given host/port using
57 C<AnyEvent::Socket::tcp_server>.
58
59 See C<new>, below, for constructor arguments.
60
61 Defaults for peerhost, peerport and fh are provided.
62
63 =cut
64
65 sub mp_server($$;%) {
66 my ($host, $port, %arg) = @_;
67
68 AnyEvent::Socket::tcp_server $host, $port, sub {
69 my ($fh, $host, $port) = @_;
70
71 my $tp = new AnyEvent::MP::Transport
72 fh => $fh,
73 peerhost => $host,
74 peerport => $port,
75 %arg,
76 ;
77 $tp->{keepalive} = $tp;
78 }, delete $arg{prepare}
79 }
80
81 =item $guard = mp_connect $host, $port, <constructor-args>, $cb->($transport)
82
83 =cut
84
85 sub mp_connect {
86 my $release = pop;
87 my ($host, $port, @args) = @_;
88
89 new AnyEvent::MP::Transport
90 connect => [$host, $port],
91 peerhost => $host,
92 peerport => $port,
93 release => $release,
94 @args,
95 ;
96 }
97
98 =item new AnyEvent::MP::Transport
99
100 Create a new transport - usually used via C<mp_server> or C<mp_connect>
101 instead.
102
103 # immediately starts negotiation
104 my $transport = new AnyEvent::MP::Transport
105 # mandatory
106 fh => $filehandle,
107 local_id => $identifier,
108 on_recv => sub { receive-callback },
109 on_error => sub { error-callback },
110
111 # optional
112 on_greet => sub { before sending greeting },
113 on_greeted => sub { after receiving greeting },
114 on_connect => sub { successful-connect-callback },
115 greeting => { key => value },
116
117 # tls support
118 tls_ctx => AnyEvent::TLS,
119 peername => $peername, # for verification
120 ;
121
122 =cut
123
124 sub hmac_sha3_512_hex($$) {
125 Digest::HMAC::hmac_hex $_[1], $_[0], \&Digest::SHA3::sha3_512, 72
126 }
127
128 sub new {
129 my ($class, %arg) = @_;
130
131 my $self = bless \%arg, $class;
132
133 {
134 Scalar::Util::weaken (my $self = $self);
135
136 my $config = $AnyEvent::MP::Kernel::CONFIG;
137
138 my $timeout = $config->{monitor_timeout};
139 my $lframing = $config->{framing_format};
140 my $auth_snd = $config->{auth_offer};
141 my $auth_rcv = $config->{auth_accept};
142
143 $self->{secret} = $config->{secret}
144 unless exists $self->{secret};
145
146 my $secret = $self->{secret};
147
148 if (exists $config->{cert}) {
149 $self->{tls_ctx} = {
150 sslv2 => 0,
151 sslv3 => 0,
152 tlsv1 => 1,
153 verify => 1,
154 cert => $config->{cert},
155 ca_cert => $config->{cert},
156 verify_require_client_cert => 1,
157 };
158 }
159
160 $self->{hdl} = new AnyEvent::Handle
161 +($self->{fh} ? (fh => $self->{fh}) : (connect => $self->{connect})),
162 autocork => $config->{autocork},
163 no_delay => exists $config->{nodelay} ? $config->{nodelay} : 1,
164 keepalive => 1,
165 on_error => sub {
166 $self->error ($_[2]);
167 },
168 rtimeout => $timeout,
169 ;
170
171 my $greeting_kv = $self->{local_greeting} ||= {};
172
173 $greeting_kv->{tls} = "1.0" if $self->{tls_ctx};
174 $greeting_kv->{provider} = "AE-$AnyEvent::MP::Config::VERSION";
175 $greeting_kv->{peeraddr} = AnyEvent::Socket::format_hostport $self->{peerhost}, $self->{peerport};
176
177 my $protocol = $self->{protocol} || "aemp";
178
179 # can modify greeting_kv
180 $_->($self) for $protocol eq "aemp" ? @HOOK_GREET : ();
181 (delete $self->{on_greet})->($self)
182 if exists $self->{on_greet};
183
184 # send greeting
185 my $lgreeting1 = "$protocol;$PROTOCOL_VERSION"
186 . ";$AnyEvent::MP::Kernel::NODE"
187 . ";" . (join ",", @$auth_rcv)
188 . ";" . (join ",", @$lframing)
189 . (join "", map ";$_=$greeting_kv->{$_}", keys %$greeting_kv);
190
191 my $lgreeting2 = MIME::Base64::encode_base64 AnyEvent::MP::Kernel::nonce (66), "";
192
193 $self->{hdl}->push_write ("$lgreeting1\012$lgreeting2\012");
194 return unless $self;
195
196 # expect greeting
197 $self->{hdl}->rbuf_max (4 * 1024);
198 $self->{hdl}->push_read (line => sub {
199 my $rgreeting1 = $_[1];
200
201 my ($aemp, $version, $rnode, $auths, $framings, @kv) = split /;/, $rgreeting1;
202
203 $self->{remote_node} = $rnode;
204
205 $self->{remote_greeting} = {
206 map /^([^=]+)(?:=(.*))?/ ? ($1 => $2) : (),
207 @kv
208 };
209
210 # maybe upgrade the protocol
211 if ($protocol eq "aemp" and $aemp =~ /^aemp-\w+$/) {
212 # maybe check for existence of the protocol handler?
213 $self->{protocol} = $protocol = $aemp;
214 }
215
216 $_->($self) for $protocol eq "aemp" ? @HOOK_GREETED : ();
217 (delete $self->{on_greeted})->($self)
218 if exists $self->{on_greeted};
219
220 if ($aemp ne $protocol and $aemp ne "aemp") {
221 return $self->error ("unparsable greeting, expected '$protocol', got '$aemp'");
222 } elsif ($version != $PROTOCOL_VERSION) {
223 return $self->error ("version mismatch (we: $PROTOCOL_VERSION, they: $version)");
224 } elsif ($protocol eq "aemp") {
225 if ($rnode eq $AnyEvent::MP::Kernel::NODE) {
226 return $self->error ("I refuse to talk to myself");
227 } elsif ($AnyEvent::MP::Kernel::NODE{$rnode} && $AnyEvent::MP::Kernel::NODE{$rnode}{transport}) {
228 return $self->error ("$rnode already connected, not connecting again.");
229 }
230 }
231
232 # read nonce
233 $self->{hdl}->push_read (line => sub {
234 my $rgreeting2 = $_[1];
235
236 "$lgreeting1\012$lgreeting2" ne "$rgreeting1\012$rgreeting2" # echo attack?
237 or return $self->error ("authentication error, echo attack?");
238
239 my $tls = $self->{tls_ctx} && 1 == int $self->{remote_greeting}{tls};
240
241 my $s_auth;
242 for my $auth_ (split /,/, $auths) {
243 if (grep $auth_ eq $_, @$auth_snd and ($auth_ !~ /^tls_/ or $tls)) {
244 $s_auth = $auth_;
245 last;
246 }
247 }
248
249 defined $s_auth
250 or return $self->error ("$auths: no common auth type supported");
251
252 my $s_framing;
253 for my $framing_ (split /,/, $framings) {
254 if (grep $framing_ eq $_, @$lframing) {
255 $s_framing = $framing_;
256 last;
257 }
258 }
259
260 defined $s_framing
261 or return $self->error ("$framings: no common framing method supported");
262
263 my $lauth;
264
265 if ($tls) {
266 $self->{tls} = $lgreeting2 lt $rgreeting2 ? "connect" : "accept";
267 $self->{hdl}->starttls ($self->{tls}, $self->{tls_ctx});
268 return unless $self->{hdl}; # starttls might destruct us
269
270 $lauth =
271 $s_auth eq "tls_anon" ? ""
272 : $s_auth eq "tls_sha3_512" ? Digest::SHA3::sha3_512_hex "$lgreeting1\012$lgreeting2\012$rgreeting1\012$rgreeting2\012"
273 : return $self->error ("$s_auth: fatal, selected unsupported snd auth method");
274
275 } elsif (length $secret) {
276 return $self->error ("$s_auth: fatal, selected unsupported snd auth method")
277 unless $s_auth eq "hmac_sha3_512"; # hardcoded atm.
278
279 $lauth = hmac_sha3_512_hex $secret, "$lgreeting1\012$lgreeting2\012$rgreeting1\012$rgreeting2\012";
280
281 } else {
282 return $self->error ("unable to handshake TLS and no shared secret configured");
283 }
284
285 $self->{hdl}->push_write ("$s_auth;$lauth;$s_framing\012");
286 return unless $self;
287
288 # read the authentication response
289 $self->{hdl}->push_read (line => sub {
290 my ($hdl, $rline) = @_;
291
292 my ($auth_method, $rauth2, $r_framing) = split /;/, $rline;
293
294 my $rauth =
295 $auth_method eq "hmac_sha3_512" ? hmac_sha3_512_hex $secret, "$rgreeting1\012$rgreeting2\012$lgreeting1\012$lgreeting2\012"
296 : $auth_method eq "cleartext" ? unpack "H*", $secret
297 : $auth_method eq "tls_anon" ? ($tls ? "" : "\012\012") # \012\012 never matches
298 : $auth_method eq "tls_sha3_512" ? ($tls ? Digest::SHA3::sha3_512_hex "$rgreeting1\012$rgreeting2\012$lgreeting1\012$lgreeting2\012" : "\012\012")
299 : return $self->error ("$auth_method: fatal, selected unsupported rcv auth method");
300
301 if ($rauth2 ne $rauth) {
302 return $self->error ("authentication failure/shared secret mismatch");
303 }
304
305 $self->{r_framing} = $r_framing;
306 $self->{s_framing} = $s_framing;
307
308 $hdl->rbuf_max (undef);
309
310 # we rely on TCP retransmit timeouts and keepalives
311 $self->{hdl}->rtimeout (undef);
312
313 $self->{remote_greeting}{untrusted} = 1
314 if $auth_method eq "tls_anon";
315
316 if ($protocol eq "aemp" and $self->{hdl}) {
317 # listener-less nodes need to continuously probe
318 # unless (@$AnyEvent::MP::Kernel::BINDS) {
319 # $self->{hdl}->wtimeout ($timeout);
320 # $self->{hdl}->on_wtimeout (sub { $self->{send}->([]) });
321 # }
322
323 # receive handling
324 $self->set_snd_framing;
325 $self->set_rcv_framing;
326 }
327
328 $self->connected;
329 });
330 });
331 });
332 }
333
334 $self
335 }
336
337 sub set_snd_framing {
338 my ($self) = @_;
339
340 my $framing = $self->{s_framing};
341 my $hdl = $self->{hdl};
342 my $push_write = $hdl->can ("push_write");
343
344 if ($framing eq "json") {
345 $self->{send} = sub {
346 $push_write->($hdl, JSON::XS::encode_json $_[0]);
347 };
348 } else {
349 $self->{send} = sub {
350 $push_write->($hdl, $framing => $_[0]);
351 };
352 }
353 }
354
355 sub set_rcv_framing {
356 my ($self) = @_;
357
358 my $node = $self->{remote_node};
359 my $framing = $self->{r_framing};
360 my $hdl = $self->{hdl};
361 my $push_read = $hdl->can ("push_read");
362
363 if ($framing eq "json") {
364 my $coder = JSON::XS->new->utf8;
365
366 $hdl->on_read (sub {
367 $AnyEvent::MP::Kernel::SRCNODE = $node;
368
369 AnyEvent::MP::Kernel::_inject (@$_)
370 for $coder->incr_parse (delete $_[0]{rbuf});
371
372 ()
373 });
374 } else {
375 my $rmsg; $rmsg = $self->{rmsg} = sub {
376 $push_read->($_[0], $framing => $rmsg);
377
378 $AnyEvent::MP::Kernel::SRCNODE = $node;
379 AnyEvent::MP::Kernel::_inject (@{ $_[1] });
380 };
381 eval {
382 $push_read->($hdl, $framing => $rmsg);
383 };
384 Scalar::Util::weaken $rmsg;
385 return $self->error ("$framing: unusable remote framing")
386 if $@;
387 }
388 }
389
390 sub error {
391 my ($self, $msg) = @_;
392
393 delete $self->{keepalive};
394
395 if ($self->{protocol}) {
396 $HOOK_PROTOCOL{$self->{protocol}}->($self, $msg);
397 } else {
398 AE::log 9 => "$self->{peerhost}:$self->{peerport} disconnected - $msg.";
399
400 $self->{node}->transport_error (transport_error => $self->{node}{id}, $msg)
401 if $self->{node} && $self->{node}{transport} == $self;
402 }
403
404 (delete $self->{release})->()
405 if exists $self->{release};
406
407 $self->destroy;
408 }
409
410 sub connected {
411 my ($self) = @_;
412
413 delete $self->{keepalive};
414
415 if ($self->{protocol}) {
416 $self->{hdl}->on_error (undef);
417 $HOOK_PROTOCOL{$self->{protocol}}->($self, undef);
418 } else {
419 AE::log 9 => "$self->{peerhost}:$self->{peerport} connected as $self->{remote_node}.";
420
421 my $node = AnyEvent::MP::Kernel::add_node ($self->{remote_node});
422 Scalar::Util::weaken ($self->{node} = $node);
423 $node->transport_connect ($self);
424
425 $_->($self) for @HOOK_CONNECT;
426 }
427
428 (delete $self->{release})->()
429 if exists $self->{release};
430
431 (delete $self->{on_connect})->($self)
432 if exists $self->{on_connect};
433 }
434
435 sub destroy {
436 my ($self) = @_;
437
438 (delete $self->{release})->()
439 if exists $self->{release};
440
441 $self->{hdl}->destroy
442 if $self->{hdl};
443
444 (delete $self->{on_destroy})->($self)
445 if exists $self->{on_destroy};
446 $_->($self) for $self->{protocol} ? () : @HOOK_DESTROY;
447
448 $self->{protocol} = "destroyed"; # to keep hooks from invoked twice.
449 }
450
451 sub DESTROY {
452 my ($self) = @_;
453
454 $self->destroy;
455 }
456
457 =back
458
459 =head1 PROTOCOL
460
461 The AEMP protocol is comparatively simple, and consists of three phases
462 which are symmetrical for both sides: greeting (followed by optionally
463 switching to TLS mode), authentication and packet exchange.
464
465 The protocol is designed to allow both full-text and binary streams.
466
467 The greeting consists of two text lines that are ended by either an ASCII
468 CR LF pair, or a single ASCII LF (recommended).
469
470 =head2 GREETING
471
472 All the lines until after authentication must not exceed 4kb in length,
473 including line delimiter. Afterwards there is no limit on the packet size
474 that can be received.
475
476 =head3 First Greeting Line
477
478 Example:
479
480 aemp;0;rain;tls_sha3_512,hmac_sha3_512,tls_anon,cleartext;json,storable;timeout=12;peeraddr=10.0.0.1:48082
481
482 The first line contains strings separated (not ended) by C<;>
483 characters. The first five strings are fixed by the protocol, the
484 remaining strings are C<KEY=VALUE> pairs. None of them may contain C<;>
485 characters themselves (when escaping is needed, use C<%3b> to represent
486 C<;> and C<%25> to represent C<%>)-
487
488 The fixed strings are:
489
490 =over 4
491
492 =item protocol identification
493
494 The constant C<aemp> to identify this protocol.
495
496 =item protocol version
497
498 The protocol version supported by this end, currently C<1>. If the
499 versions don't match then no communication is possible. Minor extensions
500 are supposed to be handled through additional key-value pairs.
501
502 =item the node ID
503
504 This is the node ID of the connecting node.
505
506 =item the acceptable authentication methods
507
508 A comma-separated list of authentication methods supported by the
509 node. Note that AnyEvent::MP supports a C<hex_secret> authentication
510 method that accepts a clear-text password (hex-encoded), but will not use
511 this authentication method itself.
512
513 The receiving side should choose the first authentication method it
514 supports.
515
516 =item the acceptable framing formats
517
518 A comma-separated list of packet encoding/framing formats understood. The
519 receiving side should choose the first framing format it supports for
520 sending packets (which might be different from the format it has to accept).
521
522 =back
523
524 The remaining arguments are C<KEY=VALUE> pairs. The following key-value
525 pairs are known at this time:
526
527 =over 4
528
529 =item provider=<module-version>
530
531 The software provider for this implementation. For AnyEvent::MP, this is
532 C<AE-0.0> or whatever version it currently is at.
533
534 =item peeraddr=<host>:<port>
535
536 The peer address (socket address of the other side) as seen locally.
537
538 =item tls=<major>.<minor>
539
540 Indicates that the other side supports TLS (version should be 1.0) and
541 wishes to do a TLS handshake.
542
543 =item nproto=<major>.<fractional>
544
545 Informs the other side of the node protocol implemented by this
546 node. Major version mismatches are fatal. If this key is missing, then it
547 is assumed that the node doesn't support the node protocol.
548
549 The node protocol is currently undocumented, but includes port
550 monitoring, spawning and informational requests.
551
552 =item gproto=<major>.<fractional>
553
554 Informs the other side of the global protocol implemented by this
555 node. Major version mismatches are fatal. If this key is missing, then it
556 is assumed that the node doesn't support the global protocol.
557
558 The global protocol is currently undocumented, but includes node address
559 lookup and shared database operations.
560
561 =back
562
563 =head3 Second Greeting Line
564
565 After this greeting line there will be a second line containing a
566 cryptographic nonce, i.e. random data of high quality. To keep the
567 protocol text-only, these are usually 32 base64-encoded octets, but
568 it could be anything that doesn't contain any ASCII CR or ASCII LF
569 characters.
570
571 I<< The two nonces B<must> be different, and an aemp implementation
572 B<must> check and fail when they are identical >>.
573
574 Example of a nonce line (yes, it's random-looking because it is random
575 data):
576
577 2XYhdG7/O6epFa4wuP0ujAEx1rXYWRcOypjUYK7eF6yWAQr7gwIN9m/2+mVvBrTPXz5GJDgfGm9d8QRABAbmAP/s
578
579 =head2 TLS handshake
580
581 I<< If, after the handshake, both sides indicate interest in TLS, then the
582 connection B<must> use TLS, or fail to continue. >>
583
584 Both sides compare their nonces, and the side who sent the lower nonce
585 value ("string" comparison on the raw octet values) becomes the client,
586 and the one with the higher nonce the server.
587
588 =head2 AUTHENTICATION PHASE
589
590 After the greeting is received (and the optional TLS handshake),
591 the authentication phase begins, which consists of sending a single
592 C<;>-separated line with three fixed strings and any number of
593 C<KEY=VALUE> pairs.
594
595 The three fixed strings are:
596
597 =over 4
598
599 =item the authentication method chosen
600
601 This must be one of the methods offered by the other side in the greeting.
602
603 Note that all methods starting with C<tls_> are only valid I<iff> TLS was
604 successfully handshaked (and to be secure the implementation must enforce
605 this).
606
607 The currently supported authentication methods are:
608
609 =over 4
610
611 =item cleartext
612
613 This is simply the shared secret, lowercase-hex-encoded. This method is of
614 course very insecure if TLS is not used (and not completely secure even
615 if TLS is used), which is why this module will accept, but not generate,
616 cleartext auth replies.
617
618 =item hmac_sha3_512
619
620 This method uses a SHA-3/512 HMAC with 576 bit blocksize and 512 bit hash,
621 and requires a shared secret. It is the preferred auth method when a
622 shared secret is available.
623
624 The secret is used to generate the "local auth reply", by taking the
625 two local greeting lines and the two remote greeting lines (without
626 line endings), appending \012 to all of them, concatenating them and
627 calculating the HMAC with the key:
628
629 lauth = HMAC_SHA3_512 key, "lgreeting1\012lgreeting2\012rgreeting1\012rgreeting2\012"
630
631 This authentication token is then lowercase-hex-encoded and sent to the
632 other side.
633
634 Then the remote auth reply is generated using the same method, but local
635 and remote greeting lines swapped:
636
637 rauth = HMAC_SHA3_512 key, "rgreeting1\012rgreeting2\012lgreeting1\012lgreeting2\012"
638
639 This is the token that is expected from the other side.
640
641 =item hmac_md6_64_256 [obsolete, not supported]
642
643 This method uses an MD6 HMAC with 64 bit blocksize and 256 bit hash, and
644 requires a shared secret. It is similar to C<hmac_sha3_512>, but uses
645 MD6 instead of SHA-3 and instead of using the secret directly, it uses
646 MD6(secret) as HMAC key.
647
648 =item tls_anon
649
650 This type is only valid I<iff> TLS was enabled and the TLS handshake
651 was successful. It has no authentication data, as the server/client
652 certificate was successfully verified.
653
654 This authentication type is somewhat insecure, as it allows a
655 man-in-the-middle attacker to change some of the connection parameters
656 (such as the framing format), although there is no known attack that
657 exploits this in a way that is worse than just denying the service.
658
659 By default, this implementation accepts but never generates this auth
660 reply.
661
662 =item tls_sha3_512
663
664 This type is only valid I<iff> TLS was enabled and the TLS handshake was
665 successful.
666
667 This authentication type simply calculates:
668
669 lauth = SHA3_512 "rgreeting1\012rgreeting2\012lgreeting1\012lgreeting2\012"
670
671 and lowercase-hex encodes the result and sends it as authentication
672 data. No shared secret is required (authentication is done by TLS). The
673 checksum exists only to make tinkering with the greeting hard.
674
675 =item tls_md6_64_256 [deprecated, unsupported]
676
677 Same as C<tls_sha3_512>, except MD6 is used.
678
679 =back
680
681 =item the authentication data
682
683 The authentication data itself, usually base64 or hex-encoded data, see
684 above.
685
686 =item the framing protocol chosen
687
688 This must be one of the framing protocols offered by the other side in the
689 greeting. Each side must accept the choice of the other side, and generate
690 packets in the format it chose itself.
691
692 =back
693
694 Example of an authentication reply:
695
696 hmac_md6_64_256;363d5175df38bd9eaddd3f6ca18aa1c0c4aa22f0da245ac638d048398c26b8d3;json
697
698 =head2 DATA PHASE
699
700 After this, packets get exchanged using the chosen framing protocol. It is
701 quite possible that both sides use a different framing protocol.
702
703 =head2 FULL EXAMPLE
704
705 This is an actual protocol dump of a handshake, followed by a single data
706 packet. The greater than/less than lines indicate the direction of the
707 transfer only.
708
709 > aemp;0;anon/57Cs1CggVJjzYaQp13XXg4;tls_md6_64_256,hmac_md6_64_256,tls_anon,cleartext;json,storable;provider=AE-0.8;timeout=12;peeraddr=10.0.0.17:4040
710 > yLgdG1ov/02shVkVQer3wzeuywZK+oraTdEQBmIqWHaegxSGDG4g+HqogLQbvdypFOsoDWJ1Sh4ImV4DMhvUBwTK
711
712 < aemp;0;ruth;tls_md6_64_256,hmac_md6_64_256,tls_anon,cleartext;json,storable;provider=AE-0.8;timeout=12;peeraddr=10.0.0.1:37108
713 < +xMQXP8ElfNmuvEhsmcp+s2wCJOuQAsPxSg3d2Ewhs6gBnJz+ypVdWJ/wAVrXqlIJfLeVS/CBy4gEGkyWHSuVb1L
714
715 > hmac_md6_64_256;5ad913855742ae5a03a5aeb7eafa4c78629de136bed6acd73eea36c9e98df44a;json
716
717 < hmac_md6_64_256;84cd590976f794914c2ca26dac3a207a57a6798b9171289c114de07cf0c20401;json
718 < ["","AnyEvent::MP::_spawn","57Cs1CggVJjzYaQp13XXg4.c","AnyEvent::MP::Global::connect",0,"anon/57Cs1CggVJjzYaQp13XXg4"]
719 ...
720
721 The shared secret in use was C<8ugxrtw6H5tKnfPWfaSr4HGhE8MoJXmzTT1BWq7sLutNcD0IbXprQlZjIbl7MBKoeklG3IEfY9GlJthC0pENzk>.
722
723 =head2 SIMPLE HANDSHAKE FOR NON-PERL NODES
724
725 Implementing the full set of options for handshaking can be a daunting
726 task.
727
728 If security is not so important (because you only connect locally and
729 control the host, a common case), and you want to interface with an AEMP
730 node from another programming language, then you can also implement a
731 simplified handshake.
732
733 For example, in a simple implementation you could decide to simply not
734 check the authenticity of the other side and use cleartext authentication
735 yourself. The the handshake is as simple as sending three lines of text,
736 reading three lines of text, and then you can exchange JSON-formatted
737 messages:
738
739 aemp;1;<nodename>;hmac_sha3_512;json
740 <nonce>
741 cleartext;<hexencoded secret>;json
742
743 The nodename should be unique within the network, preferably unique with
744 every connection, the <nonce> could be empty or some random data, and the
745 hexencoded secret would be the shared secret, in lowercase hex (e.g. if
746 the secret is "geheim", the hex-encoded version would be "67656865696d").
747
748 Note that apart from the low-level handshake and framing protocol, there
749 is a high-level protocol, e.g. for monitoring, building the mesh or
750 spawning. All these messages are sent to the node port (the empty string)
751 and can safely be ignored if you do not need the relevant functionality.
752
753 =head3 USEFUL HINTS
754
755 Since taking part in the global protocol to find port groups is
756 nontrivial, hardcoding port names should be considered as well, i.e. the
757 non-Perl node could simply listen to messages for a few well-known ports.
758
759 Alternatively, the non-Perl node could call a (already loaded) function
760 in the Perl node by sending it a special message:
761
762 ["", "Some::Function::name", "myownport", 1, 2, 3]
763
764 This would call the function C<Some::Function::name> with the string
765 C<myownport> and some additional arguments.
766
767 =head2 MONITORING
768
769 Monitoring the connection itself is transport-specific. For TCP, all
770 connection monitoring is currently left to TCP retransmit time-outs
771 on a busy link, and TCP keepalive (which should be enabled) for idle
772 connections.
773
774 This is not sufficient for listener-less nodes, however: they need
775 to regularly send data (30 seconds, or the monitoring interval, is
776 recommended), so TCP actively probes.
777
778 Future implementations of AnyEvent::MP::Transport might query the kernel TCP
779 buffer after a write timeout occurs, and if it is non-empty, shut down the
780 connections, but this is an area of future research :)
781
782 =head2 NODE PROTOCOL
783
784 The transport simply transfers messages, but to implement a full node, a
785 special node port must exist that understands a number of requests.
786
787 If you are interested in implementing this, drop us a note so we finish
788 the documentation.
789
790 =head1 SEE ALSO
791
792 L<AnyEvent::MP>.
793
794 =head1 AUTHOR
795
796 Marc Lehmann <schmorp@schmorp.de>
797 http://home.schmorp.de/
798
799 =cut
800
801 1
802