diff options
-rw-r--r-- | toxcore/DHT.c | 205 |
1 files changed, 82 insertions, 123 deletions
diff --git a/toxcore/DHT.c b/toxcore/DHT.c index 2a5b03a4..8557a5e0 100644 --- a/toxcore/DHT.c +++ b/toxcore/DHT.c | |||
@@ -193,137 +193,96 @@ static int friend_number(DHT *dht, uint8_t *client_id) | |||
193 | return -1; | 193 | return -1; |
194 | } | 194 | } |
195 | 195 | ||
196 | /* Find MAX_SENT_NODES nodes closest to the client_id for the send nodes request: | 196 | /* |
197 | * put them in the nodes_list and return how many were found. | 197 | * helper for get_close_nodes(). argument list is a monster :D |
198 | * | ||
199 | * TODO: For the love of based Allah make this function cleaner and much more efficient. | ||
200 | */ | 198 | */ |
201 | static int get_close_nodes(DHT *dht, uint8_t *client_id, Node_format *nodes_list, sa_family_t sa_family) | 199 | static int get_close_nodes_inner(DHT *dht, uint8_t *client_id, Node_format *nodes_list, |
200 | sa_family_t sa_family, Client_data *client_list, uint32_t client_list_length, | ||
201 | time_t timestamp, int *num_nodes_ptr) | ||
202 | { | 202 | { |
203 | uint32_t i, j, k; | 203 | int num_nodes = 0; |
204 | uint64_t temp_time = unix_time(); | 204 | int i, tout, inlist, ipv46x, j, closest; |
205 | int num_nodes = 0, closest, tout, inlist, ipv46x; | 205 | for(i = 0; i < client_list_length; i++) { |
206 | 206 | Client_data *client = &client_list[i]; | |
207 | for (i = 0; i < LCLIENT_LIST; ++i) { | 207 | tout = is_timeout(timestamp, client->timestamp, BAD_NODE_TIMEOUT); |
208 | tout = is_timeout(temp_time, dht->close_clientlist[i].timestamp, BAD_NODE_TIMEOUT); | 208 | inlist = client_in_nodelist(nodes_list, MAX_SENT_NODES, client->client_id); |
209 | inlist = client_in_nodelist(nodes_list, MAX_SENT_NODES, dht->close_clientlist[i].client_id); | ||
210 | |||
211 | /* | ||
212 | * NET_PACKET_SEND_NODES sends ONLY AF_INET | ||
213 | * NET_PACKET_SEND_NODES_EX sends ALL BUT AF_INET (i.e. AF_INET6), | ||
214 | * it could send both, but then a) packet size is an issue and | ||
215 | * b) duplicates the traffic (NET_PACKET_SEND_NODES has to be | ||
216 | * sent anyways for backwards compatibility) | ||
217 | * we COULD send ALL as NET_PACKET_SEND_NODES_EX if we KNEW that the | ||
218 | * partner node understands - that's true if *they* are on IPv6 | ||
219 | * | ||
220 | * Careful: AF_INET isn't seen as AF_INET on dual-stack sockets for | ||
221 | * our connections, instead we have to look if it is an embedded | ||
222 | * IPv4-in-IPv6 here and convert it down in sendnodes(). | ||
223 | */ | ||
224 | #ifdef TOX_ENABLE_IPV6 | ||
225 | IP *client_ip = &dht->close_clientlist[i].ip_port.ip; | ||
226 | sa_family_t ip_treat_as_family = client_ip->family; | ||
227 | if ((dht->c->lossless_udp->net->family == AF_INET6) && | ||
228 | (client_ip->family == AF_INET6)) { | ||
229 | /* socket is AF_INET6, address claims AF_INET6: | ||
230 | * check for embedded IPv4-in-IPv6 */ | ||
231 | if (IN6_IS_ADDR_V4MAPPED(&client_ip->ip6)) | ||
232 | ip_treat_as_family = AF_INET; | ||
233 | } | ||
234 | |||
235 | ipv46x = !(sa_family == ip_treat_as_family); | ||
236 | #else | ||
237 | ipv46x = !(sa_family == AF_INET); | ||
238 | #endif | ||
239 | |||
240 | /* If node isn't good or is already in list. */ | ||
241 | if (tout || inlist || ipv46x) | ||
242 | continue; | ||
243 | |||
244 | if (num_nodes < MAX_SENT_NODES) { | ||
245 | |||
246 | memcpy( nodes_list[num_nodes].client_id, | ||
247 | dht->close_clientlist[i].client_id, | ||
248 | CLIENT_ID_SIZE ); | ||
249 | |||
250 | nodes_list[num_nodes].ip_port = dht->close_clientlist[i].ip_port; | ||
251 | num_nodes++; | ||
252 | |||
253 | } else { | ||
254 | |||
255 | for (j = 0; j < MAX_SENT_NODES; ++j) { | ||
256 | closest = id_closest( client_id, | ||
257 | nodes_list[j].client_id, | ||
258 | dht->close_clientlist[i].client_id ); | ||
259 | |||
260 | if (closest == 2) { | ||
261 | memcpy( nodes_list[j].client_id, | ||
262 | dht->close_clientlist[i].client_id, | ||
263 | CLIENT_ID_SIZE); | ||
264 | |||
265 | nodes_list[j].ip_port = dht->close_clientlist[i].ip_port; | ||
266 | break; | ||
267 | } | ||
268 | } | ||
269 | } | ||
270 | } | ||
271 | |||
272 | for (i = 0; i < dht->num_friends; ++i) { | ||
273 | for (j = 0; j < MAX_FRIEND_CLIENTS; ++j) { | ||
274 | |||
275 | tout = is_timeout(temp_time, dht->friends_list[i].client_list[j].timestamp, BAD_NODE_TIMEOUT); | ||
276 | inlist = client_in_nodelist( nodes_list, | ||
277 | MAX_SENT_NODES, | ||
278 | dht->friends_list[i].client_list[j].client_id); | ||
279 | 209 | ||
280 | #ifdef TOX_ENABLE_IPV6 | 210 | #ifdef TOX_ENABLE_IPV6 |
281 | IP *client_ip = &dht->friends_list[i].client_list[j].ip_port.ip; | 211 | IP *client_ip = &client->ip_port.ip; |
282 | sa_family_t ip_treat_as_family = client_ip->family; | 212 | |
283 | if ((dht->c->lossless_udp->net->family == AF_INET6) && | 213 | /* |
284 | (client_ip->family == AF_INET6)) { | 214 | * Careful: AF_INET isn't seen as AF_INET on dual-stack sockets for |
285 | /* socket is AF_INET6, address claims AF_INET6: | 215 | * our connections, instead we have to look if it is an embedded |
286 | * check for embedded IPv4-in-IPv6 */ | 216 | * IPv4-in-IPv6 here and convert it down in sendnodes(). |
287 | if (IN6_IS_ADDR_V4MAPPED(&client_ip->ip6)) | 217 | */ |
288 | ip_treat_as_family = AF_INET; | 218 | sa_family_t ip_treat_as_family = client_ip->family; |
289 | } | 219 | if ((dht->c->lossless_udp->net->family == AF_INET6) && |
290 | 220 | (client_ip->family == AF_INET6)) { | |
291 | ipv46x = !(sa_family == ip_treat_as_family); | 221 | /* socket is AF_INET6, address claims AF_INET6: |
222 | * check for embedded IPv4-in-IPv6 */ | ||
223 | if (IN6_IS_ADDR_V4MAPPED(&client_ip->ip6)) | ||
224 | ip_treat_as_family = AF_INET; | ||
225 | } | ||
226 | |||
227 | ipv46x = !(sa_family == ip_treat_as_family); | ||
292 | #else | 228 | #else |
293 | ipv46x = sa_family != AF_INET; | 229 | ipv46x = !(sa_family == AF_INET); |
294 | #endif | 230 | #endif |
295 | 231 | ||
296 | /* If node isn't good or is already in list. */ | 232 | /* If node isn't good or is already in list. */ |
297 | if (tout || inlist || ipv46x) | 233 | if (tout || inlist || ipv46x) |
298 | continue; | 234 | continue; |
299 | 235 | ||
300 | if (num_nodes < MAX_SENT_NODES) { | 236 | if (num_nodes < MAX_SENT_NODES) { |
301 | 237 | memcpy(nodes_list[num_nodes].client_id, | |
302 | memcpy( nodes_list[num_nodes].client_id, | 238 | client->client_id, |
303 | dht->friends_list[i].client_list[j].client_id, | 239 | CLIENT_ID_SIZE ); |
304 | CLIENT_ID_SIZE); | 240 | |
305 | 241 | nodes_list[num_nodes].ip_port = client->ip_port; | |
306 | nodes_list[num_nodes].ip_port = dht->friends_list[i].client_list[j].ip_port; | 242 | num_nodes++; |
307 | num_nodes++; | 243 | } else { |
308 | } else { | 244 | /* see if node_list contains a client_id that's "further away" |
309 | for (k = 0; k < MAX_SENT_NODES; ++k) { | 245 | * compared to the one we're looking at at the moment, if there |
310 | 246 | * is, replace it | |
311 | closest = id_closest( client_id, | 247 | */ |
312 | nodes_list[k].client_id, | 248 | for (j = 0; j < MAX_SENT_NODES; ++j) { |
313 | dht->friends_list[i].client_list[j].client_id ); | 249 | closest = id_closest( client_id, |
314 | 250 | nodes_list[j].client_id, | |
315 | if (closest == 2) { | 251 | client->client_id ); |
316 | memcpy( nodes_list[k].client_id, | 252 | |
317 | dht->friends_list[i].client_list[j].client_id, | 253 | /* second client_id is closer than current: change to it */ |
318 | CLIENT_ID_SIZE ); | 254 | if (closest == 2) { |
255 | memcpy( nodes_list[j].client_id, | ||
256 | client->client_id, | ||
257 | CLIENT_ID_SIZE); | ||
258 | |||
259 | nodes_list[j].ip_port = client->ip_port; | ||
260 | break; | ||
261 | } | ||
262 | } | ||
263 | } | ||
264 | } | ||
265 | |||
266 | *num_nodes_ptr = num_nodes; | ||
267 | } | ||
319 | 268 | ||
320 | nodes_list[k].ip_port = dht->friends_list[i].client_list[j].ip_port; | 269 | /* Find MAX_SENT_NODES nodes closest to the client_id for the send nodes request: |
321 | break; | 270 | * put them in the nodes_list and return how many were found. |
322 | } | 271 | * |
323 | } | 272 | * TODO: For the love of based <your favorite deity, in doubt use "love"> make |
324 | } | 273 | * this function cleaner and much more efficient. |
325 | } | 274 | */ |
326 | } | 275 | static int get_close_nodes(DHT *dht, uint8_t *client_id, Node_format *nodes_list, sa_family_t sa_family) |
276 | { | ||
277 | time_t timestamp = unix_time(); | ||
278 | int num_nodes = 0, i; | ||
279 | get_close_nodes_inner(dht, client_id, nodes_list, sa_family, | ||
280 | dht->close_clientlist, LCLIENT_LIST, timestamp, &num_nodes); | ||
281 | |||
282 | for (i = 0; i < dht->num_friends; ++i) | ||
283 | get_close_nodes_inner(dht, client_id, nodes_list, sa_family, | ||
284 | dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS, | ||
285 | timestamp, &num_nodes); | ||
327 | 286 | ||
328 | return num_nodes; | 287 | return num_nodes; |
329 | } | 288 | } |