Skip to content

Commit 629da50

Browse files
project updated
1 parent 6f8a859 commit 629da50

File tree

19 files changed

+595
-32
lines changed

19 files changed

+595
-32
lines changed

include/bitchat/helpers/protocol_helper.h

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,79 @@
11
#pragma once
22

3+
#include <chrono>
34
#include <cstdint>
5+
#include <map>
46
#include <string>
57
#include <vector>
68

79
namespace bitchat
810
{
911

12+
// Version negotiation state enum
13+
enum class VersionNegotiationState
14+
{
15+
NotStarted,
16+
HelloSent,
17+
AckReceived,
18+
Failed
19+
};
20+
21+
// Version hello structure
22+
struct VersionHello
23+
{
24+
std::vector<uint8_t> supportedVersions;
25+
uint8_t preferredVersion;
26+
std::string clientVersion;
27+
std::string platform;
28+
std::vector<std::string> capabilities;
29+
30+
VersionHello() = default;
31+
VersionHello(const std::vector<uint8_t> &versions, uint8_t preferred, const std::string &version, const std::string &plat)
32+
: supportedVersions(versions)
33+
, preferredVersion(preferred)
34+
, clientVersion(version)
35+
, platform(plat)
36+
{
37+
// Pass
38+
}
39+
};
40+
41+
// Version ack structure
42+
struct VersionAck
43+
{
44+
uint8_t agreedVersion;
45+
std::string serverVersion;
46+
std::string platform;
47+
bool rejected;
48+
std::string reason;
49+
50+
VersionAck()
51+
: agreedVersion(0)
52+
, rejected(false)
53+
{
54+
// Pass
55+
}
56+
57+
VersionAck(uint8_t version, const std::string &serverVer, const std::string &plat)
58+
: agreedVersion(version)
59+
, serverVersion(serverVer)
60+
, platform(plat)
61+
, rejected(false)
62+
{
63+
// Pass
64+
}
65+
66+
VersionAck(uint8_t version, const std::string &serverVer, const std::string &plat, bool reject, const std::string &rejectReason)
67+
: agreedVersion(version)
68+
, serverVersion(serverVer)
69+
, platform(plat)
70+
, rejected(reject)
71+
, reason(rejectReason)
72+
{
73+
// Pass
74+
}
75+
};
76+
1077
// Helper class for protocol-related helper functions
1178
class ProtocolHelper
1279
{
@@ -15,6 +82,10 @@ class ProtocolHelper
1582
static bool isValidChannelName(const std::string &channel);
1683
static bool isValidNickname(const std::string &nickname);
1784

85+
// Version negotiation helpers
86+
static uint8_t negotiateVersion(const std::vector<uint8_t> &clientVersions, const std::vector<uint8_t> &serverVersions);
87+
static std::vector<uint8_t> getSupportedVersions();
88+
1889
private:
1990
ProtocolHelper() = delete;
2091
};

include/bitchat/platform/bluetooth_interface.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ class IBluetoothNetwork
4040
// Send packet to specific peer
4141
virtual bool sendPacketToPeer(const BitchatPacket &packet, const std::string &peerID) = 0;
4242

43+
// Send packet to specific peripheral by peripheralID
44+
virtual bool sendPacketToPeripheral(const BitchatPacket &packet, const std::string &peripheralID) = 0;
45+
4346
// Check if Bluetooth is ready
4447
virtual bool isReady() const = 0;
4548

include/bitchat/protocol/packet_serializer.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@ class PacketSerializer
4343
// Parse version hello payload
4444
void parseVersionHelloPayload(const std::vector<uint8_t> &payload, std::vector<uint8_t> &supportedVersions, uint8_t &preferredVersion, std::string &clientVersion, std::string &platform, std::vector<std::string> &capabilities);
4545

46+
// Create version ack payload
47+
std::vector<uint8_t> makeVersionAckPayload(uint8_t agreedVersion, const std::string &serverVersion, const std::string &platform, bool rejected, const std::string &reason);
48+
49+
// Parse version ack payload
50+
void parseVersionAckPayload(const std::vector<uint8_t> &payload, uint8_t &agreedVersion, std::string &serverVersion, std::string &platform, bool &rejected, std::string &reason);
51+
4652
// Create packet with proper fields
4753
BitchatPacket makePacket(uint8_t type, const std::vector<uint8_t> &payload, bool hasRecipient, bool hasSignature, const std::string &senderID);
4854

include/bitchat/services/message_service.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#pragma once
22

33
#include "bitchat/core/bitchat_data.h"
4+
#include "bitchat/helpers/protocol_helper.h"
45
#include "bitchat/protocol/packet.h"
56
#include "bitchat/ui/ui_interface.h"
67
#include <functional>
@@ -65,6 +66,10 @@ class MessageService
6566
BitchatPacket createChannelAnnouncePacket(const std::string &channel, bool joining);
6667
BitchatPacket createVersionHelloPacket();
6768

69+
// Version negotiation
70+
void sendVersionHello(const std::string &peripheralID);
71+
void sendVersionAck(const VersionAck &ack, const std::string &peerID);
72+
6873
// Set callbacks for message events
6974
using MessageReceivedCallback = std::function<void(const BitchatMessage &)>;
7075
using ChannelJoinedCallback = std::function<void(const std::string &)>;
@@ -97,7 +102,13 @@ class MessageService
97102
PeerConnectedCallback peerConnectedCallback;
98103
PeerDisconnectedCallback peerDisconnectedCallback;
99104

100-
// Message-related packet processing
105+
// Version hello packet processing
106+
void processVersionHelloPacket(const BitchatPacket &packet);
107+
void processVersionAckPacket(const BitchatPacket &packet);
108+
void handleVersionHello(const std::string &peerID, const std::vector<uint8_t> &data);
109+
void handleVersionAck(const std::string &peerID, const std::vector<uint8_t> &data);
110+
111+
// Message packet processing
101112
void processMessagePacket(const BitchatPacket &packet);
102113
void processChannelAnnouncePacket(const BitchatPacket &packet);
103114

include/bitchat/services/network_service.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ class NetworkService
4343
// Send a packet to a specific peer
4444
bool sendPacketToPeer(const BitchatPacket &packet, const std::string &peerID);
4545

46+
// Send a packet to a specific peripheral
47+
bool sendPacketToPeripheral(const BitchatPacket &packet, const std::string &peripheralID);
48+
4649
// Set callbacks
4750
using PacketReceivedCallback = std::function<void(const BitchatPacket &, const std::string &)>;
4851
using PeerConnectedCallback = std::function<void(const std::string &)>;

include/platforms/apple/bluetooth.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
- (BOOL)sendPacket:(NSData *)packetData;
3737
- (BOOL)sendPacket:(NSData *)packetData toPeripheral:(CBPeripheral *)peripheral;
3838
- (BOOL)sendPacket:(NSData *)packetData toPeer:(NSString *)peerID;
39+
- (BOOL)sendPacket:(NSData *)packetData toPeripheralID:(NSString *)peripheralID;
3940

4041
// State
4142
- (BOOL)isReady;

include/platforms/apple/bluetooth_bridge.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,14 @@ class AppleBluetoothNetworkBridge : public bitchat::IBluetoothNetwork
8282
*/
8383
bool sendPacketToPeer(const BitchatPacket &packet, const std::string &peerID) override;
8484

85+
/**
86+
* @brief Send a packet to a specific peripheral by peripheralID
87+
* @param packet The packet to send
88+
* @param peripheralID The target peripheral's identifier
89+
* @return true if sent successfully, false otherwise
90+
*/
91+
bool sendPacketToPeripheral(const BitchatPacket &packet, const std::string &peripheralID) override;
92+
8593
/**
8694
* @brief Check if Bluetooth system is ready for operations
8795
* @return true if ready, false otherwise

include/platforms/linux/bluetooth.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ class LinuxBluetoothNetwork : public IBluetoothNetwork
2323
void stop() override;
2424
bool sendPacket(const BitchatPacket &packet) override;
2525
bool sendPacketToPeer(const BitchatPacket &packet, const std::string &peerID) override;
26+
bool sendPacketToPeripheral(const BitchatPacket &packet, const std::string &peripheralID) override;
2627
bool isReady() const override;
2728

2829
void setPeerConnectedCallback(PeerConnectedCallback callback) override;

src/bitchat/helpers/protocol_helper.cpp

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#include "bitchat/helpers/protocol_helper.h"
2+
#include "bitchat/core/constants.h"
23
#include <algorithm>
4+
#include <spdlog/spdlog.h>
35

46
namespace bitchat
57
{
@@ -34,19 +36,19 @@ bool ProtocolHelper::isValidChannelName(const std::string &channel)
3436
return false;
3537
}
3638

37-
// Check if the channel is too long
38-
if (channel.length() > 50)
39+
// Check if the channel starts with #
40+
if (channel[0] != '#')
3941
{
4042
return false;
4143
}
4244

43-
// Check if the channel starts with a #
44-
if (channel[0] != '#')
45+
// Check if the channel is too long (more than 50 characters)
46+
if (channel.length() > 50)
4547
{
4648
return false;
4749
}
4850

49-
// Check if it contains only alphanumeric characters and underscores
51+
// Check if it contains only alphanumeric characters, underscores, and hyphens after the #
5052
// clang-format off
5153
return std::all_of(channel.begin() + 1, channel.end(), [](char c) {
5254
return std::isalnum(c) || c == '_' || c == '-';
@@ -56,14 +58,8 @@ bool ProtocolHelper::isValidChannelName(const std::string &channel)
5658

5759
bool ProtocolHelper::isValidNickname(const std::string &nickname)
5860
{
59-
// Check if the nickname is empty
60-
if (nickname.empty())
61-
{
62-
return false;
63-
}
64-
65-
// Check if the nickname is too long
66-
if (nickname.length() > 32)
61+
// Nickname should not be empty and should be reasonable length
62+
if (nickname.empty() || nickname.length() > 32)
6763
{
6864
return false;
6965
}
@@ -76,4 +72,25 @@ bool ProtocolHelper::isValidNickname(const std::string &nickname)
7672
// clang-format on
7773
}
7874

75+
uint8_t ProtocolHelper::negotiateVersion(const std::vector<uint8_t> &clientVersions, const std::vector<uint8_t> &serverVersions)
76+
{
77+
// Find the highest common version between client and server
78+
for (auto it = clientVersions.rbegin(); it != clientVersions.rend(); ++it)
79+
{
80+
if (std::find(serverVersions.begin(), serverVersions.end(), *it) != serverVersions.end())
81+
{
82+
return *it;
83+
}
84+
}
85+
86+
// No compatible version found
87+
return 0;
88+
}
89+
90+
std::vector<uint8_t> ProtocolHelper::getSupportedVersions()
91+
{
92+
// Currently only support version 1
93+
return {1};
94+
}
95+
7996
} // namespace bitchat

src/bitchat/protocol/packet_serializer.cpp

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -758,4 +758,120 @@ void PacketSerializer::parseVersionHelloPayload(const std::vector<uint8_t> &payl
758758
}
759759
}
760760

761+
std::vector<uint8_t> PacketSerializer::makeVersionAckPayload(uint8_t agreedVersion, const std::string &serverVersion, const std::string &platform, bool rejected, const std::string &reason)
762+
{
763+
std::vector<uint8_t> data;
764+
765+
// Flags byte: bit 0 = rejected, bit 1 = hasReason
766+
uint8_t flags = 0;
767+
if (rejected)
768+
{
769+
flags |= 0x01;
770+
}
771+
if (!reason.empty())
772+
{
773+
flags |= 0x02;
774+
}
775+
writeUint8(data, flags);
776+
777+
// Agreed version
778+
writeUint8(data, agreedVersion);
779+
780+
// Server version (string with length prefix)
781+
writeUint8(data, static_cast<uint8_t>(std::min(static_cast<size_t>(255), serverVersion.length())));
782+
data.insert(data.end(), serverVersion.begin(), serverVersion.begin() + std::min(static_cast<size_t>(255), serverVersion.length()));
783+
784+
// Platform (string with length prefix)
785+
writeUint8(data, static_cast<uint8_t>(std::min(static_cast<size_t>(255), platform.length())));
786+
data.insert(data.end(), platform.begin(), platform.begin() + std::min(static_cast<size_t>(255), platform.length()));
787+
788+
// Reason (if present)
789+
if (!reason.empty())
790+
{
791+
writeUint8(data, static_cast<uint8_t>(std::min(static_cast<size_t>(255), reason.length())));
792+
data.insert(data.end(), reason.begin(), reason.begin() + std::min(static_cast<size_t>(255), reason.length()));
793+
}
794+
795+
return data;
796+
}
797+
798+
void PacketSerializer::parseVersionAckPayload(const std::vector<uint8_t> &payload, uint8_t &agreedVersion, std::string &serverVersion, std::string &platform, bool &rejected, std::string &reason)
799+
{
800+
// Minimum size check: flags(1) + agreedVersion(1) + min strings
801+
if (payload.size() < 3)
802+
{
803+
spdlog::error("Version ack payload too short");
804+
return;
805+
}
806+
807+
size_t offset = 0;
808+
809+
// Flags byte
810+
uint8_t flags = readUint8(payload, offset);
811+
rejected = (flags & 0x01) != 0;
812+
bool hasReason = (flags & 0x02) != 0;
813+
814+
// Agreed version
815+
if (offset >= payload.size())
816+
{
817+
spdlog::error("Version ack payload buffer overflow reading agreed version");
818+
return;
819+
}
820+
agreedVersion = readUint8(payload, offset);
821+
822+
// Server version (string with length prefix)
823+
if (offset >= payload.size())
824+
{
825+
spdlog::error("Version ack payload buffer overflow reading server version length");
826+
return;
827+
}
828+
uint8_t serverVersionLen = readUint8(payload, offset);
829+
830+
if (offset + serverVersionLen > payload.size())
831+
{
832+
spdlog::error("Version ack payload buffer overflow reading server version");
833+
return;
834+
}
835+
836+
serverVersion = std::string(payload.begin() + offset, payload.begin() + offset + serverVersionLen);
837+
offset += serverVersionLen;
838+
839+
// Platform (string with length prefix)
840+
if (offset >= payload.size())
841+
{
842+
spdlog::error("Version ack payload buffer overflow reading platform length");
843+
return;
844+
}
845+
uint8_t platformLen = readUint8(payload, offset);
846+
847+
if (offset + platformLen > payload.size())
848+
{
849+
spdlog::error("Version ack payload buffer overflow reading platform");
850+
return;
851+
}
852+
853+
platform = std::string(payload.begin() + offset, payload.begin() + offset + platformLen);
854+
offset += platformLen;
855+
856+
// Reason (if present)
857+
reason.clear();
858+
if (hasReason)
859+
{
860+
if (offset >= payload.size())
861+
{
862+
spdlog::error("Version ack payload buffer overflow reading reason length");
863+
return;
864+
}
865+
uint8_t reasonLen = readUint8(payload, offset);
866+
867+
if (offset + reasonLen > payload.size())
868+
{
869+
spdlog::error("Version ack payload buffer overflow reading reason");
870+
return;
871+
}
872+
873+
reason = std::string(payload.begin() + offset, payload.begin() + offset + reasonLen);
874+
}
875+
}
876+
761877
} // namespace bitchat

0 commit comments

Comments
 (0)