|
37 | 37 | #include <vix/p2p/messages/Hello.hpp> |
38 | 38 | #include <vix/p2p/messages/Ping.hpp> |
39 | 39 | #include <vix/p2p/messages/Pong.hpp> |
| 40 | +#include <vix/p2p/messages/HelloAck.hpp> |
| 41 | +#include <vix/p2p/messages/HelloFinish.hpp> |
40 | 42 |
|
41 | 43 | #include <vix/p2p/transport/Tcp.hpp> |
42 | 44 | #include <vix/p2p/Bootstrap.hpp> |
@@ -428,7 +430,6 @@ namespace vix::p2p |
428 | 430 | } |
429 | 431 |
|
430 | 432 | schedule_handshake_timeout_(pid); |
431 | | - send_hello(pid); |
432 | 433 | } |
433 | 434 |
|
434 | 435 | bool has_peer_by_endpoint_unlocked_(const PeerEndpoint &ep) const |
@@ -521,71 +522,107 @@ namespace vix::p2p |
521 | 522 |
|
522 | 523 | void on_hello(const PeerId &peer_id, const msg::Hello &h) |
523 | 524 | { |
524 | | - std::scoped_lock lk(mu_); |
| 525 | + Envelope out_env; |
| 526 | + |
| 527 | + { |
| 528 | + std::scoped_lock lk(mu_); |
| 529 | + |
| 530 | + auto &peer = peers_[peer_id]; |
| 531 | + |
| 532 | + auto now_ms = now_ms_(); |
| 533 | + if (std::llabs((long long)now_ms - (long long)h.ts_ms) > 60'000) |
| 534 | + throw std::runtime_error("hello replay"); |
525 | 535 |
|
526 | | - auto &peer = peers_[peer_id]; |
| 536 | + peer.handshake.emplace(); |
| 537 | + peer.handshake->stage = HandshakeState::Stage::HelloReceived; |
| 538 | + peer.handshake->nonce_a = h.nonce_a; |
| 539 | + peer.handshake->ts_ms = h.ts_ms; |
| 540 | + peer.handshake->started_at = std::chrono::steady_clock::now(); |
527 | 541 |
|
528 | | - auto now_ms = now_ms_(); |
529 | | - if (std::llabs((long long)now_ms - (long long)h.ts_ms) > 60'000) |
530 | | - throw std::runtime_error("hello replay"); |
| 542 | + peer.meta.public_key = h.public_key; |
531 | 543 |
|
532 | | - peer.handshake.emplace(); |
533 | | - peer.handshake->stage = HandshakeState::Stage::HelloReceived; |
534 | | - peer.handshake->nonce_a = h.nonce_a; |
535 | | - peer.handshake->ts_ms = h.ts_ms; |
536 | | - peer.handshake->started_at = std::chrono::steady_clock::now(); |
537 | | - peer.meta.public_key = h.public_key; |
| 544 | + constexpr std::size_t kMinPubKey = 16; |
| 545 | + constexpr std::size_t kMaxPubKey = 2048; |
| 546 | + if (peer.meta.public_key.size() < kMinPubKey || peer.meta.public_key.size() > kMaxPubKey) |
| 547 | + throw std::runtime_error("bad public_key size"); |
538 | 548 |
|
539 | | - constexpr std::size_t kMinPubKey = 16; |
540 | | - constexpr std::size_t kMaxPubKey = 2048; |
| 549 | + msg::HelloAck ack; |
| 550 | + ack.nonce_a = h.nonce_a; |
| 551 | + ack.nonce_b = rand_u64_(); |
541 | 552 |
|
542 | | - if (peer.meta.public_key.size() < kMinPubKey || peer.meta.public_key.size() > kMaxPubKey) |
543 | | - throw std::runtime_error("bad public_key size"); |
| 553 | + ack.public_key = self_keys_.public_key; |
544 | 554 |
|
545 | | - msg::HelloAck ack; |
546 | | - ack.nonce_a = h.nonce_a; |
547 | | - ack.nonce_b = rand_u64_(); |
548 | | - peer.handshake->nonce_b = ack.nonce_b; |
549 | | - peer.handshake->stage = HandshakeState::Stage::AckSent; |
550 | | - send_envelope(peer_id, pack::make_envelope(MessageType::HelloAck, ack)); |
| 555 | + peer.handshake->nonce_b = ack.nonce_b; |
| 556 | + peer.handshake->stage = HandshakeState::Stage::AckSent; |
| 557 | + |
| 558 | + out_env = pack::make_envelope(MessageType::HelloAck, ack); |
| 559 | + } |
| 560 | + |
| 561 | + // ✅ send OUTSIDE the lock (avoid deadlock) |
| 562 | + send_envelope(peer_id, out_env); |
551 | 563 | } |
552 | 564 |
|
553 | 565 | void on_hello_ack(const PeerId &peer_id, const msg::HelloAck &a) |
554 | 566 | { |
555 | | - std::scoped_lock lk(mu_); |
| 567 | + Envelope out_env; |
556 | 568 |
|
557 | | - auto &peer = peers_[peer_id]; |
| 569 | + { |
| 570 | + std::scoped_lock lk(mu_); |
558 | 571 |
|
559 | | - if (!peer.handshake) |
560 | | - throw std::runtime_error("missing handshake state"); |
| 572 | + auto &peer = peers_[peer_id]; |
561 | 573 |
|
562 | | - auto &hs = *peer.handshake; |
| 574 | + if (!peer.handshake) |
| 575 | + throw std::runtime_error("missing handshake state"); |
563 | 576 |
|
564 | | - if (hs.ts_ms == 0) |
565 | | - throw std::runtime_error("hs missing ts_ms"); |
| 577 | + auto &hs = *peer.handshake; |
566 | 578 |
|
567 | | - if (hs.stage != HandshakeState::Stage::HelloSent) |
568 | | - throw std::runtime_error("unexpected HelloAck"); |
| 579 | + if (hs.ts_ms == 0) |
| 580 | + throw std::runtime_error("hs missing ts_ms"); |
569 | 581 |
|
570 | | - if (a.nonce_a != hs.nonce_a) |
571 | | - throw std::runtime_error("nonce mismatch"); |
| 582 | + if (hs.stage != HandshakeState::Stage::HelloSent) |
| 583 | + throw std::runtime_error("unexpected HelloAck"); |
572 | 584 |
|
573 | | - hs.nonce_b = a.nonce_b; |
574 | | - hs.stage = HandshakeState::Stage::AckReceived; |
| 585 | + if (a.nonce_a != hs.nonce_a) |
| 586 | + throw std::runtime_error("nonce mismatch"); |
575 | 587 |
|
576 | | - auto data = make_handshake_bytes_( |
577 | | - hs.nonce_a, |
578 | | - hs.nonce_b, |
579 | | - hs.ts_ms, |
580 | | - kProto_.major, |
581 | | - kProto_.minor, |
582 | | - kTransport_()); |
| 588 | + peer.meta.public_key = a.public_key; |
| 589 | + |
| 590 | + constexpr std::size_t kMinPubKey = 16; |
| 591 | + constexpr std::size_t kMaxPubKey = 2048; |
| 592 | + if (peer.meta.public_key.size() < kMinPubKey || peer.meta.public_key.size() > kMaxPubKey) |
| 593 | + throw std::runtime_error("bad public_key size"); |
| 594 | + |
| 595 | + hs.nonce_b = a.nonce_b; |
| 596 | + hs.stage = HandshakeState::Stage::AckReceived; |
| 597 | + |
| 598 | + auto data = make_handshake_bytes_( |
| 599 | + hs.nonce_a, |
| 600 | + hs.nonce_b, |
| 601 | + hs.ts_ms, |
| 602 | + kProto_.major, |
| 603 | + kProto_.minor, |
| 604 | + kTransport_()); |
| 605 | + |
| 606 | + msg::HelloFinish fin; |
| 607 | + fin.nonce_a = hs.nonce_a; |
| 608 | + fin.nonce_b = hs.nonce_b; |
| 609 | + fin.signature = crypto_->sign(data, self_keys_.private_key); |
| 610 | + |
| 611 | + auto sk = derive_session_key_unlocked_(hs, peer.meta.public_key); |
| 612 | + |
| 613 | + peer.meta.session_key_32 = std::move(sk); |
| 614 | + peer.meta.secure = true; |
| 615 | + peer.meta.send_nonce_counter = 1; |
| 616 | + |
| 617 | + peer.state = PeerState::Connected; |
| 618 | + peer.handshake.reset(); |
| 619 | + stats_.handshakes_completed++; |
| 620 | + |
| 621 | + out_env = pack::make_envelope(MessageType::HelloFinish, fin); |
| 622 | + } |
583 | 623 |
|
584 | | - msg::HelloFinish fin; |
585 | | - fin.nonce_a = hs.nonce_a; |
586 | | - fin.nonce_b = hs.nonce_b; |
587 | | - fin.signature = crypto_->sign(data, self_keys_.private_key); |
588 | | - send_envelope(peer_id, pack::make_envelope(MessageType::HelloFinish, fin)); |
| 624 | + // ✅ send OUTSIDE lock |
| 625 | + send_envelope(peer_id, out_env); |
589 | 626 | } |
590 | 627 |
|
591 | 628 | void on_hello_finish(const PeerId &peer_id, const msg::HelloFinish &f) |
@@ -725,10 +762,18 @@ namespace vix::p2p |
725 | 762 | return; |
726 | 763 | } |
727 | 764 | } |
| 765 | + catch (const std::exception &e) |
| 766 | + { |
| 767 | + if (!running_) |
| 768 | + return; |
| 769 | + log_(std::string("[p2p] envelope error: ") + e.what() + " peer_id=" + peer_id); |
| 770 | + disconnect_impl_(peer_id); |
| 771 | + } |
728 | 772 | catch (...) |
729 | 773 | { |
730 | 774 | if (!running_) |
731 | 775 | return; |
| 776 | + log_(std::string("[p2p] envelope error: unknown exception peer_id=") + peer_id); |
732 | 777 | disconnect_impl_(peer_id); |
733 | 778 | } |
734 | 779 | } |
@@ -756,11 +801,15 @@ namespace vix::p2p |
756 | 801 | h.node_id = cfg_.node_id; |
757 | 802 | h.public_key = self_keys_.public_key; |
758 | 803 |
|
759 | | - peers_[peer_id].handshake.emplace(); |
760 | | - peers_[peer_id].handshake->nonce_a = h.nonce_a; |
761 | | - peers_[peer_id].handshake->ts_ms = h.ts_ms; |
762 | | - peers_[peer_id].handshake->stage = HandshakeState::Stage::HelloSent; |
763 | | - peers_[peer_id].handshake->started_at = std::chrono::steady_clock::now(); |
| 804 | + { |
| 805 | + std::scoped_lock lk(mu_); |
| 806 | + auto &p = peers_[peer_id]; |
| 807 | + p.handshake.emplace(); |
| 808 | + p.handshake->nonce_a = h.nonce_a; |
| 809 | + p.handshake->ts_ms = h.ts_ms; |
| 810 | + p.handshake->stage = HandshakeState::Stage::HelloSent; |
| 811 | + p.handshake->started_at = std::chrono::steady_clock::now(); |
| 812 | + } |
764 | 813 |
|
765 | 814 | send_envelope(peer_id, pack::make_envelope(MessageType::Hello, h)); |
766 | 815 | } |
@@ -946,6 +995,10 @@ namespace vix::p2p |
946 | 995 | transports_.erase(tit); |
947 | 996 |
|
948 | 997 | p.id = new_id; |
| 998 | + |
| 999 | + if (t) |
| 1000 | + t->set_peer_id(new_id); |
| 1001 | + |
949 | 1002 | peers_.emplace(new_id, std::move(p)); |
950 | 1003 | transports_.emplace(new_id, std::move(t)); |
951 | 1004 | } |
|
0 commit comments