ffi-tox 0.1.1 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (153) hide show
  1. checksums.yaml +4 -4
  2. data/ProjectTox-Core/AUTHORS +0 -0
  3. data/ProjectTox-Core/ChangeLog +0 -0
  4. data/ProjectTox-Core/INSTALL +370 -0
  5. data/ProjectTox-Core/INSTALL.md +455 -56
  6. data/ProjectTox-Core/Makefile.am +35 -0
  7. data/ProjectTox-Core/NEWS +0 -0
  8. data/ProjectTox-Core/README +43 -0
  9. data/ProjectTox-Core/README.md +34 -44
  10. data/ProjectTox-Core/auto_tests/Makefile.inc +110 -0
  11. data/ProjectTox-Core/auto_tests/TCP_test.c +519 -0
  12. data/ProjectTox-Core/auto_tests/assoc_test.c +160 -0
  13. data/ProjectTox-Core/auto_tests/crypto_test.c +302 -0
  14. data/ProjectTox-Core/auto_tests/dht_test.c +362 -0
  15. data/ProjectTox-Core/auto_tests/encryptsave_test.c +104 -0
  16. data/ProjectTox-Core/auto_tests/friends_test.c +238 -0
  17. data/ProjectTox-Core/auto_tests/helpers.h +15 -0
  18. data/ProjectTox-Core/auto_tests/messenger_test.c +365 -0
  19. data/ProjectTox-Core/auto_tests/network_test.c +171 -0
  20. data/ProjectTox-Core/auto_tests/onion_test.c +363 -0
  21. data/ProjectTox-Core/auto_tests/skeleton_test.c +49 -0
  22. data/ProjectTox-Core/auto_tests/tox_test.c +454 -0
  23. data/ProjectTox-Core/auto_tests/toxav_basic_test.c +597 -0
  24. data/ProjectTox-Core/auto_tests/toxav_many_test.c +402 -0
  25. data/ProjectTox-Core/autogen.sh +6 -0
  26. data/ProjectTox-Core/build/Makefile.am +14 -0
  27. data/ProjectTox-Core/configure.ac +694 -0
  28. data/ProjectTox-Core/dist-build/android-arm.sh +3 -0
  29. data/ProjectTox-Core/dist-build/android-armv7.sh +3 -0
  30. data/ProjectTox-Core/dist-build/android-build.sh +59 -0
  31. data/ProjectTox-Core/dist-build/android-mips.sh +3 -0
  32. data/ProjectTox-Core/dist-build/android-x86.sh +3 -0
  33. data/ProjectTox-Core/docs/Group-Chats.md +71 -0
  34. data/ProjectTox-Core/docs/Hardening.txt +60 -0
  35. data/ProjectTox-Core/docs/Hardening_docs.txt +30 -0
  36. data/ProjectTox-Core/docs/Prevent_Tracking.txt +160 -0
  37. data/ProjectTox-Core/docs/TCP_Network.txt +154 -0
  38. data/ProjectTox-Core/docs/TODO +62 -0
  39. data/ProjectTox-Core/docs/Tox_middle_level_network_protocol.txt +120 -0
  40. data/ProjectTox-Core/docs/av_api.md +194 -0
  41. data/ProjectTox-Core/libtoxav.pc.in +11 -0
  42. data/ProjectTox-Core/libtoxcore.pc.in +11 -0
  43. data/ProjectTox-Core/m4/ax_have_epoll.m4 +104 -0
  44. data/ProjectTox-Core/m4/ax_pthread.m4 +317 -0
  45. data/ProjectTox-Core/m4/pkg.m4 +199 -0
  46. data/ProjectTox-Core/other/DHT_bootstrap.c +121 -58
  47. data/ProjectTox-Core/other/DHTnodes +3 -0
  48. data/ProjectTox-Core/other/Makefile.inc +20 -0
  49. data/ProjectTox-Core/other/bootstrap_node_packets.c +65 -0
  50. data/ProjectTox-Core/other/tox.png +0 -0
  51. data/ProjectTox-Core/testing/DHT_test.c +170 -98
  52. data/ProjectTox-Core/testing/Makefile.inc +112 -0
  53. data/ProjectTox-Core/testing/Messenger_test.c +133 -69
  54. data/ProjectTox-Core/testing/dns3_test.c +115 -0
  55. data/ProjectTox-Core/testing/misc_tools.c +59 -13
  56. data/ProjectTox-Core/testing/nTox.c +1127 -264
  57. data/ProjectTox-Core/testing/nTox.h +10 -19
  58. data/ProjectTox-Core/testing/tox_shell.c +159 -0
  59. data/ProjectTox-Core/testing/tox_sync.c +299 -0
  60. data/ProjectTox-Core/tools/README +11 -0
  61. data/ProjectTox-Core/tools/astylerc +11 -0
  62. data/ProjectTox-Core/tools/pre-commit +17 -0
  63. data/ProjectTox-Core/toxav/Makefile.inc +36 -0
  64. data/ProjectTox-Core/toxav/codec.c +357 -0
  65. data/ProjectTox-Core/toxav/codec.h +116 -0
  66. data/ProjectTox-Core/toxav/msi.c +1949 -0
  67. data/ProjectTox-Core/toxav/msi.h +267 -0
  68. data/ProjectTox-Core/toxav/rtp.c +600 -0
  69. data/ProjectTox-Core/toxav/rtp.h +196 -0
  70. data/ProjectTox-Core/toxav/toxav.c +1148 -0
  71. data/ProjectTox-Core/toxav/toxav.h +389 -0
  72. data/ProjectTox-Core/toxcore/DHT.c +2521 -0
  73. data/ProjectTox-Core/toxcore/DHT.h +412 -0
  74. data/ProjectTox-Core/toxcore/LAN_discovery.c +322 -0
  75. data/ProjectTox-Core/{core → toxcore}/LAN_discovery.h +17 -12
  76. data/ProjectTox-Core/toxcore/Makefile.inc +67 -0
  77. data/ProjectTox-Core/toxcore/Messenger.c +3006 -0
  78. data/ProjectTox-Core/toxcore/Messenger.h +818 -0
  79. data/ProjectTox-Core/toxcore/TCP_client.c +858 -0
  80. data/ProjectTox-Core/toxcore/TCP_client.h +156 -0
  81. data/ProjectTox-Core/toxcore/TCP_server.c +1332 -0
  82. data/ProjectTox-Core/toxcore/TCP_server.h +181 -0
  83. data/ProjectTox-Core/toxcore/assoc.c +1033 -0
  84. data/ProjectTox-Core/toxcore/assoc.h +104 -0
  85. data/ProjectTox-Core/toxcore/crypto_core.c +278 -0
  86. data/ProjectTox-Core/toxcore/crypto_core.h +151 -0
  87. data/ProjectTox-Core/toxcore/friend_requests.c +175 -0
  88. data/ProjectTox-Core/toxcore/friend_requests.h +83 -0
  89. data/ProjectTox-Core/toxcore/group_chats.c +837 -0
  90. data/ProjectTox-Core/toxcore/group_chats.h +199 -0
  91. data/ProjectTox-Core/toxcore/list.c +256 -0
  92. data/ProjectTox-Core/toxcore/list.h +85 -0
  93. data/ProjectTox-Core/toxcore/logger.c +153 -0
  94. data/ProjectTox-Core/toxcore/logger.h +84 -0
  95. data/ProjectTox-Core/toxcore/misc_tools.h +70 -0
  96. data/ProjectTox-Core/toxcore/net_crypto.c +2753 -0
  97. data/ProjectTox-Core/toxcore/net_crypto.h +410 -0
  98. data/ProjectTox-Core/toxcore/network.c +979 -0
  99. data/ProjectTox-Core/toxcore/network.h +367 -0
  100. data/ProjectTox-Core/toxcore/onion.c +540 -0
  101. data/ProjectTox-Core/toxcore/onion.h +150 -0
  102. data/ProjectTox-Core/toxcore/onion_announce.c +433 -0
  103. data/ProjectTox-Core/toxcore/onion_announce.h +139 -0
  104. data/ProjectTox-Core/toxcore/onion_client.c +1347 -0
  105. data/ProjectTox-Core/toxcore/onion_client.h +253 -0
  106. data/ProjectTox-Core/toxcore/ping.c +346 -0
  107. data/ProjectTox-Core/toxcore/ping.h +47 -0
  108. data/ProjectTox-Core/toxcore/ping_array.c +162 -0
  109. data/ProjectTox-Core/toxcore/ping_array.h +75 -0
  110. data/ProjectTox-Core/toxcore/tox.c +940 -0
  111. data/ProjectTox-Core/toxcore/tox.h +734 -0
  112. data/ProjectTox-Core/toxcore/util.c +193 -0
  113. data/ProjectTox-Core/toxcore/util.h +63 -0
  114. data/ProjectTox-Core/toxdns/Makefile.inc +29 -0
  115. data/ProjectTox-Core/toxdns/toxdns.c +238 -0
  116. data/ProjectTox-Core/toxdns/toxdns.h +88 -0
  117. data/ProjectTox-Core/toxencryptsave/Makefile.inc +45 -0
  118. data/ProjectTox-Core/toxencryptsave/toxencryptsave.c +179 -0
  119. data/ProjectTox-Core/toxencryptsave/toxencryptsave.h +74 -0
  120. data/interfaces/libtox.i +2 -6
  121. data/lib/ffi-tox/libtox.rb +406 -28
  122. metadata +124 -46
  123. data/ProjectTox-Core/CMakeLists.txt +0 -50
  124. data/ProjectTox-Core/cmake/FindLIBCONFIG.cmake +0 -15
  125. data/ProjectTox-Core/cmake/FindNaCl.cmake +0 -17
  126. data/ProjectTox-Core/cmake/FindSODIUM.cmake +0 -15
  127. data/ProjectTox-Core/core/CMakeLists.txt +0 -19
  128. data/ProjectTox-Core/core/DHT.c +0 -1104
  129. data/ProjectTox-Core/core/DHT.h +0 -111
  130. data/ProjectTox-Core/core/LAN_discovery.c +0 -79
  131. data/ProjectTox-Core/core/Lossless_UDP.c +0 -755
  132. data/ProjectTox-Core/core/Lossless_UDP.h +0 -106
  133. data/ProjectTox-Core/core/Messenger.c +0 -596
  134. data/ProjectTox-Core/core/Messenger.h +0 -165
  135. data/ProjectTox-Core/core/friend_requests.c +0 -131
  136. data/ProjectTox-Core/core/friend_requests.h +0 -51
  137. data/ProjectTox-Core/core/net_crypto.c +0 -575
  138. data/ProjectTox-Core/core/net_crypto.h +0 -134
  139. data/ProjectTox-Core/core/network.c +0 -205
  140. data/ProjectTox-Core/core/network.h +0 -134
  141. data/ProjectTox-Core/docs/commands.md +0 -25
  142. data/ProjectTox-Core/docs/start_guide.de.md +0 -40
  143. data/ProjectTox-Core/docs/start_guide.md +0 -38
  144. data/ProjectTox-Core/other/CMakeLists.txt +0 -9
  145. data/ProjectTox-Core/testing/CMakeLists.txt +0 -18
  146. data/ProjectTox-Core/testing/DHT_cryptosendfiletest.c +0 -228
  147. data/ProjectTox-Core/testing/DHT_sendfiletest.c +0 -176
  148. data/ProjectTox-Core/testing/Lossless_UDP_testclient.c +0 -214
  149. data/ProjectTox-Core/testing/Lossless_UDP_testserver.c +0 -201
  150. data/ProjectTox-Core/testing/misc_tools.h +0 -29
  151. data/ProjectTox-Core/testing/nTox_win32.c +0 -387
  152. data/ProjectTox-Core/testing/nTox_win32.h +0 -40
  153. data/ProjectTox-Core/testing/rect.py +0 -45
@@ -0,0 +1,175 @@
1
+ /* friend_requests.c
2
+ *
3
+ * Handle friend requests.
4
+ *
5
+ * Copyright (C) 2013 Tox project All Rights Reserved.
6
+ *
7
+ * This file is part of Tox.
8
+ *
9
+ * Tox is free software: you can redistribute it and/or modify
10
+ * it under the terms of the GNU General Public License as published by
11
+ * the Free Software Foundation, either version 3 of the License, or
12
+ * (at your option) any later version.
13
+ *
14
+ * Tox is distributed in the hope that it will be useful,
15
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
+ * GNU General Public License for more details.
18
+ *
19
+ * You should have received a copy of the GNU General Public License
20
+ * along with Tox. If not, see <http://www.gnu.org/licenses/>.
21
+ *
22
+ */
23
+
24
+ #ifdef HAVE_CONFIG_H
25
+ #include "config.h"
26
+ #endif
27
+
28
+ #include "friend_requests.h"
29
+ #include "util.h"
30
+
31
+ /* Try to send a friend request to peer with public_key.
32
+ * data is the data in the request and length is the length.
33
+ *
34
+ * return -1 if failure.
35
+ * return 0 if it sent the friend request directly to the friend.
36
+ * return the number of peers it was routed through if it did not send it directly.
37
+ */
38
+ int send_friendrequest(const Onion_Client *onion_c, const uint8_t *public_key, uint32_t nospam_num, const uint8_t *data,
39
+ uint32_t length)
40
+ {
41
+ if (1 + sizeof(nospam_num) + length > ONION_CLIENT_MAX_DATA_SIZE || length == 0)
42
+ return -1;
43
+
44
+ uint8_t temp[1 + sizeof(nospam_num) + length];
45
+ temp[0] = CRYPTO_PACKET_FRIEND_REQ;
46
+ memcpy(temp + 1, &nospam_num, sizeof(nospam_num));
47
+ memcpy(temp + 1 + sizeof(nospam_num), data, length);
48
+
49
+ int friend_num = onion_friend_num(onion_c, public_key);
50
+
51
+ if (friend_num == -1)
52
+ return -1;
53
+
54
+ int num = send_onion_data(onion_c, friend_num, temp, sizeof(temp));
55
+
56
+ if (num <= 0)
57
+ return -1;
58
+
59
+ return num;
60
+ }
61
+
62
+
63
+ /* Set and get the nospam variable used to prevent one type of friend request spam. */
64
+ void set_nospam(Friend_Requests *fr, uint32_t num)
65
+ {
66
+ fr->nospam = num;
67
+ }
68
+
69
+ uint32_t get_nospam(const Friend_Requests *fr)
70
+ {
71
+ return fr->nospam;
72
+ }
73
+
74
+
75
+ /* Set the function that will be executed when a friend request is received. */
76
+ void callback_friendrequest(Friend_Requests *fr, void (*function)(void *, const uint8_t *, const uint8_t *, uint16_t,
77
+ void *), void *object, void *userdata)
78
+ {
79
+ fr->handle_friendrequest = function;
80
+ fr->handle_friendrequest_isset = 1;
81
+ fr->handle_friendrequest_object = object;
82
+ fr->handle_friendrequest_userdata = userdata;
83
+ }
84
+ /* Set the function used to check if a friend request should be displayed to the user or not. */
85
+ void set_filter_function(Friend_Requests *fr, int (*function)(const uint8_t *, void *), void *userdata)
86
+ {
87
+ fr->filter_function = function;
88
+ fr->filter_function_userdata = userdata;
89
+ }
90
+
91
+ /* Add to list of received friend requests. */
92
+ static void addto_receivedlist(Friend_Requests *fr, const uint8_t *client_id)
93
+ {
94
+ if (fr->received_requests_index >= MAX_RECEIVED_STORED)
95
+ fr->received_requests_index = 0;
96
+
97
+ id_copy(fr->received_requests[fr->received_requests_index], client_id);
98
+ ++fr->received_requests_index;
99
+ }
100
+
101
+ /* Check if a friend request was already received.
102
+ *
103
+ * return 0 if it did not.
104
+ * return 1 if it did.
105
+ */
106
+ static int request_received(Friend_Requests *fr, const uint8_t *client_id)
107
+ {
108
+ uint32_t i;
109
+
110
+ for (i = 0; i < MAX_RECEIVED_STORED; ++i)
111
+ if (id_equal(fr->received_requests[i], client_id))
112
+ return 1;
113
+
114
+ return 0;
115
+ }
116
+
117
+ /* Remove client id from received_requests list.
118
+ *
119
+ * return 0 if it removed it successfully.
120
+ * return -1 if it didn't find it.
121
+ */
122
+ int remove_request_received(Friend_Requests *fr, const uint8_t *client_id)
123
+ {
124
+ uint32_t i;
125
+
126
+ for (i = 0; i < MAX_RECEIVED_STORED; ++i) {
127
+ if (id_equal(fr->received_requests[i], client_id)) {
128
+ memset(fr->received_requests[i], 0, crypto_box_PUBLICKEYBYTES);
129
+ return 0;
130
+ }
131
+ }
132
+
133
+ return -1;
134
+ }
135
+
136
+
137
+ static int friendreq_handlepacket(void *object, const uint8_t *source_pubkey, const uint8_t *packet, uint32_t length)
138
+ {
139
+ Friend_Requests *fr = object;
140
+
141
+ if (length <= 1 + sizeof(fr->nospam) || length > ONION_CLIENT_MAX_DATA_SIZE)
142
+ return 1;
143
+
144
+ ++packet;
145
+ --length;
146
+
147
+ if (fr->handle_friendrequest_isset == 0)
148
+ return 1;
149
+
150
+ if (request_received(fr, source_pubkey))
151
+ return 1;
152
+
153
+ if (memcmp(packet, &fr->nospam, sizeof(fr->nospam)) != 0)
154
+ return 1;
155
+
156
+ if (fr->filter_function)
157
+ if ((*fr->filter_function)(source_pubkey, fr->filter_function_userdata) != 0)
158
+ return 1;
159
+
160
+ addto_receivedlist(fr, source_pubkey);
161
+
162
+ uint32_t message_len = length - sizeof(fr->nospam);
163
+ uint8_t message[message_len + 1];
164
+ memcpy(message, packet + sizeof(fr->nospam), message_len);
165
+ message[sizeof(message) - 1] = 0; /* Be sure the message is null terminated. */
166
+
167
+ (*fr->handle_friendrequest)(fr->handle_friendrequest_object, source_pubkey, message, message_len,
168
+ fr->handle_friendrequest_userdata);
169
+ return 0;
170
+ }
171
+
172
+ void friendreq_init(Friend_Requests *fr, Onion_Client *onion_c)
173
+ {
174
+ oniondata_registerhandler(onion_c, CRYPTO_PACKET_FRIEND_REQ, &friendreq_handlepacket, fr);
175
+ }
@@ -0,0 +1,83 @@
1
+ /* friend_requests.h
2
+ *
3
+ * Handle friend requests.
4
+ *
5
+ * Copyright (C) 2013 Tox project All Rights Reserved.
6
+ *
7
+ * This file is part of Tox.
8
+ *
9
+ * Tox is free software: you can redistribute it and/or modify
10
+ * it under the terms of the GNU General Public License as published by
11
+ * the Free Software Foundation, either version 3 of the License, or
12
+ * (at your option) any later version.
13
+ *
14
+ * Tox is distributed in the hope that it will be useful,
15
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
+ * GNU General Public License for more details.
18
+ *
19
+ * You should have received a copy of the GNU General Public License
20
+ * along with Tox. If not, see <http://www.gnu.org/licenses/>.
21
+ *
22
+ */
23
+
24
+ #ifndef FRIEND_REQUESTS_H
25
+ #define FRIEND_REQUESTS_H
26
+
27
+ #include "onion_client.h"
28
+
29
+ #define MAX_FRIEND_REQUEST_DATA_SIZE (ONION_CLIENT_MAX_DATA_SIZE - (1 + sizeof(uint32_t)))
30
+
31
+ typedef struct {
32
+ uint32_t nospam;
33
+ void (*handle_friendrequest)(void *, const uint8_t *, const uint8_t *, uint16_t, void *);
34
+ uint8_t handle_friendrequest_isset;
35
+ void *handle_friendrequest_object;
36
+ void *handle_friendrequest_userdata;
37
+
38
+ int (*filter_function)(const uint8_t *, void *);
39
+ void *filter_function_userdata;
40
+ /* NOTE: The following is just a temporary fix for the multiple friend requests received at the same time problem.
41
+ * TODO: Make this better (This will most likely tie in with the way we will handle spam.)
42
+ */
43
+
44
+ #define MAX_RECEIVED_STORED 32
45
+
46
+ uint8_t received_requests[MAX_RECEIVED_STORED][crypto_box_PUBLICKEYBYTES];
47
+ uint16_t received_requests_index;
48
+ } Friend_Requests;
49
+
50
+ /* Try to send a friendrequest to peer with public_key.
51
+ * data is the data in the request and length is the length.
52
+ * Maximum length of data is MAX_FRIEND_REQUEST_DATA_SIZE.
53
+ */
54
+ int send_friendrequest(const Onion_Client *onion_c, const uint8_t *public_key, uint32_t nospam_num, const uint8_t *data,
55
+ uint32_t length);
56
+ /* Set and get the nospam variable used to prevent one type of friend request spam. */
57
+ void set_nospam(Friend_Requests *fr, uint32_t num);
58
+ uint32_t get_nospam(const Friend_Requests *fr);
59
+
60
+ /* Remove client id from received_requests list.
61
+ *
62
+ * return 0 if it removed it successfully.
63
+ * return -1 if it didn't find it.
64
+ */
65
+ int remove_request_received(Friend_Requests *fr, const uint8_t *client_id);
66
+
67
+ /* Set the function that will be executed when a friend request for us is received.
68
+ * Function format is function(uint8_t * public_key, uint8_t * data, uint16_t length, void * userdata)
69
+ */
70
+ void callback_friendrequest(Friend_Requests *fr, void (*function)(void *, const uint8_t *, const uint8_t *, uint16_t,
71
+ void *), void *object, void *userdata);
72
+
73
+ /* Set the function used to check if a friend request should be displayed to the user or not.
74
+ * Function format is int function(uint8_t * public_key, void * userdata)
75
+ * It must return 0 if the request is ok (anything else if it is bad.)
76
+ */
77
+ void set_filter_function(Friend_Requests *fr, int (*function)(const uint8_t *, void *), void *userdata);
78
+
79
+ /* Sets up friendreq packet handlers. */
80
+ void friendreq_init(Friend_Requests *fr, Onion_Client *onion_c);
81
+
82
+
83
+ #endif
@@ -0,0 +1,837 @@
1
+ /* group_chats.c
2
+ *
3
+ * An implementation of massive text only group chats.
4
+ *
5
+ *
6
+ * Copyright (C) 2013 Tox project All Rights Reserved.
7
+ *
8
+ * This file is part of Tox.
9
+ *
10
+ * Tox is free software: you can redistribute it and/or modify
11
+ * it under the terms of the GNU General Public License as published by
12
+ * the Free Software Foundation, either version 3 of the License, or
13
+ * (at your option) any later version.
14
+ *
15
+ * Tox is distributed in the hope that it will be useful,
16
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
+ * GNU General Public License for more details.
19
+ *
20
+ * You should have received a copy of the GNU General Public License
21
+ * along with Tox. If not, see <http://www.gnu.org/licenses/>.
22
+ *
23
+ */
24
+
25
+ #ifdef HAVE_CONFIG_H
26
+ #include "config.h"
27
+ #endif
28
+
29
+ #include "DHT.h"
30
+ #include "assoc.h"
31
+ #include "group_chats.h"
32
+ #include "LAN_discovery.h"
33
+ #include "util.h"
34
+
35
+ #define GROUPCHAT_MAXDATA_LENGTH (MAX_CRYPTO_REQUEST_SIZE - (1 + crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES))
36
+ #define GROUPCHAT_MAXPLAINDATA_LENGTH (GROUPCHAT_MAXDATA_LENGTH - crypto_box_MACBYTES)
37
+
38
+ #define GROUP_MAX_SENDNODES (GROUP_CLOSE_CONNECTIONS * 2)
39
+
40
+ typedef struct {
41
+ uint64_t pingid;
42
+ //uint8_t client_id[crypto_box_PUBLICKEYBYTES];
43
+
44
+ } getnodes_data;
45
+
46
+ typedef struct {
47
+ uint8_t client_id[crypto_box_PUBLICKEYBYTES];
48
+ IP_Port ip_port;
49
+
50
+ } groupchat_nodes;
51
+
52
+ typedef struct {
53
+ uint64_t pingid;
54
+ groupchat_nodes nodes[GROUP_CLOSE_CONNECTIONS];
55
+ //uint8_t client_id[crypto_box_PUBLICKEYBYTES];
56
+
57
+ } sendnodes_data;
58
+
59
+ /*
60
+ * check if peer with client_id is in peer array.
61
+ *
62
+ * return peer number if peer is in chat.
63
+ * return -1 if peer is not in chat.
64
+ *
65
+ * TODO: make this more efficient.
66
+ */
67
+
68
+ static int peer_in_chat(const Group_Chat *chat, const uint8_t *client_id)
69
+ {
70
+ uint32_t i;
71
+
72
+ for (i = 0; i < chat->numpeers; ++i)
73
+ if (id_equal(chat->group[i].client_id, client_id))
74
+ return i;
75
+
76
+ return -1;
77
+ }
78
+
79
+ /* Compares client_id1 and client_id2 with client_id.
80
+ *
81
+ * return 0 if both are same distance.
82
+ * return 1 if client_id1 is closer.
83
+ * return 2 if client_id2 is closer.
84
+ */
85
+ static int id_closest_groupchats(const uint8_t *id, const uint8_t *id1, const uint8_t *id2)
86
+ {
87
+ size_t i;
88
+ uint8_t distance1, distance2;
89
+
90
+ for (i = 0; i < CLIENT_ID_SIZE; ++i) {
91
+
92
+ distance1 = abs(((int8_t *)id)[i] - ((int8_t *)id1)[i]);
93
+ distance2 = abs(((int8_t *)id)[i] - ((int8_t *)id2)[i]);
94
+
95
+ if (distance1 < distance2)
96
+ return 1;
97
+
98
+ if (distance1 > distance2)
99
+ return 2;
100
+ }
101
+
102
+ return 0;
103
+ }
104
+
105
+ #define BAD_GROUPNODE_TIMEOUT 30
106
+
107
+ /*
108
+ * Check if peer is closer to us that the other peers in the list and if the peer is in the list.
109
+ * Return the number of peers it is closer to if it is not in the closelist.
110
+ * Return -1 if the peer is in the closelist.
111
+ */
112
+
113
+ static int peer_okping(const Group_Chat *chat, const uint8_t *client_id)
114
+ {
115
+ uint32_t i, j = 0;
116
+
117
+ if (id_equal(chat->self_public_key, client_id))
118
+ return -1;
119
+
120
+ for (i = 0; i < GROUP_CLOSE_CONNECTIONS; ++i) {
121
+ if (is_timeout(chat->close[i].last_recv, BAD_GROUPNODE_TIMEOUT)) {
122
+ ++j;
123
+ continue;
124
+ }
125
+
126
+ /* Equal */
127
+ if (id_equal(chat->close[i].client_id, client_id))
128
+ return -1;
129
+
130
+ if (id_closest_groupchats(chat->self_public_key, chat->close[i].client_id, client_id) == 2)
131
+ ++j;
132
+ }
133
+
134
+ return j;
135
+ }
136
+
137
+
138
+
139
+ /* Attempt to add a peer to the close list.
140
+ * Update last_recv if it is in list.
141
+ * Attempt to add it to list if it is not.
142
+ *
143
+ * Return 0 if success.
144
+ * Return -1 if peer was not put in list/updated.
145
+ */
146
+ static int add_closepeer(Group_Chat *chat, const uint8_t *client_id, IP_Port ip_port)
147
+ {
148
+ uint32_t i;
149
+
150
+ for (i = 0; i < GROUP_CLOSE_CONNECTIONS; ++i) { /* Check if node is already in list, if it is update its last_recv */
151
+ if (id_equal(chat->close[i].client_id, client_id)) {
152
+ chat->close[i].last_recv = unix_time();
153
+ return 0;
154
+ }
155
+ }
156
+
157
+ for (i = 0; i < GROUP_CLOSE_CONNECTIONS; ++i) { /* Try replacing bad nodes first */
158
+ if (is_timeout(chat->close[i].last_recv, BAD_GROUPNODE_TIMEOUT)) {
159
+ id_copy(chat->close[i].client_id, client_id);
160
+ chat->close[i].ip_port = ip_port;
161
+ chat->close[i].last_recv = unix_time();
162
+ return 0;
163
+ }
164
+ }
165
+
166
+ for (i = 0; i < GROUP_CLOSE_CONNECTIONS; ++i) { /* Replace nodes if given one is closer. */
167
+ if (id_closest_groupchats(chat->self_public_key, chat->close[i].client_id, client_id) == 2) {
168
+ id_copy(chat->close[i].client_id, client_id);
169
+ chat->close[i].ip_port = ip_port;
170
+ chat->close[i].last_recv = unix_time();
171
+ return 0;
172
+ }
173
+ }
174
+
175
+ return -1;
176
+ }
177
+
178
+ static int send_groupchatpacket(const Group_Chat *chat, IP_Port ip_port, const uint8_t *public_key, const uint8_t *data,
179
+ uint32_t length, uint8_t request_id)
180
+ {
181
+ if (id_equal(chat->self_public_key, public_key))
182
+ return -1;
183
+
184
+ uint8_t packet[MAX_CRYPTO_REQUEST_SIZE];
185
+ int len = create_request(chat->self_public_key, chat->self_secret_key, packet, public_key, data, length, request_id);
186
+ packet[0] = NET_PACKET_GROUP_CHATS;
187
+
188
+ if (len == -1)
189
+ return -1;
190
+
191
+ if (sendpacket(chat->net, ip_port, packet, len) == len)
192
+ return 0;
193
+
194
+ return -1;
195
+
196
+ }
197
+
198
+ /*
199
+ * Send data to all peers in close peer list.
200
+ *
201
+ * return the number of peers the packet was sent to.
202
+ */
203
+ static uint8_t sendto_allpeers(const Group_Chat *chat, const uint8_t *data, uint16_t length, uint8_t request_id)
204
+ {
205
+ uint16_t sent = 0;
206
+ uint32_t i;
207
+
208
+ for (i = 0; i < GROUP_CLOSE_CONNECTIONS; ++i) {
209
+ if (ip_isset(&chat->close[i].ip_port.ip) &&
210
+ !is_timeout(chat->close[i].last_recv, BAD_GROUPNODE_TIMEOUT)) {
211
+ if (send_groupchatpacket(chat, chat->close[i].ip_port, chat->close[i].client_id,
212
+ data, length, request_id) == 0)
213
+ ++sent;
214
+ }
215
+ }
216
+
217
+ return sent;
218
+ }
219
+
220
+
221
+ /*
222
+ * Add a peer to the group chat.
223
+ *
224
+ * return peernum if success or peer already in chat.
225
+ * return -1 if error.
226
+ */
227
+ static int addpeer(Group_Chat *chat, const uint8_t *client_id)
228
+ {
229
+ int peernum = peer_in_chat(chat, client_id);
230
+
231
+ if (peernum != -1)
232
+ return peernum;
233
+
234
+ Group_Peer *temp;
235
+ temp = realloc(chat->group, sizeof(Group_Peer) * (chat->numpeers + 1));
236
+
237
+ if (temp == NULL)
238
+ return -1;
239
+
240
+ memset(&(temp[chat->numpeers]), 0, sizeof(Group_Peer));
241
+ chat->group = temp;
242
+
243
+ id_copy(chat->group[chat->numpeers].client_id, client_id);
244
+ chat->group[chat->numpeers].last_recv = unix_time();
245
+ chat->group[chat->numpeers].last_recv_msgping = unix_time();
246
+ ++chat->numpeers;
247
+
248
+ if (chat->peer_namelistchange != NULL)
249
+ (*chat->peer_namelistchange)(chat, chat->numpeers - 1, CHAT_CHANGE_PEER_ADD, chat->group_namelistchange_userdata);
250
+
251
+ return (chat->numpeers - 1);
252
+ }
253
+
254
+ /*
255
+ * Set a peer from the group chat to deleted.
256
+ *
257
+ * return 0 if success
258
+ * return -1 if error.
259
+ */
260
+ static int del_peer_set(Group_Chat *chat, int peernum)
261
+ {
262
+ if ((uint32_t)peernum >= chat->numpeers)
263
+ return -1;
264
+
265
+ chat->group[peernum].deleted = 1;
266
+ chat->group[peernum].deleted_time = unix_time();
267
+ return 0;
268
+ }
269
+
270
+ /*
271
+ * Delete a peer from the group chat.
272
+ *
273
+ * return 0 if success
274
+ * return -1 if error.
275
+ */
276
+ static int delpeer(Group_Chat *chat, int peernum)
277
+ {
278
+ if ((uint32_t)peernum >= chat->numpeers)
279
+ return -1;
280
+
281
+ uint32_t i;
282
+
283
+ for (i = 0; i < GROUP_CLOSE_CONNECTIONS; ++i) { /* If peer is in close list, time it out forcefully. */
284
+ if (id_equal(chat->close[i].client_id, chat->group[peernum].client_id)) {
285
+ chat->close[i].last_recv = 0;
286
+ break;
287
+ }
288
+ }
289
+
290
+ Group_Peer *temp;
291
+ --chat->numpeers;
292
+
293
+ if (chat->numpeers == 0) {
294
+ free(chat->group);
295
+ chat->group = NULL;
296
+ return 0;
297
+ }
298
+
299
+ if (chat->numpeers != (uint32_t)peernum)
300
+ memcpy(&chat->group[peernum], &chat->group[chat->numpeers], sizeof(Group_Peer));
301
+
302
+ temp = realloc(chat->group, sizeof(Group_Peer) * (chat->numpeers));
303
+
304
+ if (temp == NULL)
305
+ return -1;
306
+
307
+ chat->group = temp;
308
+
309
+ if (chat->peer_namelistchange != NULL) {
310
+ (*chat->peer_namelistchange)(chat, peernum, CHAT_CHANGE_PEER_DEL, chat->group_namelistchange_userdata);
311
+ }
312
+
313
+ return 0;
314
+ }
315
+
316
+ /* Copy the name of peernum to name.
317
+ * name must be at least MAX_NICK_BYTES long.
318
+ *
319
+ * return length of name if success
320
+ * return -1 if failure
321
+ */
322
+ int group_peername(const Group_Chat *chat, int peernum, uint8_t *name)
323
+ {
324
+ if ((uint32_t)peernum >= chat->numpeers)
325
+ return -1;
326
+
327
+ if (chat->group[peernum].nick_len == 0) {
328
+ /* memcpy(name, "NSA agent", 10); */ /* Srsly? */ /* Kindly remind the user that someone with no name might be a moronic NSA agent.*/
329
+ name[0] = 0;
330
+ return 0;
331
+ }
332
+
333
+ memcpy(name, chat->group[peernum].nick, chat->group[peernum].nick_len);
334
+ return chat->group[peernum].nick_len;
335
+ }
336
+
337
+ static void setnick(Group_Chat *chat, int peernum, const uint8_t *contents, uint16_t contents_len)
338
+ {
339
+ if (contents_len > MAX_NICK_BYTES || contents_len == 0)
340
+ return;
341
+
342
+ /* same name as already stored? */
343
+ if (chat->group[peernum].nick_len == contents_len)
344
+ if (!memcmp(chat->group[peernum].nick, contents, contents_len))
345
+ return;
346
+
347
+ memcpy(chat->group[peernum].nick, contents, contents_len);
348
+ chat->group[peernum].nick_len = contents_len;
349
+
350
+ if (chat->peer_namelistchange != NULL)
351
+ (*chat->peer_namelistchange)(chat, peernum, CHAT_CHANGE_PEER_NAME, chat->group_namelistchange_userdata);
352
+ }
353
+
354
+ /* min time between pings sent to one peer in seconds */
355
+ /* TODO: move this to global section */
356
+ #define GROUP_PING_TIMEOUT 5
357
+
358
+ static int send_getnodes(const Group_Chat *chat, IP_Port ip_port, int peernum)
359
+ {
360
+ if ((uint32_t)peernum >= chat->numpeers)
361
+ return -1;
362
+
363
+ if (!is_timeout(chat->group[peernum].last_pinged, GROUP_PING_TIMEOUT))
364
+ return -1;
365
+
366
+ getnodes_data contents;
367
+ contents.pingid = random_64b();
368
+
369
+ chat->group[peernum].last_pinged = unix_time();
370
+ chat->group[peernum].pingid = contents.pingid;
371
+ chat->group[peernum].ping_via = ip_port;
372
+
373
+ if (chat->assoc) {
374
+ IPPTs ippts;
375
+ ippts.timestamp = unix_time();
376
+ ippts.ip_port = ip_port;
377
+
378
+ Assoc_add_entry(chat->assoc, chat->group[peernum].client_id, &ippts, NULL, 1);
379
+ }
380
+
381
+ return send_groupchatpacket(chat, ip_port, chat->group[peernum].client_id, (uint8_t *)&contents, sizeof(contents),
382
+ CRYPTO_PACKET_GROUP_CHAT_GET_NODES);
383
+ }
384
+
385
+ static int send_sendnodes(const Group_Chat *chat, IP_Port ip_port, int peernum, uint64_t pingid)
386
+ {
387
+ if ((uint32_t)peernum >= chat->numpeers)
388
+ return -1;
389
+
390
+ sendnodes_data contents;
391
+ contents.pingid = pingid;
392
+ uint32_t i, j = 0;
393
+
394
+ for (i = 0; i < GROUP_CLOSE_CONNECTIONS; ++i) {
395
+ if (!is_timeout(chat->close[i].last_recv, BAD_GROUPNODE_TIMEOUT)) {
396
+ id_copy(contents.nodes[j].client_id, chat->close[i].client_id);
397
+ contents.nodes[j].ip_port = chat->close[i].ip_port;
398
+ to_net_family(&contents.nodes[j].ip_port.ip);
399
+ ++j;
400
+ }
401
+ }
402
+
403
+ return send_groupchatpacket(chat, ip_port, chat->group[peernum].client_id, (uint8_t *)&contents,
404
+ sizeof(contents.pingid) + sizeof(groupchat_nodes) * j, CRYPTO_PACKET_GROUP_CHAT_SEND_NODES);
405
+ }
406
+
407
+ static int handle_getnodes(const Group_Chat *chat, IP_Port source, int peernum, const uint8_t *data, uint32_t len)
408
+ {
409
+ if (len != sizeof(getnodes_data))
410
+ return 1;
411
+
412
+ if ((uint32_t)peernum >= chat->numpeers)
413
+ return 1;
414
+
415
+ getnodes_data contents;
416
+ memcpy(&contents, data, sizeof(contents));
417
+ send_sendnodes(chat, source, peernum, contents.pingid);
418
+
419
+ if (peer_okping(chat, chat->group[peernum].client_id) > 0)
420
+ send_getnodes(chat, source, peernum);
421
+
422
+ return 0;
423
+ }
424
+
425
+ static int handle_sendnodes(Group_Chat *chat, IP_Port source, int peernum, const uint8_t *data, uint32_t len)
426
+ {
427
+ if ((uint32_t)peernum >= chat->numpeers)
428
+ return 1;
429
+
430
+ if (len > sizeof(sendnodes_data) || len < sizeof(uint64_t))
431
+ return 1;
432
+
433
+ if ((len - sizeof(uint64_t)) % sizeof(groupchat_nodes) != 0)
434
+ return 1;
435
+
436
+ if (is_timeout(chat->group[peernum].last_pinged, GROUP_PING_TIMEOUT))
437
+ return 1;
438
+
439
+ sendnodes_data contents;
440
+ memcpy(&contents, data, len);
441
+
442
+ if (contents.pingid != chat->group[peernum].pingid)
443
+ return 1;
444
+
445
+ uint16_t numnodes = (len - sizeof(contents.pingid)) / sizeof(groupchat_nodes);
446
+ uint32_t i;
447
+
448
+ IPPTs ippts_send;
449
+ ippts_send.timestamp = unix_time();
450
+
451
+ for (i = 0; i < numnodes; ++i) {
452
+ if (peer_okping(chat, contents.nodes[i].client_id) > 0) {
453
+ int peern = peer_in_chat(chat, contents.nodes[i].client_id);
454
+
455
+ if (peern == -1) { /*NOTE: This is just for testing and will be removed later.*/
456
+ peern = addpeer(chat, contents.nodes[i].client_id);
457
+ }
458
+
459
+ if (peern == -1)
460
+ continue;
461
+
462
+ to_host_family(&contents.nodes[i].ip_port.ip);
463
+ send_getnodes(chat, contents.nodes[i].ip_port, peern);
464
+
465
+ if (chat->assoc) {
466
+ ippts_send.ip_port = contents.nodes[i].ip_port;
467
+ Assoc_add_entry(chat->assoc, contents.nodes[i].client_id, &ippts_send, NULL, 0);
468
+ }
469
+ }
470
+ }
471
+
472
+ add_closepeer(chat, chat->group[peernum].client_id, source);
473
+
474
+ return 0;
475
+ }
476
+
477
+ #define GROUP_DATA_MIN_SIZE (crypto_box_PUBLICKEYBYTES + sizeof(uint32_t) + 1)
478
+ static void send_names_new_peer(Group_Chat *chat);
479
+
480
+ static int handle_data(Group_Chat *chat, const uint8_t *data, uint32_t len)
481
+ {
482
+ if (len < GROUP_DATA_MIN_SIZE)
483
+ return 1;
484
+
485
+ //TODO:
486
+ int peernum = peer_in_chat(chat, data);
487
+
488
+ if (peernum == -1) { /*NOTE: This is just for testing and will be removed later.*/
489
+ if (data[crypto_box_PUBLICKEYBYTES + sizeof(uint32_t)] != GROUP_CHAT_QUIT)
490
+ peernum = addpeer(chat, data);
491
+ }
492
+
493
+ if (peernum == -1)
494
+ return 1;
495
+
496
+ if (chat->group[peernum].deleted)
497
+ return 1;
498
+
499
+ /* Spam prevention (1 message per peer per second limit.)
500
+
501
+ if (chat->group[peernum].last_recv == temp_time)
502
+ return 1;
503
+ */
504
+ chat->group[peernum].last_recv = unix_time();
505
+
506
+ uint32_t message_num;
507
+ memcpy(&message_num, data + crypto_box_PUBLICKEYBYTES, sizeof(uint32_t));
508
+ message_num = ntohl(message_num);
509
+
510
+ if (chat->group[peernum].last_message_number == 0) {
511
+ chat->group[peernum].last_message_number = message_num;
512
+ } else if (message_num - chat->group[peernum].last_message_number > 64 ||
513
+ message_num == chat->group[peernum].last_message_number)
514
+ return 1;
515
+
516
+ chat->group[peernum].last_message_number = message_num;
517
+
518
+ int handled = 1;
519
+ const uint8_t *contents = data + GROUP_DATA_MIN_SIZE;
520
+ uint16_t contents_len = len - GROUP_DATA_MIN_SIZE;
521
+
522
+ switch (data[crypto_box_PUBLICKEYBYTES + sizeof(message_num)]) {
523
+ case GROUP_CHAT_PING: /* If message is ping */
524
+ if (contents_len != 0)
525
+ return 1;
526
+
527
+ chat->group[peernum].last_recv_msgping = unix_time();
528
+ break;
529
+
530
+ case GROUP_CHAT_NEW_PEER: /* If message is new peer */
531
+ if (contents_len != crypto_box_PUBLICKEYBYTES)
532
+ return 1;
533
+
534
+ addpeer(chat, contents);
535
+ send_names_new_peer(chat);
536
+ break;
537
+
538
+ case GROUP_CHAT_QUIT: /* If peer tells us he is quitting */
539
+ if (contents_len != 0)
540
+ return 1;
541
+
542
+ del_peer_set(chat, peernum);
543
+ break;
544
+
545
+ case GROUP_CHAT_PEER_NICK:
546
+ if (contents_len > MAX_NICK_BYTES || contents_len == 0)
547
+ return 1;
548
+
549
+ setnick(chat, peernum, contents, contents_len);
550
+ break;
551
+
552
+ case GROUP_CHAT_CHAT_MESSAGE: /* If message is chat message */
553
+ if (chat->group_message != NULL)
554
+ (*chat->group_message)(chat, peernum, contents, contents_len, chat->group_message_userdata);
555
+
556
+ break;
557
+
558
+ case GROUP_CHAT_ACTION: /* if message is a peer action */
559
+ if (chat->group_action != NULL)
560
+ (*chat->group_action)(chat, peernum, contents, contents_len, chat->group_action_userdata);
561
+
562
+ break;
563
+
564
+ default:
565
+ handled = 0;
566
+ break;
567
+
568
+ }
569
+
570
+ if (handled == 1) {
571
+ sendto_allpeers(chat, data, len, CRYPTO_PACKET_GROUP_CHAT_BROADCAST);
572
+ return 0;
573
+ }
574
+
575
+ return 1;
576
+ }
577
+
578
+ static uint8_t send_data(Group_Chat *chat, const uint8_t *data, uint32_t len, uint8_t message_id)
579
+ {
580
+ if (len + GROUP_DATA_MIN_SIZE > MAX_CRYPTO_REQUEST_SIZE) /*NOTE: not the real maximum len.*/
581
+ return 1;
582
+
583
+ uint8_t packet[MAX_CRYPTO_REQUEST_SIZE];
584
+ ++chat->message_number;
585
+
586
+ if (chat->message_number == 0)
587
+ chat->message_number = 1;
588
+
589
+ uint32_t message_num = htonl(chat->message_number);
590
+ //TODO
591
+ id_copy(packet, chat->self_public_key);
592
+ memcpy(packet + crypto_box_PUBLICKEYBYTES, &message_num, sizeof(message_num));
593
+
594
+ if (len != 0)
595
+ memcpy(packet + GROUP_DATA_MIN_SIZE, data, len);
596
+
597
+ packet[crypto_box_PUBLICKEYBYTES + sizeof(message_num)] = message_id;
598
+ return sendto_allpeers(chat, packet, len + GROUP_DATA_MIN_SIZE, CRYPTO_PACKET_GROUP_CHAT_BROADCAST);
599
+ }
600
+ /*
601
+ * Handle get nodes group packet.
602
+ *
603
+ * return 0 if handled correctly.
604
+ * return 1 if error.
605
+ */
606
+
607
+ int handle_groupchatpacket(Group_Chat *chat, IP_Port source, const uint8_t *packet, uint32_t length)
608
+ {
609
+ if (length > MAX_CRYPTO_REQUEST_SIZE)
610
+ return 1;
611
+
612
+ uint8_t public_key[crypto_box_PUBLICKEYBYTES];
613
+ uint8_t data[MAX_CRYPTO_REQUEST_SIZE];
614
+ uint8_t number;
615
+ int len = handle_request(chat->self_public_key, chat->self_secret_key, public_key, data, &number, packet, length);
616
+
617
+ if (len <= 0)
618
+ return 1;
619
+
620
+ if (id_equal(chat->self_public_key, public_key))
621
+ return 1;
622
+
623
+ int peernum = peer_in_chat(chat, public_key);
624
+
625
+ if (peernum == -1)
626
+ return 1;
627
+
628
+ switch (number) {
629
+ case CRYPTO_PACKET_GROUP_CHAT_GET_NODES:
630
+ return handle_getnodes(chat, source, peernum, data, len);
631
+
632
+ case CRYPTO_PACKET_GROUP_CHAT_SEND_NODES:
633
+ return handle_sendnodes(chat, source, peernum, data, len);
634
+
635
+ case CRYPTO_PACKET_GROUP_CHAT_BROADCAST:
636
+ return handle_data(chat, data, len);
637
+
638
+ default:
639
+ return 1;
640
+ }
641
+
642
+ return 1;
643
+ }
644
+
645
+ uint32_t group_sendmessage(Group_Chat *chat, const uint8_t *message, uint32_t length)
646
+ {
647
+ return send_data(chat, message, length, GROUP_CHAT_CHAT_MESSAGE); //TODO: better return values?
648
+ }
649
+
650
+ uint32_t group_sendaction(Group_Chat *chat, const uint8_t *action, uint32_t length)
651
+ {
652
+ return send_data(chat, action, length, GROUP_CHAT_ACTION);
653
+ }
654
+
655
+ /*
656
+ * Send id/nick combo to the group.
657
+ *
658
+ * returns the number of peers it has sent it to.
659
+ */
660
+ static uint32_t group_send_nick(Group_Chat *chat, uint8_t *nick, uint16_t nick_len)
661
+ {
662
+ if (nick_len > MAX_NICK_BYTES)
663
+ return 0;
664
+
665
+ return send_data(chat, nick, nick_len, GROUP_CHAT_PEER_NICK);
666
+ }
667
+
668
+ int set_nick(Group_Chat *chat, const uint8_t *nick, uint16_t nick_len)
669
+ {
670
+ if (nick_len > MAX_NICK_BYTES || nick_len == 0)
671
+ return -1;
672
+
673
+ memcpy(chat->nick, nick, nick_len);
674
+ chat->nick_len = nick_len;
675
+ group_send_nick(chat, chat->nick, chat->nick_len);
676
+ return 0;
677
+ }
678
+
679
+ uint32_t group_newpeer(Group_Chat *chat, const uint8_t *client_id)
680
+ {
681
+ addpeer(chat, client_id);
682
+ return send_data(chat, client_id, crypto_box_PUBLICKEYBYTES, GROUP_CHAT_NEW_PEER); //TODO: better return values?
683
+ }
684
+
685
+ void callback_groupmessage(Group_Chat *chat, void (*function)(Group_Chat *chat, int, const uint8_t *, uint16_t, void *),
686
+ void *userdata)
687
+ {
688
+ chat->group_message = function;
689
+ chat->group_message_userdata = userdata;
690
+ }
691
+
692
+ void callback_groupaction(Group_Chat *chat, void (*function)(Group_Chat *chat, int, const uint8_t *, uint16_t, void *),
693
+ void *userdata)
694
+ {
695
+ chat->group_action = function;
696
+ chat->group_action_userdata = userdata;
697
+ }
698
+
699
+ void callback_namelistchange(Group_Chat *chat, void (*function)(Group_Chat *chat, int peer, uint8_t change, void *),
700
+ void *userdata)
701
+ {
702
+ chat->peer_namelistchange = function;
703
+ chat->group_namelistchange_userdata = userdata;
704
+ }
705
+
706
+ uint32_t group_numpeers(const Group_Chat *chat)
707
+ {
708
+ return chat->numpeers;
709
+ }
710
+
711
+ uint32_t group_client_names(const Group_Chat *chat, uint8_t names[][MAX_NICK_BYTES], uint16_t lengths[],
712
+ uint16_t length)
713
+ {
714
+ uint32_t i;
715
+
716
+ for (i = 0; i < chat->numpeers && i < length; ++i) {
717
+ lengths[i] = group_peername(chat, i, names[i]);
718
+ }
719
+
720
+ return i;
721
+ }
722
+
723
+ Group_Chat *new_groupchat(Networking_Core *net)
724
+ {
725
+ unix_time_update();
726
+
727
+ if (net == 0)
728
+ return 0;
729
+
730
+ Group_Chat *chat = calloc(1, sizeof(Group_Chat));
731
+ chat->net = net;
732
+ crypto_box_keypair(chat->self_public_key, chat->self_secret_key);
733
+
734
+ /* (2^4) * 5 = 80 entries seems to be a moderate size */
735
+ chat->assoc = new_Assoc(4, 5, chat->self_public_key);
736
+
737
+ return chat;
738
+ }
739
+
740
+ #define NODE_PING_INTERVAL 10
741
+
742
+ static void ping_close(Group_Chat *chat)
743
+ {
744
+ uint32_t i;
745
+
746
+ for (i = 0; i < GROUP_CLOSE_CONNECTIONS; ++i) {
747
+ if (!is_timeout(chat->close[i].last_recv, BAD_GROUPNODE_TIMEOUT)) {
748
+ int peernum = peer_in_chat(chat, chat->close[i].client_id);
749
+
750
+ if (peernum == -1)
751
+ continue;
752
+
753
+ if (is_timeout(chat->group[peernum].last_pinged, NODE_PING_INTERVAL))
754
+ send_getnodes(chat, chat->close[i].ip_port, peernum);
755
+ }
756
+ }
757
+ }
758
+
759
+ /* Interval in seconds to send ping messages */
760
+ #define GROUP_PING_INTERVAL 30
761
+
762
+ static void ping_group(Group_Chat *chat)
763
+ {
764
+ if (is_timeout(chat->last_sent_ping, GROUP_PING_INTERVAL)) {
765
+ if (send_data(chat, 0, 0, GROUP_CHAT_PING) != 0) /* Ping */
766
+ chat->last_sent_ping = unix_time();
767
+ }
768
+ }
769
+
770
+ #define DEL_PEER_DELAY 3
771
+ static void del_dead_peers(Group_Chat *chat)
772
+ {
773
+ uint32_t i;
774
+
775
+ for (i = 0; i < chat->numpeers; ++i) {
776
+ if (is_timeout(chat->group[i].last_recv_msgping, GROUP_PING_INTERVAL * 4)) {
777
+ delpeer(chat, i);
778
+ }
779
+
780
+ if (chat->group == NULL || i >= chat->numpeers)
781
+ break;
782
+
783
+ if (chat->group[i].deleted) {
784
+ if (is_timeout(chat->group[i].deleted_time, DEL_PEER_DELAY))
785
+ delpeer(chat, i);
786
+ }
787
+ }
788
+ }
789
+
790
+ #define NICK_SEND_INTERVAL 180
791
+ static void send_names_new_peer(Group_Chat *chat)
792
+ {
793
+ group_send_nick(chat, chat->nick, chat->nick_len);
794
+ chat->last_sent_nick = (unix_time() - NICK_SEND_INTERVAL) + 15;
795
+ }
796
+ static void send_names(Group_Chat *chat)
797
+ {
798
+ /* send own nick from time to time, to let newly added peers be informed
799
+ * first time only: use a shorter timeframe, because we might not be in our own
800
+ * peer list yet */
801
+ if (is_timeout(chat->last_sent_nick, 180))
802
+ if (group_send_nick(chat, chat->nick, chat->nick_len) > 0) {
803
+ if (!chat->last_sent_nick)
804
+ chat->last_sent_nick = (unix_time() - NICK_SEND_INTERVAL) + 10;
805
+ else
806
+ chat->last_sent_nick = unix_time();
807
+ }
808
+ }
809
+
810
+ void do_groupchat(Group_Chat *chat)
811
+ {
812
+ unix_time_update();
813
+ ping_close(chat);
814
+ ping_group(chat);
815
+ /* TODO: Maybe run this less? */
816
+ del_dead_peers(chat);
817
+ send_names(chat);
818
+ }
819
+
820
+ void kill_groupchat(Group_Chat *chat)
821
+ {
822
+ send_data(chat, 0, 0, GROUP_CHAT_QUIT);
823
+ kill_Assoc(chat->assoc);
824
+ free(chat->group);
825
+ free(chat);
826
+ }
827
+
828
+ void chat_bootstrap(Group_Chat *chat, IP_Port ip_port, const uint8_t *client_id)
829
+ {
830
+ send_getnodes(chat, ip_port, addpeer(chat, client_id));
831
+ }
832
+
833
+ void chat_bootstrap_nonlazy(Group_Chat *chat, IP_Port ip_port, const uint8_t *client_id)
834
+ {
835
+ send_getnodes(chat, ip_port, addpeer(chat, client_id));
836
+ add_closepeer(chat, client_id, ip_port);
837
+ }