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