-
Notifications
You must be signed in to change notification settings - Fork 34
Refactor DHT node #25
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
src/toxcore/dht_new/client.rs
Outdated
| /// relay NatPingRequest/NatPingResponse to target peer | ||
| pub fn relay_nat_ping_packet(&self, addr: &SocketAddr, request: DhtRequest) -> IoFuture<()> { | ||
| let packet = DhtPacket::DhtRequest(request); | ||
| Box::new(self.tx.clone() // clone tx sender for 1 send only |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Create method send_to as method send but with explicit addr-argument. Method send should use send_to inside it passing self.addr as addr.
examples/dht_node_new.rs
Outdated
| // Create a channel for this peer | ||
| let (tx, rx) = mpsc::unbounded(); | ||
| // Add or update an entry for this `Peer` in the connected client hashmap. | ||
| let client = node.borrow_mut().add_client(&addr, &packet, tx); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
replace tx with tx_sink_c. You don't need to create let (tx, rx) = mpsc::unbounded();, pass tx into add_client, create let writer = rx future. Just use tx_sink_c.
examples/dht_node_new.rs
Outdated
| .build() | ||
| ; | ||
|
|
||
| let relay = rx_sink |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rename relay -> writer
Pull Request Test Coverage Report for Build 388
💛 - Coveralls |
src/toxcore/dht_new/dht_node.rs
Outdated
| } | ||
|
|
||
| /// add new client entry in connected_clients hashmap | ||
| pub fn add_client(&mut self, addr: &SocketAddr, packet: &Option<DhtPacket>, tx: Tx) -> Client { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you actually need to add client? To create it? It worth to keep clients in tcp server, because TCP connection is stateful and we actually need to keep tx for each client to send the data into appropriate TCP connection linked to this client. On the other hand, we do have 1 UDP connection and we send data through it with the only one difference: addr arg.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch.
I was missing it.
UDP connection doesn't need to be saved.
src/toxcore/dht_new/dht_node.rs
Outdated
| } | ||
| client.clone() | ||
| } else { | ||
| let precomputed_key = encrypt_precompute(&pk, &self.sk); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Calling encrypt_precompute only once is a good performance optimization, but do we really need this optimization for now? We may do this optimization next PR
examples/dht_node_new.rs
Outdated
| // Add or update an entry for this `Peer` in the connected client hashmap. | ||
| let client = node.borrow_mut().add_client(&addr, &packet, tx); | ||
|
|
||
| let _ = node.borrow_mut().handle_packet(&(addr, packet.unwrap()), client); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you pass &(addr, packet) by ref? Try to pass values by value.
src/toxcore/dht_new/mod.rs
Outdated
| pub mod kbucket; | ||
| pub mod packed_node; | ||
| pub mod codec; | ||
| pub mod dht_node; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it have to be named as dht_node while the next line is client? Shouldn't it be server?
src/toxcore/dht_new/client.rs
Outdated
| /// socket address of peer | ||
| pub addr: SocketAddr, | ||
| /// tx split of channel to send packet to this peer via udp socket | ||
| pub tx: Tx, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would say the server struct should store tx but not the client since it's shared between all clients. And the same for send/send_to methods.
src/toxcore/dht_new/server.rs
Outdated
| if let DhtRequestPayload::NatPingResponse(nat_ping_resp_payload) = packet.get_payload(&alice.sk).unwrap() { | ||
| assert_eq!(nat_ping_resp_payload.id, nat_req.id); | ||
| } else { | ||
| panic!("can not occur"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unreachable! :)
src/toxcore/dht_new/server.rs
Outdated
| DhtPacket::NodesRequest(nodes_request) => nodes_request.pk, | ||
| DhtPacket::NodesResponse(nodes_response) => nodes_response.pk, | ||
| DhtPacket::DhtRequest(dht_request) => dht_request.spk, | ||
| _ => unreachable!("Received packet is not a DhtPacket"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually it's not unreachable because it depends on how this method is called, so panic is preferable in such cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But why we can't just get pk when we need it from the packet directly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But why we can't just get pk when we need it from the packet directly?
How?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It means that we should get it only after matching on packet kind but not before. So we can try to move the client inside the server and get exact client by pk from packet in each handle_* method if we need it. Not sure how exact it will look like though, but perhaps it worth to try.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good Idea.
But I would like to try this idea on next PR.:)
examples/dht_node_new.rs
Outdated
| let handler = stream.for_each(move |(addr, packet)| { | ||
| let tx_c = tx.clone(); | ||
| let pk = Server::get_pk(&packet.clone().unwrap()); | ||
| let client = node.borrow_mut().create_client(&addr, pk, tx_c); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems to me that server should take only packet and maybe socket address but not the whole client. It should manage clients inside so the user of server api wouldn't even know about it.
src/toxcore/dht_new/server.rs
Outdated
| } | ||
|
|
||
| #[cfg(test)] | ||
| mod test { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mod tests
| } | ||
| } | ||
|
|
||
| // handle_ping_resp() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You forgot to mark this function as #[test]
src/toxcore/dht_new/client.rs
Outdated
| pk: pk, | ||
| addr: addr, | ||
| precomputed_key: precomputed_key, | ||
| ping_id: 0xFFFFFFFFFFFFFFFF, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why oxfff?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because, can't set ping_id of Client to desired value.
So, can't check in test code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But why did you chose such a value? Why not 0?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As you can see at https://github.com/NamsooCho/tox-1/blob/7293bfb67bfd02087f4463a438c2a64fcf01df1a/src/toxcore/dht_new/server.rs#L217-L223
0 is checked
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From implementing perspective, Client is useful for containing Tx(mpsc), SocketAddr, pk, ping_id,...
Current kbucket contains only SocektAddr, PublicKey.
Maybe It is better to extend kbucket.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From implementing perspective, Client is useful for containing Tx(mpsc), SocketAddr, pk, ping_id,...
And why does it contain ping_id? It's useless if you have new client for every packet.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it!!
Thanks for your comments.
I will try to remove Client struct.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No problem. It's not necessary have to be removed though. Just perhaps if it contains few fields we can just pass them as args.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good job, guys. @NamsooCho And please, don't init ping_id with 0xffff
src/toxcore/dht_new/client.rs
Outdated
| let nat_res = NatPingResponse { id: random_u64() }; | ||
| let nat_payload = DhtRequestPayload::NatPingResponse(nat_res); | ||
| let dht_req = DhtRequest::new(&client.precomputed_key, &client.pk, &client.pk, nat_payload.clone()); | ||
| client.relay_nat_ping_packet(tx, &client.addr, dht_req).wait().unwrap(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why relay_nat_ping_packet?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is used both for nat_ping_request/response.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still do not understand why you used relay word here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if the rpk is not same as this DHT node, it relay to proper DHT node.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
resend?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
send?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok
src/toxcore/dht_new/server.rs
Outdated
| Function to handle incoming packets. If there is a response packet, | ||
| send back it to the peer. | ||
| */ | ||
| pub fn handle_packet(&mut self, packet: DhtUdpPacket) -> IoFuture<()> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A DhtUdpPacket is a tuple of (packet, addr). Please destructure it right in arg, so there will be no packet.1 or packet.0 calls.
src/toxcore/dht_new/server.rs
Outdated
| "Crypto initialization failed.")); | ||
| } | ||
|
|
||
| let (pk, sk) = gen_keypair(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You have to get this info via args, because we want to start a node with the given keypair.
src/toxcore/dht_new/server.rs
Outdated
| pub fn handle_packet(&mut self, packet: DhtUdpPacket) -> IoFuture<()> | ||
| { | ||
| let pk = Server::get_pk(&packet.1.clone()); | ||
| let client = self.create_client(&packet.0, pk); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have a look at #33 . You logic is incorrect for BootstrapInfo packet
src/toxcore/dht_new/server.rs
Outdated
| }, | ||
| DhtPacket::PingResponse(packet) => { | ||
| debug!("Received ping response"); | ||
| let client = self.get_client(&packet.pk); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is not 100% for sure the client will be in cache
src/toxcore/dht_new/server.rs
Outdated
| }, | ||
| DhtPacket::NodesResponse(packet) => { | ||
| debug!("Received NodesResponse"); | ||
| let client = self.get_client(&packet.pk); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is not 100% for sure the client will be in cache
src/toxcore/dht_new/server.rs
Outdated
| }, | ||
| Ok(DhtRequestPayload::NatPingResponse(pl)) => { | ||
| debug!("Received nat ping response"); | ||
| let client = self.get_client(&dr.spk); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is not 100% for sure the client will be in cache
| Client::new(precomputed_key, pk, addr.clone(), self.tx.clone()) | ||
| } | ||
| /// get client from cache | ||
| pub fn get_client(&self, pk: &PublicKey) -> Option<Client> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
create_client const you almost zero CPU. Please, don't precache clients for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
send PingRequest to peer A with ping_id = 0x01.
send PingRequest to peer B with ping_id = 0x02.
received PingResponse from peer B -> handle_packet() need client.
src/toxcore/dht_new/client.rs
Outdated
|
|
||
|
|
||
| /*! | ||
| Hold peer info. connected. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wtf
kpp
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Approve for now. There is a lot of TODOs, but the seems like a good start
No description provided.