summaryrefslogtreecommitdiff
path: root/toxcore/group.c
diff options
context:
space:
mode:
authorirungentoo <irungentoo@gmail.com>2014-10-01 15:28:27 -0400
committerirungentoo <irungentoo@gmail.com>2014-10-01 15:28:27 -0400
commite304fa847ed18605b13b68558bb88da151a28c1c (patch)
treeca4ec39b4e58afb87f6b82af285c20bad57a68d1 /toxcore/group.c
parent9dd62023f50a2b5f91a52a4f7c8602b549a28ae0 (diff)
Group chats now actually work somewhat.
Diffstat (limited to 'toxcore/group.c')
-rw-r--r--toxcore/group.c617
1 files changed, 533 insertions, 84 deletions
diff --git a/toxcore/group.c b/toxcore/group.c
index ce590015..d5364420 100644
--- a/toxcore/group.c
+++ b/toxcore/group.c
@@ -130,7 +130,7 @@ static Group_c *get_group_c(const Group_Chats *g_c, int groupnumber)
130} 130}
131 131
132/* 132/*
133 * check if peer with client_id is in peer array. 133 * check if peer with real_pk is in peer array.
134 * 134 *
135 * return peer index if peer is in chat. 135 * return peer index if peer is in chat.
136 * return -1 if peer is not in chat. 136 * return -1 if peer is not in chat.
@@ -138,12 +138,12 @@ static Group_c *get_group_c(const Group_Chats *g_c, int groupnumber)
138 * TODO: make this more efficient. 138 * TODO: make this more efficient.
139 */ 139 */
140 140
141static int peer_in_chat(const Group_c *chat, const uint8_t *client_id) 141static int peer_in_chat(const Group_c *chat, const uint8_t *real_pk)
142{ 142{
143 uint32_t i; 143 uint32_t i;
144 144
145 for (i = 0; i < chat->numpeers; ++i) 145 for (i = 0; i < chat->numpeers; ++i)
146 if (id_equal(chat->group[i].client_id, client_id)) 146 if (id_equal(chat->group[i].real_pk, real_pk))
147 return i; 147 return i;
148 148
149 return -1; 149 return -1;
@@ -176,7 +176,7 @@ static int get_group_num(const Group_Chats *g_c, const uint8_t *identifier)
176 * 176 *
177 * TODO: make this more efficient. 177 * TODO: make this more efficient.
178 */ 178 */
179int get_peer_index(Group_c *g, uint16_t peer_number) 179static int get_peer_index(Group_c *g, uint16_t peer_number)
180{ 180{
181 uint32_t i; 181 uint32_t i;
182 182
@@ -187,59 +187,274 @@ int get_peer_index(Group_c *g, uint16_t peer_number)
187 return -1; 187 return -1;
188} 188}
189 189
190
191static uint16_t calculate_comp_value(const uint8_t *pk1, const uint8_t *pk2)
192{
193 uint8_t cmp1, cmp2;
194
195 for (cmp1 = crypto_box_PUBLICKEYBYTES; cmp1 != 0; --cmp1) {
196 uint8_t index = crypto_box_PUBLICKEYBYTES - cmp1;
197
198 if (pk1[index] == pk2[index])
199 continue;
200
201 cmp2 = abs((int)pk1[index] - (int)pk2[index]);
202 break;
203 }
204
205 return (cmp1 << 8) + cmp2;
206}
207
208static int friend_in_close(Group_c *g, int friendcon_id);
209static int add_conn_to_groupchat(Group_Chats *g_c, int friendcon_id, int groupnumber, uint8_t closest);
210
211static int add_to_closest(Group_Chats *g_c, int groupnumber, const uint8_t *real_pk, const uint8_t *temp_pk)
212{
213 Group_c *g = get_group_c(g_c, groupnumber);
214
215 if (!g)
216 return -1;
217
218 unsigned int i;
219 unsigned int index = DESIRED_CLOSE_CONNECTIONS;
220
221 for (i = 0; i < DESIRED_CLOSE_CONNECTIONS; ++i) {
222 if (g->closest_peers[i].entry == 0) {
223 index = i;
224 break;
225 }
226 }
227
228 if (index == DESIRED_CLOSE_CONNECTIONS) {
229 uint16_t comp_val = calculate_comp_value(g->real_pk, real_pk);
230 uint16_t comp_d = 0;
231
232 for (i = 0; i < DESIRED_CLOSE_CONNECTIONS; ++i) {
233 uint16_t comp = calculate_comp_value(g->real_pk, g->closest_peers[i].real_pk);
234
235 if (comp > comp_val && comp > comp_d) {
236 index = i;
237 comp_d = comp;
238 }
239 }
240 }
241
242 if (index == DESIRED_CLOSE_CONNECTIONS) {
243 return -1;
244 }
245
246 g->closest_peers[index].entry = 1;
247 memcpy(g->closest_peers[index].real_pk, real_pk, crypto_box_PUBLICKEYBYTES);
248 memcpy(g->closest_peers[index].temp_pk, temp_pk, crypto_box_PUBLICKEYBYTES);
249 g->changed = 1;
250
251 return 0;
252}
253
254static unsigned int pk_in_closest_peers(Group_c *g, uint8_t *real_pk)
255{
256 unsigned int i;
257
258 for (i = 0; i < DESIRED_CLOSE_CONNECTIONS; ++i) {
259 if (!g->closest_peers[i].entry)
260 continue;
261
262 if (memcmp(g->closest_peers[i].real_pk, real_pk, crypto_box_PUBLICKEYBYTES) == 0)
263 return 1;
264
265 }
266
267 return 0;
268}
269
270static int connect_to_closest(Group_Chats *g_c, int groupnumber)
271{
272 Group_c *g = get_group_c(g_c, groupnumber);
273
274 if (!g)
275 return -1;
276
277 if (!g->changed)
278 return 0;
279
280 unsigned int i;
281
282 for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) {
283 if (g->close[i].type == GROUPCHAT_CLOSE_NONE)
284 continue;
285
286 if (!g->close[i].closest)
287 continue;
288
289 uint8_t real_pk[crypto_box_PUBLICKEYBYTES];
290 uint8_t dht_temp_pk[crypto_box_PUBLICKEYBYTES];
291 get_friendcon_public_keys(real_pk, dht_temp_pk, g_c->fr_c, g->close[i].number);
292
293 if (!pk_in_closest_peers(g, real_pk)) {
294 g->close[i].type = GROUPCHAT_CLOSE_NONE;
295 kill_friend_connection(g_c->fr_c, g->close[i].number);
296 }
297 }
298
299 for (i = 0; i < DESIRED_CLOSE_CONNECTIONS; ++i) {
300 if (!g->closest_peers[i].entry)
301 continue;
302
303 int friendcon_id = getfriend_conn_id_pk(g_c->fr_c, g->closest_peers[i].real_pk);
304
305 if (friendcon_id == -1) {
306 friendcon_id = new_friend_connection(g_c->fr_c, g->closest_peers[i].real_pk);
307
308 if (friendcon_id == -1) {
309 continue;
310 }
311
312 set_dht_temp_pk(g_c->fr_c, friendcon_id, g->closest_peers[i].temp_pk);
313 }
314
315 add_conn_to_groupchat(g_c, friendcon_id, groupnumber, 1);
316 }
317
318 g->changed = 0;
319
320 return 0;
321}
322
190/* 323/*
191 * Add a peer to the group chat. 324 * Add a peer to the group chat.
192 * 325 *
193 * return peer_index if success or peer already in chat. 326 * return peer_index if success or peer already in chat.
194 * return -1 if error. 327 * return -1 if error.
195 */ 328 */
196static int addpeer(Group_c *chat, const uint8_t *client_id, uint16_t peer_number) 329static int addpeer(Group_Chats *g_c, int groupnumber, const uint8_t *real_pk, const uint8_t *temp_pk,
330 uint16_t peer_number)
197{ 331{
332 Group_c *g = get_group_c(g_c, groupnumber);
333
334 if (!g)
335 return -1;
336
198 //TODO 337 //TODO
199 //int peer_index = peer_in_chat(chat, client_id); 338 int peer_index = peer_in_chat(g, real_pk);
339
340 if (peer_index != -1) {
341 id_copy(g->group[peer_index].temp_pk, temp_pk);
342
343 if (g->group[peer_index].peer_number != peer_number)
344 return -1;
345
346 return peer_index;
347 }
200 348
201 //if (peer_index != -1) 349 peer_index = get_peer_index(g, peer_number);
202 // return peer_index; 350
351 if (peer_index != -1)
352 return -1;
203 353
204 Group_Peer *temp; 354 Group_Peer *temp;
205 temp = realloc(chat->group, sizeof(Group_Peer) * (chat->numpeers + 1)); 355 temp = realloc(g->group, sizeof(Group_Peer) * (g->numpeers + 1));
206 356
207 if (temp == NULL) 357 if (temp == NULL)
208 return -1; 358 return -1;
209 359
210 memset(&(temp[chat->numpeers]), 0, sizeof(Group_Peer)); 360 memset(&(temp[g->numpeers]), 0, sizeof(Group_Peer));
211 chat->group = temp; 361 g->group = temp;
212 362
213 id_copy(chat->group[chat->numpeers].client_id, client_id); 363 id_copy(g->group[g->numpeers].real_pk, real_pk);
214 chat->group[chat->numpeers].peer_number = peer_number; 364 id_copy(g->group[g->numpeers].temp_pk, temp_pk);
365 g->group[g->numpeers].peer_number = peer_number;
215 366
216 chat->group[chat->numpeers].last_recv = unix_time(); 367 g->group[g->numpeers].last_recv = unix_time();
217 chat->group[chat->numpeers].last_recv_msgping = unix_time(); 368 g->group[g->numpeers].last_recv_msgping = unix_time();
218 ++chat->numpeers; 369 ++g->numpeers;
219 370
220 //if (chat->peer_namelistchange != NULL) 371 add_to_closest(g_c, groupnumber, real_pk, temp_pk);
221 // (*chat->peer_namelistchange)(chat, chat->numpeers - 1, CHAT_CHANGE_PEER_ADD, chat->group_namelistchange_userdata); 372 //if (g->peer_namelistchange != NULL)
373 // (*g->peer_namelistchange)(g, g->numpeers - 1, CHAT_CHANGE_PEER_ADD, g->group_namelistchange_userdata);
222 374
223 return (chat->numpeers - 1); 375 return (g->numpeers - 1);
224} 376}
225 377
226static int handle_status(void *object, int number, uint8_t status) 378static int remove_close_conn(Group_Chats *g_c, int groupnumber, int friendcon_id)
227{ 379{
228 if (status) { /* Went online */ 380 Group_c *g = get_group_c(g_c, groupnumber);
229 381
230 } else { /* Went offline */ 382 if (!g)
383 return -1;
384
385 uint32_t i;
386
387 for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) {
388 if (g->close[i].type == GROUPCHAT_CLOSE_NONE)
389 continue;
231 390
391 if (g->close[i].number == friendcon_id) {
392 g->close[i].type = GROUPCHAT_CLOSE_NONE;
393 kill_friend_connection(g_c->fr_c, friendcon_id);
394 return 0;
395 }
232 } 396 }
397
398 return -1;
233} 399}
234 400
235static int handle_packet(void *object, int number, uint8_t *data, uint16_t length); 401static int send_packet_online(Friend_Connections *fr_c, int friendcon_id, uint16_t group_num, uint8_t *identifier);
402
403static void set_conns_type_close(Group_Chats *g_c, int groupnumber, int friendcon_id, uint8_t type)
404{
405 Group_c *g = get_group_c(g_c, groupnumber);
406
407 if (!g)
408 return;
409
410 uint32_t i;
411
412 for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) {
413 if (g->close[i].type == GROUPCHAT_CLOSE_NONE)
414 continue;
415
416 if (g->close[i].number != friendcon_id)
417 continue;
418
419 if (type == GROUPCHAT_CLOSE_ONLINE) {
420 send_packet_online(g_c->fr_c, friendcon_id, groupnumber, g->identifier);
421 } else {
422 g->close[i].type = type;
423 }
424 }
425}
426/* Set the type for all close connections with friendcon_id */
427static void set_conns_status_groups(Group_Chats *g_c, int friendcon_id, uint8_t type)
428{
429 uint32_t i;
430
431 for (i = 0; i < g_c->num_chats; ++i) {
432 set_conns_type_close(g_c, i, friendcon_id, type);
433 }
434}
435
436static int handle_status(void *object, int friendcon_id, uint8_t status)
437{
438 Group_Chats *g_c = object;
439
440 if (status) { /* Went online */
441 set_conns_status_groups(g_c, friendcon_id, GROUPCHAT_CLOSE_ONLINE);
442 } else { /* Went offline */
443 set_conns_status_groups(g_c, friendcon_id, GROUPCHAT_CLOSE_CONNECTION);
444 //TODO remove timedout connections?
445 }
446
447 return 0;
448}
449
450static int handle_packet(void *object, int friendcon_id, uint8_t *data, uint16_t length);
236 451
237/* Add friend to group chat. 452/* Add friend to group chat.
238 * 453 *
239 * return 0 on success 454 * return close index on success
240 * return -1 on failure. 455 * return -1 on failure.
241 */ 456 */
242static int add_conn_to_groupchat(Group_Chats *g_c, int friendcon_id, int groupnumber, uint16_t other_groupnum) 457static int add_conn_to_groupchat(Group_Chats *g_c, int friendcon_id, int groupnumber, uint8_t closest)
243{ 458{
244 Group_c *g = get_group_c(g_c, groupnumber); 459 Group_c *g = get_group_c(g_c, groupnumber);
245 460
@@ -254,9 +469,8 @@ static int add_conn_to_groupchat(Group_Chats *g_c, int friendcon_id, int groupnu
254 continue; 469 continue;
255 } 470 }
256 471
257 if (g->close[i].type == GROUPCHAT_CLOSE_CONNECTION && g->close[i].number == (uint32_t)friendcon_id) { 472 if (g->close[i].number == (uint32_t)friendcon_id) {
258 g->close[i].group_number = other_groupnum; /* update groupnum. */ 473 return i; /* Already in list. */
259 return 0; /* Already in list. */
260 } 474 }
261 475
262 break; 476 break;
@@ -265,14 +479,15 @@ static int add_conn_to_groupchat(Group_Chats *g_c, int friendcon_id, int groupnu
265 if (ind == MAX_GROUP_CONNECTIONS) 479 if (ind == MAX_GROUP_CONNECTIONS)
266 return -1; 480 return -1;
267 481
482 friend_connection_lock(g_c->fr_c, friendcon_id);
268 g->close[ind].type = GROUPCHAT_CLOSE_CONNECTION; 483 g->close[ind].type = GROUPCHAT_CLOSE_CONNECTION;
269 g->close[ind].number = friendcon_id; 484 g->close[ind].number = friendcon_id;
270 g->close[ind].group_number = other_groupnum; 485 g->close[ind].closest = closest;
271 //TODO 486 //TODO
272 friend_connection_callbacks(g_c->m->fr_c, friendcon_id, GROUPCHAT_CALLBACK_INDEX, &handle_status, &handle_packet, 0, 487 friend_connection_callbacks(g_c->m->fr_c, friendcon_id, GROUPCHAT_CALLBACK_INDEX, &handle_status, &handle_packet, 0,
273 g_c, friendcon_id); 488 g_c, friendcon_id);
274 489
275 return 0; 490 return ind;
276} 491}
277 492
278/* Creates a new groupchat and puts it in the chats array. 493/* Creates a new groupchat and puts it in the chats array.
@@ -289,9 +504,11 @@ int add_groupchat(Group_Chats *g_c)
289 504
290 Group_c *g = &g_c->chats[groupnumber]; 505 Group_c *g = &g_c->chats[groupnumber];
291 506
292 g->status = GROUPCHAT_STATUS_VALID; 507 g->status = GROUPCHAT_STATUS_CONNECTED;
293 new_symmetric_key(g->identifier); 508 new_symmetric_key(g->identifier);
294 g->peer_number = 0; /* Founder is peer 0. */ 509 g->peer_number = 0; /* Founder is peer 0. */
510 memcpy(g->real_pk, g_c->m->net_crypto->self_public_key, crypto_box_PUBLICKEYBYTES);
511 addpeer(g_c, groupnumber, g->real_pk, g_c->m->dht->self_public_key, 0);
295 return groupnumber; 512 return groupnumber;
296} 513}
297 514
@@ -311,20 +528,23 @@ int del_groupchat(Group_Chats *g_c, int groupnumber)
311 return wipe_group_chat(g_c, groupnumber); 528 return wipe_group_chat(g_c, groupnumber);
312} 529}
313 530
314/* Send a group message packet. 531/* Send a group packet to friendcon_id.
315 * 532 *
316 * return 1 on success 533 * return 1 on success
317 * return 0 on failure 534 * return 0 on failure
318 */ 535 */
319int send_group_message_packet(const Messenger *m, int friendcon_id, const uint8_t *data, uint16_t length) 536static unsigned int send_packet_group_peer(Friend_Connections *fr_c, int friendcon_id, uint8_t packet_id,
537 uint16_t group_num, const uint8_t *data, uint16_t length)
320{ 538{
321 if (length >= MAX_CRYPTO_DATA_SIZE) 539 if (1 + sizeof(uint16_t) + length > MAX_CRYPTO_DATA_SIZE)
322 return 0; 540 return 0;
323 541
324 uint8_t packet[1 + length]; 542 group_num = htons(group_num);
325 packet[0] = PACKET_ID_MESSAGE_GROUPCHAT; 543 uint8_t packet[1 + sizeof(uint16_t) + length];
326 memcpy(packet + 1, data, length); 544 packet[0] = packet_id;
327 return write_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c, friendcon_id), packet, 545 memcpy(packet + 1, &group_num, sizeof(uint16_t));
546 memcpy(packet + 1 + sizeof(uint16_t), data, length);
547 return write_cryptpacket(fr_c->net_crypto, friend_connection_crypt_connection_id(fr_c, friendcon_id), packet,
328 sizeof(packet), 0) != -1; 548 sizeof(packet), 0) != -1;
329} 549}
330 550
@@ -359,6 +579,8 @@ int invite_friend(Group_Chats *g_c, int32_t friendnumber, int groupnumber)
359 } 579 }
360} 580}
361 581
582static unsigned int send_peer_query(Group_Chats *g_c, int friendcon_id, uint16_t group_num);
583
362/* Join a group (you need to have been invited first.) 584/* Join a group (you need to have been invited first.)
363 * 585 *
364 * returns group number on success 586 * returns group number on success
@@ -369,6 +591,11 @@ int join_groupchat(Group_Chats *g_c, int32_t friendnumber, const uint8_t *data,
369 if (length != sizeof(uint16_t) + GROUP_IDENTIFIER_LENGTH) 591 if (length != sizeof(uint16_t) + GROUP_IDENTIFIER_LENGTH)
370 return -1; 592 return -1;
371 593
594 int friendcon_id = getfriendcon_id(g_c->m, friendnumber);
595
596 if (friendcon_id == -1)
597 return -1;
598
372 int groupnumber = create_group_chat(g_c); 599 int groupnumber = create_group_chat(g_c);
373 600
374 if (groupnumber == -1) 601 if (groupnumber == -1)
@@ -378,6 +605,8 @@ int join_groupchat(Group_Chats *g_c, int32_t friendnumber, const uint8_t *data,
378 605
379 uint16_t group_num = htons(groupnumber); 606 uint16_t group_num = htons(groupnumber);
380 g->status = GROUPCHAT_STATUS_VALID; 607 g->status = GROUPCHAT_STATUS_VALID;
608 memcpy(g->real_pk, g_c->m->net_crypto->self_public_key, crypto_box_PUBLICKEYBYTES);
609
381 uint8_t response[INVITE_RESPONSE_PACKET_SIZE]; 610 uint8_t response[INVITE_RESPONSE_PACKET_SIZE];
382 response[0] = INVITE_RESPONSE_ID; 611 response[0] = INVITE_RESPONSE_ID;
383 memcpy(response + 1, &group_num, sizeof(uint16_t)); 612 memcpy(response + 1, &group_num, sizeof(uint16_t));
@@ -386,12 +615,19 @@ int join_groupchat(Group_Chats *g_c, int32_t friendnumber, const uint8_t *data,
386 if (send_group_invite_packet(g_c->m, friendnumber, response, sizeof(response))) { 615 if (send_group_invite_packet(g_c->m, friendnumber, response, sizeof(response))) {
387 uint16_t other_groupnum; 616 uint16_t other_groupnum;
388 memcpy(&other_groupnum, data, sizeof(other_groupnum)); 617 memcpy(&other_groupnum, data, sizeof(other_groupnum));
389 other_groupnum = htons(other_groupnum); 618 other_groupnum = ntohs(other_groupnum);
390 memcpy(g->identifier, data + sizeof(uint16_t), GROUP_IDENTIFIER_LENGTH); 619 memcpy(g->identifier, data + sizeof(uint16_t), GROUP_IDENTIFIER_LENGTH);
391 add_conn_to_groupchat(g_c, getfriendcon_id(g_c->m, friendnumber), groupnumber, other_groupnum); 620 int close_index = add_conn_to_groupchat(g_c, friendcon_id, groupnumber, 0);
392 g->peer_number = rand(); /* TODO */ 621
622 if (close_index != -1) {
623 g->close[close_index].group_number = other_groupnum;
624 g->close[close_index].type = GROUPCHAT_CLOSE_ONLINE;
625 }
626
627 send_peer_query(g_c, friendcon_id, other_groupnum);
393 return groupnumber; 628 return groupnumber;
394 } else { 629 } else {
630 g->status = GROUPCHAT_STATUS_NONE;
395 return -1; 631 return -1;
396 } 632 }
397} 633}
@@ -420,6 +656,31 @@ void g_callback_group_message(Group_Chats *g_c, void (*function)(Messenger *m, i
420 g_c->message_callback_userdata = userdata; 656 g_c->message_callback_userdata = userdata;
421} 657}
422 658
659static unsigned int send_message_group(const Group_Chats *g_c, int groupnumber, uint8_t message_id, const uint8_t *data,
660 uint16_t len);
661#define GROUP_MESSAGE_NEW_PEER_ID 16
662#define GROUP_MESSAGE_NEW_PEER_LENGTH (sizeof(uint16_t) + crypto_box_PUBLICKEYBYTES * 2)
663/* send a group message
664 * return 0 on success
665 * return -1 on failure
666 */
667int group_new_peer_send(const Group_Chats *g_c, int groupnumber, uint16_t peer_num, const uint8_t *real_pk,
668 uint8_t *temp_pk)
669{
670 uint8_t packet[GROUP_MESSAGE_NEW_PEER_LENGTH];
671
672 peer_num = htons(peer_num);
673 memcpy(packet, &peer_num, sizeof(uint16_t));
674 memcpy(packet + sizeof(uint16_t), real_pk, crypto_box_PUBLICKEYBYTES);
675 memcpy(packet + sizeof(uint16_t) + crypto_box_PUBLICKEYBYTES, temp_pk, crypto_box_PUBLICKEYBYTES);
676
677 if (send_message_group(g_c, groupnumber, GROUP_MESSAGE_NEW_PEER_ID, packet, sizeof(packet))) {
678 return 0;
679 } else {
680 return -1;
681 }
682}
683
423static void handle_friend_invite_packet(Messenger *m, int32_t friendnumber, const uint8_t *data, uint16_t length) 684static void handle_friend_invite_packet(Messenger *m, int32_t friendnumber, const uint8_t *data, uint16_t length)
424{ 685{
425 Group_Chats *g_c = m->group_chat_object; 686 Group_Chats *g_c = m->group_chat_object;
@@ -442,12 +703,6 @@ static void handle_friend_invite_packet(Messenger *m, int32_t friendnumber, cons
442 g_c->invite_callback(m, friendnumber, invite_data, invite_length, g_c->invite_callback_userdata); 703 g_c->invite_callback(m, friendnumber, invite_data, invite_length, g_c->invite_callback_userdata);
443 704
444 return; 705 return;
445 } else {
446 //TODO
447 uint16_t other_groupnum;
448 memcpy(&other_groupnum, data + 1, sizeof(uint16_t));
449 other_groupnum = ntohs(other_groupnum);
450 add_conn_to_groupchat(g_c, getfriendcon_id(m, friendnumber), groupnumber, other_groupnum);
451 } 706 }
452 707
453 break; 708 break;
@@ -472,8 +727,20 @@ static void handle_friend_invite_packet(Messenger *m, int32_t friendnumber, cons
472 memcpy(&other_groupnum, data + 1, sizeof(uint16_t)); 727 memcpy(&other_groupnum, data + 1, sizeof(uint16_t));
473 other_groupnum = ntohs(other_groupnum); 728 other_groupnum = ntohs(other_groupnum);
474 729
475 add_conn_to_groupchat(g_c, getfriendcon_id(m, friendnumber), groupnum, other_groupnum); 730 int friendcon_id = getfriendcon_id(m, friendnumber);
731 uint8_t real_pk[crypto_box_PUBLICKEYBYTES], temp_pk[crypto_box_PUBLICKEYBYTES];
732 get_friendcon_public_keys(real_pk, temp_pk, g_c->fr_c, friendcon_id);
476 733
734 uint16_t peer_number = rand(); /* TODO: make it not random. */
735 addpeer(g_c, groupnum, real_pk, temp_pk, peer_number);
736 int close_index = add_conn_to_groupchat(g_c, friendcon_id, groupnum, 0);
737
738 if (close_index != -1) {
739 g->close[close_index].group_number = other_groupnum;
740 g->close[close_index].type = GROUPCHAT_CLOSE_ONLINE;
741 }
742
743 group_new_peer_send(g_c, groupnum, peer_number, real_pk, temp_pk);
477 break; 744 break;
478 } 745 }
479 746
@@ -492,7 +759,7 @@ static int friend_in_close(Group_c *g, int friendcon_id)
492 int i; 759 int i;
493 760
494 for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) { 761 for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) {
495 if (g->close[i].type != GROUPCHAT_CLOSE_CONNECTION) 762 if (g->close[i].type == GROUPCHAT_CLOSE_NONE)
496 continue; 763 continue;
497 764
498 if (g->close[i].number != (uint32_t)friendcon_id) 765 if (g->close[i].number != (uint32_t)friendcon_id)
@@ -504,6 +771,165 @@ static int friend_in_close(Group_c *g, int friendcon_id)
504 return -1; 771 return -1;
505} 772}
506 773
774#define ONLINE_PACKET_DATA_SIZE (sizeof(uint16_t) + crypto_box_PUBLICKEYBYTES)
775
776static int send_packet_online(Friend_Connections *fr_c, int friendcon_id, uint16_t group_num, uint8_t *identifier)
777{
778 uint8_t packet[1 + ONLINE_PACKET_DATA_SIZE];
779 group_num = htons(group_num);
780 packet[0] = PACKET_ID_ONLINE_PACKET;
781 memcpy(packet + 1, &group_num, sizeof(uint16_t));
782 memcpy(packet + 1 + sizeof(uint16_t), identifier, crypto_box_PUBLICKEYBYTES);
783 return write_cryptpacket(fr_c->net_crypto, friend_connection_crypt_connection_id(fr_c, friendcon_id), packet,
784 sizeof(packet), 0) != -1;
785}
786
787static int handle_packet_online(Group_Chats *g_c, int friendcon_id, uint8_t *data, uint16_t length)
788{
789 if (length != ONLINE_PACKET_DATA_SIZE)
790 return -1;
791
792 int groupnumber = get_group_num(g_c, data + sizeof(uint16_t));
793 uint16_t other_groupnum;
794 memcpy(&other_groupnum, data, sizeof(uint16_t));
795 other_groupnum = ntohs(other_groupnum);
796
797 Group_c *g = get_group_c(g_c, groupnumber);
798
799 if (!g)
800 return -1;
801
802 int index = friend_in_close(g, friendcon_id);
803
804 if (index == -1)
805 return -1;
806
807 g->close[index].group_number = other_groupnum;
808 g->close[index].type = GROUPCHAT_CLOSE_ONLINE;
809 return 0;
810}
811
812#define PEER_QUERY_ID 4
813#define PEER_RESPONSE_ID 8
814
815/* return 1 on success.
816 * return 0 on failure
817 */
818static unsigned int send_peer_query(Group_Chats *g_c, int friendcon_id, uint16_t group_num)
819{
820 uint8_t packet[1];
821 packet[0] = PEER_QUERY_ID;
822 return send_packet_group_peer(g_c->fr_c, friendcon_id, PACKET_ID_DIRECT_GROUPCHAT, group_num, packet, sizeof(packet));
823}
824
825/* return number of peers sent on success.
826 * return 0 on failure.
827 */
828static unsigned int send_peers(Group_Chats *g_c, int groupnumber, int friendcon_id, uint16_t group_num)
829{
830 Group_c *g = get_group_c(g_c, groupnumber);
831
832 if (!g)
833 return -1;
834
835 uint8_t packet[MAX_CRYPTO_DATA_SIZE - (1 + sizeof(uint16_t))];
836 packet[0] = PEER_RESPONSE_ID;
837 uint8_t *p = packet + 1;
838
839 uint16_t sent = 0;
840 unsigned int i;
841
842 for (i = 0; i < g->numpeers; ++i) {
843 uint16_t peer_num = htons(g->group[i].peer_number);
844 memcpy(p, &peer_num, sizeof(peer_num));
845 p += sizeof(peer_num);
846 memcpy(p, g->group[i].real_pk, crypto_box_PUBLICKEYBYTES);
847 p += crypto_box_PUBLICKEYBYTES;
848 memcpy(p, g->group[i].temp_pk, crypto_box_PUBLICKEYBYTES);
849 p += crypto_box_PUBLICKEYBYTES;
850
851 if ((p - packet) + sizeof(uint16_t) + crypto_box_PUBLICKEYBYTES * 2 > sizeof(packet)) {
852 if (send_packet_group_peer(g_c->fr_c, friendcon_id, PACKET_ID_DIRECT_GROUPCHAT, group_num, packet, (p - packet))) {
853 sent = i;
854 } else {
855 return sent;
856 }
857
858 p = packet + 1;
859 }
860 }
861
862 if (sent != i) {
863 if (send_packet_group_peer(g_c->fr_c, friendcon_id, PACKET_ID_DIRECT_GROUPCHAT, group_num, packet, (p - packet))) {
864 sent = i;
865 }
866 }
867
868 return sent;
869}
870
871static int handle_send_peers(Group_Chats *g_c, int groupnumber, const uint8_t *data, uint16_t length)
872{
873 if (length == 0)
874 return -1;
875
876 if (length % (sizeof(uint16_t) + crypto_box_PUBLICKEYBYTES * 2) != 0)
877 return -1;
878
879 Group_c *g = get_group_c(g_c, groupnumber);
880
881 if (!g)
882 return -1;
883
884 unsigned int i;
885 const uint8_t *d = data;
886
887 while ((length - (d - data)) >= sizeof(uint16_t) + crypto_box_PUBLICKEYBYTES * 2) {
888 uint16_t peer_num;
889 memcpy(&peer_num, d, sizeof(peer_num));
890 peer_num = ntohs(peer_num);
891 d += sizeof(uint16_t);
892 addpeer(g_c, groupnumber, d, d + crypto_box_PUBLICKEYBYTES, peer_num);
893
894 if (g->status == GROUPCHAT_STATUS_VALID
895 && memcmp(d, g_c->m->net_crypto->self_public_key, crypto_box_PUBLICKEYBYTES) == 0) {
896 g->peer_number = peer_num;
897 g->status = GROUPCHAT_STATUS_CONNECTED;
898 }
899
900 d += crypto_box_PUBLICKEYBYTES * 2;
901 }
902
903 return 0;
904}
905
906static void handle_direct_packet(Group_Chats *g_c, int groupnumber, const uint8_t *data, uint16_t length,
907 int close_index)
908{
909 if (length == 0)
910 return;
911
912 switch (data[0]) {
913 case PEER_QUERY_ID: {
914 Group_c *g = get_group_c(g_c, groupnumber);
915
916 if (!g)
917 return;
918
919 send_peers(g_c, groupnumber, g->close[close_index].number, g->close[close_index].group_number);
920 }
921
922 break;
923
924 case PEER_RESPONSE_ID: {
925 handle_send_peers(g_c, groupnumber, data + 1, length - 1);
926 }
927
928 break;
929
930 }
931}
932
507#define MIN_MESSAGE_PACKET_LEN (sizeof(uint16_t) * 2 + sizeof(uint32_t) + 1) 933#define MIN_MESSAGE_PACKET_LEN (sizeof(uint16_t) * 2 + sizeof(uint32_t) + 1)
508 934
509/* Send message to all close except receiver (if receiver isn't -1) 935/* Send message to all close except receiver (if receiver isn't -1)
@@ -514,7 +940,6 @@ static int friend_in_close(Group_c *g, int friendcon_id)
514static unsigned int send_message_all_close(const Group_Chats *g_c, int groupnumber, const uint8_t *data, 940static unsigned int send_message_all_close(const Group_Chats *g_c, int groupnumber, const uint8_t *data,
515 uint16_t length, int receiver) 941 uint16_t length, int receiver)
516{ 942{
517
518 Group_c *g = get_group_c(g_c, groupnumber); 943 Group_c *g = get_group_c(g_c, groupnumber);
519 944
520 if (!g) 945 if (!g)
@@ -523,18 +948,14 @@ static unsigned int send_message_all_close(const Group_Chats *g_c, int groupnumb
523 uint16_t i, sent = 0; 948 uint16_t i, sent = 0;
524 949
525 for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) { 950 for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) {
526 if (g->close[i].type == GROUPCHAT_CLOSE_NONE) 951 if (g->close[i].type != GROUPCHAT_CLOSE_ONLINE)
527 continue; 952 continue;
528 953
529 if ((int)i == receiver) 954 if ((int)i == receiver)
530 continue; 955 continue;
531 956
532 uint16_t other_groupnum = htons(g->close[i].group_number); 957 if (send_packet_group_peer(g_c->fr_c, g->close[i].number, PACKET_ID_MESSAGE_GROUPCHAT, g->close[i].group_number, data,
533 uint8_t packet[sizeof(uint16_t) + length]; 958 length))
534 memcpy(packet, &other_groupnum, sizeof(uint16_t));
535 memcpy(packet + sizeof(uint16_t), data, length);
536
537 if (send_group_message_packet(g_c->m, g->close[i].number, packet, sizeof(packet)))
538 ++sent; 959 ++sent;
539 } 960 }
540 961
@@ -559,6 +980,9 @@ static unsigned int send_message_group(const Group_Chats *g_c, int groupnumber,
559 if (!g) 980 if (!g)
560 return 0; 981 return 0;
561 982
983 if (g->status != GROUPCHAT_STATUS_CONNECTED)
984 return 0;
985
562 uint8_t packet[sizeof(uint16_t) + sizeof(uint32_t) + 1 + len]; 986 uint8_t packet[sizeof(uint16_t) + sizeof(uint32_t) + 1 + len];
563 uint16_t peer_num = htons(g->peer_number); 987 uint16_t peer_num = htons(g->peer_number);
564 memcpy(packet, &peer_num, sizeof(peer_num)); 988 memcpy(packet, &peer_num, sizeof(peer_num));
@@ -595,7 +1019,7 @@ int group_message_send(const Group_Chats *g_c, int groupnumber, const uint8_t *m
595static void handle_message_packet_group(Group_Chats *g_c, int groupnumber, const uint8_t *data, uint16_t length, 1019static void handle_message_packet_group(Group_Chats *g_c, int groupnumber, const uint8_t *data, uint16_t length,
596 int close_index) 1020 int close_index)
597{ 1021{
598 if (length < MIN_MESSAGE_PACKET_LEN) 1022 if (length < sizeof(uint16_t) + sizeof(uint32_t) + 1)
599 return; 1023 return;
600 1024
601 Group_c *g = get_group_c(g_c, groupnumber); 1025 Group_c *g = get_group_c(g_c, groupnumber);
@@ -604,22 +1028,16 @@ static void handle_message_packet_group(Group_Chats *g_c, int groupnumber, const
604 return; 1028 return;
605 1029
606 uint16_t peer_number; 1030 uint16_t peer_number;
607 memcpy(&peer_number, data + sizeof(uint16_t), sizeof(uint16_t)); 1031 memcpy(&peer_number, data, sizeof(uint16_t));
608 peer_number = ntohs(peer_number); 1032 peer_number = ntohs(peer_number);
609 1033
610 int index = get_peer_index(g, peer_number); 1034 int index = get_peer_index(g, peer_number);
611 1035
612 //TODO remove
613 if (index == -1) {
614 uint8_t empty_key[crypto_box_PUBLICKEYBYTES];
615 index = addpeer(g, empty_key, peer_number);
616 }
617
618 if (index == -1) 1036 if (index == -1)
619 return; 1037 return;
620 1038
621 uint32_t message_number; 1039 uint32_t message_number;
622 memcpy(&message_number, data + sizeof(uint16_t) * 2, sizeof(message_number)); 1040 memcpy(&message_number, data + sizeof(uint16_t), sizeof(message_number));
623 message_number = ntohl(message_number); 1041 message_number = ntohl(message_number);
624 1042
625 if (g->group[index].last_message_number == 0) { 1043 if (g->group[index].last_message_number == 0) {
@@ -631,11 +1049,23 @@ static void handle_message_packet_group(Group_Chats *g_c, int groupnumber, const
631 1049
632 g->group[index].last_message_number = message_number; 1050 g->group[index].last_message_number = message_number;
633 1051
634 uint8_t message_id = data[sizeof(uint16_t) * 2 + sizeof(message_number)]; 1052 uint8_t message_id = data[sizeof(uint16_t) + sizeof(message_number)];
635 const uint8_t *msg_data = data + sizeof(uint16_t) * 2 + sizeof(message_number) + 1; 1053 const uint8_t *msg_data = data + sizeof(uint16_t) + sizeof(message_number) + 1;
636 uint16_t msg_data_len = length - (sizeof(uint16_t) * 2 + sizeof(message_number) + 1); 1054 uint16_t msg_data_len = length - (sizeof(uint16_t) + sizeof(message_number) + 1);
637 1055
638 switch (message_id) { 1056 switch (message_id) {
1057 case GROUP_MESSAGE_NEW_PEER_ID: {
1058 if (msg_data_len != GROUP_MESSAGE_NEW_PEER_LENGTH)
1059 return;
1060
1061 uint16_t new_peer_number;
1062 memcpy(&new_peer_number, msg_data, sizeof(uint16_t));
1063 new_peer_number = ntohs(new_peer_number);
1064 addpeer(g_c, groupnumber, msg_data + sizeof(uint16_t), msg_data + sizeof(uint16_t) + crypto_box_PUBLICKEYBYTES,
1065 new_peer_number);
1066 }
1067 break;
1068
639 case PACKET_ID_MESSAGE: { 1069 case PACKET_ID_MESSAGE: {
640 if (msg_data_len == 0) 1070 if (msg_data_len == 0)
641 return; 1071 return;
@@ -651,38 +1081,44 @@ static void handle_message_packet_group(Group_Chats *g_c, int groupnumber, const
651 return; 1081 return;
652 } 1082 }
653 1083
654 send_message_all_close(g_c, groupnumber, data + sizeof(uint16_t), length - sizeof(uint16_t), close_index); 1084 send_message_all_close(g_c, groupnumber, data, length, close_index);
655} 1085}
656 1086
657static void handle_message_packet(Group_Chats *g_c, int friendcon_id, const uint8_t *data, uint16_t length) 1087static int handle_packet(void *object, int friendcon_id, uint8_t *data, uint16_t length)
658{ 1088{
659 if (length < MIN_MESSAGE_PACKET_LEN) 1089 Group_Chats *g_c = object;
660 return; 1090
1091 if (length < 1 + sizeof(uint16_t) + 1)
1092 return -1;
1093
1094 if (data[0] == PACKET_ID_ONLINE_PACKET) {
1095 return handle_packet_online(g_c, friendcon_id, data + 1, length - 1);
1096 }
1097
1098 if (data[0] != PACKET_ID_DIRECT_GROUPCHAT && data[0] != PACKET_ID_MESSAGE_GROUPCHAT)
1099 return -1;
661 1100
662 uint16_t groupnumber; 1101 uint16_t groupnumber;
663 memcpy(&groupnumber, data, sizeof(uint16_t)); 1102 memcpy(&groupnumber, data + 1, sizeof(uint16_t));
664 groupnumber = ntohs(groupnumber); 1103 groupnumber = ntohs(groupnumber);
665 Group_c *g = get_group_c(g_c, groupnumber); 1104 Group_c *g = get_group_c(g_c, groupnumber);
666 1105
667 if (!g) 1106 if (!g)
668 return; 1107 return -1;
669 1108
670 int index = friend_in_close(g, friendcon_id); 1109 int index = friend_in_close(g, friendcon_id);
671 1110
672 if (index == -1) 1111 if (index == -1)
673 return;
674
675 handle_message_packet_group(g_c, groupnumber, data, length, index);
676}
677
678static int handle_packet(void *object, int number, uint8_t *data, uint16_t length)
679{
680 if (length <= 1)
681 return -1; 1112 return -1;
682 1113
683 switch (data[0]) { 1114 switch (data[0]) {
1115 case PACKET_ID_DIRECT_GROUPCHAT: {
1116 handle_direct_packet(g_c, groupnumber, data + 1 + sizeof(uint16_t), length - (1 + sizeof(uint16_t)), index);
1117 break;
1118 }
1119
684 case PACKET_ID_MESSAGE_GROUPCHAT: { 1120 case PACKET_ID_MESSAGE_GROUPCHAT: {
685 handle_message_packet(object, number, data + 1, length - 1); 1121 handle_message_packet_group(g_c, groupnumber, data + 1 + sizeof(uint16_t), length - (1 + sizeof(uint16_t)), index);
686 break; 1122 break;
687 } 1123 }
688 1124
@@ -707,6 +1143,7 @@ Group_Chats *new_groupchats(Messenger *m)
707 return NULL; 1143 return NULL;
708 1144
709 temp->m = m; 1145 temp->m = m;
1146 temp->fr_c = m->fr_c;
710 m->group_chat_object = temp; 1147 m->group_chat_object = temp;
711 m_callback_group_invite(m, &handle_friend_invite_packet); 1148 m_callback_group_invite(m, &handle_friend_invite_packet);
712 1149
@@ -716,6 +1153,18 @@ Group_Chats *new_groupchats(Messenger *m)
716/* main groupchats loop. */ 1153/* main groupchats loop. */
717void do_groupchats(Group_Chats *g_c) 1154void do_groupchats(Group_Chats *g_c)
718{ 1155{
1156 unsigned int i;
1157
1158 for (i = 0; i < g_c->num_chats; ++i) {
1159 Group_c *g = get_group_c(g_c, i);
1160
1161 if (!g)
1162 continue;
1163
1164 if (g->status == GROUPCHAT_STATUS_CONNECTED)
1165 connect_to_closest(g_c, i);
1166 }
1167
719 //TODO 1168 //TODO
720} 1169}
721 1170