diff options
111 files changed, 16802 insertions, 7023 deletions
@@ -68,3 +68,6 @@ nbproject | |||
68 | # Android buildscript | 68 | # Android buildscript |
69 | android-toolchain-* | 69 | android-toolchain-* |
70 | toxcore-android-* | 70 | toxcore-android-* |
71 | |||
72 | # cscope files list | ||
73 | cscope.files | ||
diff --git a/.travis.yml b/.travis.yml index ca14c884..c90a92f2 100644 --- a/.travis.yml +++ b/.travis.yml | |||
@@ -7,7 +7,7 @@ before_script: | |||
7 | #installing libsodium, needed for Core | 7 | #installing libsodium, needed for Core |
8 | - git clone git://github.com/jedisct1/libsodium.git > /dev/null | 8 | - git clone git://github.com/jedisct1/libsodium.git > /dev/null |
9 | - cd libsodium | 9 | - cd libsodium |
10 | - git checkout tags/0.4.2 > /dev/null | 10 | - git checkout tags/1.0.0 > /dev/null |
11 | - ./autogen.sh > /dev/null | 11 | - ./autogen.sh > /dev/null |
12 | - ./configure > /dev/null | 12 | - ./configure > /dev/null |
13 | - make check -j3 > /dev/null | 13 | - make check -j3 > /dev/null |
@@ -12,8 +12,8 @@ without warranty of any kind. | |||
12 | Basic Installation | 12 | Basic Installation |
13 | ================== | 13 | ================== |
14 | 14 | ||
15 | Briefly, the shell commands `./configure; make; make install' should | 15 | Briefly, the shell command `./configure && make && make install' |
16 | configure, build, and install this package. The following | 16 | should configure, build, and install this package. The following |
17 | more-detailed instructions are generic; see the `README' file for | 17 | more-detailed instructions are generic; see the `README' file for |
18 | instructions specific to this package. Some packages provide this | 18 | instructions specific to this package. Some packages provide this |
19 | `INSTALL' file but do not implement all of the features documented | 19 | `INSTALL' file but do not implement all of the features documented |
@@ -53,14 +53,16 @@ pkg install net-im/tox | |||
53 | ``` | 53 | ``` |
54 | Note, if you install from ports select NaCl for performance, and sodium if you want it to be portable. | 54 | Note, if you install from ports select NaCl for performance, and sodium if you want it to be portable. |
55 | 55 | ||
56 | **For A/V support, also install the dependences listed in the [libtoxav] (#libtoxav) section.** | ||
57 | |||
56 | You should get and install [libsodium](https://github.com/jedisct1/libsodium): | 58 | You should get and install [libsodium](https://github.com/jedisct1/libsodium): |
57 | ```bash | 59 | ```bash |
58 | git clone git://github.com/jedisct1/libsodium.git | 60 | git clone git://github.com/jedisct1/libsodium.git |
59 | cd libsodium | 61 | cd libsodium |
60 | git checkout tags/0.5.0 | 62 | git checkout tags/1.0.0 |
61 | ./autogen.sh | 63 | ./autogen.sh |
62 | ./configure && make check | 64 | ./configure && make check |
63 | sudo checkinstall --install --pkgname libsodium --pkgversion 0.5.0 --nodoc | 65 | sudo checkinstall --install --pkgname libsodium --pkgversion 1.0.0 --nodoc |
64 | sudo ldconfig | 66 | sudo ldconfig |
65 | cd .. | 67 | cd .. |
66 | ``` | 68 | ``` |
@@ -72,7 +74,7 @@ this will install the libs to /usr/local/lib and the headers to /usr/local/inclu | |||
72 | ```bash | 74 | ```bash |
73 | git clone git://github.com/jedisct1/libsodium.git | 75 | git clone git://github.com/jedisct1/libsodium.git |
74 | cd libsodium | 76 | cd libsodium |
75 | git checkout tags/0.5.0 | 77 | git checkout tags/1.0.0 |
76 | ./autogen.sh | 78 | ./autogen.sh |
77 | ./configure | 79 | ./configure |
78 | make check | 80 | make check |
@@ -88,8 +90,8 @@ sudo ldconfig | |||
88 | 90 | ||
89 | Then clone this repo and generate makefile: | 91 | Then clone this repo and generate makefile: |
90 | ```bash | 92 | ```bash |
91 | git clone git://github.com/irungentoo/ProjectTox-Core.git | 93 | git clone git://github.com/irungentoo/toxcore.git |
92 | cd ProjectTox-Core | 94 | cd toxcore |
93 | autoreconf -i | 95 | autoreconf -i |
94 | ./configure | 96 | ./configure |
95 | make | 97 | make |
@@ -103,6 +105,8 @@ sudo make install | |||
103 | You need the latest XCode with the Developer Tools (Preferences -> Downloads -> Command Line Tools). | 105 | You need the latest XCode with the Developer Tools (Preferences -> Downloads -> Command Line Tools). |
104 | The following libraries are required along with libsodium and cmake for Mountain Lion and XCode 4.6.3 install libtool, automake and autoconf. You can download them with Homebrew, or install them manually. | 106 | The following libraries are required along with libsodium and cmake for Mountain Lion and XCode 4.6.3 install libtool, automake and autoconf. You can download them with Homebrew, or install them manually. |
105 | 107 | ||
108 | **Note: OS X users can also install Toxcore using [osx_build_script_toxcore.sh](other/osx_build_script_toxcore.sh)** | ||
109 | |||
106 | There are no binaries/executables going to /bin/ or /usr/bin/ now. Everything is compiled and ran from the inside your local branch. See [Usage](#usage) below. | 110 | There are no binaries/executables going to /bin/ or /usr/bin/ now. Everything is compiled and ran from the inside your local branch. See [Usage](#usage) below. |
107 | <a name="homebrew" /> | 111 | <a name="homebrew" /> |
108 | ####Homebrew: | 112 | ####Homebrew: |
@@ -118,8 +122,8 @@ brew install libtool automake autoconf libsodium check | |||
118 | ``` | 122 | ``` |
119 | Then clone this repo and generate makefile: | 123 | Then clone this repo and generate makefile: |
120 | ```bash | 124 | ```bash |
121 | git clone git://github.com/irungentoo/ProjectTox-Core.git | 125 | git clone git://github.com/irungentoo/toxcore.git |
122 | cd ProjectTox-Core | 126 | cd toxcore |
123 | autoreconf -i | 127 | autoreconf -i |
124 | ./configure | 128 | ./configure |
125 | make | 129 | make |
@@ -135,7 +139,7 @@ brew list libsodium | |||
135 | 139 | ||
136 | Configure include and lib folder and build again: | 140 | Configure include and lib folder and build again: |
137 | ```bash | 141 | ```bash |
138 | ./configure --with-libsodium-headers=/usr/local/Cellar/libsodium/0.4.5/include/ --with-libsodium-libs=/usr/local/Cellar/libsodium/0.4.5/lib/ | 142 | ./configure --with-libsodium-headers=/usr/local/Cellar/libsodium/1.0.0/include/ --with-libsodium-libs=/usr/local/Cellar/libsodium/1.0.0/lib/ |
139 | make | 143 | make |
140 | make install | 144 | make install |
141 | ``` | 145 | ``` |
@@ -150,12 +154,34 @@ Grab the following packages: | |||
150 | * https://gnu.org/software/automake/ | 154 | * https://gnu.org/software/automake/ |
151 | * https://github.com/jedisct1/libsodium | 155 | * https://github.com/jedisct1/libsodium |
152 | * http://check.sourceforge.net/ | 156 | * http://check.sourceforge.net/ |
153 | * http://yasm.tortall.net/Download.html | 157 | * http://yasm.tortall.net/Download.html (install before libvpx) |
154 | * https://code.google.com/p/webm/downloads/list | 158 | * https://code.google.com/p/webm/downloads/list |
155 | * http://www.opus-codec.org/downloads/ | 159 | * http://www.opus-codec.org/downloads/ |
156 | * http://www.freedesktop.org/wiki/Software/pkg-config/ | 160 | * http://www.freedesktop.org/wiki/Software/pkg-config/ |
157 | 161 | ||
158 | You must install yasm before installing libvpx, otherwise libvpx will fail to make correctly. | 162 | Macports: (https://www.macports.org/) |
163 | All toxcore dependencies can be installed from MacPorts. This is often easier on PowerPC Macs, | ||
164 | and any version of OS X prior to 10.6, since Homebrew is supported on 10.6 and up, but not much | ||
165 | (or at all) on older systems. A few packages have slightly different names from the corresponding | ||
166 | package in Debian. | ||
167 | |||
168 | Same: libtool autoconf automake libsodium check yasm | ||
169 | Different: libvpx (webm) libopus pkgconfig gettext | ||
170 | |||
171 | (the libintl, from gettext, built into OS X 10.5 is missing libintl_setlocale, but the Macports build has it) | ||
172 | |||
173 | Verify where libintl is on your system: (MacPorts puts it in /opt/local) | ||
174 | $ for d in /usr/local/lib /opt/local/lib /usr/lib /lib; do ls -l $d/libintl.*; done | ||
175 | |||
176 | Check if that copy has libintl_setlocale: | ||
177 | nm /opt/local/lib/libintl.8.dylib | grep _libintl_setlocale | ||
178 | |||
179 | Certain other tools may not be installed, or outdated, and should also be installed from MacPorts for simplicity: git cmake | ||
180 | |||
181 | If libsodium was installed with MacPorts, you may want to symlink the copy in /opt/local/lib to /usr/local/lib. That way you don't need special configure switches for toxcore to find libsodium, and every time MacPorts updates libsodium, the new version will be linked to toxcore every time you build: | ||
182 | ln -s /opt/local/lib/libsodium.dylib /usr/local/lib/libsodium.dylib | ||
183 | |||
184 | Much of the build can then be done as for other platforms: git clone, and so on. Differences will be noted with (OS X 10.5 specific) | ||
159 | 185 | ||
160 | pkg-config is important for enabling a/v support in tox core, failure to install pkg-config will prevent tox core form finding the required libopus/libvpx libraries. (pkg-config may not configure properly, if you get an error about GLIB, run configure with the following parameter, --with-internal-glib). | 186 | pkg-config is important for enabling a/v support in tox core, failure to install pkg-config will prevent tox core form finding the required libopus/libvpx libraries. (pkg-config may not configure properly, if you get an error about GLIB, run configure with the following parameter, --with-internal-glib). |
161 | 187 | ||
@@ -170,11 +196,23 @@ sudo make install | |||
170 | Compiling and installing Tox Core | 196 | Compiling and installing Tox Core |
171 | 197 | ||
172 | ```bash | 198 | ```bash |
173 | cd ProjectTox-Core | 199 | cd toxcore |
174 | autoreconf -i | 200 | autoreconf -i |
175 | ./configure | 201 | ./configure (OS X 10.5 specific) |
202 | ./configure CC="gcc -arch ppc -arch i386" CXX="g++ -arch ppc -arch i386" CPP="gcc -E" CXXCPP="g++ -E" | ||
176 | make | 203 | make |
177 | make install | 204 | make install (OS X 10.5 specific) |
205 | should be: sudo make install | ||
206 | If it worked, you should have all the toxcore dylibs in /usr/local/lib: (besides the four below, the rest are symlinks to these) | ||
207 | $ ls -la /usr/local/lib/libtox*.dylib | ||
208 | libtoxav.0.dylib | ||
209 | libtoxcore.0.dylib | ||
210 | libtoxdns.0.dylib | ||
211 | libtoxencryptsave.0.dylib | ||
212 | to check what CPU architecture they're compiled for: | ||
213 | $ lipo -i /usr/local/lib/libtoxencryptsave.0.dylib | ||
214 | You should now be able to move on to compiling Toxic/Venom or some other client application | ||
215 | There is also a shell script called "osx_build_script_toxcore.txt" which automates everything from "git pull" to "sudo make install", once the dependencies are already taken care of by MacPorts. | ||
178 | ``` | 216 | ``` |
179 | 217 | ||
180 | If after running ./configure you get an error about core being unable to find libsodium (and you have installed it) run the following in place of ./configure; | 218 | If after running ./configure you get an error about core being unable to find libsodium (and you have installed it) run the following in place of ./configure; |
@@ -318,7 +356,7 @@ Now we will build sodium crypto library: | |||
318 | ```bash | 356 | ```bash |
319 | git clone https://github.com/jedisct1/libsodium/ | 357 | git clone https://github.com/jedisct1/libsodium/ |
320 | cd libsodium | 358 | cd libsodium |
321 | git checkout tags/0.6.1 | 359 | git checkout tags/1.0.0 |
322 | ./autogen.sh | 360 | ./autogen.sh |
323 | ./configure --host="$WINDOWS_TOOLCHAIN" --prefix="$PREFIX_DIR" --disable-shared --enable-static | 361 | ./configure --host="$WINDOWS_TOOLCHAIN" --prefix="$PREFIX_DIR" --disable-shared --enable-static |
324 | make | 362 | make |
@@ -345,6 +383,7 @@ cd tmp | |||
345 | $WINDOWS_TOOLCHAIN-ar x ../lib/libtoxcore.a | 383 | $WINDOWS_TOOLCHAIN-ar x ../lib/libtoxcore.a |
346 | $WINDOWS_TOOLCHAIN-ar x ../lib/libtoxav.a | 384 | $WINDOWS_TOOLCHAIN-ar x ../lib/libtoxav.a |
347 | $WINDOWS_TOOLCHAIN-ar x ../lib/libtoxdns.a | 385 | $WINDOWS_TOOLCHAIN-ar x ../lib/libtoxdns.a |
386 | $WINDOWS_TOOLCHAIN-ar x ../lib/libtoxencryptsave.a | ||
348 | $WINDOWS_TOOLCHAIN-gcc -Wl,--export-all-symbols -Wl,--out-implib=libtox.dll.a -shared -o libtox.dll *.o ../lib/*.a /usr/$WINDOWS_TOOLCHAIN/lib/libwinpthread.a -liphlpapi -lws2_32 -static-libgcc | 387 | $WINDOWS_TOOLCHAIN-gcc -Wl,--export-all-symbols -Wl,--out-implib=libtox.dll.a -shared -o libtox.dll *.o ../lib/*.a /usr/$WINDOWS_TOOLCHAIN/lib/libwinpthread.a -liphlpapi -lws2_32 -static-libgcc |
349 | ``` | 388 | ``` |
350 | 389 | ||
@@ -372,10 +411,10 @@ When installing MinGW, make sure to select the MSYS option in the installer. | |||
372 | MinGW will install an "MinGW shell" (you should get a shortcut for it), make sure to perform all operations (i.e., generating/running configure script, compiling, etc.) from the MinGW shell. | 411 | MinGW will install an "MinGW shell" (you should get a shortcut for it), make sure to perform all operations (i.e., generating/running configure script, compiling, etc.) from the MinGW shell. |
373 | 412 | ||
374 | First download the source tarball from https://download.libsodium.org/libsodium/releases/ and build it. | 413 | First download the source tarball from https://download.libsodium.org/libsodium/releases/ and build it. |
375 | Assuming that you got the libsodium-0.5.0.tar.gz release: | 414 | Assuming that you got the libsodium-1.0.0.tar.gz release: |
376 | ```cmd | 415 | ```cmd |
377 | tar -zxvf libsodium-0.5.0.tar.gz | 416 | tar -zxvf libsodium-1.0.0.tar.gz |
378 | cd libsodium-0.5.0 | 417 | cd libsodium-1.0.0 |
379 | ./configure | 418 | ./configure |
380 | make | 419 | make |
381 | make install | 420 | make install |
@@ -384,12 +423,12 @@ cd .. | |||
384 | 423 | ||
385 | You can also use a precompiled win32 binary of libsodium, however you will have to place the files in places where they can be found, i.e., dll's go to /bin headers to /include and libraries to /lib directories in your MinGW shell. | 424 | You can also use a precompiled win32 binary of libsodium, however you will have to place the files in places where they can be found, i.e., dll's go to /bin headers to /include and libraries to /lib directories in your MinGW shell. |
386 | 425 | ||
387 | Next, install ProjectTox-Core library, should either clone this repo by using git, or just download a [zip of current Master branch](https://github.com/irungentoo/ProjectTox-Core/archive/master.zip) and extract it somewhere. | 426 | Next, install toxcore library, should either clone this repo by using git, or just download a [zip of current Master branch](https://github.com/irungentoo/toxcore/archive/master.zip) and extract it somewhere. |
388 | 427 | ||
389 | Assuming that you now have the sources in the ProjectTox-Core directory: | 428 | Assuming that you now have the sources in the toxcore directory: |
390 | 429 | ||
391 | ```cmd | 430 | ```cmd |
392 | cd ProjectTox-Core | 431 | cd toxcore |
393 | autoreconf -i | 432 | autoreconf -i |
394 | ./configure | 433 | ./configure |
395 | make | 434 | make |
@@ -440,12 +479,12 @@ There are 2 dependencies required for libtoxav: libopus and libvpx. If they are | |||
440 | 479 | ||
441 | Install on fedora: | 480 | Install on fedora: |
442 | ```bash | 481 | ```bash |
443 | yum install libopus-devel libvpx-devel | 482 | yum install opus-devel libvpx-devel |
444 | ``` | 483 | ``` |
445 | 484 | ||
446 | Install on ubuntu: | 485 | Install on ubuntu: |
447 | ```bash | 486 | ```bash |
448 | sudo apt-get install libopus-dev libvpx-dev | 487 | sudo apt-get install libopus-dev libvpx-dev pkg-config |
449 | ``` | 488 | ``` |
450 | If you get the "Unable to locate package libopus-dev" message, add the following ppa and try again: | 489 | If you get the "Unable to locate package libopus-dev" message, add the following ppa and try again: |
451 | ```bash | 490 | ```bash |
@@ -499,7 +538,7 @@ OS X homebrew: | |||
499 | brew install libconfig | 538 | brew install libconfig |
500 | ``` | 539 | ``` |
501 | OS X non-homebrew: | 540 | OS X non-homebrew: |
502 | Grab the following [package] (http://www.hyperrealm.com/libconfig/), uncompress and install | 541 | Grab the following [package](http://www.hyperrealm.com/libconfig/), uncompress and install |
503 | 542 | ||
504 | See this [readme](other/bootstrap_daemon/README.md) on how to set up the bootstrap daemon. | 543 | See this [readme](other/bootstrap_daemon/README.md) on how to set up the bootstrap daemon. |
505 | 544 | ||
@@ -3,9 +3,8 @@ | |||
3 | 3 | ||
4 | With the rise of governmental monitoring programs, Tox, a FOSS initiative, aims to be an easy to use, all-in-one communication platform that ensures their users full privacy and secure message delivery.<br /> <br /> | 4 | With the rise of governmental monitoring programs, Tox, a FOSS initiative, aims to be an easy to use, all-in-one communication platform that ensures their users full privacy and secure message delivery.<br /> <br /> |
5 | 5 | ||
6 | [**Website**](https://tox.im) **|** [**Download**](https://wiki.tox.im/Binaries) **|** [**Wiki**](https://wiki.tox.im/) **|** [**Blog**](https://blog.libtoxcore.so/) **|** [**FAQ**](https://wiki.tox.im/FAQ) **|** [**Binaries**](https://wiki.tox.im/Binaries) **|** [**Clients**](https://wiki.tox.im/Client) **|** [**Compiling**](/INSTALL.md) **|** | 6 | [**Website**](https://tox.im) **|** [**Wiki**](https://wiki.tox.im/) **|** [**Blog**](https://blog.tox.im/) **|** [**FAQ**](https://wiki.tox.im/FAQ) **|** [**Binaries/Downloads**](https://wiki.tox.im/Binaries) **|** [**Clients**](https://wiki.tox.im/Client) **|** [**Compiling**](/INSTALL.md) **|** |
7 | [**API**](https://libtoxcore.so/) **|** | 7 | [**API**](https://libtoxcore.so/) **|** [**Bugs**](http://tox.lighthouseapp.com/) **|** [**Help and Suggestions**](http://support.libtoxcore.so) **|** **IRC Channel:** [#tox@freenode](https://webchat.freenode.net/?channels=tox) |
8 | **IRC:** #tox@freenode | ||
9 | 8 | ||
10 | 9 | ||
11 | ## The Complex Stuff: | 10 | ## The Complex Stuff: |
@@ -22,12 +21,12 @@ Every peer is represented as a [byte string][String] (the public key [Tox ID] of | |||
22 | 21 | ||
23 | ## Q&A: | 22 | ## Q&A: |
24 | 23 | ||
25 | ### What are your goals of Tox? | 24 | ### What are your goals with Tox? |
26 | 25 | ||
27 | We want Tox to be as simple as possible while remaining as secure as possible. | 26 | We want Tox to be as simple as possible while remaining as secure as possible. |
28 | 27 | ||
29 | ### Why are you doing this? There are already a bunch of free Skype alternatives. | 28 | ### Why are you doing this? There are already a bunch of free Skype alternatives. |
30 | The goal of this project is to create a configuration-free P2P Skype replacement. Configuration-free means that the user will simply have to open the program and without any account configuration will be capable of adding people to his or her's friends list and start conversing with them. There are many so-called Skype replacements and all of them are either hard to configure for the normal user or suffer from being way too centralized. | 29 | The goal of this project is to create a configuration-free P2P Skype replacement. “Configuration-free” means that the user will simply have to open the program and will be capable of adding people and communicating with them without having to set up an account. There are many so-called Skype replacements, but all of them are either hard to configure for the normal user or suffer from being way too centralized. |
31 | 30 | ||
32 | ## TODO: | 31 | ## TODO: |
33 | - [TODO](/docs/TODO) | 32 | - [TODO](/docs/TODO) |
diff --git a/auto_tests/Makefile.inc b/auto_tests/Makefile.inc index c68f313b..d78a6a5a 100644 --- a/auto_tests/Makefile.inc +++ b/auto_tests/Makefile.inc | |||
@@ -1,7 +1,7 @@ | |||
1 | if BUILD_TESTS | 1 | if BUILD_TESTS |
2 | 2 | ||
3 | TESTS = messenger_autotest crypto_test network_test assoc_test onion_test TCP_test tox_test dht_autotest | 3 | TESTS = encryptsave_test messenger_autotest crypto_test network_test assoc_test onion_test TCP_test tox_test dht_autotest |
4 | check_PROGRAMS = messenger_autotest crypto_test network_test assoc_test onion_test TCP_test tox_test dht_autotest | 4 | check_PROGRAMS = encryptsave_test messenger_autotest crypto_test network_test assoc_test onion_test TCP_test tox_test dht_autotest |
5 | 5 | ||
6 | AUTOTEST_CFLAGS = \ | 6 | AUTOTEST_CFLAGS = \ |
7 | $(LIBSODIUM_CFLAGS) \ | 7 | $(LIBSODIUM_CFLAGS) \ |
@@ -12,6 +12,7 @@ AUTOTEST_LDADD = \ | |||
12 | $(LIBSODIUM_LDFLAGS) \ | 12 | $(LIBSODIUM_LDFLAGS) \ |
13 | $(NACL_LDFLAGS) \ | 13 | $(NACL_LDFLAGS) \ |
14 | libtoxcore.la \ | 14 | libtoxcore.la \ |
15 | libtoxencryptsave.la \ | ||
15 | $(LIBSODIUM_LIBS) \ | 16 | $(LIBSODIUM_LIBS) \ |
16 | $(NACL_OBJECTS) \ | 17 | $(NACL_OBJECTS) \ |
17 | $(NACL_LIBS) \ | 18 | $(NACL_LIBS) \ |
@@ -98,4 +99,12 @@ endif | |||
98 | 99 | ||
99 | endif | 100 | endif |
100 | 101 | ||
101 | EXTRA_DIST += $(top_srcdir)/auto_tests/friends_test.c \ No newline at end of file | 102 | |
103 | encryptsave_test_SOURCES = ../auto_tests/encryptsave_test.c | ||
104 | |||
105 | encryptsave_test_CFLAGS = $(AUTOTEST_CFLAGS) | ||
106 | |||
107 | encryptsave_test_LDADD = $(AUTOTEST_LDADD) | ||
108 | |||
109 | |||
110 | EXTRA_DIST += $(top_srcdir)/auto_tests/friends_test.c | ||
diff --git a/auto_tests/TCP_test.c b/auto_tests/TCP_test.c index 566013d7..e222cf01 100644 --- a/auto_tests/TCP_test.c +++ b/auto_tests/TCP_test.c | |||
@@ -118,6 +118,7 @@ START_TEST(test_basic) | |||
118 | ck_assert_msg(packet_resp_plain[0] == 1, "wrong packet id %u", packet_resp_plain[0]); | 118 | ck_assert_msg(packet_resp_plain[0] == 1, "wrong packet id %u", packet_resp_plain[0]); |
119 | ck_assert_msg(packet_resp_plain[1] == 0, "connection not refused %u", packet_resp_plain[1]); | 119 | ck_assert_msg(packet_resp_plain[1] == 0, "connection not refused %u", packet_resp_plain[1]); |
120 | ck_assert_msg(memcmp(packet_resp_plain + 2, f_public_key, crypto_box_PUBLICKEYBYTES) == 0, "key in packet wrong"); | 120 | ck_assert_msg(memcmp(packet_resp_plain + 2, f_public_key, crypto_box_PUBLICKEYBYTES) == 0, "key in packet wrong"); |
121 | kill_TCP_server(tcp_s); | ||
121 | } | 122 | } |
122 | END_TEST | 123 | END_TEST |
123 | 124 | ||
@@ -175,6 +176,12 @@ struct sec_TCP_con *new_TCP_con(TCP_Server *tcp_s) | |||
175 | return sec_c; | 176 | return sec_c; |
176 | } | 177 | } |
177 | 178 | ||
179 | void kill_TCP_con(struct sec_TCP_con *con) | ||
180 | { | ||
181 | kill_sock(con->sock); | ||
182 | free(con); | ||
183 | } | ||
184 | |||
178 | int write_packet_TCP_secure_connection(struct sec_TCP_con *con, uint8_t *data, uint16_t length) | 185 | int write_packet_TCP_secure_connection(struct sec_TCP_con *con, uint8_t *data, uint16_t length) |
179 | { | 186 | { |
180 | uint8_t packet[sizeof(uint16_t) + length + crypto_box_MACBYTES]; | 187 | uint8_t packet[sizeof(uint16_t) + length + crypto_box_MACBYTES]; |
@@ -290,6 +297,10 @@ START_TEST(test_some) | |||
290 | ck_assert_msg(len == sizeof(ping_packet), "wrong len %u", len); | 297 | ck_assert_msg(len == sizeof(ping_packet), "wrong len %u", len); |
291 | ck_assert_msg(data[0] == 5, "wrong packet id %u", data[0]); | 298 | ck_assert_msg(data[0] == 5, "wrong packet id %u", data[0]); |
292 | ck_assert_msg(memcmp(ping_packet + 1, data + 1, sizeof(uint64_t)) == 0, "wrong packet data"); | 299 | ck_assert_msg(memcmp(ping_packet + 1, data + 1, sizeof(uint64_t)) == 0, "wrong packet data"); |
300 | kill_TCP_server(tcp_s); | ||
301 | kill_TCP_con(con1); | ||
302 | kill_TCP_con(con2); | ||
303 | kill_TCP_con(con3); | ||
293 | } | 304 | } |
294 | END_TEST | 305 | END_TEST |
295 | 306 | ||
@@ -457,6 +468,9 @@ START_TEST(test_client) | |||
457 | do_TCP_connection(conn2); | 468 | do_TCP_connection(conn2); |
458 | ck_assert_msg(status_callback_good == 1, "status callback not called"); | 469 | ck_assert_msg(status_callback_good == 1, "status callback not called"); |
459 | ck_assert_msg(status_callback_status == 1, "wrong status"); | 470 | ck_assert_msg(status_callback_status == 1, "wrong status"); |
471 | kill_TCP_server(tcp_s); | ||
472 | kill_TCP_connection(conn); | ||
473 | kill_TCP_connection(conn2); | ||
460 | } | 474 | } |
461 | END_TEST | 475 | END_TEST |
462 | 476 | ||
@@ -488,6 +502,8 @@ START_TEST(test_client_invalid) | |||
488 | do_TCP_connection(conn); | 502 | do_TCP_connection(conn); |
489 | ck_assert_msg(conn->status == TCP_CLIENT_DISCONNECTED, "Wrong status. Expected: %u, is: %u", TCP_CLIENT_DISCONNECTED, | 503 | ck_assert_msg(conn->status == TCP_CLIENT_DISCONNECTED, "Wrong status. Expected: %u, is: %u", TCP_CLIENT_DISCONNECTED, |
490 | conn->status); | 504 | conn->status); |
505 | |||
506 | kill_TCP_connection(conn); | ||
491 | } | 507 | } |
492 | END_TEST | 508 | END_TEST |
493 | 509 | ||
diff --git a/auto_tests/assoc_test.c b/auto_tests/assoc_test.c index b377cadf..bcf5d3fa 100644 --- a/auto_tests/assoc_test.c +++ b/auto_tests/assoc_test.c | |||
@@ -55,6 +55,7 @@ START_TEST(test_basics) | |||
55 | 55 | ||
56 | uint8_t found = Assoc_get_close_entries(assoc, &close_entries); | 56 | uint8_t found = Assoc_get_close_entries(assoc, &close_entries); |
57 | ck_assert_msg(found == 1, "get_close_entries(): expected %u, got %u", 1, found); | 57 | ck_assert_msg(found == 1, "get_close_entries(): expected %u, got %u", 1, found); |
58 | kill_Assoc(assoc); | ||
58 | } | 59 | } |
59 | END_TEST | 60 | END_TEST |
60 | 61 | ||
@@ -130,6 +131,7 @@ START_TEST(test_fillup) | |||
130 | 131 | ||
131 | ck_assert_msg(good == 8, "Entries found were not the closest ones. Only %u/8 were.", good); | 132 | ck_assert_msg(good == 8, "Entries found were not the closest ones. Only %u/8 were.", good); |
132 | //printf("good: %u %u %u\n", good, a, ((uint32_t)current_time() - a)); | 133 | //printf("good: %u %u %u\n", good, a, ((uint32_t)current_time() - a)); |
134 | kill_Assoc(assoc); | ||
133 | } | 135 | } |
134 | END_TEST | 136 | END_TEST |
135 | 137 | ||
diff --git a/auto_tests/dht_test.c b/auto_tests/dht_test.c index 6d7e70ad..acbc3acb 100644 --- a/auto_tests/dht_test.c +++ b/auto_tests/dht_test.c | |||
@@ -45,6 +45,7 @@ void mark_good(IPPTsPng *ipptp) | |||
45 | void mark_all_good(Client_data *list, uint32_t length, uint8_t ipv6) | 45 | void mark_all_good(Client_data *list, uint32_t length, uint8_t ipv6) |
46 | { | 46 | { |
47 | uint32_t i; | 47 | uint32_t i; |
48 | |||
48 | for (i = 0; i < length; ++i) { | 49 | for (i = 0; i < length; ++i) { |
49 | if (ipv6) | 50 | if (ipv6) |
50 | mark_good(&list[i].assoc6); | 51 | mark_good(&list[i].assoc6); |
@@ -58,18 +59,22 @@ void mark_all_good(Client_data *list, uint32_t length, uint8_t ipv6) | |||
58 | uint8_t is_furthest(const uint8_t *comp_client_id, Client_data *list, uint32_t length, const uint8_t *client_id) | 59 | uint8_t is_furthest(const uint8_t *comp_client_id, Client_data *list, uint32_t length, const uint8_t *client_id) |
59 | { | 60 | { |
60 | uint32_t i; | 61 | uint32_t i; |
62 | |||
61 | for (i = 0; i < length; ++i) | 63 | for (i = 0; i < length; ++i) |
62 | if (id_closest(comp_client_id, client_id, list[i].client_id) == 1) | 64 | if (id_closest(comp_client_id, client_id, list[i].client_id) == 1) |
63 | return 0; | 65 | return 0; |
66 | |||
64 | return 1; | 67 | return 1; |
65 | } | 68 | } |
66 | 69 | ||
67 | int client_in_list(Client_data *list, uint32_t length, const uint8_t *client_id) | 70 | int client_in_list(Client_data *list, uint32_t length, const uint8_t *client_id) |
68 | { | 71 | { |
69 | int i; | 72 | int i; |
73 | |||
70 | for (i = 0; i < (int)length; ++i) | 74 | for (i = 0; i < (int)length; ++i) |
71 | if (id_equal(client_id, list[i].client_id)) | 75 | if (id_equal(client_id, list[i].client_id)) |
72 | return i; | 76 | return i; |
77 | |||
73 | return -1; | 78 | return -1; |
74 | } | 79 | } |
75 | 80 | ||
@@ -93,7 +98,8 @@ void test_addto_lists_update(DHT *dht, | |||
93 | // it is possible to have ip_port duplicates in the list, so ip_port @ found not always equal to ip_port @ test | 98 | // it is possible to have ip_port duplicates in the list, so ip_port @ found not always equal to ip_port @ test |
94 | found = client_in_list(list, length, test_id); | 99 | found = client_in_list(list, length, test_id); |
95 | ck_assert_msg(found >= 0, "Client id is not in the list"); | 100 | ck_assert_msg(found >= 0, "Client id is not in the list"); |
96 | ck_assert_msg(ipport_equal(&test_ipp, ipv6 ? &list[found].assoc6.ip_port : &list[found].assoc4.ip_port), "Client IP_Port is incorrect"); | 101 | ck_assert_msg(ipport_equal(&test_ipp, ipv6 ? &list[found].assoc6.ip_port : &list[found].assoc4.ip_port), |
102 | "Client IP_Port is incorrect"); | ||
97 | 103 | ||
98 | // check ip_port update for existing id | 104 | // check ip_port update for existing id |
99 | test = rand() % length; | 105 | test = rand() % length; |
@@ -104,7 +110,8 @@ void test_addto_lists_update(DHT *dht, | |||
104 | ck_assert_msg(used >= 1, "Wrong number of added clients"); | 110 | ck_assert_msg(used >= 1, "Wrong number of added clients"); |
105 | // it is not possible to have id duplicates in the list, so id @ found must be equal id @ test | 111 | // it is not possible to have id duplicates in the list, so id @ found must be equal id @ test |
106 | ck_assert_msg(client_in_list(list, length, test_id) == test, "Client id is not in the list"); | 112 | ck_assert_msg(client_in_list(list, length, test_id) == test, "Client id is not in the list"); |
107 | ck_assert_msg(ipport_equal(&test_ipp, ipv6 ? &list[test].assoc6.ip_port : &list[test].assoc4.ip_port), "Client IP_Port is incorrect"); | 113 | ck_assert_msg(ipport_equal(&test_ipp, ipv6 ? &list[test].assoc6.ip_port : &list[test].assoc4.ip_port), |
114 | "Client IP_Port is incorrect"); | ||
108 | 115 | ||
109 | // check ip_port update for existing id and ip_port (... port ... id ...) | 116 | // check ip_port update for existing id and ip_port (... port ... id ...) |
110 | test1 = rand() % (length / 2); | 117 | test1 = rand() % (length / 2); |
@@ -112,11 +119,15 @@ void test_addto_lists_update(DHT *dht, | |||
112 | 119 | ||
113 | ipport_copy(&test_ipp, ipv6 ? &list[test1].assoc6.ip_port : &list[test1].assoc4.ip_port); | 120 | ipport_copy(&test_ipp, ipv6 ? &list[test1].assoc6.ip_port : &list[test1].assoc4.ip_port); |
114 | id_copy(test_id, list[test2].client_id); | 121 | id_copy(test_id, list[test2].client_id); |
115 | if (ipv6) list[test2].assoc6.ip_port.port = -1; else list[test2].assoc4.ip_port.port = -1; | 122 | |
123 | if (ipv6) list[test2].assoc6.ip_port.port = -1; | ||
124 | else list[test2].assoc4.ip_port.port = -1; | ||
125 | |||
116 | used = addto_lists(dht, test_ipp, test_id); | 126 | used = addto_lists(dht, test_ipp, test_id); |
117 | ck_assert_msg(used >= 1, "Wrong number of added clients"); | 127 | ck_assert_msg(used >= 1, "Wrong number of added clients"); |
118 | ck_assert_msg(client_in_list(list, length, test_id) == test2, "Client id is not in the list"); | 128 | ck_assert_msg(client_in_list(list, length, test_id) == test2, "Client id is not in the list"); |
119 | ck_assert_msg(ipport_equal(&test_ipp, ipv6 ? &list[test2].assoc6.ip_port : &list[test2].assoc4.ip_port), "Client IP_Port is incorrect"); | 129 | ck_assert_msg(ipport_equal(&test_ipp, ipv6 ? &list[test2].assoc6.ip_port : &list[test2].assoc4.ip_port), |
130 | "Client IP_Port is incorrect"); | ||
120 | 131 | ||
121 | // check ip_port update for existing id and ip_port (... id ... port ...) | 132 | // check ip_port update for existing id and ip_port (... id ... port ...) |
122 | test1 = rand() % (length / 2); | 133 | test1 = rand() % (length / 2); |
@@ -124,11 +135,15 @@ void test_addto_lists_update(DHT *dht, | |||
124 | 135 | ||
125 | ipport_copy(&test_ipp, ipv6 ? &list[test2].assoc6.ip_port : &list[test2].assoc4.ip_port); | 136 | ipport_copy(&test_ipp, ipv6 ? &list[test2].assoc6.ip_port : &list[test2].assoc4.ip_port); |
126 | id_copy(test_id, list[test1].client_id); | 137 | id_copy(test_id, list[test1].client_id); |
127 | if (ipv6) list[test1].assoc6.ip_port.port = -1; else list[test1].assoc4.ip_port.port = -1; | 138 | |
139 | if (ipv6) list[test1].assoc6.ip_port.port = -1; | ||
140 | else list[test1].assoc4.ip_port.port = -1; | ||
141 | |||
128 | used = addto_lists(dht, test_ipp, test_id); | 142 | used = addto_lists(dht, test_ipp, test_id); |
129 | ck_assert_msg(used >= 1, "Wrong number of added clients"); | 143 | ck_assert_msg(used >= 1, "Wrong number of added clients"); |
130 | ck_assert_msg(client_in_list(list, length, test_id) == test1, "Client id is not in the list"); | 144 | ck_assert_msg(client_in_list(list, length, test_id) == test1, "Client id is not in the list"); |
131 | ck_assert_msg(ipport_equal(&test_ipp, ipv6 ? &list[test1].assoc6.ip_port : &list[test1].assoc4.ip_port), "Client IP_Port is incorrect"); | 145 | ck_assert_msg(ipport_equal(&test_ipp, ipv6 ? &list[test1].assoc6.ip_port : &list[test1].assoc4.ip_port), |
146 | "Client IP_Port is incorrect"); | ||
132 | } | 147 | } |
133 | 148 | ||
134 | void test_addto_lists_bad(DHT *dht, | 149 | void test_addto_lists_bad(DHT *dht, |
@@ -149,9 +164,9 @@ void test_addto_lists_bad(DHT *dht, | |||
149 | test3 = rand() % (length / 3) + 2 * length / 3; | 164 | test3 = rand() % (length / 3) + 2 * length / 3; |
150 | ck_assert_msg(!(test1 == test2 || test1 == test3 || test2 == test3), "Wrong test indices are chosen"); | 165 | ck_assert_msg(!(test1 == test2 || test1 == test3 || test2 == test3), "Wrong test indices are chosen"); |
151 | 166 | ||
152 | id_copy((uint8_t*)&test_id1, list[test1].client_id); | 167 | id_copy((uint8_t *)&test_id1, list[test1].client_id); |
153 | id_copy((uint8_t*)&test_id2, list[test2].client_id); | 168 | id_copy((uint8_t *)&test_id2, list[test2].client_id); |
154 | id_copy((uint8_t*)&test_id3, list[test3].client_id); | 169 | id_copy((uint8_t *)&test_id3, list[test3].client_id); |
155 | 170 | ||
156 | // mark nodes as "bad" | 171 | // mark nodes as "bad" |
157 | if (ipv6) { | 172 | if (ipv6) { |
@@ -169,9 +184,8 @@ void test_addto_lists_bad(DHT *dht, | |||
169 | ck_assert_msg(used >= 1, "Wrong number of added clients"); | 184 | ck_assert_msg(used >= 1, "Wrong number of added clients"); |
170 | 185 | ||
171 | ck_assert_msg(client_in_list(list, length, client_id) >= 0, "Client id is not in the list"); | 186 | ck_assert_msg(client_in_list(list, length, client_id) >= 0, "Client id is not in the list"); |
172 | ck_assert_msg(id_equal(client_id, list[test1].client_id), "Wrong bad client removed"); | 187 | ck_assert_msg(client_in_list(list, length, test_id2) >= 0, "Wrong bad client removed"); |
173 | ck_assert_msg(id_equal(test_id2, list[test2].client_id), "Wrong bad client removed"); | 188 | ck_assert_msg(client_in_list(list, length, test_id3) >= 0, "Wrong bad client removed"); |
174 | ck_assert_msg(id_equal(test_id3, list[test3].client_id), "Wrong bad client removed"); | ||
175 | } | 189 | } |
176 | 190 | ||
177 | void test_addto_lists_possible_bad(DHT *dht, | 191 | void test_addto_lists_possible_bad(DHT *dht, |
@@ -193,9 +207,9 @@ void test_addto_lists_possible_bad(DHT *dht, | |||
193 | test3 = rand() % (length / 3) + 2 * length / 3; | 207 | test3 = rand() % (length / 3) + 2 * length / 3; |
194 | ck_assert_msg(!(test1 == test2 || test1 == test3 || test2 == test3), "Wrong test indices are chosen"); | 208 | ck_assert_msg(!(test1 == test2 || test1 == test3 || test2 == test3), "Wrong test indices are chosen"); |
195 | 209 | ||
196 | id_copy((uint8_t*)&test_id1, list[test1].client_id); | 210 | id_copy((uint8_t *)&test_id1, list[test1].client_id); |
197 | id_copy((uint8_t*)&test_id2, list[test2].client_id); | 211 | id_copy((uint8_t *)&test_id2, list[test2].client_id); |
198 | id_copy((uint8_t*)&test_id3, list[test3].client_id); | 212 | id_copy((uint8_t *)&test_id3, list[test3].client_id); |
199 | 213 | ||
200 | // mark nodes as "possibly bad" | 214 | // mark nodes as "possibly bad" |
201 | if (ipv6) { | 215 | if (ipv6) { |
@@ -221,14 +235,20 @@ void test_addto_lists_possible_bad(DHT *dht, | |||
221 | ck_assert_msg(inlist_id1 + inlist_id2 + inlist_id3 == 2, "Wrong client removed"); | 235 | ck_assert_msg(inlist_id1 + inlist_id2 + inlist_id3 == 2, "Wrong client removed"); |
222 | 236 | ||
223 | if (!inlist_id1) { | 237 | if (!inlist_id1) { |
224 | ck_assert_msg(id_closest(comp_client_id, test_id2, test_id1) == 1, "Id has been removed but is closer to than another one"); | 238 | ck_assert_msg(id_closest(comp_client_id, test_id2, test_id1) == 1, |
225 | ck_assert_msg(id_closest(comp_client_id, test_id3, test_id1) == 1, "Id has been removed but is closer to than another one"); | 239 | "Id has been removed but is closer to than another one"); |
240 | ck_assert_msg(id_closest(comp_client_id, test_id3, test_id1) == 1, | ||
241 | "Id has been removed but is closer to than another one"); | ||
226 | } else if (!inlist_id2) { | 242 | } else if (!inlist_id2) { |
227 | ck_assert_msg(id_closest(comp_client_id, test_id1, test_id2) == 1, "Id has been removed but is closer to than another one"); | 243 | ck_assert_msg(id_closest(comp_client_id, test_id1, test_id2) == 1, |
228 | ck_assert_msg(id_closest(comp_client_id, test_id3, test_id2) == 1, "Id has been removed but is closer to than another one"); | 244 | "Id has been removed but is closer to than another one"); |
245 | ck_assert_msg(id_closest(comp_client_id, test_id3, test_id2) == 1, | ||
246 | "Id has been removed but is closer to than another one"); | ||
229 | } else if (!inlist_id3) { | 247 | } else if (!inlist_id3) { |
230 | ck_assert_msg(id_closest(comp_client_id, test_id1, test_id3) == 1, "Id has been removed but is closer to than another one"); | 248 | ck_assert_msg(id_closest(comp_client_id, test_id1, test_id3) == 1, |
231 | ck_assert_msg(id_closest(comp_client_id, test_id2, test_id3) == 1, "Id has been removed but is closer to than another one"); | 249 | "Id has been removed but is closer to than another one"); |
250 | ck_assert_msg(id_closest(comp_client_id, test_id2, test_id3) == 1, | ||
251 | "Id has been removed but is closer to than another one"); | ||
232 | } | 252 | } |
233 | } | 253 | } |
234 | 254 | ||
@@ -247,6 +267,7 @@ void test_addto_lists_good(DHT *dht, | |||
247 | do { | 267 | do { |
248 | randombytes(client_id, sizeof(client_id)); | 268 | randombytes(client_id, sizeof(client_id)); |
249 | } while (is_furthest(comp_client_id, list, length, client_id)); | 269 | } while (is_furthest(comp_client_id, list, length, client_id)); |
270 | |||
250 | ip_port->port += 1; | 271 | ip_port->port += 1; |
251 | addto_lists(dht, *ip_port, client_id); | 272 | addto_lists(dht, *ip_port, client_id); |
252 | ck_assert_msg(client_in_list(list, length, client_id) >= 0, "Good client id is not in the list"); | 273 | ck_assert_msg(client_in_list(list, length, client_id) >= 0, "Good client id is not in the list"); |
@@ -263,10 +284,10 @@ void test_addto_lists_good(DHT *dht, | |||
263 | 284 | ||
264 | void test_addto_lists(IP ip) | 285 | void test_addto_lists(IP ip) |
265 | { | 286 | { |
266 | Networking_Core* net = new_networking(ip, TOX_PORT_DEFAULT); | 287 | Networking_Core *net = new_networking(ip, TOX_PORT_DEFAULT); |
267 | ck_assert_msg(net != 0, "Failed to create Networking_Core"); | 288 | ck_assert_msg(net != 0, "Failed to create Networking_Core"); |
268 | 289 | ||
269 | DHT* dht = new_DHT(net); | 290 | DHT *dht = new_DHT(net); |
270 | ck_assert_msg(dht != 0, "Failed to create DHT"); | 291 | ck_assert_msg(dht != 0, "Failed to create DHT"); |
271 | 292 | ||
272 | IP_Port ip_port = { .ip = ip, .port = TOX_PORT_DEFAULT }; | 293 | IP_Port ip_port = { .ip = ip, .port = TOX_PORT_DEFAULT }; |
@@ -296,23 +317,30 @@ void test_addto_lists(IP ip) | |||
296 | /*check: Current behavior if there are two clients with the same id is | 317 | /*check: Current behavior if there are two clients with the same id is |
297 | * to replace the first ip by the second. */ | 318 | * to replace the first ip by the second. */ |
298 | test_addto_lists_update(dht, dht->close_clientlist, LCLIENT_LIST, &ip_port); | 319 | test_addto_lists_update(dht, dht->close_clientlist, LCLIENT_LIST, &ip_port); |
320 | |||
299 | for (i = 0; i < dht->num_friends; ++i) | 321 | for (i = 0; i < dht->num_friends; ++i) |
300 | test_addto_lists_update(dht, dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS, &ip_port); | 322 | test_addto_lists_update(dht, dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS, &ip_port); |
301 | 323 | ||
302 | // check "bad" entries | 324 | // check "bad" entries |
303 | test_addto_lists_bad(dht, dht->close_clientlist, LCLIENT_LIST, &ip_port); | 325 | test_addto_lists_bad(dht, dht->close_clientlist, LCLIENT_LIST, &ip_port); |
326 | |||
304 | for (i = 0; i < dht->num_friends; ++i) | 327 | for (i = 0; i < dht->num_friends; ++i) |
305 | test_addto_lists_bad(dht, dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS, &ip_port); | 328 | test_addto_lists_bad(dht, dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS, &ip_port); |
306 | 329 | ||
307 | // check "possibly bad" entries | 330 | // check "possibly bad" entries |
331 | /* | ||
308 | test_addto_lists_possible_bad(dht, dht->close_clientlist, LCLIENT_LIST, &ip_port, dht->self_public_key); | 332 | test_addto_lists_possible_bad(dht, dht->close_clientlist, LCLIENT_LIST, &ip_port, dht->self_public_key); |
309 | for (i = 0; i < dht->num_friends; ++i) | ||
310 | test_addto_lists_possible_bad(dht, dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS, &ip_port, dht->friends_list[i].client_id); | ||
311 | 333 | ||
334 | for (i = 0; i < dht->num_friends; ++i) | ||
335 | test_addto_lists_possible_bad(dht, dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS, &ip_port, | ||
336 | dht->friends_list[i].client_id); | ||
337 | */ | ||
312 | // check "good" entries | 338 | // check "good" entries |
313 | test_addto_lists_good(dht, dht->close_clientlist, LCLIENT_LIST, &ip_port, dht->self_public_key); | 339 | test_addto_lists_good(dht, dht->close_clientlist, LCLIENT_LIST, &ip_port, dht->self_public_key); |
340 | |||
314 | for (i = 0; i < dht->num_friends; ++i) | 341 | for (i = 0; i < dht->num_friends; ++i) |
315 | test_addto_lists_good(dht, dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS, &ip_port, dht->friends_list[i].client_id); | 342 | test_addto_lists_good(dht, dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS, &ip_port, |
343 | dht->friends_list[i].client_id); | ||
316 | 344 | ||
317 | kill_DHT(dht); | 345 | kill_DHT(dht); |
318 | kill_networking(net); | 346 | kill_networking(net); |
diff --git a/auto_tests/encryptsave_test.c b/auto_tests/encryptsave_test.c new file mode 100644 index 00000000..338c9ef1 --- /dev/null +++ b/auto_tests/encryptsave_test.c | |||
@@ -0,0 +1,190 @@ | |||
1 | #ifdef HAVE_CONFIG_H | ||
2 | #include "config.h" | ||
3 | #endif | ||
4 | |||
5 | #include <sys/types.h> | ||
6 | #include <stdint.h> | ||
7 | #include <string.h> | ||
8 | #include <check.h> | ||
9 | #include <stdlib.h> | ||
10 | #include <time.h> | ||
11 | |||
12 | #include "helpers.h" | ||
13 | |||
14 | #include "../toxcore/tox.h" | ||
15 | |||
16 | #include "../toxencryptsave/toxencryptsave.h" | ||
17 | #include "../toxcore/crypto_core.h" | ||
18 | #ifdef VANILLA_NACL | ||
19 | #include "../toxencryptsave/crypto_pwhash_scryptsalsa208sha256/crypto_pwhash_scryptsalsa208sha256.h" | ||
20 | #include "../toxencryptsave/crypto_pwhash_scryptsalsa208sha256/utils.h" /* sodium_memzero */ | ||
21 | #endif | ||
22 | |||
23 | unsigned char salt[32] = {0xB1, 0xC2, 0x09, 0xEE, 0x50, 0x6C, 0xF0, 0x20, 0xC4, 0xD6, 0xEB, 0xC0, 0x44, 0x51, 0x3B, 0x60, 0x4B, 0x39, 0x4A, 0xCF, 0x09, 0x53, 0x4F, 0xEA, 0x08, 0x41, 0xFA, 0xCA, 0x66, 0xD2, 0x68, 0x7F}; | ||
24 | unsigned char known_key[crypto_box_BEFORENMBYTES] = {0x29, 0x36, 0x1c, 0x9e, 0x65, 0xbb, 0x46, 0x8b, 0xde, 0xa1, 0xac, 0xf, 0xd5, 0x11, 0x81, 0xc8, 0x29, 0x28, 0x17, 0x23, 0xa6, 0xc3, 0x6b, 0x77, 0x2e, 0xd7, 0xd3, 0x10, 0xeb, 0xd2, 0xf7, 0xc8}; | ||
25 | char *pw = "hunter2"; | ||
26 | unsigned int pwlen = 7; | ||
27 | |||
28 | unsigned char known_key2[crypto_box_BEFORENMBYTES] = {0x7a, 0xfa, 0x95, 0x45, 0x36, 0x8a, 0xa2, 0x5c, 0x40, 0xfd, 0xc0, 0xe2, 0x35, 0x8, 0x7, 0x88, 0xfa, 0xf9, 0x37, 0x86, 0xeb, 0xff, 0x50, 0x4f, 0x3, 0xe2, 0xf6, 0xd9, 0xef, 0x9, 0x17, 0x1}; | ||
29 | // same as above, except standard opslimit instead of extra ops limit for test_known_kdf, and hash pw before kdf for compat | ||
30 | |||
31 | /* cause I'm shameless */ | ||
32 | void accept_friend_request(Tox *m, const uint8_t *public_key, const uint8_t *data, uint16_t length, void *userdata) | ||
33 | { | ||
34 | if (*((uint32_t *)userdata) != 974536) | ||
35 | return; | ||
36 | |||
37 | if (length == 7 && memcmp("Gentoo", data, 7) == 0) { | ||
38 | tox_add_friend_norequest(m, public_key); | ||
39 | } | ||
40 | } | ||
41 | |||
42 | START_TEST(test_known_kdf) | ||
43 | { | ||
44 | unsigned char out[crypto_box_BEFORENMBYTES]; | ||
45 | crypto_pwhash_scryptsalsa208sha256(out, | ||
46 | crypto_box_BEFORENMBYTES, | ||
47 | pw, | ||
48 | pwlen, | ||
49 | salt, | ||
50 | crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE * 8, | ||
51 | crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE); | ||
52 | ck_assert_msg(memcmp(out, known_key, crypto_box_BEFORENMBYTES) == 0, "derived key is wrong"); | ||
53 | } | ||
54 | END_TEST | ||
55 | |||
56 | START_TEST(test_save_friend) | ||
57 | { | ||
58 | Tox *tox1 = tox_new(0); | ||
59 | Tox *tox2 = tox_new(0); | ||
60 | ck_assert_msg(tox1 || tox2, "Failed to create 2 tox instances"); | ||
61 | uint32_t to_compare = 974536; | ||
62 | tox_callback_friend_request(tox2, accept_friend_request, &to_compare); | ||
63 | uint8_t address[TOX_FRIEND_ADDRESS_SIZE]; | ||
64 | tox_get_address(tox2, address); | ||
65 | int test = tox_add_friend(tox1, address, (uint8_t *)"Gentoo", 7); | ||
66 | ck_assert_msg(test == 0, "Failed to add friend error code: %i", test); | ||
67 | |||
68 | uint32_t size = tox_encrypted_size(tox1); | ||
69 | uint8_t data[size]; | ||
70 | test = tox_encrypted_save(tox1, data, "correcthorsebatterystaple", 25); | ||
71 | ck_assert_msg(test == 0, "failed to encrypted save"); | ||
72 | ck_assert_msg(tox_is_save_encrypted(data) == 1, "magic number missing"); | ||
73 | |||
74 | Tox *tox3 = tox_new(0); | ||
75 | test = tox_encrypted_load(tox3, data, size, "correcthorsebatterystaple", 25); | ||
76 | ck_assert_msg(test == 0, "failed to encrypted load"); | ||
77 | uint8_t address2[TOX_CLIENT_ID_SIZE]; | ||
78 | test = tox_get_client_id(tox3, 0, address2); | ||
79 | ck_assert_msg(test == 0, "no friends!"); | ||
80 | ck_assert_msg(memcmp(address, address2, TOX_CLIENT_ID_SIZE) == 0, "addresses don't match!"); | ||
81 | |||
82 | size = tox_encrypted_size(tox3); | ||
83 | uint8_t data2[size]; | ||
84 | uint8_t key[32 + crypto_box_BEFORENMBYTES]; | ||
85 | memcpy(key, salt, 32); | ||
86 | memcpy(key + 32, known_key2, crypto_box_BEFORENMBYTES); | ||
87 | test = tox_encrypted_key_save(tox3, data2, key); | ||
88 | ck_assert_msg(test == 0, "failed to encrypted save the second"); | ||
89 | ck_assert_msg(tox_is_save_encrypted(data2) == 1, "magic number the second missing"); | ||
90 | |||
91 | // first test tox_encrypted_key_load | ||
92 | Tox *tox4 = tox_new(0); | ||
93 | test = tox_encrypted_key_load(tox4, data2, size, key); | ||
94 | ck_assert_msg(test == 0, "failed to encrypted load the second"); | ||
95 | uint8_t address4[TOX_CLIENT_ID_SIZE]; | ||
96 | test = tox_get_client_id(tox4, 0, address4); | ||
97 | ck_assert_msg(test == 0, "no friends! the second"); | ||
98 | ck_assert_msg(memcmp(address, address2, TOX_CLIENT_ID_SIZE) == 0, "addresses don't match! the second"); | ||
99 | |||
100 | // now test compaitibilty with tox_encrypted_load, first manually... | ||
101 | uint8_t out1[size], out2[size]; | ||
102 | printf("Trying to decrypt from pw:\n"); | ||
103 | uint32_t sz1 = tox_pass_decrypt(data2, size, pw, pwlen, out1); | ||
104 | uint32_t sz2 = tox_pass_key_decrypt(data2, size, key, out2); | ||
105 | ck_assert_msg(sz1 == sz2, "differing output sizes"); | ||
106 | ck_assert_msg(memcmp(out1, out2, sz1) == 0, "differing output data"); | ||
107 | |||
108 | // and now with the code in use (I only bothered with manually to debug this, and it seems a waste | ||
109 | // to remove the manual check now that it's there) | ||
110 | Tox *tox5 = tox_new(0); | ||
111 | test = tox_encrypted_load(tox5, data2, size, pw, pwlen); | ||
112 | ck_assert_msg(test == 0, "failed to encrypted load the third"); | ||
113 | uint8_t address5[TOX_CLIENT_ID_SIZE]; | ||
114 | test = tox_get_client_id(tox4, 0, address5); | ||
115 | ck_assert_msg(test == 0, "no friends! the third"); | ||
116 | ck_assert_msg(memcmp(address, address2, TOX_CLIENT_ID_SIZE) == 0, "addresses don't match! the third"); | ||
117 | |||
118 | tox_kill(tox1); | ||
119 | tox_kill(tox2); | ||
120 | tox_kill(tox3); | ||
121 | tox_kill(tox4); | ||
122 | tox_kill(tox5); | ||
123 | } | ||
124 | END_TEST | ||
125 | |||
126 | START_TEST(test_keys) | ||
127 | { | ||
128 | uint8_t key[tox_pass_key_length()]; | ||
129 | tox_derive_key_from_pass("123qweasdzxc", 12, key); | ||
130 | uint8_t *string = "No Patrick, mayonnaise is not an instrument."; // 44 | ||
131 | |||
132 | uint8_t encrypted[44 + tox_pass_encryption_extra_length()]; | ||
133 | int sz = tox_pass_key_encrypt(string, 44, key, encrypted); | ||
134 | |||
135 | uint8_t encrypted2[44 + tox_pass_encryption_extra_length()]; | ||
136 | int sz2 = tox_pass_encrypt(string, 44, "123qweasdzxc", 12, encrypted2); | ||
137 | |||
138 | ck_assert_msg(sz == sz2, "an encryption failed"); | ||
139 | |||
140 | uint8_t out1[44 + tox_pass_encryption_extra_length()]; | ||
141 | uint8_t out2[44 + tox_pass_encryption_extra_length()]; | ||
142 | |||
143 | sz = tox_pass_key_decrypt(encrypted, 44 + tox_pass_encryption_extra_length(), key, out1); | ||
144 | ck_assert_msg(sz == 44, "sz isn't right"); | ||
145 | ck_assert_msg(memcmp(out1, string, 44) == 0, "decryption 1 failed"); | ||
146 | |||
147 | sz2 = tox_pass_decrypt(encrypted2, 44 + tox_pass_encryption_extra_length(), "123qweasdzxc", 12, out2); | ||
148 | ck_assert_msg(sz2 == 44, "sz2 isn't right"); | ||
149 | ck_assert_msg(memcmp(out2, string, 44) == 0, "decryption 2 failed"); | ||
150 | |||
151 | // test that pass_decrypt can decrypt things from pass_key_encrypt | ||
152 | sz = tox_pass_decrypt(encrypted, 44 + tox_pass_encryption_extra_length(), "123qweasdzxc", 12, out1); | ||
153 | ck_assert_msg(sz == 44, "sz isn't right"); | ||
154 | ck_assert_msg(memcmp(out1, string, 44) == 0, "decryption 3 failed"); | ||
155 | |||
156 | uint8_t salt[tox_pass_salt_length()]; | ||
157 | ck_assert_msg(0 == tox_get_salt(encrypted, salt), "couldn't get salt"); | ||
158 | uint8_t key2[tox_pass_key_length()]; | ||
159 | tox_derive_key_with_salt("123qweasdzxc", 12, salt, key2); | ||
160 | ck_assert_msg(0 == memcmp(key, key2, tox_pass_key_length()), "salt comparison failed"); | ||
161 | } | ||
162 | END_TEST | ||
163 | |||
164 | Suite *encryptsave_suite(void) | ||
165 | { | ||
166 | Suite *s = suite_create("encryptsave"); | ||
167 | |||
168 | DEFTESTCASE_SLOW(known_kdf, 60); /* is 5-10 seconds on my computer, but is directly dependent on CPU */ | ||
169 | DEFTESTCASE_SLOW(save_friend, 20); | ||
170 | DEFTESTCASE_SLOW(keys, 30); | ||
171 | |||
172 | return s; | ||
173 | } | ||
174 | |||
175 | int main(int argc, char *argv[]) | ||
176 | { | ||
177 | srand((unsigned int) time(NULL)); | ||
178 | |||
179 | Suite *encryptsave = encryptsave_suite(); | ||
180 | SRunner *test_runner = srunner_create(encryptsave); | ||
181 | |||
182 | int number_failed = 0; | ||
183 | srunner_run_all(test_runner, CK_NORMAL); | ||
184 | number_failed = srunner_ntests_failed(test_runner); | ||
185 | |||
186 | srunner_free(test_runner); | ||
187 | |||
188 | return number_failed; | ||
189 | } | ||
190 | |||
diff --git a/auto_tests/network_test.c b/auto_tests/network_test.c index 9d07fbb4..c1ac8084 100644 --- a/auto_tests/network_test.c +++ b/auto_tests/network_test.c | |||
@@ -134,22 +134,12 @@ START_TEST(test_ip_equal) | |||
134 | } | 134 | } |
135 | END_TEST | 135 | END_TEST |
136 | 136 | ||
137 | START_TEST(test_struct_sizes) | ||
138 | { | ||
139 | ck_assert_msg(sizeof(IP4) == 4, "sizeof(IP4): expected result 4, got %u.", sizeof(IP4)); | ||
140 | ck_assert_msg(sizeof(IP6) == 16, "sizeof(IP6): expected result 16, got %u.", sizeof(IP6)); | ||
141 | ck_assert_msg(sizeof(IP) == 17, "sizeof(IP): expected result 17, got %u.", sizeof(IP)); | ||
142 | ck_assert_msg(sizeof(IP_Port) == 19, "sizeof(IP_Port): expected result 19, got %u.", sizeof(IP_Port)); | ||
143 | } | ||
144 | END_TEST | ||
145 | |||
146 | Suite *network_suite(void) | 137 | Suite *network_suite(void) |
147 | { | 138 | { |
148 | Suite *s = suite_create("Network"); | 139 | Suite *s = suite_create("Network"); |
149 | 140 | ||
150 | DEFTESTCASE(addr_resolv_localhost); | 141 | DEFTESTCASE(addr_resolv_localhost); |
151 | DEFTESTCASE(ip_equal); | 142 | DEFTESTCASE(ip_equal); |
152 | DEFTESTCASE(struct_sizes); | ||
153 | 143 | ||
154 | return s; | 144 | return s; |
155 | } | 145 | } |
diff --git a/auto_tests/onion_test.c b/auto_tests/onion_test.c index 29f91308..f27fefb8 100644 --- a/auto_tests/onion_test.c +++ b/auto_tests/onion_test.c | |||
@@ -30,7 +30,7 @@ void do_onion(Onion *onion) | |||
30 | } | 30 | } |
31 | 31 | ||
32 | static int handled_test_1; | 32 | static int handled_test_1; |
33 | static int handle_test_1(void *object, IP_Port source, const uint8_t *packet, uint32_t length) | 33 | static int handle_test_1(void *object, IP_Port source, const uint8_t *packet, uint16_t length) |
34 | { | 34 | { |
35 | Onion *onion = object; | 35 | Onion *onion = object; |
36 | 36 | ||
@@ -46,7 +46,7 @@ static int handle_test_1(void *object, IP_Port source, const uint8_t *packet, ui | |||
46 | } | 46 | } |
47 | 47 | ||
48 | static int handled_test_2; | 48 | static int handled_test_2; |
49 | static int handle_test_2(void *object, IP_Port source, const uint8_t *packet, uint32_t length) | 49 | static int handle_test_2(void *object, IP_Port source, const uint8_t *packet, uint16_t length) |
50 | { | 50 | { |
51 | if (length != sizeof("install Gentoo")) | 51 | if (length != sizeof("install Gentoo")) |
52 | return 1; | 52 | return 1; |
@@ -72,7 +72,7 @@ uint8_t sb_data[ONION_ANNOUNCE_SENDBACK_DATA_LENGTH]; | |||
72 | static int handled_test_3; | 72 | static int handled_test_3; |
73 | uint8_t test_3_pub_key[crypto_box_PUBLICKEYBYTES]; | 73 | uint8_t test_3_pub_key[crypto_box_PUBLICKEYBYTES]; |
74 | uint8_t test_3_ping_id[crypto_hash_sha256_BYTES]; | 74 | uint8_t test_3_ping_id[crypto_hash_sha256_BYTES]; |
75 | static int handle_test_3(void *object, IP_Port source, const uint8_t *packet, uint32_t length) | 75 | static int handle_test_3(void *object, IP_Port source, const uint8_t *packet, uint16_t length) |
76 | { | 76 | { |
77 | Onion *onion = object; | 77 | Onion *onion = object; |
78 | 78 | ||
@@ -101,7 +101,7 @@ static int handle_test_3(void *object, IP_Port source, const uint8_t *packet, ui | |||
101 | 101 | ||
102 | uint8_t nonce[crypto_box_NONCEBYTES]; | 102 | uint8_t nonce[crypto_box_NONCEBYTES]; |
103 | static int handled_test_4; | 103 | static int handled_test_4; |
104 | static int handle_test_4(void *object, IP_Port source, const uint8_t *packet, uint32_t length) | 104 | static int handle_test_4(void *object, IP_Port source, const uint8_t *packet, uint16_t length) |
105 | { | 105 | { |
106 | Onion *onion = object; | 106 | Onion *onion = object; |
107 | 107 | ||
@@ -138,12 +138,12 @@ START_TEST(test_basic) | |||
138 | 138 | ||
139 | IP_Port on1 = {ip, onion1->net->port}; | 139 | IP_Port on1 = {ip, onion1->net->port}; |
140 | Node_format n1; | 140 | Node_format n1; |
141 | memcpy(n1.client_id, onion1->dht->self_public_key, crypto_box_PUBLICKEYBYTES); | 141 | memcpy(n1.public_key, onion1->dht->self_public_key, crypto_box_PUBLICKEYBYTES); |
142 | n1.ip_port = on1; | 142 | n1.ip_port = on1; |
143 | 143 | ||
144 | IP_Port on2 = {ip, onion2->net->port}; | 144 | IP_Port on2 = {ip, onion2->net->port}; |
145 | Node_format n2; | 145 | Node_format n2; |
146 | memcpy(n2.client_id, onion2->dht->self_public_key, crypto_box_PUBLICKEYBYTES); | 146 | memcpy(n2.public_key, onion2->dht->self_public_key, crypto_box_PUBLICKEYBYTES); |
147 | n2.ip_port = on2; | 147 | n2.ip_port = on2; |
148 | 148 | ||
149 | Node_format nodes[4]; | 149 | Node_format nodes[4]; |
@@ -180,7 +180,7 @@ START_TEST(test_basic) | |||
180 | randombytes(sb_data, sizeof(sb_data)); | 180 | randombytes(sb_data, sizeof(sb_data)); |
181 | uint64_t s; | 181 | uint64_t s; |
182 | memcpy(&s, sb_data, sizeof(uint64_t)); | 182 | memcpy(&s, sb_data, sizeof(uint64_t)); |
183 | memcpy(test_3_pub_key, nodes[3].client_id, crypto_box_PUBLICKEYBYTES); | 183 | memcpy(test_3_pub_key, nodes[3].public_key, crypto_box_PUBLICKEYBYTES); |
184 | ret = send_announce_request(onion1->net, &path, nodes[3], onion1->dht->self_public_key, | 184 | ret = send_announce_request(onion1->net, &path, nodes[3], onion1->dht->self_public_key, |
185 | onion1->dht->self_secret_key, | 185 | onion1->dht->self_secret_key, |
186 | zeroes, onion1->dht->self_public_key, onion1->dht->self_public_key, s); | 186 | zeroes, onion1->dht->self_public_key, onion1->dht->self_public_key, s); |
@@ -224,6 +224,39 @@ START_TEST(test_basic) | |||
224 | do_onion(onion2); | 224 | do_onion(onion2); |
225 | c_sleep(50); | 225 | c_sleep(50); |
226 | } | 226 | } |
227 | |||
228 | kill_onion_announce(onion1_a); | ||
229 | kill_onion_announce(onion2_a); | ||
230 | |||
231 | { | ||
232 | Onion *onion = onion1; | ||
233 | |||
234 | Networking_Core *net = onion->dht->net; | ||
235 | DHT *dht = onion->dht; | ||
236 | kill_onion(onion); | ||
237 | kill_DHT(dht); | ||
238 | kill_networking(net); | ||
239 | } | ||
240 | |||
241 | { | ||
242 | Onion *onion = onion2; | ||
243 | |||
244 | Networking_Core *net = onion->dht->net; | ||
245 | DHT *dht = onion->dht; | ||
246 | kill_onion(onion); | ||
247 | kill_DHT(dht); | ||
248 | kill_networking(net); | ||
249 | } | ||
250 | |||
251 | { | ||
252 | Onion *onion = onion3; | ||
253 | |||
254 | Networking_Core *net = onion->dht->net; | ||
255 | DHT *dht = onion->dht; | ||
256 | kill_onion(onion); | ||
257 | kill_DHT(dht); | ||
258 | kill_networking(net); | ||
259 | } | ||
227 | } | 260 | } |
228 | END_TEST | 261 | END_TEST |
229 | 262 | ||
@@ -257,6 +290,18 @@ void do_onions(Onions *on) | |||
257 | do_onion_client(on->onion_c); | 290 | do_onion_client(on->onion_c); |
258 | } | 291 | } |
259 | 292 | ||
293 | void kill_onions(Onions *on) | ||
294 | { | ||
295 | Networking_Core *net = on->onion->dht->net; | ||
296 | DHT *dht = on->onion->dht; | ||
297 | kill_onion_client(on->onion_c); | ||
298 | kill_onion_announce(on->onion_a); | ||
299 | kill_onion(on->onion); | ||
300 | kill_DHT(dht); | ||
301 | kill_networking(net); | ||
302 | free(on); | ||
303 | } | ||
304 | |||
260 | #define NUM_ONIONS 50 | 305 | #define NUM_ONIONS 50 |
261 | 306 | ||
262 | START_TEST(test_announce) | 307 | START_TEST(test_announce) |
@@ -334,6 +379,10 @@ START_TEST(test_announce) | |||
334 | } | 379 | } |
335 | 380 | ||
336 | ck_assert_msg(ip_port.port == onions[7]->onion->net->port, "Port in returned ip not correct."); | 381 | ck_assert_msg(ip_port.port == onions[7]->onion->net->port, "Port in returned ip not correct."); |
382 | |||
383 | for (i = 0; i < NUM_ONIONS; ++i) { | ||
384 | kill_onions(onions[i]); | ||
385 | } | ||
337 | } | 386 | } |
338 | END_TEST | 387 | END_TEST |
339 | 388 | ||
@@ -342,7 +391,7 @@ Suite *onion_suite(void) | |||
342 | Suite *s = suite_create("Onion"); | 391 | Suite *s = suite_create("Onion"); |
343 | 392 | ||
344 | DEFTESTCASE_SLOW(basic, 5); | 393 | DEFTESTCASE_SLOW(basic, 5); |
345 | DEFTESTCASE_SLOW(announce, 50); | 394 | //DEFTESTCASE_SLOW(announce, 50); //TODO: fix test. |
346 | return s; | 395 | return s; |
347 | } | 396 | } |
348 | 397 | ||
diff --git a/auto_tests/tox_test.c b/auto_tests/tox_test.c index 04dd3c22..2c157b1c 100644 --- a/auto_tests/tox_test.c +++ b/auto_tests/tox_test.c | |||
@@ -68,6 +68,27 @@ void print_typingchange(Tox *m, int friendnumber, uint8_t typing, void *userdata | |||
68 | typing_changes = 2; | 68 | typing_changes = 2; |
69 | } | 69 | } |
70 | 70 | ||
71 | uint32_t custom_packet; | ||
72 | |||
73 | int handle_custom_packet(Tox *m, int32_t friend_num, const uint8_t *data, uint32_t len, void *object) | ||
74 | { | ||
75 | uint8_t number = *((uint32_t *)object); | ||
76 | |||
77 | if (len != TOX_MAX_CUSTOM_PACKET_SIZE) | ||
78 | return -1; | ||
79 | |||
80 | uint8_t f_data[len]; | ||
81 | memset(f_data, number, len); | ||
82 | |||
83 | if (memcmp(f_data, data, len) == 0) { | ||
84 | ++custom_packet; | ||
85 | } else { | ||
86 | printf("Custom packet fail. %u\n", number ); | ||
87 | } | ||
88 | |||
89 | return 0; | ||
90 | } | ||
91 | |||
71 | uint8_t filenum; | 92 | uint8_t filenum; |
72 | uint32_t file_accepted; | 93 | uint32_t file_accepted; |
73 | uint64_t file_size; | 94 | uint64_t file_size; |
@@ -110,7 +131,7 @@ void write_file(Tox *m, int friendnumber, uint8_t filenumber, const uint8_t *dat | |||
110 | if (*((uint32_t *)userdata) != 974536) | 131 | if (*((uint32_t *)userdata) != 974536) |
111 | return; | 132 | return; |
112 | 133 | ||
113 | uint8_t *f_data = malloc(length); | 134 | uint8_t f_data[length]; |
114 | memset(f_data, num, length); | 135 | memset(f_data, num, length); |
115 | ++num; | 136 | ++num; |
116 | 137 | ||
@@ -121,6 +142,60 @@ void write_file(Tox *m, int friendnumber, uint8_t filenumber, const uint8_t *dat | |||
121 | } | 142 | } |
122 | } | 143 | } |
123 | 144 | ||
145 | START_TEST(test_one) | ||
146 | { | ||
147 | Tox *tox1 = tox_new(0); | ||
148 | Tox *tox2 = tox_new(0); | ||
149 | |||
150 | uint8_t address[TOX_FRIEND_ADDRESS_SIZE]; | ||
151 | tox_get_address(tox1, address); | ||
152 | ck_assert_msg(tox_add_friend(tox1, address, (uint8_t *)"m", 1) == TOX_FAERR_OWNKEY, "Adding own address worked."); | ||
153 | |||
154 | tox_get_address(tox2, address); | ||
155 | uint8_t message[TOX_MAX_FRIENDREQUEST_LENGTH + 1]; | ||
156 | ck_assert_msg(tox_add_friend(tox1, address, NULL, 0) == TOX_FAERR_NOMESSAGE, "Sending request with no message worked."); | ||
157 | ck_assert_msg(tox_add_friend(tox1, address, message, sizeof(message)) == TOX_FAERR_TOOLONG, | ||
158 | "TOX_MAX_FRIENDREQUEST_LENGTH is too big."); | ||
159 | |||
160 | address[0]++; | ||
161 | ck_assert_msg(tox_add_friend(tox1, address, (uint8_t *)"m", 1) == TOX_FAERR_BADCHECKSUM, | ||
162 | "Adding address with bad checksum worked."); | ||
163 | |||
164 | tox_get_address(tox2, address); | ||
165 | ck_assert_msg(tox_add_friend(tox1, address, message, TOX_MAX_FRIENDREQUEST_LENGTH) == 0, "Failed to add friend."); | ||
166 | ck_assert_msg(tox_add_friend(tox1, address, message, TOX_MAX_FRIENDREQUEST_LENGTH) == TOX_FAERR_ALREADYSENT, | ||
167 | "Adding friend twice worked."); | ||
168 | |||
169 | uint8_t name[TOX_MAX_NAME_LENGTH]; | ||
170 | int i; | ||
171 | |||
172 | for (i = 0; i < TOX_MAX_NAME_LENGTH; ++i) { | ||
173 | name[i] = rand(); | ||
174 | } | ||
175 | |||
176 | tox_set_name(tox1, name, sizeof(name)); | ||
177 | ck_assert_msg(tox_get_self_name_size(tox1) == sizeof(name), "Can't set name of TOX_MAX_NAME_LENGTH"); | ||
178 | |||
179 | size_t save_size = tox_size(tox1); | ||
180 | uint8_t data[save_size]; | ||
181 | tox_save(tox1, data); | ||
182 | |||
183 | tox_kill(tox2); | ||
184 | tox2 = tox_new(0); | ||
185 | ck_assert_msg(tox_load(tox2, data, save_size) == 0, "Load failed"); | ||
186 | |||
187 | size_t length = tox_get_self_name_size(tox2); | ||
188 | ck_assert_msg(tox_get_self_name_size(tox2) == sizeof name, "Wrong name size."); | ||
189 | |||
190 | uint8_t new_name[TOX_MAX_NAME_LENGTH] = { 0 }; | ||
191 | ck_assert_msg(tox_get_self_name(tox2, new_name) == TOX_MAX_NAME_LENGTH, "Wrong name length"); | ||
192 | ck_assert_msg(memcmp(name, new_name, TOX_MAX_NAME_LENGTH) == 0, "Wrong name"); | ||
193 | |||
194 | tox_kill(tox1); | ||
195 | tox_kill(tox2); | ||
196 | } | ||
197 | END_TEST | ||
198 | |||
124 | START_TEST(test_few_clients) | 199 | START_TEST(test_few_clients) |
125 | { | 200 | { |
126 | long long unsigned int con_time, cur_time = time(NULL); | 201 | long long unsigned int con_time, cur_time = time(NULL); |
@@ -234,6 +309,53 @@ START_TEST(test_few_clients) | |||
234 | 309 | ||
235 | ck_assert_msg(tox_get_is_typing(tox2, 0) == 0, "Typing fail"); | 310 | ck_assert_msg(tox_get_is_typing(tox2, 0) == 0, "Typing fail"); |
236 | 311 | ||
312 | uint32_t packet_number = 160; | ||
313 | int ret = tox_lossless_packet_registerhandler(tox3, 0, packet_number, &handle_custom_packet, &packet_number); | ||
314 | ck_assert_msg(ret == 0, "tox_lossless_packet_registerhandler fail %i", ret); | ||
315 | uint8_t data_c[TOX_MAX_CUSTOM_PACKET_SIZE + 1]; | ||
316 | memset(data_c, ((uint8_t)packet_number), sizeof(data_c)); | ||
317 | ret = tox_send_lossless_packet(tox2, 0, data_c, sizeof(data_c)); | ||
318 | ck_assert_msg(ret == -1, "tox_send_lossless_packet bigger fail %i", ret); | ||
319 | ret = tox_send_lossless_packet(tox2, 0, data_c, TOX_MAX_CUSTOM_PACKET_SIZE); | ||
320 | ck_assert_msg(ret == 0, "tox_send_lossless_packet fail %i", ret); | ||
321 | |||
322 | while (1) { | ||
323 | custom_packet = 0; | ||
324 | tox_do(tox1); | ||
325 | tox_do(tox2); | ||
326 | tox_do(tox3); | ||
327 | |||
328 | if (custom_packet == 1) | ||
329 | break; | ||
330 | else | ||
331 | ck_assert_msg(custom_packet == 0, "Lossless packet fail"); | ||
332 | |||
333 | c_sleep(50); | ||
334 | } | ||
335 | |||
336 | packet_number = 200; | ||
337 | ret = tox_lossy_packet_registerhandler(tox3, 0, packet_number, &handle_custom_packet, &packet_number); | ||
338 | ck_assert_msg(ret == 0, "tox_lossy_packet_registerhandler fail %i", ret); | ||
339 | memset(data_c, ((uint8_t)packet_number), sizeof(data_c)); | ||
340 | ret = tox_send_lossy_packet(tox2, 0, data_c, sizeof(data_c)); | ||
341 | ck_assert_msg(ret == -1, "tox_send_lossy_packet bigger fail %i", ret); | ||
342 | ret = tox_send_lossy_packet(tox2, 0, data_c, TOX_MAX_CUSTOM_PACKET_SIZE); | ||
343 | ck_assert_msg(ret == 0, "tox_send_lossy_packet fail %i", ret); | ||
344 | |||
345 | while (1) { | ||
346 | custom_packet = 0; | ||
347 | tox_do(tox1); | ||
348 | tox_do(tox2); | ||
349 | tox_do(tox3); | ||
350 | |||
351 | if (custom_packet == 1) | ||
352 | break; | ||
353 | else | ||
354 | ck_assert_msg(custom_packet == 0, "lossy packet fail"); | ||
355 | |||
356 | c_sleep(50); | ||
357 | } | ||
358 | |||
237 | filenum = file_accepted = file_size = file_sent = sendf_ok = size_recv = 0; | 359 | filenum = file_accepted = file_size = file_sent = sendf_ok = size_recv = 0; |
238 | long long unsigned int f_time = time(NULL); | 360 | long long unsigned int f_time = time(NULL); |
239 | tox_callback_file_data(tox3, write_file, &to_compare); | 361 | tox_callback_file_data(tox3, write_file, &to_compare); |
@@ -244,7 +366,7 @@ START_TEST(test_few_clients) | |||
244 | int fnum = tox_new_file_sender(tox2, 0, totalf_size, (uint8_t *)"Gentoo.exe", sizeof("Gentoo.exe")); | 366 | int fnum = tox_new_file_sender(tox2, 0, totalf_size, (uint8_t *)"Gentoo.exe", sizeof("Gentoo.exe")); |
245 | ck_assert_msg(fnum != -1, "tox_new_file_sender fail"); | 367 | ck_assert_msg(fnum != -1, "tox_new_file_sender fail"); |
246 | int fpiece_size = tox_file_data_size(tox2, 0); | 368 | int fpiece_size = tox_file_data_size(tox2, 0); |
247 | uint8_t *f_data = malloc(fpiece_size); | 369 | uint8_t f_data[fpiece_size]; |
248 | uint8_t num = 0; | 370 | uint8_t num = 0; |
249 | memset(f_data, num, fpiece_size); | 371 | memset(f_data, num, fpiece_size); |
250 | 372 | ||
@@ -292,7 +414,7 @@ START_TEST(test_few_clients) | |||
292 | END_TEST | 414 | END_TEST |
293 | 415 | ||
294 | #define NUM_TOXES 66 | 416 | #define NUM_TOXES 66 |
295 | #define NUM_FRIENDS 20 | 417 | #define NUM_FRIENDS 50 |
296 | 418 | ||
297 | START_TEST(test_many_clients) | 419 | START_TEST(test_many_clients) |
298 | { | 420 | { |
@@ -354,11 +476,185 @@ loop_top: | |||
354 | c_sleep(50); | 476 | c_sleep(50); |
355 | } | 477 | } |
356 | 478 | ||
479 | for (i = 0; i < NUM_TOXES; ++i) { | ||
480 | tox_kill(toxes[i]); | ||
481 | } | ||
482 | |||
357 | printf("test_many_clients succeeded, took %llu seconds\n", time(NULL) - cur_time); | 483 | printf("test_many_clients succeeded, took %llu seconds\n", time(NULL) - cur_time); |
484 | } | ||
485 | END_TEST | ||
358 | 486 | ||
359 | for (i = 0; i < NUM_TOXES; ++i) { | 487 | #define NUM_GROUP_TOX 32 |
488 | |||
489 | void g_accept_friend_request(Tox *m, const uint8_t *public_key, const uint8_t *data, uint16_t length, void *userdata) | ||
490 | { | ||
491 | if (*((uint32_t *)userdata) != 234212) | ||
492 | return; | ||
493 | |||
494 | if (length == 7 && memcmp("Gentoo", data, 7) == 0) { | ||
495 | tox_add_friend_norequest(m, public_key); | ||
496 | } | ||
497 | } | ||
498 | |||
499 | static Tox *invite_tox; | ||
500 | static unsigned int invite_counter; | ||
501 | |||
502 | void print_group_invite_callback(Tox *tox, int32_t friendnumber, uint8_t type, const uint8_t *data, uint16_t length, | ||
503 | void *userdata) | ||
504 | { | ||
505 | if (*((uint32_t *)userdata) != 234212) | ||
506 | return; | ||
507 | |||
508 | if (type != TOX_GROUPCHAT_TYPE_TEXT) | ||
509 | return; | ||
510 | |||
511 | int g_num; | ||
512 | |||
513 | if ((g_num = tox_join_groupchat(tox, friendnumber, data, length)) == -1) | ||
514 | return; | ||
515 | |||
516 | ck_assert_msg(g_num == 0, "Group number was not 0"); | ||
517 | ck_assert_msg(tox_join_groupchat(tox, friendnumber, data, length) == -1, | ||
518 | "Joining groupchat twice should be impossible."); | ||
519 | |||
520 | invite_tox = tox; | ||
521 | invite_counter = 4; | ||
522 | } | ||
523 | |||
524 | static unsigned int num_recv; | ||
525 | |||
526 | void print_group_message(Tox *tox, int groupnumber, int peernumber, const uint8_t *message, uint16_t length, | ||
527 | void *userdata) | ||
528 | { | ||
529 | if (*((uint32_t *)userdata) != 234212) | ||
530 | return; | ||
531 | |||
532 | if (length == (sizeof("Install Gentoo") - 1) && memcmp(message, "Install Gentoo", sizeof("Install Gentoo") - 1) == 0) { | ||
533 | ++num_recv; | ||
534 | } | ||
535 | } | ||
536 | |||
537 | START_TEST(test_many_group) | ||
538 | { | ||
539 | long long unsigned int cur_time = time(NULL); | ||
540 | Tox *toxes[NUM_GROUP_TOX]; | ||
541 | unsigned int i, j, k; | ||
542 | |||
543 | uint32_t to_comp = 234212; | ||
544 | |||
545 | for (i = 0; i < NUM_GROUP_TOX; ++i) { | ||
546 | toxes[i] = tox_new(0); | ||
547 | ck_assert_msg(toxes[i] != 0, "Failed to create tox instances %u", i); | ||
548 | tox_callback_friend_request(toxes[i], &g_accept_friend_request, &to_comp); | ||
549 | tox_callback_group_invite(toxes[i], &print_group_invite_callback, &to_comp); | ||
550 | } | ||
551 | |||
552 | uint8_t address[TOX_FRIEND_ADDRESS_SIZE]; | ||
553 | tox_get_address(toxes[NUM_GROUP_TOX - 1], address); | ||
554 | |||
555 | for (i = 0; i < NUM_GROUP_TOX; ++i) { | ||
556 | ck_assert_msg(tox_add_friend(toxes[i], address, (uint8_t *)"Gentoo", 7) == 0, "Failed to add friend"); | ||
557 | |||
558 | tox_get_address(toxes[i], address); | ||
559 | } | ||
560 | |||
561 | while (1) { | ||
562 | for (i = 0; i < NUM_GROUP_TOX; ++i) { | ||
563 | if (tox_get_friend_connection_status(toxes[i], 0) != 1) { | ||
564 | break; | ||
565 | } | ||
566 | } | ||
567 | |||
568 | if (i == NUM_GROUP_TOX) | ||
569 | break; | ||
570 | |||
571 | for (i = 0; i < NUM_GROUP_TOX; ++i) { | ||
572 | tox_do(toxes[i]); | ||
573 | } | ||
574 | |||
575 | c_sleep(50); | ||
576 | } | ||
577 | |||
578 | printf("friends connected, took %llu seconds\n", time(NULL) - cur_time); | ||
579 | |||
580 | ck_assert_msg(tox_add_groupchat(toxes[0]) != -1, "Failed to create group"); | ||
581 | ck_assert_msg(tox_invite_friend(toxes[0], 0, 0) == 0, "Failed to invite friend"); | ||
582 | ck_assert_msg(tox_group_set_title(toxes[0], 0, "Gentoo", sizeof("Gentoo") - 1) == 0, "Failed to set group title"); | ||
583 | invite_counter = ~0; | ||
584 | |||
585 | unsigned int done = ~0; | ||
586 | done -= 5; | ||
587 | |||
588 | while (1) { | ||
589 | for (i = 0; i < NUM_GROUP_TOX; ++i) { | ||
590 | tox_do(toxes[i]); | ||
591 | } | ||
592 | |||
593 | if (!invite_counter) { | ||
594 | ck_assert_msg(tox_invite_friend(invite_tox, 0, 0) == 0, "Failed to invite friend"); | ||
595 | } | ||
596 | |||
597 | if (done == invite_counter) { | ||
598 | break; | ||
599 | } | ||
600 | |||
601 | --invite_counter; | ||
602 | c_sleep(50); | ||
603 | } | ||
604 | |||
605 | for (i = 0; i < NUM_GROUP_TOX; ++i) { | ||
606 | int num_peers = tox_group_number_peers(toxes[i], 0); | ||
607 | ck_assert_msg(num_peers == NUM_GROUP_TOX, "Bad number of group peers. expected: %u got: %i, tox %u", NUM_GROUP_TOX, | ||
608 | num_peers, i); | ||
609 | |||
610 | uint8_t title[2048]; | ||
611 | int ret = tox_group_get_title(toxes[i], 0, title, sizeof(title)); | ||
612 | ck_assert_msg(ret == sizeof("Gentoo") - 1, "Wrong title length"); | ||
613 | ck_assert_msg(memcmp("Gentoo", title, ret) == 0, "Wrong title"); | ||
614 | } | ||
615 | |||
616 | printf("group connected\n"); | ||
617 | |||
618 | for (i = 0; i < NUM_GROUP_TOX; ++i) { | ||
619 | tox_callback_group_message(toxes[i], &print_group_message, &to_comp); | ||
620 | } | ||
621 | |||
622 | ck_assert_msg(tox_group_message_send(toxes[rand() % NUM_GROUP_TOX], 0, (uint8_t *)"Install Gentoo", | ||
623 | sizeof("Install Gentoo") - 1) == 0, "Failed to send group message."); | ||
624 | num_recv = 0; | ||
625 | |||
626 | for (j = 0; j < 20; ++j) { | ||
627 | for (i = 0; i < NUM_GROUP_TOX; ++i) { | ||
628 | tox_do(toxes[i]); | ||
629 | } | ||
630 | |||
631 | c_sleep(50); | ||
632 | } | ||
633 | |||
634 | ck_assert_msg(num_recv == NUM_GROUP_TOX, "Failed to recv group messages."); | ||
635 | |||
636 | for (k = NUM_GROUP_TOX; k != 0 ; --k) { | ||
637 | tox_del_groupchat(toxes[k - 1], 0); | ||
638 | |||
639 | for (j = 0; j < 10; ++j) { | ||
640 | for (i = 0; i < NUM_GROUP_TOX; ++i) { | ||
641 | tox_do(toxes[i]); | ||
642 | } | ||
643 | |||
644 | c_sleep(50); | ||
645 | } | ||
646 | |||
647 | for (i = 0; i < (k - 1); ++i) { | ||
648 | int num_peers = tox_group_number_peers(toxes[i], 0); | ||
649 | ck_assert_msg(num_peers == (k - 1), "Bad number of group peers. expected: %u got: %i, tox %u", (k - 1), num_peers, i); | ||
650 | } | ||
651 | } | ||
652 | |||
653 | for (i = 0; i < NUM_GROUP_TOX; ++i) { | ||
360 | tox_kill(toxes[i]); | 654 | tox_kill(toxes[i]); |
361 | } | 655 | } |
656 | |||
657 | printf("test_many_group succeeded, took %llu seconds\n", time(NULL) - cur_time); | ||
362 | } | 658 | } |
363 | END_TEST | 659 | END_TEST |
364 | 660 | ||
@@ -366,8 +662,10 @@ Suite *tox_suite(void) | |||
366 | { | 662 | { |
367 | Suite *s = suite_create("Tox"); | 663 | Suite *s = suite_create("Tox"); |
368 | 664 | ||
665 | DEFTESTCASE(one); | ||
369 | DEFTESTCASE_SLOW(few_clients, 50); | 666 | DEFTESTCASE_SLOW(few_clients, 50); |
370 | DEFTESTCASE_SLOW(many_clients, 150); | 667 | DEFTESTCASE_SLOW(many_clients, 150); |
668 | DEFTESTCASE_SLOW(many_group, 100); | ||
371 | return s; | 669 | return s; |
372 | } | 670 | } |
373 | 671 | ||
diff --git a/auto_tests/toxav_basic_test.c b/auto_tests/toxav_basic_test.c index c6481366..3139c844 100644 --- a/auto_tests/toxav_basic_test.c +++ b/auto_tests/toxav_basic_test.c | |||
@@ -11,6 +11,8 @@ | |||
11 | #include <time.h> | 11 | #include <time.h> |
12 | #include <assert.h> | 12 | #include <assert.h> |
13 | 13 | ||
14 | #include <vpx/vpx_image.h> | ||
15 | |||
14 | #include "../toxcore/tox.h" | 16 | #include "../toxcore/tox.h" |
15 | #include "../toxcore/logger.h" | 17 | #include "../toxcore/logger.h" |
16 | #include "../toxcore/crypto_core.h" | 18 | #include "../toxcore/crypto_core.h" |
@@ -33,7 +35,7 @@ typedef enum _CallStatus { | |||
33 | Ringing, | 35 | Ringing, |
34 | Ended, | 36 | Ended, |
35 | Rejected, | 37 | Rejected, |
36 | Cancel, | 38 | Canceled, |
37 | TimedOut | 39 | TimedOut |
38 | 40 | ||
39 | } CallStatus; | 41 | } CallStatus; |
@@ -66,36 +68,23 @@ void callback_recv_invite ( void *av, int32_t call_index, void *_arg ) | |||
66 | { | 68 | { |
67 | Status *cast = _arg; | 69 | Status *cast = _arg; |
68 | 70 | ||
69 | /* Bob always receives invite */ | 71 | if (cast->Alice.av == av) { |
70 | cast->Bob.status = Ringing; | 72 | // ... |
71 | cast->Bob.call_index = call_index; | 73 | } else if (cast->Bob.av == av) { |
74 | /* Bob always receives invite */ | ||
75 | cast->Bob.status = Ringing; | ||
76 | cast->Bob.call_index = call_index; | ||
77 | } | ||
72 | } | 78 | } |
73 | void callback_recv_ringing ( void *av, int32_t call_index, void *_arg ) | 79 | void callback_recv_ringing ( void *av, int32_t call_index, void *_arg ) |
74 | { | 80 | { |
75 | Status *cast = _arg; | 81 | Status *cast = _arg; |
76 | 82 | ||
77 | /* Alice always sends invite */ | 83 | if (cast->Alice.av == av) { |
78 | cast->Alice.status = Ringing; | 84 | /* Alice always sends invite */ |
79 | } | 85 | cast->Alice.status = Ringing; |
80 | void callback_recv_starting ( void *av, int32_t call_index, void *_arg ) | 86 | } else if (cast->Bob.av == av) { |
81 | { | 87 | // ... |
82 | Status *cast = _arg; | ||
83 | |||
84 | /* Alice always sends invite */ | ||
85 | printf("Call started on Alice side...\n"); | ||
86 | cast->Alice.status = InCall; | ||
87 | toxav_prepare_transmission(av, call_index, av_jbufdc, av_VADd, 1); | ||
88 | } | ||
89 | void callback_recv_ending ( void *av, int32_t call_index, void *_arg ) | ||
90 | { | ||
91 | Status *cast = _arg; | ||
92 | |||
93 | if ( cast->Alice.status == Rejected) { | ||
94 | printf ( "Call ended for Bob!\n" ); | ||
95 | cast->Bob.status = Ended; | ||
96 | } else { | ||
97 | printf ( "Call ended for Alice!\n" ); | ||
98 | cast->Alice.status = Ended; | ||
99 | } | 88 | } |
100 | } | 89 | } |
101 | 90 | ||
@@ -104,17 +93,26 @@ void callback_call_started ( void *av, int32_t call_index, void *_arg ) | |||
104 | { | 93 | { |
105 | Status *cast = _arg; | 94 | Status *cast = _arg; |
106 | 95 | ||
107 | /* Alice always sends invite */ | 96 | if (cast->Alice.av == av) { |
108 | printf("Call started on Bob side...\n"); | 97 | printf("Call started on Alices side...\n"); |
109 | cast->Bob.status = InCall; | 98 | cast->Alice.status = InCall; |
110 | toxav_prepare_transmission(av, call_index, av_jbufdc, av_VADd, 1); | 99 | toxav_prepare_transmission(av, call_index, 1); |
100 | } else if (cast->Bob.av == av) { | ||
101 | printf("Call started on Bob side...\n"); | ||
102 | cast->Bob.status = InCall; | ||
103 | toxav_prepare_transmission(av, call_index, 1); | ||
104 | } | ||
111 | } | 105 | } |
112 | void callback_call_canceled ( void *av, int32_t call_index, void *_arg ) | 106 | void callback_call_canceled ( void *av, int32_t call_index, void *_arg ) |
113 | { | 107 | { |
114 | Status *cast = _arg; | 108 | Status *cast = _arg; |
115 | 109 | ||
116 | printf ( "Call Canceled for Bob!\n" ); | 110 | if (cast->Alice.av == av) { |
117 | cast->Bob.status = Cancel; | 111 | // ... |
112 | } else if (cast->Bob.av == av) { | ||
113 | printf ( "Call Canceled for Bob!\n" ); | ||
114 | cast->Bob.status = Canceled; | ||
115 | } | ||
118 | } | 116 | } |
119 | void callback_call_rejected ( void *av, int32_t call_index, void *_arg ) | 117 | void callback_call_rejected ( void *av, int32_t call_index, void *_arg ) |
120 | { | 118 | { |
@@ -122,23 +120,58 @@ void callback_call_rejected ( void *av, int32_t call_index, void *_arg ) | |||
122 | 120 | ||
123 | printf ( "Call rejected by Bob!\n" | 121 | printf ( "Call rejected by Bob!\n" |
124 | "Call ended for Alice!\n" ); | 122 | "Call ended for Alice!\n" ); |
123 | |||
125 | /* If Bob rejects, call is ended for alice and she sends ending */ | 124 | /* If Bob rejects, call is ended for alice and she sends ending */ |
126 | cast->Alice.status = Rejected; | 125 | if (cast->Alice.av == av) { |
126 | cast->Alice.status = Rejected; | ||
127 | } else if (cast->Bob.av == av) { | ||
128 | //... ignor | ||
129 | } | ||
127 | } | 130 | } |
128 | void callback_call_ended ( void *av, int32_t call_index, void *_arg ) | 131 | void callback_call_ended ( void *av, int32_t call_index, void *_arg ) |
129 | { | 132 | { |
130 | Status *cast = _arg; | 133 | Status *cast = _arg; |
131 | 134 | ||
132 | printf ( "Call ended for Bob!\n" ); | 135 | if (cast->Alice.av == av) { |
133 | cast->Bob.status = Ended; | 136 | printf ( "Call ended for Alice!\n" ); |
137 | cast->Alice.status = Ended; | ||
138 | } else if (cast->Bob.av == av) { | ||
139 | printf ( "Call ended for Bob!\n" ); | ||
140 | cast->Bob.status = Ended; | ||
141 | } | ||
134 | } | 142 | } |
135 | 143 | ||
136 | void callback_call_type_change ( void *av, int32_t call_index, void *_arg ) | 144 | void callback_peer_cs_change ( void *av, int32_t call_index, void *_arg ) |
137 | { | 145 | { |
138 | ToxAvCSettings csettings; | 146 | ToxAvCSettings csettings; |
139 | toxav_get_peer_csettings(av, call_index, 0, &csettings); | 147 | toxav_get_peer_csettings(av, call_index, 0, &csettings); |
140 | 148 | ||
141 | printf("New settings: \n" | 149 | printf("Peer changing settings to: \n" |
150 | "Type: %u \n" | ||
151 | "Video bitrate: %u \n" | ||
152 | "Video height: %u \n" | ||
153 | "Video width: %u \n" | ||
154 | "Audio bitrate: %u \n" | ||
155 | "Audio framedur: %u \n" | ||
156 | "Audio sample rate: %u \n" | ||
157 | "Audio channels: %u \n", | ||
158 | csettings.call_type, | ||
159 | csettings.video_bitrate, | ||
160 | csettings.max_video_height, | ||
161 | csettings.max_video_width, | ||
162 | csettings.audio_bitrate, | ||
163 | csettings.audio_frame_duration, | ||
164 | csettings.audio_sample_rate, | ||
165 | csettings.audio_channels | ||
166 | ); | ||
167 | } | ||
168 | |||
169 | void callback_self_cs_change ( void *av, int32_t call_index, void *_arg ) | ||
170 | { | ||
171 | ToxAvCSettings csettings; | ||
172 | toxav_get_peer_csettings(av, call_index, 0, &csettings); | ||
173 | |||
174 | printf("Changed settings to: \n" | ||
142 | "Type: %u \n" | 175 | "Type: %u \n" |
143 | "Video bitrate: %u \n" | 176 | "Video bitrate: %u \n" |
144 | "Video height: %u \n" | 177 | "Video height: %u \n" |
@@ -162,16 +195,19 @@ void callback_requ_timeout ( void *av, int32_t call_index, void *_arg ) | |||
162 | { | 195 | { |
163 | Status *cast = _arg; | 196 | Status *cast = _arg; |
164 | printf("Call timed-out!\n"); | 197 | printf("Call timed-out!\n"); |
165 | cast->Alice.status = TimedOut; | ||
166 | } | ||
167 | 198 | ||
168 | static void callback_audio(ToxAv *av, int32_t call_index, int16_t *data, int length, void *userdata) | 199 | if (cast->Alice.av == av) { |
169 | { | 200 | cast->Alice.status = TimedOut; |
201 | } else if (cast->Bob.av == av) { | ||
202 | cast->Bob.status = TimedOut; | ||
203 | } | ||
170 | } | 204 | } |
171 | 205 | ||
172 | static void callback_video(ToxAv *av, int32_t call_index, vpx_image_t *img, void *userdata) | 206 | void callback_audio (void *agent, int32_t call_idx, const int16_t *PCM, uint16_t size, void *data) |
173 | { | 207 | {} |
174 | } | 208 | |
209 | void callback_video (void *agent, int32_t call_idx, const vpx_image_t *img, void *data) | ||
210 | {} | ||
175 | 211 | ||
176 | void register_callbacks(ToxAv *av, void *data) | 212 | void register_callbacks(ToxAv *av, void *data) |
177 | { | 213 | { |
@@ -180,17 +216,12 @@ void register_callbacks(ToxAv *av, void *data) | |||
180 | toxav_register_callstate_callback(av, callback_call_rejected, av_OnReject, data); | 216 | toxav_register_callstate_callback(av, callback_call_rejected, av_OnReject, data); |
181 | toxav_register_callstate_callback(av, callback_call_ended, av_OnEnd, data); | 217 | toxav_register_callstate_callback(av, callback_call_ended, av_OnEnd, data); |
182 | toxav_register_callstate_callback(av, callback_recv_invite, av_OnInvite, data); | 218 | toxav_register_callstate_callback(av, callback_recv_invite, av_OnInvite, data); |
183 | |||
184 | toxav_register_callstate_callback(av, callback_recv_ringing, av_OnRinging, data); | 219 | toxav_register_callstate_callback(av, callback_recv_ringing, av_OnRinging, data); |
185 | toxav_register_callstate_callback(av, callback_recv_starting, av_OnStarting, data); | ||
186 | toxav_register_callstate_callback(av, callback_recv_ending, av_OnEnding, data); | ||
187 | |||
188 | toxav_register_callstate_callback(av, callback_requ_timeout, av_OnRequestTimeout, data); | 220 | toxav_register_callstate_callback(av, callback_requ_timeout, av_OnRequestTimeout, data); |
189 | toxav_register_callstate_callback(av, callback_call_type_change, av_OnMediaChange, data); | 221 | toxav_register_callstate_callback(av, callback_peer_cs_change, av_OnPeerCSChange, data); |
190 | 222 | toxav_register_callstate_callback(av, callback_self_cs_change, av_OnSelfCSChange, data); | |
191 | 223 | toxav_register_audio_callback(av, callback_audio, NULL); | |
192 | toxav_register_audio_recv_callback(av, callback_audio, NULL); | 224 | toxav_register_video_callback(av, callback_video, NULL); |
193 | toxav_register_video_recv_callback(av, callback_video, NULL); | ||
194 | } | 225 | } |
195 | 226 | ||
196 | 227 | ||
@@ -202,6 +233,7 @@ void register_callbacks(ToxAv *av, void *data) | |||
202 | #define CALL_AND_START_LOOP(AliceCallType, BobCallType) \ | 233 | #define CALL_AND_START_LOOP(AliceCallType, BobCallType) \ |
203 | { int step = 0, running = 1; while (running) {\ | 234 | { int step = 0, running = 1; while (running) {\ |
204 | tox_do(bootstrap_node); tox_do(Alice); tox_do(Bob); \ | 235 | tox_do(bootstrap_node); tox_do(Alice); tox_do(Bob); \ |
236 | toxav_do(status_control.Bob.av); toxav_do(status_control.Alice.av); \ | ||
205 | switch ( step ) {\ | 237 | switch ( step ) {\ |
206 | case 0: /* Alice */ printf("Alice is calling...\n");\ | 238 | case 0: /* Alice */ printf("Alice is calling...\n");\ |
207 | toxav_call(status_control.Alice.av, &status_control.Alice.call_index, 0, &muhcaps, 10); step++; break;\ | 239 | toxav_call(status_control.Alice.av, &status_control.Alice.call_index, 0, &muhcaps, 10); step++; break;\ |
@@ -496,6 +528,10 @@ START_TEST(test_AV_flows) | |||
496 | tox_do(Alice); | 528 | tox_do(Alice); |
497 | tox_do(Bob); | 529 | tox_do(Bob); |
498 | 530 | ||
531 | toxav_do(status_control.Alice.av); | ||
532 | toxav_do(status_control.Bob.av); | ||
533 | |||
534 | |||
499 | switch ( step ) { | 535 | switch ( step ) { |
500 | case 0: /* Alice */ | 536 | case 0: /* Alice */ |
501 | printf("Alice is calling...\n"); | 537 | printf("Alice is calling...\n"); |
@@ -514,7 +550,7 @@ START_TEST(test_AV_flows) | |||
514 | break; | 550 | break; |
515 | 551 | ||
516 | case 2: /* Wait for Both to have status ended */ | 552 | case 2: /* Wait for Both to have status ended */ |
517 | if (status_control.Bob.status == Cancel) running = 0; | 553 | if (status_control.Bob.status == Canceled) running = 0; |
518 | 554 | ||
519 | break; | 555 | break; |
520 | } | 556 | } |
@@ -537,6 +573,9 @@ START_TEST(test_AV_flows) | |||
537 | tox_do(Alice); | 573 | tox_do(Alice); |
538 | tox_do(Bob); | 574 | tox_do(Bob); |
539 | 575 | ||
576 | toxav_do(status_control.Alice.av); | ||
577 | toxav_do(status_control.Bob.av); | ||
578 | |||
540 | switch ( step ) { | 579 | switch ( step ) { |
541 | case 0: | 580 | case 0: |
542 | printf("Alice is calling...\n"); | 581 | printf("Alice is calling...\n"); |
@@ -556,8 +595,12 @@ START_TEST(test_AV_flows) | |||
556 | printf("\n"); | 595 | printf("\n"); |
557 | } | 596 | } |
558 | 597 | ||
559 | 598 | vpx_img_free(sample_image); | |
560 | 599 | toxav_kill(status_control.Alice.av); | |
600 | toxav_kill(status_control.Bob.av); | ||
601 | tox_kill(bootstrap_node); | ||
602 | tox_kill(Alice); | ||
603 | tox_kill(Bob); | ||
561 | 604 | ||
562 | printf("Calls ended!\n"); | 605 | printf("Calls ended!\n"); |
563 | } | 606 | } |
diff --git a/auto_tests/toxav_many_test.c b/auto_tests/toxav_many_test.c index d9c588f7..99012992 100644 --- a/auto_tests/toxav_many_test.c +++ b/auto_tests/toxav_many_test.c | |||
@@ -11,6 +11,8 @@ | |||
11 | #include <time.h> | 11 | #include <time.h> |
12 | #include <assert.h> | 12 | #include <assert.h> |
13 | 13 | ||
14 | #include <vpx/vpx_image.h> | ||
15 | |||
14 | #include "../toxcore/tox.h" | 16 | #include "../toxcore/tox.h" |
15 | #include "../toxcore/logger.h" | 17 | #include "../toxcore/logger.h" |
16 | #include "../toxcore/crypto_core.h" | 18 | #include "../toxcore/crypto_core.h" |
@@ -32,7 +34,7 @@ typedef enum _CallStatus { | |||
32 | Ringing, | 34 | Ringing, |
33 | Ended, | 35 | Ended, |
34 | Rejected, | 36 | Rejected, |
35 | Cancel | 37 | Canceled |
36 | 38 | ||
37 | } CallStatus; | 39 | } CallStatus; |
38 | 40 | ||
@@ -67,66 +69,51 @@ void accept_friend_request(Tox *m, const uint8_t *public_key, const uint8_t *dat | |||
67 | /******************************************************************************/ | 69 | /******************************************************************************/ |
68 | void callback_recv_invite ( void *av, int32_t call_index, void *_arg ) | 70 | void callback_recv_invite ( void *av, int32_t call_index, void *_arg ) |
69 | { | 71 | { |
70 | /* | 72 | Status *cast = _arg; |
71 | Status *cast = _arg; | 73 | cast->calls[call_index].Callee.status = Ringing; |
72 | |||
73 | cast->calls[call_index].Callee.status = Ringing;*/ | ||
74 | } | 74 | } |
75 | void callback_recv_ringing ( void *av, int32_t call_index, void *_arg ) | 75 | void callback_recv_ringing ( void *av, int32_t call_index, void *_arg ) |
76 | { | 76 | { |
77 | Status *cast = _arg; | 77 | Status *cast = _arg; |
78 | cast->calls[call_index].Caller.status = Ringing; | 78 | cast->calls[call_index].Caller.status = Ringing; |
79 | } | 79 | } |
80 | void callback_recv_starting ( void *av, int32_t call_index, void *_arg ) | 80 | void callback_call_ended ( void *av, int32_t call_index, void *_arg ) |
81 | { | ||
82 | Status *cast = _arg; | ||
83 | cast->calls[call_index].Caller.status = InCall; | ||
84 | } | ||
85 | void callback_recv_ending ( void *av, int32_t call_index, void *_arg ) | ||
86 | { | 81 | { |
87 | Status *cast = _arg; | 82 | Status *cast = _arg; |
88 | cast->calls[call_index].Caller.status = Ended; | ||
89 | } | ||
90 | 83 | ||
84 | if (av == cast->calls[call_index].Caller.av) | ||
85 | cast->calls[call_index].Caller.status = Ended; | ||
86 | else | ||
87 | cast->calls[call_index].Callee.status = Ended; | ||
88 | } | ||
91 | void callback_call_started ( void *av, int32_t call_index, void *_arg ) | 89 | void callback_call_started ( void *av, int32_t call_index, void *_arg ) |
92 | { | 90 | { |
93 | /* | 91 | Status *cast = _arg; |
94 | Status *cast = _arg; | ||
95 | 92 | ||
96 | cast->calls[call_index].Callee.status = InCall;*/ | 93 | if (av == cast->calls[call_index].Caller.av) |
94 | cast->calls[call_index].Caller.status = InCall; | ||
95 | else | ||
96 | cast->calls[call_index].Callee.status = InCall; | ||
97 | } | 97 | } |
98 | void callback_call_canceled ( void *av, int32_t call_index, void *_arg ) | 98 | void callback_call_canceled ( void *av, int32_t call_index, void *_arg ) |
99 | { | 99 | { |
100 | /* | ||
101 | Status *cast = _arg; | ||
102 | |||
103 | cast->calls[call_index].Callee.status = Cancel;*/ | ||
104 | } | 100 | } |
105 | void callback_call_rejected ( void *av, int32_t call_index, void *_arg ) | 101 | void callback_call_rejected ( void *av, int32_t call_index, void *_arg ) |
106 | { | 102 | { |
107 | Status *cast = _arg; | 103 | Status *cast = _arg; |
108 | cast->calls[call_index].Caller.status = Rejected; | 104 | cast->calls[call_index].Caller.status = Rejected; |
109 | } | 105 | } |
110 | void callback_call_ended ( void *av, int32_t call_index, void *_arg ) | ||
111 | { | ||
112 | /* | ||
113 | Status *cast = _arg; | ||
114 | |||
115 | cast->calls[call_index].Callee.status = Ended;*/ | ||
116 | } | ||
117 | 106 | ||
118 | void callback_requ_timeout ( void *av, int32_t call_index, void *_arg ) | 107 | void callback_requ_timeout ( void *av, int32_t call_index, void *_arg ) |
119 | { | 108 | { |
120 | //ck_assert_msg(0, "No answer!"); | 109 | ck_assert_msg(0, "No answer!"); |
121 | } | 110 | } |
122 | 111 | ||
123 | static void callback_audio(ToxAv *av, int32_t call_index, int16_t *data, int length, void *userdata) | 112 | void callback_audio (void *agent, int32_t call_idx, const int16_t *PCM, uint16_t size, void *data) |
124 | { | 113 | {} |
125 | } | ||
126 | 114 | ||
127 | static void callback_video(ToxAv *av, int32_t call_index, vpx_image_t *img, void *userdata) | 115 | void callback_video (void *agent, int32_t call_idx, const vpx_image_t *img, void *data) |
128 | { | 116 | {} |
129 | } | ||
130 | 117 | ||
131 | void register_callbacks(ToxAv *av, void *data) | 118 | void register_callbacks(ToxAv *av, void *data) |
132 | { | 119 | { |
@@ -135,16 +122,12 @@ void register_callbacks(ToxAv *av, void *data) | |||
135 | toxav_register_callstate_callback(av, callback_call_rejected, av_OnReject, data); | 122 | toxav_register_callstate_callback(av, callback_call_rejected, av_OnReject, data); |
136 | toxav_register_callstate_callback(av, callback_call_ended, av_OnEnd, data); | 123 | toxav_register_callstate_callback(av, callback_call_ended, av_OnEnd, data); |
137 | toxav_register_callstate_callback(av, callback_recv_invite, av_OnInvite, data); | 124 | toxav_register_callstate_callback(av, callback_recv_invite, av_OnInvite, data); |
138 | |||
139 | toxav_register_callstate_callback(av, callback_recv_ringing, av_OnRinging, data); | 125 | toxav_register_callstate_callback(av, callback_recv_ringing, av_OnRinging, data); |
140 | toxav_register_callstate_callback(av, callback_recv_starting, av_OnStarting, data); | ||
141 | toxav_register_callstate_callback(av, callback_recv_ending, av_OnEnding, data); | ||
142 | |||
143 | toxav_register_callstate_callback(av, callback_requ_timeout, av_OnRequestTimeout, data); | 126 | toxav_register_callstate_callback(av, callback_requ_timeout, av_OnRequestTimeout, data); |
144 | 127 | ||
145 | 128 | ||
146 | toxav_register_audio_recv_callback(av, callback_audio, NULL); | 129 | toxav_register_audio_callback(av, callback_audio, NULL); |
147 | toxav_register_video_recv_callback(av, callback_video, NULL); | 130 | toxav_register_video_callback(av, callback_video, NULL); |
148 | } | 131 | } |
149 | /*************************************************************************************************/ | 132 | /*************************************************************************************************/ |
150 | 133 | ||
@@ -159,8 +142,6 @@ void *in_thread_call (void *arg) | |||
159 | int step = 0; | 142 | int step = 0; |
160 | int call_idx; | 143 | int call_idx; |
161 | 144 | ||
162 | call_running[this_call->idx] = 1; | ||
163 | |||
164 | const int frame_size = (av_DefaultSettings.audio_sample_rate * av_DefaultSettings.audio_frame_duration / 1000); | 145 | const int frame_size = (av_DefaultSettings.audio_sample_rate * av_DefaultSettings.audio_frame_duration / 1000); |
165 | int16_t sample_payload[frame_size]; | 146 | int16_t sample_payload[frame_size]; |
166 | randombytes((uint8_t *)sample_payload, sizeof(int16_t) * frame_size); | 147 | randombytes((uint8_t *)sample_payload, sizeof(int16_t) * frame_size); |
@@ -171,8 +152,12 @@ void *in_thread_call (void *arg) | |||
171 | register_callbacks(this_call->Callee.av, arg); | 152 | register_callbacks(this_call->Callee.av, arg); |
172 | 153 | ||
173 | /* NOTE: CALLEE WILL ALWAHYS NEED CALL_IDX == 0 */ | 154 | /* NOTE: CALLEE WILL ALWAHYS NEED CALL_IDX == 0 */ |
155 | pthread_mutex_lock(&muhmutex); | ||
156 | |||
174 | while (call_running[this_call->idx]) { | 157 | while (call_running[this_call->idx]) { |
175 | 158 | ||
159 | pthread_mutex_unlock(&muhmutex); | ||
160 | |||
176 | switch ( step ) { | 161 | switch ( step ) { |
177 | case 0: /* CALLER */ | 162 | case 0: /* CALLER */ |
178 | toxav_call(this_call->Caller.av, &call_idx, this_call->Callee.id, &av_DefaultSettings, 10); | 163 | toxav_call(this_call->Caller.av, &call_idx, this_call->Callee.id, &av_DefaultSettings, 10); |
@@ -181,28 +166,36 @@ void *in_thread_call (void *arg) | |||
181 | break; | 166 | break; |
182 | 167 | ||
183 | case 1: /* CALLEE */ | 168 | case 1: /* CALLEE */ |
169 | pthread_mutex_lock(&muhmutex); | ||
170 | |||
184 | if (this_call->Caller.status == Ringing) { | 171 | if (this_call->Caller.status == Ringing) { |
185 | call_print(call_idx, "Callee answers ..."); | 172 | call_print(call_idx, "Callee answers ..."); |
173 | pthread_mutex_unlock(&muhmutex); | ||
186 | toxav_answer(this_call->Callee.av, 0, &av_DefaultSettings); | 174 | toxav_answer(this_call->Callee.av, 0, &av_DefaultSettings); |
187 | step++; | 175 | step++; |
188 | start = time(NULL); | 176 | start = time(NULL); |
177 | pthread_mutex_lock(&muhmutex); | ||
189 | } | 178 | } |
190 | 179 | ||
180 | pthread_mutex_unlock(&muhmutex); | ||
191 | break; | 181 | break; |
192 | 182 | ||
193 | case 2: /* Rtp transmission */ | 183 | case 2: /* Rtp transmission */ |
184 | pthread_mutex_lock(&muhmutex); | ||
185 | |||
194 | if (this_call->Caller.status == InCall) { /* I think this is okay */ | 186 | if (this_call->Caller.status == InCall) { /* I think this is okay */ |
195 | call_print(call_idx, "Sending rtp ..."); | 187 | call_print(call_idx, "Sending rtp ..."); |
188 | pthread_mutex_unlock(&muhmutex); | ||
196 | 189 | ||
197 | c_sleep(1000); /* We have race condition here */ | 190 | c_sleep(1000); /* We have race condition here */ |
198 | toxav_prepare_transmission(this_call->Callee.av, 0, 3, 0, 1); | 191 | toxav_prepare_transmission(this_call->Callee.av, 0, 1); |
199 | toxav_prepare_transmission(this_call->Caller.av, call_idx, 3, 0, 1); | 192 | toxav_prepare_transmission(this_call->Caller.av, call_idx, 1); |
200 | 193 | ||
201 | int payload_size = toxav_prepare_audio_frame(this_call->Caller.av, call_idx, prepared_payload, RTP_PAYLOAD_SIZE, | 194 | int payload_size = toxav_prepare_audio_frame(this_call->Caller.av, call_idx, prepared_payload, RTP_PAYLOAD_SIZE, |
202 | sample_payload, frame_size); | 195 | sample_payload, frame_size); |
203 | 196 | ||
204 | if ( payload_size < 0 ) { | 197 | if ( payload_size < 0 ) { |
205 | //ck_assert_msg ( 0, "Failed to encode payload" ); | 198 | ck_assert_msg ( 0, "Failed to encode payload" ); |
206 | } | 199 | } |
207 | 200 | ||
208 | 201 | ||
@@ -229,24 +222,36 @@ void *in_thread_call (void *arg) | |||
229 | /* Call over CALLER hangs up */ | 222 | /* Call over CALLER hangs up */ |
230 | toxav_hangup(this_call->Caller.av, call_idx); | 223 | toxav_hangup(this_call->Caller.av, call_idx); |
231 | call_print(call_idx, "Hanging up ..."); | 224 | call_print(call_idx, "Hanging up ..."); |
225 | |||
226 | pthread_mutex_lock(&muhmutex); | ||
232 | } | 227 | } |
233 | 228 | ||
229 | pthread_mutex_unlock(&muhmutex); | ||
234 | break; | 230 | break; |
235 | 231 | ||
236 | case 3: /* Wait for Both to have status ended */ | 232 | case 3: /* Wait for Both to have status ended */ |
233 | pthread_mutex_lock(&muhmutex); | ||
234 | |||
237 | if (this_call->Caller.status == Ended) { | 235 | if (this_call->Caller.status == Ended) { |
236 | pthread_mutex_unlock(&muhmutex); | ||
238 | c_sleep(1000); /* race condition */ | 237 | c_sleep(1000); /* race condition */ |
238 | pthread_mutex_lock(&muhmutex); | ||
239 | this_call->Callee.status = Ended; | 239 | this_call->Callee.status = Ended; |
240 | call_running[this_call->idx] = 0; | 240 | call_running[this_call->idx] = 0; |
241 | } | 241 | } |
242 | 242 | ||
243 | pthread_mutex_unlock(&muhmutex); | ||
244 | |||
243 | break; | 245 | break; |
244 | 246 | ||
245 | } | 247 | } |
246 | 248 | ||
247 | c_sleep(20); | 249 | c_sleep(20); |
250 | |||
251 | pthread_mutex_lock(&muhmutex); | ||
248 | } | 252 | } |
249 | 253 | ||
254 | pthread_mutex_unlock(&muhmutex); | ||
250 | call_print(call_idx, "Call ended successfully!"); | 255 | call_print(call_idx, "Call ended successfully!"); |
251 | pthread_exit(NULL); | 256 | pthread_exit(NULL); |
252 | } | 257 | } |
@@ -255,8 +260,8 @@ void *in_thread_call (void *arg) | |||
255 | 260 | ||
256 | 261 | ||
257 | 262 | ||
258 | // START_TEST(test_AV_three_calls) | 263 | START_TEST(test_AV_three_calls) |
259 | void test_AV_three_calls() | 264 | // void test_AV_three_calls() |
260 | { | 265 | { |
261 | long long unsigned int cur_time = time(NULL); | 266 | long long unsigned int cur_time = time(NULL); |
262 | Tox *bootstrap_node = tox_new(0); | 267 | Tox *bootstrap_node = tox_new(0); |
@@ -268,12 +273,12 @@ void test_AV_three_calls() | |||
268 | }; | 273 | }; |
269 | 274 | ||
270 | 275 | ||
271 | //ck_assert_msg(bootstrap_node != NULL, "Failed to create bootstrap node"); | 276 | ck_assert_msg(bootstrap_node != NULL, "Failed to create bootstrap node"); |
272 | 277 | ||
273 | int i = 0; | 278 | int i = 0; |
274 | 279 | ||
275 | for (; i < 3; i ++) { | 280 | for (; i < 3; i ++) { |
276 | //ck_assert_msg(callees[i] != NULL, "Failed to create 3 tox instances"); | 281 | ck_assert_msg(callees[i] != NULL, "Failed to create 3 tox instances"); |
277 | } | 282 | } |
278 | 283 | ||
279 | for ( i = 0; i < 3; i ++ ) { | 284 | for ( i = 0; i < 3; i ++ ) { |
@@ -283,7 +288,7 @@ void test_AV_three_calls() | |||
283 | tox_get_address(callees[i], address); | 288 | tox_get_address(callees[i], address); |
284 | 289 | ||
285 | int test = tox_add_friend(caller, address, (uint8_t *)"gentoo", 7); | 290 | int test = tox_add_friend(caller, address, (uint8_t *)"gentoo", 7); |
286 | //ck_assert_msg( test == i, "Failed to add friend error code: %i", test); | 291 | ck_assert_msg( test == i, "Failed to add friend error code: %i", test); |
287 | } | 292 | } |
288 | 293 | ||
289 | uint8_t off = 1; | 294 | uint8_t off = 1; |
@@ -333,8 +338,10 @@ void test_AV_three_calls() | |||
333 | 338 | ||
334 | pthread_mutex_init(&muhmutex, NULL); | 339 | pthread_mutex_init(&muhmutex, NULL); |
335 | 340 | ||
336 | for ( i = 0; i < 3; i++ ) | 341 | for ( i = 0; i < 3; i++ ) { |
342 | call_running[i] = 1; | ||
337 | pthread_create(&status_control.calls[i].tid, NULL, in_thread_call, &status_control.calls[i]); | 343 | pthread_create(&status_control.calls[i].tid, NULL, in_thread_call, &status_control.calls[i]); |
344 | } | ||
338 | 345 | ||
339 | /* Now start 3 calls and they'll run for 10 s */ | 346 | /* Now start 3 calls and they'll run for 10 s */ |
340 | 347 | ||
@@ -350,6 +357,13 @@ void test_AV_three_calls() | |||
350 | tox_do(callees[1]); | 357 | tox_do(callees[1]); |
351 | tox_do(callees[2]); | 358 | tox_do(callees[2]); |
352 | 359 | ||
360 | for ( i = 0; i < 3; i++ ) | ||
361 | toxav_do(status_control.calls[0].Caller.av); | ||
362 | |||
363 | toxav_do(status_control.calls[0].Callee.av); | ||
364 | toxav_do(status_control.calls[1].Callee.av); | ||
365 | toxav_do(status_control.calls[2].Callee.av); | ||
366 | |||
353 | pthread_mutex_unlock(&muhmutex); | 367 | pthread_mutex_unlock(&muhmutex); |
354 | c_sleep(20); | 368 | c_sleep(20); |
355 | } | 369 | } |
@@ -366,7 +380,7 @@ void test_AV_three_calls() | |||
366 | tox_kill(callees[i]); | 380 | tox_kill(callees[i]); |
367 | 381 | ||
368 | } | 382 | } |
369 | // END_TEST | 383 | END_TEST |
370 | 384 | ||
371 | 385 | ||
372 | 386 | ||
@@ -382,21 +396,22 @@ Suite *tox_suite(void) | |||
382 | 396 | ||
383 | return s; | 397 | return s; |
384 | } | 398 | } |
399 | |||
385 | int main(int argc, char *argv[]) | 400 | int main(int argc, char *argv[]) |
386 | { | 401 | { |
387 | // Suite *tox = tox_suite(); | 402 | Suite *tox = tox_suite(); |
388 | // SRunner *test_runner = srunner_create(tox); | 403 | SRunner *test_runner = srunner_create(tox); |
389 | // | 404 | |
390 | // setbuf(stdout, NULL); | 405 | setbuf(stdout, NULL); |
391 | // | 406 | |
392 | // srunner_run_all(test_runner, CK_NORMAL); | 407 | srunner_run_all(test_runner, CK_NORMAL); |
393 | // int number_failed = srunner_ntests_failed(test_runner); | 408 | int number_failed = srunner_ntests_failed(test_runner); |
394 | // | 409 | |
395 | // srunner_free(test_runner); | 410 | srunner_free(test_runner); |
396 | // | 411 | |
397 | // return number_failed; | 412 | return number_failed; |
398 | 413 | ||
399 | test_AV_three_calls(); | 414 | // test_AV_three_calls(); |
400 | 415 | ||
401 | return 0; | 416 | // return 0; |
402 | } | 417 | } |
diff --git a/build/Makefile.am b/build/Makefile.am index c2667d5d..c0e59645 100644 --- a/build/Makefile.am +++ b/build/Makefile.am | |||
@@ -6,6 +6,7 @@ EXTRA_DIST= | |||
6 | 6 | ||
7 | include ../toxcore/Makefile.inc | 7 | include ../toxcore/Makefile.inc |
8 | include ../toxdns/Makefile.inc | 8 | include ../toxdns/Makefile.inc |
9 | include ../toxencryptsave/Makefile.inc | ||
9 | include ../toxav/Makefile.inc | 10 | include ../toxav/Makefile.inc |
10 | include ../other/Makefile.inc | 11 | include ../other/Makefile.inc |
11 | include ../testing/Makefile.inc | 12 | include ../testing/Makefile.inc |
diff --git a/configure.ac b/configure.ac index b694652d..3a45b35d 100644 --- a/configure.ac +++ b/configure.ac | |||
@@ -82,37 +82,40 @@ AC_ARG_ENABLE([randombytes-stir], | |||
82 | ] | 82 | ] |
83 | ) | 83 | ) |
84 | 84 | ||
85 | AC_ARG_ENABLE([logging], | 85 | AC_ARG_ENABLE([log], |
86 | [AC_HELP_STRING([--enable-logging], [enable logging (default: auto)]) ], | 86 | [AC_HELP_STRING([--enable-log], [enable logging (default: auto)]) ], |
87 | [ | 87 | [ |
88 | if test "x$enableval" = "xyes"; then | 88 | if test "x$enableval" = "xyes"; then |
89 | LOGGING="yes" | 89 | LOGGING="yes" |
90 | 90 | ||
91 | AC_DEFINE([LOGGING], [], [If logging enabled]) | 91 | AC_DEFINE([LOGGING], [], [If logging enabled]) |
92 | AC_DEFINE([LOGGER_LEVEL], [DEBUG], [LoggerLevel value]) | 92 | AC_DEFINE([LOGGER_LEVEL], [LOG_DEBUG], [LOG_LEVEL value]) |
93 | AC_DEFINE_UNQUOTED([LOGGER_OUTPUT_FILE], ["$LOGGING_OUTNAM"], [Output of logger]) | 93 | AC_DEFINE_UNQUOTED([LOGGER_OUTPUT_FILE], ["$LOGGING_OUTNAM"], [Output of logger]) |
94 | fi | 94 | fi |
95 | ] | 95 | ] |
96 | ) | 96 | ) |
97 | 97 | ||
98 | AC_ARG_WITH(logger-level, | 98 | AC_ARG_WITH(log-level, |
99 | AC_HELP_STRING([--with-logger-level=LEVEL], | 99 | AC_HELP_STRING([--with-log-level=LEVEL], |
100 | [Logger levels: INFO; DEBUG; WARNING; ERROR ]), | 100 | [Logger levels: TRACE; DEBUG; INFO; WARNING; ERROR ]), |
101 | [ | 101 | [ |
102 | if test "x$LOGGING" = "xno"; then | 102 | if test "x$LOGGING" = "xno"; then |
103 | AC_MSG_WARN([Logging disabled!]) | 103 | AC_MSG_WARN([Logging disabled!]) |
104 | else | 104 | else |
105 | if test "x$withval" = "xINFO"; then | 105 | if test "x$withval" = "xTRACE"; then |
106 | AC_DEFINE([LOGGER_LEVEL], [INFO], [LoggerLevel value]) | 106 | AC_DEFINE([LOGGER_LEVEL], [LOG_TRACE], [LOG_LEVEL value]) |
107 | 107 | ||
108 | elif test "x$withval" = "xDEBUG"; then | 108 | elif test "x$withval" = "xDEBUG"; then |
109 | AC_DEFINE([LOGGER_LEVEL], [DEBUG], [LoggerLevel value]) | 109 | AC_DEFINE([LOGGER_LEVEL], [LOG_DEBUG], [LOG_LEVEL value]) |
110 | 110 | ||
111 | elif test "x$withval" = "xINFO"; then | ||
112 | AC_DEFINE([LOGGER_LEVEL], [LOG_INFO], [LOG_LEVEL value]) | ||
113 | |||
111 | elif test "x$withval" = "xWARNING"; then | 114 | elif test "x$withval" = "xWARNING"; then |
112 | AC_DEFINE([LOGGER_LEVEL], [WARNING], [LoggerLevel value]) | 115 | AC_DEFINE([LOGGER_LEVEL], [LOG_WARNING], [LOG_LEVEL value]) |
113 | 116 | ||
114 | elif test "x$withval" = "xERROR"; then | 117 | elif test "x$withval" = "xERROR"; then |
115 | AC_DEFINE([LOGGER_LEVEL], [ERROR], [LoggerLevel value]) | 118 | AC_DEFINE([LOGGER_LEVEL], [LOG_ERROR], [LOG_LEVEL value]) |
116 | else | 119 | else |
117 | AC_MSG_WARN([Invalid logger level: $withval. Using default 'DEBUG']) | 120 | AC_MSG_WARN([Invalid logger level: $withval. Using default 'DEBUG']) |
118 | fi | 121 | fi |
@@ -120,8 +123,8 @@ AC_ARG_WITH(logger-level, | |||
120 | ] | 123 | ] |
121 | ) | 124 | ) |
122 | 125 | ||
123 | AC_ARG_WITH(logger-path, | 126 | AC_ARG_WITH(log-path, |
124 | AC_HELP_STRING([--with-logger-path=DIR], | 127 | AC_HELP_STRING([--with-log-path=DIR], |
125 | [Path of logger output]), | 128 | [Path of logger output]), |
126 | [ | 129 | [ |
127 | if test "x$LOGGING" = "xno"; then | 130 | if test "x$LOGGING" = "xno"; then |
@@ -371,20 +374,20 @@ else | |||
371 | LDFLAGS_SAVE="$LDFLAGS" | 374 | LDFLAGS_SAVE="$LDFLAGS" |
372 | if test -n "$LIBSODIUM_SEARCH_LIBS"; then | 375 | if test -n "$LIBSODIUM_SEARCH_LIBS"; then |
373 | LDFLAGS="-L$LIBSODIUM_SEARCH_LIBS $LDFLAGS" | 376 | LDFLAGS="-L$LIBSODIUM_SEARCH_LIBS $LDFLAGS" |
374 | AC_CHECK_LIB(sodium, randombytes_random, | 377 | AC_CHECK_LIB(sodium, crypto_pwhash_scryptsalsa208sha256, |
375 | [ | 378 | [ |
376 | LIBSODIUM_LDFLAGS="-L$LIBSODIUM_SEARCH_LIBS" | 379 | LIBSODIUM_LDFLAGS="-L$LIBSODIUM_SEARCH_LIBS" |
377 | LIBSODIUM_LIBS="-lsodium" | 380 | LIBSODIUM_LIBS="-lsodium" |
378 | ], | 381 | ], |
379 | [ | 382 | [ |
380 | AC_MSG_ERROR([required library libsodium was not found in requested location $LIBSODIUM_SEARCH_LIBS]) | 383 | AC_MSG_ERROR([required library libsodium was not found in requested location $LIBSODIUM_SEARCH_LIBS or library version is too old]) |
381 | ] | 384 | ] |
382 | ) | 385 | ) |
383 | else | 386 | else |
384 | AC_CHECK_LIB(sodium, randombytes_random, | 387 | AC_CHECK_LIB(sodium, crypto_pwhash_scryptsalsa208sha256, |
385 | [], | 388 | [], |
386 | [ | 389 | [ |
387 | AC_MSG_ERROR([required library libsodium was not found on your system, please check http://download.libsodium.org/libsodium/releases/]) | 390 | AC_MSG_ERROR([required library libsodium was not found on your system, please check http://download.libsodium.org/libsodium/releases/ or library version is too old]) |
388 | ] | 391 | ] |
389 | ) | 392 | ) |
390 | fi | 393 | fi |
@@ -489,6 +492,13 @@ AX_PTHREAD( | |||
489 | ] | 492 | ] |
490 | ) | 493 | ) |
491 | 494 | ||
495 | AC_CHECK_LIB([pthread], [pthread_self], | ||
496 | [ | ||
497 | PTHREAD_LDFLAGS="-lpthread" | ||
498 | AC_SUBST(PTHREAD_LDFLAGS) | ||
499 | ] | ||
500 | ) | ||
501 | |||
492 | if test "x$BUILD_AV" = "xyes"; then | 502 | if test "x$BUILD_AV" = "xyes"; then |
493 | PKG_CHECK_MODULES([OPUS], [opus], | 503 | PKG_CHECK_MODULES([OPUS], [opus], |
494 | [], | 504 | [], |
@@ -512,8 +522,7 @@ fi | |||
512 | if test "x$BUILD_AV" = "xyes"; then | 522 | if test "x$BUILD_AV" = "xyes"; then |
513 | # toxcore lib needs an global? | 523 | # toxcore lib needs an global? |
514 | # So far this works okay | 524 | # So far this works okay |
515 | ## What about pthread? | 525 | AV_LIBS="$OPUS_LIBS $VPX_LIBS" |
516 | AV_LIBS="$OPUS_LIBS $VPX_LIBS -pthread" | ||
517 | AC_SUBST(AV_LIBS) | 526 | AC_SUBST(AV_LIBS) |
518 | 527 | ||
519 | AV_CFLAGS="$OPUS_CFLAGS $VPX_CFLAGS" | 528 | AV_CFLAGS="$OPUS_CFLAGS $VPX_CFLAGS" |
diff --git a/docs/Avatars.md b/docs/Avatars.md new file mode 100644 index 00000000..31138af7 --- /dev/null +++ b/docs/Avatars.md | |||
@@ -0,0 +1,631 @@ | |||
1 | # User avatars in Tox | ||
2 | |||
3 | |||
4 | |||
5 | ## Introduction and rationale | ||
6 | |||
7 | User avatars are small icons or images used to identify users in the friend | ||
8 | list; they exist in virtually all VoIP and IM protocols and provide an easy | ||
9 | way for one user to identify another in the friend list. | ||
10 | |||
11 | This document describes the implementation of avatars in the Tox protocol, | ||
12 | according to the following design considerations: | ||
13 | |||
14 | - Avatars are handled as private information, i.e., they are only exchanged | ||
15 | over Tox encrypted channels among previously authenticated friends; | ||
16 | |||
17 | - The library treats all images as blobs and does not interpret or | ||
18 | understand image formats. It only ensures that the avatar data sent by | ||
19 | a user is correctly received by the other. The client application is | ||
20 | responsible for validating, decoding, resizing, and presenting the | ||
21 | image to the user. | ||
22 | |||
23 | - There is a strict limit of 16 KiB to the avatar raw data size -- this | ||
24 | seems suitable for practical use as, for example, the raw data of an | ||
25 | uncompressed 64 x 64 pixels 24 bpp RGB bitmap is 12288 bytes long; the | ||
26 | data limit provides enough space for larger bitmaps if the usual | ||
27 | compressed formats are used. | ||
28 | |||
29 | **Notice:** As designed, this limit can be changed in the future without | ||
30 | breaking the protocol compatibility, but clients using the original | ||
31 | limit will reject larger avatars. | ||
32 | |||
33 | - The protocol MUST provide means to allow caching and avoid unnecessary | ||
34 | data transfers. | ||
35 | |||
36 | - Avatars are transfered between clients in a background operation. | ||
37 | |||
38 | - Avatars are served on a "best effort" basis, without breaking clients | ||
39 | which do not support them. | ||
40 | |||
41 | - The protocol MUST resist to malicious users. | ||
42 | |||
43 | - The protocol MUST work with both UDP and TCP networks. | ||
44 | |||
45 | |||
46 | The Single Tox Standard Draft v.0.1.0 recommends implementing avatars as | ||
47 | a purely client-side feature through a procedure that can be summarized as | ||
48 | sending a specially named file as a file transfer request and accepting | ||
49 | it silently. This procedure can be improved to provide the previously stated | ||
50 | design considerations, but this requires a higher integration with the core | ||
51 | protocol. Moving this feature to the core protocol also: | ||
52 | |||
53 | - provides a simpler and cleaner interface for client applications; | ||
54 | |||
55 | - hides protocol complexities from the client; | ||
56 | |||
57 | - avoids code duplication and ad-hoc protocols in the clients; | ||
58 | |||
59 | - avoids incompatibility between client implementations; | ||
60 | |||
61 | - allows important optimizations, such as lightweight notification of | ||
62 | removed and updated avatars; | ||
63 | |||
64 | - plays well with cache schemes; | ||
65 | |||
66 | - makes avatar transfer essentially a background operation. | ||
67 | |||
68 | |||
69 | |||
70 | |||
71 | |||
72 | |||
73 | ## High level description | ||
74 | |||
75 | |||
76 | This is a very high level description. The usage patterns expected from | ||
77 | client applications are described in the section "Using Avatars in Client | ||
78 | Applications", and a low level protocol description is available in the | ||
79 | section "Internal Protocol Description".) | ||
80 | The avatar exchange is implemented with the following new elements in the | ||
81 | Tox protocol: | ||
82 | |||
83 | - **Avatar Information Notifications** are events which may be sent by | ||
84 | a user to another anytime, but are usually sent after one of them | ||
85 | connects to the network, changes his avatar, or in reply to an **avatar | ||
86 | information request**. They are delivered by a very lightweight message | ||
87 | but with information enough to allow a user to validate or discard an | ||
88 | avatar from the local cache and to decide if it is interesting to request | ||
89 | the avatar data from the peer. | ||
90 | |||
91 | This event contains two data fields: (1) the image format, and (2) the | ||
92 | cryptographic hash of the current image data. The image format may be | ||
93 | NONE (for users who have no avatar or removed their avatars) or PNG. The | ||
94 | cryptographic hash is intended to be compared with the hash of the | ||
95 | currently cached avatar (if any) in order to check if it is still up to | ||
96 | date. | ||
97 | |||
98 | - **Avatar Information Requests** are very lightweight messages sent by a | ||
99 | user asking for an **avatar information notification**. They may be sent | ||
100 | as part of the login process or when the client thinks the currently | ||
101 | cached avatar is outdated. The receiver may or may not answer to this | ||
102 | request. This message contains no data fields. | ||
103 | |||
104 | - An **Avatar Data Request** is sent by a user asking another for his | ||
105 | complete avatar data. It is sent only when the requesting user decides | ||
106 | the avatar does not exist in the local cache or is outdated. The receiver | ||
107 | may or may not answer to this request. This message contains no data | ||
108 | fields. | ||
109 | |||
110 | - An **Avatar Data Notification** is an event signaling the client that | ||
111 | the complete avatar image data of another user is available. The actual | ||
112 | data transfer is implemented using several data and control messages, | ||
113 | but the details are hidden from the client applications. This event can | ||
114 | only arrive in reply to an **avatar data request**. | ||
115 | |||
116 | This event contains three data fields: (1) the image format, (2) the | ||
117 | cryptographic hash of the image data, and (3) the raw image data. If the | ||
118 | image format is NONE (i.e. no avatar) the hash is zeroed and the image | ||
119 | data is empty. The raw image data is locally validated and ensured to | ||
120 | match the hash (the event is **not** triggered otherwise). | ||
121 | |||
122 | |||
123 | |||
124 | |||
125 | |||
126 | ## API | ||
127 | |||
128 | To implement this feature, the following public symbols were added. The | ||
129 | complete API documentation is available in `tox.h`. | ||
130 | |||
131 | |||
132 | ``` | ||
133 | #define TOX_AVATAR_MAX_DATA_LENGTH 16384 | ||
134 | #define TOX_HASH_LENGTH 32 | ||
135 | |||
136 | |||
137 | /* Data formats for user avatar images */ | ||
138 | typedef enum { | ||
139 | TOX_AVATAR_FORMAT_NONE, | ||
140 | TOX_AVATAR_FORMAT_PNG | ||
141 | } | ||
142 | TOX_AVATAR_FORMAT; | ||
143 | |||
144 | |||
145 | |||
146 | /* Set the user avatar image data. */ | ||
147 | int tox_set_avatar(Tox *tox, uint8_t format, const uint8_t *data, uint32_t length); | ||
148 | |||
149 | /* Removes the user avatar image data. */ | ||
150 | int tox_unset_avatar(Tox *tox); | ||
151 | |||
152 | /* Get avatar data from the current user. */ | ||
153 | int tox_get_self_avatar(const Tox *tox, uint8_t *format, uint8_t *buf, uint32_t *length, uint32_t maxlen, uint8_t *hash); | ||
154 | |||
155 | /* Generates a cryptographic hash of the given data (usually a cached avatar). */ | ||
156 | int tox_hash(uint8_t *hash, const uint8_t *data, const uint32_t datalen); | ||
157 | |||
158 | /* Request avatar information from a friend. */ | ||
159 | int tox_request_avatar_info(const Tox *tox, const int32_t friendnumber); | ||
160 | |||
161 | /* Send an unrequested avatar information to a friend. */ | ||
162 | int tox_send_avatar_info(Tox *tox, const int32_t friendnumber); | ||
163 | |||
164 | /* Request the avatar data from a friend. */ | ||
165 | int tox_request_avatar_data(const Tox *tox, const int32_t friendnumber); | ||
166 | |||
167 | /* Set the callback function for avatar data. */ | ||
168 | void tox_callback_avatar_info(Tox *tox, void (*function)(Tox *tox, int32_t, uint8_t, uint8_t*, void *), void *userdata); | ||
169 | |||
170 | /* Set the callback function for avatar data. */ | ||
171 | void tox_callback_avatar_data(Tox *tox, void (*function)(Tox *tox, int32_t, uint8_t, uint8_t*, uint8_t*, uint32_t, void *), void *userdata); | ||
172 | ``` | ||
173 | |||
174 | |||
175 | |||
176 | |||
177 | ## Using Avatars in Client Applications | ||
178 | |||
179 | |||
180 | ### General recommendations | ||
181 | |||
182 | - Clients MUST NOT imply the availability of avatars in other users. | ||
183 | Avatars are an optional feature and not all users and clients may | ||
184 | support them; | ||
185 | |||
186 | - Clients MUST NOT block waiting for avatar information and avatar data | ||
187 | packets; | ||
188 | |||
189 | - Clients MUST treat avatar data as insecure and potentially malicious; | ||
190 | For example, users may accidentally use corrupted images as avatars, | ||
191 | a malicious user may send a specially crafted image to exploit a know | ||
192 | vulnerability in an image decoding library, etc. It is recommended to | ||
193 | handle the avatar image data in the same way as an image downloaded | ||
194 | from an unknown Internet source; | ||
195 | |||
196 | - The peers MUST NOT assume any coupling between the operations of | ||
197 | receiving an avatar information packet, sending unrequested avatar | ||
198 | information packets, requesting avatar data, or receiving avatar data. | ||
199 | |||
200 | For example, the following situations are valid: | ||
201 | |||
202 | * A text-mode client may send avatars to other users, but never | ||
203 | request them; | ||
204 | |||
205 | * A client may not understand a particular image format and ignore | ||
206 | avatars using it, but request and handle other formats; | ||
207 | |||
208 | * A client on a slow mobile network may ask for avatar information to | ||
209 | ensure its cached avatars are still valid, but do not request avatar | ||
210 | data. The same client may start asking for avatar data once it | ||
211 | connects through a fast network. | ||
212 | |||
213 | - Clients SHOULD implement a local cache of avatars and do not request | ||
214 | avatar data from other peers unless necessary; | ||
215 | |||
216 | - When an avatar information is received, the client should delete the | ||
217 | avatar if the new avatar format is NONE or compare the hash received | ||
218 | from the peer with the hash of the currently cached avatar. If they | ||
219 | differ, send an avatar data request; | ||
220 | |||
221 | - If the cached avatar is older than a given threshold, the client may | ||
222 | also send an avatar info request to that friend once he is online and | ||
223 | mark the avatar as updated *before* any avatar information is received | ||
224 | (to not spam the peer with such requests); | ||
225 | |||
226 | - When an avatar data notification is received, the client must update | ||
227 | the cached avatar with the new one; | ||
228 | |||
229 | - Clients should resize or crop the image to the way it better adapts | ||
230 | to the client user interface; | ||
231 | |||
232 | - If the user already have an avatar defined in the client configuration, | ||
233 | it must be set before connecting to the network to avoid spurious avatar | ||
234 | change notifications and unnecessary data transfers. | ||
235 | |||
236 | - If no avatar data is available for a given friend, the client should | ||
237 | show a placeholder image. | ||
238 | |||
239 | |||
240 | |||
241 | ### Interoperability and sharing avatars among different clients | ||
242 | |||
243 | **This section is a tentative recommendation of how clients should store | ||
244 | avatars to ensure local interoperability and should be revised if this | ||
245 | code is accepted into Tox core.** | ||
246 | |||
247 | It is desirable that the user avatar and the cached friends avatars could be | ||
248 | shared among different Tox clients in the same system, in the spirit of the | ||
249 | proposed Single Tox Standard. This not only makes switching from one client | ||
250 | to another easier, but also minimizes the need of data transfers, as avatars | ||
251 | already downloaded by other clients can be reused. | ||
252 | |||
253 | Given the Tox data directory described in STS Draft v0.1.0: | ||
254 | |||
255 | - Avatars are stored in a directory called "avatars" and named | ||
256 | as "xxxxx.png", where "xxxxx" is the complete public key (but not friend | ||
257 | address!) encoded as an uppercase hexadecimal string and "png" is the | ||
258 | extension for the PNG avatar. As new image formats may be used in the | ||
259 | future, clients should ensure no other file "xxxxx.*" exists. No file | ||
260 | should be kept for a user who has no avatar. | ||
261 | |||
262 | - The client's own avatar is not special and is stored like any other. This | ||
263 | is partially for simplicity, and partially in anticipation of profiles. | ||
264 | |||
265 | - The avatar should be stored as its received, before any modifications by | ||
266 | the client for display purposes. | ||
267 | |||
268 | - The hash, as calculated by toxcore and passed in to the data callback, | ||
269 | should be saved in "avatars/xxxxx.hash" where "xxxxx" means the | ||
270 | same thing as for avatars. (The filename is longer than the file :) ) | ||
271 | |||
272 | **To be discussed:** User keys are usually presented in Tox clients as | ||
273 | upper case strings, but lower case file names are more usual. | ||
274 | |||
275 | |||
276 | Example for Linux and other Unix systems, assuming an user called "gildor": | ||
277 | |||
278 | Tox data directory: /home/gildor/.config/tox/ | ||
279 | Tox data file: /home/gildor/.config/tox/data | ||
280 | Avatar data dir: /home/gildor/.config/tox/avatars/ | ||
281 | Gildor's avatar: /home/gildor/.config/tox/avatars/446F4E6F744D6564646C65496E546865416666616972734F6657697A61726473.png | ||
282 | Elrond's avatar: /home/gildor/.config/tox/avatars/43656C65627269616E20646F6E277420546F782E426164206D656D6F72696573.png | ||
283 | Elrond's hash: /home/gildor/.config/tox/avatars/43656C65627269616E20646F6E277420546F782E426164206D656D6F72696573.hash | ||
284 | Elladan's avatar: /home/gildor/.config/tox/avatars/49486174655768656E48756D616E735468696E6B49416D4D7942726F74686572.png | ||
285 | Elladan's hash: /home/gildor/.config/tox/avatars/49486174655768656E48756D616E735468696E6B49416D4D7942726F74686572.hash | ||
286 | Elrohir's avatar /home/gildor/.config/tox/avatars/726568746F7242794D6D41496B6E696854736E616D75486E6568576574614849.png | ||
287 | Elrohir's hash: /home/gildor/.config/tox/avatars/726568746F7242794D6D41496B6E696854736E616D75486E6568576574614849.hash | ||
288 | |||
289 | This recommendation is partially implemented by "testing/test_avatars.c". | ||
290 | |||
291 | |||
292 | |||
293 | |||
294 | |||
295 | ### Common operations | ||
296 | |||
297 | These are minimal examples of how perform common operations with avatar | ||
298 | functions. For a complete, working, example, see `testing/test_avatars.c`. | ||
299 | |||
300 | |||
301 | #### Setting an avatar for the current user | ||
302 | |||
303 | In this example `load_data_file` is just an hypothetical function that loads | ||
304 | data from a file into the buffer and sets the length accordingly. | ||
305 | |||
306 | uint8_t buf[TOX_AVATAR_MAX_DATA_LENGTH]; | ||
307 | uint32_t len; | ||
308 | |||
309 | if (load_data_file("avatar.png", buf, &len) == 0) | ||
310 | if (tox_set_avatar(tox, TOX_AVATAR_FORMAT_PNG, buf, len) != 0) | ||
311 | fprintf(stderr, "Failed to set avatar.\n"); | ||
312 | |||
313 | If the user is connected, this function will also notify all connected | ||
314 | friends about the avatar change. | ||
315 | |||
316 | If the user already have an avatar defined in the client configuration, it | ||
317 | must be set before connecting to the network to avoid spurious avatar change | ||
318 | notifications and unnecessary data transfers. | ||
319 | |||
320 | |||
321 | |||
322 | |||
323 | #### Removing the avatar from the current user | ||
324 | |||
325 | To remove the current avatar, an application must call | ||
326 | |||
327 | tox_unset_avatar(tox); | ||
328 | |||
329 | the effect is the same as setting the avatar format to `TOX_AVATAR_FORMAT_NONE` | ||
330 | and with no data: | ||
331 | |||
332 | tox_set_avatar(tox, TOX_AVATAR_FORMAT_NONE, NULL, 0); | ||
333 | |||
334 | If the user is connected, this function will also notify all connected | ||
335 | friends about the avatar change. | ||
336 | |||
337 | |||
338 | |||
339 | |||
340 | |||
341 | #### Receiving avatar information from friends | ||
342 | |||
343 | All avatar information is passed to a callback function with the prototype: | ||
344 | |||
345 | void function(Tox *tox, int32_t friendnumber, uint8_t format, | ||
346 | uint8_t *hash, uint8_t *data, uint32_t datalen, void *userdata) | ||
347 | |||
348 | As in this example: | ||
349 | |||
350 | static void avatar_info_cb(Tox *tox, int32_t friendnumber, uint8_t format, | ||
351 | uint8_t *hash, void *userdata) | ||
352 | { | ||
353 | printf("Receiving avatar information from friend %d. Format = %d\n", | ||
354 | friendnumber, format); | ||
355 | printf("Data hash: "); | ||
356 | hex_printf(hash, TOX_HASH_LENGTH); /* Hypothetical function */ | ||
357 | printf("\n"); | ||
358 | } | ||
359 | |||
360 | And, somewhere in the Tox initialization calls, set if as the callback to be | ||
361 | triggered when an avatar information event arrives: | ||
362 | |||
363 | tox_callback_avatar_info(tox, avatar_info_cb, NULL); | ||
364 | |||
365 | |||
366 | A typical client will test the currently cached avatar against the hash given | ||
367 | in the avatar information event and, if needed, request the avatar data. | ||
368 | |||
369 | |||
370 | |||
371 | #### Receiving avatar data from friends | ||
372 | |||
373 | Avatar data events are only delivered in reply of avatar data requests which | ||
374 | **should** only be sent after getting the user avatar information (format | ||
375 | and hash) from an avatar information event and checking it against a local | ||
376 | cache. | ||
377 | |||
378 | For this, an application must define an avatar information callback which | ||
379 | checks the local avatar cache and emits an avatar data request if necessary: | ||
380 | |||
381 | static void avatar_info_cb(Tox *tox, int32_t friendnumber, uint8_t format, | ||
382 | uint8_t *hash, void *userdata) | ||
383 | { | ||
384 | printf("Receiving avatar information from friend %d. Format = %d\n", | ||
385 | friendnumber, format); | ||
386 | if (format = TOX_AVATAR_FORMAT_NONE) { | ||
387 | /* User has no avatar or removed the avatar */ | ||
388 | delete_avatar_from_cache(tox, friendnumber); | ||
389 | } else { | ||
390 | /* Use the received hash to check if the cached avatar is | ||
391 | still updated. */ | ||
392 | if (!is_user_cached_avatar_updated(tox, friendnumber, hash)) { | ||
393 | /* User avatar is outdated, send data request */ | ||
394 | tox_request_avatar_data(tox, friendnumber); | ||
395 | } | ||
396 | } | ||
397 | } | ||
398 | |||
399 | |||
400 | Then define an avatar data callback to store the received data in the local | ||
401 | cache: | ||
402 | |||
403 | static void avatar_data_cb(Tox *tox, int32_t friendnumber, uint8_t format, | ||
404 | uint8_t *hash, uint8_t *data, uint32_t datalen, void *userdata) | ||
405 | { | ||
406 | if (format = TOX_AVATAR_FORMAT_NONE) { | ||
407 | /* User has no avatar or removed the avatar */ | ||
408 | delete_avatar_from_cache(tox, friendnumber); | ||
409 | } else { | ||
410 | save_avatar_data_to_cache(tox, friendnumber, format, hash, | ||
411 | data, datalen); | ||
412 | } | ||
413 | } | ||
414 | |||
415 | |||
416 | And, finally, register both callbacks somewhere in the Tox initialization | ||
417 | calls: | ||
418 | |||
419 | tox_callback_avatar_info(tox, avatar_info_cb, NULL); | ||
420 | tox_callback_avatar_data(tox, avatar_data_cb, NULL); | ||
421 | |||
422 | |||
423 | In the previous examples, implementation of the functions to check, store | ||
424 | and retrieve data from the cache were omitted for brevity. These functions | ||
425 | will also need to get the friend public key (client id) from they friend | ||
426 | number and, usually, convert it from a byte string to a hexadecimal | ||
427 | string. A complete, yet more complex, example is available in the file | ||
428 | `testing/test_avatars.c`. | ||
429 | |||
430 | |||
431 | |||
432 | |||
433 | |||
434 | |||
435 | |||
436 | |||
437 | |||
438 | |||
439 | |||
440 | ## Internal Protocol Description | ||
441 | |||
442 | ### New packet types | ||
443 | |||
444 | The avatar transfer protocol adds the following new packet types and ids: | ||
445 | |||
446 | PACKET_ID_AVATAR_INFO_REQ = 52 | ||
447 | PACKET_ID_AVATAR_INFO = 53 | ||
448 | PACKET_ID_AVATAR_DATA_CONTROL = 54 | ||
449 | PACKET_ID_AVATAR_DATA_START = 55 | ||
450 | PACKET_ID_AVATAR_DATA_PUSH = 56 | ||
451 | |||
452 | |||
453 | |||
454 | |||
455 | ### Requesting avatar information | ||
456 | |||
457 | To request avatar information, an user must send a packet of type | ||
458 | `PACKET_ID_AVATAR_INFO_REQ`. This packet has no data fields. Upon | ||
459 | receiving this packet, a client which supports avatars should answer with | ||
460 | a `PACKET_ID_AVATAR_INFO`. The sender must accept that the friend may | ||
461 | not answer at all. | ||
462 | |||
463 | |||
464 | |||
465 | |||
466 | ### Receiving avatar information | ||
467 | |||
468 | Avatar information arrives in a packet of type `PACKET_ID_AVATAR_INFO` with | ||
469 | the following structure: | ||
470 | |||
471 | PACKET_ID_AVATAR_INFO (53) | ||
472 | Packet data size: 33 bytes | ||
473 | [1: uint8_t format][32: uint8_t hash] | ||
474 | |||
475 | Where 'format' is the image data format, one of the following: | ||
476 | |||
477 | 0 = AVATAR_FORMAT_NONE (no avatar set) | ||
478 | 1 = AVATAR_FORMAT_PNG | ||
479 | |||
480 | and 'hash' is the SHA-256 message digest of the avatar data. | ||
481 | |||
482 | This packet may be sent at any time and no previous request is required. | ||
483 | Clients should send this packet upon connection or when a friend | ||
484 | connects, in the same way Tox sends name, status and action information. | ||
485 | |||
486 | |||
487 | |||
488 | |||
489 | |||
490 | ### Requesting avatar data | ||
491 | |||
492 | Transmission of avatar data is a multi-step procedure using three new packet | ||
493 | types. | ||
494 | |||
495 | - Packet `PACKET_ID_AVATAR_DATA_CONTROL` have the format: | ||
496 | |||
497 | PACKET_ID_AVATAR_DATA_CONTROL (54) | ||
498 | Packet data size: 1 byte | ||
499 | [1: uint8_t op] | ||
500 | |||
501 | where 'op' is a code signaling both an operation request or a status | ||
502 | return, which semantics are explained bellow. The following values are | ||
503 | defined: | ||
504 | |||
505 | 0 = AVATAR_DATACONTROL_REQ | ||
506 | 1 = AVATAR_DATACONTROL_ERROR | ||
507 | |||
508 | |||
509 | - Packet `PACKET_ID_AVATAR_DATA_START` have the following format: | ||
510 | |||
511 | PACKET_ID_AVATAR_DATA_START (55) | ||
512 | Packet data size: 37 bytes | ||
513 | [1: uint8_t format][32: uint8_t hash][1: uint32_t data_length] | ||
514 | |||
515 | |||
516 | where 'format' is the image format, with the same values accepted for | ||
517 | the field 'format' in packet type `PACKET_ID_AVATAR_INFO`, 'hash' is | ||
518 | the SHA-256 cryptographic hash of the avatar raw data and 'data_length' | ||
519 | is the total number of bytes the raw avatar data. | ||
520 | |||
521 | |||
522 | - Packet `PACKET_ID_AVATAR_DATA_PUSH` has no format structure, just up | ||
523 | to `AVATAR_DATA_MAX_CHUNK_SIZE` bytes of raw avatar image data; this | ||
524 | value is defined according to the maximum amount of data a Tox crypted | ||
525 | packet can hold. | ||
526 | |||
527 | |||
528 | |||
529 | The following procedure assumes that a client "A" is requesting avatar data | ||
530 | from a client "B": | ||
531 | |||
532 | - "A" must initialize its control structures and mark its data transfer | ||
533 | as not yet started. Then it requests avatar data from "B" by sending a | ||
534 | packet `PACKET_ID_AVATAR_DATA_CONTROL` with 'op' set to | ||
535 | `AVATAR_DATACONTROL_REQ`. | ||
536 | |||
537 | - If "B" accepts this transfer, it answers by sending an | ||
538 | `PACKET_ID_AVATAR_DATA_START` with the fields 'format', 'hash' and | ||
539 | 'data_length' set to the respective values from the current avatar. | ||
540 | If "B" has no avatar set, 'format' must be `AVATAR_FORMAT_NONE`, 'hash' | ||
541 | must be zeroed and 'data_length' must be zero. | ||
542 | |||
543 | If "B" does not accept sending the avatar, it may send a packet | ||
544 | `PACKET_ID_AVATAR_DATA_CONTROL` with the field 'op' set to | ||
545 | `AVATAR_DATACONTROL_ERROR` or simply ignore this request. "A" must cope | ||
546 | with this. | ||
547 | |||
548 | If "B" have an avatar, it sends a variable number of | ||
549 | `PACKET_ID_AVATAR_DATA_PUSH` packets with the avatar data in a single | ||
550 | shot. | ||
551 | |||
552 | - Upon receiving a `PACKET_ID_AVATAR_DATA_START`, "A" checks if it | ||
553 | has sent a data request to "B". If not, just ignores the packet. | ||
554 | |||
555 | If "A" really requested avatar data and the format is `AVATAR_FORMAT_NONE`, | ||
556 | it triggers the avatar data callback, and clears all the temporary data, | ||
557 | finishing the process. For other formats, "A" just waits for packets | ||
558 | of type `PACKET_ID_AVATAR_DATA_PUSH`. | ||
559 | |||
560 | - Upon receiving a `PACKET_ID_AVATAR_DATA_PUSH`, "A" checks if it really | ||
561 | sent an avatar data request and if the `PACKET_ID_AVATAR_DATA_START` was | ||
562 | already received. If this conditions are valid, it checks if the total | ||
563 | length of the data already stored in the receiving buffer plus the data | ||
564 | present in the push packet is still less or equal than | ||
565 | `TOX_AVATAR_MAX_DATA_LENGTH`. If invalid, it replies with a | ||
566 | `PACKET_ID_AVATAR_DATA_CONTROL` with the field 'op' set to | ||
567 | `AVATAR_DATACONTROL_ERROR`. | ||
568 | |||
569 | If valid, "A" updates the 'bytes_received' counter and concatenates the | ||
570 | newly arrived data to the buffer. | ||
571 | |||
572 | Then "A" checks if all the data was already received by comparing the | ||
573 | counter 'bytes_received' with the field 'total_length'. If they are | ||
574 | equal, "A" takes a SHA-256 hash of the data and compares it with the | ||
575 | hash stored in the field 'hash' received from the first | ||
576 | `PACKET_ID_AVATAR_DATA_START`. | ||
577 | |||
578 | If the hashes match, the avatar data was correctly received and "A" | ||
579 | triggers the avatar data callback, and clears all the temporary data, | ||
580 | finishing the process. | ||
581 | |||
582 | If not all data was received, "A" simply waits for more data. | ||
583 | |||
584 | Client "A" is always responsible for controlling the transfer and | ||
585 | validating the data received. "B" don't need to keep any state for the | ||
586 | protocol, have full control over the data sent and should implement | ||
587 | some transfer limit for the data it sends. | ||
588 | |||
589 | - Any peer receiving a `PACKET_ID_AVATAR_DATA_CONTROL` with the field 'op' | ||
590 | set to `AVATAR_DATACONTROL_ERROR` clears any existing control state and | ||
591 | finishes sending or receiving data. | ||
592 | |||
593 | |||
594 | |||
595 | |||
596 | |||
597 | ## Security considerations | ||
598 | |||
599 | The major security implication of background data transfers of large objects, | ||
600 | like avatars, is the possibility of exhausting the network resources from a | ||
601 | client. This problem is exacerbated when there is the possibility of an | ||
602 | amplification attack as happens, for example, when sending a very small | ||
603 | avatar request message will force the user to reply with a larger avatar | ||
604 | data message. | ||
605 | |||
606 | The present proposal mitigates this situation by: | ||
607 | |||
608 | - Only transferring data between previously authenticated friends; | ||
609 | |||
610 | - Enforcing strict limits on the avatar data size; | ||
611 | |||
612 | - Providing an alternate, smaller, message to cooperative users refresh | ||
613 | avatar information when nothing has changed (`PACKET_ID_AVATAR_INFO`); | ||
614 | |||
615 | - Having per-friend data transfer limit. As the current protocol still | ||
616 | allows an user to request avatar data again and again, the implementation | ||
617 | limits the amount of data a particular user can request for some time. The | ||
618 | exact values are defined in constants `AVATAR_DATA_TRANSFER_LIMIT` and | ||
619 | `AVATAR_DATA_TRANSFER_TIMEOUT` in file `Messenger.c`. | ||
620 | |||
621 | - Making the requester responsible for storing partial data and state | ||
622 | information; | ||
623 | |||
624 | Another problem present in the avatars is the possibility of a friend send | ||
625 | a maliciously crafted image intended to exploit vulnerabilities in image | ||
626 | decoders. Without an intermediate server to recompress and validate and | ||
627 | convert the images to neutral formats, the client applications must handle | ||
628 | this situation by themselves using stable and secure image libraries and | ||
629 | imposing limits on the maximum amount of system resources the decoding | ||
630 | process can take. Images coming from Tox friends must be treated in the same | ||
631 | way as images coming from random Internet sources. | ||
diff --git a/docs/Group-Chats.md b/docs/Group-Chats.md index 5e00b550..e937d549 100644 --- a/docs/Group-Chats.md +++ b/docs/Group-Chats.md | |||
@@ -1,44 +1,52 @@ | |||
1 | Massive public group chats. | 1 | Group chats. |
2 | 2 | ||
3 | Note that not all this document has been implemented: only private (invite only) group chats are currently implemented. | 3 | Note: we assume everyone in the chat trusts each other. |
4 | 4 | ||
5 | Everyone generates a short term public private key pair right before joining | 5 | These group chats work by temporarily adding the 4 "closest" people defined by a distance function |
6 | the chat. | 6 | in group.c in order to form a circle of connected peers. These peers then relay messages to each other. |
7 | 7 | ||
8 | Note that for public group chats it is impossible to protect the chat from | 8 | A friend invites another friend to a group chat by sending them an invite packet. The friend either ignores |
9 | being spied on by a very dedicated attacker, encryption is therefor used as a | 9 | the invite or responds with a response packet if he wants to join the chat. The friend invite contains the type |
10 | form of spam/access control. | 10 | of groupchat (text only, A/V) the friend is being invited to. |
11 | 11 | ||
12 | ## Joining the chats | ||
13 | 12 | ||
13 | TODO: write more of this. | ||
14 | 14 | ||
15 | ## Protocol | 15 | ## Protocol |
16 | 16 | ||
17 | Invite packets: | ||
18 | Invite packet: | ||
19 | [uint8_t id 96][uint8_t id 0][uint16_t group chat number][33 bytes group chat identifier[1 byte type][32 bytes id]] | ||
17 | 20 | ||
18 | Node format: | 21 | Response packet |
19 | See DHT, currently uses the IPv6 Node_format. | 22 | [uint8_t id 96][uint8_t id 1][uint16_t group chat number(local)][uint16_t group chat number to join][33 bytes group chat identifier[1 byte type][32 bytes id]] |
20 | 23 | ||
21 | Get nodes (Request): | ||
22 | Packet contents: | ||
23 | ``` | ||
24 | [char with a value of 48][Bob's (The receiver's) Public key (client_id) (32 bytes))][Alice's (The sender's) Public key (client_id) (32 bytes)][Random nonce (24 bytes)][Encrypted with the nonce, private key of the sender and public key of the receiver:[char with a value of 48][random 8 byte (ping_id)] | ||
25 | ``` | ||
26 | Valid replies: a send_nodes packet | ||
27 | 24 | ||
28 | Send_nodes (response): | 25 | Peer online packet: |
29 | ``` | 26 | [uint8_t id 97][uint16_t group chat number (local)][33 bytes group chat identifier[1 byte type][32 bytes id]] |
30 | [char with a value of 48][Bob's (The receiver's) Public key (client_id) (32 bytes))][Alice's (The sender's) Public key (client_id) (32 bytes)][Random nonce (24 bytes)][Encrypted with the nonce, private key of the sender and public key of the receiver:[char with a value of 49][random 8 byte (ping_id)][Nodes in node format, length=40 * (number of nodes (maximum of 6 nodes)) bytes]] | ||
31 | ``` | ||
32 | 27 | ||
33 | Broadcast packet: | 28 | Peer leave packet: |
34 | ``` | 29 | [uint8_t id 98][uint16_t group chat number][uint8_t id 1] |
35 | [char with a value of 48][Bob's (The receiver's) Public key (client_id) (32 bytes))][Alice's (The sender's) Public key (client_id) (32 bytes)][nonce][Encrypted with the nonce, private key of the sender and public key of the receiver:[char with a value of 50][Data to send to everyone]] | ||
36 | ``` | ||
37 | 30 | ||
31 | Peer query packet: | ||
32 | [uint8_t id 98][uint16_t group chat number][uint8_t id 8] | ||
33 | |||
34 | Peer response packet: | ||
35 | [uint8_t id 98][uint16_t group chat number][uint8_t id 9][Repeated times number of peers: [uint16_t peer num][uint8_t 32bytes real public key][uint8_t 32bytes temp DHT public key][uint8_t name length][name]] | ||
36 | |||
37 | Title response packet: | ||
38 | [uint8_t id 98][uint16_t group chat number][uint8_t id 10][title] | ||
39 | |||
40 | Message packets: | ||
41 | [uint8_t id 99][uint16_t group chat number][uint16_t peer number][uint32_t message number][uint8_t with a value representing id of message][data] | ||
42 | |||
43 | Lossy Message packets: | ||
44 | [uint8_t id 199][uint16_t group chat number][uint16_t peer number][uint16_t message number][uint8_t with a value representing id of message][data] | ||
45 | |||
46 | Group chat types: | ||
47 | 0: text | ||
48 | 1: AV | ||
38 | 49 | ||
39 | Data to send to everyone: | ||
40 | TODO: signing and spam control + permissions. | ||
41 | [client_id of sender][uint32_t message number][char with a value representing id of message][data] | ||
42 | 50 | ||
43 | Note: the message number is increased by 1 for each sent message. | 51 | Note: the message number is increased by 1 for each sent message. |
44 | 52 | ||
@@ -49,23 +57,22 @@ No data. | |||
49 | 57 | ||
50 | 16 - new_peer | 58 | 16 - new_peer |
51 | Tell everyone about a new peer in the chat. | 59 | Tell everyone about a new peer in the chat. |
52 | [uint8_t public_key[public_key_len]] | 60 | [uint16_t peer_num][uint8_t 32bytes real public key][uint8_t 32bytes temp DHT public key] |
53 | 61 | ||
54 | 17 - ban_peer | 62 | 17 - kill_peer |
55 | Ban a peer | 63 | [uint16_t peer_num] |
56 | [uint8_t public_key[public_key_len]] | ||
57 | |||
58 | 18 - topic change | ||
59 | [uint8_t topic[topiclen]] | ||
60 | 64 | ||
61 | 48 - name change | 65 | 48 - name change |
62 | [uint8_t name[namelen]] | 66 | [uint8_t name[namelen]] |
63 | 67 | ||
64 | 49 - status change | 68 | 49 - groupchat title change |
65 | [uint8_t (status id)] | 69 | [uint8_t title[titlelen]] |
66 | 70 | ||
67 | 64 - chat message | 71 | 64 - chat message |
68 | [uint8_t message[messagelen]] | 72 | [uint8_t message[messagelen]] |
69 | 73 | ||
70 | 65 - action (/me) | 74 | 65 - action (/me) |
71 | [uint8_t message[messagelen]] | 75 | [uint8_t message[messagelen]] |
76 | |||
77 | |||
78 | |||
diff --git a/docs/Prevent_Tracking.txt b/docs/Prevent_Tracking.txt index d170103f..a641f02c 100644 --- a/docs/Prevent_Tracking.txt +++ b/docs/Prevent_Tracking.txt | |||
@@ -117,8 +117,10 @@ Data sent to us: | |||
117 | announce response packet: | 117 | announce response packet: |
118 | [uint8_t packet id (132)][data to send back in response(fixed size)][nonce] | 118 | [uint8_t packet id (132)][data to send back in response(fixed size)][nonce] |
119 | encrypted with the DHT private key of Node D, the public key in the request and the nonce:[[uint8_t is_stored] | 119 | encrypted with the DHT private key of Node D, the public key in the request and the nonce:[[uint8_t is_stored] |
120 | [(32 bytes) ping_id if is_stored is 0, public key that must be used to send data packets if is_stored is not 0][Node_Format * (maximum of 8)]] | 120 | [(32 bytes) ping_id if is_stored is 0 or 2, public key that must be used to send data packets if is_stored is 1][Node_Format * (maximum of 8)]] |
121 | (if the is_stored is not 0, it means the information to reach the client id we are searching for is stored on this node) | 121 | (if the is_stored is not 0, it means the information to reach the client id we are searching for is stored on this node) |
122 | is_stored is 2 as a response to a peer trying to announce himself to tell the | ||
123 | peer that he is currently announced successfully. | ||
122 | 124 | ||
123 | data to route response packet: | 125 | data to route response packet: |
124 | [uint8_t packet id (134)][nonce][temporary just generated public key] | 126 | [uint8_t packet id (134)][nonce][temporary just generated public key] |
@@ -3,7 +3,7 @@ TODO list. | |||
3 | [IN PROGRESS] Add what is left to do to the TODO list. | 3 | [IN PROGRESS] Add what is left to do to the TODO list. |
4 | 4 | ||
5 | Networking: | 5 | Networking: |
6 | [NOT STARTED] UPnP port forwarding. | 6 | [NEEDS TESTING] UPnP port forwarding. (https://github.com/irungentoo/toxcore/pull/969) |
7 | [NOT STARTED] NAT-PMP port forwarding. | 7 | [NOT STARTED] NAT-PMP port forwarding. |
8 | 8 | ||
9 | DHT: | 9 | DHT: |
@@ -11,13 +11,11 @@ DHT: | |||
11 | [IN PROGRESS] Hardening against attacks. | 11 | [IN PROGRESS] Hardening against attacks. |
12 | [IN PROGRESS] Optimizing the code. | 12 | [IN PROGRESS] Optimizing the code. |
13 | 13 | ||
14 | Lossless UDP: | 14 | [DONE] Friend only group chats |
15 | [DONE] Increase data send/receive rates. | ||
16 | |||
17 | [IN PROGRESS] Massive IRC like group chats (text only) | ||
18 | [DONE] Networking base. | 15 | [DONE] Networking base. |
19 | [NOT STARTED] Syncing chat state between clients (nicknames, list of who is in chat, etc...) | 16 | [MOSTLY DONE] Syncing chat state between clients (nicknames, list of who is in chat, etc...) |
20 | [NOT STARTED] Make clients sign their messages so that peers can't modify them. | 17 | [NOT STARTED] Private messages. (and adding friends from group chats using those private messages.) |
18 | [NOT STARTED] File transfers. | ||
21 | 19 | ||
22 | [IN PROGRESS] Audio/Video | 20 | [IN PROGRESS] Audio/Video |
23 | [DONE] encoding/streaming/decoding | 21 | [DONE] encoding/streaming/decoding |
@@ -26,7 +24,7 @@ Lossless UDP: | |||
26 | [IN PROGRESS] Auditing. | 24 | [IN PROGRESS] Auditing. |
27 | [NEEDS TESTING] Video packet splitting. | 25 | [NEEDS TESTING] Video packet splitting. |
28 | [IN PROGRESS] Prevent audio skew (seems to be easily solvable client side.) | 26 | [IN PROGRESS] Prevent audio skew (seems to be easily solvable client side.) |
29 | [IN PROGRESS] Group chats. | 27 | [IN PROGRESS] Group chats, audio done. |
30 | 28 | ||
31 | Friend_requests.c: | 29 | Friend_requests.c: |
32 | [NOT STARTED] What happens when a friend request is received needs to be changed. | 30 | [NOT STARTED] What happens when a friend request is received needs to be changed. |
@@ -34,29 +32,17 @@ Friend_requests.c: | |||
34 | 32 | ||
35 | [DONE] File transfers | 33 | [DONE] File transfers |
36 | [NOT STARTED] Offline messaging | 34 | [NOT STARTED] Offline messaging |
37 | [NOT STARTED] Friends list syncing | 35 | [IN PROGRESS] Friends list syncing |
38 | [IN PROGRESS] IPV6 support | 36 | [DONE] IPV6 support |
39 | [DONE] Networking | ||
40 | [DONE] DHT + Messenger | ||
41 | [NOT STARTED] Group chats (They work with IPv6 but some things need to be tested.) | ||
42 | |||
43 | 37 | ||
44 | [IN PROGRESS] Make toxcore thread safe. | 38 | [IN PROGRESS] Make toxcore thread safe. |
45 | 39 | ||
46 | [NOT STARTED] Make the core save/datafile portable across client versions/different processor architectures. | 40 | [NOT STARTED] Make the core save/datafile portable across client versions/different processor architectures. |
47 | 41 | ||
48 | [MOSTLY DONE] A way for people to connect to people on Tox if they are behind a bad NAT that | 42 | [MOSTLY DONE] A way for people to connect to people on Tox if they are behind a bad NAT that |
49 | blocks UDP (or is just unpunchable) (docs/TCP_Network.txt) | 43 | blocks UDP (or is just unpunchable) (docs/TCP_Network.txt) (Current way doesn't scale very well.) |
50 | 44 | ||
51 | [NEEDS TESTING] Make the save made with tox_save_encrypted(...) harder to brute force. | 45 | [DONE] Encrypted Saves. (see: toxencryptsave) |
52 | See: (https://github.com/jencka/ProjectTox-libtoxdata) | 46 | |
53 | |||
54 | [IN PROGRESS] GUI (no official one chosen yet, a list of promising ones follows) | ||
55 | https://github.com/notsecure/uTox | ||
56 | https://github.com/naxuroqa/Venom | ||
57 | https://github.com/Impyy/Toxy | ||
58 | https://github.com/lehitoskin/blight | ||
59 | https://github.com/nurupo/ProjectTox-Qt-GUI | ||
60 | https://github.com/Astonex/Antox | ||
61 | 47 | ||
62 | [NOT STARTED] Security audit from professionals | 48 | [NOT STARTED] Security audit from professionals |
diff --git a/docs/Tox_middle_level_network_protocol.txt b/docs/Tox_middle_level_network_protocol.txt index a84132b6..ca561474 100644 --- a/docs/Tox_middle_level_network_protocol.txt +++ b/docs/Tox_middle_level_network_protocol.txt | |||
@@ -43,13 +43,13 @@ cookie request packet: | |||
43 | bytes)][Encrypted message containing: [Senders real public key (32 | 43 | bytes)][Encrypted message containing: [Senders real public key (32 |
44 | bytes)][padding (32 bytes)][uint64_t number (must be sent | 44 | bytes)][padding (32 bytes)][uint64_t number (must be sent |
45 | back untouched in cookie response)]] | 45 | back untouched in cookie response)]] |
46 | Encrypted message is encrypted with sender DHT private key, recievers DHT | 46 | Encrypted message is encrypted with sender DHT private key, receivers DHT |
47 | public key and the nonce. | 47 | public key and the nonce. |
48 | 48 | ||
49 | cookie response packet: | 49 | cookie response packet: |
50 | [uint8_t 25][Random nonce (24 bytes)][Encrypted message containing: | 50 | [uint8_t 25][Random nonce (24 bytes)][Encrypted message containing: |
51 | [Cookie][uint64_t number (that was sent in the request)]] | 51 | [Cookie][uint64_t number (that was sent in the request)]] |
52 | Encrypted message is encrypted with sender DHT private key, recievers DHT | 52 | Encrypted message is encrypted with sender DHT private key, receivers DHT |
53 | public key and the nonce. | 53 | public key and the nonce. |
54 | 54 | ||
55 | The Cookie should be basically: | 55 | The Cookie should be basically: |
@@ -63,7 +63,7 @@ Cookie sitting outside the encrypted part][Other Cookie (used by the other to | |||
63 | respond to the handshake packet)]] | 63 | respond to the handshake packet)]] |
64 | 64 | ||
65 | The handshake packet is encrypted using the real private key of the sender, the | 65 | The handshake packet is encrypted using the real private key of the sender, the |
66 | real private key of the receiver and the nonce. | 66 | real public key of the receiver and the nonce. |
67 | 67 | ||
68 | 68 | ||
69 | Alice wants to connect to bob. | 69 | Alice wants to connect to bob. |
@@ -110,11 +110,11 @@ packet request packet: [uint8_t (1)][uint8_t num][uint8_t num][uint8_t | |||
110 | num]...[uint8_t num] | 110 | num]...[uint8_t num] |
111 | 111 | ||
112 | the list of nums are a list of packet numbers the other is requesting. | 112 | the list of nums are a list of packet numbers the other is requesting. |
113 | to get the real packet numbers from this list take the recvbuffers buffer_start | 113 | to get the real packet numbers from this list take the recvbuffers buffer_start |
114 | from the packet, substract 1 to it and put it in packet_num then start from the | 114 | from the packet, subtract 1 to it and put it in packet_num then start from the |
115 | beggining of the num list: if num is zero, add 255 to packet_num then do the | 115 | beginning of the num list: if num is zero, add 255 to packet_num then do the |
116 | next num. if num isn't zero, add its value to packet_num, note that the other | 116 | next num. if num isn't zero, add its value to packet_num, note that the other |
117 | has requested we send this packet again to them then continue to the next num in | 117 | has requested we send this packet again to them then continue to the next num in |
118 | the list. | 118 | the list. |
119 | 119 | ||
120 | 120 | ||
diff --git a/docs/updates/DHT.md b/docs/updates/DHT.md index 17db70ce..9857b419 100644 --- a/docs/updates/DHT.md +++ b/docs/updates/DHT.md | |||
@@ -1,6 +1,8 @@ | |||
1 | DHT protocol | 1 | DHT protocol |
2 | ============ | 2 | ============ |
3 | 3 | ||
4 | NOTE: only the protocol section is up to date, the rest needs to be rewritten. | ||
5 | |||
4 | Follows pretty much the principle of the torrent DHT: http://www.bittorrent.org/beps/bep_0005.html (READ IT) | 6 | Follows pretty much the principle of the torrent DHT: http://www.bittorrent.org/beps/bep_0005.html (READ IT) |
5 | 7 | ||
6 | But: | 8 | But: |
@@ -36,39 +38,39 @@ Send a get nodes request every 20 seconds to a random good node in the client li | |||
36 | 38 | ||
37 | When a client receives any request from another | 39 | When a client receives any request from another |
38 | ----------------------------------------------- | 40 | ----------------------------------------------- |
39 | -Respond to the request | 41 | - Respond to the request |
40 | -Ping request is replied to with with a ping response containing the same encrypted data | 42 | - Ping request is replied to with with a ping response containing the same encrypted data |
41 | -Get nodes request is replied with a send nodes reply containing the same encrypted data and the good nodes from the client list and/or the "friends" list that are closest to the requested_node_id | 43 | - Get nodes request is replied with a send nodes reply containing the same encrypted data and the good nodes from the client list and/or the "friends" list that are closest to the requested_node_id |
42 | 44 | ||
43 | -If the requesting client is not in the client list: | 45 | - If the requesting client is not in the client list: |
44 | -If there are no bad clients in the list and the list is full: | 46 | - If there are no bad clients in the list and the list is full: |
45 | -If the id of the other client is closer (mathematically see bittorrent doc) than at least one of the clients in the list or our "friends" list: | 47 | - If the id of the other client is closer (mathematically see bittorrent doc) than at least one of the clients in the list or our "friends" list: |
46 | -Send a ping request to the client. | 48 | - Send a ping request to the client. |
47 | -if not forget about the client. | 49 | - if not forget about the client. |
48 | 50 | ||
49 | -If there are bad clients and/or the list isn't full: | 51 | - If there are bad clients and/or the list isn't full: |
50 | -Send a ping request to the client | 52 | - Send a ping request to the client |
51 | 53 | ||
52 | When a client receives a response | 54 | When a client receives a response |
53 | --------------------------------- | 55 | --------------------------------- |
54 | -Ping response | 56 | - Ping response |
55 | -If the node was previously pinged with a matching ping_id (check in the corresponding pinged list.) | 57 | - If the node was previously pinged with a matching ping_id (check in the corresponding pinged list.) |
56 | -If the node is in the client list the matching client's timestamp is set to current time. | 58 | - If the node is in the client list the matching client's timestamp is set to current time. |
57 | -If the node is in the "friends" list the matching client's timestamp is set to current time for every occurrence. | 59 | - If the node is in the "friends" list the matching client's timestamp is set to current time for every occurrence. |
58 | -If the node is not in the client list: | 60 | - If the node is not in the client list: |
59 | -If the list isn't full, add it to the list. | 61 | - If the list isn't full, add it to the list. |
60 | -If the list is full, the furthest away (mathematically see bittorrent doc) bad client is replaced by the new one. | 62 | - If the list is full, the furthest away (mathematically see bittorrent doc) bad client is replaced by the new one. |
61 | -If the list is filled with good nodes replace the furthest client with it only if it is closer than the replaced node. | 63 | - If the list is filled with good nodes replace the furthest client with it only if it is closer than the replaced node. |
62 | -for each friend in the "friends" list: | 64 | - for each friend in the "friends" list: |
63 | -If that friend's client list isn't full, add that client to it | 65 | - If that friend's client list isn't full, add that client to it |
64 | -If that friend's client list contains bad clients, replace the furthest one with that client. | 66 | - If that friend's client list contains bad clients, replace the furthest one with that client. |
65 | -If that friend's client list contains only good clients | 67 | - If that friend's client list contains only good clients |
66 | -If the client is closer to the friend than one of the other clients, it replaces the farthest one | 68 | - If the client is closer to the friend than one of the other clients, it replaces the farthest one |
67 | -If not, nothing happens. | 69 | - If not, nothing happens. |
68 | 70 | ||
69 | -Send nodes | 71 | - Send nodes |
70 | -If the ping_id matches what we sent previously (check in the corresponding pinged list.): | 72 | - If the ping_id matches what we sent previously (check in the corresponding pinged list.): |
71 | -Each node in the response is pinged. | 73 | - Each node in the response is pinged. |
72 | 74 | ||
73 | 75 | ||
74 | 76 | ||
@@ -95,11 +97,11 @@ ping_id = a random integer, the response must contain the exact same number as t | |||
95 | Get nodes (Request): | 97 | Get nodes (Request): |
96 | Packet contents: | 98 | Packet contents: |
97 | ``` | 99 | ``` |
98 | [byte with value: 02][char array (client node_id), length=32 bytes][random 24 byte nonce][Encrypted with the nonce and private key of the sender:[char array: requested_node_id (node_id of which we want the ip), length=32 bytes][Sendback data (must be sent back unmodified by in the response), length=1 to NODES_ENCRYPTED_MESSAGE_LENGTH bytes]] | 100 | [byte with value: 02][char array (client node_id), length=32 bytes][random 24 byte nonce][Encrypted with the nonce and private key of the sender:[char array: requested_node_id (node_id of which we want the ip), length=32 bytes][Sendback data (must be sent back unmodified by in the response), length=8 bytes]] |
99 | ``` | 101 | ``` |
100 | Valid replies: a send_nodes packet | 102 | Valid replies: a send_nodes packet |
101 | 103 | ||
102 | Send_nodes (response (for all addresses)): | 104 | Send_nodes (response (for all addresses)): |
103 | ``` | 105 | ``` |
104 | [byte with value: 04][char array (client node_id), length=32 bytes][random 24 byte nonce][Encrypted with the nonce and private key of the sender:[uint8_t number of nodes in this packet][Nodes in node format, length=?? * (number of nodes (maximum of 8 nodes)) bytes][Sendback data, length=1 to NODES_ENCRYPTED_MESSAGE_LENGTH bytes]] | 106 | [byte with value: 04][char array (client node_id), length=32 bytes][random 24 byte nonce][Encrypted with the nonce and private key of the sender:[uint8_t number of nodes in this packet][Nodes in node format, length=?? * (number of nodes (maximum of 4 nodes)) bytes][Sendback data, length=8 bytes]] |
105 | ``` | 107 | ``` |
diff --git a/libtoxav.pc.in b/libtoxav.pc.in index 05493231..b36b5a91 100644 --- a/libtoxav.pc.in +++ b/libtoxav.pc.in | |||
@@ -5,7 +5,7 @@ includedir=@includedir@ | |||
5 | 5 | ||
6 | Name: libtoxav | 6 | Name: libtoxav |
7 | Description: Tox A/V library | 7 | Description: Tox A/V library |
8 | Requires: | 8 | Requires: libtoxcore |
9 | Version: @PACKAGE_VERSION@ | 9 | Version: @PACKAGE_VERSION@ |
10 | Libs: -L${libdir} -ltoxav @AV_LIBS@ | 10 | Libs: -L${libdir} -ltoxav @AV_LIBS@ |
11 | Cflags: -I${includedir} \ No newline at end of file | 11 | Cflags: -I${includedir} |
diff --git a/libtoxcore.pc.in b/libtoxcore.pc.in index a91a1fb7..0ff86827 100644 --- a/libtoxcore.pc.in +++ b/libtoxcore.pc.in | |||
@@ -7,5 +7,5 @@ Name: libtoxcore | |||
7 | Description: Tox protocol library | 7 | Description: Tox protocol library |
8 | Requires: | 8 | Requires: |
9 | Version: @PACKAGE_VERSION@ | 9 | Version: @PACKAGE_VERSION@ |
10 | Libs: @NACL_OBJECTS_PKGCONFIG@ -L${libdir} @NACL_LDFLAGS@ -ltoxdns -ltoxcore @NACL_LIBS@ @LIBS@ @MATH_LDFLAGS@ | 10 | Libs: @NACL_OBJECTS_PKGCONFIG@ -L${libdir} @NACL_LDFLAGS@ -ltoxdns -ltoxencryptsave -ltoxcore @NACL_LIBS@ @LIBS@ @MATH_LDFLAGS@ @PTHREAD_LDFLAGS@ |
11 | Cflags: -I${includedir} | 11 | Cflags: -I${includedir} |
diff --git a/other/DHT_bootstrap.c b/other/DHT_bootstrap.c index 462360c3..29aa5bcf 100644 --- a/other/DHT_bootstrap.c +++ b/other/DHT_bootstrap.c | |||
@@ -83,6 +83,11 @@ void manage_keys(DHT *dht) | |||
83 | memcpy(keys + crypto_box_PUBLICKEYBYTES, dht->self_secret_key, crypto_box_SECRETKEYBYTES); | 83 | memcpy(keys + crypto_box_PUBLICKEYBYTES, dht->self_secret_key, crypto_box_SECRETKEYBYTES); |
84 | keys_file = fopen("key", "w"); | 84 | keys_file = fopen("key", "w"); |
85 | 85 | ||
86 | if (keys_file == NULL) { | ||
87 | printf("Error opening key file in write mode.\nKeys will not be saved.\n"); | ||
88 | return; | ||
89 | } | ||
90 | |||
86 | if (fwrite(keys, sizeof(uint8_t), KEYS_SIZE, keys_file) != KEYS_SIZE) { | 91 | if (fwrite(keys, sizeof(uint8_t), KEYS_SIZE, keys_file) != KEYS_SIZE) { |
87 | printf("Error while writing the key file.\nExiting.\n"); | 92 | printf("Error while writing the key file.\nExiting.\n"); |
88 | exit(1); | 93 | exit(1); |
diff --git a/other/bootstrap_daemon/README.md b/other/bootstrap_daemon/README.md index a63ea5de..d0c16eb1 100644 --- a/other/bootstrap_daemon/README.md +++ b/other/bootstrap_daemon/README.md | |||
@@ -1,29 +1,32 @@ | |||
1 | ##Instructions for Debian | 1 | ##Instructions |
2 | |||
3 | This instruction primarily tested on Linux but, may be, will work on other POSIX-compliant systems. | ||
2 | 4 | ||
3 | For security reasons we run the daemon under its own user. | 5 | For security reasons we run the daemon under its own user. |
6 | |||
4 | Create a new user by executing the following: | 7 | Create a new user by executing the following: |
5 | ```sh | 8 | ```sh |
6 | sudo useradd --system --shell /sbin/nologin --comment "Account to run Tox's DHT bootstrap daemon" --user-group tox-bootstrapd | 9 | sudo useradd --home-dir /var/lib/tox-bootstrapd --create-home --system --shell /sbin/nologin --comment "Account to run Tox's DHT bootstrap daemon" --user-group tox-bootstrapd |
7 | ``` | 10 | ``` |
8 | 11 | ||
9 | Create a directory where the daemon will store its keys: | 12 | Copy `tox-bootstrapd.conf` file to where `CFGFILE` variable from `tox-bootstrapd.sh` tells (for `init.d` users) or `ExecStart=` from `tox-bootstrap.service` ( for `systemd` users). By default it's `/etc/tox-bootstrapd.conf`. |
10 | ```sh | 13 | |
11 | sudo mkdir /var/lib/tox-bootstrapd/ | 14 | Go over everything in `tox-bootstrapd.conf`. Make sure `pid_file_path` matches `PIDFILE` from `tox-bootstrapd.sh` (`init.d`) or `PIDFile=` from `tox-bootstrap.service` AND file in `ExecStartPre`(`systemd`). |
12 | ``` | 15 | |
13 | 16 | ||
14 | Restrain other users from accessing the directory: | 17 | Restrict access to home directory: |
15 | ```sh | 18 | ```sh |
16 | sudo chown tox-bootstrapd:tox-bootstrapd /var/lib/tox-bootstrapd/ | 19 | sudo chmod 700 /var/lib/tox-bootstrapd |
17 | sudo chmod 700 /var/lib/tox-bootstrapd/ | ||
18 | ``` | 20 | ``` |
19 | 21 | ||
20 | Look at the variable declarations in the beginning of `tox-bootstrapd.sh` init script to see if you need to change anything for it to work for you. The default values must be fine for most users and we assume that you use those next. | 22 | ##For `init.d` users: |
21 | |||
22 | Go over everything in `tox-bootstrapd.conf`. Make sure `pid_file_path` matches `PIDFILE` from `tox-bootstrapd.sh`. | ||
23 | 23 | ||
24 | Place `tox-bootstrapd.conf` file to where `CFGFILE` variable from `tox-bootstrapd` tells. By default it's `/etc/tox-bootstrapd.conf`. | 24 | Look at the variable declarations in the beginning of `tox-bootstrapd.sh` init script to see if you need to change anything for it to work for you. The default values must be fine for most users and we assume that you use those next. |
25 | 25 | ||
26 | Place `tox-bootstrapd.sh` init file at `/etc/init.d/tox-bootstrapd` (note the disappearance of ".sh" ending). | 26 | Copy `tox-bootstrapd.sh` init file to `/etc/init.d/tox-bootstrapd` (note the disappearance of ".sh" ending). |
27 | ```sh | ||
28 | sudo cp tox-bootstrapd.sh /etc/init.d/tox-bootstrapd | ||
29 | ``` | ||
27 | 30 | ||
28 | Set permissions for the init system to run the script: | 31 | Set permissions for the init system to run the script: |
29 | ```sh | 32 | ```sh |
@@ -50,23 +53,56 @@ Get your public key and check that the daemon initialized correctly: | |||
50 | sudo grep "tox-bootstrapd" /var/log/syslog | 53 | sudo grep "tox-bootstrapd" /var/log/syslog |
51 | ``` | 54 | ``` |
52 | 55 | ||
56 | ##For `systemd` users: | ||
57 | |||
58 | Copy tox-bootstrap.service to /etc/systemd/system/: | ||
59 | ```sh | ||
60 | sudo cp tox-bootstrap.service /etc/systemd/system/ | ||
61 | ``` | ||
62 | |||
63 | Make sure, that path to `chown` and `mkdir` is correct in `tox-bootstrap.service` (they may be different in some distributions, by default `/bin/chown` and `/bin/mkdir`) | ||
64 | |||
65 | You must uncomment the next line in tox-bootstrap.service, if you want to use port number <1024 | ||
66 | |||
67 | #CapabilityBoundingSet=CAP_NET_BIND_SERVICE | ||
68 | |||
69 | and, possibly, install `libcap2-bin` or `libcap2` package, depending of your distribution. | ||
70 | |||
53 | 71 | ||
72 | Reload systemd units definitions, enable service for automatic start (if needed), and start it: | ||
73 | ```sh | ||
74 | sudo systemctl daemon-reload | ||
75 | sudo systemctl enable tox-bootstrap.service | ||
76 | sudo systemctl start tox-bootstrap.service | ||
77 | ``` | ||
54 | ###Troubleshooting: | 78 | ###Troubleshooting: |
55 | 79 | ||
56 | - Check daemon's status: | 80 | - Check daemon's status: |
57 | ```sh | 81 | ```sh |
82 | #init.d | ||
58 | sudo service tox-bootstrapd status | 83 | sudo service tox-bootstrapd status |
84 | |||
85 | #systemd | ||
86 | sudo systemctl status tox-bootstrap.service | ||
59 | ``` | 87 | ``` |
60 | 88 | ||
61 | - Check the log for errors: | 89 | - Check the log for errors: |
62 | ```sh | 90 | ```sh |
91 | #init.d | ||
63 | sudo grep "tox-bootstrapd" /var/log/syslog | 92 | sudo grep "tox-bootstrapd" /var/log/syslog |
93 | |||
94 | #systemd | ||
95 | sudo journalctl -f _SYSTEMD_UNIT=tox-bootstrap.service | ||
64 | ``` | 96 | ``` |
65 | 97 | ||
98 | `init.d`: | ||
66 | - Check that variables in the beginning of `/etc/init.d/tox-bootstrapd` are valid. | 99 | - Check that variables in the beginning of `/etc/init.d/tox-bootstrapd` are valid. |
67 | 100 | ||
68 | - Make sure `pid_file_path` in `/etc/tox-bootstrapd.conf` matches `PIDFILE` from `/etc/init.d/tox-bootstrapd`. | ||
69 | 101 | ||
70 | - Make sure you have write permission for keys and pid files. | 102 | Common: |
103 | |||
104 | - Make sure tox-bootstrapd user has write permission for keys and pid files (in systemd pid file insured by unit definition). | ||
105 | |||
106 | - Make sure tox-bootstrapd has read permission for the config file. | ||
71 | 107 | ||
72 | - Make sure you have read permission for the config file. \ No newline at end of file | 108 | - Make sure tox-bootstrapd location matches its path in init scripts, if you specified non-default `--prefix`, when building. |
diff --git a/other/bootstrap_daemon/tox-bootstrapd.c b/other/bootstrap_daemon/tox-bootstrapd.c index a5d1c525..1bcae732 100644 --- a/other/bootstrap_daemon/tox-bootstrapd.c +++ b/other/bootstrap_daemon/tox-bootstrapd.c | |||
@@ -53,7 +53,7 @@ | |||
53 | 53 | ||
54 | 54 | ||
55 | #define DAEMON_NAME "tox-bootstrapd" | 55 | #define DAEMON_NAME "tox-bootstrapd" |
56 | #define DAEMON_VERSION_NUMBER 2014081600UL // yyyymmmddvv format: yyyy year, mm month, dd day, vv version change count for that day | 56 | #define DAEMON_VERSION_NUMBER 2014101200UL // yyyymmmddvv format: yyyy year, mm month, dd day, vv version change count for that day |
57 | 57 | ||
58 | #define SLEEP_TIME_MILLISECONDS 30 | 58 | #define SLEEP_TIME_MILLISECONDS 30 |
59 | #define sleep usleep(1000*SLEEP_TIME_MILLISECONDS) | 59 | #define sleep usleep(1000*SLEEP_TIME_MILLISECONDS) |
@@ -61,7 +61,8 @@ | |||
61 | #define DEFAULT_PID_FILE_PATH "tox-bootstrapd.pid" | 61 | #define DEFAULT_PID_FILE_PATH "tox-bootstrapd.pid" |
62 | #define DEFAULT_KEYS_FILE_PATH "tox-bootstrapd.keys" | 62 | #define DEFAULT_KEYS_FILE_PATH "tox-bootstrapd.keys" |
63 | #define DEFAULT_PORT 33445 | 63 | #define DEFAULT_PORT 33445 |
64 | #define DEFAULT_ENABLE_IPV6 0 // 1 - true, 0 - false | 64 | #define DEFAULT_ENABLE_IPV6 1 // 1 - true, 0 - false |
65 | #define DEFAULT_ENABLE_IPV4_FALLBACK 1 // 1 - true, 0 - false | ||
65 | #define DEFAULT_ENABLE_LAN_DISCOVERY 1 // 1 - true, 0 - false | 66 | #define DEFAULT_ENABLE_LAN_DISCOVERY 1 // 1 - true, 0 - false |
66 | #define DEFAULT_ENABLE_TCP_RELAY 1 // 1 - true, 0 - false | 67 | #define DEFAULT_ENABLE_TCP_RELAY 1 // 1 - true, 0 - false |
67 | #define DEFAULT_TCP_RELAY_PORTS 443, 3389, 33445 // comma-separated list of ports. make sure to adjust DEFAULT_TCP_RELAY_PORTS_COUNT accordingly | 68 | #define DEFAULT_TCP_RELAY_PORTS 443, 3389, 33445 // comma-separated list of ports. make sure to adjust DEFAULT_TCP_RELAY_PORTS_COUNT accordingly |
@@ -88,7 +89,7 @@ int manage_keys(DHT *dht, char *keys_file_path) | |||
88 | keys_file = fopen(keys_file_path, "r"); | 89 | keys_file = fopen(keys_file_path, "r"); |
89 | 90 | ||
90 | if (keys_file != NULL) { | 91 | if (keys_file != NULL) { |
91 | size_t read_size = fread(keys, sizeof(uint8_t), KEYS_SIZE, keys_file); | 92 | const size_t read_size = fread(keys, sizeof(uint8_t), KEYS_SIZE, keys_file); |
92 | 93 | ||
93 | if (read_size != KEYS_SIZE) { | 94 | if (read_size != KEYS_SIZE) { |
94 | fclose(keys_file); | 95 | fclose(keys_file); |
@@ -104,7 +105,7 @@ int manage_keys(DHT *dht, char *keys_file_path) | |||
104 | 105 | ||
105 | keys_file = fopen(keys_file_path, "w"); | 106 | keys_file = fopen(keys_file_path, "w"); |
106 | 107 | ||
107 | size_t write_size = fwrite(keys, sizeof(uint8_t), KEYS_SIZE, keys_file); | 108 | const size_t write_size = fwrite(keys, sizeof(uint8_t), KEYS_SIZE, keys_file); |
108 | 109 | ||
109 | if (write_size != KEYS_SIZE) { | 110 | if (write_size != KEYS_SIZE) { |
110 | fclose(keys_file); | 111 | fclose(keys_file); |
@@ -161,7 +162,12 @@ void parse_tcp_relay_ports_config(config_t *cfg, uint16_t **tcp_relay_ports, int | |||
161 | } | 162 | } |
162 | 163 | ||
163 | // the loop above skips invalid ports, so we adjust the allocated memory size | 164 | // the loop above skips invalid ports, so we adjust the allocated memory size |
164 | *tcp_relay_ports = realloc(*tcp_relay_ports, (*tcp_relay_port_count) * sizeof(uint16_t)); | 165 | if ((*tcp_relay_port_count) > 0) { |
166 | *tcp_relay_ports = realloc(*tcp_relay_ports, (*tcp_relay_port_count) * sizeof(uint16_t)); | ||
167 | } else { | ||
168 | free(*tcp_relay_ports); | ||
169 | *tcp_relay_ports = NULL; | ||
170 | } | ||
165 | 171 | ||
166 | return; | 172 | return; |
167 | } | 173 | } |
@@ -187,7 +193,7 @@ void parse_tcp_relay_ports_config(config_t *cfg, uint16_t **tcp_relay_ports, int | |||
187 | config_setting_t *elem = config_setting_get_elem(ports_array, i); | 193 | config_setting_t *elem = config_setting_get_elem(ports_array, i); |
188 | 194 | ||
189 | if (elem == NULL) { | 195 | if (elem == NULL) { |
190 | // it's NULL if `ports_array` is not an array (we have that check ealier) or if `i` is out of range, which should not be | 196 | // it's NULL if `ports_array` is not an array (we have that check earlier) or if `i` is out of range, which should not be |
191 | syslog(LOG_WARNING, "Port #%d: Something went wrong while parsing the port. Stopping reading ports.\n", i); | 197 | syslog(LOG_WARNING, "Port #%d: Something went wrong while parsing the port. Stopping reading ports.\n", i); |
192 | break; | 198 | break; |
193 | } | 199 | } |
@@ -210,7 +216,12 @@ void parse_tcp_relay_ports_config(config_t *cfg, uint16_t **tcp_relay_ports, int | |||
210 | } | 216 | } |
211 | 217 | ||
212 | // the loop above skips invalid ports, so we adjust the allocated memory size | 218 | // the loop above skips invalid ports, so we adjust the allocated memory size |
213 | *tcp_relay_ports = realloc(*tcp_relay_ports, (*tcp_relay_port_count) * sizeof(uint16_t)); | 219 | if ((*tcp_relay_port_count) > 0) { |
220 | *tcp_relay_ports = realloc(*tcp_relay_ports, (*tcp_relay_port_count) * sizeof(uint16_t)); | ||
221 | } else { | ||
222 | free(*tcp_relay_ports); | ||
223 | *tcp_relay_ports = NULL; | ||
224 | } | ||
214 | } | 225 | } |
215 | 226 | ||
216 | // Gets general config options | 227 | // Gets general config options |
@@ -222,9 +233,10 @@ void parse_tcp_relay_ports_config(config_t *cfg, uint16_t **tcp_relay_ports, int | |||
222 | // returns 1 on success | 233 | // returns 1 on success |
223 | // 0 on failure, doesn't modify any data pointed by arguments | 234 | // 0 on failure, doesn't modify any data pointed by arguments |
224 | 235 | ||
225 | int get_general_config(char *cfg_file_path, char **pid_file_path, char **keys_file_path, int *port, int *enable_ipv6, | 236 | int get_general_config(const char *cfg_file_path, char **pid_file_path, char **keys_file_path, int *port, |
226 | int *enable_lan_discovery, int *enable_tcp_relay, uint16_t **tcp_relay_ports, int *tcp_relay_port_count, | 237 | int *enable_ipv6, |
227 | int *enable_motd, char **motd) | 238 | int *enable_ipv4_fallback, int *enable_lan_discovery, int *enable_tcp_relay, uint16_t **tcp_relay_ports, |
239 | int *tcp_relay_port_count, int *enable_motd, char **motd) | ||
228 | { | 240 | { |
229 | config_t cfg; | 241 | config_t cfg; |
230 | 242 | ||
@@ -232,6 +244,7 @@ int get_general_config(char *cfg_file_path, char **pid_file_path, char **keys_fi | |||
232 | const char *NAME_PID_FILE_PATH = "pid_file_path"; | 244 | const char *NAME_PID_FILE_PATH = "pid_file_path"; |
233 | const char *NAME_KEYS_FILE_PATH = "keys_file_path"; | 245 | const char *NAME_KEYS_FILE_PATH = "keys_file_path"; |
234 | const char *NAME_ENABLE_IPV6 = "enable_ipv6"; | 246 | const char *NAME_ENABLE_IPV6 = "enable_ipv6"; |
247 | const char *NAME_ENABLE_IPV4_FALLBACK = "enable_ipv4_fallback"; | ||
235 | const char *NAME_ENABLE_LAN_DISCOVERY = "enable_lan_discovery"; | 248 | const char *NAME_ENABLE_LAN_DISCOVERY = "enable_lan_discovery"; |
236 | const char *NAME_ENABLE_TCP_RELAY = "enable_tcp_relay"; | 249 | const char *NAME_ENABLE_TCP_RELAY = "enable_tcp_relay"; |
237 | const char *NAME_ENABLE_MOTD = "enable_motd"; | 250 | const char *NAME_ENABLE_MOTD = "enable_motd"; |
@@ -284,6 +297,14 @@ int get_general_config(char *cfg_file_path, char **pid_file_path, char **keys_fi | |||
284 | *enable_ipv6 = DEFAULT_ENABLE_IPV6; | 297 | *enable_ipv6 = DEFAULT_ENABLE_IPV6; |
285 | } | 298 | } |
286 | 299 | ||
300 | // Get IPv4 fallback option | ||
301 | if (config_lookup_bool(&cfg, NAME_ENABLE_IPV4_FALLBACK, enable_ipv4_fallback) == CONFIG_FALSE) { | ||
302 | syslog(LOG_WARNING, "No '%s' setting in configuration file.\n", NAME_ENABLE_IPV4_FALLBACK); | ||
303 | syslog(LOG_WARNING, "Using default '%s': %s\n", NAME_ENABLE_IPV4_FALLBACK, | ||
304 | DEFAULT_ENABLE_IPV4_FALLBACK ? "true" : "false"); | ||
305 | *enable_ipv4_fallback = DEFAULT_ENABLE_IPV4_FALLBACK; | ||
306 | } | ||
307 | |||
287 | // Get LAN discovery option | 308 | // Get LAN discovery option |
288 | if (config_lookup_bool(&cfg, NAME_ENABLE_LAN_DISCOVERY, enable_lan_discovery) == CONFIG_FALSE) { | 309 | if (config_lookup_bool(&cfg, NAME_ENABLE_LAN_DISCOVERY, enable_lan_discovery) == CONFIG_FALSE) { |
289 | syslog(LOG_WARNING, "No '%s' setting in configuration file.\n", NAME_ENABLE_LAN_DISCOVERY); | 310 | syslog(LOG_WARNING, "No '%s' setting in configuration file.\n", NAME_ENABLE_LAN_DISCOVERY); |
@@ -338,6 +359,7 @@ int get_general_config(char *cfg_file_path, char **pid_file_path, char **keys_fi | |||
338 | syslog(LOG_DEBUG, "'%s': %s\n", NAME_KEYS_FILE_PATH, *keys_file_path); | 359 | syslog(LOG_DEBUG, "'%s': %s\n", NAME_KEYS_FILE_PATH, *keys_file_path); |
339 | syslog(LOG_DEBUG, "'%s': %d\n", NAME_PORT, *port); | 360 | syslog(LOG_DEBUG, "'%s': %d\n", NAME_PORT, *port); |
340 | syslog(LOG_DEBUG, "'%s': %s\n", NAME_ENABLE_IPV6, *enable_ipv6 ? "true" : "false"); | 361 | syslog(LOG_DEBUG, "'%s': %s\n", NAME_ENABLE_IPV6, *enable_ipv6 ? "true" : "false"); |
362 | syslog(LOG_DEBUG, "'%s': %s\n", NAME_ENABLE_IPV4_FALLBACK, *enable_ipv4_fallback ? "true" : "false"); | ||
341 | syslog(LOG_DEBUG, "'%s': %s\n", NAME_ENABLE_LAN_DISCOVERY, *enable_lan_discovery ? "true" : "false"); | 363 | syslog(LOG_DEBUG, "'%s': %s\n", NAME_ENABLE_LAN_DISCOVERY, *enable_lan_discovery ? "true" : "false"); |
342 | 364 | ||
343 | syslog(LOG_DEBUG, "'%s': %s\n", NAME_ENABLE_TCP_RELAY, *enable_tcp_relay ? "true" : "false"); | 365 | syslog(LOG_DEBUG, "'%s': %s\n", NAME_ENABLE_TCP_RELAY, *enable_tcp_relay ? "true" : "false"); |
@@ -370,7 +392,7 @@ int get_general_config(char *cfg_file_path, char **pid_file_path, char **keys_fi | |||
370 | // returns 1 on success, some or no bootstrap nodes were added | 392 | // returns 1 on success, some or no bootstrap nodes were added |
371 | // 0 on failure, a error accured while parsing config file | 393 | // 0 on failure, a error accured while parsing config file |
372 | 394 | ||
373 | int bootstrap_from_config(char *cfg_file_path, DHT *dht, int enable_ipv6) | 395 | int bootstrap_from_config(const char *cfg_file_path, DHT *dht, int enable_ipv6) |
374 | { | 396 | { |
375 | const char *NAME_BOOTSTRAP_NODES = "bootstrap_nodes"; | 397 | const char *NAME_BOOTSTRAP_NODES = "bootstrap_nodes"; |
376 | 398 | ||
@@ -475,7 +497,7 @@ next: | |||
475 | 497 | ||
476 | // Prints public key | 498 | // Prints public key |
477 | 499 | ||
478 | void print_public_key(uint8_t *public_key) | 500 | void print_public_key(const uint8_t *public_key) |
479 | { | 501 | { |
480 | char buffer[2 * crypto_box_PUBLICKEYBYTES + 1]; | 502 | char buffer[2 * crypto_box_PUBLICKEYBYTES + 1]; |
481 | int index = 0; | 503 | int index = 0; |
@@ -502,10 +524,11 @@ int main(int argc, char *argv[]) | |||
502 | return 1; | 524 | return 1; |
503 | } | 525 | } |
504 | 526 | ||
505 | char *cfg_file_path = argv[1]; | 527 | const char *cfg_file_path = argv[1]; |
506 | char *pid_file_path, *keys_file_path; | 528 | char *pid_file_path, *keys_file_path; |
507 | int port; | 529 | int port; |
508 | int enable_ipv6; | 530 | int enable_ipv6; |
531 | int enable_ipv4_fallback; | ||
509 | int enable_lan_discovery; | 532 | int enable_lan_discovery; |
510 | int enable_tcp_relay; | 533 | int enable_tcp_relay; |
511 | uint16_t *tcp_relay_ports; | 534 | uint16_t *tcp_relay_ports; |
@@ -513,8 +536,8 @@ int main(int argc, char *argv[]) | |||
513 | int enable_motd; | 536 | int enable_motd; |
514 | char *motd; | 537 | char *motd; |
515 | 538 | ||
516 | if (get_general_config(cfg_file_path, &pid_file_path, &keys_file_path, &port, &enable_ipv6, &enable_lan_discovery, | 539 | if (get_general_config(cfg_file_path, &pid_file_path, &keys_file_path, &port, &enable_ipv6, &enable_ipv4_fallback, |
517 | &enable_tcp_relay, &tcp_relay_ports, &tcp_relay_port_count, &enable_motd, &motd)) { | 540 | &enable_lan_discovery, &enable_tcp_relay, &tcp_relay_ports, &tcp_relay_port_count, &enable_motd, &motd)) { |
518 | syslog(LOG_DEBUG, "General config read successfully\n"); | 541 | syslog(LOG_DEBUG, "General config read successfully\n"); |
519 | } else { | 542 | } else { |
520 | syslog(LOG_ERR, "Couldn't read config file: %s. Exiting.\n", cfg_file_path); | 543 | syslog(LOG_ERR, "Couldn't read config file: %s. Exiting.\n", cfg_file_path); |
@@ -537,7 +560,27 @@ int main(int argc, char *argv[]) | |||
537 | IP ip; | 560 | IP ip; |
538 | ip_init(&ip, enable_ipv6); | 561 | ip_init(&ip, enable_ipv6); |
539 | 562 | ||
540 | DHT *dht = new_DHT(new_networking(ip, port)); | 563 | Networking_Core *net = new_networking(ip, port); |
564 | |||
565 | if (net == NULL) { | ||
566 | if (enable_ipv6 && enable_ipv4_fallback) { | ||
567 | syslog(LOG_DEBUG, "Couldn't initialize IPv6 networking. Falling back to using IPv4.\n"); | ||
568 | enable_ipv6 = 0; | ||
569 | ip_init(&ip, enable_ipv6); | ||
570 | net = new_networking(ip, port); | ||
571 | |||
572 | if (net == NULL) { | ||
573 | syslog(LOG_DEBUG, "Couldn't fallback to IPv4. Exiting.\n"); | ||
574 | return 1; | ||
575 | } | ||
576 | } else { | ||
577 | syslog(LOG_DEBUG, "Couldn't initialize networking. Exiting.\n"); | ||
578 | return 1; | ||
579 | } | ||
580 | } | ||
581 | |||
582 | |||
583 | DHT *dht = new_DHT(net); | ||
541 | 584 | ||
542 | if (dht == NULL) { | 585 | if (dht == NULL) { |
543 | syslog(LOG_ERR, "Couldn't initialize Tox DHT instance. Exiting.\n"); | 586 | syslog(LOG_ERR, "Couldn't initialize Tox DHT instance. Exiting.\n"); |
@@ -613,10 +656,10 @@ int main(int argc, char *argv[]) | |||
613 | free(keys_file_path); | 656 | free(keys_file_path); |
614 | 657 | ||
615 | // Fork off from the parent process | 658 | // Fork off from the parent process |
616 | pid_t pid = fork(); | 659 | const pid_t pid = fork(); |
617 | 660 | ||
618 | if (pid > 0) { | 661 | if (pid > 0) { |
619 | fprintf(pidf, "%d ", pid); | 662 | fprintf(pidf, "%d", pid); |
620 | fclose(pidf); | 663 | fclose(pidf); |
621 | syslog(LOG_DEBUG, "Forked successfully: PID: %d.\n", pid); | 664 | syslog(LOG_DEBUG, "Forked successfully: PID: %d.\n", pid); |
622 | return 0; | 665 | return 0; |
@@ -650,7 +693,7 @@ int main(int argc, char *argv[]) | |||
650 | close(STDERR_FILENO); | 693 | close(STDERR_FILENO); |
651 | 694 | ||
652 | uint64_t last_LANdiscovery = 0; | 695 | uint64_t last_LANdiscovery = 0; |
653 | uint16_t htons_port = htons(port); | 696 | const uint16_t htons_port = htons(port); |
654 | 697 | ||
655 | int waiting_for_dht_connection = 1; | 698 | int waiting_for_dht_connection = 1; |
656 | 699 | ||
diff --git a/other/bootstrap_daemon/tox-bootstrapd.conf b/other/bootstrap_daemon/tox-bootstrapd.conf index 60efb939..d02eb3d0 100644 --- a/other/bootstrap_daemon/tox-bootstrapd.conf +++ b/other/bootstrap_daemon/tox-bootstrapd.conf | |||
@@ -1,54 +1,65 @@ | |||
1 | // Tox DHT bootstrap daemon configuration file. | 1 | // Tox DHT bootstrap daemon configuration file. |
2 | 2 | ||
3 | // Listening port. | 3 | // Listening port (UDP). |
4 | port = 33445 | 4 | port = 33445 |
5 | 5 | ||
6 | // A key file is like a password, so keep it where no one can read it. | 6 | // A key file is like a password, so keep it where no one can read it. |
7 | // If there is no key file, a new one will be generated. | 7 | // If there is no key file, a new one will be generated. |
8 | // The daemon should have permission to read/write to it. | 8 | // The daemon should have permission to read/write it. |
9 | keys_file_path = "/var/lib/tox-bootstrapd/keys" | 9 | keys_file_path = "/var/lib/tox-bootstrapd/keys" |
10 | 10 | ||
11 | // The PID file written to by daemon. | 11 | // The PID file written to by the daemon. |
12 | // Make sure that the user who runs the daemon has permissions to write to the | 12 | // Make sure that the user that daemon runs as has permissions to write to the |
13 | // PID file. | 13 | // PID file. |
14 | pid_file_path = "/var/run/tox-bootstrapd/tox-bootstrapd.pid" | 14 | pid_file_path = "/var/run/tox-bootstrapd/tox-bootstrapd.pid" |
15 | 15 | ||
16 | // Enable IPv6. | 16 | // Enable IPv6. |
17 | enable_ipv6 = false | 17 | enable_ipv6 = true |
18 | |||
19 | // Fallback to IPv4 in case IPv6 fails. | ||
20 | enable_ipv4_fallback = true | ||
18 | 21 | ||
19 | // Automatically bootstrap with nodes on local area network. | 22 | // Automatically bootstrap with nodes on local area network. |
20 | enable_lan_discovery = true | 23 | enable_lan_discovery = true |
21 | 24 | ||
22 | enable_tcp_relay = true | 25 | enable_tcp_relay = true |
23 | 26 | ||
24 | // Tox uses 443, 3389 and 33445 ports by default, so it's highly recommended to keep | 27 | // While Tox uses 33445 port by default, 443 (https) and 3389 (rdp) ports are very |
25 | // them. | 28 | // common among nodes, so it's encouraged to keep them in place. |
26 | tcp_relay_ports = [443, 3389, 33445] | 29 | tcp_relay_ports = [443, 3389, 33445] |
27 | 30 | ||
28 | // It's planned to use message of the day as a convenient method of checking | 31 | // Reply to MOTD (Message Of The Day) requests. |
29 | // whether a node is up or not, though there are other methods of doing that. | ||
30 | enable_motd = true | 32 | enable_motd = true |
31 | 33 | ||
34 | // Just a message that is sent when someone requests MOTD. | ||
35 | // Put anything you want, but note that it will be trimmed to fit into 255 bytes. | ||
32 | motd = "tox-bootstrapd" | 36 | motd = "tox-bootstrapd" |
33 | 37 | ||
34 | // Any number of nodes the daemon will bootstrap itself off. | 38 | // Any number of nodes the daemon will bootstrap itself off. |
39 | // | ||
35 | // Remember to replace the provided example with your own node list. | 40 | // Remember to replace the provided example with your own node list. |
36 | // There is a maintained list of bootstrap nodes on Tox's wiki, if you need it | 41 | // There is a maintained list of bootstrap nodes on Tox's wiki, if you need it |
37 | // (http://wiki.tox.im/Nodes). | 42 | // (http://wiki.tox.im/Nodes). |
38 | // You may leave the list empty or remove "bootstrap_nodes" complitely, | 43 | // |
44 | // You may leave the list empty or remove "bootstrap_nodes" completely, | ||
39 | // in both cases this will be interpreted as if you don't want to bootstrap | 45 | // in both cases this will be interpreted as if you don't want to bootstrap |
40 | // from anyone. | 46 | // from anyone. |
47 | // | ||
48 | // address = any IPv4 or IPv6 address and also any US-ASCII domain name. | ||
41 | bootstrap_nodes = ( | 49 | bootstrap_nodes = ( |
42 | { // Node 1 | 50 | { // Example Node 1 (IPv4) |
43 | // Any ipv4 or ipv6, depending on whether `enable_ipv6` is set or not, | 51 | address = "127.0.0.1" |
44 | // and also any US-ASCII domain name. | ||
45 | address = "198.46.136.167" | ||
46 | port = 33445 | 52 | port = 33445 |
47 | public_key = "728925473812C7AAC482BE7250BCCAD0B8CB9F737BF3D42ABD34459C1768F854" | 53 | public_key = "728925473812C7AAC482BE7250BCCAD0B8CB9F737BF3D42ABD34459C1768F854" |
48 | }, | 54 | }, |
49 | { // Node 2 | 55 | { // Example Node 2 (IPv6) |
56 | address = "::1/128" | ||
57 | port = 33445 | ||
58 | public_key = "3E78BACF0F84235B30054B54898F56793E1DEF8BD46B1038B9D822E8460FAB67" | ||
59 | }, | ||
60 | { // Example Node 3 (US-ASCII domain name) | ||
50 | address = "example.org" | 61 | address = "example.org" |
51 | port = 33445 | 62 | port = 33445 |
52 | public_key = "8CD5A9BF0A6CE358BA36F7A653F99FA6B258FF756E490F52C1F98CC420F78858" | 63 | public_key = "8CD5A9BF0A6CE358BA36F7A653F99FA6B258FF756E490F52C1F98CC420F78858" |
53 | } | 64 | } |
54 | ) | 65 | ) \ No newline at end of file |
diff --git a/other/bootstrap_daemon/tox-bootstrapd.service b/other/bootstrap_daemon/tox-bootstrapd.service new file mode 100644 index 00000000..4b499311 --- /dev/null +++ b/other/bootstrap_daemon/tox-bootstrapd.service | |||
@@ -0,0 +1,19 @@ | |||
1 | [Unit] | ||
2 | Description=Tox DHT Bootstrap Daemon | ||
3 | After=network.target | ||
4 | |||
5 | [Service] | ||
6 | Type=forking | ||
7 | PermissionsStartOnly=true | ||
8 | ExecStartPre=-/bin/mkdir /var/run/tox-bootstrapd -p | ||
9 | ExecStartPre=/bin/chown tox-bootstrapd:tox-bootstrapd -R /var/run/tox-bootstrapd | ||
10 | WorkingDirectory=/var/lib/tox-bootstrapd | ||
11 | ExecStart=/usr/local/bin/tox-bootstrapd /etc/tox-bootstrapd.conf | ||
12 | User=tox-bootstrapd | ||
13 | Group=tox-bootstrapd | ||
14 | PIDFile=/var/run/tox-bootstrapd/tox-bootstrapd.pid | ||
15 | #CapabilityBoundingSet=CAP_NET_BIND_SERVICE | ||
16 | |||
17 | [Install] | ||
18 | WantedBy=multi-user.target | ||
19 | |||
diff --git a/other/bootstrap_daemon/tox-bootstrapd.sh b/other/bootstrap_daemon/tox-bootstrapd.sh index a6c137bd..1431bde0 100644 --- a/other/bootstrap_daemon/tox-bootstrapd.sh +++ b/other/bootstrap_daemon/tox-bootstrapd.sh | |||
@@ -23,7 +23,7 @@ USER=tox-bootstrapd | |||
23 | GROUP=tox-bootstrapd | 23 | GROUP=tox-bootstrapd |
24 | 24 | ||
25 | # Exit if the package is not installed | 25 | # Exit if the package is not installed |
26 | [ -x "$DAEMON" ] || exit 5 | 26 | [ -x "$DAEMON" ] || exit 0 |
27 | 27 | ||
28 | # Load the VERBOSE setting and other rcS variables | 28 | # Load the VERBOSE setting and other rcS variables |
29 | . /lib/init/vars.sh | 29 | . /lib/init/vars.sh |
diff --git a/other/bootstrap_node_packets.c b/other/bootstrap_node_packets.c index e8df3289..0bf9b9b0 100644 --- a/other/bootstrap_node_packets.c +++ b/other/bootstrap_node_packets.c | |||
@@ -34,7 +34,7 @@ static uint16_t bootstrap_motd_length; | |||
34 | /* To request this packet just send a packet of length INFO_REQUEST_PACKET_LENGTH | 34 | /* To request this packet just send a packet of length INFO_REQUEST_PACKET_LENGTH |
35 | * with the first byte being BOOTSTRAP_INFO_PACKET_ID | 35 | * with the first byte being BOOTSTRAP_INFO_PACKET_ID |
36 | */ | 36 | */ |
37 | static int handle_info_request(void *object, IP_Port source, const uint8_t *packet, uint32_t length) | 37 | static int handle_info_request(void *object, IP_Port source, const uint8_t *packet, uint16_t length) |
38 | { | 38 | { |
39 | if (length != INFO_REQUEST_PACKET_LENGTH) | 39 | if (length != INFO_REQUEST_PACKET_LENGTH) |
40 | return 1; | 40 | return 1; |
diff --git a/other/fun/make-funny-savefile.py b/other/fun/make-funny-savefile.py new file mode 100755 index 00000000..43f14a6e --- /dev/null +++ b/other/fun/make-funny-savefile.py | |||
@@ -0,0 +1,122 @@ | |||
1 | #!/usr/bin/python | ||
2 | |||
3 | """ | ||
4 | Generate a new (and empty) save file with predefined keys. Used to play | ||
5 | with externally generated keys. | ||
6 | |||
7 | (c) 2015 Alexandre Erwin Ittner | ||
8 | |||
9 | Distributed under the GNU GPL v3 or later, WITHOUT ANY WARRANTY. See the | ||
10 | file "COPYING" for license information. | ||
11 | |||
12 | |||
13 | Usage: | ||
14 | |||
15 | ./make-funny-savefile.py <public key> <private key> <user name> <out file> | ||
16 | |||
17 | The new user profile will be saved to <out file>. | ||
18 | |||
19 | The keys must be an hex-encoded valid key pair generated by any means | ||
20 | (eg. strkey.c); username may be anything. A random nospam value will be | ||
21 | generated. | ||
22 | |||
23 | Once the savefile is done, load it in your favorite client to get some | ||
24 | DHT nodes, set status and status messages, add friends, etc. | ||
25 | |||
26 | |||
27 | Example (of course, do not try using this key for anything real): | ||
28 | |||
29 | ./make-funny-savefile.py 123411DC8B1A4760B648E0C7243B65F01069E4858F45C612CE1A6F673B603830 CC39440CFC063E4A95B7F2FB2580210558BE5C073AFC1C9604D431CCA3132238 "Test user" test.tox | ||
30 | |||
31 | |||
32 | """ | ||
33 | |||
34 | |||
35 | PUBLIC_KEY_LENGTH = 32 | ||
36 | PRIVATE_KEY_LENGTH = 32 | ||
37 | |||
38 | # Constants taken from messenger.c | ||
39 | MESSENGER_STATE_COOKIE_GLOBAL = 0x15ed1b1f | ||
40 | MESSENGER_STATE_COOKIE_TYPE = 0x01ce | ||
41 | MESSENGER_STATE_TYPE_NOSPAMKEYS = 1 | ||
42 | MESSENGER_STATE_TYPE_DHT = 2 | ||
43 | MESSENGER_STATE_TYPE_FRIENDS = 3 | ||
44 | MESSENGER_STATE_TYPE_NAME = 4 | ||
45 | MESSENGER_STATE_TYPE_STATUSMESSAGE = 5 | ||
46 | MESSENGER_STATE_TYPE_STATUS = 6 | ||
47 | MESSENGER_STATE_TYPE_TCP_RELAY = 10 | ||
48 | MESSENGER_STATE_TYPE_PATH_NODE = 11 | ||
49 | |||
50 | STATUS_MESSAGE = "New user".encode("utf-8") | ||
51 | |||
52 | |||
53 | |||
54 | import sys | ||
55 | import struct | ||
56 | import os | ||
57 | |||
58 | def abort(msg): | ||
59 | print(msg) | ||
60 | exit(1) | ||
61 | |||
62 | |||
63 | |||
64 | if len(sys.argv) != 5: | ||
65 | abort("Usage: %s <public key> <private key> <user name> <out file>" % (sys.argv[0])) | ||
66 | |||
67 | try: | ||
68 | public_key = sys.argv[1].decode("hex") | ||
69 | except: | ||
70 | abort("Bad public key") | ||
71 | |||
72 | try: | ||
73 | private_key = sys.argv[2].decode("hex") | ||
74 | except: | ||
75 | abort("Bad private key") | ||
76 | |||
77 | if len(public_key) != PUBLIC_KEY_LENGTH: | ||
78 | abort("Public key with wrong length") | ||
79 | |||
80 | if len(private_key) != PRIVATE_KEY_LENGTH: | ||
81 | abort("Private key with wrong length") | ||
82 | |||
83 | user_name = sys.argv[3].encode("utf-8") | ||
84 | |||
85 | if len(user_name) > 32: | ||
86 | abort("User name too long (for this script, at least)") | ||
87 | |||
88 | out_file_name = sys.argv[4] | ||
89 | nospam = os.urandom(4) | ||
90 | |||
91 | |||
92 | def make_subheader(h_type, h_length): | ||
93 | return ( | ||
94 | struct.pack("<I", h_length) + | ||
95 | struct.pack("<H", h_type) + | ||
96 | struct.pack("<H", MESSENGER_STATE_COOKIE_TYPE)) | ||
97 | |||
98 | data = ( | ||
99 | # Main header | ||
100 | struct.pack("<I", 0) + | ||
101 | struct.pack("<I", MESSENGER_STATE_COOKIE_GLOBAL) + | ||
102 | |||
103 | # Keys | ||
104 | make_subheader(MESSENGER_STATE_TYPE_NOSPAMKEYS, | ||
105 | len(nospam) + PUBLIC_KEY_LENGTH + PRIVATE_KEY_LENGTH) + | ||
106 | nospam + public_key + private_key + | ||
107 | |||
108 | # Name (not really needed, but helps) | ||
109 | make_subheader(MESSENGER_STATE_TYPE_NAME, len(user_name)) + | ||
110 | user_name + | ||
111 | |||
112 | # Status message (not really needed, but helps) | ||
113 | make_subheader(MESSENGER_STATE_TYPE_STATUSMESSAGE, len(STATUS_MESSAGE)) + | ||
114 | STATUS_MESSAGE | ||
115 | ) | ||
116 | |||
117 | |||
118 | try: | ||
119 | with open(out_file_name, "wb") as fp: | ||
120 | fp.write(data) | ||
121 | except Exception as e: | ||
122 | abort(str(e)) | ||
diff --git a/other/osx_build_script_toxcore.sh b/other/osx_build_script_toxcore.sh new file mode 100644 index 00000000..8aea0d1c --- /dev/null +++ b/other/osx_build_script_toxcore.sh | |||
@@ -0,0 +1,38 @@ | |||
1 | #!/usr/bin/env bash | ||
2 | # written by Lubo Diakov | ||
3 | # hard coded toxcore directory, replace with other path or variable as needed | ||
4 | cd ~/Downloads/toxcore | ||
5 | echo "Now working in:"`pwd` | ||
6 | |||
7 | # must have working git binary, and have done git clone at least once before | ||
8 | git pull | ||
9 | echo "If git pull responds: Already up-to-date. you can cancel the build" | ||
10 | echo "by typing anything except y or Y below" | ||
11 | read -p "Continue with build? (enter y to continue): " Last_Chance | ||
12 | |||
13 | # blah blah | ||
14 | if [[ $Last_Chance = [Yy] ]]; then echo "Continuing!"; | ||
15 | else echo "Aborted!"; exit | ||
16 | fi | ||
17 | sleep 3 | ||
18 | |||
19 | # if libsodium is built with macports, link it from /opt/local/ to /usr/local | ||
20 | if [ ! -L "/usr/local/lib/libsodium.dylib" ]; then | ||
21 | # Control will enter here if $DIRECTORY doesn't exist. | ||
22 | ln -s /opt/local/lib/libsodium.dylib /usr/local/lib/libsodium.dylib | ||
23 | fi | ||
24 | echo "The symlink /usr/local/lib/libsodium.dylib exists." | ||
25 | sleep 3 | ||
26 | |||
27 | # replace ppc, i386 as needed. | ||
28 | ./configure CC="gcc -arch ppc -arch i386" CXX="g++ -arch ppc -arch i386" CPP="gcc -E" CXXCPP="g++ -E" | ||
29 | |||
30 | # get rid of prior builds, start clean | ||
31 | make clean | ||
32 | make | ||
33 | echo "" | ||
34 | echo "Sudo is required for make install only, all other steps run without it." | ||
35 | echo "Please type your sudo password below for make install:" | ||
36 | sudo make install | ||
37 | |||
38 | exit | ||
diff --git a/testing/DHT_test.c b/testing/DHT_test.c index 2636ed02..5cdd1823 100644 --- a/testing/DHT_test.c +++ b/testing/DHT_test.c | |||
@@ -208,7 +208,7 @@ int main(int argc, char *argv[]) | |||
208 | temp_id[strlen(temp_id) - 1] = '\0'; | 208 | temp_id[strlen(temp_id) - 1] = '\0'; |
209 | 209 | ||
210 | uint8_t *bin_id = hex_string_to_bin(temp_id); | 210 | uint8_t *bin_id = hex_string_to_bin(temp_id); |
211 | DHT_addfriend(dht, bin_id); | 211 | DHT_addfriend(dht, bin_id, 0, 0, 0, 0); |
212 | free(bin_id); | 212 | free(bin_id); |
213 | 213 | ||
214 | perror("Initialization"); | 214 | perror("Initialization"); |
diff --git a/testing/Makefile.inc b/testing/Makefile.inc index 42d89e05..8b93c8ac 100644 --- a/testing/Makefile.inc +++ b/testing/Makefile.inc | |||
@@ -105,6 +105,35 @@ tox_shell_LDADD = $(LIBSODIUM_LDFLAGS) \ | |||
105 | $(NACL_LIBS) \ | 105 | $(NACL_LIBS) \ |
106 | -lutil | 106 | -lutil |
107 | 107 | ||
108 | |||
109 | noinst_PROGRAMS += test_avatars | ||
110 | |||
111 | test_avatars_SOURCES = ../testing/test_avatars.c | ||
112 | |||
113 | test_avatars_CFLAGS = $(LIBSODIUM_CFLAGS) \ | ||
114 | $(NACL_CFLAGS) | ||
115 | |||
116 | test_avatars_LDADD = $(LIBSODIUM_LDFLAGS) \ | ||
117 | $(NACL_LDFLAGS) \ | ||
118 | libtoxcore.la \ | ||
119 | $(LIBSODIUM_LIBS) \ | ||
120 | $(NACL_OBJECTS) \ | ||
121 | $(NACL_LIBS) | ||
122 | |||
123 | |||
124 | noinst_PROGRAMS += irc_syncbot | ||
125 | |||
126 | irc_syncbot_SOURCES = ../testing/irc_syncbot.c | ||
127 | |||
128 | irc_syncbot_CFLAGS = $(LIBSODIUM_CFLAGS) \ | ||
129 | $(NACL_CFLAGS) | ||
130 | |||
131 | irc_syncbot_LDADD = $(LIBSODIUM_LDFLAGS) \ | ||
132 | $(NACL_LDFLAGS) \ | ||
133 | libtoxcore.la \ | ||
134 | $(LIBSODIUM_LIBS) \ | ||
135 | $(NACL_OBJECTS) \ | ||
136 | $(NACL_LIBS) | ||
108 | endif | 137 | endif |
109 | 138 | ||
110 | EXTRA_DIST += $(top_srcdir)/testing/misc_tools.c | 139 | EXTRA_DIST += $(top_srcdir)/testing/misc_tools.c |
diff --git a/testing/irc_syncbot.c b/testing/irc_syncbot.c new file mode 100644 index 00000000..f7486115 --- /dev/null +++ b/testing/irc_syncbot.c | |||
@@ -0,0 +1,350 @@ | |||
1 | |||
2 | #include <stdlib.h> | ||
3 | #include <stdio.h> | ||
4 | #include <stdint.h> | ||
5 | #include <string.h> | ||
6 | #include <time.h> | ||
7 | |||
8 | |||
9 | #include <fcntl.h> | ||
10 | #include <sys/socket.h> | ||
11 | #include <netinet/in.h> | ||
12 | #include <arpa/inet.h> | ||
13 | #include <errno.h> | ||
14 | #include <sys/time.h> | ||
15 | #include <sys/types.h> | ||
16 | #include <netdb.h> | ||
17 | #include <unistd.h> | ||
18 | |||
19 | #include <sys/ioctl.h> | ||
20 | |||
21 | #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(__MACH__) | ||
22 | #define MSG_NOSIGNAL 0 | ||
23 | #endif | ||
24 | |||
25 | //IRC name and channel. | ||
26 | #define IRC_NAME "Tox_syncbot" | ||
27 | #define IRC_CHANNEL "#tox-real-ontopic" | ||
28 | |||
29 | //IRC server ip and port. | ||
30 | uint8_t ip[4] = {127, 0, 0, 1}; | ||
31 | uint16_t port = 6667; | ||
32 | |||
33 | #define SILENT_TIMEOUT 20 | ||
34 | |||
35 | int sock; | ||
36 | |||
37 | #define SERVER_CONNECT "NICK "IRC_NAME"\nUSER "IRC_NAME" 8 * :"IRC_NAME"\n" | ||
38 | #define CHANNEL_JOIN "JOIN "IRC_CHANNEL"\n" | ||
39 | |||
40 | /* In toxcore/network.c */ | ||
41 | uint64_t current_time_monotonic(void); | ||
42 | |||
43 | uint64_t get_monotime_sec(void) | ||
44 | { | ||
45 | return current_time_monotonic() / 1000; | ||
46 | } | ||
47 | |||
48 | int reconnect(void) | ||
49 | { | ||
50 | int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); | ||
51 | |||
52 | if (sock < 0) { | ||
53 | printf("error socket\n"); | ||
54 | return -1; | ||
55 | } | ||
56 | |||
57 | struct sockaddr_storage addr = {0}; | ||
58 | |||
59 | size_t addrsize; | ||
60 | |||
61 | struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr; | ||
62 | |||
63 | addrsize = sizeof(struct sockaddr_in); | ||
64 | |||
65 | addr4->sin_family = AF_INET; | ||
66 | |||
67 | memcpy(&addr4->sin_addr, ip, 4); | ||
68 | |||
69 | addr4->sin_port = htons(port); | ||
70 | |||
71 | if (connect(sock, (struct sockaddr *)&addr, addrsize) != 0) { | ||
72 | printf("error connect\n"); | ||
73 | return -1; | ||
74 | } | ||
75 | |||
76 | send(sock, SERVER_CONNECT, sizeof(SERVER_CONNECT) - 1, MSG_NOSIGNAL); | ||
77 | |||
78 | return sock; | ||
79 | } | ||
80 | |||
81 | #include "../toxcore/tox.h" | ||
82 | #include "misc_tools.c" | ||
83 | |||
84 | int current_group = -1; | ||
85 | |||
86 | static void callback_group_invite(Tox *tox, int fid, uint8_t type, const uint8_t *data, uint16_t length, void *userdata) | ||
87 | { | ||
88 | if (current_group == -1) | ||
89 | current_group = tox_join_groupchat(tox, fid, data, length); | ||
90 | } | ||
91 | |||
92 | void callback_friend_message(Tox *tox, int fid, const uint8_t *message, uint16_t length, void *userdata) | ||
93 | { | ||
94 | if (length == 1 && *message == 'c') { | ||
95 | if (tox_del_groupchat(tox, current_group) == 0) | ||
96 | current_group = -1; | ||
97 | } | ||
98 | |||
99 | if (length == 1 && *message == 'i') { | ||
100 | tox_invite_friend(tox, fid, current_group); | ||
101 | } | ||
102 | |||
103 | if (length == 1 && *message == 'j' && sock >= 0) { | ||
104 | send(sock, CHANNEL_JOIN, sizeof(CHANNEL_JOIN) - 1, MSG_NOSIGNAL); | ||
105 | } | ||
106 | } | ||
107 | |||
108 | static void copy_groupmessage(Tox *tox, int groupnumber, int friendgroupnumber, const uint8_t *message, uint16_t length, | ||
109 | void *userdata) | ||
110 | { | ||
111 | if (tox_group_peernumber_is_ours(tox, groupnumber, friendgroupnumber)) | ||
112 | return; | ||
113 | |||
114 | uint8_t name[TOX_MAX_NAME_LENGTH]; | ||
115 | int namelen = tox_group_peername(tox, groupnumber, friendgroupnumber, name); | ||
116 | |||
117 | if (namelen == 0 || namelen == -1) { | ||
118 | memcpy(name, "<unknown>", 9); | ||
119 | namelen = 9; | ||
120 | } | ||
121 | |||
122 | uint8_t sendbuf[2048]; | ||
123 | uint16_t send_len = 0; | ||
124 | |||
125 | memcpy(sendbuf, "PRIVMSG "IRC_CHANNEL" :", sizeof("PRIVMSG "IRC_CHANNEL" :")); | ||
126 | send_len += sizeof("PRIVMSG "IRC_CHANNEL" :") - 1; | ||
127 | memcpy(sendbuf + send_len, name, namelen); | ||
128 | send_len += namelen; | ||
129 | sendbuf[send_len] = ':'; | ||
130 | send_len += 1; | ||
131 | sendbuf[send_len] = ' '; | ||
132 | send_len += 1; | ||
133 | memcpy(sendbuf + send_len, message, length); | ||
134 | send_len += length; | ||
135 | unsigned int i; | ||
136 | |||
137 | for (i = 0; i < send_len; ++i) { | ||
138 | if (sendbuf[i] == '\n') | ||
139 | sendbuf[i] = '|'; | ||
140 | |||
141 | if (sendbuf[i] == 0) | ||
142 | sendbuf[i] = ' '; | ||
143 | } | ||
144 | |||
145 | sendbuf[send_len] = '\n'; | ||
146 | send_len += 1; | ||
147 | |||
148 | if (sock >= 0) | ||
149 | send(sock, sendbuf, send_len, MSG_NOSIGNAL); | ||
150 | } | ||
151 | |||
152 | void send_irc_group(Tox *tox, uint8_t *msg, uint16_t len) | ||
153 | { | ||
154 | if (len > 1350 || len == 0 || len == 1) | ||
155 | return; | ||
156 | |||
157 | --len; | ||
158 | |||
159 | if (*msg != ':') | ||
160 | return; | ||
161 | |||
162 | uint8_t req[len]; | ||
163 | unsigned int i; | ||
164 | |||
165 | for (i = 0; i < (len - 1); ++i) { | ||
166 | if (msg[i + 1] == ':') { | ||
167 | break; | ||
168 | } | ||
169 | |||
170 | req[i] = msg[i + 1]; | ||
171 | } | ||
172 | |||
173 | unsigned int req_len = i; | ||
174 | req[i] = 0; | ||
175 | |||
176 | uint8_t message[len]; | ||
177 | uint16_t length = 0; | ||
178 | |||
179 | uint8_t *pmsg = (uint8_t *)strstr((char *)req, " PRIVMSG"); | ||
180 | |||
181 | if (pmsg == NULL) | ||
182 | return; | ||
183 | |||
184 | uint8_t *dt = req; | ||
185 | |||
186 | for (dt = req, i = 0; dt != pmsg && *dt != '!'; ++dt, ++i) { | ||
187 | message[i] = *dt; | ||
188 | ++length; | ||
189 | } | ||
190 | |||
191 | message[length] = ':'; | ||
192 | length += 1; | ||
193 | message[length] = ' '; | ||
194 | length += 1; | ||
195 | |||
196 | if ((req_len + 2) >= len) | ||
197 | return; | ||
198 | |||
199 | memcpy(message + length, msg + req_len + 2, len - (req_len + 2)); | ||
200 | length += len - (req_len + 2); | ||
201 | tox_group_message_send(tox, current_group, message, length); | ||
202 | } | ||
203 | |||
204 | Tox *init_tox(int argc, char *argv[]) | ||
205 | { | ||
206 | uint8_t ipv6enabled = TOX_ENABLE_IPV6_DEFAULT; /* x */ | ||
207 | int argvoffset = cmdline_parsefor_ipv46(argc, argv, &ipv6enabled); | ||
208 | |||
209 | if (argvoffset < 0) | ||
210 | exit(1); | ||
211 | |||
212 | /* with optional --ipvx, now it can be 1-4 arguments... */ | ||
213 | if ((argc != argvoffset + 2) && (argc != argvoffset + 4)) { | ||
214 | printf("Usage: %s [--ipv4|--ipv6] ip port public_key (of the DHT bootstrap node)\n", argv[0]); | ||
215 | exit(0); | ||
216 | } | ||
217 | |||
218 | Tox *tox = tox_new(0); | ||
219 | |||
220 | if (!tox) | ||
221 | exit(1); | ||
222 | |||
223 | tox_set_name(tox, (uint8_t *)IRC_NAME, sizeof(IRC_NAME) - 1); | ||
224 | tox_callback_friend_message(tox, &callback_friend_message, 0); | ||
225 | tox_callback_group_invite(tox, &callback_group_invite, 0); | ||
226 | tox_callback_group_message(tox, ©_groupmessage, 0); | ||
227 | tox_callback_group_action(tox, ©_groupmessage, 0); | ||
228 | |||
229 | uint16_t port = atoi(argv[argvoffset + 2]); | ||
230 | unsigned char *binary_string = hex_string_to_bin(argv[argvoffset + 3]); | ||
231 | int res = tox_bootstrap_from_address(tox, argv[argvoffset + 1], port, binary_string); | ||
232 | free(binary_string); | ||
233 | |||
234 | char temp_id[128]; | ||
235 | printf("\nEnter the address of irc_syncbots master (38 bytes HEX format):\n"); | ||
236 | |||
237 | if (scanf("%s", temp_id) != 1) { | ||
238 | exit (1); | ||
239 | } | ||
240 | |||
241 | uint8_t *bin_id = hex_string_to_bin(temp_id); | ||
242 | int num = tox_add_friend(tox, bin_id, (uint8_t *)"Install Gentoo", sizeof("Install Gentoo") - 1); | ||
243 | free(bin_id); | ||
244 | |||
245 | if (num < 0) { | ||
246 | printf("\nSomething went wrong when adding friend.\n"); | ||
247 | exit(1); | ||
248 | } | ||
249 | |||
250 | return tox; | ||
251 | } | ||
252 | |||
253 | int main(int argc, char *argv[]) | ||
254 | { | ||
255 | Tox *tox = init_tox(argc, argv); | ||
256 | |||
257 | sock = reconnect(); | ||
258 | |||
259 | if (sock < 0) | ||
260 | return 1; | ||
261 | |||
262 | uint64_t last_get = get_monotime_sec(); | ||
263 | int connected = 0, ping_sent = 0; | ||
264 | |||
265 | while (1) { | ||
266 | int count = 0; | ||
267 | ioctl(sock, FIONREAD, &count); | ||
268 | |||
269 | if (count > 0) { | ||
270 | last_get = get_monotime_sec(); | ||
271 | ping_sent = 0; | ||
272 | uint8_t data[count + 1]; | ||
273 | data[count] = 0; | ||
274 | recv(sock, data, count, MSG_NOSIGNAL); | ||
275 | printf("%s", data); | ||
276 | |||
277 | if (!connected) | ||
278 | connected = 1; | ||
279 | |||
280 | if (count > 6 && data[0] == 'P' && data[1] == 'I' && data[2] == 'N' && data[3] == 'G') { | ||
281 | data[1] = 'O'; | ||
282 | unsigned int i; | ||
283 | |||
284 | for (i = 0; i < count; ++i) { | ||
285 | if (data[i] == '\n') { | ||
286 | ++i; | ||
287 | break; | ||
288 | } | ||
289 | } | ||
290 | |||
291 | send(sock, data, i, MSG_NOSIGNAL); | ||
292 | } | ||
293 | |||
294 | unsigned int i, p_i = 0; | ||
295 | |||
296 | for (i = 1; data[0] == ':' && i < count; ++i) { | ||
297 | if (data[i] == ' ') { | ||
298 | if (i + 5 < count && memcmp(data + i, " 404 ", 5) == 0) { | ||
299 | connected = 1; | ||
300 | } | ||
301 | |||
302 | break; | ||
303 | } | ||
304 | |||
305 | if (data[i] == ':') | ||
306 | break; | ||
307 | } | ||
308 | |||
309 | for (i = 0; i < count; ++i) { | ||
310 | if (data[i] == '\n' && i != 0) { | ||
311 | send_irc_group(tox, data + p_i, i - p_i); | ||
312 | p_i = i + 1; | ||
313 | } | ||
314 | } | ||
315 | } | ||
316 | |||
317 | if (connected == 1) { | ||
318 | send(sock, CHANNEL_JOIN, sizeof(CHANNEL_JOIN) - 1, MSG_NOSIGNAL); | ||
319 | connected = 2; | ||
320 | } | ||
321 | |||
322 | if (!ping_sent && last_get + (SILENT_TIMEOUT / 2) < get_monotime_sec()) { | ||
323 | unsigned int p_s = sizeof("PING :test\n") - 1; | ||
324 | |||
325 | if (send(sock, "PING :test\n", p_s, MSG_NOSIGNAL) == p_s) | ||
326 | ping_sent = 1; | ||
327 | } | ||
328 | |||
329 | int error = 0; | ||
330 | socklen_t len = sizeof (error); | ||
331 | |||
332 | if (sock < 0 || last_get + SILENT_TIMEOUT < get_monotime_sec() | ||
333 | || getsockopt(sock, SOL_SOCKET, SO_ERROR, &error, &len ) != 0) { | ||
334 | close(sock); | ||
335 | printf("reconnect\n"); | ||
336 | sock = reconnect(); | ||
337 | |||
338 | if (sock >= 0) { | ||
339 | last_get = get_monotime_sec(); | ||
340 | connected = 0; | ||
341 | ping_sent = 0; | ||
342 | } | ||
343 | } | ||
344 | |||
345 | tox_do(tox); | ||
346 | usleep(1000 * 50); | ||
347 | } | ||
348 | |||
349 | return 0; | ||
350 | } | ||
diff --git a/testing/nTox.c b/testing/nTox.c index edda43b1..329191d7 100644 --- a/testing/nTox.c +++ b/testing/nTox.c | |||
@@ -1001,11 +1001,17 @@ void print_help(char *prog_name) | |||
1001 | puts(" -f keyfile [Optional] Specify a keyfile to read from and write to."); | 1001 | puts(" -f keyfile [Optional] Specify a keyfile to read from and write to."); |
1002 | } | 1002 | } |
1003 | 1003 | ||
1004 | void print_invite(Tox *m, int friendnumber, const uint8_t *group_public_key, void *userdata) | 1004 | void print_invite(Tox *m, int friendnumber, uint8_t type, const uint8_t *data, uint16_t length, void *userdata) |
1005 | { | 1005 | { |
1006 | char msg[256]; | 1006 | char msg[256]; |
1007 | sprintf(msg, "[i] received group chat invite from: %u, auto accepting and joining. group number: %u", friendnumber, | 1007 | |
1008 | tox_join_groupchat(m, friendnumber, group_public_key)); | 1008 | if (type == TOX_GROUPCHAT_TYPE_TEXT) { |
1009 | sprintf(msg, "[i] received group chat invite from: %u, auto accepting and joining. group number: %u", friendnumber, | ||
1010 | tox_join_groupchat(m, friendnumber, data, length)); | ||
1011 | } else { | ||
1012 | sprintf(msg, "[i] Group chat invite received of type %u that could not be accepted by ntox.", type); | ||
1013 | } | ||
1014 | |||
1009 | new_lines(msg); | 1015 | new_lines(msg); |
1010 | } | 1016 | } |
1011 | 1017 | ||
diff --git a/testing/test_avatars.c b/testing/test_avatars.c new file mode 100644 index 00000000..b4adc48f --- /dev/null +++ b/testing/test_avatars.c | |||
@@ -0,0 +1,755 @@ | |||
1 | /* | ||
2 | * A bot to test Tox avatars | ||
3 | * | ||
4 | * Usage: ./test_avatars <data dir> | ||
5 | * | ||
6 | * Connects to the Tox network, publishes our avatar, requests our friends | ||
7 | * avatars and, if available, saves them to a local cache. | ||
8 | * This bot automatically accepts any friend request. | ||
9 | * | ||
10 | * | ||
11 | * Data dir MUST have: | ||
12 | * | ||
13 | * - A file named "data" (named accordingly to STS Draft v0.1.0) with | ||
14 | * user id, friends, bootstrap data, etc. from a previously configured | ||
15 | * Tox session; use a client (eg. toxic) to configure it, add friends, | ||
16 | * etc. | ||
17 | * | ||
18 | * Data dir MAY have: | ||
19 | * | ||
20 | * - A directory named "avatars" with the user's avatar and cached avatars. | ||
21 | * The user avatar must be named in the format: "<uppercase pub key>.png" | ||
22 | * | ||
23 | * | ||
24 | * The bot will answer to these commands: | ||
25 | * | ||
26 | * !debug-on - Enable extended debug messages | ||
27 | * !debug-off - Disenable extended debug messages | ||
28 | * !set-avatar - Set our avatar from "avatars/<USERID>.png" | ||
29 | * !remove-avatar - Remove our avatar | ||
30 | * | ||
31 | */ | ||
32 | |||
33 | #define DATA_FILE_NAME "data" | ||
34 | #define AVATAR_DIR_NAME "avatars" | ||
35 | |||
36 | #ifdef HAVE_CONFIG_H | ||
37 | #include "config.h" | ||
38 | #endif | ||
39 | |||
40 | #include "../toxcore/tox.h" | ||
41 | |||
42 | #include <stdlib.h> | ||
43 | #include <stdio.h> | ||
44 | #include <string.h> | ||
45 | #include <unistd.h> | ||
46 | #include <time.h> | ||
47 | #include <stdbool.h> | ||
48 | #include <limits.h> | ||
49 | #include <sys/stat.h> | ||
50 | #include <unistd.h> | ||
51 | #include <errno.h> | ||
52 | #include <stdarg.h> | ||
53 | |||
54 | |||
55 | |||
56 | /* Basic debug utils */ | ||
57 | |||
58 | #define DEBUG(format, ...) debug_printf("DEBUG: %s:%d %s: " format "\n", __FILE__, __LINE__, __func__, ##__VA_ARGS__) | ||
59 | |||
60 | static bool print_debug_msgs = true; | ||
61 | |||
62 | static void debug_printf(const char *fmt, ...) | ||
63 | { | ||
64 | if (print_debug_msgs == true) { | ||
65 | va_list ap; | ||
66 | va_start(ap, fmt); | ||
67 | vprintf(fmt, ap); | ||
68 | va_end(ap); | ||
69 | } | ||
70 | } | ||
71 | |||
72 | |||
73 | |||
74 | |||
75 | |||
76 | |||
77 | /* ------------ Avatar cache managenment functions ------------ */ | ||
78 | |||
79 | typedef struct { | ||
80 | uint8_t format; | ||
81 | char *suffix; | ||
82 | } avatar_format_data_t; | ||
83 | |||
84 | static const avatar_format_data_t avatar_formats[] = { | ||
85 | /* In order of preference */ | ||
86 | { TOX_AVATAR_FORMAT_PNG, "png" }, | ||
87 | { TOX_AVATAR_FORMAT_NONE, NULL }, /* Must be the last one */ | ||
88 | }; | ||
89 | |||
90 | |||
91 | |||
92 | static void set_avatar(Tox *tox, const char *base_dir); | ||
93 | |||
94 | |||
95 | static char *get_avatar_suffix_from_format(uint8_t format) | ||
96 | { | ||
97 | int i; | ||
98 | |||
99 | for (i = 0; avatar_formats[i].format != TOX_AVATAR_FORMAT_NONE; i++) | ||
100 | if (avatar_formats[i].format == format) | ||
101 | return avatar_formats[i].suffix; | ||
102 | |||
103 | return NULL; | ||
104 | } | ||
105 | |||
106 | |||
107 | /* Load avatar data from a file into a memory buffer 'buf'. | ||
108 | * buf must have at least TOX_MAX_AVATAR_DATA_LENGTH bytes | ||
109 | * Returns the length of the data sucess or < 0 on error | ||
110 | */ | ||
111 | static int load_avatar_data(char *fname, uint8_t *buf) | ||
112 | { | ||
113 | FILE *fp = fopen(fname, "rb"); | ||
114 | |||
115 | if (fp == NULL) | ||
116 | return -1; /* Error */ | ||
117 | |||
118 | size_t n = fread(buf, 1, TOX_AVATAR_MAX_DATA_LENGTH, fp); | ||
119 | int ret; | ||
120 | |||
121 | if (ferror(fp) != 0 || n == 0) | ||
122 | ret = -1; /* Error */ | ||
123 | else | ||
124 | ret = n; | ||
125 | |||
126 | fclose(fp); | ||
127 | return ret; | ||
128 | } | ||
129 | |||
130 | |||
131 | /* Save avatar data to a file */ | ||
132 | static int save_avatar_data(char *fname, uint8_t *data, uint32_t len) | ||
133 | { | ||
134 | FILE *fp = fopen(fname, "wb"); | ||
135 | |||
136 | if (fp == NULL) | ||
137 | return -1; /* Error */ | ||
138 | |||
139 | int ret = 0; /* Ok */ | ||
140 | |||
141 | if (fwrite(data, 1, len, fp) != len) | ||
142 | ret = -1; /* Error */ | ||
143 | |||
144 | if (fclose(fp) != 0) | ||
145 | ret = -1; /* Error */ | ||
146 | |||
147 | return ret; | ||
148 | } | ||
149 | |||
150 | |||
151 | static void byte_to_hex_str(const uint8_t *buf, const size_t buflen, char *dst) | ||
152 | { | ||
153 | const char *hex_chars = "0123456789ABCDEF"; | ||
154 | size_t i = 0; | ||
155 | size_t j = 0; | ||
156 | |||
157 | while (i < buflen) { | ||
158 | dst[j++] = hex_chars[(buf[i] >> 4) & 0xf]; | ||
159 | dst[j++] = hex_chars[buf[i] & 0xf]; | ||
160 | i++; | ||
161 | } | ||
162 | |||
163 | dst[j++] = '\0'; | ||
164 | } | ||
165 | |||
166 | /* Make the cache file name for an avatar of the given format for the given | ||
167 | * public key. | ||
168 | */ | ||
169 | static int make_avatar_file_name(char *dst, size_t dst_len, const char *base_dir, | ||
170 | const uint8_t format, uint8_t *public_key) | ||
171 | { | ||
172 | char public_key_str[2 * TOX_PUBLIC_KEY_SIZE + 1]; | ||
173 | byte_to_hex_str(public_key, TOX_PUBLIC_KEY_SIZE, public_key_str); | ||
174 | |||
175 | const char *suffix = get_avatar_suffix_from_format(format); | ||
176 | |||
177 | if (suffix == NULL) | ||
178 | return -1; /* Error */ | ||
179 | |||
180 | int n = snprintf(dst, dst_len, "%s/%s/%s.%s", base_dir, AVATAR_DIR_NAME, | ||
181 | public_key_str, suffix); | ||
182 | dst[dst_len - 1] = '\0'; | ||
183 | |||
184 | if (n >= dst_len) | ||
185 | return -1; /* Error: Output truncated */ | ||
186 | |||
187 | return 0; /* Ok */ | ||
188 | } | ||
189 | |||
190 | |||
191 | /* Load a cached avatar into the buffer 'data' (which must be at least | ||
192 | * TOX_MAX_AVATAR_DATA_LENGTH bytes long). Gets the file name from client | ||
193 | * id and the given data format. | ||
194 | * Returns 0 on success, or -1 on error. | ||
195 | */ | ||
196 | static int load_user_avatar(Tox *tox, char *base_dir, int friendnum, | ||
197 | uint8_t format, uint8_t *hash, uint8_t *data, uint32_t *datalen) | ||
198 | { | ||
199 | uint8_t addr[TOX_PUBLIC_KEY_SIZE]; | ||
200 | |||
201 | if (tox_get_client_id(tox, friendnum, addr) != 0) { | ||
202 | DEBUG("Bad client id, friendnumber=%d", friendnum); | ||
203 | return -1; | ||
204 | } | ||
205 | |||
206 | char path[PATH_MAX]; | ||
207 | int ret = make_avatar_file_name(path, sizeof(path), base_dir, format, addr); | ||
208 | |||
209 | if (ret != 0) { | ||
210 | DEBUG("Can't create an file name for this user/avatar."); | ||
211 | return -1; | ||
212 | } | ||
213 | |||
214 | ret = load_avatar_data(path, data); | ||
215 | |||
216 | if (ret < 0) { | ||
217 | DEBUG("Failed to load avatar data."); | ||
218 | return -1; | ||
219 | } | ||
220 | |||
221 | *datalen = ret; | ||
222 | tox_hash(hash, data, *datalen); | ||
223 | |||
224 | return 0; | ||
225 | } | ||
226 | |||
227 | /* Save a user avatar into the cache. Gets the file name from the public key | ||
228 | * and the given data format. | ||
229 | * Returns 0 on success, or -1 on error. | ||
230 | */ | ||
231 | static int save_user_avatar(Tox *tox, char *base_dir, int friendnum, | ||
232 | uint8_t format, uint8_t *data, uint32_t datalen) | ||
233 | { | ||
234 | uint8_t addr[TOX_PUBLIC_KEY_SIZE]; | ||
235 | |||
236 | if (tox_get_client_id(tox, friendnum, addr) != 0) { | ||
237 | DEBUG("Bad client id, friendnumber=%d", friendnum); | ||
238 | return -1; | ||
239 | } | ||
240 | |||
241 | char path[PATH_MAX]; | ||
242 | int ret = make_avatar_file_name(path, sizeof(path), base_dir, format, addr); | ||
243 | |||
244 | if (ret != 0) { | ||
245 | DEBUG("Can't create a file name for this user/avatar"); | ||
246 | return -1; | ||
247 | } | ||
248 | |||
249 | return save_avatar_data(path, data, datalen); | ||
250 | } | ||
251 | |||
252 | /* Delete all cached avatars for a given user */ | ||
253 | static int delete_user_avatar(Tox *tox, char *base_dir, int friendnum) | ||
254 | { | ||
255 | uint8_t addr[TOX_PUBLIC_KEY_SIZE]; | ||
256 | |||
257 | if (tox_get_client_id(tox, friendnum, addr) != 0) { | ||
258 | DEBUG("Bad client id, friendnumber=%d", friendnum); | ||
259 | return -1; | ||
260 | } | ||
261 | |||
262 | char path[PATH_MAX]; | ||
263 | |||
264 | /* This iteration is dumb and inefficient */ | ||
265 | int i; | ||
266 | |||
267 | for (i = 0; avatar_formats[i].format != TOX_AVATAR_FORMAT_NONE; i++) { | ||
268 | int ret = make_avatar_file_name(path, sizeof(path), base_dir, | ||
269 | avatar_formats[i].format, addr); | ||
270 | |||
271 | if (ret != 0) { | ||
272 | DEBUG("Failed to create avatar path for friend #%d, format %d\n", | ||
273 | friendnum, avatar_formats[i].format); | ||
274 | continue; | ||
275 | } | ||
276 | |||
277 | if (unlink(path) == 0) | ||
278 | printf("Avatar file %s deleted.\n", path); | ||
279 | } | ||
280 | |||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | |||
285 | |||
286 | |||
287 | /* ------------ Protocol callbacks ------------ */ | ||
288 | |||
289 | static void friend_status_cb(Tox *tox, int n, uint8_t status, void *ud) | ||
290 | { | ||
291 | uint8_t addr[TOX_PUBLIC_KEY_SIZE]; | ||
292 | char addr_str[2 * TOX_PUBLIC_KEY_SIZE + 1]; | ||
293 | |||
294 | if (tox_get_client_id(tox, n, addr) == 0) { | ||
295 | byte_to_hex_str(addr, TOX_PUBLIC_KEY_SIZE, addr_str); | ||
296 | printf("Receiving status from %s: %u\n", addr_str, status); | ||
297 | } | ||
298 | } | ||
299 | |||
300 | static void friend_avatar_info_cb(Tox *tox, int32_t n, uint8_t format, uint8_t *hash, void *ud) | ||
301 | { | ||
302 | char *base_dir = (char *) ud; | ||
303 | uint8_t addr[TOX_PUBLIC_KEY_SIZE]; | ||
304 | char addr_str[2 * TOX_PUBLIC_KEY_SIZE + 1]; | ||
305 | char hash_str[2 * TOX_HASH_LENGTH + 1]; | ||
306 | |||
307 | if (tox_get_client_id(tox, n, addr) == 0) { | ||
308 | byte_to_hex_str(addr, TOX_PUBLIC_KEY_SIZE, addr_str); | ||
309 | printf("Receiving avatar information from %s.\n", addr_str); | ||
310 | } else { | ||
311 | DEBUG("tox_get_client_id failed"); | ||
312 | printf("Receiving avatar information from friend number %u.\n", n); | ||
313 | } | ||
314 | |||
315 | byte_to_hex_str(hash, TOX_HASH_LENGTH, hash_str); | ||
316 | DEBUG("format=%u, hash=%s", format, hash_str); | ||
317 | |||
318 | if (format == TOX_AVATAR_FORMAT_NONE) { | ||
319 | printf(" -> User do not have an avatar.\n"); | ||
320 | /* User have no avatar anymore, delete it from our cache */ | ||
321 | delete_user_avatar(tox, base_dir, n); | ||
322 | } else { | ||
323 | /* Check the hash of the currently cached user avatar | ||
324 | * WARNING: THIS IS ONLY AN EXAMPLE! | ||
325 | * | ||
326 | * Real clients should keep the hashes in memory (eg. in the object | ||
327 | * used to represent a friend in the friend list) and do not access | ||
328 | * the file system or do anything resource intensive in reply of | ||
329 | * these events. | ||
330 | */ | ||
331 | uint32_t cur_av_len; | ||
332 | uint8_t cur_av_data[TOX_AVATAR_MAX_DATA_LENGTH]; | ||
333 | uint8_t cur_av_hash[TOX_HASH_LENGTH]; | ||
334 | int ret; | ||
335 | |||
336 | ret = load_user_avatar(tox, base_dir, n, format, cur_av_hash, cur_av_data, &cur_av_len); | ||
337 | |||
338 | if (ret != 0 | ||
339 | && memcpy(cur_av_hash, hash, TOX_HASH_LENGTH) != 0) { | ||
340 | printf(" -> Cached avatar is outdated. Requesting avatar data.\n"); | ||
341 | tox_request_avatar_data(tox, n); | ||
342 | } else { | ||
343 | printf(" -> Cached avatar is still updated.\n"); | ||
344 | } | ||
345 | } | ||
346 | |||
347 | } | ||
348 | |||
349 | static void friend_avatar_data_cb(Tox *tox, int32_t n, uint8_t format, | ||
350 | uint8_t *hash, uint8_t *data, uint32_t datalen, void *ud) | ||
351 | { | ||
352 | char *base_dir = (char *) ud; | ||
353 | uint8_t addr[TOX_PUBLIC_KEY_SIZE]; | ||
354 | char addr_str[2 * TOX_PUBLIC_KEY_SIZE + 1]; | ||
355 | char hash_str[2 * TOX_HASH_LENGTH + 1]; | ||
356 | |||
357 | if (tox_get_client_id(tox, n, addr) == 0) { | ||
358 | byte_to_hex_str(addr, TOX_PUBLIC_KEY_SIZE, addr_str); | ||
359 | printf("Receiving avatar data from %s.\n", addr_str); | ||
360 | } else { | ||
361 | DEBUG("tox_get_client_id failed"); | ||
362 | printf("Receiving avatar data from friend number %u.\n", n); | ||
363 | } | ||
364 | |||
365 | byte_to_hex_str(hash, TOX_HASH_LENGTH, hash_str); | ||
366 | DEBUG("format=%u, datalen=%d, hash=%s\n", format, datalen, hash_str); | ||
367 | |||
368 | delete_user_avatar(tox, base_dir, n); | ||
369 | |||
370 | if (format != TOX_AVATAR_FORMAT_NONE) { | ||
371 | int ret = save_user_avatar(tox, base_dir, n, format, data, datalen); | ||
372 | |||
373 | if (ret == 0) | ||
374 | printf(" -> Avatar updated in the cache.\n"); | ||
375 | else | ||
376 | printf(" -> Failed to save user avatar.\n"); | ||
377 | } | ||
378 | } | ||
379 | |||
380 | |||
381 | static void friend_msg_cb(Tox *tox, int n, const uint8_t *msg, uint16_t len, void *ud) | ||
382 | { | ||
383 | const char *base_dir = (char *) ud; | ||
384 | const char *msg_str = (char *) msg; | ||
385 | uint8_t addr[TOX_PUBLIC_KEY_SIZE]; | ||
386 | char addr_str[2 * TOX_PUBLIC_KEY_SIZE + 1]; | ||
387 | |||
388 | if (tox_get_client_id(tox, n, addr) == 0) { | ||
389 | byte_to_hex_str(addr, TOX_FRIEND_ADDRESS_SIZE, addr_str); | ||
390 | printf("Receiving message from %s:\n %s\n", addr_str, msg); | ||
391 | } | ||
392 | |||
393 | /* Handle bot commands for the tests */ | ||
394 | char *reply_ptr = NULL; | ||
395 | |||
396 | if (strstr(msg_str, "!debug-on") != NULL) { | ||
397 | print_debug_msgs = true; | ||
398 | reply_ptr = "Debug enabled."; | ||
399 | } else if (strstr(msg_str, "!debug-off") != NULL) { | ||
400 | print_debug_msgs = false; | ||
401 | reply_ptr = "Debug disabled."; | ||
402 | } else if (strstr(msg_str, "!set-avatar") != NULL) { | ||
403 | set_avatar(tox, base_dir); | ||
404 | reply_ptr = "Setting image avatar"; | ||
405 | } else if (strstr(msg_str, "!remove-avatar") != NULL) { | ||
406 | int r = tox_set_avatar(tox, TOX_AVATAR_FORMAT_NONE, NULL, 0); | ||
407 | DEBUG("tox_set_avatar returned %d", r); | ||
408 | reply_ptr = "Removing avatar"; | ||
409 | } | ||
410 | |||
411 | /* Add more useful commands here: add friend, etc. */ | ||
412 | |||
413 | char reply[TOX_MAX_MESSAGE_LENGTH]; | ||
414 | int reply_len; | ||
415 | |||
416 | if (reply_ptr) | ||
417 | reply_len = snprintf(reply, sizeof(reply), "%s", reply_ptr); | ||
418 | else | ||
419 | reply_len = snprintf(reply, sizeof(reply), | ||
420 | "No command found in message: %s", msg); | ||
421 | |||
422 | reply[sizeof(reply) - 1] = '\0'; | ||
423 | printf(" -> Reply: %s\n", reply); | ||
424 | tox_send_message(tox, n, (uint8_t *) reply, reply_len); | ||
425 | } | ||
426 | |||
427 | |||
428 | static void friend_request_cb(Tox *tox, const uint8_t *public_key, | ||
429 | const uint8_t *data, uint16_t length, void *ud) | ||
430 | { | ||
431 | char addr_str[2 * TOX_PUBLIC_KEY_SIZE + 1]; | ||
432 | byte_to_hex_str(public_key, TOX_PUBLIC_KEY_SIZE, addr_str); | ||
433 | printf("Accepting friend request from %s.\n %s\n", addr_str, data); | ||
434 | tox_add_friend_norequest(tox, public_key); | ||
435 | } | ||
436 | |||
437 | |||
438 | static void set_avatar(Tox *tox, const char *base_dir) | ||
439 | { | ||
440 | uint8_t addr[TOX_FRIEND_ADDRESS_SIZE]; | ||
441 | char path[PATH_MAX]; | ||
442 | uint8_t buf[2 * TOX_AVATAR_MAX_DATA_LENGTH]; | ||
443 | |||
444 | tox_get_address(tox, addr); | ||
445 | |||
446 | int i; | ||
447 | |||
448 | for (i = 0; ; i++) { | ||
449 | if (avatar_formats[i].format == TOX_AVATAR_FORMAT_NONE) { | ||
450 | tox_set_avatar(tox, TOX_AVATAR_FORMAT_NONE, NULL, 0); | ||
451 | printf("No avatar file found, setting to NONE.\n"); | ||
452 | break; | ||
453 | } else { | ||
454 | int ret = make_avatar_file_name(path, sizeof(path), base_dir, | ||
455 | avatar_formats[i].format, addr); | ||
456 | |||
457 | if (ret < 0) { | ||
458 | printf("Failed to generate avatar file name.\n"); | ||
459 | return; | ||
460 | } | ||
461 | |||
462 | int len = load_avatar_data(path, buf); | ||
463 | |||
464 | if (len < 0) { | ||
465 | printf("Failed to load avatar data from file: %s\n", path); | ||
466 | continue; | ||
467 | } | ||
468 | |||
469 | if (len > TOX_AVATAR_MAX_DATA_LENGTH) { | ||
470 | printf("Avatar file %s is too big (more than %d bytes)", | ||
471 | path, TOX_AVATAR_MAX_DATA_LENGTH); | ||
472 | return; | ||
473 | } | ||
474 | |||
475 | ret = tox_set_avatar(tox, avatar_formats[i].format, buf, len); | ||
476 | DEBUG("tox_set_avatar returned=%d", ret); | ||
477 | |||
478 | if (ret == 0) | ||
479 | printf("Setting avatar from %s (%d bytes).\n", path, len); | ||
480 | else | ||
481 | printf("Error setting avatar from %s.\n", path); | ||
482 | |||
483 | return; | ||
484 | } | ||
485 | } | ||
486 | } | ||
487 | |||
488 | |||
489 | static void print_avatar_info(Tox *tox) | ||
490 | { | ||
491 | uint8_t format; | ||
492 | uint8_t data[TOX_AVATAR_MAX_DATA_LENGTH]; | ||
493 | uint8_t hash[TOX_HASH_LENGTH]; | ||
494 | uint32_t data_length; | ||
495 | char hash_str[2 * TOX_HASH_LENGTH + 1]; | ||
496 | |||
497 | int ret = tox_get_self_avatar(tox, &format, data, &data_length, sizeof(data), hash); | ||
498 | DEBUG("tox_get_self_avatar returned %d", ret); | ||
499 | DEBUG("format: %d, data_length: %d", format, data_length); | ||
500 | byte_to_hex_str(hash, TOX_HASH_LENGTH, hash_str); | ||
501 | DEBUG("hash: %s", hash_str); | ||
502 | } | ||
503 | |||
504 | |||
505 | /* ------------ Initialization functions ------------ */ | ||
506 | |||
507 | /* Create directory to store tha avatars. Returns 0 if it was sucessfuly | ||
508 | * created or already existed. Returns -1 on error. | ||
509 | */ | ||
510 | static int create_avatar_diretory(const char *base_dir) | ||
511 | { | ||
512 | char path[PATH_MAX]; | ||
513 | int n = snprintf(path, sizeof(path), "%s/%s", base_dir, AVATAR_DIR_NAME); | ||
514 | path[sizeof(path) - 1] = '\0'; | ||
515 | |||
516 | if (n >= sizeof(path)) | ||
517 | return -1; | ||
518 | |||
519 | if (mkdir(path, 0755) == 0) { | ||
520 | return 0; /* Done */ | ||
521 | } else if (errno == EEXIST) { | ||
522 | /* Check if the existing path is a directory */ | ||
523 | struct stat st; | ||
524 | |||
525 | if (stat(path, &st) != 0) { | ||
526 | perror("stat()ing avatar directory"); | ||
527 | return -1; | ||
528 | } | ||
529 | |||
530 | if (S_ISDIR(st.st_mode)) | ||
531 | return 0; | ||
532 | } | ||
533 | |||
534 | return -1; /* Error */ | ||
535 | } | ||
536 | |||
537 | |||
538 | static void *load_bootstrap_data(const char *base_dir, uint32_t *len) | ||
539 | { | ||
540 | char path[PATH_MAX]; | ||
541 | int n = snprintf(path, sizeof(path), "%s/%s", base_dir, DATA_FILE_NAME); | ||
542 | path[sizeof(path) - 1] = '\0'; | ||
543 | |||
544 | if (n >= sizeof(path)) { | ||
545 | printf("Load error: path %s too long\n", path); | ||
546 | return NULL; | ||
547 | } | ||
548 | |||
549 | /* We should be using POSIX functions here, but let's try to be | ||
550 | * compatible with Windows. | ||
551 | */ | ||
552 | |||
553 | FILE *fp = fopen(path, "rb"); | ||
554 | |||
555 | if (fp == NULL) { | ||
556 | printf("fatal error: file %s not found.\n", path); | ||
557 | return NULL; | ||
558 | } | ||
559 | |||
560 | if (fseek(fp, 0, SEEK_END) != 0) { | ||
561 | printf("seek fail\n"); | ||
562 | fclose(fp); | ||
563 | return NULL; | ||
564 | } | ||
565 | |||
566 | int32_t flen = ftell(fp); | ||
567 | |||
568 | if (flen < 8 || flen > 2e6) { | ||
569 | printf("Fatal error: file %s have %u bytes. Out of acceptable range.\n", path, flen); | ||
570 | fclose(fp); | ||
571 | return NULL; | ||
572 | } | ||
573 | |||
574 | if (fseek(fp, 0, SEEK_SET) != 0) { | ||
575 | printf("seek fail\n"); | ||
576 | fclose(fp); | ||
577 | return NULL; | ||
578 | } | ||
579 | |||
580 | void *buf = malloc(flen); | ||
581 | |||
582 | if (buf == NULL) { | ||
583 | printf("malloc failed, %u bytes", flen); | ||
584 | fclose(fp); | ||
585 | return NULL; | ||
586 | } | ||
587 | |||
588 | *len = fread(buf, 1, flen, fp); | ||
589 | fclose(fp); | ||
590 | |||
591 | if (*len != flen) { | ||
592 | printf("fatal: %s have %u bytes, read only %u\n", path, flen, *len); | ||
593 | free(buf); | ||
594 | return NULL; | ||
595 | } | ||
596 | |||
597 | printf("bootstrap data loaded from %s (%u bytes)\n", path, flen); | ||
598 | return buf; | ||
599 | } | ||
600 | |||
601 | static int save_bootstrap_data(Tox *tox, const char *base_dir) | ||
602 | { | ||
603 | char path[PATH_MAX]; | ||
604 | int n = snprintf(path, sizeof(path), "%s/%s", base_dir, DATA_FILE_NAME); | ||
605 | path[sizeof(path) - 1] = '\0'; | ||
606 | |||
607 | if (n >= sizeof(path)) { | ||
608 | printf("Save error: path %s too long\n", path); | ||
609 | return -1; | ||
610 | } | ||
611 | |||
612 | char path_tmp[PATH_MAX]; | ||
613 | n = snprintf(path_tmp, sizeof(path_tmp), "%s.tmp", path); | ||
614 | path_tmp[sizeof(path_tmp) - 1] = '\0'; | ||
615 | |||
616 | if (n >= sizeof(path_tmp)) { | ||
617 | printf("error: path %s too long\n", path); | ||
618 | return -1; | ||
619 | } | ||
620 | |||
621 | uint32_t len = tox_size(tox); | ||
622 | |||
623 | if (len < 8 || len > 2e6) { | ||
624 | printf("save data length == %u, out of acceptable range\n", len); | ||
625 | return -1; | ||
626 | } | ||
627 | |||
628 | void *buf = malloc(len); | ||
629 | |||
630 | if (buf == NULL) { | ||
631 | printf("save data: malloc failed\n"); | ||
632 | return -1; | ||
633 | } | ||
634 | |||
635 | tox_save(tox, buf); | ||
636 | |||
637 | FILE *fp = fopen(path_tmp, "wb"); | ||
638 | |||
639 | if (fp == NULL) { | ||
640 | printf("Error saving data: can't open %s\n", path_tmp); | ||
641 | free(buf); | ||
642 | return -1; | ||
643 | } | ||
644 | |||
645 | if (fwrite(buf, 1, len, fp) != len) { | ||
646 | printf("Error writing data to %s\n", path_tmp); | ||
647 | free(buf); | ||
648 | fclose(fp); | ||
649 | return -1; | ||
650 | } | ||
651 | |||
652 | free(buf); | ||
653 | |||
654 | if (fclose(fp) != 0) { | ||
655 | printf("Error writing data to %s\n", path_tmp); | ||
656 | return -1; | ||
657 | } | ||
658 | |||
659 | if (rename(path_tmp, path) != 0) { | ||
660 | printf("Error renaming %s to %s\n", path_tmp, path); | ||
661 | return -1; | ||
662 | } | ||
663 | |||
664 | printf("Bootstrap data saved to %s\n", path); | ||
665 | return 0; /* Done */ | ||
666 | } | ||
667 | |||
668 | |||
669 | |||
670 | |||
671 | int main(int argc, char *argv[]) | ||
672 | { | ||
673 | int ret; | ||
674 | |||
675 | if (argc != 2) { | ||
676 | printf("usage: %s <data dir>\n", argv[0]); | ||
677 | return 1; | ||
678 | } | ||
679 | |||
680 | char *base_dir = argv[1]; | ||
681 | |||
682 | if (create_avatar_diretory(base_dir) != 0) | ||
683 | printf("Error creating avatar directory.\n"); | ||
684 | |||
685 | Tox *tox = tox_new(NULL); | ||
686 | |||
687 | uint32_t len; | ||
688 | void *data = load_bootstrap_data(base_dir, &len); | ||
689 | |||
690 | if (data == NULL) | ||
691 | return 1; | ||
692 | |||
693 | ret = tox_load(tox, data, len); | ||
694 | free(data); | ||
695 | |||
696 | if (ret == 0) { | ||
697 | printf("Tox initialized\n"); | ||
698 | } else { | ||
699 | printf("Fatal: tox_load returned %d\n", ret); | ||
700 | return 1; | ||
701 | } | ||
702 | |||
703 | tox_callback_connection_status(tox, friend_status_cb, NULL); | ||
704 | tox_callback_friend_message(tox, friend_msg_cb, base_dir); | ||
705 | tox_callback_friend_request(tox, friend_request_cb, NULL); | ||
706 | tox_callback_avatar_info(tox, friend_avatar_info_cb, base_dir); | ||
707 | tox_callback_avatar_data(tox, friend_avatar_data_cb, base_dir); | ||
708 | |||
709 | uint8_t addr[TOX_FRIEND_ADDRESS_SIZE]; | ||
710 | char addr_str[2 * TOX_FRIEND_ADDRESS_SIZE + 1]; | ||
711 | tox_get_address(tox, addr); | ||
712 | byte_to_hex_str(addr, TOX_FRIEND_ADDRESS_SIZE, addr_str); | ||
713 | printf("Using local tox address: %s\n", addr_str); | ||
714 | |||
715 | #ifdef TEST_SET_RESET_AVATAR | ||
716 | printf("Printing default avatar information:\n"); | ||
717 | print_avatar_info(tox); | ||
718 | |||
719 | printf("Setting a new avatar:\n"); | ||
720 | set_avatar(tox, base_dir); | ||
721 | print_avatar_info(tox); | ||
722 | |||
723 | printf("Removing the avatar we just set:\n"); | ||
724 | tox_avatar(tox, TOX_AVATARFORMAT_NONE, NULL, 0); | ||
725 | print_avatar_info(tox); | ||
726 | |||
727 | printf("Setting that avatar again:\n"); | ||
728 | #endif /* TEST_SET_RESET_AVATAR */ | ||
729 | |||
730 | set_avatar(tox, base_dir); | ||
731 | print_avatar_info(tox); | ||
732 | |||
733 | bool waiting = true; | ||
734 | time_t last_save = time(0); | ||
735 | |||
736 | while (1) { | ||
737 | if (tox_isconnected(tox) && waiting) { | ||
738 | printf("DHT connected.\n"); | ||
739 | waiting = false; | ||
740 | } | ||
741 | |||
742 | tox_do(tox); | ||
743 | |||
744 | time_t now = time(0); | ||
745 | |||
746 | if (now - last_save > 120) { | ||
747 | save_bootstrap_data(tox, base_dir); | ||
748 | last_save = now; | ||
749 | } | ||
750 | |||
751 | usleep(500000); | ||
752 | } | ||
753 | |||
754 | return 0; | ||
755 | } | ||
diff --git a/toxav/Makefile.inc b/toxav/Makefile.inc index de8ef8ff..0b4b869d 100644 --- a/toxav/Makefile.inc +++ b/toxav/Makefile.inc | |||
@@ -8,6 +8,8 @@ libtoxav_la_SOURCES = ../toxav/rtp.h \ | |||
8 | ../toxav/rtp.c \ | 8 | ../toxav/rtp.c \ |
9 | ../toxav/msi.h \ | 9 | ../toxav/msi.h \ |
10 | ../toxav/msi.c \ | 10 | ../toxav/msi.c \ |
11 | ../toxav/group.h \ | ||
12 | ../toxav/group.c \ | ||
11 | ../toxav/codec.h \ | 13 | ../toxav/codec.h \ |
12 | ../toxav/codec.c \ | 14 | ../toxav/codec.c \ |
13 | ../toxav/toxav.h \ | 15 | ../toxav/toxav.h \ |
diff --git a/toxav/codec.c b/toxav/codec.c index 10dc4f53..de802526 100644 --- a/toxav/codec.c +++ b/toxav/codec.c | |||
@@ -27,20 +27,112 @@ | |||
27 | #endif /* HAVE_CONFIG_H */ | 27 | #endif /* HAVE_CONFIG_H */ |
28 | 28 | ||
29 | #include "../toxcore/logger.h" | 29 | #include "../toxcore/logger.h" |
30 | #include "../toxcore/util.h" | ||
30 | 31 | ||
31 | #include <stdio.h> | 32 | #include <stdio.h> |
32 | #include <stdlib.h> | 33 | #include <stdlib.h> |
33 | #include <math.h> | 34 | #include <math.h> |
34 | #include <assert.h> | 35 | #include <assert.h> |
36 | #include <time.h> | ||
35 | 37 | ||
38 | #include "msi.h" | ||
36 | #include "rtp.h" | 39 | #include "rtp.h" |
37 | #include "codec.h" | 40 | #include "codec.h" |
38 | 41 | ||
39 | JitterBuffer *create_queue(unsigned int capacity) | 42 | /* Good quality encode. */ |
43 | #define MAX_DECODE_TIME_US 0 | ||
44 | |||
45 | // TODO this has to be exchanged in msi | ||
46 | #define MAX_VIDEOFRAME_SIZE 0x40000 /* 256KiB */ | ||
47 | #define VIDEOFRAME_PIECE_SIZE 0x500 /* 1.25 KiB*/ | ||
48 | #define VIDEOFRAME_HEADER_SIZE 0x2 | ||
49 | |||
50 | /* FIXME: Might not be enough */ | ||
51 | #define VIDEO_DECODE_BUFFER_SIZE 20 | ||
52 | |||
53 | #define ARRAY(TYPE__) struct { uint16_t size; TYPE__ data[]; } | ||
54 | |||
55 | typedef ARRAY(uint8_t) Payload; | ||
56 | |||
57 | typedef struct { | ||
58 | uint16_t size; /* Max size */ | ||
59 | uint16_t start; | ||
60 | uint16_t end; | ||
61 | Payload **packets; | ||
62 | } PayloadBuffer; | ||
63 | |||
64 | static _Bool buffer_full(const PayloadBuffer *b) | ||
65 | { | ||
66 | return (b->end + 1) % b->size == b->start; | ||
67 | } | ||
68 | |||
69 | static _Bool buffer_empty(const PayloadBuffer *b) | ||
70 | { | ||
71 | return b->end == b->start; | ||
72 | } | ||
73 | |||
74 | static void buffer_write(PayloadBuffer *b, Payload *p) | ||
75 | { | ||
76 | b->packets[b->end] = p; | ||
77 | b->end = (b->end + 1) % b->size; | ||
78 | |||
79 | if (b->end == b->start) b->start = (b->start + 1) % b->size; /* full, overwrite */ | ||
80 | } | ||
81 | |||
82 | static void buffer_read(PayloadBuffer *b, Payload **p) | ||
83 | { | ||
84 | *p = b->packets[b->start]; | ||
85 | b->start = (b->start + 1) % b->size; | ||
86 | } | ||
87 | |||
88 | static void buffer_clear(PayloadBuffer *b) | ||
89 | { | ||
90 | while (!buffer_empty(b)) { | ||
91 | Payload *p; | ||
92 | buffer_read(b, &p); | ||
93 | free(p); | ||
94 | } | ||
95 | } | ||
96 | |||
97 | static PayloadBuffer *buffer_new(int size) | ||
98 | { | ||
99 | PayloadBuffer *buf = calloc(sizeof(PayloadBuffer), 1); | ||
100 | |||
101 | if (!buf) return NULL; | ||
102 | |||
103 | buf->size = size + 1; /* include empty elem */ | ||
104 | |||
105 | if (!(buf->packets = calloc(buf->size, sizeof(Payload *)))) { | ||
106 | free(buf); | ||
107 | return NULL; | ||
108 | } | ||
109 | |||
110 | return buf; | ||
111 | } | ||
112 | |||
113 | static void buffer_free(PayloadBuffer *b) | ||
114 | { | ||
115 | if (b) { | ||
116 | buffer_clear(b); | ||
117 | free(b->packets); | ||
118 | free(b); | ||
119 | } | ||
120 | } | ||
121 | |||
122 | /* JITTER BUFFER WORK */ | ||
123 | typedef struct _JitterBuffer { | ||
124 | RTPMessage **queue; | ||
125 | uint32_t size; | ||
126 | uint32_t capacity; | ||
127 | uint16_t bottom; | ||
128 | uint16_t top; | ||
129 | } JitterBuffer; | ||
130 | |||
131 | static JitterBuffer *jbuf_new(uint32_t capacity) | ||
40 | { | 132 | { |
41 | unsigned int size = 1; | 133 | unsigned int size = 1; |
42 | 134 | ||
43 | while (size <= capacity) { | 135 | while (size <= (capacity * 4)) { |
44 | size *= 2; | 136 | size *= 2; |
45 | } | 137 | } |
46 | 138 | ||
@@ -58,7 +150,7 @@ JitterBuffer *create_queue(unsigned int capacity) | |||
58 | return q; | 150 | return q; |
59 | } | 151 | } |
60 | 152 | ||
61 | static void clear_queue(JitterBuffer *q) | 153 | static void jbuf_clear(JitterBuffer *q) |
62 | { | 154 | { |
63 | for (; q->bottom != q->top; ++q->bottom) { | 155 | for (; q->bottom != q->top; ++q->bottom) { |
64 | if (q->queue[q->bottom % q->size]) { | 156 | if (q->queue[q->bottom % q->size]) { |
@@ -68,40 +160,44 @@ static void clear_queue(JitterBuffer *q) | |||
68 | } | 160 | } |
69 | } | 161 | } |
70 | 162 | ||
71 | void terminate_queue(JitterBuffer *q) | 163 | static void jbuf_free(JitterBuffer *q) |
72 | { | 164 | { |
73 | if (!q) return; | 165 | if (!q) return; |
74 | 166 | ||
75 | clear_queue(q); | 167 | jbuf_clear(q); |
76 | free(q->queue); | 168 | free(q->queue); |
77 | free(q); | 169 | free(q); |
78 | } | 170 | } |
79 | 171 | ||
80 | void queue(JitterBuffer *q, RTPMessage *pk) | 172 | static int jbuf_write(JitterBuffer *q, RTPMessage *m) |
81 | { | 173 | { |
82 | uint16_t sequnum = pk->header->sequnum; | 174 | uint16_t sequnum = m->header->sequnum; |
83 | 175 | ||
84 | unsigned int num = sequnum % q->size; | 176 | unsigned int num = sequnum % q->size; |
85 | 177 | ||
86 | if ((uint32_t)(sequnum - q->bottom) > q->size) { | 178 | if ((uint32_t)(sequnum - q->bottom) > q->size) { |
87 | clear_queue(q); | 179 | jbuf_clear(q); |
88 | q->bottom = sequnum; | 180 | q->bottom = sequnum - q->capacity; |
89 | q->queue[num] = pk; | 181 | q->queue[num] = m; |
90 | q->top = sequnum + 1; | 182 | q->top = sequnum + 1; |
91 | return; | 183 | return 0; |
92 | } | 184 | } |
93 | 185 | ||
94 | if (q->queue[num]) | 186 | if (q->queue[num]) |
95 | return; | 187 | return -1; |
96 | 188 | ||
97 | q->queue[num] = pk; | 189 | q->queue[num] = m; |
98 | 190 | ||
99 | if ((sequnum - q->bottom) >= (q->top - q->bottom)) | 191 | if ((sequnum - q->bottom) >= (q->top - q->bottom)) |
100 | q->top = sequnum + 1; | 192 | q->top = sequnum + 1; |
193 | |||
194 | return 0; | ||
101 | } | 195 | } |
102 | 196 | ||
103 | /* success is 0 when there is nothing to dequeue, 1 when there's a good packet, 2 when there's a lost packet */ | 197 | /* Success is 0 when there is nothing to dequeue, |
104 | RTPMessage *dequeue(JitterBuffer *q, int *success) | 198 | * 1 when there's a good packet, |
199 | * 2 when there's a lost packet */ | ||
200 | static RTPMessage *jbuf_read(JitterBuffer *q, int32_t *success) | ||
105 | { | 201 | { |
106 | if (q->top == q->bottom) { | 202 | if (q->top == q->bottom) { |
107 | *success = 0; | 203 | *success = 0; |
@@ -128,8 +224,7 @@ RTPMessage *dequeue(JitterBuffer *q, int *success) | |||
128 | return NULL; | 224 | return NULL; |
129 | } | 225 | } |
130 | 226 | ||
131 | 227 | static int init_video_decoder(CSSession *cs) | |
132 | int init_video_decoder(CodecState *cs) | ||
133 | { | 228 | { |
134 | int rc = vpx_codec_dec_init_ver(&cs->v_decoder, VIDEO_CODEC_DECODER_INTERFACE, NULL, 0, VPX_DECODER_ABI_VERSION); | 229 | int rc = vpx_codec_dec_init_ver(&cs->v_decoder, VIDEO_CODEC_DECODER_INTERFACE, NULL, 0, VPX_DECODER_ABI_VERSION); |
135 | 230 | ||
@@ -141,63 +236,20 @@ int init_video_decoder(CodecState *cs) | |||
141 | return 0; | 236 | return 0; |
142 | } | 237 | } |
143 | 238 | ||
144 | int init_audio_decoder(CodecState *cs, uint32_t audio_channels) | 239 | static int init_audio_decoder(CSSession *cs) |
145 | { | 240 | { |
146 | int rc; | 241 | int rc; |
147 | cs->audio_decoder = opus_decoder_create(cs->audio_sample_rate, audio_channels, &rc ); | 242 | cs->audio_decoder = opus_decoder_create(cs->audio_decoder_sample_rate, cs->audio_decoder_channels, &rc ); |
148 | 243 | ||
149 | if ( rc != OPUS_OK ) { | 244 | if ( rc != OPUS_OK ) { |
150 | LOGGER_ERROR("Error while starting audio decoder: %s", opus_strerror(rc)); | 245 | LOGGER_ERROR("Error while starting audio decoder: %s", opus_strerror(rc)); |
151 | return -1; | 246 | return -1; |
152 | } | 247 | } |
153 | 248 | ||
154 | cs->audio_decoder_channels = audio_channels; | ||
155 | return 0; | 249 | return 0; |
156 | } | 250 | } |
157 | 251 | ||
158 | int reconfigure_video_encoder_resolution(CodecState *cs, uint16_t width, uint16_t height) | 252 | static int init_video_encoder(CSSession *cs, uint16_t max_width, uint16_t max_height, uint32_t video_bitrate) |
159 | { | ||
160 | vpx_codec_enc_cfg_t cfg = *cs->v_encoder.config.enc; | ||
161 | |||
162 | if (cfg.g_w == width && cfg.g_h == height) | ||
163 | return 0; | ||
164 | |||
165 | if (width * height > cs->max_width * cs->max_height) | ||
166 | return -1; | ||
167 | |||
168 | LOGGER_DEBUG("New video resolution: %u %u", width, height); | ||
169 | cfg.g_w = width; | ||
170 | cfg.g_h = height; | ||
171 | int rc = vpx_codec_enc_config_set(&cs->v_encoder, &cfg); | ||
172 | |||
173 | if ( rc != VPX_CODEC_OK) { | ||
174 | LOGGER_ERROR("Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc)); | ||
175 | return -1; | ||
176 | } | ||
177 | |||
178 | return 0; | ||
179 | } | ||
180 | |||
181 | int reconfigure_video_encoder_bitrate(CodecState *cs, uint32_t video_bitrate) | ||
182 | { | ||
183 | vpx_codec_enc_cfg_t cfg = *cs->v_encoder.config.enc; | ||
184 | |||
185 | if (cfg.rc_target_bitrate == video_bitrate) | ||
186 | return 0; | ||
187 | |||
188 | LOGGER_DEBUG("New video bitrate: %u", video_bitrate); | ||
189 | cfg.rc_target_bitrate = video_bitrate; | ||
190 | int rc = vpx_codec_enc_config_set(&cs->v_encoder, &cfg); | ||
191 | |||
192 | if ( rc != VPX_CODEC_OK) { | ||
193 | LOGGER_ERROR("Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc)); | ||
194 | return -1; | ||
195 | } | ||
196 | |||
197 | return 0; | ||
198 | } | ||
199 | |||
200 | int init_video_encoder(CodecState *cs, uint16_t max_width, uint16_t max_height, uint32_t video_bitrate) | ||
201 | { | 253 | { |
202 | vpx_codec_enc_cfg_t cfg; | 254 | vpx_codec_enc_cfg_t cfg; |
203 | int rc = vpx_codec_enc_config_default(VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0); | 255 | int rc = vpx_codec_enc_config_default(VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0); |
@@ -214,13 +266,9 @@ int init_video_encoder(CodecState *cs, uint16_t max_width, uint16_t max_height, | |||
214 | cfg.g_error_resilient = VPX_ERROR_RESILIENT_DEFAULT | VPX_ERROR_RESILIENT_PARTITIONS; | 266 | cfg.g_error_resilient = VPX_ERROR_RESILIENT_DEFAULT | VPX_ERROR_RESILIENT_PARTITIONS; |
215 | cfg.g_lag_in_frames = 0; | 267 | cfg.g_lag_in_frames = 0; |
216 | cfg.kf_min_dist = 0; | 268 | cfg.kf_min_dist = 0; |
217 | cfg.kf_max_dist = 300; | 269 | cfg.kf_max_dist = 48; |
218 | cfg.kf_mode = VPX_KF_AUTO; | 270 | cfg.kf_mode = VPX_KF_AUTO; |
219 | 271 | ||
220 | cs->max_width = max_width; | ||
221 | cs->max_height = max_height; | ||
222 | cs->bitrate = video_bitrate; | ||
223 | |||
224 | rc = vpx_codec_enc_init_ver(&cs->v_encoder, VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0, VPX_ENCODER_ABI_VERSION); | 272 | rc = vpx_codec_enc_init_ver(&cs->v_encoder, VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0, VPX_ENCODER_ABI_VERSION); |
225 | 273 | ||
226 | if ( rc != VPX_CODEC_OK) { | 274 | if ( rc != VPX_CODEC_OK) { |
@@ -228,27 +276,32 @@ int init_video_encoder(CodecState *cs, uint16_t max_width, uint16_t max_height, | |||
228 | return -1; | 276 | return -1; |
229 | } | 277 | } |
230 | 278 | ||
231 | rc = vpx_codec_control(&cs->v_encoder, VP8E_SET_CPUUSED, 7); | 279 | rc = vpx_codec_control(&cs->v_encoder, VP8E_SET_CPUUSED, 8); |
232 | 280 | ||
233 | if ( rc != VPX_CODEC_OK) { | 281 | if ( rc != VPX_CODEC_OK) { |
234 | LOGGER_ERROR("Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc)); | 282 | LOGGER_ERROR("Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc)); |
235 | return -1; | 283 | return -1; |
236 | } | 284 | } |
237 | 285 | ||
286 | cs->max_width = max_width; | ||
287 | cs->max_height = max_height; | ||
288 | cs->video_bitrate = video_bitrate; | ||
289 | |||
238 | return 0; | 290 | return 0; |
239 | } | 291 | } |
240 | 292 | ||
241 | int init_audio_encoder(CodecState *cs, uint32_t audio_channels) | 293 | static int init_audio_encoder(CSSession *cs) |
242 | { | 294 | { |
243 | int rc = OPUS_OK; | 295 | int rc = OPUS_OK; |
244 | cs->audio_encoder = opus_encoder_create(cs->audio_sample_rate, audio_channels, OPUS_APPLICATION_AUDIO, &rc); | 296 | cs->audio_encoder = opus_encoder_create(cs->audio_encoder_sample_rate, |
297 | cs->audio_encoder_channels, OPUS_APPLICATION_AUDIO, &rc); | ||
245 | 298 | ||
246 | if ( rc != OPUS_OK ) { | 299 | if ( rc != OPUS_OK ) { |
247 | LOGGER_ERROR("Error while starting audio encoder: %s", opus_strerror(rc)); | 300 | LOGGER_ERROR("Error while starting audio encoder: %s", opus_strerror(rc)); |
248 | return -1; | 301 | return -1; |
249 | } | 302 | } |
250 | 303 | ||
251 | rc = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_BITRATE(cs->audio_bitrate)); | 304 | rc = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_BITRATE(cs->audio_encoder_bitrate)); |
252 | 305 | ||
253 | if ( rc != OPUS_OK ) { | 306 | if ( rc != OPUS_OK ) { |
254 | LOGGER_ERROR("Error while setting encoder ctl: %s", opus_strerror(rc)); | 307 | LOGGER_ERROR("Error while setting encoder ctl: %s", opus_strerror(rc)); |
@@ -262,96 +315,374 @@ int init_audio_encoder(CodecState *cs, uint32_t audio_channels) | |||
262 | return -1; | 315 | return -1; |
263 | } | 316 | } |
264 | 317 | ||
265 | cs->audio_encoder_channels = audio_channels; | ||
266 | return 0; | 318 | return 0; |
267 | } | 319 | } |
268 | 320 | ||
321 | /* PUBLIC */ | ||
322 | int cs_split_video_payload(CSSession *cs, const uint8_t *payload, uint16_t length) | ||
323 | { | ||
324 | if (!cs || !length || length > cs->max_video_frame_size) { | ||
325 | LOGGER_ERROR("Invalid CodecState or video frame size: %u", length); | ||
326 | return cs_ErrorSplittingVideoPayload; | ||
327 | } | ||
269 | 328 | ||
270 | CodecState *codec_init_session ( uint32_t audio_bitrate, | 329 | cs->split_video_frame[0] = cs->frameid_out++; |
271 | uint16_t audio_frame_duration, | 330 | cs->split_video_frame[1] = 0; |
272 | uint32_t audio_sample_rate, | 331 | cs->processing_video_frame = payload; |
273 | uint32_t encoder_audio_channels, | 332 | cs->processing_video_frame_size = length; |
274 | uint32_t decoder_audio_channels, | 333 | |
275 | uint32_t audio_VAD_tolerance_ms, | 334 | return ((length - 1) / cs->video_frame_piece_size) + 1; |
276 | uint16_t max_video_width, | 335 | } |
277 | uint16_t max_video_height, | 336 | |
278 | uint32_t video_bitrate ) | 337 | const uint8_t *cs_get_split_video_frame(CSSession *cs, uint16_t *size) |
279 | { | 338 | { |
280 | CodecState *retu = calloc(sizeof(CodecState), 1); | 339 | if (!cs || !size) return NULL; |
281 | 340 | ||
282 | if (!retu) return NULL; | 341 | if (cs->processing_video_frame_size > cs->video_frame_piece_size) { |
342 | memcpy(cs->split_video_frame + VIDEOFRAME_HEADER_SIZE, | ||
343 | cs->processing_video_frame, | ||
344 | cs->video_frame_piece_size); | ||
283 | 345 | ||
284 | retu->audio_bitrate = audio_bitrate; | 346 | cs->processing_video_frame += cs->video_frame_piece_size; |
285 | retu->audio_sample_rate = audio_sample_rate; | 347 | cs->processing_video_frame_size -= cs->video_frame_piece_size; |
286 | 348 | ||
287 | /* Encoders */ | 349 | *size = cs->video_frame_piece_size + VIDEOFRAME_HEADER_SIZE; |
288 | if (!max_video_width || !max_video_height) { /* Disable video */ | ||
289 | /*video_width = 320; | ||
290 | video_height = 240; */ | ||
291 | } else { | 350 | } else { |
292 | retu->capabilities |= ( 0 == init_video_encoder(retu, max_video_width, max_video_height, | 351 | memcpy(cs->split_video_frame + VIDEOFRAME_HEADER_SIZE, |
293 | video_bitrate) ) ? v_encoding : 0; | 352 | cs->processing_video_frame, |
294 | retu->capabilities |= ( 0 == init_video_decoder(retu) ) ? v_decoding : 0; | 353 | cs->processing_video_frame_size); |
354 | |||
355 | *size = cs->processing_video_frame_size + VIDEOFRAME_HEADER_SIZE; | ||
295 | } | 356 | } |
296 | 357 | ||
297 | retu->capabilities |= ( 0 == init_audio_encoder(retu, encoder_audio_channels) ) ? a_encoding : 0; | 358 | cs->split_video_frame[1]++; |
298 | retu->capabilities |= ( 0 == init_audio_decoder(retu, decoder_audio_channels) ) ? a_decoding : 0; | 359 | |
360 | return cs->split_video_frame; | ||
361 | } | ||
362 | |||
363 | void cs_do(CSSession *cs) | ||
364 | { | ||
365 | /* Codec session should always be protected by call mutex so no need to check for cs validity | ||
366 | */ | ||
367 | |||
368 | if (!cs) return; | ||
369 | |||
370 | Payload *p; | ||
371 | int rc; | ||
372 | |||
373 | int success = 0; | ||
374 | |||
375 | pthread_mutex_lock(cs->queue_mutex); | ||
376 | RTPMessage *msg; | ||
377 | |||
378 | while ((msg = jbuf_read(cs->j_buf, &success)) || success == 2) { | ||
379 | pthread_mutex_unlock(cs->queue_mutex); | ||
380 | |||
381 | uint16_t fsize = ((cs->audio_decoder_sample_rate * cs->audio_decoder_frame_duration) / 1000); | ||
382 | int16_t tmp[fsize * cs->audio_decoder_channels]; | ||
383 | |||
384 | if (success == 2) { | ||
385 | rc = opus_decode(cs->audio_decoder, 0, 0, tmp, fsize, 1); | ||
386 | } else { | ||
387 | rc = opus_decode(cs->audio_decoder, msg->data, msg->length, tmp, fsize, 0); | ||
388 | rtp_free_msg(NULL, msg); | ||
389 | } | ||
299 | 390 | ||
300 | if ( retu->capabilities == 0 ) { /* everything failed */ | 391 | if (rc < 0) { |
301 | free (retu); | 392 | LOGGER_WARNING("Decoding error: %s", opus_strerror(rc)); |
393 | } else if (cs->acb.first) { | ||
394 | /* Play */ | ||
395 | cs->acb.first(cs->agent, cs->call_idx, tmp, rc, cs->acb.second); | ||
396 | } | ||
397 | |||
398 | pthread_mutex_lock(cs->queue_mutex); | ||
399 | } | ||
400 | |||
401 | if (cs->vbuf_raw && !buffer_empty(cs->vbuf_raw)) { | ||
402 | /* Decode video */ | ||
403 | buffer_read(cs->vbuf_raw, &p); | ||
404 | |||
405 | /* Leave space for (possibly) other thread to queue more data after we read it here */ | ||
406 | pthread_mutex_unlock(cs->queue_mutex); | ||
407 | |||
408 | rc = vpx_codec_decode(&cs->v_decoder, p->data, p->size, NULL, MAX_DECODE_TIME_US); | ||
409 | free(p); | ||
410 | |||
411 | if (rc != VPX_CODEC_OK) { | ||
412 | LOGGER_ERROR("Error decoding video: %s", vpx_codec_err_to_string(rc)); | ||
413 | } else { | ||
414 | vpx_codec_iter_t iter = NULL; | ||
415 | vpx_image_t *dest = vpx_codec_get_frame(&cs->v_decoder, &iter); | ||
416 | |||
417 | /* Play decoded images */ | ||
418 | for (; dest; dest = vpx_codec_get_frame(&cs->v_decoder, &iter)) { | ||
419 | if (cs->vcb.first) | ||
420 | cs->vcb.first(cs->agent, cs->call_idx, dest, cs->vcb.second); | ||
421 | |||
422 | vpx_img_free(dest); | ||
423 | } | ||
424 | } | ||
425 | |||
426 | return; | ||
427 | } | ||
428 | |||
429 | pthread_mutex_unlock(cs->queue_mutex); | ||
430 | } | ||
431 | |||
432 | int cs_set_video_encoder_resolution(CSSession *cs, uint16_t width, uint16_t height) | ||
433 | { | ||
434 | vpx_codec_enc_cfg_t cfg = *cs->v_encoder.config.enc; | ||
435 | |||
436 | if (cfg.g_w == width && cfg.g_h == height) | ||
437 | return 0; | ||
438 | |||
439 | if (width * height > cs->max_width * cs->max_height) { | ||
440 | vpx_codec_ctx_t v_encoder = cs->v_encoder; | ||
441 | |||
442 | if (init_video_encoder(cs, width, height, cs->video_bitrate) == -1) { | ||
443 | cs->v_encoder = v_encoder; | ||
444 | return cs_ErrorSettingVideoResolution; | ||
445 | } | ||
446 | |||
447 | vpx_codec_destroy(&v_encoder); | ||
448 | return 0; | ||
449 | } | ||
450 | |||
451 | LOGGER_DEBUG("New video resolution: %u %u", width, height); | ||
452 | cfg.g_w = width; | ||
453 | cfg.g_h = height; | ||
454 | int rc = vpx_codec_enc_config_set(&cs->v_encoder, &cfg); | ||
455 | |||
456 | if ( rc != VPX_CODEC_OK) { | ||
457 | LOGGER_ERROR("Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc)); | ||
458 | return cs_ErrorSettingVideoResolution; | ||
459 | } | ||
460 | |||
461 | return 0; | ||
462 | } | ||
463 | |||
464 | int cs_set_video_encoder_bitrate(CSSession *cs, uint32_t video_bitrate) | ||
465 | { | ||
466 | vpx_codec_enc_cfg_t cfg = *cs->v_encoder.config.enc; | ||
467 | |||
468 | if (cfg.rc_target_bitrate == video_bitrate) | ||
469 | return 0; | ||
470 | |||
471 | LOGGER_DEBUG("New video bitrate: %u", video_bitrate); | ||
472 | cfg.rc_target_bitrate = video_bitrate; | ||
473 | int rc = vpx_codec_enc_config_set(&cs->v_encoder, &cfg); | ||
474 | |||
475 | if ( rc != VPX_CODEC_OK) { | ||
476 | LOGGER_ERROR("Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc)); | ||
477 | return cs_ErrorSettingVideoBitrate; | ||
478 | } | ||
479 | |||
480 | cs->video_bitrate = video_bitrate; | ||
481 | return 0; | ||
482 | } | ||
483 | |||
484 | CSSession *cs_new(const ToxAvCSettings *cs_self, const ToxAvCSettings *cs_peer, uint32_t jbuf_size, int has_video) | ||
485 | { | ||
486 | CSSession *cs = calloc(sizeof(CSSession), 1); | ||
487 | |||
488 | if (!cs) { | ||
489 | LOGGER_WARNING("Allocation failed! Application might misbehave!"); | ||
490 | return NULL; | ||
491 | } | ||
492 | |||
493 | if (create_recursive_mutex(cs->queue_mutex) != 0) { | ||
494 | LOGGER_WARNING("Failed to create recursive mutex!"); | ||
495 | free(cs); | ||
302 | return NULL; | 496 | return NULL; |
303 | } | 497 | } |
304 | 498 | ||
499 | if ( !(cs->j_buf = jbuf_new(jbuf_size)) ) { | ||
500 | LOGGER_WARNING("Jitter buffer creaton failed!"); | ||
501 | goto error; | ||
502 | } | ||
503 | |||
504 | cs->audio_encoder_bitrate = cs_self->audio_bitrate; | ||
505 | cs->audio_encoder_sample_rate = cs_self->audio_sample_rate; | ||
506 | cs->audio_encoder_channels = cs_self->audio_channels; | ||
507 | cs->audio_encoder_frame_duration = cs_self->audio_frame_duration; | ||
508 | |||
509 | cs->audio_decoder_bitrate = cs_peer->audio_bitrate; | ||
510 | cs->audio_decoder_sample_rate = cs_peer->audio_sample_rate; | ||
511 | cs->audio_decoder_channels = cs_peer->audio_channels; | ||
512 | cs->audio_decoder_frame_duration = cs_peer->audio_frame_duration; | ||
513 | |||
514 | |||
515 | cs->capabilities |= ( 0 == init_audio_encoder(cs) ) ? cs_AudioEncoding : 0; | ||
516 | cs->capabilities |= ( 0 == init_audio_decoder(cs) ) ? cs_AudioDecoding : 0; | ||
517 | |||
518 | if ( !(cs->capabilities & cs_AudioEncoding) || !(cs->capabilities & cs_AudioDecoding) ) goto error; | ||
519 | |||
520 | if ((cs->support_video = has_video)) { | ||
521 | cs->max_video_frame_size = MAX_VIDEOFRAME_SIZE; | ||
522 | cs->video_frame_piece_size = VIDEOFRAME_PIECE_SIZE; | ||
523 | |||
524 | cs->capabilities |= ( 0 == init_video_encoder(cs, cs_self->max_video_width, | ||
525 | cs_self->max_video_height, cs_self->video_bitrate) ) ? cs_VideoEncoding : 0; | ||
526 | cs->capabilities |= ( 0 == init_video_decoder(cs) ) ? cs_VideoDecoding : 0; | ||
527 | |||
528 | if ( !(cs->capabilities & cs_VideoEncoding) || !(cs->capabilities & cs_VideoDecoding) ) goto error; | ||
529 | |||
530 | if ( !(cs->frame_buf = calloc(cs->max_video_frame_size, 1)) ) goto error; | ||
531 | |||
532 | if ( !(cs->split_video_frame = calloc(cs->video_frame_piece_size + VIDEOFRAME_HEADER_SIZE, 1)) ) | ||
533 | goto error; | ||
534 | |||
535 | if ( !(cs->vbuf_raw = buffer_new(VIDEO_DECODE_BUFFER_SIZE)) ) goto error; | ||
536 | } | ||
537 | |||
538 | return cs; | ||
539 | |||
540 | error: | ||
541 | LOGGER_WARNING("Error initializing codec session! Application might misbehave!"); | ||
542 | |||
543 | pthread_mutex_destroy(cs->queue_mutex); | ||
544 | |||
545 | if ( cs->audio_encoder ) opus_encoder_destroy(cs->audio_encoder); | ||
546 | |||
547 | if ( cs->audio_decoder ) opus_decoder_destroy(cs->audio_decoder); | ||
548 | |||
305 | 549 | ||
306 | retu->EVAD_tolerance = audio_VAD_tolerance_ms > audio_frame_duration ? | 550 | if (has_video) { |
307 | audio_VAD_tolerance_ms / audio_frame_duration : audio_frame_duration; | 551 | if ( cs->capabilities & cs_VideoDecoding ) vpx_codec_destroy(&cs->v_decoder); |
308 | 552 | ||
309 | return retu; | 553 | if ( cs->capabilities & cs_VideoEncoding ) vpx_codec_destroy(&cs->v_encoder); |
554 | |||
555 | buffer_free(cs->vbuf_raw); | ||
556 | |||
557 | free(cs->frame_buf); | ||
558 | free(cs->split_video_frame); | ||
559 | } | ||
560 | |||
561 | jbuf_free(cs->j_buf); | ||
562 | free(cs); | ||
563 | |||
564 | return NULL; | ||
310 | } | 565 | } |
311 | 566 | ||
312 | void codec_terminate_session ( CodecState *cs ) | 567 | void cs_kill(CSSession *cs) |
313 | { | 568 | { |
314 | if (!cs) return; | 569 | if (!cs) return; |
315 | 570 | ||
571 | /* queue_message will not be called since it's unregistered before cs_kill is called */ | ||
572 | pthread_mutex_destroy(cs->queue_mutex); | ||
573 | |||
574 | |||
316 | if ( cs->audio_encoder ) | 575 | if ( cs->audio_encoder ) |
317 | opus_encoder_destroy(cs->audio_encoder); | 576 | opus_encoder_destroy(cs->audio_encoder); |
318 | 577 | ||
319 | if ( cs->audio_decoder ) | 578 | if ( cs->audio_decoder ) |
320 | opus_decoder_destroy(cs->audio_decoder); | 579 | opus_decoder_destroy(cs->audio_decoder); |
321 | 580 | ||
322 | if ( cs->capabilities & v_decoding ) | 581 | if ( cs->capabilities & cs_VideoDecoding ) |
323 | vpx_codec_destroy(&cs->v_decoder); | 582 | vpx_codec_destroy(&cs->v_decoder); |
324 | 583 | ||
325 | if ( cs->capabilities & v_encoding ) | 584 | if ( cs->capabilities & cs_VideoEncoding ) |
326 | vpx_codec_destroy(&cs->v_encoder); | 585 | vpx_codec_destroy(&cs->v_encoder); |
327 | 586 | ||
587 | jbuf_free(cs->j_buf); | ||
588 | buffer_free(cs->vbuf_raw); | ||
589 | free(cs->frame_buf); | ||
590 | free(cs->split_video_frame); | ||
591 | |||
328 | LOGGER_DEBUG("Terminated codec state: %p", cs); | 592 | LOGGER_DEBUG("Terminated codec state: %p", cs); |
329 | free(cs); | 593 | free(cs); |
330 | } | 594 | } |
331 | 595 | ||
332 | static float calculate_sum_sq (int16_t *n, uint16_t k) | ||
333 | { | ||
334 | float result = 0; | ||
335 | uint16_t i = 0; | ||
336 | 596 | ||
337 | for ( ; i < k; i ++) result += (float) (n[i] * n[i]); | ||
338 | 597 | ||
339 | return result; | ||
340 | } | ||
341 | 598 | ||
342 | int energy_VAD(CodecState *cs, int16_t *PCM, uint16_t frame_size, float energy) | 599 | /* Called from RTP */ |
600 | void queue_message(RTPSession *session, RTPMessage *msg) | ||
343 | { | 601 | { |
344 | float frame_energy = sqrt(calculate_sum_sq(PCM, frame_size)) / frame_size; | 602 | /* This function is unregistered during call termination befor destroing |
603 | * Codec session so no need to check for validity of cs | ||
604 | */ | ||
605 | CSSession *cs = session->cs; | ||
345 | 606 | ||
346 | if ( frame_energy > energy) { | 607 | if (!cs) return; |
347 | cs->EVAD_tolerance_cr = cs->EVAD_tolerance; /* Reset counter */ | ||
348 | return 1; | ||
349 | } | ||
350 | 608 | ||
351 | if ( cs->EVAD_tolerance_cr ) { | 609 | /* Audio */ |
352 | cs->EVAD_tolerance_cr --; | 610 | if (session->payload_type == msi_TypeAudio % 128) { |
353 | return 1; | 611 | pthread_mutex_lock(cs->queue_mutex); |
612 | int ret = jbuf_write(cs->j_buf, msg); | ||
613 | pthread_mutex_unlock(cs->queue_mutex); | ||
614 | |||
615 | if (ret == -1) { | ||
616 | rtp_free_msg(NULL, msg); | ||
617 | } | ||
354 | } | 618 | } |
619 | /* Video */ | ||
620 | else { | ||
621 | uint8_t *packet = msg->data; | ||
622 | uint32_t packet_size = msg->length; | ||
623 | |||
624 | if (packet_size < VIDEOFRAME_HEADER_SIZE) | ||
625 | goto end; | ||
626 | |||
627 | uint8_t diff = packet[0] - cs->frameid_in; | ||
628 | |||
629 | if (diff != 0) { | ||
630 | if (diff < 225) { /* New frame */ | ||
631 | /* Flush last frames' data and get ready for this frame */ | ||
632 | Payload *p = malloc(sizeof(Payload) + cs->frame_size); | ||
633 | |||
634 | if (p) { | ||
635 | pthread_mutex_lock(cs->queue_mutex); | ||
636 | |||
637 | if (buffer_full(cs->vbuf_raw)) { | ||
638 | LOGGER_DEBUG("Dropped video frame"); | ||
639 | Payload *tp; | ||
640 | buffer_read(cs->vbuf_raw, &tp); | ||
641 | free(tp); | ||
642 | } else { | ||
643 | p->size = cs->frame_size; | ||
644 | memcpy(p->data, cs->frame_buf, cs->frame_size); | ||
645 | } | ||
646 | |||
647 | buffer_write(cs->vbuf_raw, p); | ||
648 | pthread_mutex_unlock(cs->queue_mutex); | ||
649 | } else { | ||
650 | LOGGER_WARNING("Allocation failed! Program might misbehave!"); | ||
651 | goto end; | ||
652 | } | ||
653 | |||
654 | cs->last_timestamp = msg->header->timestamp; | ||
655 | cs->frameid_in = packet[0]; | ||
656 | memset(cs->frame_buf, 0, cs->frame_size); | ||
657 | cs->frame_size = 0; | ||
658 | |||
659 | } else { /* Old frame; drop */ | ||
660 | LOGGER_DEBUG("Old packet: %u", packet[0]); | ||
661 | goto end; | ||
662 | } | ||
663 | } | ||
355 | 664 | ||
356 | return 0; | 665 | uint8_t piece_number = packet[1]; |
666 | |||
667 | uint32_t length_before_piece = ((piece_number - 1) * cs->video_frame_piece_size); | ||
668 | uint32_t framebuf_new_length = length_before_piece + (packet_size - VIDEOFRAME_HEADER_SIZE); | ||
669 | |||
670 | if (framebuf_new_length > cs->max_video_frame_size) { | ||
671 | goto end; | ||
672 | } | ||
673 | |||
674 | /* Otherwise it's part of the frame so just process */ | ||
675 | /* LOGGER_DEBUG("Video Packet: %u %u", packet[0], packet[1]); */ | ||
676 | |||
677 | memcpy(cs->frame_buf + length_before_piece, | ||
678 | packet + VIDEOFRAME_HEADER_SIZE, | ||
679 | packet_size - VIDEOFRAME_HEADER_SIZE); | ||
680 | |||
681 | if (framebuf_new_length > cs->frame_size) { | ||
682 | cs->frame_size = framebuf_new_length; | ||
683 | } | ||
684 | |||
685 | end: | ||
686 | rtp_free_msg(NULL, msg); | ||
687 | } | ||
357 | } | 688 | } |
diff --git a/toxav/codec.h b/toxav/codec.h index db4fbea0..6018e5df 100644 --- a/toxav/codec.h +++ b/toxav/codec.h | |||
@@ -24,6 +24,9 @@ | |||
24 | #ifndef _CODEC_H_ | 24 | #ifndef _CODEC_H_ |
25 | #define _CODEC_H_ | 25 | #define _CODEC_H_ |
26 | 26 | ||
27 | #include "toxav.h" | ||
28 | #include "rtp.h" | ||
29 | |||
27 | #include <stdio.h> | 30 | #include <stdio.h> |
28 | #include <math.h> | 31 | #include <math.h> |
29 | #include <pthread.h> | 32 | #include <pthread.h> |
@@ -32,23 +35,47 @@ | |||
32 | #include <vpx/vpx_encoder.h> | 35 | #include <vpx/vpx_encoder.h> |
33 | #include <vpx/vp8dx.h> | 36 | #include <vpx/vp8dx.h> |
34 | #include <vpx/vp8cx.h> | 37 | #include <vpx/vp8cx.h> |
38 | #include <vpx/vpx_image.h> | ||
35 | #define VIDEO_CODEC_DECODER_INTERFACE (vpx_codec_vp8_dx()) | 39 | #define VIDEO_CODEC_DECODER_INTERFACE (vpx_codec_vp8_dx()) |
36 | #define VIDEO_CODEC_ENCODER_INTERFACE (vpx_codec_vp8_cx()) | 40 | #define VIDEO_CODEC_ENCODER_INTERFACE (vpx_codec_vp8_cx()) |
37 | 41 | ||
38 | /* Audio encoding/decoding */ | 42 | /* Audio encoding/decoding */ |
39 | #include <opus.h> | 43 | #include <opus.h> |
40 | 44 | ||
41 | typedef enum _Capabilities { | 45 | #define PAIR(TYPE1__, TYPE2__) struct { TYPE1__ first; TYPE2__ second; } |
42 | none, | 46 | |
43 | a_encoding = 1 << 0, | 47 | typedef void (*CSAudioCallback) (void *agent, int32_t call_idx, const int16_t *PCM, uint16_t size, void *data); |
44 | a_decoding = 1 << 1, | 48 | typedef void (*CSVideoCallback) (void *agent, int32_t call_idx, const vpx_image_t *img, void *data); |
45 | v_encoding = 1 << 2, | ||
46 | v_decoding = 1 << 3 | ||
47 | } Capabilities; | ||
48 | 49 | ||
49 | extern const uint16_t min_jbuf_size; | 50 | /** |
51 | * Codec capabilities | ||
52 | */ | ||
53 | typedef enum { | ||
54 | cs_AudioEncoding = 1 << 0, | ||
55 | cs_AudioDecoding = 1 << 1, | ||
56 | cs_VideoEncoding = 1 << 2, | ||
57 | cs_VideoDecoding = 1 << 3 | ||
58 | } CSCapabilities; | ||
59 | |||
60 | /** | ||
61 | * Codec errors. | ||
62 | */ | ||
63 | typedef enum { | ||
64 | cs_ErrorSettingVideoResolution = -30, | ||
65 | cs_ErrorSettingVideoBitrate = -31, | ||
66 | cs_ErrorSplittingVideoPayload = -32, | ||
67 | } CSError; | ||
68 | |||
69 | /** | ||
70 | * Codec session - controling codec | ||
71 | */ | ||
72 | typedef struct _CSSession { | ||
50 | 73 | ||
51 | typedef struct _CodecState { | 74 | /* VIDEO |
75 | * | ||
76 | * | ||
77 | */ | ||
78 | int support_video; | ||
52 | 79 | ||
53 | /* video encoding */ | 80 | /* video encoding */ |
54 | vpx_codec_ctx_t v_encoder; | 81 | vpx_codec_ctx_t v_encoder; |
@@ -56,61 +83,94 @@ typedef struct _CodecState { | |||
56 | 83 | ||
57 | /* video decoding */ | 84 | /* video decoding */ |
58 | vpx_codec_ctx_t v_decoder; | 85 | vpx_codec_ctx_t v_decoder; |
59 | int bitrate; | ||
60 | int max_width; | 86 | int max_width; |
61 | int max_height; | 87 | int max_height; |
88 | unsigned int video_bitrate; | ||
89 | |||
90 | |||
91 | /* Data handling */ | ||
92 | uint8_t *frame_buf; /* buffer for split video payloads */ | ||
93 | uint32_t frame_size; /* largest address written to in frame_buf for current input frame*/ | ||
94 | uint8_t frameid_in, frameid_out; /* id of input and output video frame */ | ||
95 | uint32_t last_timestamp; /* calculating cycles */ | ||
96 | |||
97 | /* Limits */ | ||
98 | uint32_t video_frame_piece_size; | ||
99 | uint32_t max_video_frame_size; | ||
100 | |||
101 | /* Reassembling */ | ||
102 | uint8_t *split_video_frame; | ||
103 | const uint8_t *processing_video_frame; | ||
104 | uint16_t processing_video_frame_size; | ||
105 | |||
106 | |||
107 | |||
108 | /* AUDIO | ||
109 | * | ||
110 | * | ||
111 | */ | ||
62 | 112 | ||
63 | /* audio encoding */ | 113 | /* audio encoding */ |
64 | OpusEncoder *audio_encoder; | 114 | OpusEncoder *audio_encoder; |
65 | int audio_bitrate; | 115 | int audio_encoder_bitrate; |
66 | int audio_sample_rate; | 116 | int audio_encoder_sample_rate; |
117 | int audio_encoder_frame_duration; | ||
67 | int audio_encoder_channels; | 118 | int audio_encoder_channels; |
68 | 119 | ||
69 | /* audio decoding */ | 120 | /* audio decoding */ |
70 | OpusDecoder *audio_decoder; | 121 | OpusDecoder *audio_decoder; |
122 | int audio_decoder_bitrate; | ||
123 | int audio_decoder_sample_rate; | ||
124 | int audio_decoder_frame_duration; | ||
71 | int audio_decoder_channels; | 125 | int audio_decoder_channels; |
72 | 126 | ||
73 | uint64_t capabilities; /* supports*/ | 127 | struct _JitterBuffer *j_buf; |
128 | |||
74 | 129 | ||
75 | /* Voice activity detection */ | 130 | /* Voice activity detection */ |
76 | uint32_t EVAD_tolerance; /* In frames */ | 131 | uint32_t EVAD_tolerance; /* In frames */ |
77 | uint32_t EVAD_tolerance_cr; | 132 | uint32_t EVAD_tolerance_cr; |
78 | } CodecState; | ||
79 | 133 | ||
80 | 134 | ||
81 | typedef struct _JitterBuffer { | ||
82 | RTPMessage **queue; | ||
83 | uint32_t size; | ||
84 | uint32_t capacity; | ||
85 | uint16_t bottom; | ||
86 | uint16_t top; | ||
87 | } JitterBuffer; | ||
88 | 135 | ||
89 | JitterBuffer *create_queue(unsigned int capacity); | 136 | /* OTHER |
90 | void terminate_queue(JitterBuffer *q); | 137 | * |
91 | void queue(JitterBuffer *q, RTPMessage *pk); | 138 | * |
92 | RTPMessage *dequeue(JitterBuffer *q, int *success); | 139 | */ |
140 | |||
141 | uint64_t capabilities; /* supports*/ | ||
142 | |||
143 | /* Callbacks */ | ||
144 | PAIR(CSAudioCallback, void *) acb; | ||
145 | PAIR(CSVideoCallback, void *) vcb; | ||
146 | |||
147 | /* Buffering */ | ||
148 | void *vbuf_raw; /* Un-decoded data */ | ||
149 | pthread_mutex_t queue_mutex[1]; | ||
150 | |||
151 | void *agent; /* Pointer to ToxAv */ | ||
152 | int32_t call_idx; | ||
153 | } CSSession; | ||
93 | 154 | ||
155 | /* Make sure to be called BEFORE corresponding rtp_new */ | ||
156 | CSSession *cs_new(const ToxAvCSettings *cs_self, const ToxAvCSettings *cs_peer, uint32_t jbuf_size, int has_video); | ||
157 | /* Make sure to be called AFTER corresponding rtp_kill */ | ||
158 | void cs_kill(CSSession *cs); | ||
94 | 159 | ||
95 | CodecState *codec_init_session ( uint32_t audio_bitrate, | 160 | int cs_split_video_payload(CSSession *cs, const uint8_t *payload, uint16_t length); |
96 | uint16_t audio_frame_duration, | 161 | const uint8_t *cs_get_split_video_frame(CSSession *cs, uint16_t *size); |
97 | uint32_t audio_sample_rate, | 162 | |
98 | uint32_t encoder_audio_channels, | 163 | /** |
99 | uint32_t decoder_audio_channels, | 164 | * Call playback callbacks |
100 | uint32_t audio_VAD_tolerance_ms, | 165 | */ |
101 | uint16_t max_video_width, | 166 | void cs_do(CSSession *cs); |
102 | uint16_t max_video_height, | ||
103 | uint32_t video_bitrate ); | ||
104 | 167 | ||
105 | void codec_terminate_session(CodecState *cs); | ||
106 | 168 | ||
107 | /* Reconfigure video encoder | 169 | /* Reconfigure video encoder; return 0 on success or -1 on failure. */ |
108 | return 0 on success. | 170 | int cs_set_video_encoder_resolution(CSSession *cs, uint16_t width, uint16_t height); |
109 | return -1 on failure. */ | 171 | int cs_set_video_encoder_bitrate(CSSession *cs, uint32_t video_bitrate); |
110 | int reconfigure_video_encoder_resolution(CodecState *cs, uint16_t width, uint16_t height); | ||
111 | int reconfigure_video_encoder_bitrate(CodecState *cs, uint32_t video_bitrate); | ||
112 | 172 | ||
113 | /* Calculate energy and return 1 if has voice, 0 if not */ | ||
114 | int energy_VAD(CodecState *cs, int16_t *PCM, uint16_t frame_size, float energy); | ||
115 | 173 | ||
174 | /* Internal. Called from rtp_handle_message */ | ||
175 | void queue_message(RTPSession *session, RTPMessage *msg); | ||
116 | #endif /* _CODEC_H_ */ | 176 | #endif /* _CODEC_H_ */ |
diff --git a/toxav/group.c b/toxav/group.c new file mode 100644 index 00000000..3c09878a --- /dev/null +++ b/toxav/group.c | |||
@@ -0,0 +1,525 @@ | |||
1 | /** groupav.h | ||
2 | * | ||
3 | * Copyright (C) 2014 Tox project All Rights Reserved. | ||
4 | * | ||
5 | * This file is part of Tox. | ||
6 | * | ||
7 | * Tox is free software: you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation, either version 3 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * Tox is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with Tox. If not, see <http://www.gnu.org/licenses/>. | ||
19 | */ | ||
20 | |||
21 | #ifdef HAVE_CONFIG_H | ||
22 | #include "config.h" | ||
23 | #endif | ||
24 | |||
25 | #include "group.h" | ||
26 | #include "../toxcore/logger.h" | ||
27 | |||
28 | #define GROUP_JBUF_SIZE 6 | ||
29 | |||
30 | typedef struct { | ||
31 | uint16_t sequnum; | ||
32 | uint16_t length; | ||
33 | uint8_t data[]; | ||
34 | } Group_Audio_Packet; | ||
35 | |||
36 | typedef struct { | ||
37 | Group_Audio_Packet **queue; | ||
38 | uint32_t size; | ||
39 | uint32_t capacity; | ||
40 | uint16_t bottom; | ||
41 | uint16_t top; | ||
42 | } Group_JitterBuffer; | ||
43 | |||
44 | static Group_JitterBuffer *create_queue(unsigned int capacity) | ||
45 | { | ||
46 | unsigned int size = 1; | ||
47 | |||
48 | while (size <= capacity) { | ||
49 | size *= 2; | ||
50 | } | ||
51 | |||
52 | Group_JitterBuffer *q; | ||
53 | |||
54 | if ( !(q = calloc(sizeof(Group_JitterBuffer), 1)) ) return NULL; | ||
55 | |||
56 | if (!(q->queue = calloc(sizeof(Group_Audio_Packet *), size))) { | ||
57 | free(q); | ||
58 | return NULL; | ||
59 | } | ||
60 | |||
61 | q->size = size; | ||
62 | q->capacity = capacity; | ||
63 | return q; | ||
64 | } | ||
65 | |||
66 | static void clear_queue(Group_JitterBuffer *q) | ||
67 | { | ||
68 | for (; q->bottom != q->top; ++q->bottom) { | ||
69 | if (q->queue[q->bottom % q->size]) { | ||
70 | free(q->queue[q->bottom % q->size]); | ||
71 | q->queue[q->bottom % q->size] = NULL; | ||
72 | } | ||
73 | } | ||
74 | } | ||
75 | |||
76 | static void terminate_queue(Group_JitterBuffer *q) | ||
77 | { | ||
78 | if (!q) return; | ||
79 | |||
80 | clear_queue(q); | ||
81 | free(q->queue); | ||
82 | free(q); | ||
83 | } | ||
84 | |||
85 | /* Return 0 if packet was queued, -1 if it wasn't. | ||
86 | */ | ||
87 | static int queue(Group_JitterBuffer *q, Group_Audio_Packet *pk) | ||
88 | { | ||
89 | uint16_t sequnum = pk->sequnum; | ||
90 | |||
91 | unsigned int num = sequnum % q->size; | ||
92 | |||
93 | if ((uint32_t)(sequnum - q->bottom) > q->size) { | ||
94 | clear_queue(q); | ||
95 | q->bottom = sequnum - q->capacity; | ||
96 | q->queue[num] = pk; | ||
97 | q->top = sequnum + 1; | ||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | if (q->queue[num]) | ||
102 | return -1; | ||
103 | |||
104 | q->queue[num] = pk; | ||
105 | |||
106 | if ((sequnum - q->bottom) >= (q->top - q->bottom)) | ||
107 | q->top = sequnum + 1; | ||
108 | |||
109 | return 0; | ||
110 | } | ||
111 | |||
112 | /* success is 0 when there is nothing to dequeue, 1 when there's a good packet, 2 when there's a lost packet */ | ||
113 | static Group_Audio_Packet *dequeue(Group_JitterBuffer *q, int *success) | ||
114 | { | ||
115 | if (q->top == q->bottom) { | ||
116 | *success = 0; | ||
117 | return NULL; | ||
118 | } | ||
119 | |||
120 | unsigned int num = q->bottom % q->size; | ||
121 | |||
122 | if (q->queue[num]) { | ||
123 | Group_Audio_Packet *ret = q->queue[num]; | ||
124 | q->queue[num] = NULL; | ||
125 | ++q->bottom; | ||
126 | *success = 1; | ||
127 | return ret; | ||
128 | } | ||
129 | |||
130 | if ((uint32_t)(q->top - q->bottom) > q->capacity) { | ||
131 | ++q->bottom; | ||
132 | *success = 2; | ||
133 | return NULL; | ||
134 | } | ||
135 | |||
136 | *success = 0; | ||
137 | return NULL; | ||
138 | } | ||
139 | |||
140 | typedef struct { | ||
141 | Group_Chats *g_c; | ||
142 | OpusEncoder *audio_encoder; | ||
143 | |||
144 | unsigned int audio_channels, audio_sample_rate, audio_bitrate; | ||
145 | |||
146 | uint16_t audio_sequnum; | ||
147 | |||
148 | void (*audio_data)(Messenger *m, int groupnumber, int peernumber, const int16_t *pcm, unsigned int samples, | ||
149 | uint8_t channels, unsigned int sample_rate, void *userdata); | ||
150 | void *userdata; | ||
151 | } Group_AV; | ||
152 | |||
153 | typedef struct { | ||
154 | Group_JitterBuffer *buffer; | ||
155 | |||
156 | OpusDecoder *audio_decoder; | ||
157 | int decoder_channels; | ||
158 | unsigned int last_packet_samples; | ||
159 | } Group_Peer_AV; | ||
160 | |||
161 | static void kill_group_av(Group_AV *group_av) | ||
162 | { | ||
163 | if (group_av->audio_encoder) { | ||
164 | opus_encoder_destroy(group_av->audio_encoder); | ||
165 | } | ||
166 | |||
167 | free(group_av); | ||
168 | } | ||
169 | |||
170 | static int recreate_encoder(Group_AV *group_av) | ||
171 | { | ||
172 | if (group_av->audio_encoder) { | ||
173 | opus_encoder_destroy(group_av->audio_encoder); | ||
174 | group_av->audio_encoder = NULL; | ||
175 | } | ||
176 | |||
177 | int rc = OPUS_OK; | ||
178 | group_av->audio_encoder = opus_encoder_create(group_av->audio_sample_rate, group_av->audio_channels, | ||
179 | OPUS_APPLICATION_AUDIO, &rc); | ||
180 | |||
181 | if ( rc != OPUS_OK ) { | ||
182 | LOGGER_ERROR("Error while starting audio encoder: %s", opus_strerror(rc)); | ||
183 | group_av->audio_encoder = NULL; | ||
184 | return -1; | ||
185 | } | ||
186 | |||
187 | rc = opus_encoder_ctl(group_av->audio_encoder, OPUS_SET_BITRATE(group_av->audio_bitrate)); | ||
188 | |||
189 | if ( rc != OPUS_OK ) { | ||
190 | LOGGER_ERROR("Error while setting encoder ctl: %s", opus_strerror(rc)); | ||
191 | opus_encoder_destroy(group_av->audio_encoder); | ||
192 | group_av->audio_encoder = NULL; | ||
193 | return -1; | ||
194 | } | ||
195 | |||
196 | rc = opus_encoder_ctl(group_av->audio_encoder, OPUS_SET_COMPLEXITY(10)); | ||
197 | |||
198 | if ( rc != OPUS_OK ) { | ||
199 | LOGGER_ERROR("Error while setting encoder ctl: %s", opus_strerror(rc)); | ||
200 | opus_encoder_destroy(group_av->audio_encoder); | ||
201 | group_av->audio_encoder = NULL; | ||
202 | return -1; | ||
203 | } | ||
204 | |||
205 | return 0; | ||
206 | } | ||
207 | |||
208 | static Group_AV *new_group_av(Group_Chats *g_c, void (*audio_callback)(Messenger *, int, int, const int16_t *, | ||
209 | unsigned int, uint8_t, unsigned int, void *), void *userdata) | ||
210 | { | ||
211 | if (!g_c) | ||
212 | return NULL; | ||
213 | |||
214 | Group_AV *group_av = calloc(1, sizeof(Group_AV)); | ||
215 | |||
216 | if (!group_av) | ||
217 | return NULL; | ||
218 | |||
219 | group_av->g_c = g_c; | ||
220 | |||
221 | group_av->audio_data = audio_callback; | ||
222 | group_av->userdata = userdata; | ||
223 | |||
224 | return group_av; | ||
225 | } | ||
226 | |||
227 | static void group_av_peer_new(void *object, int groupnumber, int friendgroupnumber) | ||
228 | { | ||
229 | Group_AV *group_av = object; | ||
230 | Group_Peer_AV *peer_av = calloc(1, sizeof(Group_Peer_AV)); | ||
231 | |||
232 | if (!peer_av) | ||
233 | return; | ||
234 | |||
235 | peer_av->buffer = create_queue(GROUP_JBUF_SIZE); | ||
236 | group_peer_set_object(group_av->g_c, groupnumber, friendgroupnumber, peer_av); | ||
237 | } | ||
238 | |||
239 | static void group_av_peer_delete(void *object, int groupnumber, int friendgroupnumber, void *peer_object) | ||
240 | { | ||
241 | Group_Peer_AV *peer_av = peer_object; | ||
242 | |||
243 | if (!peer_av) | ||
244 | return; | ||
245 | |||
246 | if (peer_av->audio_decoder) | ||
247 | opus_decoder_destroy(peer_av->audio_decoder); | ||
248 | |||
249 | terminate_queue(peer_av->buffer); | ||
250 | free(peer_object); | ||
251 | } | ||
252 | |||
253 | static void group_av_groupchat_delete(void *object, int groupnumber) | ||
254 | { | ||
255 | if (object) | ||
256 | kill_group_av(object); | ||
257 | } | ||
258 | |||
259 | static int decode_audio_packet(Group_AV *group_av, Group_Peer_AV *peer_av, int groupnumber, int friendgroupnumber) | ||
260 | { | ||
261 | if (!group_av || !peer_av) | ||
262 | return -1; | ||
263 | |||
264 | int success; | ||
265 | Group_Audio_Packet *pk = dequeue(peer_av->buffer, &success); | ||
266 | |||
267 | if (success == 0) | ||
268 | return -1; | ||
269 | |||
270 | int16_t *out_audio = NULL; | ||
271 | int out_audio_samples = 0; | ||
272 | |||
273 | unsigned int sample_rate = 48000; | ||
274 | |||
275 | if (success == 1) { | ||
276 | int channels = opus_packet_get_nb_channels(pk->data); | ||
277 | |||
278 | if (channels == OPUS_INVALID_PACKET) { | ||
279 | free(pk); | ||
280 | return -1; | ||
281 | } | ||
282 | |||
283 | if (channels != 1 && channels != 2) { | ||
284 | free(pk); | ||
285 | return -1; | ||
286 | } | ||
287 | |||
288 | if (channels != peer_av->decoder_channels) { | ||
289 | if (peer_av->audio_decoder) { | ||
290 | opus_decoder_destroy(peer_av->audio_decoder); | ||
291 | peer_av->audio_decoder = NULL; | ||
292 | } | ||
293 | |||
294 | int rc; | ||
295 | peer_av->audio_decoder = opus_decoder_create(sample_rate, channels, &rc); | ||
296 | |||
297 | if ( rc != OPUS_OK ) { | ||
298 | LOGGER_ERROR("Error while starting audio decoder: %s", opus_strerror(rc)); | ||
299 | free(pk); | ||
300 | return -1; | ||
301 | } | ||
302 | |||
303 | peer_av->decoder_channels = channels; | ||
304 | } | ||
305 | |||
306 | int num_samples = opus_decoder_get_nb_samples(peer_av->audio_decoder, pk->data, pk->length); | ||
307 | |||
308 | out_audio = malloc(num_samples * peer_av->decoder_channels * sizeof(int16_t)); | ||
309 | |||
310 | if (!out_audio) { | ||
311 | free(pk); | ||
312 | return -1; | ||
313 | } | ||
314 | |||
315 | out_audio_samples = opus_decode(peer_av->audio_decoder, pk->data, pk->length, out_audio, num_samples, 0); | ||
316 | free(pk); | ||
317 | |||
318 | if (out_audio_samples <= 0) | ||
319 | return -1; | ||
320 | |||
321 | peer_av->last_packet_samples = out_audio_samples; | ||
322 | } else { | ||
323 | if (!peer_av->audio_decoder) | ||
324 | return -1; | ||
325 | |||
326 | if (!peer_av->last_packet_samples) | ||
327 | return -1; | ||
328 | |||
329 | out_audio = malloc(peer_av->last_packet_samples * peer_av->decoder_channels * sizeof(int16_t)); | ||
330 | |||
331 | if (!out_audio) { | ||
332 | free(pk); | ||
333 | return -1; | ||
334 | } | ||
335 | |||
336 | out_audio_samples = opus_decode(peer_av->audio_decoder, NULL, 0, out_audio, peer_av->last_packet_samples, 1); | ||
337 | |||
338 | if (out_audio_samples <= 0) | ||
339 | return -1; | ||
340 | |||
341 | } | ||
342 | |||
343 | if (out_audio) { | ||
344 | |||
345 | if (group_av->audio_data) | ||
346 | group_av->audio_data(group_av->g_c->m, groupnumber, friendgroupnumber, out_audio, out_audio_samples, | ||
347 | peer_av->decoder_channels, sample_rate, group_av->userdata); | ||
348 | |||
349 | free(out_audio); | ||
350 | return 0; | ||
351 | } | ||
352 | |||
353 | return -1; | ||
354 | } | ||
355 | |||
356 | static int handle_group_audio_packet(void *object, int groupnumber, int friendgroupnumber, void *peer_object, | ||
357 | const uint8_t *packet, uint16_t length) | ||
358 | { | ||
359 | if (!peer_object || !object || length <= sizeof(uint16_t)) { | ||
360 | return -1; | ||
361 | } | ||
362 | |||
363 | Group_Peer_AV *peer_av = peer_object; | ||
364 | |||
365 | Group_Audio_Packet *pk = calloc(1, sizeof(Group_Audio_Packet) + (length - sizeof(uint16_t))); | ||
366 | |||
367 | if (!pk) { | ||
368 | return -1; | ||
369 | } | ||
370 | |||
371 | uint16_t sequnum; | ||
372 | memcpy(&sequnum, packet, sizeof(sequnum)); | ||
373 | pk->sequnum = ntohs(sequnum); | ||
374 | pk->length = length - sizeof(uint16_t); | ||
375 | memcpy(pk->data, packet + sizeof(uint16_t), length - sizeof(uint16_t)); | ||
376 | |||
377 | if (queue(peer_av->buffer, pk) == -1) { | ||
378 | free(pk); | ||
379 | return -1; | ||
380 | } | ||
381 | |||
382 | while (decode_audio_packet(object, peer_av, groupnumber, friendgroupnumber) == 0); | ||
383 | |||
384 | return 0; | ||
385 | } | ||
386 | |||
387 | /* Convert groupchat to an A/V groupchat. | ||
388 | * | ||
389 | * return 0 on success. | ||
390 | * return -1 on failure. | ||
391 | */ | ||
392 | static int groupchat_enable_av(Group_Chats *g_c, int groupnumber, void (*audio_callback)(Messenger *, int, int, | ||
393 | const int16_t *, unsigned int, uint8_t, unsigned int, void *), void *userdata) | ||
394 | { | ||
395 | if (groupnumber == -1) | ||
396 | return -1; | ||
397 | |||
398 | Group_AV *group_av = new_group_av(g_c, audio_callback, userdata); | ||
399 | |||
400 | if (group_av == NULL) | ||
401 | return -1; | ||
402 | |||
403 | if (group_set_object(g_c, groupnumber, group_av) == -1 | ||
404 | || callback_groupchat_peer_new(g_c, groupnumber, group_av_peer_new) == -1 | ||
405 | || callback_groupchat_peer_delete(g_c, groupnumber, group_av_peer_delete) == -1 | ||
406 | || callback_groupchat_delete(g_c, groupnumber, group_av_groupchat_delete) == -1) { | ||
407 | kill_group_av(group_av); | ||
408 | return -1; | ||
409 | } | ||
410 | |||
411 | group_lossy_packet_registerhandler(g_c, GROUP_AUDIO_PACKET_ID, &handle_group_audio_packet); | ||
412 | return 0; | ||
413 | } | ||
414 | |||
415 | /* Create a new toxav group. | ||
416 | * | ||
417 | * return group number on success. | ||
418 | * return -1 on failure. | ||
419 | */ | ||
420 | int add_av_groupchat(Group_Chats *g_c, void (*audio_callback)(Messenger *, int, int, const int16_t *, unsigned int, | ||
421 | uint8_t, unsigned int, void *), void *userdata) | ||
422 | { | ||
423 | int groupnumber = add_groupchat(g_c, GROUPCHAT_TYPE_AV); | ||
424 | |||
425 | if (groupnumber == -1) { | ||
426 | return -1; | ||
427 | } | ||
428 | |||
429 | if (groupchat_enable_av(g_c, groupnumber, audio_callback, userdata) == -1) { | ||
430 | del_groupchat(g_c, groupnumber); | ||
431 | return -1; | ||
432 | } | ||
433 | |||
434 | return groupnumber; | ||
435 | } | ||
436 | |||
437 | /* Join a AV group (you need to have been invited first.) | ||
438 | * | ||
439 | * returns group number on success | ||
440 | * returns -1 on failure. | ||
441 | */ | ||
442 | int join_av_groupchat(Group_Chats *g_c, int32_t friendnumber, const uint8_t *data, uint16_t length, | ||
443 | void (*audio_callback)(Messenger *, int, int, const int16_t *, unsigned int, uint8_t, unsigned int, void *), | ||
444 | void *userdata) | ||
445 | { | ||
446 | int groupnumber = join_groupchat(g_c, friendnumber, GROUPCHAT_TYPE_AV, data, length); | ||
447 | |||
448 | if (groupnumber == -1) { | ||
449 | return -1; | ||
450 | } | ||
451 | |||
452 | if (groupchat_enable_av(g_c, groupnumber, audio_callback, userdata) == -1) { | ||
453 | del_groupchat(g_c, groupnumber); | ||
454 | return -1; | ||
455 | } | ||
456 | |||
457 | return groupnumber; | ||
458 | } | ||
459 | |||
460 | /* Send an encoded audio packet to the group chat. | ||
461 | * | ||
462 | * return 0 on success. | ||
463 | * return -1 on failure. | ||
464 | */ | ||
465 | static int send_audio_packet(Group_Chats *g_c, int groupnumber, uint8_t *packet, uint16_t length) | ||
466 | { | ||
467 | if (!length) | ||
468 | return -1; | ||
469 | |||
470 | Group_AV *group_av = group_get_object(g_c, groupnumber); | ||
471 | uint8_t data[1 + sizeof(uint16_t) + length]; | ||
472 | data[0] = GROUP_AUDIO_PACKET_ID; | ||
473 | |||
474 | uint16_t sequnum = htons(group_av->audio_sequnum); | ||
475 | memcpy(data + 1, &sequnum, sizeof(sequnum)); | ||
476 | memcpy(data + 1 + sizeof(sequnum), packet, length); | ||
477 | |||
478 | if (send_group_lossy_packet(g_c, groupnumber, data, sizeof(data)) == -1) | ||
479 | return -1; | ||
480 | |||
481 | ++group_av->audio_sequnum; | ||
482 | return 0; | ||
483 | } | ||
484 | |||
485 | /* Send audio to the group chat. | ||
486 | * | ||
487 | * return 0 on success. | ||
488 | * return -1 on failure. | ||
489 | */ | ||
490 | int group_send_audio(Group_Chats *g_c, int groupnumber, const int16_t *pcm, unsigned int samples, uint8_t channels, | ||
491 | unsigned int sample_rate) | ||
492 | { | ||
493 | Group_AV *group_av = group_get_object(g_c, groupnumber); | ||
494 | |||
495 | if (!group_av) | ||
496 | return -1; | ||
497 | |||
498 | if (channels != 1 && channels != 2) | ||
499 | return -1; | ||
500 | |||
501 | if (sample_rate != 8000 && sample_rate != 12000 && sample_rate != 16000 && sample_rate != 24000 && sample_rate != 48000) | ||
502 | return -1; | ||
503 | |||
504 | if (!group_av->audio_encoder || group_av->audio_channels != channels || group_av->audio_sample_rate != sample_rate) { | ||
505 | group_av->audio_channels = channels; | ||
506 | group_av->audio_sample_rate = sample_rate; | ||
507 | |||
508 | if (channels == 1) { | ||
509 | group_av->audio_bitrate = 32000; //TODO: add way of adjusting bitrate | ||
510 | } else { | ||
511 | group_av->audio_bitrate = 64000; //TODO: add way of adjusting bitrate | ||
512 | } | ||
513 | |||
514 | if (recreate_encoder(group_av) == -1) | ||
515 | return -1; | ||
516 | } | ||
517 | |||
518 | uint8_t encoded[1024]; | ||
519 | int32_t size = opus_encode(group_av->audio_encoder, pcm, samples, encoded, sizeof(encoded)); | ||
520 | |||
521 | if (size <= 0) | ||
522 | return -1; | ||
523 | |||
524 | return send_audio_packet(g_c, groupnumber, encoded, size); | ||
525 | } | ||
diff --git a/toxav/group.h b/toxav/group.h new file mode 100644 index 00000000..3355a447 --- /dev/null +++ b/toxav/group.h | |||
@@ -0,0 +1,53 @@ | |||
1 | /** groupav.c | ||
2 | * | ||
3 | * Copyright (C) 2014 Tox project All Rights Reserved. | ||
4 | * | ||
5 | * This file is part of Tox. | ||
6 | * | ||
7 | * Tox is free software: you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation, either version 3 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * Tox is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with Tox. If not, see <http://www.gnu.org/licenses/>. | ||
19 | */ | ||
20 | |||
21 | /* Audio encoding/decoding */ | ||
22 | #include <opus.h> | ||
23 | |||
24 | #include "../toxcore/group.h" | ||
25 | |||
26 | #define GROUP_AUDIO_PACKET_ID 192 | ||
27 | |||
28 | /* Create a new toxav group. | ||
29 | * | ||
30 | * return group number on success. | ||
31 | * return -1 on failure. | ||
32 | */ | ||
33 | int add_av_groupchat(Group_Chats *g_c, void (*audio_callback)(Messenger *, int, int, const int16_t *, unsigned int, | ||
34 | uint8_t, unsigned int, void *), void *userdata); | ||
35 | |||
36 | /* Join a AV group (you need to have been invited first.) | ||
37 | * | ||
38 | * returns group number on success | ||
39 | * returns -1 on failure. | ||
40 | */ | ||
41 | int join_av_groupchat(Group_Chats *g_c, int32_t friendnumber, const uint8_t *data, uint16_t length, | ||
42 | void (*audio_callback)(Messenger *, int, int, const int16_t *, unsigned int, uint8_t, unsigned int, void *), | ||
43 | void *userdata); | ||
44 | |||
45 | |||
46 | /* Send audio to the group chat. | ||
47 | * | ||
48 | * return 0 on success. | ||
49 | * return -1 on failure. | ||
50 | */ | ||
51 | int group_send_audio(Group_Chats *g_c, int groupnumber, const int16_t *pcm, unsigned int samples, uint8_t channels, | ||
52 | unsigned int sample_rate); | ||
53 | |||
diff --git a/toxav/msi.c b/toxav/msi.c index 91742c35..dcb7b62a 100644 --- a/toxav/msi.c +++ b/toxav/msi.c | |||
@@ -97,11 +97,6 @@ GENERIC_HEADER ( Reason, MSIReasonStrType ) | |||
97 | GENERIC_HEADER ( CSettings, MSIRawCSettingsType ) | 97 | GENERIC_HEADER ( CSettings, MSIRawCSettingsType ) |
98 | 98 | ||
99 | 99 | ||
100 | /** | ||
101 | * @brief This is the message structure. It contains all of the headers and | ||
102 | * destination/source of the message stored in friend_id. | ||
103 | * | ||
104 | */ | ||
105 | typedef struct _MSIMessage { | 100 | typedef struct _MSIMessage { |
106 | 101 | ||
107 | MSIHeaderRequest request; | 102 | MSIHeaderRequest request; |
@@ -115,24 +110,19 @@ typedef struct _MSIMessage { | |||
115 | } MSIMessage; | 110 | } MSIMessage; |
116 | 111 | ||
117 | 112 | ||
118 | inline__ void invoke_callback(MSISession *session, int32_t call_index, MSICallbackID id) | 113 | static void invoke_callback(MSISession *s, int32_t c, MSICallbackID i) |
119 | { | 114 | { |
120 | if ( session->callbacks[id].function ) { | 115 | if ( s->callbacks[i].first ) { |
121 | LOGGER_DEBUG("Invoking callback function: %d", id); | 116 | LOGGER_DEBUG("Invoking callback function: %d", i); |
122 | session->callbacks[id].function ( session->agent_handler, call_index, session->callbacks[id].data ); | 117 | |
118 | s->callbacks[i].first( s->agent_handler, c, s->callbacks[i].second ); | ||
123 | } | 119 | } |
124 | } | 120 | } |
125 | 121 | ||
126 | /** | 122 | /** |
127 | * @brief Parse raw 'data' received from socket into MSIMessage struct. | 123 | * Parse raw 'data' received from socket into MSIMessage struct. |
128 | * Every message has to have end value of 'end_byte' or _undefined_ behavior | 124 | * Every message has to have end value of 'end_byte' or _undefined_ behavior |
129 | * occures. The best practice is to check the end of the message at the handle_packet. | 125 | * occures. The best practice is to check the end of the message at the handle_packet. |
130 | * | ||
131 | * @param msg Container. | ||
132 | * @param data The data. | ||
133 | * @return int | ||
134 | * @retval -1 Error occurred. | ||
135 | * @retval 0 Success. | ||
136 | */ | 126 | */ |
137 | static int parse_raw_data ( MSIMessage *msg, const uint8_t *data, uint16_t length ) | 127 | static int parse_raw_data ( MSIMessage *msg, const uint8_t *data, uint16_t length ) |
138 | { | 128 | { |
@@ -211,12 +201,7 @@ static int parse_raw_data ( MSIMessage *msg, const uint8_t *data, uint16_t lengt | |||
211 | } | 201 | } |
212 | 202 | ||
213 | /** | 203 | /** |
214 | * @brief Create the message. | 204 | * Create the message. |
215 | * | ||
216 | * @param type Request or response. | ||
217 | * @param type_id Type of request/response. | ||
218 | * @return MSIMessage* Created message. | ||
219 | * @retval NULL Error occurred. | ||
220 | */ | 205 | */ |
221 | MSIMessage *msi_new_message ( MSIMessageType type, const uint8_t type_value ) | 206 | MSIMessage *msi_new_message ( MSIMessageType type, const uint8_t type_value ) |
222 | { | 207 | { |
@@ -241,11 +226,7 @@ MSIMessage *msi_new_message ( MSIMessageType type, const uint8_t type_value ) | |||
241 | 226 | ||
242 | 227 | ||
243 | /** | 228 | /** |
244 | * @brief Parse data from handle_packet. | 229 | * Parse data from handle_packet. |
245 | * | ||
246 | * @param data The data. | ||
247 | * @return MSIMessage* Parsed message. | ||
248 | * @retval NULL Error occurred. | ||
249 | */ | 230 | */ |
250 | MSIMessage *parse_recv ( const uint8_t *data, uint16_t length ) | 231 | MSIMessage *parse_recv ( const uint8_t *data, uint16_t length ) |
251 | { | 232 | { |
@@ -272,16 +253,13 @@ MSIMessage *parse_recv ( const uint8_t *data, uint16_t length ) | |||
272 | 253 | ||
273 | 254 | ||
274 | /** | 255 | /** |
275 | * @brief Speaks for it self. | 256 | * Speaks for itself. |
276 | * | ||
277 | * @param dest Container. | ||
278 | * @param header_field Field. | ||
279 | * @param header_value Field value. | ||
280 | * @param value_len Length of field value. | ||
281 | * @param length Pointer to container length. | ||
282 | * @return uint8_t* Iterated container. | ||
283 | */ | 257 | */ |
284 | uint8_t *format_output ( uint8_t *dest, MSIHeaderID id, const void *value, uint8_t value_len, uint16_t *length ) | 258 | uint8_t *format_output ( uint8_t *dest, |
259 | MSIHeaderID id, | ||
260 | const void *value, | ||
261 | uint8_t value_len, | ||
262 | uint16_t *length ) | ||
285 | { | 263 | { |
286 | if ( dest == NULL ) { | 264 | if ( dest == NULL ) { |
287 | LOGGER_ERROR("No destination space!"); | 265 | LOGGER_ERROR("No destination space!"); |
@@ -307,11 +285,7 @@ uint8_t *format_output ( uint8_t *dest, MSIHeaderID id, const void *value, uint8 | |||
307 | 285 | ||
308 | 286 | ||
309 | /** | 287 | /** |
310 | * @brief Parse MSIMessage to send. | 288 | * Parse MSIMessage to send. |
311 | * | ||
312 | * @param msg The message. | ||
313 | * @param dest Destination. | ||
314 | * @return uint16_t Its final size. | ||
315 | */ | 289 | */ |
316 | uint16_t parse_send ( MSIMessage *msg, uint8_t *dest ) | 290 | uint16_t parse_send ( MSIMessage *msg, uint8_t *dest ) |
317 | { | 291 | { |
@@ -452,119 +426,83 @@ void msi_msg_get_csettings ( MSIMessage *msg, MSICSettings *dest ) | |||
452 | } | 426 | } |
453 | 427 | ||
454 | typedef struct _Timer { | 428 | typedef struct _Timer { |
455 | void *(*func)(void *); | 429 | void (*func)(struct _Timer *); |
456 | void *func_arg1; | ||
457 | int func_arg2; | ||
458 | uint64_t timeout; | 430 | uint64_t timeout; |
459 | int idx; | 431 | MSISession *session; |
432 | int call_idx; | ||
433 | int id; | ||
460 | 434 | ||
461 | } Timer; | 435 | } Timer; |
462 | 436 | ||
463 | typedef struct _TimerHandler { | 437 | typedef struct _TimerHandler { |
464 | Timer **timers; | 438 | Timer **timers; |
465 | pthread_mutex_t mutex; | ||
466 | 439 | ||
467 | uint32_t max_capacity; | 440 | uint32_t max_capacity; |
468 | uint32_t size; | 441 | uint32_t size; |
469 | uint64_t resolution; | ||
470 | |||
471 | _Bool running; | ||
472 | |||
473 | } TimerHandler; | 442 | } TimerHandler; |
474 | 443 | ||
475 | struct timer_function_args { | ||
476 | void *arg1; | ||
477 | int arg2; | ||
478 | }; | ||
479 | 444 | ||
480 | /** | 445 | static int timer_alloc (MSISession *session , void (*func)(Timer *), int call_idx, uint32_t timeout) |
481 | * @brief Allocate timer in array | ||
482 | * | ||
483 | * @param timers_container Handler | ||
484 | * @param func Function to be executed | ||
485 | * @param arg Its args | ||
486 | * @param timeout Timeout in ms | ||
487 | * @return int | ||
488 | */ | ||
489 | static int timer_alloc ( TimerHandler *timers_container, void *(func)(void *), void *arg1, int arg2, uint32_t timeout) | ||
490 | { | 446 | { |
491 | static int timer_id; | 447 | static int timer_id; |
492 | pthread_mutex_lock(&timers_container->mutex); | 448 | TimerHandler *timer_handler = session->timer_handler; |
493 | 449 | ||
494 | uint32_t i = 0; | 450 | uint32_t i = 0; |
495 | 451 | ||
496 | for (; i < timers_container->max_capacity && timers_container->timers[i]; i ++); | 452 | for (; i < timer_handler->max_capacity && timer_handler->timers[i]; i ++); |
497 | 453 | ||
498 | if (i == timers_container->max_capacity) { | 454 | if (i == timer_handler->max_capacity) { |
499 | LOGGER_WARNING("Maximum capacity reached!"); | 455 | LOGGER_WARNING("Maximum capacity reached!"); |
500 | pthread_mutex_unlock(&timers_container->mutex); | ||
501 | return -1; | 456 | return -1; |
502 | } | 457 | } |
503 | 458 | ||
504 | Timer *timer = timers_container->timers[i] = calloc(sizeof(Timer), 1); | 459 | Timer *timer = timer_handler->timers[i] = calloc(sizeof(Timer), 1); |
505 | 460 | ||
506 | if (timer == NULL) { | 461 | if (timer == NULL) { |
507 | LOGGER_ERROR("Failed to allocate timer!"); | 462 | LOGGER_ERROR("Failed to allocate timer!"); |
508 | pthread_mutex_unlock(&timers_container->mutex); | ||
509 | return -1; | 463 | return -1; |
510 | } | 464 | } |
511 | 465 | ||
512 | timers_container->size ++; | 466 | timer_handler->size ++; |
513 | 467 | ||
514 | timer->func = func; | 468 | timer->func = func; |
515 | timer->func_arg1 = arg1; | 469 | timer->session = session; |
516 | timer->func_arg2 = arg2; | 470 | timer->call_idx = call_idx; |
517 | timer->timeout = timeout + current_time_monotonic(); /* In ms */ | 471 | timer->timeout = timeout + current_time_monotonic(); /* In ms */ |
518 | ++timer_id; | 472 | ++timer_id; |
519 | timer->idx = timer_id; | 473 | timer->id = timer_id; |
520 | 474 | ||
521 | /* reorder */ | 475 | /* reorder */ |
522 | if (i) { | 476 | if (i) { |
523 | int64_t j = i - 1; | 477 | int64_t j = i - 1; |
524 | 478 | ||
525 | for (; j >= 0 && timeout < timers_container->timers[j]->timeout; j--) { | 479 | for (; j >= 0 && timeout < timer_handler->timers[j]->timeout; j--) { |
526 | Timer *tmp = timers_container->timers[j]; | 480 | Timer *tmp = timer_handler->timers[j]; |
527 | timers_container->timers[j] = timer; | 481 | timer_handler->timers[j] = timer; |
528 | timers_container->timers[j + 1] = tmp; | 482 | timer_handler->timers[j + 1] = tmp; |
529 | } | 483 | } |
530 | } | 484 | } |
531 | 485 | ||
532 | pthread_mutex_unlock(&timers_container->mutex); | 486 | LOGGER_DEBUG("Allocated timer index: %ull timeout: %ull, current size: %ull", i, timeout, timer_handler->size); |
533 | 487 | return timer->id; | |
534 | LOGGER_DEBUG("Allocated timer index: %ull timeout: %ull, current size: %ull", i, timeout, timers_container->size); | ||
535 | return timer->idx; | ||
536 | } | 488 | } |
537 | 489 | ||
538 | /** | 490 | static int timer_release ( TimerHandler *timers_container, int id) |
539 | * @brief Remove timer from array | ||
540 | * | ||
541 | * @param timers_container handler | ||
542 | * @param idx timer id | ||
543 | * @param lock_mutex (does the mutex need to be locked) | ||
544 | * @return int | ||
545 | */ | ||
546 | static int timer_release ( TimerHandler *timers_container, int idx , int lock_mutex) | ||
547 | { | 491 | { |
548 | if (lock_mutex) | ||
549 | pthread_mutex_lock(&timers_container->mutex); | ||
550 | |||
551 | Timer **timed_events = timers_container->timers; | 492 | Timer **timed_events = timers_container->timers; |
552 | 493 | ||
553 | size_t i; | 494 | uint32_t i; |
554 | int rc = -1; | 495 | int rc = -1; |
555 | 496 | ||
556 | for (i = 0; i < timers_container->max_capacity; ++i) { | 497 | for (i = 0; i < timers_container->max_capacity; ++i) { |
557 | if (timed_events[i] && timed_events[i]->idx == idx) { | 498 | if (timed_events[i] && timed_events[i]->id == id) { |
558 | rc = i; | 499 | rc = i; |
559 | break; | 500 | break; |
560 | } | 501 | } |
561 | } | 502 | } |
562 | 503 | ||
563 | if (rc == -1) { | 504 | if (rc == -1) { |
564 | LOGGER_WARNING("No event with id: %d", idx); | 505 | LOGGER_WARNING("No event with id: %d", id); |
565 | |||
566 | if (lock_mutex) pthread_mutex_unlock(&timers_container->mutex); | ||
567 | |||
568 | return -1; | 506 | return -1; |
569 | } | 507 | } |
570 | 508 | ||
@@ -581,132 +519,12 @@ static int timer_release ( TimerHandler *timers_container, int idx , int lock_mu | |||
581 | 519 | ||
582 | timers_container->size--; | 520 | timers_container->size--; |
583 | 521 | ||
584 | LOGGER_DEBUG("Popped id: %d, current size: %ull ", idx, timers_container->size); | 522 | LOGGER_DEBUG("Popped id: %d, current size: %ull ", id, timers_container->size); |
585 | |||
586 | if (lock_mutex) pthread_mutex_unlock(&timers_container->mutex); | ||
587 | |||
588 | return 0; | 523 | return 0; |
589 | } | 524 | } |
590 | 525 | ||
591 | /** | 526 | /** |
592 | * @brief Main poll for timer execution | 527 | * Generate _random_ alphanumerical string. |
593 | * | ||
594 | * @param arg ... | ||
595 | * @return void* | ||
596 | */ | ||
597 | static void *timer_poll( void *arg ) | ||
598 | { | ||
599 | TimerHandler *handler = arg; | ||
600 | |||
601 | while ( handler->running ) { | ||
602 | |||
603 | pthread_mutex_lock(&handler->mutex); | ||
604 | |||
605 | if ( handler->running ) { | ||
606 | |||
607 | uint64_t time = current_time_monotonic(); | ||
608 | |||
609 | while ( handler->timers[0] && handler->timers[0]->timeout < time ) { | ||
610 | pthread_t tid; | ||
611 | |||
612 | struct timer_function_args *args = malloc(sizeof(struct timer_function_args)); | ||
613 | args->arg1 = handler->timers[0]->func_arg1; | ||
614 | args->arg2 = handler->timers[0]->func_arg2; | ||
615 | |||
616 | if ( 0 != pthread_create(&tid, NULL, handler->timers[0]->func, args) || | ||
617 | 0 != pthread_detach(tid) ) { | ||
618 | LOGGER_ERROR("Failed to execute timer at: %d!", handler->timers[0]->timeout); | ||
619 | free(args); | ||
620 | } else { | ||
621 | LOGGER_DEBUG("Exectued timer assigned at: %d", handler->timers[0]->timeout); | ||
622 | } | ||
623 | |||
624 | timer_release(handler, handler->timers[0]->idx, 0); | ||
625 | } | ||
626 | |||
627 | } | ||
628 | |||
629 | pthread_mutex_unlock(&handler->mutex); | ||
630 | |||
631 | usleep(handler->resolution); | ||
632 | } | ||
633 | |||
634 | pthread_exit(NULL); | ||
635 | } | ||
636 | |||
637 | /** | ||
638 | * @brief Start timer poll and return handler | ||
639 | * | ||
640 | * @param max_capacity capacity | ||
641 | * @param resolution ... | ||
642 | * @return TimerHandler* | ||
643 | */ | ||
644 | static TimerHandler *timer_init_session (int max_capacity, int resolution) | ||
645 | { | ||
646 | TimerHandler *handler = calloc(1, sizeof(TimerHandler)); | ||
647 | |||
648 | if (handler == NULL) { | ||
649 | LOGGER_ERROR("Failed to allocate memory, program might misbehave!"); | ||
650 | return NULL; | ||
651 | } | ||
652 | |||
653 | handler->timers = calloc(max_capacity, sizeof(Timer *)); | ||
654 | |||
655 | if (handler->timers == NULL) { | ||
656 | LOGGER_ERROR("Failed to allocate %d timed events!", max_capacity); | ||
657 | free(handler); | ||
658 | return NULL; | ||
659 | } | ||
660 | |||
661 | handler->max_capacity = max_capacity; | ||
662 | handler->running = 1; | ||
663 | handler->resolution = resolution; | ||
664 | |||
665 | pthread_mutex_init(&handler->mutex, NULL); | ||
666 | |||
667 | |||
668 | pthread_t _tid; | ||
669 | |||
670 | if ( 0 != pthread_create(&_tid, NULL, timer_poll, handler) || 0 != pthread_detach(_tid) ) { | ||
671 | LOGGER_ERROR("Failed to start timer poll thread!"); | ||
672 | free(handler->timers); | ||
673 | free(handler); | ||
674 | return NULL; | ||
675 | } | ||
676 | |||
677 | return handler; | ||
678 | } | ||
679 | |||
680 | /** | ||
681 | * @brief Terminate timer session | ||
682 | * | ||
683 | * @param handler The timer handler | ||
684 | * @return void | ||
685 | */ | ||
686 | static void timer_terminate_session(TimerHandler *handler) | ||
687 | { | ||
688 | pthread_mutex_lock(&handler->mutex); | ||
689 | |||
690 | handler->running = 0; | ||
691 | |||
692 | pthread_mutex_unlock(&handler->mutex); | ||
693 | |||
694 | size_t i = 0; | ||
695 | |||
696 | for (; i < handler->max_capacity; i ++) | ||
697 | free(handler->timers[i]); | ||
698 | |||
699 | free(handler->timers); | ||
700 | |||
701 | pthread_mutex_destroy( &handler->mutex ); | ||
702 | } | ||
703 | |||
704 | /** | ||
705 | * @brief Generate _random_ alphanumerical string. | ||
706 | * | ||
707 | * @param str Destination. | ||
708 | * @param size Size of string. | ||
709 | * @return void | ||
710 | */ | 528 | */ |
711 | static void t_randomstr ( uint8_t *str, uint32_t size ) | 529 | static void t_randomstr ( uint8_t *str, uint32_t size ) |
712 | { | 530 | { |
@@ -727,7 +545,7 @@ static void t_randomstr ( uint8_t *str, uint32_t size ) | |||
727 | } | 545 | } |
728 | } | 546 | } |
729 | 547 | ||
730 | 548 | /* TODO: it would be nice to actually have some sane error codes */ | |
731 | typedef enum { | 549 | typedef enum { |
732 | error_none, | 550 | error_none, |
733 | error_deadcall, /* has call id but it's from old call */ | 551 | error_deadcall, /* has call id but it's from old call */ |
@@ -743,12 +561,9 @@ typedef enum { | |||
743 | 561 | ||
744 | 562 | ||
745 | /** | 563 | /** |
746 | * @brief Stringify error code. | 564 | * Stringify error code. |
747 | * | ||
748 | * @param error_code The code. | ||
749 | * @return const uint8_t* The string. | ||
750 | */ | 565 | */ |
751 | static inline__ const uint8_t *stringify_error ( MSICallError error_code ) | 566 | static const uint8_t *stringify_error ( MSICallError error_code ) |
752 | { | 567 | { |
753 | static const uint8_t *strings[] = { | 568 | static const uint8_t *strings[] = { |
754 | ( uint8_t *) "", | 569 | ( uint8_t *) "", |
@@ -763,16 +578,6 @@ static inline__ const uint8_t *stringify_error ( MSICallError error_code ) | |||
763 | return strings[error_code]; | 578 | return strings[error_code]; |
764 | } | 579 | } |
765 | 580 | ||
766 | /** | ||
767 | * @brief Speaks for it self. | ||
768 | * | ||
769 | * @param session Control session. | ||
770 | * @param msg The message. | ||
771 | * @param to Where to. | ||
772 | * @return int | ||
773 | * @retval -1 Error occurred. | ||
774 | * @retval 0 Success. | ||
775 | */ | ||
776 | static int send_message ( MSISession *session, MSICall *call, MSIMessage *msg, uint32_t to ) | 581 | static int send_message ( MSISession *session, MSICall *call, MSIMessage *msg, uint32_t to ) |
777 | { | 582 | { |
778 | msi_msg_set_callid ( msg, call->id ); | 583 | msi_msg_set_callid ( msg, call->id ); |
@@ -793,7 +598,7 @@ static int send_message ( MSISession *session, MSICall *call, MSIMessage *msg, u | |||
793 | return -1; | 598 | return -1; |
794 | } | 599 | } |
795 | 600 | ||
796 | inline__ int send_reponse ( MSISession *session, MSICall *call, MSIResponse response, uint32_t to ) | 601 | static int send_reponse ( MSISession *session, MSICall *call, MSIResponse response, uint32_t to ) |
797 | { | 602 | { |
798 | MSIMessage *msg = msi_new_message ( TypeResponse, response ); | 603 | MSIMessage *msg = msi_new_message ( TypeResponse, response ); |
799 | int ret = send_message ( session, call, msg, to ); | 604 | int ret = send_message ( session, call, msg, to ); |
@@ -801,14 +606,26 @@ inline__ int send_reponse ( MSISession *session, MSICall *call, MSIResponse resp | |||
801 | return ret; | 606 | return ret; |
802 | } | 607 | } |
803 | 608 | ||
609 | static int send_error ( MSISession *session, MSICall *call, MSICallError errid, uint32_t to ) | ||
610 | { | ||
611 | if (!call) { | ||
612 | LOGGER_WARNING("Cannot handle error on 'null' call"); | ||
613 | return -1; | ||
614 | } | ||
615 | |||
616 | LOGGER_DEBUG("Sending error: %d on call: %s", errid, call->id); | ||
617 | |||
618 | MSIMessage *msg_error = msi_new_message ( TypeResponse, error ); | ||
619 | |||
620 | msi_msg_set_reason ( msg_error, stringify_error(errid) ); | ||
621 | send_message ( session, call, msg_error, to ); | ||
622 | free ( msg_error ); | ||
623 | |||
624 | return 0; | ||
625 | } | ||
626 | |||
804 | /** | 627 | /** |
805 | * @brief Determine 'bigger' call id | 628 | * Determine 'bigger' call id |
806 | * | ||
807 | * @param first duh | ||
808 | * @param second duh | ||
809 | * @return int | ||
810 | * @retval 0 it's first | ||
811 | * @retval 1 it's second | ||
812 | */ | 629 | */ |
813 | static int call_id_bigger( const uint8_t *first, const uint8_t *second) | 630 | static int call_id_bigger( const uint8_t *first, const uint8_t *second) |
814 | { | 631 | { |
@@ -817,12 +634,7 @@ static int call_id_bigger( const uint8_t *first, const uint8_t *second) | |||
817 | 634 | ||
818 | 635 | ||
819 | /** | 636 | /** |
820 | * @brief Speaks for it self. | 637 | * Set/change peer csettings |
821 | * | ||
822 | * @param session Control session. | ||
823 | * @param msg The message. | ||
824 | * @param peer_id The peer. | ||
825 | * @return -1, 0 | ||
826 | */ | 638 | */ |
827 | static int flush_peer_csettings ( MSICall *call, MSIMessage *msg, int peer_id ) | 639 | static int flush_peer_csettings ( MSICall *call, MSIMessage *msg, int peer_id ) |
828 | { | 640 | { |
@@ -854,88 +666,9 @@ static int flush_peer_csettings ( MSICall *call, MSIMessage *msg, int peer_id ) | |||
854 | return -1; | 666 | return -1; |
855 | } | 667 | } |
856 | 668 | ||
857 | static int terminate_call ( MSISession *session, MSICall *call ); | ||
858 | |||
859 | static void handle_remote_connection_change(Messenger *messenger, int friend_num, uint8_t status, void *session_p) | ||
860 | { | ||
861 | (void)messenger; | ||
862 | MSISession *session = session_p; | ||
863 | |||
864 | switch ( status ) { | ||
865 | case 0: { /* Went offline */ | ||
866 | int32_t j = 0; | ||
867 | |||
868 | for ( ; j < session->max_calls; j ++ ) { | ||
869 | |||
870 | if ( !session->calls[j] ) continue; | ||
871 | |||
872 | uint16_t i = 0; | ||
873 | |||
874 | for ( ; i < session->calls[j]->peer_count; i ++ ) | ||
875 | if ( session->calls[j]->peers[i] == (uint32_t)friend_num ) { | ||
876 | invoke_callback(session, j, MSI_OnPeerTimeout); | ||
877 | terminate_call(session, session->calls[j]); | ||
878 | LOGGER_DEBUG("Remote: %d timed out!", friend_num); | ||
879 | return; /* TODO: On group calls change behaviour */ | ||
880 | } | ||
881 | } | ||
882 | } | ||
883 | break; | ||
884 | |||
885 | default: | ||
886 | break; | ||
887 | } | ||
888 | } | ||
889 | |||
890 | static MSICall *find_call ( MSISession *session, uint8_t *call_id ) | ||
891 | { | ||
892 | if ( call_id == NULL ) return NULL; | ||
893 | |||
894 | int32_t i = 0; | ||
895 | |||
896 | for (; i < session->max_calls; i ++ ) | ||
897 | if ( session->calls[i] && memcmp(session->calls[i]->id, call_id, sizeof(session->calls[i]->id)) == 0 ) { | ||
898 | return session->calls[i]; | ||
899 | } | ||
900 | |||
901 | return NULL; | ||
902 | } | ||
903 | |||
904 | /** | ||
905 | * @brief Sends error response to peer. | ||
906 | * | ||
907 | * @param session The session. | ||
908 | * @param errid The id. | ||
909 | * @param to Where to? | ||
910 | * @return int | ||
911 | * @retval -1/0 It's usually always success. | ||
912 | */ | ||
913 | static int send_error ( MSISession *session, MSICall *call, MSICallError errid, uint32_t to ) | ||
914 | { | ||
915 | if (!call) { | ||
916 | LOGGER_WARNING("Cannot handle error on 'null' call"); | ||
917 | return -1; | ||
918 | } | ||
919 | |||
920 | LOGGER_DEBUG("Sending error: %d on call: %s", errid, call->id); | ||
921 | |||
922 | MSIMessage *msg_error = msi_new_message ( TypeResponse, error ); | ||
923 | |||
924 | msi_msg_set_reason ( msg_error, stringify_error(errid) ); | ||
925 | send_message ( session, call, msg_error, to ); | ||
926 | free ( msg_error ); | ||
927 | |||
928 | return 0; | ||
929 | } | ||
930 | |||
931 | |||
932 | 669 | ||
933 | /** | 670 | /** |
934 | * @brief Add peer to peer list. | 671 | * Add peer to peer list. |
935 | * | ||
936 | * @param call What call. | ||
937 | * @param peer_id Its id. | ||
938 | * @return void | ||
939 | */ | 672 | */ |
940 | static void add_peer( MSICall *call, int peer_id ) | 673 | static void add_peer( MSICall *call, int peer_id ) |
941 | { | 674 | { |
@@ -955,14 +688,20 @@ static void add_peer( MSICall *call, int peer_id ) | |||
955 | } | 688 | } |
956 | 689 | ||
957 | 690 | ||
958 | /** | 691 | static MSICall *find_call ( MSISession *session, uint8_t *call_id ) |
959 | * @brief Speaks for it self. | 692 | { |
960 | * | 693 | if ( call_id == NULL ) return NULL; |
961 | * @param session Control session. | 694 | |
962 | * @param peers Amount of peers. (Currently it only supports 1) | 695 | int32_t i = 0; |
963 | * @param ringing_timeout Ringing timeout. | 696 | |
964 | * @return MSICall* The created call. | 697 | for (; i < session->max_calls; i ++ ) |
965 | */ | 698 | if ( session->calls[i] && memcmp(session->calls[i]->id, call_id, sizeof(session->calls[i]->id)) == 0 ) { |
699 | return session->calls[i]; | ||
700 | } | ||
701 | |||
702 | return NULL; | ||
703 | } | ||
704 | |||
966 | static MSICall *init_call ( MSISession *session, int peers, int ringing_timeout ) | 705 | static MSICall *init_call ( MSISession *session, int peers, int ringing_timeout ) |
967 | { | 706 | { |
968 | 707 | ||
@@ -1008,21 +747,10 @@ static MSICall *init_call ( MSISession *session, int peers, int ringing_timeout | |||
1008 | 747 | ||
1009 | call->ringing_tout_ms = ringing_timeout; | 748 | call->ringing_tout_ms = ringing_timeout; |
1010 | 749 | ||
1011 | pthread_mutex_init ( &call->mutex, NULL ); | ||
1012 | |||
1013 | LOGGER_DEBUG("Started new call with index: %u", call_idx); | 750 | LOGGER_DEBUG("Started new call with index: %u", call_idx); |
1014 | return call; | 751 | return call; |
1015 | } | 752 | } |
1016 | 753 | ||
1017 | |||
1018 | /** | ||
1019 | * @brief Terminate the call. | ||
1020 | * | ||
1021 | * @param session Control session. | ||
1022 | * @return int | ||
1023 | * @retval -1 Error occurred. | ||
1024 | * @retval 0 Success. | ||
1025 | */ | ||
1026 | static int terminate_call ( MSISession *session, MSICall *call ) | 754 | static int terminate_call ( MSISession *session, MSICall *call ) |
1027 | { | 755 | { |
1028 | if ( !call ) { | 756 | if ( !call ) { |
@@ -1030,67 +758,71 @@ static int terminate_call ( MSISession *session, MSICall *call ) | |||
1030 | return -1; | 758 | return -1; |
1031 | } | 759 | } |
1032 | 760 | ||
1033 | LOGGER_DEBUG("Terminated call id: %d", call->call_idx); | ||
1034 | /* Check event loop and cancel timed events if there are any | 761 | /* Check event loop and cancel timed events if there are any |
1035 | * NOTE: This has to be done before possibly | ||
1036 | * locking the mutex the second time | ||
1037 | */ | 762 | */ |
1038 | timer_release ( session->timer_handler, call->request_timer_id, 1); | 763 | timer_release ( session->timer_handler, call->request_timer_id); |
1039 | timer_release ( session->timer_handler, call->ringing_timer_id, 1); | 764 | timer_release ( session->timer_handler, call->ringing_timer_id); |
1040 | |||
1041 | /* Get a handle */ | ||
1042 | pthread_mutex_lock ( &call->mutex ); | ||
1043 | 765 | ||
1044 | session->calls[call->call_idx] = NULL; | 766 | session->calls[call->call_idx] = NULL; |
1045 | 767 | ||
1046 | free ( call->csettings_peer ); | 768 | LOGGER_DEBUG("Terminated call id: %d", call->call_idx); |
1047 | free ( call->peers); | ||
1048 | |||
1049 | /* Release handle */ | ||
1050 | pthread_mutex_unlock ( &call->mutex ); | ||
1051 | |||
1052 | pthread_mutex_destroy ( &call->mutex ); | ||
1053 | 769 | ||
770 | free ( call->csettings_peer ); | ||
771 | free ( call->peers ); | ||
1054 | free ( call ); | 772 | free ( call ); |
1055 | 773 | ||
1056 | return 0; | 774 | return 0; |
1057 | } | 775 | } |
1058 | 776 | ||
777 | static void handle_remote_connection_change(Messenger *messenger, uint32_t friend_num, uint8_t status, void *session_p) | ||
778 | { | ||
779 | (void)messenger; | ||
780 | MSISession *session = session_p; | ||
781 | |||
782 | switch ( status ) { | ||
783 | case 0: { /* Went offline */ | ||
784 | int32_t j = 0; | ||
785 | |||
786 | for ( ; j < session->max_calls; j ++ ) { | ||
787 | |||
788 | if ( !session->calls[j] ) continue; | ||
789 | |||
790 | uint16_t i = 0; | ||
791 | |||
792 | for ( ; i < session->calls[j]->peer_count; i ++ ) | ||
793 | if ( session->calls[j]->peers[i] == (uint32_t)friend_num ) { | ||
794 | invoke_callback(session, j, msi_OnPeerTimeout); | ||
795 | terminate_call(session, session->calls[j]); | ||
796 | LOGGER_DEBUG("Remote: %d timed out!", friend_num); | ||
797 | return; /* TODO: On group calls change behaviour */ | ||
798 | } | ||
799 | } | ||
800 | } | ||
801 | break; | ||
802 | |||
803 | default: | ||
804 | break; | ||
805 | } | ||
806 | } | ||
1059 | 807 | ||
1060 | /** | 808 | /** |
1061 | * @brief Function called at request timeout. If not called in thread it might cause trouble | 809 | * Function called at request timeout |
1062 | * | ||
1063 | * @param arg Control session | ||
1064 | * @return void* | ||
1065 | */ | 810 | */ |
1066 | static void *handle_timeout ( void *arg ) | 811 | static void handle_timeout ( Timer *timer ) |
1067 | { | 812 | { |
1068 | /* TODO: Cancel might not arrive there; set up | 813 | /* TODO: Cancel might not arrive there; set up |
1069 | * timers on these cancels and terminate call on | 814 | * timers on these cancels and terminate call on |
1070 | * their timeout | 815 | * their timeout |
1071 | */ | 816 | */ |
1072 | struct timer_function_args *args = arg; | 817 | MSICall *call = timer->session->calls[timer->call_idx]; |
1073 | int call_index = args->arg2; | 818 | |
1074 | MSISession *session = args->arg1; | ||
1075 | MSICall *call = session->calls[call_index]; | ||
1076 | 819 | ||
1077 | if (call) { | 820 | if (call) { |
1078 | LOGGER_DEBUG("[Call: %d] Request timed out!", call->call_idx); | 821 | LOGGER_DEBUG("[Call: %d] Request timed out!", call->call_idx); |
1079 | 822 | ||
1080 | invoke_callback(session, call_index, MSI_OnRequestTimeout); | 823 | invoke_callback(timer->session, timer->call_idx, msi_OnRequestTimeout); |
1081 | } | 824 | msi_cancel(timer->session, timer->call_idx, call->peers [0], "Request timed out"); |
1082 | |||
1083 | if ( call && call->session ) { | ||
1084 | |||
1085 | /* TODO: Cancel all? */ | ||
1086 | /* uint16_t _it = 0; | ||
1087 | * for ( ; _it < _session->call->peer_count; _it++ ) */ | ||
1088 | msi_cancel ( call->session, call->call_idx, call->peers [0], "Request timed out" ); | ||
1089 | /*terminate_call(call->session, call);*/ | ||
1090 | } | 825 | } |
1091 | |||
1092 | free(arg); | ||
1093 | pthread_exit(NULL); | ||
1094 | } | 826 | } |
1095 | 827 | ||
1096 | 828 | ||
@@ -1099,18 +831,16 @@ static int handle_recv_invite ( MSISession *session, MSICall *call, MSIMessage * | |||
1099 | { | 831 | { |
1100 | LOGGER_DEBUG("Session: %p Handling 'invite' on call: %d", session, call ? call->call_idx : -1); | 832 | LOGGER_DEBUG("Session: %p Handling 'invite' on call: %d", session, call ? call->call_idx : -1); |
1101 | 833 | ||
1102 | pthread_mutex_lock(&session->mutex); | ||
1103 | 834 | ||
1104 | if (!msg->csettings.exists) {/**/ | 835 | if (!msg->csettings.exists) {/**/ |
1105 | LOGGER_WARNING("Peer sent invalid codec settings!"); | 836 | LOGGER_WARNING("Peer sent invalid codec settings!"); |
1106 | send_error ( session, call, error_no_callid, msg->friend_id ); | 837 | send_error ( session, call, error_no_callid, msg->friend_id ); |
1107 | pthread_mutex_unlock(&session->mutex); | ||
1108 | return 0; | 838 | return 0; |
1109 | } | 839 | } |
1110 | 840 | ||
1111 | if ( call ) { | 841 | if ( call ) { |
1112 | if ( call->peers[0] == (uint32_t)msg->friend_id ) { | 842 | if ( call->peers[0] == (uint32_t)msg->friend_id ) { |
1113 | if (call->state == call_inviting) { | 843 | if (call->state == msi_CallInviting) { |
1114 | /* The glare case. A calls B when at the same time | 844 | /* The glare case. A calls B when at the same time |
1115 | * B calls A. Who has advantage is set bey calculating | 845 | * B calls A. Who has advantage is set bey calculating |
1116 | * 'bigger' Call id and then that call id is being used in | 846 | * 'bigger' Call id and then that call id is being used in |
@@ -1127,41 +857,35 @@ static int handle_recv_invite ( MSISession *session, MSICall *call, MSIMessage * | |||
1127 | call = init_call ( session, 1, 0 ); | 857 | call = init_call ( session, 1, 0 ); |
1128 | 858 | ||
1129 | if ( !call ) { | 859 | if ( !call ) { |
1130 | pthread_mutex_unlock(&session->mutex); | ||
1131 | LOGGER_ERROR("Starting call"); | 860 | LOGGER_ERROR("Starting call"); |
1132 | return 0; | 861 | return 0; |
1133 | } | 862 | } |
1134 | 863 | ||
1135 | } else { | 864 | } else { |
1136 | pthread_mutex_unlock(&session->mutex); | ||
1137 | return 0; /* Wait for ringing from peer */ | 865 | return 0; /* Wait for ringing from peer */ |
1138 | } | 866 | } |
1139 | } else if (call->state == call_active) { | 867 | } else if (call->state == msi_CallActive) { |
1140 | /* Request for media change; call callback and send starting response */ | 868 | /* Request for media change; call callback and send starting response */ |
1141 | if (flush_peer_csettings(call, msg, 0) != 0) { /**/ | 869 | if (flush_peer_csettings(call, msg, 0) != 0) { /**/ |
1142 | LOGGER_WARNING("Peer sent invalid csetting!"); | 870 | LOGGER_WARNING("Peer sent invalid csetting!"); |
1143 | send_error ( session, call, error_no_callid, msg->friend_id ); | 871 | send_error ( session, call, error_no_callid, msg->friend_id ); |
1144 | pthread_mutex_unlock(&session->mutex); | ||
1145 | return 0; | 872 | return 0; |
1146 | } | 873 | } |
1147 | 874 | ||
1148 | LOGGER_DEBUG("Set new call type: %s", call->csettings_peer[0].call_type == type_audio ? "audio" : "video"); | 875 | LOGGER_DEBUG("Set new call type: %s", call->csettings_peer[0].call_type == msi_TypeAudio ? "audio" : "video"); |
1149 | send_reponse(session, call, starting, msg->friend_id); | 876 | send_reponse(session, call, starting, msg->friend_id); |
1150 | pthread_mutex_unlock(&session->mutex); | 877 | invoke_callback(session, call->call_idx, msi_OnPeerCSChange); |
1151 | invoke_callback(session, call->call_idx, MSI_OnMediaChange); | ||
1152 | return 1; | 878 | return 1; |
1153 | } | 879 | } |
1154 | } else { | 880 | } else { |
1155 | send_error ( session, call, error_busy, msg->friend_id ); /* TODO: Ugh*/ | 881 | send_error ( session, call, error_busy, msg->friend_id ); /* TODO: Ugh*/ |
1156 | terminate_call(session, call); | 882 | terminate_call(session, call); |
1157 | pthread_mutex_unlock(&session->mutex); | ||
1158 | return 0; | 883 | return 0; |
1159 | } | 884 | } |
1160 | } else { | 885 | } else { |
1161 | call = init_call ( session, 1, 0 ); | 886 | call = init_call ( session, 1, 0 ); |
1162 | 887 | ||
1163 | if ( !call ) { | 888 | if ( !call ) { |
1164 | pthread_mutex_unlock(&session->mutex); | ||
1165 | LOGGER_ERROR("Starting call"); | 889 | LOGGER_ERROR("Starting call"); |
1166 | return 0; | 890 | return 0; |
1167 | } | 891 | } |
@@ -1170,22 +894,16 @@ static int handle_recv_invite ( MSISession *session, MSICall *call, MSIMessage * | |||
1170 | if ( !msg->callid.exists ) { | 894 | if ( !msg->callid.exists ) { |
1171 | send_error ( session, call, error_no_callid, msg->friend_id ); | 895 | send_error ( session, call, error_no_callid, msg->friend_id ); |
1172 | terminate_call(session, call); | 896 | terminate_call(session, call); |
1173 | pthread_mutex_unlock(&session->mutex); | ||
1174 | return 0; | 897 | return 0; |
1175 | } | 898 | } |
1176 | 899 | ||
1177 | memcpy ( call->id, msg->callid.value, sizeof(msg->callid.value) ); | 900 | memcpy ( call->id, msg->callid.value, sizeof(msg->callid.value) ); |
1178 | call->state = call_starting; | 901 | call->state = msi_CallStarting; |
1179 | 902 | ||
1180 | add_peer( call, msg->friend_id); | 903 | add_peer( call, msg->friend_id); |
1181 | |||
1182 | flush_peer_csettings ( call, msg, 0 ); | 904 | flush_peer_csettings ( call, msg, 0 ); |
1183 | |||
1184 | send_reponse(session, call, ringing, msg->friend_id); | 905 | send_reponse(session, call, ringing, msg->friend_id); |
1185 | 906 | invoke_callback(session, call->call_idx, msi_OnInvite); | |
1186 | pthread_mutex_unlock(&session->mutex); | ||
1187 | |||
1188 | invoke_callback(session, call->call_idx, MSI_OnInvite); | ||
1189 | 907 | ||
1190 | return 1; | 908 | return 1; |
1191 | } | 909 | } |
@@ -1201,13 +919,8 @@ static int handle_recv_start ( MSISession *session, MSICall *call, MSIMessage *m | |||
1201 | 919 | ||
1202 | LOGGER_DEBUG("Session: %p Handling 'start' on call: %d, friend id: %d", session, call->call_idx, msg->friend_id ); | 920 | LOGGER_DEBUG("Session: %p Handling 'start' on call: %d, friend id: %d", session, call->call_idx, msg->friend_id ); |
1203 | 921 | ||
1204 | pthread_mutex_lock(&session->mutex); | 922 | call->state = msi_CallActive; |
1205 | 923 | invoke_callback(session, call->call_idx, msi_OnStart); | |
1206 | call->state = call_active; | ||
1207 | |||
1208 | pthread_mutex_unlock(&session->mutex); | ||
1209 | |||
1210 | invoke_callback(session, call->call_idx, MSI_OnStart); | ||
1211 | return 1; | 924 | return 1; |
1212 | } | 925 | } |
1213 | 926 | ||
@@ -1220,15 +933,11 @@ static int handle_recv_reject ( MSISession *session, MSICall *call, MSIMessage * | |||
1220 | 933 | ||
1221 | LOGGER_DEBUG("Session: %p Handling 'reject' on call: %u", session, call->call_idx); | 934 | LOGGER_DEBUG("Session: %p Handling 'reject' on call: %u", session, call->call_idx); |
1222 | 935 | ||
1223 | invoke_callback(session, call->call_idx, MSI_OnReject); | 936 | invoke_callback(session, call->call_idx, msi_OnReject); |
1224 | |||
1225 | pthread_mutex_lock(&session->mutex); | ||
1226 | 937 | ||
1227 | send_reponse(session, call, ending, msg->friend_id); | 938 | send_reponse(session, call, ending, msg->friend_id); |
1228 | terminate_call(session, call); | 939 | terminate_call(session, call); |
1229 | 940 | ||
1230 | pthread_mutex_unlock(&session->mutex); | ||
1231 | |||
1232 | return 1; | 941 | return 1; |
1233 | } | 942 | } |
1234 | 943 | ||
@@ -1243,14 +952,9 @@ static int handle_recv_cancel ( MSISession *session, MSICall *call, MSIMessage * | |||
1243 | 952 | ||
1244 | LOGGER_DEBUG("Session: %p Handling 'cancel' on call: %u", session, call->call_idx); | 953 | LOGGER_DEBUG("Session: %p Handling 'cancel' on call: %u", session, call->call_idx); |
1245 | 954 | ||
1246 | invoke_callback(session, call->call_idx, MSI_OnCancel); | 955 | invoke_callback(session, call->call_idx, msi_OnCancel); |
1247 | |||
1248 | pthread_mutex_lock(&session->mutex); | ||
1249 | |||
1250 | terminate_call ( session, call ); | 956 | terminate_call ( session, call ); |
1251 | 957 | ||
1252 | pthread_mutex_unlock(&session->mutex); | ||
1253 | |||
1254 | return 1; | 958 | return 1; |
1255 | } | 959 | } |
1256 | 960 | ||
@@ -1263,15 +967,10 @@ static int handle_recv_end ( MSISession *session, MSICall *call, MSIMessage *msg | |||
1263 | 967 | ||
1264 | LOGGER_DEBUG("Session: %p Handling 'end' on call: %d", session, call->call_idx); | 968 | LOGGER_DEBUG("Session: %p Handling 'end' on call: %d", session, call->call_idx); |
1265 | 969 | ||
1266 | invoke_callback(session, call->call_idx, MSI_OnEnd); | 970 | invoke_callback(session, call->call_idx, msi_OnEnd); |
1267 | pthread_mutex_lock(&session->mutex); | ||
1268 | |||
1269 | send_reponse(session, call, ending, msg->friend_id); | 971 | send_reponse(session, call, ending, msg->friend_id); |
1270 | terminate_call ( session, call ); | 972 | terminate_call ( session, call ); |
1271 | 973 | ||
1272 | pthread_mutex_unlock(&session->mutex); | ||
1273 | |||
1274 | |||
1275 | return 1; | 974 | return 1; |
1276 | } | 975 | } |
1277 | 976 | ||
@@ -1285,22 +984,16 @@ static int handle_recv_ringing ( MSISession *session, MSICall *call, MSIMessage | |||
1285 | 984 | ||
1286 | (void)msg; | 985 | (void)msg; |
1287 | 986 | ||
1288 | pthread_mutex_lock(&session->mutex); | ||
1289 | |||
1290 | if ( call->ringing_timer_id ) { | 987 | if ( call->ringing_timer_id ) { |
1291 | LOGGER_WARNING("Call already ringing"); | 988 | LOGGER_WARNING("Call already ringing"); |
1292 | pthread_mutex_unlock(&session->mutex); | ||
1293 | return 0; | 989 | return 0; |
1294 | } | 990 | } |
1295 | 991 | ||
1296 | LOGGER_DEBUG("Session: %p Handling 'ringing' on call: %d", session, call->call_idx ); | 992 | LOGGER_DEBUG("Session: %p Handling 'ringing' on call: %d", session, call->call_idx ); |
1297 | 993 | ||
1298 | call->ringing_timer_id = timer_alloc ( session->timer_handler, handle_timeout, session, call->call_idx, | 994 | call->ringing_timer_id = timer_alloc |
1299 | call->ringing_tout_ms ); | 995 | ( session, handle_timeout, call->call_idx, call->ringing_tout_ms ); |
1300 | 996 | invoke_callback(session, call->call_idx, msi_OnRinging); | |
1301 | pthread_mutex_unlock(&session->mutex); | ||
1302 | |||
1303 | invoke_callback(session, call->call_idx, MSI_OnRinging); | ||
1304 | return 1; | 997 | return 1; |
1305 | } | 998 | } |
1306 | static int handle_recv_starting ( MSISession *session, MSICall *call, MSIMessage *msg ) | 999 | static int handle_recv_starting ( MSISession *session, MSICall *call, MSIMessage *msg ) |
@@ -1310,19 +1003,16 @@ static int handle_recv_starting ( MSISession *session, MSICall *call, MSIMessage | |||
1310 | return 0; | 1003 | return 0; |
1311 | } | 1004 | } |
1312 | 1005 | ||
1313 | pthread_mutex_lock(&session->mutex); | 1006 | if ( call->state == msi_CallActive ) { /* Change media */ |
1314 | |||
1315 | if ( call->state == call_active ) { /* Change media */ | ||
1316 | 1007 | ||
1317 | LOGGER_DEBUG("Session: %p Changing media on call: %d", session, call->call_idx ); | 1008 | LOGGER_DEBUG("Session: %p Changing media on call: %d", session, call->call_idx ); |
1318 | pthread_mutex_unlock(&session->mutex); | ||
1319 | 1009 | ||
1320 | invoke_callback(session, call->call_idx, MSI_OnMediaChange); | 1010 | invoke_callback(session, call->call_idx, msi_OnSelfCSChange); |
1321 | 1011 | ||
1322 | } else if ( call->state == call_inviting ) { | 1012 | } else if ( call->state == msi_CallInviting ) { |
1323 | LOGGER_DEBUG("Session: %p Handling 'starting' on call: %d", session, call->call_idx ); | 1013 | LOGGER_DEBUG("Session: %p Handling 'starting' on call: %d", session, call->call_idx ); |
1324 | 1014 | ||
1325 | call->state = call_active; | 1015 | call->state = msi_CallActive; |
1326 | 1016 | ||
1327 | MSIMessage *msg_start = msi_new_message ( TypeRequest, start ); | 1017 | MSIMessage *msg_start = msi_new_message ( TypeRequest, start ); |
1328 | send_message ( session, call, msg_start, msg->friend_id ); | 1018 | send_message ( session, call, msg_start, msg->friend_id ); |
@@ -1332,15 +1022,11 @@ static int handle_recv_starting ( MSISession *session, MSICall *call, MSIMessage | |||
1332 | flush_peer_csettings ( call, msg, 0 ); | 1022 | flush_peer_csettings ( call, msg, 0 ); |
1333 | 1023 | ||
1334 | /* This is here in case of glare */ | 1024 | /* This is here in case of glare */ |
1335 | timer_release ( session->timer_handler, call->ringing_timer_id, 1 ); | 1025 | timer_release(session->timer_handler, call->ringing_timer_id); |
1336 | 1026 | invoke_callback(session, call->call_idx, msi_OnStart); | |
1337 | pthread_mutex_unlock(&session->mutex); | ||
1338 | |||
1339 | invoke_callback(session, call->call_idx, MSI_OnStarting); | ||
1340 | } else { | 1027 | } else { |
1341 | LOGGER_ERROR("Invalid call state"); | 1028 | LOGGER_ERROR("Invalid call state"); |
1342 | terminate_call(session, call ); | 1029 | terminate_call(session, call ); |
1343 | pthread_mutex_unlock(&session->mutex); | ||
1344 | return 0; | 1030 | return 0; |
1345 | } | 1031 | } |
1346 | 1032 | ||
@@ -1357,29 +1043,21 @@ static int handle_recv_ending ( MSISession *session, MSICall *call, MSIMessage * | |||
1357 | 1043 | ||
1358 | LOGGER_DEBUG("Session: %p Handling 'ending' on call: %d", session, call->call_idx ); | 1044 | LOGGER_DEBUG("Session: %p Handling 'ending' on call: %d", session, call->call_idx ); |
1359 | 1045 | ||
1360 | invoke_callback(session, call->call_idx, MSI_OnEnding); | 1046 | invoke_callback(session, call->call_idx, msi_OnEnd); |
1361 | |||
1362 | /* Terminate call */ | ||
1363 | pthread_mutex_lock(&session->mutex); | ||
1364 | terminate_call ( session, call ); | 1047 | terminate_call ( session, call ); |
1365 | pthread_mutex_unlock(&session->mutex); | ||
1366 | 1048 | ||
1367 | return 1; | 1049 | return 1; |
1368 | } | 1050 | } |
1369 | static int handle_recv_error ( MSISession *session, MSICall *call, MSIMessage *msg ) | 1051 | static int handle_recv_error ( MSISession *session, MSICall *call, MSIMessage *msg ) |
1370 | { | 1052 | { |
1371 | |||
1372 | if ( !call ) { | 1053 | if ( !call ) { |
1373 | LOGGER_WARNING("Handling 'error' on non-existing call!"); | 1054 | LOGGER_WARNING("Handling 'error' on non-existing call!"); |
1374 | pthread_mutex_unlock(&session->mutex); | ||
1375 | return -1; | 1055 | return -1; |
1376 | } | 1056 | } |
1377 | 1057 | ||
1378 | LOGGER_DEBUG("Session: %p Handling 'error' on call: %d", session, call->call_idx ); | 1058 | LOGGER_DEBUG("Session: %p Handling 'error' on call: %d", session, call->call_idx ); |
1379 | 1059 | ||
1380 | invoke_callback(session, call->call_idx, MSI_OnEnding); | 1060 | invoke_callback(session, call->call_idx, msi_OnEnd); |
1381 | |||
1382 | pthread_mutex_lock(&session->mutex); | ||
1383 | 1061 | ||
1384 | /* Handle error accordingly */ | 1062 | /* Handle error accordingly */ |
1385 | if ( msg->reason.exists ) { | 1063 | if ( msg->reason.exists ) { |
@@ -1388,14 +1066,11 @@ static int handle_recv_error ( MSISession *session, MSICall *call, MSIMessage *m | |||
1388 | 1066 | ||
1389 | terminate_call ( session, call ); | 1067 | terminate_call ( session, call ); |
1390 | 1068 | ||
1391 | pthread_mutex_unlock(&session->mutex); | ||
1392 | |||
1393 | return 1; | 1069 | return 1; |
1394 | } | 1070 | } |
1395 | 1071 | ||
1396 | |||
1397 | /** | 1072 | /** |
1398 | * @brief BASIC call flow: | 1073 | * BASIC call flow: |
1399 | * | 1074 | * |
1400 | * ALICE BOB | 1075 | * ALICE BOB |
1401 | * | invite --> | | 1076 | * | invite --> | |
@@ -1426,7 +1101,8 @@ static int handle_recv_error ( MSISession *session, MSICall *call, MSIMessage *m | |||
1426 | * | 1101 | * |
1427 | * | 1102 | * |
1428 | */ | 1103 | */ |
1429 | static void msi_handle_packet ( Messenger *messenger, int source, const uint8_t *data, uint16_t length, void *object ) | 1104 | static void msi_handle_packet ( Messenger *messenger, uint32_t source, const uint8_t *data, uint16_t length, |
1105 | void *object ) | ||
1430 | { | 1106 | { |
1431 | LOGGER_DEBUG("Got msi message"); | 1107 | LOGGER_DEBUG("Got msi message"); |
1432 | /* Unused */ | 1108 | /* Unused */ |
@@ -1436,7 +1112,7 @@ static void msi_handle_packet ( Messenger *messenger, int source, const uint8_t | |||
1436 | MSIMessage *msg; | 1112 | MSIMessage *msg; |
1437 | 1113 | ||
1438 | if ( !length ) { | 1114 | if ( !length ) { |
1439 | LOGGER_WARNING("Lenght param negative"); | 1115 | LOGGER_WARNING("Length param negative"); |
1440 | return; | 1116 | return; |
1441 | } | 1117 | } |
1442 | 1118 | ||
@@ -1451,6 +1127,7 @@ static void msi_handle_packet ( Messenger *messenger, int source, const uint8_t | |||
1451 | 1127 | ||
1452 | msg->friend_id = source; | 1128 | msg->friend_id = source; |
1453 | 1129 | ||
1130 | pthread_mutex_lock(session->mutex); | ||
1454 | 1131 | ||
1455 | /* Find what call */ | 1132 | /* Find what call */ |
1456 | MSICall *call = msg->callid.exists ? find_call(session, msg->callid.value ) : NULL; | 1133 | MSICall *call = msg->callid.exists ? find_call(session, msg->callid.value ) : NULL; |
@@ -1484,7 +1161,7 @@ static void msi_handle_packet ( Messenger *messenger, int source, const uint8_t | |||
1484 | } else if ( msg->response.exists ) { /* Handle response */ | 1161 | } else if ( msg->response.exists ) { /* Handle response */ |
1485 | 1162 | ||
1486 | /* Got response so cancel timer */ | 1163 | /* Got response so cancel timer */ |
1487 | if ( call ) timer_release ( session->timer_handler, call->request_timer_id, 1 ); | 1164 | if ( call ) timer_release(session->timer_handler, call->request_timer_id); |
1488 | 1165 | ||
1489 | switch (msg->response.value) { | 1166 | switch (msg->response.value) { |
1490 | case ringing: | 1167 | case ringing: |
@@ -1509,42 +1186,29 @@ static void msi_handle_packet ( Messenger *messenger, int source, const uint8_t | |||
1509 | } | 1186 | } |
1510 | 1187 | ||
1511 | free ( msg ); | 1188 | free ( msg ); |
1189 | |||
1190 | pthread_mutex_unlock(session->mutex); | ||
1512 | } | 1191 | } |
1513 | 1192 | ||
1514 | 1193 | ||
1515 | /** | 1194 | |
1516 | * @brief Callback setter. | 1195 | /********** User functions **********/ |
1517 | * | ||
1518 | * @param callback The callback. | ||
1519 | * @param id The id. | ||
1520 | * @return void | ||
1521 | */ | ||
1522 | void msi_register_callback ( MSISession *session, MSICallbackType callback, MSICallbackID id, void *userdata ) | 1196 | void msi_register_callback ( MSISession *session, MSICallbackType callback, MSICallbackID id, void *userdata ) |
1523 | { | 1197 | { |
1524 | session->callbacks[id].function = callback; | 1198 | session->callbacks[id].first = callback; |
1525 | session->callbacks[id].data = userdata; | 1199 | session->callbacks[id].second = userdata; |
1526 | } | 1200 | } |
1527 | 1201 | ||
1528 | 1202 | ||
1529 | /** | 1203 | MSISession *msi_new ( Messenger *messenger, int32_t max_calls ) |
1530 | * @brief Start the control session. | ||
1531 | * | ||
1532 | * @param messenger Tox* object. | ||
1533 | * @param max_calls Amount of calls possible | ||
1534 | * @return MSISession* The created session. | ||
1535 | * @retval NULL Error occurred. | ||
1536 | */ | ||
1537 | MSISession *msi_init_session ( Messenger *messenger, int32_t max_calls ) | ||
1538 | { | 1204 | { |
1539 | if (messenger == NULL) { | 1205 | if (messenger == NULL) { |
1540 | LOGGER_ERROR("Could not init session on empty messenger!"); | 1206 | LOGGER_ERROR("Could not init session on empty messenger!"); |
1541 | return NULL; | 1207 | return NULL; |
1542 | } | 1208 | } |
1543 | 1209 | ||
1544 | TimerHandler *handler = timer_init_session(max_calls * 10, 10000); | 1210 | if ( !max_calls ) { |
1545 | 1211 | LOGGER_WARNING("Invalid max call treshold!"); | |
1546 | if ( !max_calls || !handler ) { | ||
1547 | LOGGER_WARNING("Invalid max call treshold or timer handler initialization failed!"); | ||
1548 | return NULL; | 1212 | return NULL; |
1549 | } | 1213 | } |
1550 | 1214 | ||
@@ -1555,87 +1219,105 @@ MSISession *msi_init_session ( Messenger *messenger, int32_t max_calls ) | |||
1555 | return NULL; | 1219 | return NULL; |
1556 | } | 1220 | } |
1557 | 1221 | ||
1558 | retu->messenger_handle = messenger; | ||
1559 | retu->agent_handler = NULL; | ||
1560 | retu->timer_handler = handler; | ||
1561 | |||
1562 | if (!(retu->calls = calloc( sizeof (MSICall *), max_calls ))) { | 1222 | if (!(retu->calls = calloc( sizeof (MSICall *), max_calls ))) { |
1563 | LOGGER_ERROR("Allocation failed! Program might misbehave!"); | 1223 | LOGGER_ERROR("Allocation failed! Program might misbehave!"); |
1564 | free(retu); | 1224 | goto error; |
1565 | return NULL; | ||
1566 | } | 1225 | } |
1567 | 1226 | ||
1568 | retu->max_calls = max_calls; | 1227 | retu->timer_handler = calloc(1, sizeof(TimerHandler)); |
1569 | 1228 | ||
1229 | if (retu->timer_handler == NULL) { | ||
1230 | LOGGER_ERROR("Allocation failed! Program might misbehave!"); | ||
1231 | goto error; | ||
1232 | } | ||
1233 | |||
1234 | /* Allocate space for timers */ | ||
1235 | ((TimerHandler *)retu->timer_handler)->max_capacity = max_calls * 10; | ||
1236 | |||
1237 | if (!(((TimerHandler *)retu->timer_handler)->timers = calloc(max_calls * 10, sizeof(Timer *)))) { | ||
1238 | LOGGER_ERROR("Allocation failed! Program might misbehave!"); | ||
1239 | goto error; | ||
1240 | } | ||
1241 | |||
1242 | if (create_recursive_mutex(retu->mutex) != 0) { | ||
1243 | LOGGER_ERROR("Failed to init mutex! Program might misbehave"); | ||
1244 | goto error; | ||
1245 | } | ||
1246 | |||
1247 | retu->messenger_handle = messenger; | ||
1248 | retu->agent_handler = NULL; | ||
1249 | retu->max_calls = max_calls; | ||
1570 | retu->frequ = 10000; /* default value? */ | 1250 | retu->frequ = 10000; /* default value? */ |
1571 | retu->call_timeout = 30000; /* default value? */ | 1251 | retu->call_timeout = 30000; /* default value? */ |
1572 | 1252 | ||
1573 | |||
1574 | m_callback_msi_packet(messenger, msi_handle_packet, retu ); | 1253 | m_callback_msi_packet(messenger, msi_handle_packet, retu ); |
1575 | 1254 | ||
1576 | /* This is called when remote terminates session */ | 1255 | /* This is called when remote terminates session */ |
1577 | m_callback_connectionstatus_internal_av(messenger, handle_remote_connection_change, retu); | 1256 | m_callback_connectionstatus_internal_av(messenger, handle_remote_connection_change, retu); |
1578 | 1257 | ||
1579 | pthread_mutex_init(&retu->mutex, NULL); | ||
1580 | |||
1581 | LOGGER_DEBUG("New msi session: %p max calls: %u", retu, max_calls); | 1258 | LOGGER_DEBUG("New msi session: %p max calls: %u", retu, max_calls); |
1582 | return retu; | 1259 | return retu; |
1260 | |||
1261 | error: | ||
1262 | |||
1263 | if (retu->timer_handler) { | ||
1264 | free(((TimerHandler *)retu->timer_handler)->timers); | ||
1265 | free(retu->timer_handler); | ||
1266 | } | ||
1267 | |||
1268 | free(retu->calls); | ||
1269 | free(retu); | ||
1270 | return NULL; | ||
1583 | } | 1271 | } |
1584 | 1272 | ||
1585 | 1273 | ||
1586 | /** | 1274 | int msi_kill ( MSISession *session ) |
1587 | * @brief Terminate control session. | ||
1588 | * | ||
1589 | * @param session The session | ||
1590 | * @return int | ||
1591 | */ | ||
1592 | int msi_terminate_session ( MSISession *session ) | ||
1593 | { | 1275 | { |
1594 | if (session == NULL) { | 1276 | if (session == NULL) { |
1595 | LOGGER_ERROR("Tried to terminate non-existing session"); | 1277 | LOGGER_ERROR("Tried to terminate non-existing session"); |
1596 | return -1; | 1278 | return -1; |
1597 | } | 1279 | } |
1598 | 1280 | ||
1599 | pthread_mutex_lock(&session->mutex); | ||
1600 | m_callback_msi_packet((struct Messenger *) session->messenger_handle, NULL, NULL); | 1281 | m_callback_msi_packet((struct Messenger *) session->messenger_handle, NULL, NULL); |
1601 | pthread_mutex_unlock(&session->mutex); | 1282 | pthread_mutex_lock(session->mutex); |
1602 | |||
1603 | int _status = 0; | ||
1604 | 1283 | ||
1605 | /* If have calls, cancel them */ | 1284 | /* Cancel active calls */ |
1606 | int32_t idx = 0; | 1285 | int32_t idx = 0; |
1607 | 1286 | ||
1608 | for (; idx < session->max_calls; idx ++) if ( session->calls[idx] ) { | 1287 | for (; idx < session->max_calls; idx ++) if ( session->calls[idx] ) { |
1609 | /* Cancel all? */ | 1288 | /* Cancel all? */ |
1610 | uint16_t _it = 0; | 1289 | uint16_t _it = 0; |
1611 | /*for ( ; _it < session->calls[idx]->peer_count; _it++ ) | 1290 | /*for ( ; _it < session->calls[idx]->peer_count; _it++ ) |
1612 | * FIXME: will not work on multiple peers, must cancel call for all peers | 1291 | * FIXME: will not work on multiple peers, must cancel call for all peers |
1613 | */ | 1292 | */ |
1614 | msi_cancel ( session, idx, session->calls[idx]->peers [_it], "MSI session terminated!" ); | 1293 | MSICallState state = session->calls[idx]->state; |
1294 | |||
1295 | if (state == msi_CallInviting) { | ||
1296 | msi_cancel( session, idx, session->calls[idx]->peers [_it], "MSI session terminated!" ); | ||
1297 | } else { | ||
1298 | msi_stopcall(session, idx); | ||
1299 | } | ||
1615 | } | 1300 | } |
1616 | 1301 | ||
1617 | timer_terminate_session(session->timer_handler); | 1302 | free(((TimerHandler *)session->timer_handler)->timers); |
1303 | free(session->timer_handler); | ||
1618 | 1304 | ||
1619 | pthread_mutex_destroy(&session->mutex); | 1305 | free ( session->calls ); |
1306 | pthread_mutex_unlock(session->mutex); | ||
1307 | pthread_mutex_destroy(session->mutex); | ||
1620 | 1308 | ||
1621 | LOGGER_DEBUG("Terminated session: %p", session); | 1309 | LOGGER_DEBUG("Terminated session: %p", session); |
1622 | free ( session ); | 1310 | free ( session ); |
1623 | return _status; | 1311 | return 0; |
1624 | } | 1312 | } |
1625 | 1313 | ||
1626 | 1314 | int msi_invite ( MSISession *session, | |
1627 | /** | 1315 | int32_t *call_index, |
1628 | * @brief Send invite request to friend_id. | 1316 | const MSICSettings *csettings, |
1629 | * | 1317 | uint32_t rngsec, |
1630 | * @param session Control session. | 1318 | uint32_t friend_id ) |
1631 | * @param call_type Type of the call. Audio or Video(both audio and video) | ||
1632 | * @param rngsec Ringing timeout. | ||
1633 | * @param friend_id The friend. | ||
1634 | * @return int | ||
1635 | */ | ||
1636 | int msi_invite ( MSISession *session, int32_t *call_index, MSICSettings csettings, uint32_t rngsec, uint32_t friend_id ) | ||
1637 | { | 1319 | { |
1638 | pthread_mutex_lock(&session->mutex); | 1320 | pthread_mutex_lock(session->mutex); |
1639 | 1321 | ||
1640 | LOGGER_DEBUG("Session: %p Inviting friend: %u", session, friend_id); | 1322 | LOGGER_DEBUG("Session: %p Inviting friend: %u", session, friend_id); |
1641 | 1323 | ||
@@ -1645,17 +1327,17 @@ int msi_invite ( MSISession *session, int32_t *call_index, MSICSettings csetting | |||
1645 | for (; i < session->max_calls; i ++) | 1327 | for (; i < session->max_calls; i ++) |
1646 | if (session->calls[i] && session->calls[i]->peers[0] == friend_id) { | 1328 | if (session->calls[i] && session->calls[i]->peers[0] == friend_id) { |
1647 | LOGGER_ERROR("Already in a call with friend %d", friend_id); | 1329 | LOGGER_ERROR("Already in a call with friend %d", friend_id); |
1648 | pthread_mutex_unlock(&session->mutex); | 1330 | pthread_mutex_unlock(session->mutex); |
1649 | return -1; | 1331 | return msi_ErrorAlreadyInCallWithPeer; |
1650 | } | 1332 | } |
1651 | 1333 | ||
1652 | 1334 | ||
1653 | MSICall *call = init_call ( session, 1, rngsec ); /* Just one peer for now */ | 1335 | MSICall *call = init_call ( session, 1, rngsec ); /* Just one peer for now */ |
1654 | 1336 | ||
1655 | if ( !call ) { | 1337 | if ( !call ) { |
1656 | pthread_mutex_unlock(&session->mutex); | 1338 | pthread_mutex_unlock(session->mutex); |
1657 | LOGGER_ERROR("Cannot handle more calls"); | 1339 | LOGGER_ERROR("Cannot handle more calls"); |
1658 | return -1; | 1340 | return msi_ErrorReachedCallLimit; |
1659 | } | 1341 | } |
1660 | 1342 | ||
1661 | *call_index = call->call_idx; | 1343 | *call_index = call->call_idx; |
@@ -1664,50 +1346,40 @@ int msi_invite ( MSISession *session, int32_t *call_index, MSICSettings csetting | |||
1664 | 1346 | ||
1665 | add_peer ( call, friend_id ); | 1347 | add_peer ( call, friend_id ); |
1666 | 1348 | ||
1667 | call->csettings_local = csettings; | 1349 | call->csettings_local = *csettings; |
1668 | 1350 | ||
1669 | MSIMessage *msg_invite = msi_new_message ( TypeRequest, invite ); | 1351 | MSIMessage *msg_invite = msi_new_message ( TypeRequest, invite ); |
1670 | 1352 | ||
1671 | msi_msg_set_csettings(msg_invite, &csettings); | 1353 | msi_msg_set_csettings(msg_invite, csettings); |
1672 | send_message ( session, call, msg_invite, friend_id ); | 1354 | send_message ( session, call, msg_invite, friend_id ); |
1673 | free( msg_invite ); | 1355 | free( msg_invite ); |
1674 | 1356 | ||
1675 | call->state = call_inviting; | 1357 | call->state = msi_CallInviting; |
1676 | 1358 | ||
1677 | call->request_timer_id = timer_alloc ( session->timer_handler, handle_timeout, session, call->call_idx, m_deftout ); | 1359 | call->request_timer_id = timer_alloc ( session, handle_timeout, call->call_idx, m_deftout ); |
1678 | 1360 | ||
1679 | LOGGER_DEBUG("Invite sent"); | 1361 | LOGGER_DEBUG("Invite sent"); |
1680 | 1362 | ||
1681 | pthread_mutex_unlock(&session->mutex); | 1363 | pthread_mutex_unlock(session->mutex); |
1682 | 1364 | ||
1683 | return 0; | 1365 | return 0; |
1684 | } | 1366 | } |
1685 | 1367 | ||
1686 | |||
1687 | /** | ||
1688 | * @brief Hangup active call. | ||
1689 | * | ||
1690 | * @param session Control session. | ||
1691 | * @param call_id To which call is this action handled. | ||
1692 | * @return int | ||
1693 | * @retval -1 Error occurred. | ||
1694 | * @retval 0 Success. | ||
1695 | */ | ||
1696 | int msi_hangup ( MSISession *session, int32_t call_index ) | 1368 | int msi_hangup ( MSISession *session, int32_t call_index ) |
1697 | { | 1369 | { |
1698 | pthread_mutex_lock(&session->mutex); | 1370 | pthread_mutex_lock(session->mutex); |
1699 | LOGGER_DEBUG("Session: %p Hanging up call: %u", session, call_index); | 1371 | LOGGER_DEBUG("Session: %p Hanging up call: %u", session, call_index); |
1700 | 1372 | ||
1701 | if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) { | 1373 | if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) { |
1702 | LOGGER_ERROR("Invalid call index!"); | 1374 | LOGGER_ERROR("Invalid call index!"); |
1703 | pthread_mutex_unlock(&session->mutex); | 1375 | pthread_mutex_unlock(session->mutex); |
1704 | return -1; | 1376 | return msi_ErrorNoCall; |
1705 | } | 1377 | } |
1706 | 1378 | ||
1707 | if ( session->calls[call_index]->state != call_active ) { | 1379 | if ( session->calls[call_index]->state != msi_CallActive ) { |
1708 | LOGGER_ERROR("No call with such index or call is not active!"); | 1380 | LOGGER_ERROR("Call is not active!"); |
1709 | pthread_mutex_unlock(&session->mutex); | 1381 | pthread_mutex_unlock(session->mutex); |
1710 | return -1; | 1382 | return msi_ErrorInvalidState; |
1711 | } | 1383 | } |
1712 | 1384 | ||
1713 | MSIMessage *msg_end = msi_new_message ( TypeRequest, end ); | 1385 | MSIMessage *msg_end = msi_new_message ( TypeRequest, end ); |
@@ -1718,70 +1390,64 @@ int msi_hangup ( MSISession *session, int32_t call_index ) | |||
1718 | for ( ; it < session->calls[call_index]->peer_count; it ++ ) | 1390 | for ( ; it < session->calls[call_index]->peer_count; it ++ ) |
1719 | send_message ( session, session->calls[call_index], msg_end, session->calls[call_index]->peers[it] ); | 1391 | send_message ( session, session->calls[call_index], msg_end, session->calls[call_index]->peers[it] ); |
1720 | 1392 | ||
1721 | session->calls[call_index]->state = call_hanged_up; | 1393 | session->calls[call_index]->state = msi_CallOver; |
1722 | 1394 | ||
1723 | free ( msg_end ); | 1395 | free ( msg_end ); |
1724 | 1396 | ||
1725 | session->calls[call_index]->request_timer_id = | 1397 | session->calls[call_index]->request_timer_id = |
1726 | timer_alloc ( session->timer_handler, handle_timeout, session, call_index, m_deftout ); | 1398 | timer_alloc ( session, handle_timeout, call_index, m_deftout ); |
1727 | 1399 | ||
1728 | pthread_mutex_unlock(&session->mutex); | 1400 | pthread_mutex_unlock(session->mutex); |
1729 | return 0; | 1401 | return 0; |
1730 | } | 1402 | } |
1731 | 1403 | ||
1732 | 1404 | int msi_answer ( MSISession *session, int32_t call_index, const MSICSettings *csettings ) | |
1733 | /** | ||
1734 | * @brief Answer active call request. | ||
1735 | * | ||
1736 | * @param session Control session. | ||
1737 | * @param call_id To which call is this action handled. | ||
1738 | * @param call_type Answer with Audio or Video(both). | ||
1739 | * @return int | ||
1740 | */ | ||
1741 | int msi_answer ( MSISession *session, int32_t call_index, MSICSettings csettings ) | ||
1742 | { | 1405 | { |
1743 | pthread_mutex_lock(&session->mutex); | 1406 | pthread_mutex_lock(session->mutex); |
1744 | LOGGER_DEBUG("Session: %p Answering call: %u", session, call_index); | 1407 | LOGGER_DEBUG("Session: %p Answering call: %u", session, call_index); |
1745 | 1408 | ||
1746 | if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) { | 1409 | if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) { |
1747 | LOGGER_ERROR("Invalid call index!"); | 1410 | LOGGER_ERROR("Invalid call index!"); |
1748 | pthread_mutex_unlock(&session->mutex); | 1411 | pthread_mutex_unlock(session->mutex); |
1749 | return -1; | 1412 | return msi_ErrorNoCall; |
1413 | } | ||
1414 | |||
1415 | if ( session->calls[call_index]->state != msi_CallStarting ) { | ||
1416 | LOGGER_ERROR("Call is in invalid state!"); | ||
1417 | pthread_mutex_unlock(session->mutex); | ||
1418 | return msi_ErrorInvalidState; | ||
1750 | } | 1419 | } |
1751 | 1420 | ||
1752 | MSIMessage *msg_starting = msi_new_message ( TypeResponse, starting ); | 1421 | MSIMessage *msg_starting = msi_new_message ( TypeResponse, starting ); |
1753 | 1422 | ||
1754 | session->calls[call_index]->csettings_local = csettings; | 1423 | session->calls[call_index]->csettings_local = *csettings; |
1755 | 1424 | ||
1756 | msi_msg_set_csettings(msg_starting, &csettings); | 1425 | msi_msg_set_csettings(msg_starting, csettings); |
1757 | 1426 | ||
1758 | send_message ( session, session->calls[call_index], msg_starting, session->calls[call_index]->peers[0] ); | 1427 | send_message ( session, session->calls[call_index], msg_starting, session->calls[call_index]->peers[0] ); |
1759 | free ( msg_starting ); | 1428 | free ( msg_starting ); |
1760 | 1429 | ||
1761 | session->calls[call_index]->state = call_active; | 1430 | session->calls[call_index]->state = msi_CallActive; |
1762 | 1431 | ||
1763 | pthread_mutex_unlock(&session->mutex); | 1432 | pthread_mutex_unlock(session->mutex); |
1764 | return 0; | 1433 | return 0; |
1765 | } | 1434 | } |
1766 | 1435 | ||
1767 | |||
1768 | /** | ||
1769 | * @brief Cancel request. | ||
1770 | * | ||
1771 | * @param session Control session. | ||
1772 | * @param call_id To which call is this action handled. | ||
1773 | * @param reason Set optional reason header. Pass NULL if none. | ||
1774 | * @return int | ||
1775 | */ | ||
1776 | int msi_cancel ( MSISession *session, int32_t call_index, uint32_t peer, const char *reason ) | 1436 | int msi_cancel ( MSISession *session, int32_t call_index, uint32_t peer, const char *reason ) |
1777 | { | 1437 | { |
1778 | pthread_mutex_lock(&session->mutex); | 1438 | pthread_mutex_lock(session->mutex); |
1779 | LOGGER_DEBUG("Session: %p Canceling call: %u; reason: %s", session, call_index, reason ? reason : "Unknown"); | 1439 | LOGGER_DEBUG("Session: %p Canceling call: %u; reason: %s", session, call_index, reason ? reason : "Unknown"); |
1780 | 1440 | ||
1781 | if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) { | 1441 | if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) { |
1782 | LOGGER_ERROR("Invalid call index!"); | 1442 | LOGGER_ERROR("Invalid call index!"); |
1783 | pthread_mutex_unlock(&session->mutex); | 1443 | pthread_mutex_unlock(session->mutex); |
1784 | return -1; | 1444 | return msi_ErrorNoCall; |
1445 | } | ||
1446 | |||
1447 | if ( session->calls[call_index]->state != msi_CallInviting ) { | ||
1448 | LOGGER_ERROR("Call is in invalid state: %u", session->calls[call_index]->state); | ||
1449 | pthread_mutex_unlock(session->mutex); | ||
1450 | return msi_ErrorInvalidState; | ||
1785 | } | 1451 | } |
1786 | 1452 | ||
1787 | MSIMessage *msg_cancel = msi_new_message ( TypeRequest, cancel ); | 1453 | MSIMessage *msg_cancel = msi_new_message ( TypeRequest, cancel ); |
@@ -1805,28 +1471,26 @@ int msi_cancel ( MSISession *session, int32_t call_index, uint32_t peer, const c | |||
1805 | free ( msg_cancel ); | 1471 | free ( msg_cancel ); |
1806 | 1472 | ||
1807 | terminate_call ( session, session->calls[call_index] ); | 1473 | terminate_call ( session, session->calls[call_index] ); |
1808 | pthread_mutex_unlock(&session->mutex); | 1474 | pthread_mutex_unlock(session->mutex); |
1809 | 1475 | ||
1810 | return 0; | 1476 | return 0; |
1811 | } | 1477 | } |
1812 | 1478 | ||
1813 | |||
1814 | /** | ||
1815 | * @brief Reject request. | ||
1816 | * | ||
1817 | * @param session Control session. | ||
1818 | * @param call_id To which call is this action handled. | ||
1819 | * @return int | ||
1820 | */ | ||
1821 | int msi_reject ( MSISession *session, int32_t call_index, const char *reason ) | 1479 | int msi_reject ( MSISession *session, int32_t call_index, const char *reason ) |
1822 | { | 1480 | { |
1823 | pthread_mutex_lock(&session->mutex); | 1481 | pthread_mutex_lock(session->mutex); |
1824 | LOGGER_DEBUG("Session: %p Rejecting call: %u; reason: %s", session, call_index, reason ? reason : "Unknown"); | 1482 | LOGGER_DEBUG("Session: %p Rejecting call: %u; reason: %s", session, call_index, reason ? reason : "Unknown"); |
1825 | 1483 | ||
1826 | if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) { | 1484 | if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) { |
1827 | LOGGER_ERROR("Invalid call index!"); | 1485 | LOGGER_ERROR("Invalid call index!"); |
1828 | pthread_mutex_unlock(&session->mutex); | 1486 | pthread_mutex_unlock(session->mutex); |
1829 | return -1; | 1487 | return msi_ErrorNoCall; |
1488 | } | ||
1489 | |||
1490 | if ( session->calls[call_index]->state != msi_CallStarting ) { | ||
1491 | LOGGER_ERROR("Call is in invalid state!"); | ||
1492 | pthread_mutex_unlock(session->mutex); | ||
1493 | return msi_ErrorInvalidState; | ||
1830 | } | 1494 | } |
1831 | 1495 | ||
1832 | MSIMessage *msg_reject = msi_new_message ( TypeRequest, reject ); | 1496 | MSIMessage *msg_reject = msi_new_message ( TypeRequest, reject ); |
@@ -1850,62 +1514,69 @@ int msi_reject ( MSISession *session, int32_t call_index, const char *reason ) | |||
1850 | session->calls[call_index]->peers[session->calls[call_index]->peer_count - 1] ); | 1514 | session->calls[call_index]->peers[session->calls[call_index]->peer_count - 1] ); |
1851 | free ( msg_reject ); | 1515 | free ( msg_reject ); |
1852 | 1516 | ||
1853 | session->calls[call_index]->state = call_hanged_up; | 1517 | session->calls[call_index]->state = msi_CallOver; |
1854 | session->calls[call_index]->request_timer_id = | 1518 | session->calls[call_index]->request_timer_id = |
1855 | timer_alloc ( session->timer_handler, handle_timeout, session, call_index, m_deftout ); | 1519 | timer_alloc ( session, handle_timeout, call_index, m_deftout ); |
1856 | 1520 | ||
1857 | pthread_mutex_unlock(&session->mutex); | 1521 | pthread_mutex_unlock(session->mutex); |
1858 | return 0; | 1522 | return 0; |
1859 | } | 1523 | } |
1860 | 1524 | ||
1525 | int msi_stopcall ( MSISession *session, int32_t call_index ) | ||
1526 | { | ||
1527 | pthread_mutex_lock(session->mutex); | ||
1528 | LOGGER_DEBUG("Session: %p Stopping call index: %u", session, call_index); | ||
1861 | 1529 | ||
1862 | /** | 1530 | if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) { |
1863 | * @brief Send invite request to friend_id. | 1531 | pthread_mutex_unlock(session->mutex); |
1864 | * | 1532 | return msi_ErrorNoCall; |
1865 | * @param session Control session. | 1533 | } |
1866 | * @param call_index Call index. | 1534 | |
1867 | * @param call_type Type of the call. Audio or Video(both audio and video) | 1535 | /* just terminate it */ |
1868 | * @param rngsec Ringing timeout. | 1536 | |
1869 | * @param friend_id The friend. | 1537 | terminate_call ( session, session->calls[call_index] ); |
1870 | * @return int | 1538 | |
1871 | */ | 1539 | pthread_mutex_unlock(session->mutex); |
1872 | int msi_change_csettings(MSISession *session, int32_t call_index, MSICSettings csettings) | 1540 | return 0; |
1541 | } | ||
1542 | |||
1543 | int msi_change_csettings(MSISession *session, int32_t call_index, const MSICSettings *csettings) | ||
1873 | { | 1544 | { |
1874 | pthread_mutex_lock(&session->mutex); | 1545 | pthread_mutex_lock(session->mutex); |
1875 | 1546 | ||
1876 | LOGGER_DEBUG("Changing media on call: %d", call_index); | 1547 | LOGGER_DEBUG("Changing media on call: %d", call_index); |
1877 | 1548 | ||
1878 | if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) { | 1549 | if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) { |
1879 | LOGGER_ERROR("Invalid call index!"); | 1550 | LOGGER_ERROR("Invalid call index!"); |
1880 | pthread_mutex_unlock(&session->mutex); | 1551 | pthread_mutex_unlock(session->mutex); |
1881 | return -1; | 1552 | return msi_ErrorNoCall; |
1882 | } | 1553 | } |
1883 | 1554 | ||
1884 | MSICall *call = session->calls[call_index]; | 1555 | MSICall *call = session->calls[call_index]; |
1885 | 1556 | ||
1886 | if ( call->state != call_active ) { | 1557 | if ( call->state != msi_CallActive ) { |
1887 | LOGGER_ERROR("Call is not active!"); | 1558 | LOGGER_ERROR("Call is not active!"); |
1888 | pthread_mutex_unlock(&session->mutex); | 1559 | pthread_mutex_unlock(session->mutex); |
1889 | return -1; | 1560 | return msi_ErrorInvalidState; |
1890 | } | 1561 | } |
1891 | 1562 | ||
1892 | MSICSettings *local = &call->csettings_local; | 1563 | MSICSettings *local = &call->csettings_local; |
1893 | 1564 | ||
1894 | if ( | 1565 | if ( |
1895 | local->call_type == csettings.call_type && | 1566 | local->call_type == csettings->call_type && |
1896 | local->video_bitrate == csettings.video_bitrate && | 1567 | local->video_bitrate == csettings->video_bitrate && |
1897 | local->max_video_width == csettings.max_video_width && | 1568 | local->max_video_width == csettings->max_video_width && |
1898 | local->max_video_height == csettings.max_video_height && | 1569 | local->max_video_height == csettings->max_video_height && |
1899 | local->audio_bitrate == csettings.audio_bitrate && | 1570 | local->audio_bitrate == csettings->audio_bitrate && |
1900 | local->audio_frame_duration == csettings.audio_frame_duration && | 1571 | local->audio_frame_duration == csettings->audio_frame_duration && |
1901 | local->audio_sample_rate == csettings.audio_sample_rate && | 1572 | local->audio_sample_rate == csettings->audio_sample_rate && |
1902 | local->audio_channels == csettings.audio_channels ) { | 1573 | local->audio_channels == csettings->audio_channels ) { |
1903 | LOGGER_ERROR("Call is already set accordingly!"); | 1574 | LOGGER_ERROR("Call is already set accordingly!"); |
1904 | pthread_mutex_unlock(&session->mutex); | 1575 | pthread_mutex_unlock(session->mutex); |
1905 | return -1; | 1576 | return -1; |
1906 | } | 1577 | } |
1907 | 1578 | ||
1908 | *local = csettings; | 1579 | *local = *csettings; |
1909 | 1580 | ||
1910 | MSIMessage *msg_invite = msi_new_message ( TypeRequest, invite ); | 1581 | MSIMessage *msg_invite = msi_new_message ( TypeRequest, invite ); |
1911 | 1582 | ||
@@ -1915,33 +1586,29 @@ int msi_change_csettings(MSISession *session, int32_t call_index, MSICSettings c | |||
1915 | 1586 | ||
1916 | LOGGER_DEBUG("Request for media change sent"); | 1587 | LOGGER_DEBUG("Request for media change sent"); |
1917 | 1588 | ||
1918 | pthread_mutex_unlock(&session->mutex); | 1589 | pthread_mutex_unlock(session->mutex); |
1919 | 1590 | ||
1920 | return 0; | 1591 | return 0; |
1921 | } | 1592 | } |
1922 | 1593 | ||
1923 | 1594 | void msi_do(MSISession *session) | |
1924 | /** | ||
1925 | * @brief Terminate the current call. | ||
1926 | * | ||
1927 | * @param session Control session. | ||
1928 | * @param call_id To which call is this action handled. | ||
1929 | * @return int | ||
1930 | */ | ||
1931 | int msi_stopcall ( MSISession *session, int32_t call_index ) | ||
1932 | { | 1595 | { |
1933 | pthread_mutex_lock(&session->mutex); | 1596 | pthread_mutex_lock(session->mutex); |
1934 | LOGGER_DEBUG("Session: %p Stopping call index: %u", session, call_index); | ||
1935 | 1597 | ||
1936 | if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) { | 1598 | TimerHandler *timer = session->timer_handler; |
1937 | pthread_mutex_unlock(&session->mutex); | ||
1938 | return -1; | ||
1939 | } | ||
1940 | 1599 | ||
1941 | /* just terminate it */ | 1600 | uint64_t time = current_time_monotonic(); |
1942 | 1601 | ||
1943 | terminate_call ( session, session->calls[call_index] ); | 1602 | while ( timer->timers[0] && timer->timers[0]->timeout < time ) { |
1603 | LOGGER_DEBUG("Executing timer assigned at: %d", timer->timers[0]->timeout); | ||
1944 | 1604 | ||
1945 | pthread_mutex_unlock(&session->mutex); | 1605 | int id = timer->timers[0]->id; |
1946 | return 0; | 1606 | timer->timers[0]->func(timer->timers[0]); |
1607 | |||
1608 | /* In case function has released timer */ | ||
1609 | if (timer->timers[0] && timer->timers[0]->id == id) | ||
1610 | timer_release(timer, id); | ||
1611 | } | ||
1612 | |||
1613 | pthread_mutex_unlock(session->mutex); | ||
1947 | } | 1614 | } |
diff --git a/toxav/msi.h b/toxav/msi.h index 64fa0881..660df05e 100644 --- a/toxav/msi.h +++ b/toxav/msi.h | |||
@@ -25,37 +25,37 @@ | |||
25 | #include <inttypes.h> | 25 | #include <inttypes.h> |
26 | #include <pthread.h> | 26 | #include <pthread.h> |
27 | 27 | ||
28 | #include "codec.h" | ||
28 | #include "../toxcore/Messenger.h" | 29 | #include "../toxcore/Messenger.h" |
29 | 30 | ||
30 | typedef uint8_t MSICallIDType[12]; | 31 | typedef uint8_t MSICallIDType[12]; |
31 | typedef uint8_t MSIReasonStrType[255]; | 32 | typedef uint8_t MSIReasonStrType[255]; |
32 | typedef void ( *MSICallbackType ) ( void *agent, int32_t call_idx, void *arg ); | 33 | typedef void ( *MSICallbackType ) ( void *agent, int32_t call_idx, void *arg ); |
33 | 34 | ||
34 | |||
35 | /** | 35 | /** |
36 | * @brief Call type identifier. Also used as rtp callback prefix. | 36 | * Call type identifier. Also used as rtp callback prefix. |
37 | */ | 37 | */ |
38 | typedef enum { | 38 | typedef enum { |
39 | type_audio = 192, | 39 | msi_TypeAudio = 192, |
40 | type_video | 40 | msi_TypeVideo |
41 | } MSICallType; | 41 | } MSICallType; |
42 | 42 | ||
43 | 43 | ||
44 | /** | 44 | /** |
45 | * @brief Call state identifiers. | 45 | * Call state identifiers. |
46 | */ | 46 | */ |
47 | typedef enum { | 47 | typedef enum { |
48 | call_inviting, /* when sending call invite */ | 48 | msi_CallInviting, /* when sending call invite */ |
49 | call_starting, /* when getting call invite */ | 49 | msi_CallStarting, /* when getting call invite */ |
50 | call_active, | 50 | msi_CallActive, |
51 | call_hold, | 51 | msi_CallHold, |
52 | call_hanged_up | 52 | msi_CallOver |
53 | 53 | ||
54 | } MSICallState; | 54 | } MSICallState; |
55 | 55 | ||
56 | 56 | ||
57 | /** | 57 | /** |
58 | * @brief Encoding settings. | 58 | * Encoding settings. |
59 | */ | 59 | */ |
60 | typedef struct _MSICodecSettings { | 60 | typedef struct _MSICodecSettings { |
61 | MSICallType call_type; | 61 | MSICallType call_type; |
@@ -72,46 +72,41 @@ typedef struct _MSICodecSettings { | |||
72 | 72 | ||
73 | 73 | ||
74 | /** | 74 | /** |
75 | * @brief Callbacks ids that handle the states | 75 | * Callbacks ids that handle the states |
76 | */ | 76 | */ |
77 | typedef enum { | 77 | typedef enum { |
78 | /* Requests */ | 78 | msi_OnInvite, /* Incoming call */ |
79 | MSI_OnInvite, | 79 | msi_OnRinging, /* When peer is ready to accept/reject the call */ |
80 | MSI_OnStart, | 80 | msi_OnStart, /* Call (RTP transmission) started */ |
81 | MSI_OnCancel, | 81 | msi_OnCancel, /* The side that initiated call canceled invite */ |
82 | MSI_OnReject, | 82 | msi_OnReject, /* The side that was invited rejected the call */ |
83 | MSI_OnEnd, | 83 | msi_OnEnd, /* Call that was active ended */ |
84 | 84 | msi_OnRequestTimeout, /* When the requested action didn't get response in specified time */ | |
85 | /* Responses */ | 85 | msi_OnPeerTimeout, /* Peer timed out; stop the call */ |
86 | MSI_OnRinging, | 86 | msi_OnPeerCSChange, /* Peer requested Csettings change */ |
87 | MSI_OnStarting, | 87 | msi_OnSelfCSChange /* Csettings change confirmation */ |
88 | MSI_OnEnding, | ||
89 | |||
90 | /* Protocol */ | ||
91 | MSI_OnRequestTimeout, | ||
92 | MSI_OnPeerTimeout, | ||
93 | MSI_OnMediaChange | ||
94 | } MSICallbackID; | 88 | } MSICallbackID; |
95 | 89 | ||
96 | /** | 90 | /** |
97 | * @brief Callbacks container | 91 | * Errors |
98 | */ | 92 | */ |
99 | typedef struct _MSICallbackCont { | 93 | typedef enum { |
100 | MSICallbackType function; | 94 | msi_ErrorNoCall = -20, /* Trying to perform call action while not in a call */ |
101 | void *data; | 95 | msi_ErrorInvalidState = -21, /* Trying to perform call action while in invalid state*/ |
102 | } MSICallbackCont; | 96 | msi_ErrorAlreadyInCallWithPeer = -22, /* Trying to call peer when already in a call with peer */ |
97 | msi_ErrorReachedCallLimit = -23, /* Cannot handle more calls */ | ||
98 | } MSIError; | ||
103 | 99 | ||
104 | /** | 100 | /** |
105 | * @brief The call struct. | 101 | * The call struct. |
106 | * | ||
107 | */ | 102 | */ |
108 | typedef struct _MSICall { /* Call info structure */ | 103 | typedef struct _MSICall { /* Call info structure */ |
109 | struct _MSISession *session; /* Session pointer */ | 104 | struct _MSISession *session; /* Session pointer */ |
110 | 105 | ||
111 | MSICallState state; | 106 | MSICallState state; |
112 | 107 | ||
113 | MSICSettings csettings_local; /* Local call settings */ | 108 | MSICSettings csettings_local; /* Local call settings */ |
114 | MSICSettings *csettings_peer; /* Peers call settings */ | 109 | MSICSettings *csettings_peer; /* Peers call settings */ |
115 | 110 | ||
116 | MSICallIDType id; /* Random value identifying the call */ | 111 | MSICallIDType id; /* Random value identifying the call */ |
117 | 112 | ||
@@ -120,8 +115,6 @@ typedef struct _MSICall { /* Call info structure */ | |||
120 | int request_timer_id; /* Timer id for outgoing request/action */ | 115 | int request_timer_id; /* Timer id for outgoing request/action */ |
121 | int ringing_timer_id; /* Timer id for ringing timeout */ | 116 | int ringing_timer_id; /* Timer id for ringing timeout */ |
122 | 117 | ||
123 | |||
124 | pthread_mutex_t mutex; /* */ | ||
125 | uint32_t *peers; | 118 | uint32_t *peers; |
126 | uint16_t peer_count; | 119 | uint16_t peer_count; |
127 | 120 | ||
@@ -130,8 +123,7 @@ typedef struct _MSICall { /* Call info structure */ | |||
130 | 123 | ||
131 | 124 | ||
132 | /** | 125 | /** |
133 | * @brief Control session struct | 126 | * Control session struct |
134 | * | ||
135 | */ | 127 | */ |
136 | typedef struct _MSISession { | 128 | typedef struct _MSISession { |
137 | 129 | ||
@@ -143,125 +135,71 @@ typedef struct _MSISession { | |||
143 | Messenger *messenger_handle; | 135 | Messenger *messenger_handle; |
144 | 136 | ||
145 | uint32_t frequ; | 137 | uint32_t frequ; |
146 | uint32_t call_timeout; /* Time of the timeout for some action to end; 0 if infinite */ | 138 | uint32_t call_timeout; /* Time of the timeout for some action to end; 0 if infinite */ |
147 | 139 | ||
148 | pthread_mutex_t mutex; | 140 | pthread_mutex_t mutex[1]; |
149 | 141 | ||
150 | void *timer_handler; | 142 | void *timer_handler; |
151 | MSICallbackCont callbacks[11]; /* Callbacks used by this session */ | 143 | PAIR(MSICallbackType, void *) callbacks[10]; |
152 | } MSISession; | 144 | } MSISession; |
153 | 145 | ||
154 | /** | 146 | /** |
155 | * @brief Callback setter. | 147 | * Start the control session. |
156 | * | ||
157 | * @param session The container. | ||
158 | * @param callback The callback. | ||
159 | * @param id The id. | ||
160 | * @return void | ||
161 | */ | 148 | */ |
162 | void msi_register_callback(MSISession *session, MSICallbackType callback, MSICallbackID id, void *userdata); | 149 | MSISession *msi_new ( Messenger *messenger, int32_t max_calls ); |
163 | |||
164 | 150 | ||
165 | /** | 151 | /** |
166 | * @brief Start the control session. | 152 | * Terminate control session. |
167 | * | ||
168 | * @param messenger Tox* object. | ||
169 | * @param max_calls Amount of calls possible | ||
170 | * @return MSISession* The created session. | ||
171 | * @retval NULL Error occurred. | ||
172 | */ | 153 | */ |
173 | MSISession *msi_init_session ( Messenger *messenger, int32_t max_calls ); | 154 | int msi_kill ( MSISession *session ); |
174 | |||
175 | 155 | ||
176 | /** | 156 | /** |
177 | * @brief Terminate control session. | 157 | * Callback setter. |
178 | * | ||
179 | * @param session The session | ||
180 | * @return int | ||
181 | */ | 158 | */ |
182 | int msi_terminate_session ( MSISession *session ); | 159 | void msi_register_callback(MSISession *session, MSICallbackType callback, MSICallbackID id, void *userdata); |
183 | |||
184 | 160 | ||
185 | /** | 161 | /** |
186 | * @brief Send invite request to friend_id. | 162 | * Send invite request to friend_id. |
187 | * | ||
188 | * @param session Control session. | ||
189 | * @param call_index Set to new call index. | ||
190 | * @param call_type Type of the call. Audio or Video(both audio and video) | ||
191 | * @param rngsec Ringing timeout. | ||
192 | * @param friend_id The friend. | ||
193 | * @return int | ||
194 | */ | 163 | */ |
195 | int msi_invite ( MSISession *session, int32_t *call_index, MSICSettings csettings, uint32_t rngsec, | 164 | int msi_invite ( MSISession *session, |
165 | int32_t *call_index, | ||
166 | const MSICSettings *csettings, | ||
167 | uint32_t rngsec, | ||
196 | uint32_t friend_id ); | 168 | uint32_t friend_id ); |
197 | 169 | ||
198 | |||
199 | /** | 170 | /** |
200 | * @brief Hangup active call. | 171 | * Hangup active call. |
201 | * | ||
202 | * @param session Control session. | ||
203 | * @param call_index To which call is this action handled. | ||
204 | * @return int | ||
205 | * @retval -1 Error occurred. | ||
206 | * @retval 0 Success. | ||
207 | */ | 172 | */ |
208 | int msi_hangup ( MSISession *session, int32_t call_index ); | 173 | int msi_hangup ( MSISession *session, int32_t call_index ); |
209 | 174 | ||
210 | |||
211 | /** | 175 | /** |
212 | * @brief Answer active call request. | 176 | * Answer active call request. |
213 | * | ||
214 | * @param session Control session. | ||
215 | * @param call_index To which call is this action handled. | ||
216 | * @param call_type Answer with Audio or Video(both). | ||
217 | * @return int | ||
218 | */ | 177 | */ |
219 | int msi_answer ( MSISession *session, int32_t call_index, MSICSettings csettings ); | 178 | int msi_answer ( MSISession *session, int32_t call_index, const MSICSettings *csettings ); |
220 | |||
221 | 179 | ||
222 | /** | 180 | /** |
223 | * @brief Cancel request. | 181 | * Cancel request. |
224 | * | ||
225 | * @param session Control session. | ||
226 | * @param call_index To which call is this action handled. | ||
227 | * @param peer To which peer. | ||
228 | * @param reason Set optional reason header. Pass NULL if none. | ||
229 | * @return int | ||
230 | */ | 182 | */ |
231 | int msi_cancel ( MSISession *session, int32_t call_index, uint32_t peer, const char *reason ); | 183 | int msi_cancel ( MSISession *session, int32_t call_index, uint32_t peer, const char *reason ); |
232 | 184 | ||
233 | |||
234 | /** | 185 | /** |
235 | * @brief Reject request. | 186 | * Reject incoming call. |
236 | * | ||
237 | * @param session Control session. | ||
238 | * @param call_index To which call is this action handled. | ||
239 | * @param reason Set optional reason header. Pass NULL if none. | ||
240 | * @return int | ||
241 | */ | 187 | */ |
242 | int msi_reject ( MSISession *session, int32_t call_index, const char *reason ); | 188 | int msi_reject ( MSISession *session, int32_t call_index, const char *reason ); |
243 | 189 | ||
244 | |||
245 | /** | 190 | /** |
246 | * @brief Send invite request to friend_id. | 191 | * Terminate the call. |
247 | * | ||
248 | * @param session Control session. | ||
249 | * @param call_index Call index. | ||
250 | * @param call_type Type of the call. Audio or Video(both audio and video) | ||
251 | * @param rngsec Ringing timeout. | ||
252 | * @param friend_id The friend. | ||
253 | * @return int | ||
254 | */ | 192 | */ |
255 | int msi_change_csettings ( MSISession *session, int32_t call_index, MSICSettings csettings ); | 193 | int msi_stopcall ( MSISession *session, int32_t call_index ); |
256 | 194 | ||
195 | /** | ||
196 | * Change codec settings of the current call. | ||
197 | */ | ||
198 | int msi_change_csettings ( MSISession *session, int32_t call_index, const MSICSettings *csettings ); | ||
257 | 199 | ||
258 | /** | 200 | /** |
259 | * @brief Terminate the current call. | 201 | * Main msi loop |
260 | * | ||
261 | * @param session Control session. | ||
262 | * @param call_index To which call is this action handled. | ||
263 | * @return int | ||
264 | */ | 202 | */ |
265 | int msi_stopcall ( MSISession *session, int32_t call_index ); | 203 | void msi_do( MSISession *session ); |
266 | 204 | ||
267 | #endif /* __TOXMSI */ | 205 | #endif /* __TOXMSI */ |
diff --git a/toxav/rtp.c b/toxav/rtp.c index de6c9c41..63c2cdcb 100644 --- a/toxav/rtp.c +++ b/toxav/rtp.c | |||
@@ -28,7 +28,7 @@ | |||
28 | 28 | ||
29 | #include "rtp.h" | 29 | #include "rtp.h" |
30 | #include <stdlib.h> | 30 | #include <stdlib.h> |
31 | void toxav_handle_packet(RTPSession *_session, RTPMessage *_msg); | 31 | void queue_message(RTPSession *_session, RTPMessage *_msg); |
32 | 32 | ||
33 | #define size_32 4 | 33 | #define size_32 4 |
34 | 34 | ||
@@ -47,15 +47,9 @@ void toxav_handle_packet(RTPSession *_session, RTPMessage *_msg); | |||
47 | #define GET_SETTING_PAYLOAD(_h) ((_h->marker_payloadt) & 0x7f) | 47 | #define GET_SETTING_PAYLOAD(_h) ((_h->marker_payloadt) & 0x7f) |
48 | 48 | ||
49 | /** | 49 | /** |
50 | * @brief Checks if message came in late. | 50 | * Checks if message came in late. |
51 | * | ||
52 | * @param session Control session. | ||
53 | * @param msg The message. | ||
54 | * @return int | ||
55 | * @retval -1 The message came in order. | ||
56 | * @retval 0 The message came late. | ||
57 | */ | 51 | */ |
58 | inline__ int check_late_message (RTPSession *session, RTPMessage *msg) | 52 | static int check_late_message (RTPSession *session, RTPMessage *msg) |
59 | { | 53 | { |
60 | /* | 54 | /* |
61 | * Check Sequence number. If this new msg has lesser number then the session->rsequnum | 55 | * Check Sequence number. If this new msg has lesser number then the session->rsequnum |
@@ -67,12 +61,7 @@ inline__ int check_late_message (RTPSession *session, RTPMessage *msg) | |||
67 | 61 | ||
68 | 62 | ||
69 | /** | 63 | /** |
70 | * @brief Extracts header from payload. | 64 | * Extracts header from payload. |
71 | * | ||
72 | * @param payload The payload. | ||
73 | * @param length The size of payload. | ||
74 | * @return RTPHeader* Extracted header. | ||
75 | * @retval NULL Error occurred while extracting header. | ||
76 | */ | 65 | */ |
77 | RTPHeader *extract_header ( const uint8_t *payload, int length ) | 66 | RTPHeader *extract_header ( const uint8_t *payload, int length ) |
78 | { | 67 | { |
@@ -81,29 +70,30 @@ RTPHeader *extract_header ( const uint8_t *payload, int length ) | |||
81 | return NULL; | 70 | return NULL; |
82 | } | 71 | } |
83 | 72 | ||
84 | RTPHeader *_retu = calloc(1, sizeof (RTPHeader)); | 73 | RTPHeader *retu = calloc(1, sizeof (RTPHeader)); |
85 | 74 | ||
86 | if ( !_retu ) { | 75 | if ( !retu ) { |
87 | LOGGER_WARNING("Alloc failed! Program might misbehave!"); | 76 | LOGGER_WARNING("Alloc failed! Program might misbehave!"); |
88 | return NULL; | 77 | return NULL; |
89 | } | 78 | } |
90 | 79 | ||
91 | bytes_to_U16(&_retu->sequnum, payload); | 80 | memcpy(&retu->sequnum, payload, sizeof(retu->sequnum)); |
81 | retu->sequnum = ntohs(retu->sequnum); | ||
92 | 82 | ||
93 | const uint8_t *_it = payload + 2; | 83 | const uint8_t *it = payload + 2; |
94 | 84 | ||
95 | _retu->flags = *_it; | 85 | retu->flags = *it; |
96 | ++_it; | 86 | ++it; |
97 | 87 | ||
98 | /* This indicates if the first 2 bits are valid. | 88 | /* This indicates if the first 2 bits are valid. |
99 | * Now it may happen that this is out of order but | 89 | * Now it may happen that this is out of order but |
100 | * it cuts down chances of parsing some invalid value | 90 | * it cuts down chances of parsing some invalid value |
101 | */ | 91 | */ |
102 | 92 | ||
103 | if ( GET_FLAG_VERSION(_retu) != RTP_VERSION ) { | 93 | if ( GET_FLAG_VERSION(retu) != RTP_VERSION ) { |
104 | /* Deallocate */ | 94 | /* Deallocate */ |
105 | LOGGER_WARNING("Invalid version!"); | 95 | LOGGER_WARNING("Invalid version!"); |
106 | free(_retu); | 96 | free(retu); |
107 | return NULL; | 97 | return NULL; |
108 | } | 98 | } |
109 | 99 | ||
@@ -111,297 +101,276 @@ RTPHeader *extract_header ( const uint8_t *payload, int length ) | |||
111 | * Added a check for the size of the header little sooner so | 101 | * Added a check for the size of the header little sooner so |
112 | * I don't need to parse the other stuff if it's bad | 102 | * I don't need to parse the other stuff if it's bad |
113 | */ | 103 | */ |
114 | uint8_t _cc = GET_FLAG_CSRCC ( _retu ); | 104 | uint8_t cc = GET_FLAG_CSRCC ( retu ); |
115 | int _length = 12 /* Minimum header len */ + ( _cc * 4 ); | 105 | int total = 12 /* Minimum header len */ + ( cc * 4 ); |
116 | 106 | ||
117 | if ( length < _length ) { | 107 | if ( length < total ) { |
118 | /* Deallocate */ | 108 | /* Deallocate */ |
119 | LOGGER_WARNING("Length invalid!"); | 109 | LOGGER_WARNING("Length invalid!"); |
120 | free(_retu); | 110 | free(retu); |
121 | return NULL; | 111 | return NULL; |
122 | } | 112 | } |
123 | 113 | ||
124 | memset(_retu->csrc, 0, 16 * sizeof (uint32_t)); | 114 | memset(retu->csrc, 0, 16 * sizeof (uint32_t)); |
125 | 115 | ||
126 | _retu->marker_payloadt = *_it; | 116 | retu->marker_payloadt = *it; |
127 | ++_it; | 117 | ++it; |
128 | _retu->length = _length; | 118 | retu->length = total; |
129 | 119 | ||
130 | 120 | ||
131 | bytes_to_U32(&_retu->timestamp, _it); | 121 | memcpy(&retu->timestamp, it, sizeof(retu->timestamp)); |
132 | _it += 4; | 122 | retu->timestamp = ntohl(retu->timestamp); |
133 | bytes_to_U32(&_retu->ssrc, _it); | 123 | it += 4; |
124 | memcpy(&retu->ssrc, it, sizeof(retu->ssrc)); | ||
125 | retu->ssrc = ntohl(retu->ssrc); | ||
134 | 126 | ||
135 | uint8_t _x; | 127 | uint8_t x; |
136 | 128 | ||
137 | for ( _x = 0; _x < _cc; _x++ ) { | 129 | for ( x = 0; x < cc; x++ ) { |
138 | _it += 4; | 130 | it += 4; |
139 | bytes_to_U32(&(_retu->csrc[_x]), _it); | 131 | memcpy(&retu->csrc[x], it, sizeof(retu->csrc[x])); |
132 | retu->csrc[x] = ntohl(retu->csrc[x]); | ||
140 | } | 133 | } |
141 | 134 | ||
142 | return _retu; | 135 | return retu; |
143 | } | 136 | } |
144 | 137 | ||
145 | /** | 138 | /** |
146 | * @brief Extracts external header from payload. Must be called AFTER extract_header()! | 139 | * Extracts external header from payload. Must be called AFTER extract_header()! |
147 | * | ||
148 | * @param payload The ITERATED payload. | ||
149 | * @param length The size of payload. | ||
150 | * @return RTPExtHeader* Extracted extension header. | ||
151 | * @retval NULL Error occurred while extracting extension header. | ||
152 | */ | 140 | */ |
153 | RTPExtHeader *extract_ext_header ( const uint8_t *payload, uint16_t length ) | 141 | RTPExtHeader *extract_ext_header ( const uint8_t *payload, uint16_t length ) |
154 | { | 142 | { |
155 | const uint8_t *_it = payload; | 143 | const uint8_t *it = payload; |
156 | 144 | ||
157 | RTPExtHeader *_retu = calloc(1, sizeof (RTPExtHeader)); | 145 | RTPExtHeader *retu = calloc(1, sizeof (RTPExtHeader)); |
158 | 146 | ||
159 | if ( !_retu ) { | 147 | if ( !retu ) { |
160 | LOGGER_WARNING("Alloc failed! Program might misbehave!"); | 148 | LOGGER_WARNING("Alloc failed! Program might misbehave!"); |
161 | return NULL; | 149 | return NULL; |
162 | } | 150 | } |
163 | 151 | ||
164 | uint16_t _ext_length; | 152 | uint16_t ext_length; |
165 | bytes_to_U16(&_ext_length, _it); | 153 | memcpy(&ext_length, it, sizeof(ext_length)); |
166 | _it += 2; | 154 | ext_length = ntohs(ext_length); |
155 | it += 2; | ||
167 | 156 | ||
168 | 157 | ||
169 | if ( length < ( _ext_length * sizeof(uint32_t) ) ) { | 158 | if ( length < ( ext_length * sizeof(uint32_t) ) ) { |
170 | LOGGER_WARNING("Length invalid!"); | 159 | LOGGER_WARNING("Length invalid!"); |
171 | free(_retu); | 160 | free(retu); |
172 | return NULL; | 161 | return NULL; |
173 | } | 162 | } |
174 | 163 | ||
175 | _retu->length = _ext_length; | 164 | retu->length = ext_length; |
176 | bytes_to_U16(&_retu->type, _it); | 165 | memcpy(&retu->type, it, sizeof(retu->type)); |
177 | _it += 2; | 166 | retu->type = ntohs(retu->type); |
167 | it += 2; | ||
178 | 168 | ||
179 | if ( !(_retu->table = calloc(_ext_length, sizeof (uint32_t))) ) { | 169 | if ( !(retu->table = calloc(ext_length, sizeof (uint32_t))) ) { |
180 | LOGGER_WARNING("Alloc failed! Program might misbehave!"); | 170 | LOGGER_WARNING("Alloc failed! Program might misbehave!"); |
181 | free(_retu); | 171 | free(retu); |
182 | return NULL; | 172 | return NULL; |
183 | } | 173 | } |
184 | 174 | ||
185 | uint16_t _x; | 175 | uint16_t x; |
186 | 176 | ||
187 | for ( _x = 0; _x < _ext_length; _x++ ) { | 177 | for ( x = 0; x < ext_length; x++ ) { |
188 | _it += 4; | 178 | it += 4; |
189 | bytes_to_U32(&(_retu->table[_x]), _it); | 179 | memcpy(&(retu->table[x]), it, sizeof(retu->table[x])); |
180 | retu->table[x] = ntohl(retu->table[x]); | ||
190 | } | 181 | } |
191 | 182 | ||
192 | return _retu; | 183 | return retu; |
193 | } | 184 | } |
194 | 185 | ||
195 | /** | 186 | /** |
196 | * @brief Adds header to payload. Make sure _payload_ has enough space. | 187 | * Adds header to payload. Make sure _payload_ has enough space. |
197 | * | ||
198 | * @param header The header. | ||
199 | * @param payload The payload. | ||
200 | * @return uint8_t* Iterated position. | ||
201 | */ | 188 | */ |
202 | uint8_t *add_header ( RTPHeader *header, uint8_t *payload ) | 189 | uint8_t *add_header ( RTPHeader *header, uint8_t *payload ) |
203 | { | 190 | { |
204 | uint8_t _cc = GET_FLAG_CSRCC ( header ); | 191 | uint8_t cc = GET_FLAG_CSRCC ( header ); |
205 | 192 | uint8_t *it = payload; | |
206 | uint8_t *_it = payload; | 193 | uint16_t sequnum; |
194 | uint32_t timestamp; | ||
195 | uint32_t ssrc; | ||
196 | uint32_t csrc; | ||
207 | 197 | ||
208 | 198 | ||
209 | /* Add sequence number first */ | 199 | /* Add sequence number first */ |
210 | U16_to_bytes(_it, header->sequnum); | 200 | sequnum = htons(header->sequnum); |
211 | _it += 2; | 201 | memcpy(it, &sequnum, sizeof(sequnum)); |
202 | it += 2; | ||
212 | 203 | ||
213 | *_it = header->flags; | 204 | *it = header->flags; |
214 | ++_it; | 205 | ++it; |
215 | *_it = header->marker_payloadt; | 206 | *it = header->marker_payloadt; |
216 | ++_it; | 207 | ++it; |
217 | 208 | ||
218 | 209 | ||
219 | U32_to_bytes( _it, header->timestamp); | 210 | timestamp = htonl(header->timestamp); |
220 | _it += 4; | 211 | memcpy(it, ×tamp, sizeof(timestamp)); |
221 | U32_to_bytes( _it, header->ssrc); | 212 | it += 4; |
213 | ssrc = htonl(header->ssrc); | ||
214 | memcpy(it, &ssrc, sizeof(ssrc)); | ||
222 | 215 | ||
223 | uint8_t _x; | 216 | uint8_t x; |
224 | 217 | ||
225 | for ( _x = 0; _x < _cc; _x++ ) { | 218 | for ( x = 0; x < cc; x++ ) { |
226 | _it += 4; | 219 | it += 4; |
227 | U32_to_bytes( _it, header->csrc[_x]); | 220 | csrc = htonl(header->csrc[x]); |
221 | memcpy(it, &csrc, sizeof(csrc)); | ||
228 | } | 222 | } |
229 | 223 | ||
230 | return _it + 4; | 224 | return it + 4; |
231 | } | 225 | } |
232 | 226 | ||
233 | /** | 227 | /** |
234 | * @brief Adds extension header to payload. Make sure _payload_ has enough space. | 228 | * Adds extension header to payload. Make sure _payload_ has enough space. |
235 | * | ||
236 | * @param header The header. | ||
237 | * @param payload The payload. | ||
238 | * @return uint8_t* Iterated position. | ||
239 | */ | 229 | */ |
240 | uint8_t *add_ext_header ( RTPExtHeader *header, uint8_t *payload ) | 230 | uint8_t *add_ext_header ( RTPExtHeader *header, uint8_t *payload ) |
241 | { | 231 | { |
242 | uint8_t *_it = payload; | 232 | uint8_t *it = payload; |
243 | 233 | uint16_t length; | |
244 | U16_to_bytes(_it, header->length); | 234 | uint16_t type; |
245 | _it += 2; | 235 | uint32_t entry; |
246 | U16_to_bytes(_it, header->type); | 236 | |
247 | _it -= 2; /* Return to 0 position */ | 237 | length = htons(header->length); |
238 | memcpy(it, &length, sizeof(length)); | ||
239 | it += 2; | ||
240 | type = htons(header->type); | ||
241 | memcpy(it, &type, sizeof(type)); | ||
242 | it -= 2; /* Return to 0 position */ | ||
248 | 243 | ||
249 | if ( header->table ) { | 244 | if ( header->table ) { |
250 | uint16_t _x; | ||
251 | 245 | ||
252 | for ( _x = 0; _x < header->length; _x++ ) { | 246 | uint16_t x; |
253 | _it += 4; | 247 | |
254 | U32_to_bytes(_it, header->table[_x]); | 248 | for ( x = 0; x < header->length; x++ ) { |
249 | it += 4; | ||
250 | entry = htonl(header->table[x]); | ||
251 | memcpy(it, &entry, sizeof(entry)); | ||
255 | } | 252 | } |
256 | } | 253 | } |
257 | 254 | ||
258 | return _it + 4; | 255 | return it + 4; |
259 | } | 256 | } |
260 | 257 | ||
261 | /** | 258 | /** |
262 | * @brief Builds header from control session values. | 259 | * Builds header from control session values. |
263 | * | ||
264 | * @param session Control session. | ||
265 | * @return RTPHeader* Created header. | ||
266 | */ | 260 | */ |
267 | RTPHeader *build_header ( RTPSession *session ) | 261 | RTPHeader *build_header ( RTPSession *session ) |
268 | { | 262 | { |
269 | RTPHeader *_retu = calloc ( 1, sizeof (RTPHeader) ); | 263 | RTPHeader *retu = calloc ( 1, sizeof (RTPHeader) ); |
270 | 264 | ||
271 | if ( !_retu ) { | 265 | if ( !retu ) { |
272 | LOGGER_WARNING("Alloc failed! Program might misbehave!"); | 266 | LOGGER_WARNING("Alloc failed! Program might misbehave!"); |
273 | return NULL; | 267 | return NULL; |
274 | } | 268 | } |
275 | 269 | ||
276 | ADD_FLAG_VERSION ( _retu, session->version ); | 270 | ADD_FLAG_VERSION ( retu, session->version ); |
277 | ADD_FLAG_PADDING ( _retu, session->padding ); | 271 | ADD_FLAG_PADDING ( retu, session->padding ); |
278 | ADD_FLAG_EXTENSION ( _retu, session->extension ); | 272 | ADD_FLAG_EXTENSION ( retu, session->extension ); |
279 | ADD_FLAG_CSRCC ( _retu, session->cc ); | 273 | ADD_FLAG_CSRCC ( retu, session->cc ); |
280 | ADD_SETTING_MARKER ( _retu, session->marker ); | 274 | ADD_SETTING_MARKER ( retu, session->marker ); |
281 | ADD_SETTING_PAYLOAD ( _retu, session->payload_type ); | 275 | ADD_SETTING_PAYLOAD ( retu, session->payload_type ); |
282 | 276 | ||
283 | _retu->sequnum = session->sequnum; | 277 | retu->sequnum = session->sequnum; |
284 | _retu->timestamp = current_time_monotonic(); /* milliseconds */ | 278 | retu->timestamp = current_time_monotonic(); /* milliseconds */ |
285 | _retu->ssrc = session->ssrc; | 279 | retu->ssrc = session->ssrc; |
286 | 280 | ||
287 | int i; | 281 | int i; |
288 | 282 | ||
289 | for ( i = 0; i < session->cc; i++ ) | 283 | for ( i = 0; i < session->cc; i++ ) |
290 | _retu->csrc[i] = session->csrc[i]; | 284 | retu->csrc[i] = session->csrc[i]; |
291 | 285 | ||
292 | _retu->length = 12 /* Minimum header len */ + ( session->cc * size_32 ); | 286 | retu->length = 12 /* Minimum header len */ + ( session->cc * size_32 ); |
293 | 287 | ||
294 | return _retu; | 288 | return retu; |
295 | } | 289 | } |
296 | 290 | ||
297 | 291 | ||
298 | /** | 292 | /** |
299 | * @brief Parses data into RTPMessage struct. Stores headers separately from the payload data | 293 | * Parses data into RTPMessage struct. Stores headers separately from the payload data |
300 | * and so the length variable is set accordingly. _sequnum_ argument is | 294 | * and so the length variable is set accordingly. |
301 | * passed by the handle_packet() since it's parsed already. | ||
302 | * | ||
303 | * @param session Control session. | ||
304 | * @param sequnum Sequence number that's parsed from payload in handle_packet() | ||
305 | * @param data Payload data. | ||
306 | * @param length Payload size. | ||
307 | * @return RTPMessage* | ||
308 | * @retval NULL Error occurred. | ||
309 | */ | 295 | */ |
310 | RTPMessage *msg_parse ( const uint8_t *data, int length ) | 296 | RTPMessage *msg_parse ( const uint8_t *data, int length ) |
311 | { | 297 | { |
312 | RTPMessage *_retu = calloc(1, sizeof (RTPMessage)); | 298 | RTPMessage *retu = calloc(1, sizeof (RTPMessage)); |
313 | 299 | ||
314 | _retu->header = extract_header ( data, length ); /* It allocates memory and all */ | 300 | retu->header = extract_header ( data, length ); /* It allocates memory and all */ |
315 | 301 | ||
316 | if ( !_retu->header ) { | 302 | if ( !retu->header ) { |
317 | LOGGER_WARNING("Header failed to extract!"); | 303 | LOGGER_WARNING("Header failed to extract!"); |
318 | free(_retu); | 304 | free(retu); |
319 | return NULL; | 305 | return NULL; |
320 | } | 306 | } |
321 | 307 | ||
322 | uint16_t _from_pos = _retu->header->length; | 308 | uint16_t from_pos = retu->header->length; |
323 | _retu->length = length - _from_pos; | 309 | retu->length = length - from_pos; |
324 | 310 | ||
325 | 311 | ||
326 | 312 | ||
327 | if ( GET_FLAG_EXTENSION ( _retu->header ) ) { | 313 | if ( GET_FLAG_EXTENSION ( retu->header ) ) { |
328 | _retu->ext_header = extract_ext_header ( data + _from_pos, length ); | 314 | retu->ext_header = extract_ext_header ( data + from_pos, length ); |
329 | 315 | ||
330 | if ( _retu->ext_header ) { | 316 | if ( retu->ext_header ) { |
331 | _retu->length -= ( 4 /* Minimum ext header len */ + _retu->ext_header->length * size_32 ); | 317 | retu->length -= ( 4 /* Minimum ext header len */ + retu->ext_header->length * size_32 ); |
332 | _from_pos += ( 4 /* Minimum ext header len */ + _retu->ext_header->length * size_32 ); | 318 | from_pos += ( 4 /* Minimum ext header len */ + retu->ext_header->length * size_32 ); |
333 | } else { /* Error */ | 319 | } else { /* Error */ |
334 | LOGGER_WARNING("Ext Header failed to extract!"); | 320 | LOGGER_WARNING("Ext Header failed to extract!"); |
335 | rtp_free_msg(NULL, _retu); | 321 | rtp_free_msg(NULL, retu); |
336 | return NULL; | 322 | return NULL; |
337 | } | 323 | } |
338 | } else { | 324 | } else { |
339 | _retu->ext_header = NULL; | 325 | retu->ext_header = NULL; |
340 | } | 326 | } |
341 | 327 | ||
342 | if ( length - _from_pos <= MAX_RTP_SIZE ) | 328 | if ( length - from_pos <= MAX_RTP_SIZE ) |
343 | memcpy ( _retu->data, data + _from_pos, length - _from_pos ); | 329 | memcpy ( retu->data, data + from_pos, length - from_pos ); |
344 | else { | 330 | else { |
345 | LOGGER_WARNING("Invalid length!"); | 331 | LOGGER_WARNING("Invalid length!"); |
346 | rtp_free_msg(NULL, _retu); | 332 | rtp_free_msg(NULL, retu); |
347 | return NULL; | 333 | return NULL; |
348 | } | 334 | } |
349 | 335 | ||
350 | _retu->next = NULL; | 336 | retu->next = NULL; |
351 | 337 | ||
352 | return _retu; | 338 | return retu; |
353 | } | 339 | } |
354 | 340 | ||
355 | /** | 341 | /** |
356 | * @brief Callback for networking core. | 342 | * Callback for networking core. |
357 | * | ||
358 | * @param object RTPSession object. | ||
359 | * @param ip_port Where the message comes from. | ||
360 | * @param data Message data. | ||
361 | * @param length Message length. | ||
362 | * @return int | ||
363 | * @retval -1 Error occurred. | ||
364 | * @retval 0 Success. | ||
365 | */ | 343 | */ |
366 | int rtp_handle_packet ( void *object, const uint8_t *data, uint32_t length ) | 344 | int rtp_handle_packet ( Messenger *m, uint32_t friendnumber, const uint8_t *data, uint32_t length, void *object ) |
367 | { | 345 | { |
368 | RTPSession *_session = object; | 346 | RTPSession *session = object; |
369 | RTPMessage *_msg; | 347 | RTPMessage *msg; |
370 | 348 | ||
371 | if ( !_session || length < 13 ) { /* 12 is the minimum length for rtp + desc. byte */ | 349 | if ( !session || length < 13 ) { /* 12 is the minimum length for rtp + desc. byte */ |
372 | LOGGER_WARNING("No session or invalid length of received buffer!"); | 350 | LOGGER_WARNING("No session or invalid length of received buffer!"); |
373 | return -1; | 351 | return -1; |
374 | } | 352 | } |
375 | 353 | ||
376 | _msg = msg_parse ( data + 1, length - 1 ); | 354 | msg = msg_parse ( data + 1, length - 1 ); |
377 | 355 | ||
378 | if ( !_msg ) { | 356 | if ( !msg ) { |
379 | LOGGER_WARNING("Could not parse message!"); | 357 | LOGGER_WARNING("Could not parse message!"); |
380 | return -1; | 358 | return -1; |
381 | } | 359 | } |
382 | 360 | ||
383 | /* Check if message came in late */ | 361 | /* Check if message came in late */ |
384 | if ( check_late_message(_session, _msg) < 0 ) { /* Not late */ | 362 | if ( check_late_message(session, msg) < 0 ) { /* Not late */ |
385 | _session->rsequnum = _msg->header->sequnum; | 363 | session->rsequnum = msg->header->sequnum; |
386 | _session->timestamp = _msg->header->timestamp; | 364 | session->timestamp = msg->header->timestamp; |
387 | } | 365 | } |
388 | 366 | ||
389 | toxav_handle_packet(_session, _msg); | 367 | queue_message(session, msg); |
390 | 368 | ||
391 | return 0; | 369 | return 0; |
392 | } | 370 | } |
393 | 371 | ||
394 | |||
395 | |||
396 | /** | 372 | /** |
397 | * @brief Stores headers and payload data in one container ( data ) | 373 | * Allocate message and store data there |
398 | * and the length is set accordingly. Returned message is used for sending _only_. | ||
399 | * | ||
400 | * @param session The control session. | ||
401 | * @param data Payload data to send ( This is what you pass ). | ||
402 | * @param length Size of the payload data. | ||
403 | * @return RTPMessage* Created message. | ||
404 | * @retval NULL Error occurred. | ||
405 | */ | 374 | */ |
406 | RTPMessage *rtp_new_message ( RTPSession *session, const uint8_t *data, uint32_t length ) | 375 | RTPMessage *rtp_new_message ( RTPSession *session, const uint8_t *data, uint32_t length ) |
407 | { | 376 | { |
@@ -410,30 +379,30 @@ RTPMessage *rtp_new_message ( RTPSession *session, const uint8_t *data, uint32_t | |||
410 | return NULL; | 379 | return NULL; |
411 | } | 380 | } |
412 | 381 | ||
413 | uint8_t *_from_pos; | 382 | uint8_t *from_pos; |
414 | RTPMessage *_retu = calloc(1, sizeof (RTPMessage)); | 383 | RTPMessage *retu = calloc(1, sizeof (RTPMessage)); |
415 | 384 | ||
416 | if ( !_retu ) { | 385 | if ( !retu ) { |
417 | LOGGER_WARNING("Alloc failed! Program might misbehave!"); | 386 | LOGGER_WARNING("Alloc failed! Program might misbehave!"); |
418 | return NULL; | 387 | return NULL; |
419 | } | 388 | } |
420 | 389 | ||
421 | /* Sets header values and copies the extension header in _retu */ | 390 | /* Sets header values and copies the extension header in retu */ |
422 | _retu->header = build_header ( session ); /* It allocates memory and all */ | 391 | retu->header = build_header ( session ); /* It allocates memory and all */ |
423 | _retu->ext_header = session->ext_header; | 392 | retu->ext_header = session->ext_header; |
424 | 393 | ||
425 | 394 | ||
426 | uint32_t _total_length = length + _retu->header->length + 1; | 395 | uint32_t total_length = length + retu->header->length + 1; |
427 | 396 | ||
428 | _retu->data[0] = session->prefix; | 397 | retu->data[0] = session->prefix; |
429 | 398 | ||
430 | if ( _retu->ext_header ) { | 399 | if ( retu->ext_header ) { |
431 | _total_length += ( 4 /* Minimum ext header len */ + _retu->ext_header->length * size_32 ); | 400 | total_length += ( 4 /* Minimum ext header len */ + retu->ext_header->length * size_32 ); |
432 | 401 | ||
433 | _from_pos = add_header ( _retu->header, _retu->data + 1 ); | 402 | from_pos = add_header ( retu->header, retu->data + 1 ); |
434 | _from_pos = add_ext_header ( _retu->ext_header, _from_pos + 1 ); | 403 | from_pos = add_ext_header ( retu->ext_header, from_pos + 1 ); |
435 | } else { | 404 | } else { |
436 | _from_pos = add_header ( _retu->header, _retu->data + 1 ); | 405 | from_pos = add_header ( retu->header, retu->data + 1 ); |
437 | } | 406 | } |
438 | 407 | ||
439 | /* | 408 | /* |
@@ -441,41 +410,28 @@ RTPMessage *rtp_new_message ( RTPSession *session, const uint8_t *data, uint32_t | |||
441 | * Of course if any | 410 | * Of course if any |
442 | */ | 411 | */ |
443 | 412 | ||
444 | /* Appends _data on to _retu->_data */ | 413 | /* Appends data on to retu->data */ |
445 | memcpy ( _from_pos, data, length ); | 414 | memcpy ( from_pos, data, length ); |
446 | 415 | ||
447 | _retu->length = _total_length; | 416 | retu->length = total_length; |
448 | 417 | ||
449 | _retu->next = NULL; | 418 | retu->next = NULL; |
450 | 419 | ||
451 | return _retu; | 420 | return retu; |
452 | } | 421 | } |
453 | 422 | ||
454 | 423 | ||
455 | /** | 424 | |
456 | * @brief Sends data to _RTPSession::dest | ||
457 | * | ||
458 | * @param session The session. | ||
459 | * @param messenger Tox* object. | ||
460 | * @param data The payload. | ||
461 | * @param length Size of the payload. | ||
462 | * @return int | ||
463 | * @retval -1 On error. | ||
464 | * @retval 0 On success. | ||
465 | */ | ||
466 | int rtp_send_msg ( RTPSession *session, Messenger *messenger, const uint8_t *data, uint16_t length ) | 425 | int rtp_send_msg ( RTPSession *session, Messenger *messenger, const uint8_t *data, uint16_t length ) |
467 | { | 426 | { |
468 | RTPMessage *msg = rtp_new_message (session, data, length); | 427 | RTPMessage *msg = rtp_new_message (session, data, length); |
469 | 428 | ||
470 | if ( !msg ) { | 429 | if ( !msg ) return -1; |
471 | LOGGER_WARNING("No session!"); | ||
472 | return -1; | ||
473 | } | ||
474 | 430 | ||
475 | if ( -1 == send_custom_lossy_packet(messenger, session->dest, msg->data, msg->length) ) { | 431 | if ( -1 == send_custom_lossy_packet(messenger, session->dest, msg->data, msg->length) ) { |
476 | LOGGER_WARNING("Failed to send full packet! std error: %s", strerror(errno)); | 432 | LOGGER_WARNING("Failed to send full packet (len: %d)! std error: %s", length, strerror(errno)); |
477 | rtp_free_msg ( session, msg ); | 433 | rtp_free_msg ( session, msg ); |
478 | return -1; | 434 | return rtp_ErrorSending; |
479 | } | 435 | } |
480 | 436 | ||
481 | 437 | ||
@@ -486,15 +442,6 @@ int rtp_send_msg ( RTPSession *session, Messenger *messenger, const uint8_t *dat | |||
486 | return 0; | 442 | return 0; |
487 | } | 443 | } |
488 | 444 | ||
489 | |||
490 | /** | ||
491 | * @brief Speaks for it self. | ||
492 | * | ||
493 | * @param session The control session msg belongs to. You set it as NULL when freeing recved messages. | ||
494 | * Otherwise set it to session the message was created from. | ||
495 | * @param msg The message. | ||
496 | * @return void | ||
497 | */ | ||
498 | void rtp_free_msg ( RTPSession *session, RTPMessage *msg ) | 445 | void rtp_free_msg ( RTPSession *session, RTPMessage *msg ) |
499 | { | 446 | { |
500 | if ( !session ) { | 447 | if ( !session ) { |
@@ -513,77 +460,57 @@ void rtp_free_msg ( RTPSession *session, RTPMessage *msg ) | |||
513 | free ( msg ); | 460 | free ( msg ); |
514 | } | 461 | } |
515 | 462 | ||
516 | /** | 463 | RTPSession *rtp_new ( int payload_type, Messenger *messenger, int friend_num ) |
517 | * @brief Must be called before calling any other rtp function. It's used | ||
518 | * to initialize RTP control session. | ||
519 | * | ||
520 | * @param payload_type Type of payload used to send. You can use values in toxmsi.h::MSICallType | ||
521 | * @param messenger Tox* object. | ||
522 | * @param friend_num Friend id. | ||
523 | * @return RTPSession* Created control session. | ||
524 | * @retval NULL Error occurred. | ||
525 | */ | ||
526 | RTPSession *rtp_init_session ( int payload_type, Messenger *messenger, int friend_num ) | ||
527 | { | 464 | { |
528 | RTPSession *_retu = calloc(1, sizeof(RTPSession)); | 465 | RTPSession *retu = calloc(1, sizeof(RTPSession)); |
529 | 466 | ||
530 | if ( !_retu ) { | 467 | if ( !retu ) { |
531 | LOGGER_WARNING("Alloc failed! Program might misbehave!"); | 468 | LOGGER_WARNING("Alloc failed! Program might misbehave!"); |
532 | return NULL; | 469 | return NULL; |
533 | } | 470 | } |
534 | 471 | ||
535 | if ( -1 == custom_lossy_packet_registerhandler(messenger, friend_num, payload_type, rtp_handle_packet, _retu)) { | 472 | if ( -1 == custom_lossy_packet_registerhandler(messenger, friend_num, payload_type, rtp_handle_packet, retu)) { |
536 | LOGGER_ERROR("Error setting custom register handler for rtp session"); | 473 | LOGGER_ERROR("Error setting custom register handler for rtp session"); |
537 | free(_retu); | 474 | free(retu); |
538 | return NULL; | 475 | return NULL; |
539 | } | 476 | } |
540 | 477 | ||
541 | LOGGER_DEBUG("Registered packet handler: pt: %d; fid: %d", payload_type, friend_num); | 478 | LOGGER_DEBUG("Registered packet handler: pt: %d; fid: %d", payload_type, friend_num); |
542 | 479 | ||
543 | _retu->version = RTP_VERSION; /* It's always 2 */ | 480 | retu->version = RTP_VERSION; /* It's always 2 */ |
544 | _retu->padding = 0; /* If some additional data is needed about the packet */ | 481 | retu->padding = 0; /* If some additional data is needed about the packet */ |
545 | _retu->extension = 0; /* If extension to header is needed */ | 482 | retu->extension = 0; /* If extension to header is needed */ |
546 | _retu->cc = 1; /* Amount of contributors */ | 483 | retu->cc = 1; /* Amount of contributors */ |
547 | _retu->csrc = NULL; /* Container */ | 484 | retu->csrc = NULL; /* Container */ |
548 | _retu->ssrc = random_int(); | 485 | retu->ssrc = random_int(); |
549 | _retu->marker = 0; | 486 | retu->marker = 0; |
550 | _retu->payload_type = payload_type % 128; | 487 | retu->payload_type = payload_type % 128; |
551 | 488 | ||
552 | _retu->dest = friend_num; | 489 | retu->dest = friend_num; |
553 | 490 | ||
554 | _retu->rsequnum = _retu->sequnum = 0; | 491 | retu->rsequnum = retu->sequnum = 0; |
555 | 492 | ||
556 | _retu->ext_header = NULL; /* When needed allocate */ | 493 | retu->ext_header = NULL; /* When needed allocate */ |
557 | 494 | ||
558 | 495 | ||
559 | if ( !(_retu->csrc = calloc(1, sizeof (uint32_t))) ) { | 496 | if ( !(retu->csrc = calloc(1, sizeof (uint32_t))) ) { |
560 | LOGGER_WARNING("Alloc failed! Program might misbehave!"); | 497 | LOGGER_WARNING("Alloc failed! Program might misbehave!"); |
561 | free(_retu); | 498 | free(retu); |
562 | return NULL; | 499 | return NULL; |
563 | } | 500 | } |
564 | 501 | ||
565 | _retu->csrc[0] = _retu->ssrc; /* Set my ssrc to the list receive */ | 502 | retu->csrc[0] = retu->ssrc; /* Set my ssrc to the list receive */ |
566 | 503 | ||
567 | /* Also set payload type as prefix */ | 504 | /* Also set payload type as prefix */ |
568 | _retu->prefix = payload_type; | 505 | retu->prefix = payload_type; |
569 | 506 | ||
570 | /* | 507 | /* |
571 | * | 508 | * |
572 | */ | 509 | */ |
573 | return _retu; | 510 | return retu; |
574 | } | 511 | } |
575 | 512 | ||
576 | 513 | void rtp_kill ( RTPSession *session, Messenger *messenger ) | |
577 | /** | ||
578 | * @brief Terminate the session. | ||
579 | * | ||
580 | * @param session The session. | ||
581 | * @param messenger The messenger who owns the session | ||
582 | * @return int | ||
583 | * @retval -1 Error occurred. | ||
584 | * @retval 0 Success. | ||
585 | */ | ||
586 | void rtp_terminate_session ( RTPSession *session, Messenger *messenger ) | ||
587 | { | 514 | { |
588 | if ( !session ) return; | 515 | if ( !session ) return; |
589 | 516 | ||
diff --git a/toxav/rtp.h b/toxav/rtp.h index d57c5ef7..c98840ac 100644 --- a/toxav/rtp.h +++ b/toxav/rtp.h | |||
@@ -24,21 +24,19 @@ | |||
24 | 24 | ||
25 | #define RTP_VERSION 2 | 25 | #define RTP_VERSION 2 |
26 | #include <inttypes.h> | 26 | #include <inttypes.h> |
27 | #include <pthread.h> | 27 | // #include <pthread.h> |
28 | 28 | ||
29 | #include "../toxcore/util.h" | ||
30 | #include "../toxcore/network.h" | ||
31 | #include "../toxcore/net_crypto.h" | ||
32 | #include "../toxcore/Messenger.h" | 29 | #include "../toxcore/Messenger.h" |
33 | 30 | ||
34 | #define MAX_SEQU_NUM 65535 | 31 | #define MAX_SEQU_NUM 65535 |
35 | #define MAX_RTP_SIZE 65535 | 32 | #define MAX_RTP_SIZE 65535 |
36 | 33 | ||
34 | typedef enum { | ||
35 | rtp_ErrorSending = -40 | ||
36 | } RTPError; | ||
37 | /** | 37 | /** |
38 | * @brief Standard rtp header | 38 | * Standard rtp header |
39 | * | ||
40 | */ | 39 | */ |
41 | |||
42 | typedef struct _RTPHeader { | 40 | typedef struct _RTPHeader { |
43 | uint8_t flags; /* Version(2),Padding(1), Ext(1), Cc(4) */ | 41 | uint8_t flags; /* Version(2),Padding(1), Ext(1), Cc(4) */ |
44 | uint8_t marker_payloadt; /* Marker(1), PlayLoad Type(7) */ | 42 | uint8_t marker_payloadt; /* Marker(1), PlayLoad Type(7) */ |
@@ -50,10 +48,8 @@ typedef struct _RTPHeader { | |||
50 | 48 | ||
51 | } RTPHeader; | 49 | } RTPHeader; |
52 | 50 | ||
53 | |||
54 | /** | 51 | /** |
55 | * @brief Standard rtp extension header. | 52 | * Standard rtp extension header. |
56 | * | ||
57 | */ | 53 | */ |
58 | typedef struct _RTPExtHeader { | 54 | typedef struct _RTPExtHeader { |
59 | uint16_t type; /* Extension profile */ | 55 | uint16_t type; /* Extension profile */ |
@@ -62,10 +58,8 @@ typedef struct _RTPExtHeader { | |||
62 | 58 | ||
63 | } RTPExtHeader; | 59 | } RTPExtHeader; |
64 | 60 | ||
65 | |||
66 | /** | 61 | /** |
67 | * @brief Standard rtp message. | 62 | * Standard rtp message. |
68 | * | ||
69 | */ | 63 | */ |
70 | typedef struct _RTPMessage { | 64 | typedef struct _RTPMessage { |
71 | RTPHeader *header; | 65 | RTPHeader *header; |
@@ -77,14 +71,8 @@ typedef struct _RTPMessage { | |||
77 | struct _RTPMessage *next; | 71 | struct _RTPMessage *next; |
78 | } RTPMessage; | 72 | } RTPMessage; |
79 | 73 | ||
80 | |||
81 | /** | 74 | /** |
82 | * @brief Our main session descriptor. | 75 | * RTP control session. |
83 | * It measures the session variables and controls | ||
84 | * the entire session. There are functions for manipulating | ||
85 | * the session so tend to use those instead of directly modifying | ||
86 | * session parameters. | ||
87 | * | ||
88 | */ | 76 | */ |
89 | typedef struct _RTPSession { | 77 | typedef struct _RTPSession { |
90 | uint8_t version; | 78 | uint8_t version; |
@@ -109,88 +97,31 @@ typedef struct _RTPSession { | |||
109 | uint8_t prefix; | 97 | uint8_t prefix; |
110 | 98 | ||
111 | int dest; | 99 | int dest; |
112 | int32_t call_index; | ||
113 | struct _ToxAv *av; | ||
114 | |||
115 | } RTPSession; | ||
116 | 100 | ||
101 | struct _CSSession *cs; | ||
117 | 102 | ||
118 | /** | 103 | } RTPSession; |
119 | * @brief Release all messages held by session. | ||
120 | * | ||
121 | * @param session The session. | ||
122 | * @return int | ||
123 | * @retval -1 Error occurred. | ||
124 | * @retval 0 Success. | ||
125 | */ | ||
126 | int rtp_release_session_recv ( RTPSession *session ); | ||
127 | |||
128 | 104 | ||
129 | /** | 105 | /** |
130 | * @brief Call this to change queue limit | 106 | * Must be called before calling any other rtp function. |
131 | * | ||
132 | * @param session The session | ||
133 | * @param limit new limit | ||
134 | * @return void | ||
135 | */ | 107 | */ |
136 | void rtp_queue_adjust_limit ( RTPSession *session, uint64_t limit ); | 108 | RTPSession *rtp_new ( int payload_type, Messenger *messenger, int friend_num ); |
137 | 109 | ||
138 | /** | 110 | /** |
139 | * @brief Get's oldest message in the list. | 111 | * Terminate the session. |
140 | * | ||
141 | * @param session Where the list is. | ||
142 | * @return RTPMessage* The message. You need to call rtp_msg_free() to free it. | ||
143 | * @retval NULL No messages in the list, or no list. | ||
144 | */ | 112 | */ |
145 | RTPMessage *rtp_recv_msg ( RTPSession *session ); | 113 | void rtp_kill ( RTPSession *session, Messenger *messenger ); |
146 | |||
147 | 114 | ||
148 | /** | 115 | /** |
149 | * @brief Sends msg to _RTPSession::dest | 116 | * Sends msg to _RTPSession::dest |
150 | * | ||
151 | * @param session The session. | ||
152 | * @param msg The message | ||
153 | * @param messenger Tox* object. | ||
154 | * @return int | ||
155 | * @retval -1 On error. | ||
156 | * @retval 0 On success. | ||
157 | */ | 117 | */ |
158 | int rtp_send_msg ( RTPSession *session, Messenger *messenger, const uint8_t *data, uint16_t length ); | 118 | int rtp_send_msg ( RTPSession *session, Messenger *messenger, const uint8_t *data, uint16_t length ); |
159 | 119 | ||
160 | |||
161 | /** | 120 | /** |
162 | * @brief Speaks for it self. | 121 | * Dealloc msg. |
163 | * | ||
164 | * @param session The control session msg belongs to. It can be NULL. | ||
165 | * @param msg The message. | ||
166 | * @return void | ||
167 | */ | 122 | */ |
168 | void rtp_free_msg ( RTPSession *session, RTPMessage *msg ); | 123 | void rtp_free_msg ( RTPSession *session, RTPMessage *msg ); |
169 | 124 | ||
170 | /** | ||
171 | * @brief Must be called before calling any other rtp function. It's used | ||
172 | * to initialize RTP control session. | ||
173 | * | ||
174 | * @param payload_type Type of payload used to send. You can use values in toxmsi.h::MSICallType | ||
175 | * @param messenger Tox* object. | ||
176 | * @param friend_num Friend id. | ||
177 | * @return RTPSession* Created control session. | ||
178 | * @retval NULL Error occurred. | ||
179 | */ | ||
180 | RTPSession *rtp_init_session ( int payload_type, Messenger *messenger, int friend_num ); | ||
181 | |||
182 | |||
183 | /** | ||
184 | * @brief Terminate the session. | ||
185 | * | ||
186 | * @param session The session. | ||
187 | * @param messenger The messenger who owns the session | ||
188 | * @return int | ||
189 | * @retval -1 Error occurred. | ||
190 | * @retval 0 Success. | ||
191 | */ | ||
192 | void rtp_terminate_session ( RTPSession *session, Messenger *messenger ); | ||
193 | |||
194 | 125 | ||
195 | 126 | ||
196 | #endif /* __TOXRTP */ | 127 | #endif /* __TOXRTP */ |
diff --git a/toxav/toxav.c b/toxav/toxav.c index cd0ec70e..f8605fd5 100644 --- a/toxav/toxav.c +++ b/toxav/toxav.c | |||
@@ -23,15 +23,17 @@ | |||
23 | #include "config.h" | 23 | #include "config.h" |
24 | #endif /* HAVE_CONFIG_H */ | 24 | #endif /* HAVE_CONFIG_H */ |
25 | 25 | ||
26 | #define __TOX_DEFINED__ | ||
27 | typedef struct Messenger Tox; | ||
26 | 28 | ||
27 | #define _GNU_SOURCE /* implicit declaration warning */ | 29 | #define _GNU_SOURCE /* implicit declaration warning */ |
28 | 30 | ||
29 | #include "rtp.h" | ||
30 | #include "codec.h" | 31 | #include "codec.h" |
31 | #include "msi.h" | 32 | #include "msi.h" |
32 | #include "toxav.h" | 33 | #include "group.h" |
33 | 34 | ||
34 | #include "../toxcore/logger.h" | 35 | #include "../toxcore/logger.h" |
36 | #include "../toxcore/util.h" | ||
35 | 37 | ||
36 | #include <assert.h> | 38 | #include <assert.h> |
37 | #include <stdlib.h> | 39 | #include <stdlib.h> |
@@ -39,134 +41,64 @@ | |||
39 | 41 | ||
40 | /* Assume 24 fps*/ | 42 | /* Assume 24 fps*/ |
41 | #define MAX_ENCODE_TIME_US ((1000 / 24) * 1000) | 43 | #define MAX_ENCODE_TIME_US ((1000 / 24) * 1000) |
42 | #define MAX_DECODE_TIME_US 0 | ||
43 | |||
44 | #define MAX_VIDEOFRAME_SIZE 0x40000 /* 256KiB */ | ||
45 | #define VIDEOFRAME_PIECE_SIZE 0x500 /* 1.25 KiB*/ | ||
46 | #define VIDEOFRAME_HEADER_SIZE 0x2 | ||
47 | |||
48 | |||
49 | #define inline__ inline __attribute__((always_inline)) | ||
50 | |||
51 | /* call index invalid: true if invalid */ | ||
52 | #define cii(c_idx, session) (c_idx < 0 || c_idx >= session->max_calls) | ||
53 | 44 | ||
45 | /* true if invalid call index */ | ||
46 | #define CALL_INVALID_INDEX(idx, max) (idx < 0 || idx >= max) | ||
54 | 47 | ||
55 | const ToxAvCSettings av_DefaultSettings = { | 48 | const ToxAvCSettings av_DefaultSettings = { |
56 | TypeAudio, | 49 | av_TypeAudio, |
57 | 50 | ||
58 | 500, | 51 | 500, |
59 | 1280, | 52 | 1280, |
60 | 720, | 53 | 720, |
61 | 54 | ||
62 | 64000, | 55 | 32000, |
63 | 20, | 56 | 20, |
64 | 48000, | 57 | 48000, |
65 | 1 | 58 | 1 |
66 | }; | 59 | }; |
67 | 60 | ||
68 | const uint32_t av_jbufdc = 3; | 61 | static const uint32_t jbuf_capacity = 6; |
69 | const uint32_t av_VADd = 40; | ||
70 | |||
71 | |||
72 | static const uint8_t audio_index = 0, video_index = 1; | 62 | static const uint8_t audio_index = 0, video_index = 1; |
73 | 63 | ||
74 | typedef struct { | 64 | typedef struct _ToxAvCall { |
75 | uint32_t size; | 65 | pthread_mutex_t mutex[1]; |
76 | uint8_t data[0]; | 66 | pthread_mutex_t mutex_encoding_audio[1]; |
77 | } DECODE_PACKET; | 67 | pthread_mutex_t mutex_encoding_video[1]; |
78 | 68 | pthread_mutex_t mutex_do[1]; | |
79 | #define VIDEO_DECODE_QUEUE_SIZE 2 | ||
80 | #define AUDIO_DECODE_QUEUE_SIZE 16 | ||
81 | |||
82 | typedef struct _CallSpecific { | ||
83 | RTPSession *crtps[2]; /** Audio is first and video is second */ | 69 | RTPSession *crtps[2]; /** Audio is first and video is second */ |
84 | CodecState *cs;/** Each call have its own encoders and decoders. | 70 | CSSession *cs; |
85 | * You can, but don't have to, reuse encoders for | 71 | _Bool active; |
86 | * multiple calls. If you choose to reuse encoders, | 72 | } ToxAvCall; |
87 | * make sure to also reuse encoded payload for every call. | ||
88 | * Decoders have to be unique for each call. FIXME: Now add refcounted encoders and | ||
89 | * reuse them really. | ||
90 | */ | ||
91 | JitterBuffer *j_buf; /** Jitter buffer for audio */ | ||
92 | |||
93 | uint32_t frame_limit; /* largest address written to in frame_buf for current input frame*/ | ||
94 | uint8_t frame_id, frame_outid; /* id of input and output video frame */ | ||
95 | void *frame_buf; /* buffer for split video payloads */ | ||
96 | |||
97 | _Bool call_active; | ||
98 | pthread_mutex_t mutex; | ||
99 | |||
100 | /* used in the "decode on another thread" system */ | ||
101 | volatile _Bool exit, decoding; | ||
102 | uint8_t video_decode_read, video_decode_write, audio_decode_read, audio_decode_write; | ||
103 | pthread_mutex_t decode_cond_mutex; | ||
104 | pthread_cond_t decode_cond; | ||
105 | DECODE_PACKET *volatile video_decode_queue[VIDEO_DECODE_QUEUE_SIZE]; | ||
106 | DECODE_PACKET *volatile audio_decode_queue[AUDIO_DECODE_QUEUE_SIZE]; | ||
107 | } CallSpecific; | ||
108 | 73 | ||
109 | struct _ToxAv { | 74 | struct _ToxAv { |
110 | Messenger *messenger; | 75 | Messenger *messenger; |
111 | MSISession *msi_session; /** Main msi session */ | 76 | MSISession *msi_session; /** Main msi session */ |
112 | CallSpecific *calls; /** Per-call params */ | 77 | ToxAvCall *calls; /** Per-call params */ |
113 | 78 | uint32_t max_calls; | |
114 | void (*audio_callback)(ToxAv *, int32_t, int16_t *, int, void *); | ||
115 | void (*video_callback)(ToxAv *, int32_t, vpx_image_t *, void *); | ||
116 | 79 | ||
117 | void *audio_callback_userdata; | 80 | PAIR(ToxAvAudioCallback, void *) acb; |
118 | void *video_callback_userdata; | 81 | PAIR(ToxAvVideoCallback, void *) vcb; |
119 | 82 | ||
120 | uint32_t max_calls; | 83 | /* Decode time measure */ |
84 | int32_t dectmsscount; /** Measure count */ | ||
85 | int32_t dectmsstotal; /** Last cycle total */ | ||
86 | int32_t avgdectms; /** Average decoding time in ms */ | ||
121 | }; | 87 | }; |
122 | 88 | ||
123 | static void *toxav_decoding(void *arg); | 89 | static const MSICSettings *msicsettings_cast (const ToxAvCSettings *from) |
124 | |||
125 | static MSICSettings msicsettings_cast (const ToxAvCSettings *from) | ||
126 | { | 90 | { |
127 | MSICSettings csettings; | 91 | assert(sizeof(MSICSettings) == sizeof(ToxAvCSettings)); |
128 | csettings.call_type = from->call_type; | 92 | return (const MSICSettings *) from; |
129 | |||
130 | csettings.video_bitrate = from->video_bitrate; | ||
131 | csettings.max_video_width = from->max_video_width; | ||
132 | csettings.max_video_height = from->max_video_height; | ||
133 | |||
134 | csettings.audio_bitrate = from->audio_bitrate; | ||
135 | csettings.audio_frame_duration = from->audio_frame_duration; | ||
136 | csettings.audio_sample_rate = from->audio_sample_rate; | ||
137 | csettings.audio_channels = from->audio_channels; | ||
138 | |||
139 | return csettings; | ||
140 | } | 93 | } |
141 | 94 | ||
142 | static ToxAvCSettings toxavcsettings_cast (const MSICSettings *from) | 95 | static const ToxAvCSettings *toxavcsettings_cast (const MSICSettings *from) |
143 | { | 96 | { |
144 | ToxAvCSettings csettings; | 97 | assert(sizeof(MSICSettings) == sizeof(ToxAvCSettings)); |
145 | csettings.call_type = from->call_type; | 98 | return (const ToxAvCSettings *) from; |
146 | |||
147 | csettings.video_bitrate = from->video_bitrate; | ||
148 | csettings.max_video_width = from->max_video_width; | ||
149 | csettings.max_video_height = from->max_video_height; | ||
150 | |||
151 | csettings.audio_bitrate = from->audio_bitrate; | ||
152 | csettings.audio_frame_duration = from->audio_frame_duration; | ||
153 | csettings.audio_sample_rate = from->audio_sample_rate; | ||
154 | csettings.audio_channels = from->audio_channels; | ||
155 | 99 | ||
156 | return csettings; | ||
157 | } | 100 | } |
158 | 101 | ||
159 | /** | ||
160 | * @brief Start new A/V session. There can only be one session at the time. If you register more | ||
161 | * it will result in undefined behaviour. | ||
162 | * | ||
163 | * @param messenger The messenger handle. | ||
164 | * @param userdata The agent handling A/V session (i.e. phone). | ||
165 | * @param video_width Width of video frame. | ||
166 | * @param video_height Height of video frame. | ||
167 | * @return ToxAv* | ||
168 | * @retval NULL On error. | ||
169 | */ | ||
170 | ToxAv *toxav_new( Tox *messenger, int32_t max_calls) | 102 | ToxAv *toxav_new( Tox *messenger, int32_t max_calls) |
171 | { | 103 | { |
172 | ToxAv *av = calloc ( sizeof(ToxAv), 1); | 104 | ToxAv *av = calloc ( sizeof(ToxAv), 1); |
@@ -177,556 +109,371 @@ ToxAv *toxav_new( Tox *messenger, int32_t max_calls) | |||
177 | } | 109 | } |
178 | 110 | ||
179 | av->messenger = (Messenger *)messenger; | 111 | av->messenger = (Messenger *)messenger; |
180 | av->msi_session = msi_init_session(av->messenger, max_calls); | 112 | av->msi_session = msi_new(av->messenger, max_calls); |
181 | av->msi_session->agent_handler = av; | 113 | av->msi_session->agent_handler = av; |
182 | av->calls = calloc(sizeof(CallSpecific), max_calls); | 114 | av->calls = calloc(sizeof(ToxAvCall), max_calls); |
183 | av->max_calls = max_calls; | 115 | av->max_calls = max_calls; |
184 | 116 | ||
117 | unsigned int i; | ||
118 | |||
119 | for (i = 0; i < max_calls; ++i) { | ||
120 | if (create_recursive_mutex(av->calls[i].mutex) != 0 ) { | ||
121 | LOGGER_WARNING("Failed to init call(%u) mutex!", i); | ||
122 | msi_kill(av->msi_session); | ||
123 | |||
124 | free(av->calls); | ||
125 | free(av); | ||
126 | return NULL; | ||
127 | } | ||
128 | } | ||
129 | |||
185 | return av; | 130 | return av; |
186 | } | 131 | } |
187 | 132 | ||
188 | /** | ||
189 | * @brief Remove A/V session. | ||
190 | * | ||
191 | * @param av Handler. | ||
192 | * @return void | ||
193 | */ | ||
194 | void toxav_kill ( ToxAv *av ) | 133 | void toxav_kill ( ToxAv *av ) |
195 | { | 134 | { |
196 | uint32_t i; | 135 | uint32_t i; |
197 | 136 | ||
198 | for (i = 0; i < av->max_calls; i ++) { | 137 | for (i = 0; i < av->max_calls; i ++) { |
199 | if ( av->calls[i].crtps[audio_index] ) | 138 | if ( av->calls[i].crtps[audio_index] ) |
200 | rtp_terminate_session(av->calls[i].crtps[audio_index], av->msi_session->messenger_handle); | 139 | rtp_kill(av->calls[i].crtps[audio_index], av->msi_session->messenger_handle); |
201 | 140 | ||
202 | 141 | ||
203 | if ( av->calls[i].crtps[video_index] ) | 142 | if ( av->calls[i].crtps[video_index] ) |
204 | rtp_terminate_session(av->calls[i].crtps[video_index], av->msi_session->messenger_handle); | 143 | rtp_kill(av->calls[i].crtps[video_index], av->msi_session->messenger_handle); |
205 | 144 | ||
145 | if ( av->calls[i].cs ) | ||
146 | cs_kill(av->calls[i].cs); | ||
206 | 147 | ||
207 | 148 | pthread_mutex_destroy(av->calls[i].mutex); | |
208 | if ( av->calls[i].j_buf ) terminate_queue(av->calls[i].j_buf); | ||
209 | |||
210 | if ( av->calls[i].cs ) codec_terminate_session(av->calls[i].cs); | ||
211 | } | 149 | } |
212 | 150 | ||
213 | msi_terminate_session(av->msi_session); | 151 | msi_kill(av->msi_session); |
214 | 152 | ||
215 | free(av->calls); | 153 | free(av->calls); |
216 | free(av); | 154 | free(av); |
217 | } | 155 | } |
218 | 156 | ||
219 | /** | 157 | uint32_t toxav_do_interval(ToxAv *av) |
220 | * @brief Register callback for call state. | ||
221 | * | ||
222 | * @param av Handler. | ||
223 | * @param callback The callback | ||
224 | * @param id One of the ToxAvCallbackID values | ||
225 | * @return void | ||
226 | */ | ||
227 | void toxav_register_callstate_callback ( ToxAv *av, ToxAVCallback callback, ToxAvCallbackID id, void *userdata ) | ||
228 | { | 158 | { |
229 | msi_register_callback(av->msi_session, (MSICallbackType)callback, (MSICallbackID) id, userdata); | 159 | int i = 0; |
160 | uint32_t rc = 200 + av->avgdectms; /* Return 200 if no call is active */ | ||
161 | |||
162 | for (; i < av->max_calls; i ++) { | ||
163 | pthread_mutex_lock(av->calls[i].mutex); | ||
164 | |||
165 | if (av->calls[i].active) { | ||
166 | /* This should work. Video payload will always come in greater intervals */ | ||
167 | rc = MIN(av->calls[i].cs->audio_decoder_frame_duration, rc); | ||
168 | } | ||
169 | |||
170 | pthread_mutex_unlock(av->calls[i].mutex); | ||
171 | } | ||
172 | |||
173 | return rc < av->avgdectms ? 0 : rc - av->avgdectms; | ||
230 | } | 174 | } |
231 | 175 | ||
232 | /** | 176 | void toxav_do(ToxAv *av) |
233 | * @brief Register callback for recieving audio data | ||
234 | * | ||
235 | * @param callback The callback | ||
236 | * @return void | ||
237 | */ | ||
238 | void toxav_register_audio_recv_callback (ToxAv *av, void (*callback)(ToxAv *, int32_t, int16_t *, int, void *), | ||
239 | void *user_data) | ||
240 | { | 177 | { |
241 | av->audio_callback = callback; | 178 | msi_do(av->msi_session); |
242 | av->audio_callback_userdata = user_data; | 179 | |
180 | uint64_t start = current_time_monotonic(); | ||
181 | |||
182 | uint32_t i = 0; | ||
183 | |||
184 | for (; i < av->max_calls; i ++) { | ||
185 | pthread_mutex_lock(av->calls[i].mutex); | ||
186 | |||
187 | if (av->calls[i].active) { | ||
188 | pthread_mutex_lock(av->calls[i].mutex_do); | ||
189 | pthread_mutex_unlock(av->calls[i].mutex); | ||
190 | cs_do(av->calls[i].cs); | ||
191 | pthread_mutex_unlock(av->calls[i].mutex_do); | ||
192 | } else { | ||
193 | pthread_mutex_unlock(av->calls[i].mutex); | ||
194 | } | ||
195 | } | ||
196 | |||
197 | uint64_t end = current_time_monotonic(); | ||
198 | |||
199 | /* TODO maybe use variable for sizes */ | ||
200 | av->dectmsstotal += end - start; | ||
201 | |||
202 | if (++av->dectmsscount == 3) { | ||
203 | av->avgdectms = av->dectmsstotal / 3 + 2 /* NOTE Magic Offset */; | ||
204 | av->dectmsscount = 0; | ||
205 | av->dectmsstotal = 0; | ||
206 | } | ||
243 | } | 207 | } |
244 | 208 | ||
245 | /** | 209 | void toxav_register_callstate_callback ( ToxAv *av, ToxAVCallback cb, ToxAvCallbackID id, void *userdata ) |
246 | * @brief Register callback for recieving video data | ||
247 | * | ||
248 | * @param callback The callback | ||
249 | * @return void | ||
250 | */ | ||
251 | void toxav_register_video_recv_callback (ToxAv *av, void (*callback)(ToxAv *, int32_t, vpx_image_t *, void *), | ||
252 | void *user_data) | ||
253 | { | 210 | { |
254 | av->video_callback = callback; | 211 | msi_register_callback(av->msi_session, (MSICallbackType)cb, (MSICallbackID) id, userdata); |
255 | av->video_callback_userdata = user_data; | ||
256 | } | 212 | } |
257 | 213 | ||
258 | /** | 214 | void toxav_register_audio_callback(ToxAv *av, ToxAvAudioCallback cb, void *userdata) |
259 | * @brief Call user. Use its friend_id. | ||
260 | * | ||
261 | * @param av Handler. | ||
262 | * @param user The user. | ||
263 | * @param call_type Call type. | ||
264 | * @param ringing_seconds Ringing timeout. | ||
265 | * @return int | ||
266 | * @retval 0 Success. | ||
267 | * @retval ToxAvError On error. | ||
268 | */ | ||
269 | int toxav_call (ToxAv *av, int32_t *call_index, int user, const ToxAvCSettings *csettings, int ringing_seconds ) | ||
270 | { | 215 | { |
271 | return msi_invite(av->msi_session, call_index, msicsettings_cast(csettings), ringing_seconds * 1000, user); | 216 | av->acb.first = cb; |
217 | av->acb.second = userdata; | ||
272 | } | 218 | } |
273 | 219 | ||
274 | /** | 220 | void toxav_register_video_callback(ToxAv *av, ToxAvVideoCallback cb, void *userdata) |
275 | * @brief Hangup active call. | ||
276 | * | ||
277 | * @param av Handler. | ||
278 | * @return int | ||
279 | * @retval 0 Success. | ||
280 | * @retval ToxAvError On error. | ||
281 | */ | ||
282 | int toxav_hangup ( ToxAv *av, int32_t call_index ) | ||
283 | { | 221 | { |
284 | if ( cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] ) { | 222 | av->vcb.first = cb; |
285 | return ErrorNoCall; | 223 | av->vcb.second = userdata; |
286 | } | 224 | } |
287 | 225 | ||
288 | if ( av->msi_session->calls[call_index]->state != call_active ) { | 226 | int toxav_call (ToxAv *av, |
289 | return ErrorInvalidState; | 227 | int32_t *call_index, |
290 | } | 228 | int user, |
229 | const ToxAvCSettings *csettings, | ||
230 | int ringing_seconds ) | ||
231 | { | ||
232 | return msi_invite(av->msi_session, call_index, msicsettings_cast(csettings), ringing_seconds * 1000, user); | ||
233 | } | ||
291 | 234 | ||
235 | int toxav_hangup ( ToxAv *av, int32_t call_index ) | ||
236 | { | ||
292 | return msi_hangup(av->msi_session, call_index); | 237 | return msi_hangup(av->msi_session, call_index); |
293 | } | 238 | } |
294 | 239 | ||
295 | /** | ||
296 | * @brief Answer incomming call. | ||
297 | * | ||
298 | * @param av Handler. | ||
299 | * @param call_type Answer with... | ||
300 | * @return int | ||
301 | * @retval 0 Success. | ||
302 | * @retval ToxAvError On error. | ||
303 | */ | ||
304 | int toxav_answer ( ToxAv *av, int32_t call_index, const ToxAvCSettings *csettings ) | 240 | int toxav_answer ( ToxAv *av, int32_t call_index, const ToxAvCSettings *csettings ) |
305 | { | 241 | { |
306 | if ( cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] ) { | ||
307 | return ErrorNoCall; | ||
308 | } | ||
309 | |||
310 | if ( av->msi_session->calls[call_index]->state != call_starting ) { | ||
311 | return ErrorInvalidState; | ||
312 | } | ||
313 | |||
314 | return msi_answer(av->msi_session, call_index, msicsettings_cast(csettings)); | 242 | return msi_answer(av->msi_session, call_index, msicsettings_cast(csettings)); |
315 | } | 243 | } |
316 | 244 | ||
317 | /** | ||
318 | * @brief Reject incomming call. | ||
319 | * | ||
320 | * @param av Handler. | ||
321 | * @param reason Optional reason. Set NULL if none. | ||
322 | * @return int | ||
323 | * @retval 0 Success. | ||
324 | * @retval ToxAvError On error. | ||
325 | */ | ||
326 | int toxav_reject ( ToxAv *av, int32_t call_index, const char *reason ) | 245 | int toxav_reject ( ToxAv *av, int32_t call_index, const char *reason ) |
327 | { | 246 | { |
328 | if ( cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] ) { | ||
329 | return ErrorNoCall; | ||
330 | } | ||
331 | |||
332 | if ( av->msi_session->calls[call_index]->state != call_starting ) { | ||
333 | return ErrorInvalidState; | ||
334 | } | ||
335 | |||
336 | return msi_reject(av->msi_session, call_index, reason); | 247 | return msi_reject(av->msi_session, call_index, reason); |
337 | } | 248 | } |
338 | 249 | ||
339 | /** | ||
340 | * @brief Cancel outgoing request. | ||
341 | * | ||
342 | * @param av Handler. | ||
343 | * @param reason Optional reason. | ||
344 | * @param peer_id peer friend_id | ||
345 | * @return int | ||
346 | * @retval 0 Success. | ||
347 | * @retval ToxAvError On error. | ||
348 | */ | ||
349 | int toxav_cancel ( ToxAv *av, int32_t call_index, int peer_id, const char *reason ) | 250 | int toxav_cancel ( ToxAv *av, int32_t call_index, int peer_id, const char *reason ) |
350 | { | 251 | { |
351 | if ( cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] ) { | ||
352 | return ErrorNoCall; | ||
353 | } | ||
354 | |||
355 | if ( av->msi_session->calls[call_index]->state != call_inviting ) { | ||
356 | return ErrorInvalidState; | ||
357 | } | ||
358 | |||
359 | return msi_cancel(av->msi_session, call_index, peer_id, reason); | 252 | return msi_cancel(av->msi_session, call_index, peer_id, reason); |
360 | } | 253 | } |
361 | 254 | ||
362 | /** | ||
363 | * @brief Notify peer that we are changing call type | ||
364 | * | ||
365 | * @param av Handler. | ||
366 | * @return int | ||
367 | * @param call_type Change to... | ||
368 | * @retval 0 Success. | ||
369 | * @retval ToxAvError On error. | ||
370 | */ | ||
371 | int toxav_change_settings(ToxAv *av, int32_t call_index, const ToxAvCSettings *csettings) | 255 | int toxav_change_settings(ToxAv *av, int32_t call_index, const ToxAvCSettings *csettings) |
372 | { | 256 | { |
373 | if ( cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] ) { | ||
374 | return ErrorNoCall; | ||
375 | } | ||
376 | |||
377 | return msi_change_csettings(av->msi_session, call_index, msicsettings_cast(csettings)); | 257 | return msi_change_csettings(av->msi_session, call_index, msicsettings_cast(csettings)); |
378 | } | 258 | } |
379 | 259 | ||
380 | /** | ||
381 | * @brief Terminate transmission. Note that transmission will be terminated without informing remote peer. | ||
382 | * | ||
383 | * @param av Handler. | ||
384 | * @return int | ||
385 | * @retval 0 Success. | ||
386 | * @retval ToxAvError On error. | ||
387 | */ | ||
388 | int toxav_stop_call ( ToxAv *av, int32_t call_index ) | 260 | int toxav_stop_call ( ToxAv *av, int32_t call_index ) |
389 | { | 261 | { |
390 | if ( cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] ) { | ||
391 | return ErrorNoCall; | ||
392 | } | ||
393 | |||
394 | return msi_stopcall(av->msi_session, call_index); | 262 | return msi_stopcall(av->msi_session, call_index); |
395 | } | 263 | } |
396 | 264 | ||
397 | /** | 265 | int toxav_prepare_transmission ( ToxAv *av, int32_t call_index, int support_video ) |
398 | * @brief Must be call before any RTP transmission occurs. | ||
399 | * | ||
400 | * @param av Handler. | ||
401 | * @return int | ||
402 | * @retval 0 Success. | ||
403 | * @retval ToxAvError On error. | ||
404 | */ | ||
405 | int toxav_prepare_transmission ( ToxAv *av, int32_t call_index, uint32_t jbuf_capacity, uint32_t VAD_treshold, | ||
406 | int support_video ) | ||
407 | { | 266 | { |
408 | if ( !av->msi_session || cii(call_index, av->msi_session) || | 267 | if ( !av->msi_session || CALL_INVALID_INDEX(call_index, av->msi_session->max_calls) || |
409 | !av->msi_session->calls[call_index] || !av->msi_session->calls[call_index]->csettings_peer || | 268 | !av->msi_session->calls[call_index] || !av->msi_session->calls[call_index]->csettings_peer) { |
410 | av->calls[call_index].call_active) { | ||
411 | LOGGER_ERROR("Error while starting RTP session: invalid call!\n"); | 269 | LOGGER_ERROR("Error while starting RTP session: invalid call!\n"); |
412 | return ErrorInternal; | 270 | return av_ErrorNoCall; |
413 | } | 271 | } |
414 | 272 | ||
415 | CallSpecific *call = &av->calls[call_index]; | 273 | ToxAvCall *call = &av->calls[call_index]; |
274 | |||
275 | pthread_mutex_lock(call->mutex); | ||
276 | |||
277 | if (call->active) { | ||
278 | pthread_mutex_unlock(call->mutex); | ||
279 | LOGGER_ERROR("Error while starting RTP session: call already active!\n"); | ||
280 | return av_ErrorAlreadyInCallWithPeer; | ||
281 | } | ||
282 | |||
283 | if (pthread_mutex_init(call->mutex_encoding_audio, NULL) != 0 | ||
284 | || pthread_mutex_init(call->mutex_encoding_video, NULL) != 0 || pthread_mutex_init(call->mutex_do, NULL) != 0) { | ||
285 | pthread_mutex_unlock(call->mutex); | ||
286 | LOGGER_ERROR("Error while starting RTP session: mutex initializing failed!\n"); | ||
287 | return av_ErrorUnknown; | ||
288 | } | ||
289 | |||
290 | const ToxAvCSettings *c_peer = toxavcsettings_cast | ||
291 | (&av->msi_session->calls[call_index]->csettings_peer[0]); | ||
292 | const ToxAvCSettings *c_self = toxavcsettings_cast | ||
293 | (&av->msi_session->calls[call_index]->csettings_local); | ||
294 | |||
295 | LOGGER_DEBUG( | ||
296 | "Type: %u(s) %u(p)\n" | ||
297 | "Video bitrate: %u(s) %u(p)\n" | ||
298 | "Video height: %u(s) %u(p)\n" | ||
299 | "Video width: %u(s) %u(p)\n" | ||
300 | "Audio bitrate: %u(s) %u(p)\n" | ||
301 | "Audio framedur: %u(s) %u(p)\n" | ||
302 | "Audio sample rate: %u(s) %u(p)\n" | ||
303 | "Audio channels: %u(s) %u(p)\n", | ||
304 | c_self->call_type, c_peer->call_type, | ||
305 | c_self->video_bitrate, c_peer->video_bitrate, | ||
306 | c_self->max_video_height, c_peer->max_video_height, | ||
307 | c_self->max_video_width, c_peer->max_video_width, | ||
308 | c_self->audio_bitrate, c_peer->audio_bitrate, | ||
309 | c_self->audio_frame_duration, c_peer->audio_frame_duration, | ||
310 | c_self->audio_sample_rate, c_peer->audio_sample_rate, | ||
311 | c_self->audio_channels, c_peer->audio_channels ); | ||
312 | |||
313 | if ( !(call->cs = cs_new(c_self, c_peer, jbuf_capacity, support_video)) ) { | ||
314 | LOGGER_ERROR("Error while starting Codec State!\n"); | ||
315 | pthread_mutex_unlock(call->mutex); | ||
316 | return av_ErrorInitializingCodecs; | ||
317 | } | ||
318 | |||
319 | call->cs->agent = av; | ||
320 | call->cs->call_idx = call_index; | ||
321 | |||
322 | call->cs->acb.first = av->acb.first; | ||
323 | call->cs->acb.second = av->acb.second; | ||
324 | |||
325 | call->cs->vcb.first = av->vcb.first; | ||
326 | call->cs->vcb.second = av->vcb.second; | ||
416 | 327 | ||
417 | call->crtps[audio_index] = | ||
418 | rtp_init_session(type_audio, av->messenger, av->msi_session->calls[call_index]->peers[0]); | ||
419 | 328 | ||
329 | call->crtps[audio_index] = | ||
330 | rtp_new(msi_TypeAudio, av->messenger, av->msi_session->calls[call_index]->peers[0]); | ||
420 | 331 | ||
421 | if ( !call->crtps[audio_index] ) { | 332 | if ( !call->crtps[audio_index] ) { |
422 | LOGGER_ERROR("Error while starting audio RTP session!\n"); | 333 | LOGGER_ERROR("Error while starting audio RTP session!\n"); |
423 | return ErrorInternal; | 334 | goto error; |
424 | } | 335 | } |
425 | 336 | ||
426 | call->crtps[audio_index]->call_index = call_index; | 337 | call->crtps[audio_index]->cs = call->cs; |
427 | call->crtps[audio_index]->av = av; | ||
428 | 338 | ||
429 | if ( support_video ) { | 339 | if ( support_video ) { |
430 | call->crtps[video_index] = | 340 | call->crtps[video_index] = |
431 | rtp_init_session(type_video, av->messenger, av->msi_session->calls[call_index]->peers[0]); | 341 | rtp_new(msi_TypeVideo, av->messenger, av->msi_session->calls[call_index]->peers[0]); |
432 | 342 | ||
433 | if ( !call->crtps[video_index] ) { | 343 | if ( !call->crtps[video_index] ) { |
434 | LOGGER_ERROR("Error while starting video RTP session!\n"); | 344 | LOGGER_ERROR("Error while starting video RTP session!\n"); |
435 | goto error; | 345 | goto error; |
436 | } | 346 | } |
437 | 347 | ||
438 | call->crtps[video_index]->call_index = call_index; | 348 | call->crtps[video_index]->cs = call->cs; |
439 | call->crtps[video_index]->av = av; | ||
440 | |||
441 | call->frame_limit = 0; | ||
442 | call->frame_id = 0; | ||
443 | call->frame_outid = 0; | ||
444 | |||
445 | call->frame_buf = calloc(MAX_VIDEOFRAME_SIZE, 1); | ||
446 | |||
447 | if (!call->frame_buf) { | ||
448 | LOGGER_WARNING("Frame buffer allocation failed!"); | ||
449 | goto error; | ||
450 | } | ||
451 | |||
452 | } | ||
453 | |||
454 | if ( !(call->j_buf = create_queue(jbuf_capacity)) ) { | ||
455 | LOGGER_WARNING("Jitter buffer creaton failed!"); | ||
456 | goto error; | ||
457 | } | ||
458 | |||
459 | ToxAvCSettings csettings_peer = toxavcsettings_cast(&av->msi_session->calls[call_index]->csettings_peer[0]); | ||
460 | ToxAvCSettings csettings_local = toxavcsettings_cast(&av->msi_session->calls[call_index]->csettings_local); | ||
461 | LOGGER_DEBUG( | ||
462 | "Type: %u \n" | ||
463 | "Video bitrate: %u \n" | ||
464 | "Video height: %u \n" | ||
465 | "Video width: %u \n" | ||
466 | "Audio bitrate: %u \n" | ||
467 | "Audio framedur: %u \n" | ||
468 | "Audio sample rate: %u \n" | ||
469 | "Audio channels: %u \n", | ||
470 | csettings_peer.call_type, | ||
471 | csettings_peer.video_bitrate, | ||
472 | csettings_peer.max_video_height, | ||
473 | csettings_peer.max_video_width, | ||
474 | csettings_peer.audio_bitrate, | ||
475 | csettings_peer.audio_frame_duration, | ||
476 | csettings_peer.audio_sample_rate, | ||
477 | csettings_peer.audio_channels ); | ||
478 | |||
479 | if ( (call->cs = codec_init_session(csettings_local.audio_bitrate, | ||
480 | csettings_local.audio_frame_duration, | ||
481 | csettings_local.audio_sample_rate, | ||
482 | csettings_local.audio_channels, | ||
483 | csettings_peer.audio_channels, | ||
484 | VAD_treshold, | ||
485 | csettings_local.max_video_width, | ||
486 | csettings_local.max_video_height, | ||
487 | csettings_local.video_bitrate) )) { | ||
488 | |||
489 | if ( pthread_mutex_init(&call->mutex, NULL) != 0 ) goto error; | ||
490 | |||
491 | //todo: add error checks | ||
492 | pthread_mutex_init(&call->decode_cond_mutex, NULL); | ||
493 | pthread_cond_init(&call->decode_cond, NULL); | ||
494 | |||
495 | void **arg = malloc(2 * sizeof(void *)); | ||
496 | arg[0] = av; | ||
497 | arg[1] = call; | ||
498 | |||
499 | pthread_t temp; | ||
500 | pthread_attr_t attr; | ||
501 | |||
502 | pthread_attr_init(&attr); | ||
503 | pthread_attr_setstacksize(&attr, 1 << 18); | ||
504 | pthread_create(&temp, &attr, toxav_decoding, arg); | ||
505 | pthread_attr_destroy(&attr); | ||
506 | |||
507 | |||
508 | LOGGER_WARNING("Got here"); | ||
509 | call->call_active = 1; | ||
510 | |||
511 | return ErrorNone; | ||
512 | } | 349 | } |
513 | 350 | ||
351 | call->active = 1; | ||
352 | pthread_mutex_unlock(call->mutex); | ||
353 | return av_ErrorNone; | ||
514 | error: | 354 | error: |
515 | rtp_terminate_session(call->crtps[audio_index], av->messenger); | 355 | rtp_kill(call->crtps[audio_index], av->messenger); |
516 | rtp_terminate_session(call->crtps[video_index], av->messenger); | 356 | call->crtps[audio_index] = NULL; |
517 | free(call->frame_buf); | 357 | rtp_kill(call->crtps[video_index], av->messenger); |
518 | terminate_queue(call->j_buf); | 358 | call->crtps[video_index] = NULL; |
519 | codec_terminate_session(call->cs); | 359 | cs_kill(call->cs); |
360 | call->cs = NULL; | ||
361 | call->active = 0; | ||
362 | pthread_mutex_destroy(call->mutex_encoding_audio); | ||
363 | pthread_mutex_destroy(call->mutex_encoding_video); | ||
364 | pthread_mutex_destroy(call->mutex_do); | ||
520 | 365 | ||
521 | return ErrorInternal; | 366 | pthread_mutex_unlock(call->mutex); |
367 | return av_ErrorCreatingRtpSessions; | ||
522 | } | 368 | } |
523 | 369 | ||
524 | /** | ||
525 | * @brief Call this at the end of the transmission. | ||
526 | * | ||
527 | * @param av Handler. | ||
528 | * @return int | ||
529 | * @retval 0 Success. | ||
530 | * @retval ToxAvError On error. | ||
531 | */ | ||
532 | int toxav_kill_transmission ( ToxAv *av, int32_t call_index ) | 370 | int toxav_kill_transmission ( ToxAv *av, int32_t call_index ) |
533 | { | 371 | { |
534 | if (cii(call_index, av->msi_session)) { | 372 | if (CALL_INVALID_INDEX(call_index, av->msi_session->max_calls)) { |
535 | LOGGER_WARNING("Invalid call index: %d", call_index); | 373 | LOGGER_WARNING("Invalid call index: %d", call_index); |
536 | return ErrorNoCall; | 374 | return av_ErrorNoCall; |
537 | } | 375 | } |
538 | 376 | ||
539 | CallSpecific *call = &av->calls[call_index]; | 377 | ToxAvCall *call = &av->calls[call_index]; |
540 | 378 | ||
541 | pthread_mutex_lock(&call->mutex); | 379 | pthread_mutex_lock(call->mutex); |
542 | 380 | ||
543 | if (!call->call_active) { | 381 | if (!call->active) { |
544 | pthread_mutex_unlock(&call->mutex); | 382 | pthread_mutex_unlock(call->mutex); |
545 | LOGGER_WARNING("Action on inactive call: %d", call_index); | 383 | LOGGER_WARNING("Action on inactive call: %d", call_index); |
546 | return ErrorNoCall; | 384 | return av_ErrorInvalidState; |
547 | } | 385 | } |
548 | 386 | ||
387 | call->active = 0; | ||
549 | 388 | ||
550 | call->call_active = 0; | 389 | pthread_mutex_lock(call->mutex_encoding_audio); |
390 | pthread_mutex_unlock(call->mutex_encoding_audio); | ||
391 | pthread_mutex_lock(call->mutex_encoding_video); | ||
392 | pthread_mutex_unlock(call->mutex_encoding_video); | ||
393 | pthread_mutex_lock(call->mutex_do); | ||
394 | pthread_mutex_unlock(call->mutex_do); | ||
551 | 395 | ||
552 | rtp_terminate_session(call->crtps[audio_index], av->messenger); | 396 | rtp_kill(call->crtps[audio_index], av->messenger); |
553 | call->crtps[audio_index] = NULL; | 397 | call->crtps[audio_index] = NULL; |
554 | rtp_terminate_session(call->crtps[video_index], av->messenger); | 398 | rtp_kill(call->crtps[video_index], av->messenger); |
555 | call->crtps[video_index] = NULL; | 399 | call->crtps[video_index] = NULL; |
556 | terminate_queue(call->j_buf); | 400 | cs_kill(call->cs); |
557 | call->j_buf = NULL; | ||
558 | |||
559 | int i; | ||
560 | DECODE_PACKET *p; | ||
561 | |||
562 | call->exit = 1; | ||
563 | pthread_mutex_lock(&call->decode_cond_mutex); | ||
564 | pthread_cond_signal(&call->decode_cond); | ||
565 | pthread_cond_wait(&call->decode_cond, &call->decode_cond_mutex); | ||
566 | pthread_mutex_unlock(&call->decode_cond_mutex); | ||
567 | pthread_mutex_destroy(&call->decode_cond_mutex); | ||
568 | pthread_cond_destroy(&call->decode_cond); | ||
569 | |||
570 | for (i = 0; i != VIDEO_DECODE_QUEUE_SIZE; i++) { | ||
571 | p = call->video_decode_queue[i]; | ||
572 | call->video_decode_queue[i] = NULL; | ||
573 | |||
574 | if (p) { | ||
575 | free(p); | ||
576 | } | ||
577 | } | ||
578 | |||
579 | for (i = 0; i != AUDIO_DECODE_QUEUE_SIZE; i++) { | ||
580 | p = call->audio_decode_queue[i]; | ||
581 | call->audio_decode_queue[i] = NULL; | ||
582 | |||
583 | if (p) { | ||
584 | free(p); | ||
585 | } | ||
586 | } | ||
587 | |||
588 | codec_terminate_session(call->cs); | ||
589 | call->cs = NULL; | 401 | call->cs = NULL; |
590 | 402 | ||
591 | pthread_mutex_unlock(&call->mutex); | 403 | pthread_mutex_destroy(call->mutex_encoding_audio); |
592 | pthread_mutex_destroy(&call->mutex); | 404 | pthread_mutex_destroy(call->mutex_encoding_video); |
405 | pthread_mutex_destroy(call->mutex_do); | ||
593 | 406 | ||
594 | memset(call, 0, sizeof(CallSpecific)); | 407 | pthread_mutex_unlock(call->mutex); |
595 | return ErrorNone; | ||
596 | } | ||
597 | 408 | ||
409 | return av_ErrorNone; | ||
410 | } | ||
598 | 411 | ||
599 | /** | 412 | static int toxav_send_rtp_payload(ToxAv *av, |
600 | * @brief Send RTP payload. | 413 | ToxAvCall *call, |
601 | * | 414 | ToxAvCallType type, |
602 | * @param av Handler. | 415 | const uint8_t *payload, |
603 | * @param type Type of payload. | ||
604 | * @param payload The payload. | ||
605 | * @param length Size of it. | ||
606 | * @return int | ||
607 | * @retval 0 Success. | ||
608 | * @retval -1 Failure. | ||
609 | */ | ||
610 | static int toxav_send_rtp_payload(ToxAv *av, int32_t call_index, ToxAvCallType type, const uint8_t *payload, | ||
611 | unsigned int length) | 416 | unsigned int length) |
612 | { | 417 | { |
613 | CallSpecific *call = &av->calls[call_index]; | 418 | if (call->crtps[type - av_TypeAudio]) { |
614 | |||
615 | if (call->crtps[type - TypeAudio]) { | ||
616 | 419 | ||
617 | if (type == TypeAudio) { | 420 | /* Audio */ |
618 | return rtp_send_msg(call->crtps[type - TypeAudio], av->messenger, payload, length); | 421 | if (type == av_TypeAudio) |
619 | } else { | 422 | return rtp_send_msg(call->crtps[audio_index], av->messenger, payload, length); |
620 | if (length == 0 || length > MAX_VIDEOFRAME_SIZE) { | ||
621 | LOGGER_ERROR("Invalid video frame size: %u\n", length); | ||
622 | return ErrorInternal; | ||
623 | } | ||
624 | |||
625 | /* number of pieces - 1*/ | ||
626 | uint8_t numparts = (length - 1) / VIDEOFRAME_PIECE_SIZE; | ||
627 | 423 | ||
628 | uint8_t load[2 + VIDEOFRAME_PIECE_SIZE]; | 424 | /* Video */ |
629 | load[0] = call->frame_outid++; | 425 | int parts = cs_split_video_payload(call->cs, payload, length); |
630 | load[1] = 0; | ||
631 | 426 | ||
632 | int i; | 427 | if (parts < 0) return parts; |
633 | 428 | ||
634 | for (i = 0; i < numparts; i++) { | 429 | uint16_t part_size; |
635 | memcpy(load + VIDEOFRAME_HEADER_SIZE, payload, VIDEOFRAME_PIECE_SIZE); | 430 | const uint8_t *iter; |
636 | payload += VIDEOFRAME_PIECE_SIZE; | ||
637 | 431 | ||
638 | if (rtp_send_msg(call->crtps[type - TypeAudio], av->messenger, | 432 | int i; |
639 | load, VIDEOFRAME_HEADER_SIZE + VIDEOFRAME_PIECE_SIZE) != 0) { | ||
640 | 433 | ||
641 | return ErrorInternal; | 434 | for (i = 0; i < parts; i++) { |
642 | } | 435 | iter = cs_get_split_video_frame(call->cs, &part_size); |
643 | |||
644 | load[1]++; | ||
645 | } | ||
646 | 436 | ||
647 | /* remainder = length % VIDEOFRAME_PIECE_SIZE, VIDEOFRAME_PIECE_SIZE if = 0 */ | 437 | if (rtp_send_msg(call->crtps[video_index], av->messenger, iter, part_size) < 0) |
648 | length = ((length - 1) % VIDEOFRAME_PIECE_SIZE) + 1; | 438 | return av_ErrorSendingPayload; |
649 | memcpy(load + VIDEOFRAME_HEADER_SIZE, payload, length); | ||
650 | |||
651 | return rtp_send_msg(call->crtps[type - TypeAudio], av->messenger, load, VIDEOFRAME_HEADER_SIZE + length); | ||
652 | } | 439 | } |
653 | } else { | ||
654 | return ErrorNoRtpSession; | ||
655 | } | ||
656 | } | ||
657 | |||
658 | /** | ||
659 | * @brief Encode and send video packet. | ||
660 | * | ||
661 | * @param av Handler. | ||
662 | * @param input The packet. | ||
663 | * @return int | ||
664 | * @retval 0 Success. | ||
665 | * @retval ToxAvError On error. | ||
666 | */ | ||
667 | int toxav_send_video ( ToxAv *av, int32_t call_index, const uint8_t *frame, unsigned int frame_size) | ||
668 | { | ||
669 | |||
670 | if (cii(call_index, av->msi_session)) { | ||
671 | LOGGER_WARNING("Invalid call index: %d", call_index); | ||
672 | return ErrorNoCall; | ||
673 | } | ||
674 | |||
675 | CallSpecific *call = &av->calls[call_index]; | ||
676 | pthread_mutex_lock(&call->mutex); | ||
677 | 440 | ||
441 | return av_ErrorNone; | ||
678 | 442 | ||
679 | if (!call->call_active) { | 443 | } else return av_ErrorNoRtpSession; |
680 | pthread_mutex_unlock(&call->mutex); | ||
681 | LOGGER_WARNING("Action on inactive call: %d", call_index); | ||
682 | return ErrorNoCall; | ||
683 | } | ||
684 | |||
685 | int rc = toxav_send_rtp_payload(av, call_index, TypeVideo, frame, frame_size); | ||
686 | pthread_mutex_unlock(&call->mutex); | ||
687 | |||
688 | return rc; | ||
689 | } | 444 | } |
690 | 445 | ||
691 | /** | 446 | int toxav_prepare_video_frame ( ToxAv *av, int32_t call_index, uint8_t *dest, int dest_max, vpx_image_t *input) |
692 | * @brief Encode video frame | ||
693 | * | ||
694 | * @param av Handler | ||
695 | * @param dest Where to | ||
696 | * @param dest_max Max size | ||
697 | * @param input What to encode | ||
698 | * @return int | ||
699 | * @retval ToxAvError On error. | ||
700 | * @retval >0 On success | ||
701 | */ | ||
702 | int toxav_prepare_video_frame(ToxAv *av, int32_t call_index, uint8_t *dest, int dest_max, vpx_image_t *input) | ||
703 | { | 447 | { |
704 | if (cii(call_index, av->msi_session)) { | 448 | if (CALL_INVALID_INDEX(call_index, av->msi_session->max_calls)) { |
705 | LOGGER_WARNING("Invalid call index: %d", call_index); | 449 | LOGGER_WARNING("Invalid call index: %d", call_index); |
706 | return ErrorNoCall; | 450 | return av_ErrorNoCall; |
707 | } | 451 | } |
708 | 452 | ||
709 | 453 | ||
710 | CallSpecific *call = &av->calls[call_index]; | 454 | ToxAvCall *call = &av->calls[call_index]; |
711 | pthread_mutex_lock(&call->mutex); | 455 | pthread_mutex_lock(call->mutex); |
712 | 456 | ||
713 | if (!call->call_active) { | 457 | if (!call->active) { |
714 | pthread_mutex_unlock(&call->mutex); | 458 | pthread_mutex_unlock(call->mutex); |
715 | LOGGER_WARNING("Action on inactive call: %d", call_index); | 459 | LOGGER_WARNING("Action on inactive call: %d", call_index); |
716 | return ErrorNoCall; | 460 | return av_ErrorInvalidState; |
717 | } | 461 | } |
718 | 462 | ||
719 | if (reconfigure_video_encoder_resolution(call->cs, input->d_w, input->d_h) != 0) { | 463 | if (cs_set_video_encoder_resolution(call->cs, input->d_w, input->d_h) < 0) { |
720 | pthread_mutex_unlock(&call->mutex); | 464 | pthread_mutex_unlock(call->mutex); |
721 | return ErrorInternal; | 465 | return av_ErrorSettingVideoResolution; |
722 | } | 466 | } |
723 | 467 | ||
468 | pthread_mutex_lock(call->mutex_encoding_video); | ||
469 | pthread_mutex_unlock(call->mutex); | ||
470 | |||
724 | int rc = vpx_codec_encode(&call->cs->v_encoder, input, call->cs->frame_counter, 1, 0, MAX_ENCODE_TIME_US); | 471 | int rc = vpx_codec_encode(&call->cs->v_encoder, input, call->cs->frame_counter, 1, 0, MAX_ENCODE_TIME_US); |
725 | 472 | ||
726 | if ( rc != VPX_CODEC_OK) { | 473 | if ( rc != VPX_CODEC_OK) { |
727 | LOGGER_ERROR("Could not encode video frame: %s\n", vpx_codec_err_to_string(rc)); | 474 | LOGGER_ERROR("Could not encode video frame: %s\n", vpx_codec_err_to_string(rc)); |
728 | pthread_mutex_unlock(&call->mutex); | 475 | pthread_mutex_unlock(call->mutex_encoding_video); |
729 | return ErrorInternal; | 476 | return av_ErrorEncodingVideo; |
730 | } | 477 | } |
731 | 478 | ||
732 | ++call->cs->frame_counter; | 479 | ++call->cs->frame_counter; |
@@ -738,8 +485,8 @@ int toxav_prepare_video_frame(ToxAv *av, int32_t call_index, uint8_t *dest, int | |||
738 | while ( (pkt = vpx_codec_get_cx_data(&call->cs->v_encoder, &iter)) ) { | 485 | while ( (pkt = vpx_codec_get_cx_data(&call->cs->v_encoder, &iter)) ) { |
739 | if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) { | 486 | if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) { |
740 | if ( copied + pkt->data.frame.sz > dest_max ) { | 487 | if ( copied + pkt->data.frame.sz > dest_max ) { |
741 | pthread_mutex_unlock(&call->mutex); | 488 | pthread_mutex_unlock(call->mutex_encoding_video); |
742 | return ErrorPacketTooLarge; | 489 | return av_ErrorPacketTooLarge; |
743 | } | 490 | } |
744 | 491 | ||
745 | memcpy(dest + copied, pkt->data.frame.buf, pkt->data.frame.sz); | 492 | memcpy(dest + copied, pkt->data.frame.buf, pkt->data.frame.sz); |
@@ -747,402 +494,198 @@ int toxav_prepare_video_frame(ToxAv *av, int32_t call_index, uint8_t *dest, int | |||
747 | } | 494 | } |
748 | } | 495 | } |
749 | 496 | ||
750 | pthread_mutex_unlock(&call->mutex); | 497 | pthread_mutex_unlock(call->mutex_encoding_video); |
751 | return copied; | 498 | return copied; |
752 | } | 499 | } |
753 | 500 | ||
754 | /** | 501 | int toxav_send_video ( ToxAv *av, int32_t call_index, const uint8_t *frame, unsigned int frame_size) |
755 | * @brief Send audio frame. | ||
756 | * | ||
757 | * @param av Handler. | ||
758 | * @param data The audio data encoded with toxav_prepare_audio_frame(). | ||
759 | * @param size Its size in number of bytes. | ||
760 | * @return int | ||
761 | * @retval 0 Success. | ||
762 | * @retval ToxAvError On error. | ||
763 | */ | ||
764 | int toxav_send_audio ( ToxAv *av, int32_t call_index, const uint8_t *data, unsigned int size) | ||
765 | { | 502 | { |
766 | if (size > MAX_CRYPTO_DATA_SIZE) | ||
767 | return ErrorInternal; | ||
768 | 503 | ||
769 | if (cii(call_index, av->msi_session) || !av->calls[call_index].call_active) { | 504 | if (CALL_INVALID_INDEX(call_index, av->msi_session->max_calls)) { |
770 | LOGGER_WARNING("Action on inactive call: %d", call_index); | 505 | LOGGER_WARNING("Invalid call index: %d", call_index); |
771 | return ErrorNoCall; | 506 | return av_ErrorNoCall; |
772 | } | 507 | } |
773 | 508 | ||
774 | CallSpecific *call = &av->calls[call_index]; | 509 | ToxAvCall *call = &av->calls[call_index]; |
775 | pthread_mutex_lock(&call->mutex); | 510 | pthread_mutex_lock(call->mutex); |
776 | 511 | ||
777 | 512 | ||
778 | if (!call->call_active) { | 513 | if (!call->active) { |
779 | pthread_mutex_unlock(&call->mutex); | 514 | pthread_mutex_unlock(call->mutex); |
780 | LOGGER_WARNING("Action on inactive call: %d", call_index); | 515 | LOGGER_WARNING("Action on inactive call: %d", call_index); |
781 | return ErrorNoCall; | 516 | return av_ErrorInvalidState; |
782 | } | 517 | } |
783 | 518 | ||
784 | int rc = toxav_send_rtp_payload(av, call_index, TypeAudio, data, size); | 519 | int rc = toxav_send_rtp_payload(av, call, av_TypeVideo, frame, frame_size); |
785 | pthread_mutex_unlock(&call->mutex); | 520 | pthread_mutex_unlock(call->mutex); |
786 | 521 | ||
787 | return rc; | 522 | return rc; |
788 | } | 523 | } |
789 | 524 | ||
790 | /** | 525 | int toxav_prepare_audio_frame ( ToxAv *av, |
791 | * @brief Encode audio frame | 526 | int32_t call_index, |
792 | * | 527 | uint8_t *dest, |
793 | * @param av Handler | 528 | int dest_max, |
794 | * @param dest dest | 529 | const int16_t *frame, |
795 | * @param dest_max Max dest size | ||
796 | * @param frame The frame | ||
797 | * @param frame_size The frame size | ||
798 | * @return int | ||
799 | * @retval ToxAvError On error. | ||
800 | * @retval >0 On success | ||
801 | */ | ||
802 | int toxav_prepare_audio_frame ( ToxAv *av, int32_t call_index, uint8_t *dest, int dest_max, const int16_t *frame, | ||
803 | int frame_size) | 530 | int frame_size) |
804 | { | 531 | { |
805 | if (cii(call_index, av->msi_session) || !av->calls[call_index].call_active) { | 532 | if (CALL_INVALID_INDEX(call_index, av->msi_session->max_calls)) { |
806 | LOGGER_WARNING("Action on inactive call: %d", call_index); | 533 | LOGGER_WARNING("Action on nonexisting call: %d", call_index); |
807 | return ErrorNoCall; | 534 | return av_ErrorNoCall; |
808 | } | 535 | } |
809 | 536 | ||
810 | CallSpecific *call = &av->calls[call_index]; | 537 | ToxAvCall *call = &av->calls[call_index]; |
811 | pthread_mutex_lock(&call->mutex); | 538 | pthread_mutex_lock(call->mutex); |
812 | 539 | ||
813 | 540 | if (!call->active) { | |
814 | if (!call->call_active) { | 541 | pthread_mutex_unlock(call->mutex); |
815 | pthread_mutex_unlock(&call->mutex); | ||
816 | LOGGER_WARNING("Action on inactive call: %d", call_index); | 542 | LOGGER_WARNING("Action on inactive call: %d", call_index); |
817 | return ErrorNoCall; | 543 | return av_ErrorInvalidState; |
818 | } | 544 | } |
819 | 545 | ||
546 | pthread_mutex_lock(call->mutex_encoding_audio); | ||
547 | pthread_mutex_unlock(call->mutex); | ||
820 | int32_t rc = opus_encode(call->cs->audio_encoder, frame, frame_size, dest, dest_max); | 548 | int32_t rc = opus_encode(call->cs->audio_encoder, frame, frame_size, dest, dest_max); |
821 | pthread_mutex_unlock(&call->mutex); | 549 | pthread_mutex_unlock(call->mutex_encoding_audio); |
822 | 550 | ||
823 | if (rc < 0) { | 551 | if (rc < 0) { |
824 | LOGGER_ERROR("Failed to encode payload: %s\n", opus_strerror(rc)); | 552 | LOGGER_ERROR("Failed to encode payload: %s\n", opus_strerror(rc)); |
825 | return ErrorInternal; | 553 | return av_ErrorEncodingAudio; |
826 | } | 554 | } |
827 | 555 | ||
828 | return rc; | 556 | return rc; |
829 | } | 557 | } |
830 | 558 | ||
831 | /** | 559 | int toxav_send_audio ( ToxAv *av, int32_t call_index, const uint8_t *data, unsigned int size) |
832 | * @brief Get peer transmission type. It can either be audio or video. | 560 | { |
833 | * | 561 | if (CALL_INVALID_INDEX(call_index, av->msi_session->max_calls)) { |
834 | * @param av Handler. | 562 | LOGGER_WARNING("Action on nonexisting call: %d", call_index); |
835 | * @param peer The peer | 563 | return av_ErrorNoCall; |
836 | * @return int | 564 | } |
837 | * @retval ToxAvCallType On success. | 565 | |
838 | * @retval ToxAvError On error. | 566 | ToxAvCall *call = &av->calls[call_index]; |
839 | */ | 567 | pthread_mutex_lock(call->mutex); |
568 | |||
569 | |||
570 | if (!call->active) { | ||
571 | pthread_mutex_unlock(call->mutex); | ||
572 | LOGGER_WARNING("Action on inactive call: %d", call_index); | ||
573 | return av_ErrorInvalidState; | ||
574 | } | ||
575 | |||
576 | int rc = toxav_send_rtp_payload(av, call, av_TypeAudio, data, size); | ||
577 | pthread_mutex_unlock(call->mutex); | ||
578 | return rc; | ||
579 | } | ||
580 | |||
840 | int toxav_get_peer_csettings ( ToxAv *av, int32_t call_index, int peer, ToxAvCSettings *dest ) | 581 | int toxav_get_peer_csettings ( ToxAv *av, int32_t call_index, int peer, ToxAvCSettings *dest ) |
841 | { | 582 | { |
842 | if ( peer < 0 || cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] | 583 | if ( peer < 0 || CALL_INVALID_INDEX(call_index, av->msi_session->max_calls) || |
843 | || av->msi_session->calls[call_index]->peer_count <= peer ) | 584 | !av->msi_session->calls[call_index] || av->msi_session->calls[call_index]->peer_count <= peer ) |
844 | return ErrorInternal; | 585 | return av_ErrorNoCall; |
845 | 586 | ||
846 | *dest = toxavcsettings_cast(&av->msi_session->calls[call_index]->csettings_peer[peer]); | 587 | *dest = *toxavcsettings_cast(&av->msi_session->calls[call_index]->csettings_peer[peer]); |
847 | return ErrorNone; | 588 | return av_ErrorNone; |
848 | } | 589 | } |
849 | 590 | ||
850 | /** | ||
851 | * @brief Get id of peer participating in conversation | ||
852 | * | ||
853 | * @param av Handler | ||
854 | * @param peer peer index | ||
855 | * @return int | ||
856 | * @retval ToxAvError No peer id | ||
857 | */ | ||
858 | int toxav_get_peer_id ( ToxAv *av, int32_t call_index, int peer ) | 591 | int toxav_get_peer_id ( ToxAv *av, int32_t call_index, int peer ) |
859 | { | 592 | { |
860 | if ( peer < 0 || cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] | 593 | if ( peer < 0 || CALL_INVALID_INDEX(call_index, av->msi_session->max_calls) || !av->msi_session->calls[call_index] |
861 | || av->msi_session->calls[call_index]->peer_count <= peer ) | 594 | || av->msi_session->calls[call_index]->peer_count <= peer ) |
862 | return ErrorInternal; | 595 | return av_ErrorNoCall; |
863 | 596 | ||
864 | return av->msi_session->calls[call_index]->peers[peer]; | 597 | return av->msi_session->calls[call_index]->peers[peer]; |
865 | } | 598 | } |
866 | 599 | ||
867 | /** | ||
868 | * @brief Get id of peer participating in conversation | ||
869 | * | ||
870 | * @param av Handler | ||
871 | * @param peer peer index | ||
872 | * @return int | ||
873 | * @retval ToxAvError No peer id | ||
874 | */ | ||
875 | ToxAvCallState toxav_get_call_state(ToxAv *av, int32_t call_index) | 600 | ToxAvCallState toxav_get_call_state(ToxAv *av, int32_t call_index) |
876 | { | 601 | { |
877 | if ( cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] ) | 602 | if ( CALL_INVALID_INDEX(call_index, av->msi_session->max_calls) || !av->msi_session->calls[call_index] ) |
878 | return av_CallNonExistant; | 603 | return av_CallNonExistent; |
879 | 604 | ||
880 | return av->msi_session->calls[call_index]->state; | 605 | return av->msi_session->calls[call_index]->state; |
881 | 606 | ||
882 | } | 607 | } |
883 | 608 | ||
884 | /** | 609 | int toxav_capability_supported ( ToxAv *av, int32_t call_index, ToxAvCapabilities capability ) |
885 | * @brief Is certain capability supported | ||
886 | * | ||
887 | * @param av Handler | ||
888 | * @return int | ||
889 | * @retval 1 Yes. | ||
890 | * @retval 0 No. | ||
891 | */ | ||
892 | inline__ int toxav_capability_supported ( ToxAv *av, int32_t call_index, ToxAvCapabilities capability ) | ||
893 | { | 610 | { |
894 | return av->calls[call_index].cs ? av->calls[call_index].cs->capabilities & (Capabilities) capability : 0; | 611 | return av->calls[call_index].cs ? av->calls[call_index].cs->capabilities & (CSCapabilities) capability : 0; |
895 | /* 0 is error here */ | 612 | /* 0 is error here */ |
896 | } | 613 | } |
897 | 614 | ||
898 | inline__ Tox *toxav_get_tox(ToxAv *av) | 615 | Tox *toxav_get_tox(ToxAv *av) |
899 | { | 616 | { |
900 | return (Tox *)av->messenger; | 617 | return (Tox *)av->messenger; |
901 | } | 618 | } |
902 | 619 | ||
903 | int toxav_has_activity(ToxAv *av, int32_t call_index, int16_t *PCM, uint16_t frame_size, float ref_energy) | 620 | int toxav_get_active_count(ToxAv *av) |
904 | { | ||
905 | if ( !av->calls[call_index].cs ) return ErrorInvalidCodecState; | ||
906 | |||
907 | return energy_VAD(av->calls[call_index].cs, PCM, frame_size, ref_energy); | ||
908 | } | ||
909 | |||
910 | |||
911 | static void decode_video(ToxAv *av, CallSpecific *call, DECODE_PACKET *p) | ||
912 | { | 621 | { |
913 | int32_t call_index = call - av->calls; | 622 | if (!av) return -1; |
914 | 623 | ||
915 | int rc = vpx_codec_decode(&call->cs->v_decoder, p->data, p->size, NULL, MAX_DECODE_TIME_US); | 624 | int rc = 0, i = 0; |
916 | 625 | ||
917 | if (rc != VPX_CODEC_OK) { | 626 | for (; i < av->max_calls; i++) { |
918 | LOGGER_ERROR("Error decoding video: %s\n", vpx_codec_err_to_string(rc)); | 627 | pthread_mutex_lock(av->calls[i].mutex); |
919 | } | ||
920 | 628 | ||
921 | vpx_codec_iter_t iter = NULL; | 629 | if (av->calls[i].active) rc++; |
922 | vpx_image_t *img; | ||
923 | img = vpx_codec_get_frame(&call->cs->v_decoder, &iter); | ||
924 | 630 | ||
925 | if (img && av->video_callback) { | 631 | pthread_mutex_unlock(av->calls[i].mutex); |
926 | av->video_callback(av, call_index, img, av->video_callback_userdata); | ||
927 | } else { | ||
928 | LOGGER_WARNING("Video packet dropped due to missing callback or no image!"); | ||
929 | } | 632 | } |
930 | 633 | ||
931 | free(p); | 634 | return rc; |
932 | } | 635 | } |
933 | 636 | ||
934 | static void decode_audio(ToxAv *av, CallSpecific *call, DECODE_PACKET *p) | 637 | /* Create a new toxav group. |
638 | * | ||
639 | * return group number on success. | ||
640 | * return -1 on failure. | ||
641 | * | ||
642 | * Audio data callback format: | ||
643 | * audio_callback(Tox *tox, int groupnumber, int peernumber, const int16_t *pcm, unsigned int samples, uint8_t channels, unsigned int sample_rate, void *userdata) | ||
644 | * | ||
645 | * Note that total size of pcm in bytes is equal to (samples * channels * sizeof(int16_t)). | ||
646 | */ | ||
647 | int toxav_add_av_groupchat(Tox *tox, void (*audio_callback)(Messenger *, int, int, const int16_t *, unsigned int, | ||
648 | uint8_t, unsigned int, void *), void *userdata) | ||
935 | { | 649 | { |
936 | int32_t call_index = call - av->calls; | 650 | Messenger *m = tox; |
937 | 651 | return add_av_groupchat(m->group_chat_object, audio_callback, userdata); | |
938 | // ToxAvCSettings csettings; | ||
939 | // toxav_get_peer_csettings(av, call_index, 0, &csettings); | ||
940 | |||
941 | int frame_size = 10000; /* FIXME: not static? */ | ||
942 | int16_t dest[frame_size]; | ||
943 | |||
944 | int dec_size = opus_decode(call->cs->audio_decoder, p->data, p->size, dest, frame_size, (p->size == 0)); | ||
945 | free(p); | ||
946 | |||
947 | if (dec_size < 0) { | ||
948 | LOGGER_WARNING("Decoding error: %s", opus_strerror(dec_size)); | ||
949 | return; | ||
950 | } | ||
951 | |||
952 | if ( av->audio_callback ) | ||
953 | av->audio_callback(av, call_index, dest, dec_size, av->audio_callback_userdata); | ||
954 | else | ||
955 | LOGGER_WARNING("Audio packet dropped due to missing callback!"); | ||
956 | } | 652 | } |
957 | 653 | ||
958 | static void *toxav_decoding(void *arg) | 654 | /* Join a AV group (you need to have been invited first.) |
655 | * | ||
656 | * returns group number on success | ||
657 | * returns -1 on failure. | ||
658 | * | ||
659 | * Audio data callback format (same as the one for toxav_add_av_groupchat()): | ||
660 | * audio_callback(Tox *tox, int groupnumber, int peernumber, const int16_t *pcm, unsigned int samples, uint8_t channels, unsigned int sample_rate, void *userdata) | ||
661 | * | ||
662 | * Note that total size of pcm in bytes is equal to (samples * channels * sizeof(int16_t)). | ||
663 | */ | ||
664 | int toxav_join_av_groupchat(Tox *tox, int32_t friendnumber, const uint8_t *data, uint16_t length, | ||
665 | void (*audio_callback)(Messenger *, int, int, const int16_t *, unsigned int, uint8_t, unsigned int, void *), | ||
666 | void *userdata) | ||
959 | { | 667 | { |
960 | void **pp = arg; | 668 | Messenger *m = tox; |
961 | ToxAv *av = pp[0]; | 669 | return join_av_groupchat(m->group_chat_object, friendnumber, data, length, audio_callback, userdata); |
962 | CallSpecific *call = pp[1]; | ||
963 | free(pp); | ||
964 | |||
965 | while (1) { | ||
966 | DECODE_PACKET *p; | ||
967 | _Bool video = 0; | ||
968 | |||
969 | pthread_mutex_lock(&call->decode_cond_mutex); | ||
970 | |||
971 | if (call->exit) { | ||
972 | break; | ||
973 | } | ||
974 | |||
975 | uint8_t r; | ||
976 | |||
977 | /* first check for available packets, otherwise wait for condition*/ | ||
978 | r = call->audio_decode_read; | ||
979 | p = call->audio_decode_queue[r]; | ||
980 | |||
981 | if (!p) { | ||
982 | r = call->video_decode_read; | ||
983 | p = call->video_decode_queue[r]; | ||
984 | |||
985 | if (!p) { | ||
986 | pthread_cond_wait(&call->decode_cond, &call->decode_cond_mutex); | ||
987 | r = call->audio_decode_read; | ||
988 | p = call->audio_decode_queue[r]; | ||
989 | |||
990 | if (!p) { | ||
991 | r = call->video_decode_read; | ||
992 | p = call->video_decode_queue[r]; | ||
993 | video = 1; | ||
994 | } | ||
995 | } else { | ||
996 | video = 1; | ||
997 | } | ||
998 | } | ||
999 | |||
1000 | if (video) { | ||
1001 | if (p) { | ||
1002 | call->video_decode_queue[r] = NULL; | ||
1003 | call->video_decode_read = (r + 1) % VIDEO_DECODE_QUEUE_SIZE; | ||
1004 | } | ||
1005 | } else { | ||
1006 | call->audio_decode_queue[r] = NULL; | ||
1007 | call->audio_decode_read = (r + 1) % AUDIO_DECODE_QUEUE_SIZE; | ||
1008 | } | ||
1009 | |||
1010 | pthread_mutex_unlock(&call->decode_cond_mutex); | ||
1011 | |||
1012 | if (p) { | ||
1013 | if (video) { | ||
1014 | decode_video(av, call, p); | ||
1015 | } else { | ||
1016 | decode_audio(av, call, p); | ||
1017 | } | ||
1018 | } | ||
1019 | } | ||
1020 | |||
1021 | call->exit = 0; | ||
1022 | pthread_cond_signal(&call->decode_cond); | ||
1023 | pthread_mutex_unlock(&call->decode_cond_mutex); | ||
1024 | |||
1025 | return NULL; | ||
1026 | } | 670 | } |
1027 | 671 | ||
1028 | void toxav_handle_packet(RTPSession *_session, RTPMessage *_msg) | 672 | /* Send audio to the group chat. |
673 | * | ||
674 | * return 0 on success. | ||
675 | * return -1 on failure. | ||
676 | * | ||
677 | * Note that total size of pcm in bytes is equal to (samples * channels * sizeof(int16_t)). | ||
678 | * | ||
679 | * Valid number of samples are ((sample rate) * (audio length (Valid ones are: 2.5, 5, 10, 20, 40 or 60 ms)) / 1000) | ||
680 | * Valid number of channels are 1 or 2. | ||
681 | * Valid sample rates are 8000, 12000, 16000, 24000, or 48000. | ||
682 | * | ||
683 | * Recommended values are: samples = 960, channels = 1, sample_rate = 48000 | ||
684 | */ | ||
685 | int toxav_group_send_audio(Tox *tox, int groupnumber, const int16_t *pcm, unsigned int samples, uint8_t channels, | ||
686 | unsigned int sample_rate) | ||
1029 | { | 687 | { |
1030 | ToxAv *av = _session->av; | 688 | Messenger *m = tox; |
1031 | int32_t call_index = _session->call_index; | 689 | return group_send_audio(m->group_chat_object, groupnumber, pcm, samples, channels, sample_rate); |
1032 | CallSpecific *call = &av->calls[call_index]; | ||
1033 | |||
1034 | if (!call->call_active) return; | ||
1035 | |||
1036 | if (_session->payload_type == type_audio % 128) { | ||
1037 | queue(call->j_buf, _msg); | ||
1038 | |||
1039 | int success = 0; | ||
1040 | |||
1041 | while ((_msg = dequeue(call->j_buf, &success)) || success == 2) { | ||
1042 | DECODE_PACKET *p; | ||
1043 | |||
1044 | if (success == 2) { | ||
1045 | p = malloc(sizeof(DECODE_PACKET)); | ||
1046 | |||
1047 | if (p) { | ||
1048 | p->size = 0; | ||
1049 | } | ||
1050 | } else { | ||
1051 | p = malloc(sizeof(DECODE_PACKET) + _msg->length); | ||
1052 | |||
1053 | if (p) { | ||
1054 | p->size = _msg->length; | ||
1055 | memcpy(p->data, _msg->data, _msg->length); | ||
1056 | } | ||
1057 | |||
1058 | rtp_free_msg(NULL, _msg); | ||
1059 | } | ||
1060 | |||
1061 | if (p) { | ||
1062 | /* do the decoding on another thread */ | ||
1063 | pthread_mutex_lock(&call->decode_cond_mutex); | ||
1064 | uint8_t w = call->audio_decode_write; | ||
1065 | |||
1066 | if (call->audio_decode_queue[w] == NULL) { | ||
1067 | call->audio_decode_queue[w] = p; | ||
1068 | call->audio_decode_write = (w + 1) % AUDIO_DECODE_QUEUE_SIZE; | ||
1069 | pthread_cond_signal(&call->decode_cond); | ||
1070 | } else { | ||
1071 | LOGGER_DEBUG("Dropped audio frame\n"); | ||
1072 | free(p); | ||
1073 | } | ||
1074 | |||
1075 | pthread_mutex_unlock(&call->decode_cond_mutex); | ||
1076 | } else { | ||
1077 | //malloc failed | ||
1078 | } | ||
1079 | } | ||
1080 | |||
1081 | } else { | ||
1082 | uint8_t *packet = _msg->data; | ||
1083 | int recved_size = _msg->length; | ||
1084 | |||
1085 | if (recved_size < VIDEOFRAME_HEADER_SIZE) { | ||
1086 | goto end; | ||
1087 | } | ||
1088 | |||
1089 | uint8_t i = packet[0] - call->frame_id; | ||
1090 | |||
1091 | if (i == 0) { | ||
1092 | /* piece of current frame */ | ||
1093 | } else if (i > 0 && i < 128) { | ||
1094 | /* recieved a piece of a frame ahead, flush current frame and start reading this new frame */ | ||
1095 | DECODE_PACKET *p = malloc(sizeof(DECODE_PACKET) + call->frame_limit); | ||
1096 | |||
1097 | if (p) { | ||
1098 | p->size = call->frame_limit; | ||
1099 | memcpy(p->data, call->frame_buf, call->frame_limit); | ||
1100 | |||
1101 | /* do the decoding on another thread */ | ||
1102 | pthread_mutex_lock(&call->decode_cond_mutex); | ||
1103 | uint8_t w = call->video_decode_write; | ||
1104 | |||
1105 | if (call->video_decode_queue[w] == NULL) { | ||
1106 | call->video_decode_queue[w] = p; | ||
1107 | call->video_decode_write = (w + 1) % VIDEO_DECODE_QUEUE_SIZE; | ||
1108 | pthread_cond_signal(&call->decode_cond); | ||
1109 | } else { | ||
1110 | LOGGER_DEBUG("Dropped video frame\n"); | ||
1111 | free(p); | ||
1112 | } | ||
1113 | |||
1114 | pthread_mutex_unlock(&call->decode_cond_mutex); | ||
1115 | } else { | ||
1116 | //malloc failed | ||
1117 | } | ||
1118 | |||
1119 | call->frame_id = packet[0]; | ||
1120 | memset(call->frame_buf, 0, call->frame_limit); | ||
1121 | call->frame_limit = 0; | ||
1122 | } else { | ||
1123 | /* old packet, dont read */ | ||
1124 | LOGGER_DEBUG("Old packet: %u\n", i); | ||
1125 | goto end; | ||
1126 | } | ||
1127 | |||
1128 | if (packet[1] > (MAX_VIDEOFRAME_SIZE - VIDEOFRAME_PIECE_SIZE + 1) / | ||
1129 | VIDEOFRAME_PIECE_SIZE) { //TODO, fix this check? not sure | ||
1130 | /* packet out of buffer range */ | ||
1131 | goto end; | ||
1132 | } | ||
1133 | |||
1134 | LOGGER_DEBUG("Video Packet: %u %u\n", packet[0], packet[1]); | ||
1135 | memcpy(call->frame_buf + packet[1] * VIDEOFRAME_PIECE_SIZE, packet + VIDEOFRAME_HEADER_SIZE, | ||
1136 | recved_size - VIDEOFRAME_HEADER_SIZE); | ||
1137 | uint32_t limit = packet[1] * VIDEOFRAME_PIECE_SIZE + recved_size - VIDEOFRAME_HEADER_SIZE; | ||
1138 | |||
1139 | if (limit > call->frame_limit) { | ||
1140 | call->frame_limit = limit; | ||
1141 | LOGGER_DEBUG("Limit: %u\n", call->frame_limit); | ||
1142 | } | ||
1143 | |||
1144 | end: | ||
1145 | ; | ||
1146 | rtp_free_msg(NULL, _msg); | ||
1147 | } | ||
1148 | } | 690 | } |
691 | |||
diff --git a/toxav/toxav.h b/toxav/toxav.h index e31c7aad..3696f961 100644 --- a/toxav/toxav.h +++ b/toxav/toxav.h | |||
@@ -28,11 +28,14 @@ | |||
28 | extern "C" { | 28 | extern "C" { |
29 | #endif | 29 | #endif |
30 | 30 | ||
31 | typedef struct _ToxAv ToxAv; | ||
32 | |||
31 | /* vpx_image_t */ | 33 | /* vpx_image_t */ |
32 | #include <vpx/vpx_image.h> | 34 | #include <vpx/vpx_image.h> |
33 | 35 | ||
34 | typedef void ( *ToxAVCallback ) ( void *agent, int32_t call_idx, void *arg ); | 36 | typedef void ( *ToxAVCallback ) ( void *agent, int32_t call_idx, void *arg ); |
35 | typedef struct _ToxAv ToxAv; | 37 | typedef void ( *ToxAvAudioCallback ) (void *agent, int32_t call_idx, const int16_t *PCM, uint16_t size, void *data); |
38 | typedef void ( *ToxAvVideoCallback ) (void *agent, int32_t call_idx, const vpx_image_t *img, void *data); | ||
36 | 39 | ||
37 | #ifndef __TOX_DEFINED__ | 40 | #ifndef __TOX_DEFINED__ |
38 | #define __TOX_DEFINED__ | 41 | #define __TOX_DEFINED__ |
@@ -43,82 +46,79 @@ typedef struct Tox Tox; | |||
43 | 46 | ||
44 | 47 | ||
45 | /** | 48 | /** |
46 | * @brief Callbacks ids that handle the call states. | 49 | * Callbacks ids that handle the call states. |
47 | */ | 50 | */ |
48 | typedef enum { | 51 | typedef enum { |
49 | /* Requests */ | 52 | av_OnInvite, /* Incoming call */ |
50 | av_OnInvite, | 53 | av_OnRinging, /* When peer is ready to accept/reject the call */ |
51 | av_OnStart, | 54 | av_OnStart, /* Call (RTP transmission) started */ |
52 | av_OnCancel, | 55 | av_OnCancel, /* The side that initiated call canceled invite */ |
53 | av_OnReject, | 56 | av_OnReject, /* The side that was invited rejected the call */ |
54 | av_OnEnd, | 57 | av_OnEnd, /* Call that was active ended */ |
55 | 58 | av_OnRequestTimeout, /* When the requested action didn't get response in specified time */ | |
56 | /* Responses */ | 59 | av_OnPeerTimeout, /* Peer timed out; stop the call */ |
57 | av_OnRinging, | 60 | av_OnPeerCSChange, /* Peer changing Csettings. Prepare for changed AV */ |
58 | av_OnStarting, | 61 | av_OnSelfCSChange /* Csettings change confirmation. Once triggered peer is ready to recv changed AV */ |
59 | av_OnEnding, | ||
60 | |||
61 | /* Protocol */ | ||
62 | av_OnRequestTimeout, | ||
63 | av_OnPeerTimeout, | ||
64 | av_OnMediaChange | ||
65 | } ToxAvCallbackID; | 62 | } ToxAvCallbackID; |
66 | 63 | ||
67 | 64 | ||
68 | /** | 65 | /** |
69 | * @brief Call type identifier. | 66 | * Call type identifier. |
70 | */ | 67 | */ |
71 | typedef enum { | 68 | typedef enum { |
72 | TypeAudio = 192, | 69 | av_TypeAudio = 192, |
73 | TypeVideo | 70 | av_TypeVideo |
74 | } ToxAvCallType; | 71 | } ToxAvCallType; |
75 | 72 | ||
76 | 73 | ||
77 | typedef enum { | 74 | typedef enum { |
78 | av_CallNonExistant = -1, | 75 | av_CallNonExistent = -1, |
79 | av_CallInviting, /* when sending call invite */ | 76 | av_CallInviting, /* when sending call invite */ |
80 | av_CallStarting, /* when getting call invite */ | 77 | av_CallStarting, /* when getting call invite */ |
81 | av_CallActive, | 78 | av_CallActive, |
82 | av_CallHold, | 79 | av_CallHold, |
83 | av_CallHanged_up | 80 | av_CallHungUp |
84 | } ToxAvCallState; | 81 | } ToxAvCallState; |
85 | 82 | ||
86 | /** | 83 | /** |
87 | * @brief Error indicators. | 84 | * Error indicators. Values under -20 are reserved for toxcore. |
88 | */ | 85 | */ |
89 | typedef enum { | 86 | typedef enum { |
90 | ErrorNone = 0, | 87 | av_ErrorNone = 0, |
91 | ErrorInternal = -1, /* Internal error */ | 88 | av_ErrorUnknown = -1, /* Unknown error */ |
92 | ErrorAlreadyInCall = -2, /* Already has an active call */ | 89 | av_ErrorNoCall = -20, /* Trying to perform call action while not in a call */ |
93 | ErrorNoCall = -3, /* Trying to perform call action while not in a call */ | 90 | av_ErrorInvalidState = -21, /* Trying to perform call action while in invalid state*/ |
94 | ErrorInvalidState = -4, /* Trying to perform call action while in invalid state*/ | 91 | av_ErrorAlreadyInCallWithPeer = -22, /* Trying to call peer when already in a call with peer */ |
95 | ErrorNoRtpSession = -5, /* Trying to perform rtp action on invalid session */ | 92 | av_ErrorReachedCallLimit = -23, /* Cannot handle more calls */ |
96 | ErrorAudioPacketLost = -6, /* Indicating packet loss */ | 93 | av_ErrorInitializingCodecs = -30, /* Failed creating CSSession */ |
97 | ErrorStartingAudioRtp = -7, /* Error in toxav_prepare_transmission() */ | 94 | av_ErrorSettingVideoResolution = -31, /* Error setting resolution */ |
98 | ErrorStartingVideoRtp = -8 , /* Error in toxav_prepare_transmission() */ | 95 | av_ErrorSettingVideoBitrate = -32, /* Error setting bitrate */ |
99 | ErrorTerminatingAudioRtp = -9, /* Returned in toxav_kill_transmission() */ | 96 | av_ErrorSplittingVideoPayload = -33, /* Error splitting video payload */ |
100 | ErrorTerminatingVideoRtp = -10, /* Returned in toxav_kill_transmission() */ | 97 | av_ErrorEncodingVideo = -34, /* vpx_codec_encode failed */ |
101 | ErrorPacketTooLarge = -11, /* Buffer exceeds size while encoding */ | 98 | av_ErrorEncodingAudio = -35, /* opus_encode failed */ |
102 | ErrorInvalidCodecState = -12, /* Codec state not initialized */ | 99 | av_ErrorSendingPayload = -40, /* Sending lossy packet failed */ |
103 | 100 | av_ErrorCreatingRtpSessions = -41, /* One of the rtp sessions failed to initialize */ | |
101 | av_ErrorNoRtpSession = -50, /* Trying to perform rtp action on invalid session */ | ||
102 | av_ErrorInvalidCodecState = -51, /* Codec state not initialized */ | ||
103 | av_ErrorPacketTooLarge = -52, /* Split packet exceeds it's limit */ | ||
104 | } ToxAvError; | 104 | } ToxAvError; |
105 | 105 | ||
106 | 106 | ||
107 | /** | 107 | /** |
108 | * @brief Locally supported capabilities. | 108 | * Locally supported capabilities. |
109 | */ | 109 | */ |
110 | typedef enum { | 110 | typedef enum { |
111 | AudioEncoding = 1 << 0, | 111 | av_AudioEncoding = 1 << 0, |
112 | AudioDecoding = 1 << 1, | 112 | av_AudioDecoding = 1 << 1, |
113 | VideoEncoding = 1 << 2, | 113 | av_VideoEncoding = 1 << 2, |
114 | VideoDecoding = 1 << 3 | 114 | av_VideoDecoding = 1 << 3 |
115 | } ToxAvCapabilities; | 115 | } ToxAvCapabilities; |
116 | 116 | ||
117 | 117 | ||
118 | /** | 118 | /** |
119 | * @brief Encoding settings. | 119 | * Encoding settings. |
120 | */ | 120 | */ |
121 | typedef struct _ToxAvCodecSettings { | 121 | typedef struct _ToxAvCSettings { |
122 | ToxAvCallType call_type; | 122 | ToxAvCallType call_type; |
123 | 123 | ||
124 | uint32_t video_bitrate; /* In kbits/s */ | 124 | uint32_t video_bitrate; /* In kbits/s */ |
@@ -132,255 +132,195 @@ typedef struct _ToxAvCodecSettings { | |||
132 | } ToxAvCSettings; | 132 | } ToxAvCSettings; |
133 | 133 | ||
134 | extern const ToxAvCSettings av_DefaultSettings; | 134 | extern const ToxAvCSettings av_DefaultSettings; |
135 | extern const uint32_t av_jbufdc; /* Jitter buffer default capacity */ | ||
136 | extern const uint32_t av_VADd; /* VAD default treshold */ | ||
137 | 135 | ||
138 | /** | 136 | /** |
139 | * @brief Start new A/V session. There can only be one session at the time. If you register more | 137 | * Start new A/V session. There can only be one session at the time. |
140 | * it will result in undefined behaviour. | ||
141 | * | ||
142 | * @param messenger The messenger handle. | ||
143 | * @param userdata The agent handling A/V session (i.e. phone). | ||
144 | * @param video_width Width of video frame. | ||
145 | * @param video_height Height of video frame. | ||
146 | * @return ToxAv* | ||
147 | * @retval NULL On error. | ||
148 | */ | 138 | */ |
149 | ToxAv *toxav_new(Tox *messenger, int32_t max_calls); | 139 | ToxAv *toxav_new(Tox *messenger, int32_t max_calls); |
150 | 140 | ||
151 | /** | 141 | /** |
152 | * @brief Remove A/V session. | 142 | * Remove A/V session. |
153 | * | ||
154 | * @param av Handler. | ||
155 | * @return void | ||
156 | */ | 143 | */ |
157 | void toxav_kill(ToxAv *av); | 144 | void toxav_kill(ToxAv *av); |
158 | 145 | ||
159 | /** | 146 | /** |
160 | * @brief Register callback for call state. | 147 | * Returns the interval in milliseconds when the next toxav_do() should be called. |
161 | * | 148 | * If no call is active at the moment returns 200. |
162 | * @param av Handler. | ||
163 | * @param callback The callback | ||
164 | * @param id One of the ToxAvCallbackID values | ||
165 | * @return void | ||
166 | */ | 149 | */ |
167 | void toxav_register_callstate_callback (ToxAv *av, ToxAVCallback callback, ToxAvCallbackID id, void *userdata); | 150 | uint32_t toxav_do_interval(ToxAv *av); |
168 | 151 | ||
169 | /** | 152 | /** |
170 | * @brief Register callback for recieving audio data | 153 | * Main loop for the session. Best called right after tox_do(); |
171 | * | ||
172 | * @param av Handler. | ||
173 | * @param callback The callback | ||
174 | * @return void | ||
175 | */ | 154 | */ |
176 | void toxav_register_audio_recv_callback (ToxAv *av, void (*callback)(ToxAv *, int32_t, int16_t *, int, void *), | 155 | void toxav_do(ToxAv *av); |
177 | void *user_data); | ||
178 | 156 | ||
179 | /** | 157 | /** |
180 | * @brief Register callback for recieving video data | 158 | * Register callback for call state. |
181 | * | ||
182 | * @param av Handler. | ||
183 | * @param callback The callback | ||
184 | * @return void | ||
185 | */ | 159 | */ |
186 | void toxav_register_video_recv_callback (ToxAv *av, void (*callback)(ToxAv *, int32_t, vpx_image_t *, void *), | 160 | void toxav_register_callstate_callback (ToxAv *av, ToxAVCallback cb, ToxAvCallbackID id, void *userdata); |
187 | void *user_data); | ||
188 | 161 | ||
189 | /** | 162 | /** |
190 | * @brief Call user. Use its friend_id. | 163 | * Register callback for audio data. |
191 | * | ||
192 | * @param av Handler. | ||
193 | * @param user The user. | ||
194 | * @param call_type Call type. | ||
195 | * @param ringing_seconds Ringing timeout. | ||
196 | * @return int | ||
197 | * @retval 0 Success. | ||
198 | * @retval ToxAvError On error. | ||
199 | */ | 164 | */ |
200 | int toxav_call(ToxAv *av, int32_t *call_index, int user, const ToxAvCSettings *csettings, int ringing_seconds); | 165 | void toxav_register_audio_callback (ToxAv *av, ToxAvAudioCallback cb, void *userdata); |
201 | 166 | ||
202 | /** | 167 | /** |
203 | * @brief Hangup active call. | 168 | * Register callback for video data. |
204 | * | 169 | */ |
205 | * @param av Handler. | 170 | void toxav_register_video_callback (ToxAv *av, ToxAvVideoCallback cb, void *userdata); |
206 | * @return int | 171 | |
207 | * @retval 0 Success. | 172 | /** |
208 | * @retval ToxAvError On error. | 173 | * Call user. Use its friend_id. |
174 | */ | ||
175 | int toxav_call(ToxAv *av, | ||
176 | int32_t *call_index, | ||
177 | int friend_id, | ||
178 | const ToxAvCSettings *csettings, | ||
179 | int ringing_seconds); | ||
180 | |||
181 | /** | ||
182 | * Hangup active call. | ||
209 | */ | 183 | */ |
210 | int toxav_hangup(ToxAv *av, int32_t call_index); | 184 | int toxav_hangup(ToxAv *av, int32_t call_index); |
211 | 185 | ||
212 | /** | 186 | /** |
213 | * @brief Answer incomming call. | 187 | * Answer incoming call. Pass the csettings that you will use. |
214 | * | ||
215 | * @param av Handler. | ||
216 | * @param call_type Answer with... | ||
217 | * @return int | ||
218 | * @retval 0 Success. | ||
219 | * @retval ToxAvError On error. | ||
220 | */ | 188 | */ |
221 | int toxav_answer(ToxAv *av, int32_t call_index, const ToxAvCSettings *csettings ); | 189 | int toxav_answer(ToxAv *av, int32_t call_index, const ToxAvCSettings *csettings ); |
222 | 190 | ||
223 | /** | 191 | /** |
224 | * @brief Reject incomming call. | 192 | * Reject incoming call. |
225 | * | ||
226 | * @param av Handler. | ||
227 | * @param reason Optional reason. Set NULL if none. | ||
228 | * @return int | ||
229 | * @retval 0 Success. | ||
230 | * @retval ToxAvError On error. | ||
231 | */ | 193 | */ |
232 | int toxav_reject(ToxAv *av, int32_t call_index, const char *reason); | 194 | int toxav_reject(ToxAv *av, int32_t call_index, const char *reason); |
233 | 195 | ||
234 | /** | 196 | /** |
235 | * @brief Cancel outgoing request. | 197 | * Cancel outgoing request. |
236 | * | ||
237 | * @param av Handler. | ||
238 | * @param reason Optional reason. | ||
239 | * @param peer_id peer friend_id | ||
240 | * @return int | ||
241 | * @retval 0 Success. | ||
242 | * @retval ToxAvError On error. | ||
243 | */ | 198 | */ |
244 | int toxav_cancel(ToxAv *av, int32_t call_index, int peer_id, const char *reason); | 199 | int toxav_cancel(ToxAv *av, int32_t call_index, int peer_id, const char *reason); |
245 | 200 | ||
246 | /** | 201 | /** |
247 | * @brief Notify peer that we are changing call settings | 202 | * Notify peer that we are changing codec settings. |
248 | * | ||
249 | * @param av Handler. | ||
250 | * @return int | ||
251 | * @retval 0 Success. | ||
252 | * @retval ToxAvError On error. | ||
253 | */ | 203 | */ |
254 | int toxav_change_settings(ToxAv *av, int32_t call_index, const ToxAvCSettings *csettings); | 204 | int toxav_change_settings(ToxAv *av, int32_t call_index, const ToxAvCSettings *csettings); |
255 | 205 | ||
256 | /** | 206 | /** |
257 | * @brief Terminate transmission. Note that transmission will be terminated without informing remote peer. | 207 | * Terminate transmission. Note that transmission will be |
258 | * | 208 | * terminated without informing remote peer. Usually called when we can't inform peer. |
259 | * @param av Handler. | ||
260 | * @return int | ||
261 | * @retval 0 Success. | ||
262 | * @retval ToxAvError On error. | ||
263 | */ | 209 | */ |
264 | int toxav_stop_call(ToxAv *av, int32_t call_index); | 210 | int toxav_stop_call(ToxAv *av, int32_t call_index); |
265 | 211 | ||
266 | /** | 212 | /** |
267 | * @brief Must be call before any RTP transmission occurs. | 213 | * Allocates transmission data. Must be call before calling toxav_prepare_* and toxav_send_*. |
268 | * | 214 | * Also, it must be called when call is started |
269 | * @param av Handler. | ||
270 | * @param support_video Is video supported ? 1 : 0 | ||
271 | * @return int | ||
272 | * @retval 0 Success. | ||
273 | * @retval ToxAvError On error. | ||
274 | */ | 215 | */ |
275 | int toxav_prepare_transmission(ToxAv *av, int32_t call_index, uint32_t jbuf_size, uint32_t VAD_treshold, | 216 | int toxav_prepare_transmission(ToxAv *av, int32_t call_index, int support_video); |
276 | int support_video); | ||
277 | 217 | ||
278 | /** | 218 | /** |
279 | * @brief Call this at the end of the transmission. | 219 | * Clears transmission data. Call this at the end of the transmission. |
280 | * | ||
281 | * @param av Handler. | ||
282 | * @return int | ||
283 | * @retval 0 Success. | ||
284 | * @retval ToxAvError On error. | ||
285 | */ | 220 | */ |
286 | int toxav_kill_transmission(ToxAv *av, int32_t call_index); | 221 | int toxav_kill_transmission(ToxAv *av, int32_t call_index); |
287 | 222 | ||
288 | /** | 223 | /** |
289 | * @brief Encode and send video packet. | 224 | * Encode video frame. |
290 | * | ||
291 | * @param av Handler. | ||
292 | * @param frame The encoded frame. | ||
293 | * @param frame_size The size of the encoded frame. | ||
294 | * @return int | ||
295 | * @retval 0 Success. | ||
296 | * @retval ToxAvError On error. | ||
297 | */ | 225 | */ |
298 | int toxav_send_video ( ToxAv *av, int32_t call_index, const uint8_t *frame, unsigned int frame_size); | 226 | int toxav_prepare_video_frame ( ToxAv *av, |
227 | int32_t call_index, | ||
228 | uint8_t *dest, | ||
229 | int dest_max, | ||
230 | vpx_image_t *input); | ||
299 | 231 | ||
300 | /** | 232 | /** |
301 | * @brief Send audio frame. | 233 | * Send encoded video packet. |
302 | * | ||
303 | * @param av Handler. | ||
304 | * @param data The audio data encoded with toxav_prepare_audio_frame(). | ||
305 | * @param size Its size in number of bytes. | ||
306 | * @return int | ||
307 | * @retval 0 Success. | ||
308 | * @retval ToxAvError On error. | ||
309 | */ | 234 | */ |
310 | int toxav_send_audio ( ToxAv *av, int32_t call_index, const uint8_t *frame, unsigned int size); | 235 | int toxav_send_video ( ToxAv *av, int32_t call_index, const uint8_t *frame, uint32_t frame_size); |
311 | 236 | ||
312 | /** | 237 | /** |
313 | * @brief Encode video frame | 238 | * Encode audio frame. |
314 | * | ||
315 | * @param av Handler | ||
316 | * @param dest Where to | ||
317 | * @param dest_max Max size | ||
318 | * @param input What to encode | ||
319 | * @return int | ||
320 | * @retval ToxAvError On error. | ||
321 | * @retval >0 On success | ||
322 | */ | 239 | */ |
323 | int toxav_prepare_video_frame ( ToxAv *av, int32_t call_index, uint8_t *dest, int dest_max, vpx_image_t *input ); | 240 | int toxav_prepare_audio_frame ( ToxAv *av, |
241 | int32_t call_index, | ||
242 | uint8_t *dest, | ||
243 | int dest_max, | ||
244 | const int16_t *frame, | ||
245 | int frame_size); | ||
324 | 246 | ||
325 | /** | 247 | /** |
326 | * @brief Encode audio frame | 248 | * Send encoded audio frame. |
327 | * | 249 | */ |
328 | * @param av Handler | 250 | int toxav_send_audio ( ToxAv *av, int32_t call_index, const uint8_t *frame, unsigned int size); |
329 | * @param dest dest | ||
330 | * @param dest_max Max dest size | ||
331 | * @param frame The frame | ||
332 | * @param frame_size The frame size | ||
333 | * @return int | ||
334 | * @retval ToxAvError On error. | ||
335 | * @retval >0 On success | ||
336 | */ | ||
337 | int toxav_prepare_audio_frame ( ToxAv *av, int32_t call_index, uint8_t *dest, int dest_max, const int16_t *frame, | ||
338 | int frame_size); | ||
339 | 251 | ||
340 | /** | 252 | /** |
341 | * @brief Get peer transmission type. It can either be audio or video. | 253 | * Get codec settings from the peer. These were exchanged during call initialization |
342 | * | 254 | * or when peer send us new csettings. |
343 | * @param av Handler. | ||
344 | * @param peer The peer | ||
345 | * @return int | ||
346 | * @retval ToxAvCallType On success. | ||
347 | * @retval ToxAvError On error. | ||
348 | */ | 255 | */ |
349 | int toxav_get_peer_csettings ( ToxAv *av, int32_t call_index, int peer, ToxAvCSettings *dest ); | 256 | int toxav_get_peer_csettings ( ToxAv *av, int32_t call_index, int peer, ToxAvCSettings *dest ); |
350 | 257 | ||
351 | /** | 258 | /** |
352 | * @brief Get id of peer participating in conversation | 259 | * Get friend id of peer participating in conversation. |
353 | * | ||
354 | * @param av Handler | ||
355 | * @param peer peer index | ||
356 | * @return int | ||
357 | * @retval ToxAvError No peer id | ||
358 | */ | 260 | */ |
359 | int toxav_get_peer_id ( ToxAv *av, int32_t call_index, int peer ); | 261 | int toxav_get_peer_id ( ToxAv *av, int32_t call_index, int peer ); |
360 | 262 | ||
361 | /** | 263 | /** |
362 | * @brief Get current call state | 264 | * Get current call state. |
363 | * | ||
364 | * @param av Handler | ||
365 | * @param call_index What call | ||
366 | * @return int | ||
367 | * @retval ToxAvCallState State id | ||
368 | */ | 265 | */ |
369 | ToxAvCallState toxav_get_call_state ( ToxAv *av, int32_t call_index ); | 266 | ToxAvCallState toxav_get_call_state ( ToxAv *av, int32_t call_index ); |
267 | |||
370 | /** | 268 | /** |
371 | * @brief Is certain capability supported | 269 | * Is certain capability supported. Used to determine if encoding/decoding is ready. |
372 | * | ||
373 | * @param av Handler | ||
374 | * @return int | ||
375 | * @retval 1 Yes. | ||
376 | * @retval 0 No. | ||
377 | */ | 270 | */ |
378 | int toxav_capability_supported ( ToxAv *av, int32_t call_index, ToxAvCapabilities capability ); | 271 | int toxav_capability_supported ( ToxAv *av, int32_t call_index, ToxAvCapabilities capability ); |
379 | 272 | ||
273 | /** | ||
274 | * Returns tox reference. | ||
275 | */ | ||
276 | Tox *toxav_get_tox (ToxAv *av); | ||
277 | |||
278 | /** | ||
279 | * Returns number of active calls or -1 on error. | ||
280 | */ | ||
281 | int toxav_get_active_count (ToxAv *av); | ||
282 | |||
283 | /* Create a new toxav group. | ||
284 | * | ||
285 | * return group number on success. | ||
286 | * return -1 on failure. | ||
287 | * | ||
288 | * Audio data callback format: | ||
289 | * audio_callback(Tox *tox, int groupnumber, int peernumber, const int16_t *pcm, unsigned int samples, uint8_t channels, unsigned int sample_rate, void *userdata) | ||
290 | * | ||
291 | * Note that total size of pcm in bytes is equal to (samples * channels * sizeof(int16_t)). | ||
292 | */ | ||
293 | int toxav_add_av_groupchat(Tox *tox, void (*audio_callback)(Tox *, int, int, const int16_t *, unsigned int, uint8_t, | ||
294 | unsigned int, void *), void *userdata); | ||
380 | 295 | ||
381 | Tox *toxav_get_tox(ToxAv *av); | 296 | /* Join a AV group (you need to have been invited first.) |
297 | * | ||
298 | * returns group number on success | ||
299 | * returns -1 on failure. | ||
300 | * | ||
301 | * Audio data callback format (same as the one for toxav_add_av_groupchat()): | ||
302 | * audio_callback(Tox *tox, int groupnumber, int peernumber, const int16_t *pcm, unsigned int samples, uint8_t channels, unsigned int sample_rate, void *userdata) | ||
303 | * | ||
304 | * Note that total size of pcm in bytes is equal to (samples * channels * sizeof(int16_t)). | ||
305 | */ | ||
306 | int toxav_join_av_groupchat(Tox *tox, int32_t friendnumber, const uint8_t *data, uint16_t length, | ||
307 | void (*audio_callback)(Tox *, int, int, const int16_t *, unsigned int, uint8_t, unsigned int, void *), void *userdata); | ||
382 | 308 | ||
383 | int toxav_has_activity ( ToxAv *av, int32_t call_index, int16_t *PCM, uint16_t frame_size, float ref_energy ); | 309 | /* Send audio to the group chat. |
310 | * | ||
311 | * return 0 on success. | ||
312 | * return -1 on failure. | ||
313 | * | ||
314 | * Note that total size of pcm in bytes is equal to (samples * channels * sizeof(int16_t)). | ||
315 | * | ||
316 | * Valid number of samples are ((sample rate) * (audio length (Valid ones are: 2.5, 5, 10, 20, 40 or 60 ms)) / 1000) | ||
317 | * Valid number of channels are 1 or 2. | ||
318 | * Valid sample rates are 8000, 12000, 16000, 24000, or 48000. | ||
319 | * | ||
320 | * Recommended values are: samples = 960, channels = 1, sample_rate = 48000 | ||
321 | */ | ||
322 | int toxav_group_send_audio(Tox *tox, int groupnumber, const int16_t *pcm, unsigned int samples, uint8_t channels, | ||
323 | unsigned int sample_rate); | ||
384 | 324 | ||
385 | #ifdef __cplusplus | 325 | #ifdef __cplusplus |
386 | } | 326 | } |
diff --git a/toxcore/DHT.c b/toxcore/DHT.c index 6bd23081..2d3d6ffe 100644 --- a/toxcore/DHT.c +++ b/toxcore/DHT.c | |||
@@ -65,11 +65,6 @@ | |||
65 | /* Number of get node requests to send to quickly find close nodes. */ | 65 | /* Number of get node requests to send to quickly find close nodes. */ |
66 | #define MAX_BOOTSTRAP_TIMES 10 | 66 | #define MAX_BOOTSTRAP_TIMES 10 |
67 | 67 | ||
68 | Client_data *DHT_get_close_list(DHT *dht) | ||
69 | { | ||
70 | return dht->close_clientlist; | ||
71 | } | ||
72 | |||
73 | /* Compares client_id1 and client_id2 with client_id. | 68 | /* Compares client_id1 and client_id2 with client_id. |
74 | * | 69 | * |
75 | * return 0 if both are same distance. | 70 | * return 0 if both are same distance. |
@@ -169,12 +164,17 @@ void to_net_family(IP *ip) | |||
169 | ip->family = TOX_AF_INET6; | 164 | ip->family = TOX_AF_INET6; |
170 | } | 165 | } |
171 | 166 | ||
172 | void to_host_family(IP *ip) | 167 | int to_host_family(IP *ip) |
173 | { | 168 | { |
174 | if (ip->family == TOX_AF_INET) | 169 | if (ip->family == TOX_AF_INET) { |
175 | ip->family = AF_INET; | 170 | ip->family = AF_INET; |
176 | else if (ip->family == TOX_AF_INET6) | 171 | return 0; |
172 | } else if (ip->family == TOX_AF_INET6) { | ||
177 | ip->family = AF_INET6; | 173 | ip->family = AF_INET6; |
174 | return 0; | ||
175 | } else { | ||
176 | return -1; | ||
177 | } | ||
178 | } | 178 | } |
179 | 179 | ||
180 | /* Pack number of nodes into data of maxlength length. | 180 | /* Pack number of nodes into data of maxlength length. |
@@ -207,7 +207,7 @@ int pack_nodes(uint8_t *data, uint16_t length, const Node_format *nodes, uint16_ | |||
207 | } | 207 | } |
208 | 208 | ||
209 | if (ipv6 == 0) { | 209 | if (ipv6 == 0) { |
210 | uint32_t size = 1 + sizeof(IP4) + sizeof(uint16_t) + CLIENT_ID_SIZE; | 210 | uint32_t size = 1 + sizeof(IP4) + sizeof(uint16_t) + crypto_box_PUBLICKEYBYTES; |
211 | 211 | ||
212 | if (packed_length + size > length) | 212 | if (packed_length + size > length) |
213 | return -1; | 213 | return -1; |
@@ -215,10 +215,10 @@ int pack_nodes(uint8_t *data, uint16_t length, const Node_format *nodes, uint16_ | |||
215 | data[packed_length] = net_family; | 215 | data[packed_length] = net_family; |
216 | memcpy(data + packed_length + 1, &nodes[i].ip_port.ip.ip4, sizeof(IP4)); | 216 | memcpy(data + packed_length + 1, &nodes[i].ip_port.ip.ip4, sizeof(IP4)); |
217 | memcpy(data + packed_length + 1 + sizeof(IP4), &nodes[i].ip_port.port, sizeof(uint16_t)); | 217 | memcpy(data + packed_length + 1 + sizeof(IP4), &nodes[i].ip_port.port, sizeof(uint16_t)); |
218 | memcpy(data + packed_length + 1 + sizeof(IP4) + sizeof(uint16_t), nodes[i].client_id, CLIENT_ID_SIZE); | 218 | memcpy(data + packed_length + 1 + sizeof(IP4) + sizeof(uint16_t), nodes[i].public_key, crypto_box_PUBLICKEYBYTES); |
219 | packed_length += size; | 219 | packed_length += size; |
220 | } else if (ipv6 == 1) { | 220 | } else if (ipv6 == 1) { |
221 | uint32_t size = 1 + sizeof(IP6) + sizeof(uint16_t) + CLIENT_ID_SIZE; | 221 | uint32_t size = 1 + sizeof(IP6) + sizeof(uint16_t) + crypto_box_PUBLICKEYBYTES; |
222 | 222 | ||
223 | if (packed_length + size > length) | 223 | if (packed_length + size > length) |
224 | return -1; | 224 | return -1; |
@@ -226,7 +226,7 @@ int pack_nodes(uint8_t *data, uint16_t length, const Node_format *nodes, uint16_ | |||
226 | data[packed_length] = net_family; | 226 | data[packed_length] = net_family; |
227 | memcpy(data + packed_length + 1, &nodes[i].ip_port.ip.ip6, sizeof(IP6)); | 227 | memcpy(data + packed_length + 1, &nodes[i].ip_port.ip.ip6, sizeof(IP6)); |
228 | memcpy(data + packed_length + 1 + sizeof(IP6), &nodes[i].ip_port.port, sizeof(uint16_t)); | 228 | memcpy(data + packed_length + 1 + sizeof(IP6), &nodes[i].ip_port.port, sizeof(uint16_t)); |
229 | memcpy(data + packed_length + 1 + sizeof(IP6) + sizeof(uint16_t), nodes[i].client_id, CLIENT_ID_SIZE); | 229 | memcpy(data + packed_length + 1 + sizeof(IP6) + sizeof(uint16_t), nodes[i].public_key, crypto_box_PUBLICKEYBYTES); |
230 | packed_length += size; | 230 | packed_length += size; |
231 | } else { | 231 | } else { |
232 | return -1; | 232 | return -1; |
@@ -275,7 +275,7 @@ int unpack_nodes(Node_format *nodes, uint16_t max_num_nodes, uint16_t *processed | |||
275 | } | 275 | } |
276 | 276 | ||
277 | if (ipv6 == 0) { | 277 | if (ipv6 == 0) { |
278 | uint32_t size = 1 + sizeof(IP4) + sizeof(uint16_t) + CLIENT_ID_SIZE; | 278 | uint32_t size = 1 + sizeof(IP4) + sizeof(uint16_t) + crypto_box_PUBLICKEYBYTES; |
279 | 279 | ||
280 | if (len_processed + size > length) | 280 | if (len_processed + size > length) |
281 | return -1; | 281 | return -1; |
@@ -283,11 +283,11 @@ int unpack_nodes(Node_format *nodes, uint16_t max_num_nodes, uint16_t *processed | |||
283 | nodes[num].ip_port.ip.family = host_family; | 283 | nodes[num].ip_port.ip.family = host_family; |
284 | memcpy(&nodes[num].ip_port.ip.ip4, data + len_processed + 1, sizeof(IP4)); | 284 | memcpy(&nodes[num].ip_port.ip.ip4, data + len_processed + 1, sizeof(IP4)); |
285 | memcpy(&nodes[num].ip_port.port, data + len_processed + 1 + sizeof(IP4), sizeof(uint16_t)); | 285 | memcpy(&nodes[num].ip_port.port, data + len_processed + 1 + sizeof(IP4), sizeof(uint16_t)); |
286 | memcpy(nodes[num].client_id, data + len_processed + 1 + sizeof(IP4) + sizeof(uint16_t), CLIENT_ID_SIZE); | 286 | memcpy(nodes[num].public_key, data + len_processed + 1 + sizeof(IP4) + sizeof(uint16_t), crypto_box_PUBLICKEYBYTES); |
287 | len_processed += size; | 287 | len_processed += size; |
288 | ++num; | 288 | ++num; |
289 | } else if (ipv6 == 1) { | 289 | } else if (ipv6 == 1) { |
290 | uint32_t size = 1 + sizeof(IP6) + sizeof(uint16_t) + CLIENT_ID_SIZE; | 290 | uint32_t size = 1 + sizeof(IP6) + sizeof(uint16_t) + crypto_box_PUBLICKEYBYTES; |
291 | 291 | ||
292 | if (len_processed + size > length) | 292 | if (len_processed + size > length) |
293 | return -1; | 293 | return -1; |
@@ -295,7 +295,7 @@ int unpack_nodes(Node_format *nodes, uint16_t max_num_nodes, uint16_t *processed | |||
295 | nodes[num].ip_port.ip.family = host_family; | 295 | nodes[num].ip_port.ip.family = host_family; |
296 | memcpy(&nodes[num].ip_port.ip.ip6, data + len_processed + 1, sizeof(IP6)); | 296 | memcpy(&nodes[num].ip_port.ip.ip6, data + len_processed + 1, sizeof(IP6)); |
297 | memcpy(&nodes[num].ip_port.port, data + len_processed + 1 + sizeof(IP6), sizeof(uint16_t)); | 297 | memcpy(&nodes[num].ip_port.port, data + len_processed + 1 + sizeof(IP6), sizeof(uint16_t)); |
298 | memcpy(nodes[num].client_id, data + len_processed + 1 + sizeof(IP6) + sizeof(uint16_t), CLIENT_ID_SIZE); | 298 | memcpy(nodes[num].public_key, data + len_processed + 1 + sizeof(IP6) + sizeof(uint16_t), crypto_box_PUBLICKEYBYTES); |
299 | len_processed += size; | 299 | len_processed += size; |
300 | ++num; | 300 | ++num; |
301 | } else { | 301 | } else { |
@@ -318,7 +318,7 @@ int unpack_nodes(Node_format *nodes, uint16_t max_num_nodes, uint16_t *processed | |||
318 | * | 318 | * |
319 | * return True(1) or False(0) | 319 | * return True(1) or False(0) |
320 | */ | 320 | */ |
321 | static int client_or_ip_port_in_list(Client_data *list, uint32_t length, const uint8_t *client_id, IP_Port ip_port) | 321 | static int client_or_ip_port_in_list(Client_data *list, uint16_t length, const uint8_t *client_id, IP_Port ip_port) |
322 | { | 322 | { |
323 | uint32_t i; | 323 | uint32_t i; |
324 | uint64_t temp_time = unix_time(); | 324 | uint64_t temp_time = unix_time(); |
@@ -330,9 +330,9 @@ static int client_or_ip_port_in_list(Client_data *list, uint32_t length, const u | |||
330 | if (ip_port.ip.family == AF_INET) { | 330 | if (ip_port.ip.family == AF_INET) { |
331 | 331 | ||
332 | LOGGER_SCOPE( if (!ipport_equal(&list[i].assoc4.ip_port, &ip_port)) { | 332 | LOGGER_SCOPE( if (!ipport_equal(&list[i].assoc4.ip_port, &ip_port)) { |
333 | LOGGER_INFO("coipil[%u]: switching ipv4 from %s:%u to %s:%u", i, | 333 | LOGGER_TRACE("coipil[%u]: switching ipv4 from %s:%u to %s:%u", i, |
334 | ip_ntoa(&list[i].assoc4.ip_port.ip), ntohs(list[i].assoc4.ip_port.port), | 334 | ip_ntoa(&list[i].assoc4.ip_port.ip), ntohs(list[i].assoc4.ip_port.port), |
335 | ip_ntoa(&ip_port.ip), ntohs(ip_port.port)); | 335 | ip_ntoa(&ip_port.ip), ntohs(ip_port.port)); |
336 | } | 336 | } |
337 | ); | 337 | ); |
338 | 338 | ||
@@ -344,9 +344,9 @@ static int client_or_ip_port_in_list(Client_data *list, uint32_t length, const u | |||
344 | } else if (ip_port.ip.family == AF_INET6) { | 344 | } else if (ip_port.ip.family == AF_INET6) { |
345 | 345 | ||
346 | LOGGER_SCOPE( if (!ipport_equal(&list[i].assoc4.ip_port, &ip_port)) { | 346 | LOGGER_SCOPE( if (!ipport_equal(&list[i].assoc4.ip_port, &ip_port)) { |
347 | LOGGER_INFO("coipil[%u]: switching ipv6 from %s:%u to %s:%u", i, | 347 | LOGGER_TRACE("coipil[%u]: switching ipv6 from %s:%u to %s:%u", i, |
348 | ip_ntoa(&list[i].assoc6.ip_port.ip), ntohs(list[i].assoc6.ip_port.port), | 348 | ip_ntoa(&list[i].assoc6.ip_port.ip), ntohs(list[i].assoc6.ip_port.port), |
349 | ip_ntoa(&ip_port.ip), ntohs(ip_port.port)); | 349 | ip_ntoa(&ip_port.ip), ntohs(ip_port.port)); |
350 | } | 350 | } |
351 | ); | 351 | ); |
352 | 352 | ||
@@ -397,12 +397,12 @@ static int client_or_ip_port_in_list(Client_data *list, uint32_t length, const u | |||
397 | * return 1 if true. | 397 | * return 1 if true. |
398 | * return 0 if false. | 398 | * return 0 if false. |
399 | */ | 399 | */ |
400 | static int client_in_nodelist(const Node_format *list, uint32_t length, const uint8_t *client_id) | 400 | static int client_in_nodelist(const Node_format *list, uint16_t length, const uint8_t *public_key) |
401 | { | 401 | { |
402 | uint32_t i; | 402 | uint32_t i; |
403 | 403 | ||
404 | for (i = 0; i < length; ++i) { | 404 | for (i = 0; i < length; ++i) { |
405 | if (id_equal(list[i].client_id, client_id)) | 405 | if (id_equal(list[i].public_key, public_key)) |
406 | return 1; | 406 | return 1; |
407 | } | 407 | } |
408 | 408 | ||
@@ -484,9 +484,9 @@ static void get_close_nodes_inner(const uint8_t *client_id, Node_format *nodes_l | |||
484 | continue; | 484 | continue; |
485 | 485 | ||
486 | if (num_nodes < MAX_SENT_NODES) { | 486 | if (num_nodes < MAX_SENT_NODES) { |
487 | memcpy(nodes_list[num_nodes].client_id, | 487 | memcpy(nodes_list[num_nodes].public_key, |
488 | client->client_id, | 488 | client->client_id, |
489 | CLIENT_ID_SIZE ); | 489 | crypto_box_PUBLICKEYBYTES ); |
490 | 490 | ||
491 | nodes_list[num_nodes].ip_port = ipptp->ip_port; | 491 | nodes_list[num_nodes].ip_port = ipptp->ip_port; |
492 | num_nodes++; | 492 | num_nodes++; |
@@ -497,14 +497,14 @@ static void get_close_nodes_inner(const uint8_t *client_id, Node_format *nodes_l | |||
497 | */ | 497 | */ |
498 | for (j = 0; j < MAX_SENT_NODES; ++j) { | 498 | for (j = 0; j < MAX_SENT_NODES; ++j) { |
499 | closest = id_closest( client_id, | 499 | closest = id_closest( client_id, |
500 | nodes_list[j].client_id, | 500 | nodes_list[j].public_key, |
501 | client->client_id ); | 501 | client->client_id ); |
502 | 502 | ||
503 | /* second client_id is closer than current: change to it */ | 503 | /* second client_id is closer than current: change to it */ |
504 | if (closest == 2) { | 504 | if (closest == 2) { |
505 | memcpy( nodes_list[j].client_id, | 505 | memcpy( nodes_list[j].public_key, |
506 | client->client_id, | 506 | client->client_id, |
507 | CLIENT_ID_SIZE); | 507 | crypto_box_PUBLICKEYBYTES); |
508 | 508 | ||
509 | nodes_list[j].ip_port = ipptp->ip_port; | 509 | nodes_list[j].ip_port = ipptp->ip_port; |
510 | break; | 510 | break; |
@@ -583,7 +583,7 @@ int get_close_nodes(const DHT *dht, const uint8_t *client_id, Node_format *nodes | |||
583 | Client_data *client = result[i]; | 583 | Client_data *client = result[i]; |
584 | 584 | ||
585 | if (client) { | 585 | if (client) { |
586 | id_copy(nodes_list[num_returned].client_id, client->client_id); | 586 | id_copy(nodes_list[num_returned].public_key, client->client_id); |
587 | 587 | ||
588 | if (sa_family == AF_INET) | 588 | if (sa_family == AF_INET) |
589 | if (ipport_isset(&client->assoc4.ip_port)) { | 589 | if (ipport_isset(&client->assoc4.ip_port)) { |
@@ -605,6 +605,63 @@ int get_close_nodes(const DHT *dht, const uint8_t *client_id, Node_format *nodes | |||
605 | #endif | 605 | #endif |
606 | } | 606 | } |
607 | 607 | ||
608 | static uint8_t cmp_public_key[crypto_box_PUBLICKEYBYTES]; | ||
609 | static int cmp_dht_entry(const void *a, const void *b) | ||
610 | { | ||
611 | Client_data entry1, entry2; | ||
612 | memcpy(&entry1, a, sizeof(Client_data)); | ||
613 | memcpy(&entry2, b, sizeof(Client_data)); | ||
614 | int t1 = is_timeout(entry1.assoc4.timestamp, BAD_NODE_TIMEOUT) && is_timeout(entry1.assoc6.timestamp, BAD_NODE_TIMEOUT); | ||
615 | int t2 = is_timeout(entry2.assoc4.timestamp, BAD_NODE_TIMEOUT) && is_timeout(entry2.assoc6.timestamp, BAD_NODE_TIMEOUT); | ||
616 | |||
617 | if (t1 && t2) | ||
618 | return 0; | ||
619 | |||
620 | if (t1) | ||
621 | return -1; | ||
622 | |||
623 | if (t2) | ||
624 | return 1; | ||
625 | |||
626 | t1 = hardening_correct(&entry1.assoc4.hardening) != HARDENING_ALL_OK | ||
627 | && hardening_correct(&entry1.assoc6.hardening) != HARDENING_ALL_OK; | ||
628 | t2 = hardening_correct(&entry2.assoc4.hardening) != HARDENING_ALL_OK | ||
629 | && hardening_correct(&entry2.assoc6.hardening) != HARDENING_ALL_OK; | ||
630 | |||
631 | if (t1 != t2) { | ||
632 | if (t1) | ||
633 | return -1; | ||
634 | |||
635 | if (t2) | ||
636 | return 1; | ||
637 | } | ||
638 | |||
639 | int close = id_closest(cmp_public_key, entry1.client_id, entry2.client_id); | ||
640 | |||
641 | if (close == 1) | ||
642 | return 1; | ||
643 | |||
644 | if (close == 2) | ||
645 | return -1; | ||
646 | |||
647 | return 0; | ||
648 | } | ||
649 | |||
650 | /* Is it ok to store node with client_id in client. | ||
651 | * | ||
652 | * return 0 if node can't be stored. | ||
653 | * return 1 if it can. | ||
654 | */ | ||
655 | static unsigned int store_node_ok(const Client_data *client, const uint8_t *client_id, const uint8_t *comp_client_id) | ||
656 | { | ||
657 | if ((is_timeout(client->assoc4.timestamp, BAD_NODE_TIMEOUT) && is_timeout(client->assoc6.timestamp, BAD_NODE_TIMEOUT)) | ||
658 | || (id_closest(comp_client_id, client->client_id, client_id) == 2)) { | ||
659 | return 1; | ||
660 | } else { | ||
661 | return 0; | ||
662 | } | ||
663 | } | ||
664 | |||
608 | /* Replace a first bad (or empty) node with this one | 665 | /* Replace a first bad (or empty) node with this one |
609 | * or replace a possibly bad node (tests failed or not done yet) | 666 | * or replace a possibly bad node (tests failed or not done yet) |
610 | * that is further than any other in the list | 667 | * that is further than any other in the list |
@@ -619,48 +676,20 @@ int get_close_nodes(const DHT *dht, const uint8_t *client_id, Node_format *nodes | |||
619 | * | 676 | * |
620 | * returns True(1) when the item was stored, False(0) otherwise */ | 677 | * returns True(1) when the item was stored, False(0) otherwise */ |
621 | static int replace_all( Client_data *list, | 678 | static int replace_all( Client_data *list, |
622 | uint32_t length, | 679 | uint16_t length, |
623 | const uint8_t *client_id, | 680 | const uint8_t *client_id, |
624 | IP_Port ip_port, | 681 | IP_Port ip_port, |
625 | const uint8_t *comp_client_id ) | 682 | const uint8_t *comp_client_id ) |
626 | { | 683 | { |
627 | if ((ip_port.ip.family != AF_INET) && (ip_port.ip.family != AF_INET6)) | 684 | if ((ip_port.ip.family != AF_INET) && (ip_port.ip.family != AF_INET6)) |
628 | return 1; | 685 | return 0; |
629 | |||
630 | uint32_t i, replace = ~0, bad = ~0, possibly_bad = ~0, good = ~0; | ||
631 | |||
632 | for (i = 0; i < length; ++i) { | ||
633 | |||
634 | Client_data *client = &list[i]; | ||
635 | 686 | ||
636 | if (is_timeout(client->assoc4.timestamp, BAD_NODE_TIMEOUT) && | 687 | memcpy(cmp_public_key, comp_client_id, crypto_box_PUBLICKEYBYTES); |
637 | is_timeout(client->assoc6.timestamp, BAD_NODE_TIMEOUT)) { | 688 | qsort(list, length, sizeof(Client_data), cmp_dht_entry); |
638 | // "bad" node | ||
639 | bad = i; | ||
640 | break; | ||
641 | } else if (hardening_correct(&client->assoc4.hardening) != HARDENING_ALL_OK && | ||
642 | hardening_correct(&client->assoc6.hardening) != HARDENING_ALL_OK) { | ||
643 | // "possibly bad" node | ||
644 | if (possibly_bad == (uint32_t)~0 || | ||
645 | id_closest(comp_client_id, list[possibly_bad].client_id, list[i].client_id) == 1) | ||
646 | possibly_bad = i; | ||
647 | } else { | ||
648 | // "good" node | ||
649 | if (good == (uint32_t)~0 || | ||
650 | id_closest(comp_client_id, list[good].client_id, list[i].client_id) == 1) | ||
651 | good = i; | ||
652 | } | ||
653 | } | ||
654 | 689 | ||
655 | if (bad != (uint32_t)~0) | 690 | Client_data *client = &list[0]; |
656 | replace = bad; | ||
657 | else if (possibly_bad != (uint32_t)~0) | ||
658 | replace = possibly_bad; | ||
659 | else if (good != (uint32_t)~0 && id_closest(comp_client_id, list[good].client_id, client_id) == 2) | ||
660 | replace = good; | ||
661 | 691 | ||
662 | if (replace != (uint32_t)~0) { | 692 | if (store_node_ok(client, client_id, comp_client_id)) { |
663 | Client_data *client = &list[replace]; | ||
664 | IPPTsPng *ipptp_write = NULL; | 693 | IPPTsPng *ipptp_write = NULL; |
665 | IPPTsPng *ipptp_clear = NULL; | 694 | IPPTsPng *ipptp_clear = NULL; |
666 | 695 | ||
@@ -689,6 +718,29 @@ static int replace_all( Client_data *list, | |||
689 | return 0; | 718 | return 0; |
690 | } | 719 | } |
691 | 720 | ||
721 | /* Check if the node obtained with a get_nodes with client_id should be pinged. | ||
722 | * NOTE: for best results call it after addto_lists; | ||
723 | * | ||
724 | * return 0 if the node should not be pinged. | ||
725 | * return 1 if it should. | ||
726 | */ | ||
727 | static unsigned int ping_node_from_getnodes_ok(DHT *dht, const uint8_t *client_id) | ||
728 | { | ||
729 | if (store_node_ok(&dht->close_clientlist[0], client_id, dht->self_public_key)) { | ||
730 | return 1; | ||
731 | } | ||
732 | |||
733 | unsigned int i; | ||
734 | |||
735 | for (i = 0; i < dht->num_friends; ++i) { | ||
736 | if (store_node_ok(&dht->friends_list[i].client_list[0], client_id, dht->self_public_key)) { | ||
737 | return 1; | ||
738 | } | ||
739 | } | ||
740 | |||
741 | return 0; | ||
742 | } | ||
743 | |||
692 | /* Attempt to add client with ip_port and client_id to the friends client list | 744 | /* Attempt to add client with ip_port and client_id to the friends client list |
693 | * and close_clientlist. | 745 | * and close_clientlist. |
694 | * | 746 | * |
@@ -713,14 +765,41 @@ int addto_lists(DHT *dht, IP_Port ip_port, const uint8_t *client_id) | |||
713 | } else | 765 | } else |
714 | used++; | 766 | used++; |
715 | 767 | ||
768 | DHT_Friend *friend_foundip = 0; | ||
769 | |||
716 | for (i = 0; i < dht->num_friends; ++i) { | 770 | for (i = 0; i < dht->num_friends; ++i) { |
717 | if (!client_or_ip_port_in_list(dht->friends_list[i].client_list, | 771 | if (!client_or_ip_port_in_list(dht->friends_list[i].client_list, |
718 | MAX_FRIEND_CLIENTS, client_id, ip_port)) { | 772 | MAX_FRIEND_CLIENTS, client_id, ip_port)) { |
719 | if (replace_all(dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS, | 773 | if (replace_all(dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS, |
720 | client_id, ip_port, dht->friends_list[i].client_id)) | 774 | client_id, ip_port, dht->friends_list[i].client_id)) { |
775 | |||
776 | DHT_Friend *friend = &dht->friends_list[i]; | ||
777 | |||
778 | if (memcmp(client_id, friend->client_id, CLIENT_ID_SIZE) == 0) { | ||
779 | friend_foundip = friend; | ||
780 | } | ||
781 | |||
721 | used++; | 782 | used++; |
722 | } else | 783 | } |
784 | } else { | ||
785 | DHT_Friend *friend = &dht->friends_list[i]; | ||
786 | |||
787 | if (memcmp(client_id, friend->client_id, CLIENT_ID_SIZE) == 0) { | ||
788 | friend_foundip = friend; | ||
789 | } | ||
790 | |||
723 | used++; | 791 | used++; |
792 | } | ||
793 | } | ||
794 | |||
795 | if (friend_foundip) { | ||
796 | uint32_t j; | ||
797 | |||
798 | for (j = 0; j < friend_foundip->lock_count; ++j) { | ||
799 | if (friend_foundip->callbacks[j].ip_callback) | ||
800 | friend_foundip->callbacks[j].ip_callback(friend_foundip->callbacks[j].data, friend_foundip->callbacks[j].number, | ||
801 | ip_port); | ||
802 | } | ||
724 | } | 803 | } |
725 | 804 | ||
726 | #ifdef ENABLE_ASSOC_DHT | 805 | #ifdef ENABLE_ASSOC_DHT |
@@ -806,8 +885,6 @@ end: | |||
806 | return 0; | 885 | return 0; |
807 | } | 886 | } |
808 | 887 | ||
809 | #define NODES_ENCRYPTED_MESSAGE_LENGTH (crypto_box_NONCEBYTES + sizeof(uint64_t) + sizeof(Node_format) + sizeof(Node_format) + crypto_box_MACBYTES) | ||
810 | |||
811 | /* Send a getnodes request. | 888 | /* Send a getnodes request. |
812 | sendback_node is the node that it will send back the response to (set to NULL to disable this) */ | 889 | sendback_node is the node that it will send back the response to (set to NULL to disable this) */ |
813 | static int getnodes(DHT *dht, IP_Port ip_port, const uint8_t *public_key, const uint8_t *client_id, | 890 | static int getnodes(DHT *dht, IP_Port ip_port, const uint8_t *public_key, const uint8_t *client_id, |
@@ -820,7 +897,7 @@ static int getnodes(DHT *dht, IP_Port ip_port, const uint8_t *public_key, const | |||
820 | uint8_t plain_message[sizeof(Node_format) * 2] = {0}; | 897 | uint8_t plain_message[sizeof(Node_format) * 2] = {0}; |
821 | 898 | ||
822 | Node_format receiver; | 899 | Node_format receiver; |
823 | memcpy(receiver.client_id, public_key, CLIENT_ID_SIZE); | 900 | memcpy(receiver.public_key, public_key, CLIENT_ID_SIZE); |
824 | receiver.ip_port = ip_port; | 901 | receiver.ip_port = ip_port; |
825 | memcpy(plain_message, &receiver, sizeof(receiver)); | 902 | memcpy(plain_message, &receiver, sizeof(receiver)); |
826 | 903 | ||
@@ -874,7 +951,7 @@ static int sendnodes_ipv6(const DHT *dht, IP_Port ip_port, const uint8_t *public | |||
874 | if (id_equal(public_key, dht->self_public_key)) | 951 | if (id_equal(public_key, dht->self_public_key)) |
875 | return -1; | 952 | return -1; |
876 | 953 | ||
877 | if (length > NODES_ENCRYPTED_MESSAGE_LENGTH || length == 0) | 954 | if (length != sizeof(uint64_t)) |
878 | return -1; | 955 | return -1; |
879 | 956 | ||
880 | size_t Node_format_size = sizeof(Node_format); | 957 | size_t Node_format_size = sizeof(Node_format); |
@@ -916,38 +993,31 @@ static int sendnodes_ipv6(const DHT *dht, IP_Port ip_port, const uint8_t *public | |||
916 | return sendpacket(dht->net, ip_port, data, 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + len); | 993 | return sendpacket(dht->net, ip_port, data, 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + len); |
917 | } | 994 | } |
918 | 995 | ||
919 | static int handle_getnodes(void *object, IP_Port source, const uint8_t *packet, uint32_t length) | 996 | static int handle_getnodes(void *object, IP_Port source, const uint8_t *packet, uint16_t length) |
920 | { | 997 | { |
921 | uint32_t cmp_len = 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + CLIENT_ID_SIZE + crypto_box_MACBYTES; | 998 | if (length != (1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + CLIENT_ID_SIZE + sizeof(uint64_t) + crypto_box_MACBYTES)) |
922 | |||
923 | if (length <= cmp_len) | ||
924 | return 1; | 999 | return 1; |
925 | 1000 | ||
926 | if (length > cmp_len + NODES_ENCRYPTED_MESSAGE_LENGTH) | ||
927 | return 1; | ||
928 | |||
929 | uint16_t sendback_data_length = length - cmp_len; | ||
930 | |||
931 | DHT *dht = object; | 1001 | DHT *dht = object; |
932 | 1002 | ||
933 | /* Check if packet is from ourself. */ | 1003 | /* Check if packet is from ourself. */ |
934 | if (id_equal(packet + 1, dht->self_public_key)) | 1004 | if (id_equal(packet + 1, dht->self_public_key)) |
935 | return 1; | 1005 | return 1; |
936 | 1006 | ||
937 | uint8_t plain[CLIENT_ID_SIZE + sendback_data_length]; | 1007 | uint8_t plain[CLIENT_ID_SIZE + sizeof(uint64_t)]; |
938 | uint8_t shared_key[crypto_box_BEFORENMBYTES]; | 1008 | uint8_t shared_key[crypto_box_BEFORENMBYTES]; |
939 | 1009 | ||
940 | DHT_get_shared_key_recv(dht, shared_key, packet + 1); | 1010 | DHT_get_shared_key_recv(dht, shared_key, packet + 1); |
941 | int len = decrypt_data_symmetric( shared_key, | 1011 | int len = decrypt_data_symmetric( shared_key, |
942 | packet + 1 + CLIENT_ID_SIZE, | 1012 | packet + 1 + CLIENT_ID_SIZE, |
943 | packet + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, | 1013 | packet + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, |
944 | CLIENT_ID_SIZE + sendback_data_length + crypto_box_MACBYTES, | 1014 | CLIENT_ID_SIZE + sizeof(uint64_t) + crypto_box_MACBYTES, |
945 | plain ); | 1015 | plain ); |
946 | 1016 | ||
947 | if (len != CLIENT_ID_SIZE + sendback_data_length) | 1017 | if (len != CLIENT_ID_SIZE + sizeof(uint64_t)) |
948 | return 1; | 1018 | return 1; |
949 | 1019 | ||
950 | sendnodes_ipv6(dht, source, packet + 1, plain, plain + CLIENT_ID_SIZE, sendback_data_length, shared_key); | 1020 | sendnodes_ipv6(dht, source, packet + 1, plain, plain + CLIENT_ID_SIZE, sizeof(uint64_t), shared_key); |
951 | 1021 | ||
952 | add_to_ping(dht->ping, packet + 1, source); | 1022 | add_to_ping(dht->ping, packet + 1, source); |
953 | 1023 | ||
@@ -971,7 +1041,7 @@ static uint8_t sent_getnode_to_node(DHT *dht, const uint8_t *client_id, IP_Port | |||
971 | Node_format test; | 1041 | Node_format test; |
972 | memcpy(&test, data, sizeof(Node_format)); | 1042 | memcpy(&test, data, sizeof(Node_format)); |
973 | 1043 | ||
974 | if (!ipport_equal(&test.ip_port, &node_ip_port) || memcmp(test.client_id, client_id, CLIENT_ID_SIZE) != 0) | 1044 | if (!ipport_equal(&test.ip_port, &node_ip_port) || memcmp(test.public_key, client_id, CLIENT_ID_SIZE) != 0) |
975 | return 0; | 1045 | return 0; |
976 | 1046 | ||
977 | return 1; | 1047 | return 1; |
@@ -981,7 +1051,7 @@ static uint8_t sent_getnode_to_node(DHT *dht, const uint8_t *client_id, IP_Port | |||
981 | static int send_hardening_getnode_res(const DHT *dht, const Node_format *sendto, const uint8_t *queried_client_id, | 1051 | static int send_hardening_getnode_res(const DHT *dht, const Node_format *sendto, const uint8_t *queried_client_id, |
982 | const uint8_t *nodes_data, uint16_t nodes_data_length); | 1052 | const uint8_t *nodes_data, uint16_t nodes_data_length); |
983 | 1053 | ||
984 | static int handle_sendnodes_core(void *object, IP_Port source, const uint8_t *packet, uint32_t length, | 1054 | static int handle_sendnodes_core(void *object, IP_Port source, const uint8_t *packet, uint16_t length, |
985 | Node_format *plain_nodes, uint16_t size_plain_nodes, uint32_t *num_nodes_out) | 1055 | Node_format *plain_nodes, uint16_t size_plain_nodes, uint32_t *num_nodes_out) |
986 | { | 1056 | { |
987 | DHT *dht = object; | 1057 | DHT *dht = object; |
@@ -1043,7 +1113,7 @@ static int handle_sendnodes_core(void *object, IP_Port source, const uint8_t *pa | |||
1043 | return 0; | 1113 | return 0; |
1044 | } | 1114 | } |
1045 | 1115 | ||
1046 | static int handle_sendnodes_ipv6(void *object, IP_Port source, const uint8_t *packet, uint32_t length) | 1116 | static int handle_sendnodes_ipv6(void *object, IP_Port source, const uint8_t *packet, uint16_t length) |
1047 | { | 1117 | { |
1048 | DHT *dht = object; | 1118 | DHT *dht = object; |
1049 | Node_format plain_nodes[MAX_SENT_NODES]; | 1119 | Node_format plain_nodes[MAX_SENT_NODES]; |
@@ -1058,9 +1128,10 @@ static int handle_sendnodes_ipv6(void *object, IP_Port source, const uint8_t *pa | |||
1058 | uint32_t i; | 1128 | uint32_t i; |
1059 | 1129 | ||
1060 | for (i = 0; i < num_nodes; i++) { | 1130 | for (i = 0; i < num_nodes; i++) { |
1061 | if (ipport_isset(&plain_nodes[i].ip_port)) { | 1131 | if (ipport_isset(&plain_nodes[i].ip_port) && (LAN_ip(plain_nodes[i].ip_port.ip) == 0 |
1062 | send_ping_request(dht->ping, plain_nodes[i].ip_port, plain_nodes[i].client_id); | 1132 | || ping_node_from_getnodes_ok(dht, plain_nodes[i].public_key))) { |
1063 | returnedip_ports(dht, plain_nodes[i].ip_port, plain_nodes[i].client_id, packet + 1); | 1133 | send_ping_request(dht->ping, plain_nodes[i].ip_port, plain_nodes[i].public_key); |
1134 | returnedip_ports(dht, plain_nodes[i].ip_port, plain_nodes[i].public_key, packet + 1); | ||
1064 | } | 1135 | } |
1065 | } | 1136 | } |
1066 | 1137 | ||
@@ -1094,23 +1165,54 @@ static void get_bunchnodes(DHT *dht, Client_data *list, uint16_t length, uint16_ | |||
1094 | } | 1165 | } |
1095 | } | 1166 | } |
1096 | */ | 1167 | */ |
1097 | int DHT_addfriend(DHT *dht, const uint8_t *client_id) | 1168 | int DHT_addfriend(DHT *dht, const uint8_t *client_id, void (*ip_callback)(void *data, int32_t number, IP_Port), |
1169 | void *data, int32_t number, uint16_t *lock_count) | ||
1098 | { | 1170 | { |
1099 | if (friend_number(dht, client_id) != -1) /* Is friend already in DHT? */ | 1171 | int friend_num = friend_number(dht, client_id); |
1100 | return 1; | 1172 | |
1173 | uint16_t lock_num; | ||
1174 | |||
1175 | if (friend_num != -1) { /* Is friend already in DHT? */ | ||
1176 | DHT_Friend *friend = &dht->friends_list[friend_num]; | ||
1177 | |||
1178 | if (friend->lock_count == DHT_FRIEND_MAX_LOCKS) | ||
1179 | return -1; | ||
1180 | |||
1181 | lock_num = friend->lock_count; | ||
1182 | ++friend->lock_count; | ||
1183 | friend->callbacks[lock_num].ip_callback = ip_callback; | ||
1184 | friend->callbacks[lock_num].data = data; | ||
1185 | friend->callbacks[lock_num].number = number; | ||
1186 | |||
1187 | if (lock_count) | ||
1188 | *lock_count = lock_num + 1; | ||
1189 | |||
1190 | return 0; | ||
1191 | } | ||
1101 | 1192 | ||
1102 | DHT_Friend *temp; | 1193 | DHT_Friend *temp; |
1103 | temp = realloc(dht->friends_list, sizeof(DHT_Friend) * (dht->num_friends + 1)); | 1194 | temp = realloc(dht->friends_list, sizeof(DHT_Friend) * (dht->num_friends + 1)); |
1104 | 1195 | ||
1105 | if (temp == NULL) | 1196 | if (temp == NULL) |
1106 | return 1; | 1197 | return -1; |
1107 | 1198 | ||
1108 | dht->friends_list = temp; | 1199 | dht->friends_list = temp; |
1109 | memset(&dht->friends_list[dht->num_friends], 0, sizeof(DHT_Friend)); | 1200 | DHT_Friend *friend = &dht->friends_list[dht->num_friends]; |
1110 | memcpy(dht->friends_list[dht->num_friends].client_id, client_id, CLIENT_ID_SIZE); | 1201 | memset(friend, 0, sizeof(DHT_Friend)); |
1202 | memcpy(friend->client_id, client_id, CLIENT_ID_SIZE); | ||
1111 | 1203 | ||
1112 | dht->friends_list[dht->num_friends].nat.NATping_id = random_64b(); | 1204 | friend->nat.NATping_id = random_64b(); |
1113 | ++dht->num_friends; | 1205 | ++dht->num_friends; |
1206 | |||
1207 | lock_num = friend->lock_count; | ||
1208 | ++friend->lock_count; | ||
1209 | friend->callbacks[lock_num].ip_callback = ip_callback; | ||
1210 | friend->callbacks[lock_num].data = data; | ||
1211 | friend->callbacks[lock_num].number = number; | ||
1212 | |||
1213 | if (lock_count) | ||
1214 | *lock_count = lock_num + 1; | ||
1215 | |||
1114 | #ifdef ENABLE_ASSOC_DHT | 1216 | #ifdef ENABLE_ASSOC_DHT |
1115 | 1217 | ||
1116 | if (dht->assoc) { | 1218 | if (dht->assoc) { |
@@ -1148,39 +1250,48 @@ int DHT_addfriend(DHT *dht, const uint8_t *client_id) | |||
1148 | return 0; | 1250 | return 0; |
1149 | } | 1251 | } |
1150 | 1252 | ||
1151 | int DHT_delfriend(DHT *dht, const uint8_t *client_id) | 1253 | int DHT_delfriend(DHT *dht, const uint8_t *client_id, uint16_t lock_count) |
1152 | { | 1254 | { |
1153 | uint32_t i; | 1255 | int friend_num = friend_number(dht, client_id); |
1154 | DHT_Friend *temp; | ||
1155 | 1256 | ||
1156 | for (i = 0; i < dht->num_friends; ++i) { | 1257 | if (friend_num == -1) { |
1157 | /* Equal */ | 1258 | return -1; |
1158 | if (id_equal(dht->friends_list[i].client_id, client_id)) { | 1259 | } |
1159 | --dht->num_friends; | ||
1160 | 1260 | ||
1161 | if (dht->num_friends != i) { | 1261 | DHT_Friend *friend = &dht->friends_list[friend_num]; |
1162 | memcpy( &dht->friends_list[i], | 1262 | --friend->lock_count; |
1163 | &dht->friends_list[dht->num_friends], | ||
1164 | sizeof(DHT_Friend) ); | ||
1165 | } | ||
1166 | 1263 | ||
1167 | if (dht->num_friends == 0) { | 1264 | if (friend->lock_count && lock_count) { /* DHT friend is still in use.*/ |
1168 | free(dht->friends_list); | 1265 | --lock_count; |
1169 | dht->friends_list = NULL; | 1266 | friend->callbacks[lock_count].ip_callback = NULL; |
1170 | return 0; | 1267 | friend->callbacks[lock_count].data = NULL; |
1171 | } | 1268 | friend->callbacks[lock_count].number = 0; |
1269 | return 0; | ||
1270 | } | ||
1172 | 1271 | ||
1173 | temp = realloc(dht->friends_list, sizeof(DHT_Friend) * (dht->num_friends)); | 1272 | DHT_Friend *temp; |
1174 | 1273 | ||
1175 | if (temp == NULL) | 1274 | --dht->num_friends; |
1176 | return 1; | ||
1177 | 1275 | ||
1178 | dht->friends_list = temp; | 1276 | if (dht->num_friends != friend_num) { |
1179 | return 0; | 1277 | memcpy( &dht->friends_list[friend_num], |
1180 | } | 1278 | &dht->friends_list[dht->num_friends], |
1279 | sizeof(DHT_Friend) ); | ||
1181 | } | 1280 | } |
1182 | 1281 | ||
1183 | return 1; | 1282 | if (dht->num_friends == 0) { |
1283 | free(dht->friends_list); | ||
1284 | dht->friends_list = NULL; | ||
1285 | return 0; | ||
1286 | } | ||
1287 | |||
1288 | temp = realloc(dht->friends_list, sizeof(DHT_Friend) * (dht->num_friends)); | ||
1289 | |||
1290 | if (temp == NULL) | ||
1291 | return -1; | ||
1292 | |||
1293 | dht->friends_list = temp; | ||
1294 | return 0; | ||
1184 | } | 1295 | } |
1185 | 1296 | ||
1186 | /* TODO: Optimize this. */ | 1297 | /* TODO: Optimize this. */ |
@@ -1356,7 +1467,7 @@ int DHT_bootstrap_from_address(DHT *dht, const char *address, uint8_t ipv6enable | |||
1356 | * | 1467 | * |
1357 | * return -1 if failure. | 1468 | * return -1 if failure. |
1358 | */ | 1469 | */ |
1359 | int route_packet(const DHT *dht, const uint8_t *client_id, const uint8_t *packet, uint32_t length) | 1470 | int route_packet(const DHT *dht, const uint8_t *client_id, const uint8_t *packet, uint16_t length) |
1360 | { | 1471 | { |
1361 | uint32_t i; | 1472 | uint32_t i; |
1362 | 1473 | ||
@@ -1451,7 +1562,7 @@ static int friend_iplist(const DHT *dht, IP_Port *ip_portlist, uint16_t friend_n | |||
1451 | * return ip for friend. | 1562 | * return ip for friend. |
1452 | * return number of nodes the packet was sent to. (Only works if more than (MAX_FRIEND_CLIENTS / 4). | 1563 | * return number of nodes the packet was sent to. (Only works if more than (MAX_FRIEND_CLIENTS / 4). |
1453 | */ | 1564 | */ |
1454 | int route_tofriend(const DHT *dht, const uint8_t *friend_id, const uint8_t *packet, uint32_t length) | 1565 | int route_tofriend(const DHT *dht, const uint8_t *friend_id, const uint8_t *packet, uint16_t length) |
1455 | { | 1566 | { |
1456 | int num = friend_number(dht, friend_id); | 1567 | int num = friend_number(dht, friend_id); |
1457 | 1568 | ||
@@ -1506,7 +1617,7 @@ int route_tofriend(const DHT *dht, const uint8_t *friend_id, const uint8_t *pack | |||
1506 | * | 1617 | * |
1507 | * return number of nodes the packet was sent to. | 1618 | * return number of nodes the packet was sent to. |
1508 | */ | 1619 | */ |
1509 | static int routeone_tofriend(DHT *dht, const uint8_t *friend_id, const uint8_t *packet, uint32_t length) | 1620 | static int routeone_tofriend(DHT *dht, const uint8_t *friend_id, const uint8_t *packet, uint16_t length) |
1510 | { | 1621 | { |
1511 | int num = friend_number(dht, friend_id); | 1622 | int num = friend_number(dht, friend_id); |
1512 | 1623 | ||
@@ -1552,26 +1663,6 @@ static int routeone_tofriend(DHT *dht, const uint8_t *friend_id, const uint8_t * | |||
1552 | return 0; | 1663 | return 0; |
1553 | } | 1664 | } |
1554 | 1665 | ||
1555 | /* Puts all the different ips returned by the nodes for a friend_id into array ip_portlist. | ||
1556 | * ip_portlist must be at least MAX_FRIEND_CLIENTS big. | ||
1557 | * | ||
1558 | * return number of ips returned. | ||
1559 | * return 0 if we are connected to friend or if no ips were found. | ||
1560 | * return -1 if no such friend. | ||
1561 | */ | ||
1562 | int friend_ips(const DHT *dht, IP_Port *ip_portlist, const uint8_t *friend_id) | ||
1563 | { | ||
1564 | uint32_t i; | ||
1565 | |||
1566 | for (i = 0; i < dht->num_friends; ++i) { | ||
1567 | /* Equal */ | ||
1568 | if (id_equal(dht->friends_list[i].client_id, friend_id)) | ||
1569 | return friend_iplist(dht, ip_portlist, i); | ||
1570 | } | ||
1571 | |||
1572 | return -1; | ||
1573 | } | ||
1574 | |||
1575 | /*----------------------------------------------------------------------------------*/ | 1666 | /*----------------------------------------------------------------------------------*/ |
1576 | /*---------------------BEGINNING OF NAT PUNCHING FUNCTIONS--------------------------*/ | 1667 | /*---------------------BEGINNING OF NAT PUNCHING FUNCTIONS--------------------------*/ |
1577 | 1668 | ||
@@ -1604,7 +1695,7 @@ static int send_NATping(DHT *dht, const uint8_t *public_key, uint64_t ping_id, u | |||
1604 | 1695 | ||
1605 | /* Handle a received ping request for. */ | 1696 | /* Handle a received ping request for. */ |
1606 | static int handle_NATping(void *object, IP_Port source, const uint8_t *source_pubkey, const uint8_t *packet, | 1697 | static int handle_NATping(void *object, IP_Port source, const uint8_t *source_pubkey, const uint8_t *packet, |
1607 | uint32_t length) | 1698 | uint16_t length) |
1608 | { | 1699 | { |
1609 | if (length != sizeof(uint64_t) + 1) | 1700 | if (length != sizeof(uint64_t) + 1) |
1610 | return 1; | 1701 | return 1; |
@@ -1794,7 +1885,7 @@ static int send_hardening_req(DHT *dht, Node_format *sendto, uint8_t type, uint8 | |||
1794 | uint8_t data[HARDREQ_DATA_SIZE] = {0}; | 1885 | uint8_t data[HARDREQ_DATA_SIZE] = {0}; |
1795 | data[0] = type; | 1886 | data[0] = type; |
1796 | memcpy(data + 1, contents, length); | 1887 | memcpy(data + 1, contents, length); |
1797 | int len = create_request(dht->self_public_key, dht->self_secret_key, packet, sendto->client_id, data, | 1888 | int len = create_request(dht->self_public_key, dht->self_secret_key, packet, sendto->public_key, data, |
1798 | sizeof(data), CRYPTO_PACKET_HARDENING); | 1889 | sizeof(data), CRYPTO_PACKET_HARDENING); |
1799 | 1890 | ||
1800 | if (len == -1) | 1891 | if (len == -1) |
@@ -1824,7 +1915,7 @@ static int send_hardening_getnode_res(const DHT *dht, const Node_format *sendto, | |||
1824 | data[0] = CHECK_TYPE_GETNODE_RES; | 1915 | data[0] = CHECK_TYPE_GETNODE_RES; |
1825 | memcpy(data + 1, queried_client_id, CLIENT_ID_SIZE); | 1916 | memcpy(data + 1, queried_client_id, CLIENT_ID_SIZE); |
1826 | memcpy(data + 1 + CLIENT_ID_SIZE, nodes_data, nodes_data_length); | 1917 | memcpy(data + 1 + CLIENT_ID_SIZE, nodes_data, nodes_data_length); |
1827 | int len = create_request(dht->self_public_key, dht->self_secret_key, packet, sendto->client_id, data, | 1918 | int len = create_request(dht->self_public_key, dht->self_secret_key, packet, sendto->public_key, data, |
1828 | sizeof(data), CRYPTO_PACKET_HARDENING); | 1919 | sizeof(data), CRYPTO_PACKET_HARDENING); |
1829 | 1920 | ||
1830 | if (len == -1) | 1921 | if (len == -1) |
@@ -1861,12 +1952,12 @@ static uint32_t have_nodes_closelist(DHT *dht, Node_format *nodes, uint16_t num) | |||
1861 | uint32_t i; | 1952 | uint32_t i; |
1862 | 1953 | ||
1863 | for (i = 0; i < num; ++i) { | 1954 | for (i = 0; i < num; ++i) { |
1864 | if (id_equal(nodes[i].client_id, dht->self_public_key)) { | 1955 | if (id_equal(nodes[i].public_key, dht->self_public_key)) { |
1865 | ++counter; | 1956 | ++counter; |
1866 | continue; | 1957 | continue; |
1867 | } | 1958 | } |
1868 | 1959 | ||
1869 | IPPTsPng *temp = get_closelist_IPPTsPng(dht, nodes[i].client_id, nodes[i].ip_port.ip.family); | 1960 | IPPTsPng *temp = get_closelist_IPPTsPng(dht, nodes[i].public_key, nodes[i].ip_port.ip.family); |
1870 | 1961 | ||
1871 | if (temp) { | 1962 | if (temp) { |
1872 | if (!is_timeout(temp->timestamp, BAD_NODE_TIMEOUT)) { | 1963 | if (!is_timeout(temp->timestamp, BAD_NODE_TIMEOUT)) { |
@@ -1884,7 +1975,7 @@ static uint32_t have_nodes_closelist(DHT *dht, Node_format *nodes, uint16_t num) | |||
1884 | 1975 | ||
1885 | /* Handle a received hardening packet */ | 1976 | /* Handle a received hardening packet */ |
1886 | static int handle_hardening(void *object, IP_Port source, const uint8_t *source_pubkey, const uint8_t *packet, | 1977 | static int handle_hardening(void *object, IP_Port source, const uint8_t *source_pubkey, const uint8_t *packet, |
1887 | uint32_t length) | 1978 | uint16_t length) |
1888 | { | 1979 | { |
1889 | DHT *dht = object; | 1980 | DHT *dht = object; |
1890 | 1981 | ||
@@ -1899,10 +1990,10 @@ static int handle_hardening(void *object, IP_Port source, const uint8_t *source_ | |||
1899 | 1990 | ||
1900 | Node_format node, tocheck_node; | 1991 | Node_format node, tocheck_node; |
1901 | node.ip_port = source; | 1992 | node.ip_port = source; |
1902 | memcpy(node.client_id, source_pubkey, CLIENT_ID_SIZE); | 1993 | memcpy(node.public_key, source_pubkey, crypto_box_PUBLICKEYBYTES); |
1903 | memcpy(&tocheck_node, packet + 1, sizeof(Node_format)); | 1994 | memcpy(&tocheck_node, packet + 1, sizeof(Node_format)); |
1904 | 1995 | ||
1905 | if (getnodes(dht, tocheck_node.ip_port, tocheck_node.client_id, packet + 1 + sizeof(Node_format), &node) == -1) | 1996 | if (getnodes(dht, tocheck_node.ip_port, tocheck_node.public_key, packet + 1 + sizeof(Node_format), &node) == -1) |
1906 | return 1; | 1997 | return 1; |
1907 | 1998 | ||
1908 | return 0; | 1999 | return 0; |
@@ -1999,7 +2090,7 @@ uint16_t closelist_nodes(DHT *dht, Node_format *nodes, uint16_t max_num) | |||
1999 | } | 2090 | } |
2000 | 2091 | ||
2001 | if (assoc != NULL) { | 2092 | if (assoc != NULL) { |
2002 | memcpy(nodes[count].client_id, list[i - 1].client_id, CLIENT_ID_SIZE); | 2093 | memcpy(nodes[count].public_key, list[i - 1].client_id, CLIENT_ID_SIZE); |
2003 | nodes[count].ip_port = assoc->ip_port; | 2094 | nodes[count].ip_port = assoc->ip_port; |
2004 | ++count; | 2095 | ++count; |
2005 | 2096 | ||
@@ -2011,82 +2102,6 @@ uint16_t closelist_nodes(DHT *dht, Node_format *nodes, uint16_t max_num) | |||
2011 | return count; | 2102 | return count; |
2012 | } | 2103 | } |
2013 | 2104 | ||
2014 | /* Put a random node from list of list_size in node. LAN_ok is 1 if LAN ips are ok, 0 if we don't want them. */ | ||
2015 | static int random_node_fromlist(Client_data *list, uint16_t list_size, Node_format *node, uint8_t LAN_ok) | ||
2016 | { | ||
2017 | uint32_t i; | ||
2018 | uint32_t num_nodes = 0; | ||
2019 | Client_data *client_list[list_size * 2]; | ||
2020 | IPPTsPng *assoc_list[list_size * 2]; | ||
2021 | |||
2022 | for (i = 0; i < list_size; i++) { | ||
2023 | /* If node is not dead. */ | ||
2024 | Client_data *client = &list[i]; | ||
2025 | IPPTsPng *assoc; | ||
2026 | uint32_t a; | ||
2027 | |||
2028 | for (a = 0, assoc = &client->assoc6; a < 2; a++, assoc = &client->assoc4) { | ||
2029 | /* If node is good. */ | ||
2030 | if (!is_timeout(assoc->timestamp, BAD_NODE_TIMEOUT)) { | ||
2031 | if (!LAN_ok) { | ||
2032 | if (LAN_ip(assoc->ip_port.ip) == 0) | ||
2033 | continue; | ||
2034 | } | ||
2035 | |||
2036 | client_list[num_nodes] = client; | ||
2037 | assoc_list[num_nodes] = assoc; | ||
2038 | ++num_nodes; | ||
2039 | } | ||
2040 | } | ||
2041 | } | ||
2042 | |||
2043 | if (num_nodes == 0) | ||
2044 | return -1; | ||
2045 | |||
2046 | uint32_t rand_node = rand() % num_nodes; | ||
2047 | node->ip_port = assoc_list[rand_node]->ip_port; | ||
2048 | memcpy(node->client_id, client_list[rand_node]->client_id, CLIENT_ID_SIZE); | ||
2049 | return 0; | ||
2050 | } | ||
2051 | |||
2052 | /* Put up to max_num random nodes in nodes. | ||
2053 | * | ||
2054 | * return the number of nodes. | ||
2055 | * | ||
2056 | * NOTE:this is used to pick nodes for paths. | ||
2057 | * | ||
2058 | * TODO: remove the LAN stuff from this. | ||
2059 | */ | ||
2060 | uint16_t random_nodes_path(const DHT *dht, Node_format *nodes, uint16_t max_num) | ||
2061 | { | ||
2062 | if (max_num == 0) | ||
2063 | return 0; | ||
2064 | |||
2065 | if (dht->num_friends == 0) | ||
2066 | return 0; | ||
2067 | |||
2068 | uint16_t count = 0; | ||
2069 | uint16_t list_size = 0; | ||
2070 | uint32_t i; | ||
2071 | |||
2072 | for (i = 0; i < max_num; ++i) { | ||
2073 | Client_data *list = NULL; | ||
2074 | uint16_t rand_num = rand() % (dht->num_friends); | ||
2075 | list = dht->friends_list[rand_num].client_list; | ||
2076 | list_size = MAX_FRIEND_CLIENTS; | ||
2077 | |||
2078 | uint8_t LAN_ok = 1; | ||
2079 | |||
2080 | if (count != 0 && LAN_ip(nodes[0].ip_port.ip) != 0) | ||
2081 | LAN_ok = 0; | ||
2082 | |||
2083 | if (random_node_fromlist(list, list_size, &nodes[count], LAN_ok) == 0) | ||
2084 | ++count; | ||
2085 | } | ||
2086 | |||
2087 | return count; | ||
2088 | } | ||
2089 | |||
2090 | void do_hardening(DHT *dht) | 2105 | void do_hardening(DHT *dht) |
2091 | { | 2106 | { |
2092 | uint32_t i; | 2107 | uint32_t i; |
@@ -2114,16 +2129,16 @@ void do_hardening(DHT *dht) | |||
2114 | if (!ipport_isset(&rand_node.ip_port)) | 2129 | if (!ipport_isset(&rand_node.ip_port)) |
2115 | continue; | 2130 | continue; |
2116 | 2131 | ||
2117 | if (id_equal(client_id, rand_node.client_id)) | 2132 | if (id_equal(client_id, rand_node.public_key)) |
2118 | continue; | 2133 | continue; |
2119 | 2134 | ||
2120 | Node_format to_test; | 2135 | Node_format to_test; |
2121 | to_test.ip_port = cur_iptspng->ip_port; | 2136 | to_test.ip_port = cur_iptspng->ip_port; |
2122 | memcpy(to_test.client_id, client_id, CLIENT_ID_SIZE); | 2137 | memcpy(to_test.public_key, client_id, crypto_box_PUBLICKEYBYTES); |
2123 | 2138 | ||
2124 | //TODO: The search id should maybe not be ours? | 2139 | //TODO: The search id should maybe not be ours? |
2125 | if (send_hardening_getnode_req(dht, &rand_node, &to_test, dht->self_public_key) > 0) { | 2140 | if (send_hardening_getnode_req(dht, &rand_node, &to_test, dht->self_public_key) > 0) { |
2126 | memcpy(cur_iptspng->hardening.send_nodes_pingedid, rand_node.client_id, CLIENT_ID_SIZE); | 2141 | memcpy(cur_iptspng->hardening.send_nodes_pingedid, rand_node.public_key, crypto_box_PUBLICKEYBYTES); |
2127 | cur_iptspng->hardening.send_nodes_timestamp = unix_time(); | 2142 | cur_iptspng->hardening.send_nodes_timestamp = unix_time(); |
2128 | } | 2143 | } |
2129 | } | 2144 | } |
@@ -2145,7 +2160,7 @@ void cryptopacket_registerhandler(DHT *dht, uint8_t byte, cryptopacket_handler_c | |||
2145 | dht->cryptopackethandlers[byte].object = object; | 2160 | dht->cryptopackethandlers[byte].object = object; |
2146 | } | 2161 | } |
2147 | 2162 | ||
2148 | static int cryptopacket_handle(void *object, IP_Port source, const uint8_t *packet, uint32_t length) | 2163 | static int cryptopacket_handle(void *object, IP_Port source, const uint8_t *packet, uint16_t length) |
2149 | { | 2164 | { |
2150 | DHT *dht = object; | 2165 | DHT *dht = object; |
2151 | 2166 | ||
@@ -2221,7 +2236,7 @@ DHT *new_DHT(Networking_Core *net) | |||
2221 | for (i = 0; i < DHT_FAKE_FRIEND_NUMBER; ++i) { | 2236 | for (i = 0; i < DHT_FAKE_FRIEND_NUMBER; ++i) { |
2222 | uint8_t random_key_bytes[CLIENT_ID_SIZE]; | 2237 | uint8_t random_key_bytes[CLIENT_ID_SIZE]; |
2223 | randombytes(random_key_bytes, sizeof(random_key_bytes)); | 2238 | randombytes(random_key_bytes, sizeof(random_key_bytes)); |
2224 | DHT_addfriend(dht, random_key_bytes); | 2239 | DHT_addfriend(dht, random_key_bytes, 0, 0, 0, 0); |
2225 | } | 2240 | } |
2226 | 2241 | ||
2227 | return dht; | 2242 | return dht; |
@@ -2229,6 +2244,12 @@ DHT *new_DHT(Networking_Core *net) | |||
2229 | 2244 | ||
2230 | void do_DHT(DHT *dht) | 2245 | void do_DHT(DHT *dht) |
2231 | { | 2246 | { |
2247 | // Load friends/clients if first call to do_DHT | ||
2248 | if (dht->has_loaded_friends_clients == 0) { | ||
2249 | dht->has_loaded_friends_clients = 1; | ||
2250 | DHT_connect_after_load(dht); | ||
2251 | } | ||
2252 | |||
2232 | unix_time_update(); | 2253 | unix_time_update(); |
2233 | 2254 | ||
2234 | if (dht->last_run == unix_time()) { | 2255 | if (dht->last_run == unix_time()) { |
@@ -2254,7 +2275,6 @@ void kill_DHT(DHT *dht) | |||
2254 | kill_Assoc(dht->assoc); | 2275 | kill_Assoc(dht->assoc); |
2255 | #endif | 2276 | #endif |
2256 | networking_registerhandler(dht->net, NET_PACKET_GET_NODES, NULL, NULL); | 2277 | networking_registerhandler(dht->net, NET_PACKET_GET_NODES, NULL, NULL); |
2257 | networking_registerhandler(dht->net, NET_PACKET_SEND_NODES, NULL, NULL); | ||
2258 | networking_registerhandler(dht->net, NET_PACKET_SEND_NODES_IPV6, NULL, NULL); | 2278 | networking_registerhandler(dht->net, NET_PACKET_SEND_NODES_IPV6, NULL, NULL); |
2259 | cryptopacket_registerhandler(dht, CRYPTO_PACKET_NAT_PING, NULL, NULL); | 2279 | cryptopacket_registerhandler(dht, CRYPTO_PACKET_NAT_PING, NULL, NULL); |
2260 | cryptopacket_registerhandler(dht, CRYPTO_PACKET_HARDENING, NULL, NULL); | 2280 | cryptopacket_registerhandler(dht, CRYPTO_PACKET_HARDENING, NULL, NULL); |
@@ -2262,6 +2282,8 @@ void kill_DHT(DHT *dht) | |||
2262 | ping_array_free_all(&dht->dht_harden_ping_array); | 2282 | ping_array_free_all(&dht->dht_harden_ping_array); |
2263 | kill_ping(dht->ping); | 2283 | kill_ping(dht->ping); |
2264 | free(dht->friends_list); | 2284 | free(dht->friends_list); |
2285 | free(dht->loaded_friends_list); | ||
2286 | free(dht->loaded_clients_list); | ||
2265 | free(dht); | 2287 | free(dht); |
2266 | } | 2288 | } |
2267 | 2289 | ||
@@ -2333,10 +2355,73 @@ void DHT_save(DHT *dht, uint8_t *data) | |||
2333 | } | 2355 | } |
2334 | } | 2356 | } |
2335 | 2357 | ||
2358 | static void DHT_bootstrap_loaded_clients(DHT *dht) | ||
2359 | { | ||
2360 | if (!dht->loaded_clients_list) | ||
2361 | return; | ||
2362 | |||
2363 | uint32_t i; | ||
2364 | |||
2365 | Client_data *client_list = dht->loaded_clients_list; | ||
2366 | uint32_t client_count = dht->loaded_num_clients; | ||
2367 | |||
2368 | for (i = 0; i < client_count; ++i) { | ||
2369 | if (client_list[i].assoc4.timestamp != 0) | ||
2370 | DHT_bootstrap(dht, client_list[i].assoc4.ip_port, client_list[i].client_id); | ||
2371 | |||
2372 | if (client_list[i].assoc6.timestamp != 0) | ||
2373 | DHT_bootstrap(dht, client_list[i].assoc6.ip_port, client_list[i].client_id); | ||
2374 | } | ||
2375 | } | ||
2376 | |||
2377 | static void getnodes_of_loaded_friend_clients(DHT *dht) | ||
2378 | { | ||
2379 | if (!dht->loaded_friends_list) | ||
2380 | return; | ||
2381 | |||
2382 | uint32_t i, j; | ||
2383 | |||
2384 | DHT_Friend *friend_list = dht->loaded_friends_list; | ||
2385 | uint32_t friend_count = dht->loaded_num_friends; | ||
2386 | |||
2387 | for (i = 0; i < friend_count; ++i) { | ||
2388 | for (j = 0; j < MAX_FRIEND_CLIENTS; ++j) { | ||
2389 | Client_data *client = &friend_list[i].client_list[j]; | ||
2390 | |||
2391 | if (client->assoc4.timestamp != 0) | ||
2392 | getnodes(dht, client->assoc4.ip_port, client->client_id, friend_list[i].client_id, NULL); | ||
2393 | |||
2394 | if (client->assoc6.timestamp != 0) | ||
2395 | getnodes(dht, client->assoc6.ip_port, client->client_id, friend_list[i].client_id, NULL); | ||
2396 | } | ||
2397 | } | ||
2398 | } | ||
2399 | |||
2400 | /* Start sending packets after DHT loaded_friends_list and loaded_clients_list are set */ | ||
2401 | int DHT_connect_after_load(DHT *dht) | ||
2402 | { | ||
2403 | if (dht == NULL) | ||
2404 | return -1; | ||
2405 | |||
2406 | getnodes_of_loaded_friend_clients(dht); | ||
2407 | DHT_bootstrap_loaded_clients(dht); | ||
2408 | |||
2409 | // Loaded lists were allocd, free them | ||
2410 | free(dht->loaded_friends_list); | ||
2411 | dht->loaded_friends_list = NULL; | ||
2412 | dht->loaded_num_friends = 0; | ||
2413 | |||
2414 | free(dht->loaded_clients_list); | ||
2415 | dht->loaded_clients_list = NULL; | ||
2416 | dht->loaded_num_clients = 0; | ||
2417 | |||
2418 | return 0; | ||
2419 | } | ||
2420 | |||
2336 | static int dht_load_state_callback(void *outer, const uint8_t *data, uint32_t length, uint16_t type) | 2421 | static int dht_load_state_callback(void *outer, const uint8_t *data, uint32_t length, uint16_t type) |
2337 | { | 2422 | { |
2338 | DHT *dht = outer; | 2423 | DHT *dht = outer; |
2339 | uint32_t num, i, j; | 2424 | uint32_t num, i; |
2340 | 2425 | ||
2341 | switch (type) { | 2426 | switch (type) { |
2342 | case DHT_STATE_TYPE_FRIENDS_ASSOC46: | 2427 | case DHT_STATE_TYPE_FRIENDS_ASSOC46: |
@@ -2347,18 +2432,16 @@ static int dht_load_state_callback(void *outer, const uint8_t *data, uint32_t le | |||
2347 | DHT_Friend *friend_list = (DHT_Friend *)data; | 2432 | DHT_Friend *friend_list = (DHT_Friend *)data; |
2348 | num = length / sizeof(DHT_Friend); | 2433 | num = length / sizeof(DHT_Friend); |
2349 | 2434 | ||
2350 | for (i = 0; i < num; ++i) { | 2435 | free(dht->loaded_friends_list); |
2436 | // Copy to loaded_friends_list | ||
2437 | dht->loaded_friends_list = calloc(num, sizeof(DHT_Friend)); | ||
2351 | 2438 | ||
2352 | for (j = 0; j < MAX_FRIEND_CLIENTS; ++j) { | 2439 | for (i = 0; i < num; i++) |
2353 | Client_data *client = &friend_list[i].client_list[j]; | 2440 | memcpy(&(dht->loaded_friends_list[i]), &(friend_list[i]), sizeof(DHT_Friend)); |
2354 | 2441 | ||
2355 | if (client->assoc4.timestamp != 0) | 2442 | dht->loaded_num_friends = num; |
2356 | getnodes(dht, client->assoc4.ip_port, client->client_id, friend_list[i].client_id, NULL); | ||
2357 | 2443 | ||
2358 | if (client->assoc6.timestamp != 0) | 2444 | dht->has_loaded_friends_clients = 1; |
2359 | getnodes(dht, client->assoc6.ip_port, client->client_id, friend_list[i].client_id, NULL); | ||
2360 | } | ||
2361 | } | ||
2362 | } /* localize declarations */ | 2445 | } /* localize declarations */ |
2363 | 2446 | ||
2364 | break; | 2447 | break; |
@@ -2371,13 +2454,16 @@ static int dht_load_state_callback(void *outer, const uint8_t *data, uint32_t le | |||
2371 | num = length / sizeof(Client_data); | 2454 | num = length / sizeof(Client_data); |
2372 | Client_data *client_list = (Client_data *)data; | 2455 | Client_data *client_list = (Client_data *)data; |
2373 | 2456 | ||
2374 | for (i = 0; i < num; ++i) { | 2457 | free(dht->loaded_clients_list); |
2375 | if (client_list[i].assoc4.timestamp != 0) | 2458 | // Copy to loaded_clients_list |
2376 | DHT_bootstrap(dht, client_list[i].assoc4.ip_port, client_list[i].client_id); | 2459 | dht->loaded_clients_list = calloc(num, sizeof(Client_data)); |
2377 | 2460 | ||
2378 | if (client_list[i].assoc6.timestamp != 0) | 2461 | for (i = 0; i < num; i++) |
2379 | DHT_bootstrap(dht, client_list[i].assoc6.ip_port, client_list[i].client_id); | 2462 | memcpy(&(dht->loaded_clients_list[i]), &(client_list[i]), sizeof(Client_data)); |
2380 | } | 2463 | |
2464 | dht->loaded_num_clients = num; | ||
2465 | |||
2466 | dht->has_loaded_friends_clients = 1; | ||
2381 | } /* localize declarations */ | 2467 | } /* localize declarations */ |
2382 | 2468 | ||
2383 | break; | 2469 | break; |
diff --git a/toxcore/DHT.h b/toxcore/DHT.h index 563ae08c..318a6002 100644 --- a/toxcore/DHT.h +++ b/toxcore/DHT.h | |||
@@ -65,7 +65,9 @@ | |||
65 | 65 | ||
66 | /* Functions to transfer ips safely across wire. */ | 66 | /* Functions to transfer ips safely across wire. */ |
67 | void to_net_family(IP *ip); | 67 | void to_net_family(IP *ip); |
68 | void to_host_family(IP *ip); | 68 | |
69 | /* return 0 on success, -1 on failure. */ | ||
70 | int to_host_family(IP *ip); | ||
69 | 71 | ||
70 | typedef struct { | 72 | typedef struct { |
71 | IP_Port ip_port; | 73 | IP_Port ip_port; |
@@ -122,6 +124,8 @@ typedef struct { | |||
122 | uint64_t NATping_timestamp; | 124 | uint64_t NATping_timestamp; |
123 | } NAT; | 125 | } NAT; |
124 | 126 | ||
127 | #define DHT_FRIEND_MAX_LOCKS 32 | ||
128 | |||
125 | typedef struct { | 129 | typedef struct { |
126 | uint8_t client_id[CLIENT_ID_SIZE]; | 130 | uint8_t client_id[CLIENT_ID_SIZE]; |
127 | Client_data client_list[MAX_FRIEND_CLIENTS]; | 131 | Client_data client_list[MAX_FRIEND_CLIENTS]; |
@@ -133,11 +137,18 @@ typedef struct { | |||
133 | 137 | ||
134 | /* Symetric NAT hole punching stuff. */ | 138 | /* Symetric NAT hole punching stuff. */ |
135 | NAT nat; | 139 | NAT nat; |
140 | |||
141 | uint16_t lock_count; | ||
142 | struct { | ||
143 | void (*ip_callback)(void *, int32_t, IP_Port); | ||
144 | void *data; | ||
145 | int32_t number; | ||
146 | } callbacks[DHT_FRIEND_MAX_LOCKS]; | ||
147 | |||
136 | } DHT_Friend; | 148 | } DHT_Friend; |
137 | 149 | ||
138 | typedef struct __attribute__ ((__packed__)) | 150 | typedef struct { |
139 | { | 151 | uint8_t public_key[crypto_box_PUBLICKEYBYTES]; |
140 | uint8_t client_id[CLIENT_ID_SIZE]; | ||
141 | IP_Port ip_port; | 152 | IP_Port ip_port; |
142 | } | 153 | } |
143 | Node_format; | 154 | Node_format; |
@@ -177,7 +188,7 @@ typedef struct { | |||
177 | /*----------------------------------------------------------------------------------*/ | 188 | /*----------------------------------------------------------------------------------*/ |
178 | 189 | ||
179 | typedef int (*cryptopacket_handler_callback)(void *object, IP_Port ip_port, const uint8_t *source_pubkey, | 190 | typedef int (*cryptopacket_handler_callback)(void *object, IP_Port ip_port, const uint8_t *source_pubkey, |
180 | const uint8_t *data, uint32_t len); | 191 | const uint8_t *data, uint16_t len); |
181 | 192 | ||
182 | typedef struct { | 193 | typedef struct { |
183 | cryptopacket_handler_callback function; | 194 | cryptopacket_handler_callback function; |
@@ -200,6 +211,14 @@ typedef struct { | |||
200 | DHT_Friend *friends_list; | 211 | DHT_Friend *friends_list; |
201 | uint16_t num_friends; | 212 | uint16_t num_friends; |
202 | 213 | ||
214 | // Used after loading of file (tox_load), but no longer needed after connect (tox_connect) | ||
215 | // Unsure if friends_list and num_friends could just be used instead? | ||
216 | int has_loaded_friends_clients; // Whether or not we have loaded on the first do_DHT | ||
217 | DHT_Friend *loaded_friends_list; | ||
218 | uint32_t loaded_num_friends; | ||
219 | Client_data *loaded_clients_list; | ||
220 | uint32_t loaded_num_clients; | ||
221 | |||
203 | Shared_Keys shared_keys_recv; | 222 | Shared_Keys shared_keys_recv; |
204 | Shared_Keys shared_keys_sent; | 223 | Shared_Keys shared_keys_sent; |
205 | 224 | ||
@@ -238,18 +257,25 @@ void DHT_getnodes(DHT *dht, const IP_Port *from_ipp, const uint8_t *from_id, con | |||
238 | /* Add a new friend to the friends list. | 257 | /* Add a new friend to the friends list. |
239 | * client_id must be CLIENT_ID_SIZE bytes long. | 258 | * client_id must be CLIENT_ID_SIZE bytes long. |
240 | * | 259 | * |
260 | * ip_callback is the callback of a function that will be called when the ip address | ||
261 | * is found along with arguments data and number. | ||
262 | * | ||
263 | * lock_count will be set to a non zero number that must be passed to DHT_delfriend() | ||
264 | * to properly remove the callback. | ||
265 | * | ||
241 | * return 0 if success. | 266 | * return 0 if success. |
242 | * return 1 if failure (friends list is full). | 267 | * return -1 if failure (friends list is full). |
243 | */ | 268 | */ |
244 | int DHT_addfriend(DHT *dht, const uint8_t *client_id); | 269 | int DHT_addfriend(DHT *dht, const uint8_t *client_id, void (*ip_callback)(void *data, int32_t number, IP_Port), |
270 | void *data, int32_t number, uint16_t *lock_count); | ||
245 | 271 | ||
246 | /* Delete a friend from the friends list. | 272 | /* Delete a friend from the friends list. |
247 | * client_id must be CLIENT_ID_SIZE bytes long. | 273 | * client_id must be CLIENT_ID_SIZE bytes long. |
248 | * | 274 | * |
249 | * return 0 if success. | 275 | * return 0 if success. |
250 | * return 1 if failure (client_id not in friends list). | 276 | * return -1 if failure (client_id not in friends list). |
251 | */ | 277 | */ |
252 | int DHT_delfriend(DHT *dht, const uint8_t *client_id); | 278 | int DHT_delfriend(DHT *dht, const uint8_t *client_id, uint16_t lock_count); |
253 | 279 | ||
254 | /* Get ip of friend. | 280 | /* Get ip of friend. |
255 | * client_id must be CLIENT_ID_SIZE bytes long. | 281 | * client_id must be CLIENT_ID_SIZE bytes long. |
@@ -300,14 +326,6 @@ int get_close_nodes(const DHT *dht, const uint8_t *client_id, Node_format *nodes | |||
300 | */ | 326 | */ |
301 | uint16_t closelist_nodes(DHT *dht, Node_format *nodes, uint16_t max_num); | 327 | uint16_t closelist_nodes(DHT *dht, Node_format *nodes, uint16_t max_num); |
302 | 328 | ||
303 | /* Put up to max_num random nodes in nodes. | ||
304 | * | ||
305 | * return the number of nodes. | ||
306 | * | ||
307 | * NOTE:this is used to pick nodes for paths. | ||
308 | */ | ||
309 | uint16_t random_nodes_path(const DHT *dht, Node_format *nodes, uint16_t max_num); | ||
310 | |||
311 | /* Run this function at least a couple times per second (It's the main loop). */ | 329 | /* Run this function at least a couple times per second (It's the main loop). */ |
312 | void do_DHT(DHT *dht); | 330 | void do_DHT(DHT *dht); |
313 | 331 | ||
@@ -332,6 +350,12 @@ void DHT_bootstrap(DHT *dht, IP_Port ip_port, const uint8_t *public_key); | |||
332 | int DHT_bootstrap_from_address(DHT *dht, const char *address, uint8_t ipv6enabled, | 350 | int DHT_bootstrap_from_address(DHT *dht, const char *address, uint8_t ipv6enabled, |
333 | uint16_t port, const uint8_t *public_key); | 351 | uint16_t port, const uint8_t *public_key); |
334 | 352 | ||
353 | /* Start sending packets after DHT loaded_friends_list and loaded_clients_list are set. | ||
354 | * | ||
355 | * returns 0 if successful | ||
356 | * returns -1 otherwise | ||
357 | */ | ||
358 | int DHT_connect_after_load(DHT *dht); | ||
335 | 359 | ||
336 | /* ROUTING FUNCTIONS */ | 360 | /* ROUTING FUNCTIONS */ |
337 | 361 | ||
@@ -339,28 +363,18 @@ int DHT_bootstrap_from_address(DHT *dht, const char *address, uint8_t ipv6enable | |||
339 | * | 363 | * |
340 | * return -1 if failure. | 364 | * return -1 if failure. |
341 | */ | 365 | */ |
342 | int route_packet(const DHT *dht, const uint8_t *client_id, const uint8_t *packet, uint32_t length); | 366 | int route_packet(const DHT *dht, const uint8_t *client_id, const uint8_t *packet, uint16_t length); |
343 | 367 | ||
344 | /* Send the following packet to everyone who tells us they are connected to friend_id. | 368 | /* Send the following packet to everyone who tells us they are connected to friend_id. |
345 | * | 369 | * |
346 | * return number of nodes it sent the packet to. | 370 | * return number of nodes it sent the packet to. |
347 | */ | 371 | */ |
348 | int route_tofriend(const DHT *dht, const uint8_t *friend_id, const uint8_t *packet, uint32_t length); | 372 | int route_tofriend(const DHT *dht, const uint8_t *friend_id, const uint8_t *packet, uint16_t length); |
349 | 373 | ||
350 | /* Function to handle crypto packets. | 374 | /* Function to handle crypto packets. |
351 | */ | 375 | */ |
352 | void cryptopacket_registerhandler(DHT *dht, uint8_t byte, cryptopacket_handler_callback cb, void *object); | 376 | void cryptopacket_registerhandler(DHT *dht, uint8_t byte, cryptopacket_handler_callback cb, void *object); |
353 | 377 | ||
354 | /* NAT PUNCHING FUNCTIONS */ | ||
355 | |||
356 | /* Puts all the different ips returned by the nodes for a friend_id into array ip_portlist. | ||
357 | * ip_portlist must be at least MAX_FRIEND_CLIENTS big. | ||
358 | * | ||
359 | * returns number of ips returned. | ||
360 | * returns -1 if no such friend. | ||
361 | */ | ||
362 | int friend_ips(const DHT *dht, IP_Port *ip_portlist, const uint8_t *friend_id); | ||
363 | |||
364 | /* SAVE/LOAD functions */ | 378 | /* SAVE/LOAD functions */ |
365 | 379 | ||
366 | /* Get the size of the DHT (for saving). */ | 380 | /* Get the size of the DHT (for saving). */ |
diff --git a/toxcore/LAN_discovery.c b/toxcore/LAN_discovery.c index 3c05fe8d..bc020d87 100644 --- a/toxcore/LAN_discovery.c +++ b/toxcore/LAN_discovery.c | |||
@@ -28,6 +28,13 @@ | |||
28 | #include "LAN_discovery.h" | 28 | #include "LAN_discovery.h" |
29 | #include "util.h" | 29 | #include "util.h" |
30 | 30 | ||
31 | /* Used for get_broadcast(). */ | ||
32 | #ifdef __linux | ||
33 | #include <sys/ioctl.h> | ||
34 | #include <arpa/inet.h> | ||
35 | #include <linux/netdevice.h> | ||
36 | #endif | ||
37 | |||
31 | #define MAX_INTERFACES 16 | 38 | #define MAX_INTERFACES 16 |
32 | 39 | ||
33 | 40 | ||
@@ -86,6 +93,10 @@ static void fetch_broadcast_info(uint16_t port) | |||
86 | pAdapter = pAdapter->Next; | 93 | pAdapter = pAdapter->Next; |
87 | } | 94 | } |
88 | } | 95 | } |
96 | |||
97 | if (pAdapterInfo) { | ||
98 | free(pAdapterInfo); | ||
99 | } | ||
89 | } | 100 | } |
90 | 101 | ||
91 | #elif defined(__linux__) | 102 | #elif defined(__linux__) |
@@ -141,6 +152,11 @@ static void fetch_broadcast_info(uint16_t port) | |||
141 | IP_Port *ip_port = &broadcast_ip_port[broadcast_count]; | 152 | IP_Port *ip_port = &broadcast_ip_port[broadcast_count]; |
142 | ip_port->ip.family = AF_INET; | 153 | ip_port->ip.family = AF_INET; |
143 | ip_port->ip.ip4.in_addr = sock4->sin_addr; | 154 | ip_port->ip.ip4.in_addr = sock4->sin_addr; |
155 | |||
156 | if (ip_port->ip.ip4.uint32 == 0) { | ||
157 | continue; | ||
158 | } | ||
159 | |||
144 | ip_port->port = port; | 160 | ip_port->port = port; |
145 | broadcast_count++; | 161 | broadcast_count++; |
146 | } | 162 | } |
@@ -269,7 +285,7 @@ int LAN_ip(IP ip) | |||
269 | return -1; | 285 | return -1; |
270 | } | 286 | } |
271 | 287 | ||
272 | static int handle_LANdiscovery(void *object, IP_Port source, const uint8_t *packet, uint32_t length) | 288 | static int handle_LANdiscovery(void *object, IP_Port source, const uint8_t *packet, uint16_t length) |
273 | { | 289 | { |
274 | DHT *dht = object; | 290 | DHT *dht = object; |
275 | 291 | ||
diff --git a/toxcore/LAN_discovery.h b/toxcore/LAN_discovery.h index fcb094e4..5dffc3ad 100644 --- a/toxcore/LAN_discovery.h +++ b/toxcore/LAN_discovery.h | |||
@@ -28,13 +28,6 @@ | |||
28 | 28 | ||
29 | #include "DHT.h" | 29 | #include "DHT.h" |
30 | 30 | ||
31 | /* Used for get_broadcast(). */ | ||
32 | #ifdef __linux | ||
33 | #include <sys/ioctl.h> | ||
34 | #include <arpa/inet.h> | ||
35 | #include <linux/netdevice.h> | ||
36 | #endif | ||
37 | |||
38 | /* Interval in seconds between LAN discovery packet sending. */ | 31 | /* Interval in seconds between LAN discovery packet sending. */ |
39 | #define LAN_DISCOVERY_INTERVAL 10 | 32 | #define LAN_DISCOVERY_INTERVAL 10 |
40 | 33 | ||
diff --git a/toxcore/Makefile.inc b/toxcore/Makefile.inc index 8e39f96e..9fd1f94a 100644 --- a/toxcore/Makefile.inc +++ b/toxcore/Makefile.inc | |||
@@ -19,6 +19,8 @@ libtoxcore_la_SOURCES = ../toxcore/DHT.h \ | |||
19 | ../toxcore/friend_requests.c \ | 19 | ../toxcore/friend_requests.c \ |
20 | ../toxcore/LAN_discovery.h \ | 20 | ../toxcore/LAN_discovery.h \ |
21 | ../toxcore/LAN_discovery.c \ | 21 | ../toxcore/LAN_discovery.c \ |
22 | ../toxcore/friend_connection.h \ | ||
23 | ../toxcore/friend_connection.c \ | ||
22 | ../toxcore/Messenger.h \ | 24 | ../toxcore/Messenger.h \ |
23 | ../toxcore/Messenger.c \ | 25 | ../toxcore/Messenger.c \ |
24 | ../toxcore/ping.h \ | 26 | ../toxcore/ping.h \ |
@@ -27,8 +29,8 @@ libtoxcore_la_SOURCES = ../toxcore/DHT.h \ | |||
27 | ../toxcore/tox.c \ | 29 | ../toxcore/tox.c \ |
28 | ../toxcore/util.h \ | 30 | ../toxcore/util.h \ |
29 | ../toxcore/util.c \ | 31 | ../toxcore/util.c \ |
30 | ../toxcore/group_chats.h \ | 32 | ../toxcore/group.h \ |
31 | ../toxcore/group_chats.c \ | 33 | ../toxcore/group.c \ |
32 | ../toxcore/assoc.h \ | 34 | ../toxcore/assoc.h \ |
33 | ../toxcore/assoc.c \ | 35 | ../toxcore/assoc.c \ |
34 | ../toxcore/onion.h \ | 36 | ../toxcore/onion.h \ |
diff --git a/toxcore/Messenger.c b/toxcore/Messenger.c index eff845cf..a9d5e6a1 100644 --- a/toxcore/Messenger.c +++ b/toxcore/Messenger.c | |||
@@ -36,18 +36,21 @@ | |||
36 | #include "util.h" | 36 | #include "util.h" |
37 | 37 | ||
38 | 38 | ||
39 | #define MIN(a,b) (((a)<(b))?(a):(b)) | ||
40 | |||
41 | |||
42 | static void set_friend_status(Messenger *m, int32_t friendnumber, uint8_t status); | 39 | static void set_friend_status(Messenger *m, int32_t friendnumber, uint8_t status); |
43 | static int write_cryptpacket_id(const Messenger *m, int32_t friendnumber, uint8_t packet_id, const uint8_t *data, | 40 | static int write_cryptpacket_id(const Messenger *m, int32_t friendnumber, uint8_t packet_id, const uint8_t *data, |
44 | uint32_t length); | 41 | uint32_t length, uint8_t congestion_control); |
45 | static int clear_receipts(Messenger *m, int32_t friendnumber); | 42 | static int send_avatar_data_control(const Messenger *m, const uint32_t friendnumber, uint8_t op); |
46 | 43 | ||
47 | // friend_not_valid determines if the friendnumber passed is valid in the Messenger object | 44 | // friend_not_valid determines if the friendnumber passed is valid in the Messenger object |
48 | static uint8_t friend_not_valid(const Messenger *m, int32_t friendnumber) | 45 | static uint8_t friend_not_valid(const Messenger *m, int32_t friendnumber) |
49 | { | 46 | { |
50 | return (unsigned int)friendnumber >= m->numfriends; | 47 | if ((unsigned int)friendnumber < m->numfriends) { |
48 | if (m->friendlist[friendnumber].status != 0) { | ||
49 | return 0; | ||
50 | } | ||
51 | } | ||
52 | |||
53 | return 1; | ||
51 | } | 54 | } |
52 | 55 | ||
53 | static int add_online_friend(Messenger *m, int32_t friendnumber) | 56 | static int add_online_friend(Messenger *m, int32_t friendnumber) |
@@ -92,37 +95,45 @@ int realloc_friendlist(Messenger *m, uint32_t num) | |||
92 | /* return the friend id associated to that public key. | 95 | /* return the friend id associated to that public key. |
93 | * return -1 if no such friend. | 96 | * return -1 if no such friend. |
94 | */ | 97 | */ |
95 | int32_t getfriend_id(const Messenger *m, const uint8_t *client_id) | 98 | int32_t getfriend_id(const Messenger *m, const uint8_t *real_pk) |
96 | { | 99 | { |
97 | uint32_t i; | 100 | uint32_t i; |
98 | 101 | ||
99 | for (i = 0; i < m->numfriends; ++i) { | 102 | for (i = 0; i < m->numfriends; ++i) { |
100 | if (m->friendlist[i].status > 0) | 103 | if (m->friendlist[i].status > 0) |
101 | if (id_equal(client_id, m->friendlist[i].client_id)) | 104 | if (id_equal(real_pk, m->friendlist[i].real_pk)) |
102 | return i; | 105 | return i; |
103 | } | 106 | } |
104 | 107 | ||
105 | return -1; | 108 | return -1; |
106 | } | 109 | } |
107 | 110 | ||
108 | /* Copies the public key associated to that friend id into client_id buffer. | 111 | /* Copies the public key associated to that friend id into real_pk buffer. |
109 | * Make sure that client_id is of size CLIENT_ID_SIZE. | 112 | * Make sure that real_pk is of size crypto_box_PUBLICKEYBYTES. |
110 | * | 113 | * |
111 | * return 0 if success. | 114 | * return 0 if success. |
112 | * return -1 if failure. | 115 | * return -1 if failure. |
113 | */ | 116 | */ |
114 | int getclient_id(const Messenger *m, int32_t friendnumber, uint8_t *client_id) | 117 | int get_real_pk(const Messenger *m, int32_t friendnumber, uint8_t *real_pk) |
115 | { | 118 | { |
116 | if (friend_not_valid(m, friendnumber)) | 119 | if (friend_not_valid(m, friendnumber)) |
117 | return -1; | 120 | return -1; |
118 | 121 | ||
119 | if (m->friendlist[friendnumber].status > 0) { | 122 | memcpy(real_pk, m->friendlist[friendnumber].real_pk, crypto_box_PUBLICKEYBYTES); |
120 | memcpy(client_id, m->friendlist[friendnumber].client_id, CLIENT_ID_SIZE); | 123 | return 0; |
121 | return 0; | 124 | } |
122 | } | ||
123 | 125 | ||
124 | return -1; | 126 | /* return friend connection id on success. |
127 | * return -1 if failure. | ||
128 | */ | ||
129 | int getfriendcon_id(const Messenger *m, int32_t friendnumber) | ||
130 | { | ||
131 | if (friend_not_valid(m, friendnumber)) | ||
132 | return -1; | ||
133 | |||
134 | return m->friendlist[friendnumber].friendcon_id; | ||
125 | } | 135 | } |
136 | |||
126 | /* TODO: Another checksum algorithm might be better. | 137 | /* TODO: Another checksum algorithm might be better. |
127 | * | 138 | * |
128 | * return a uint16_t that represents the checksum of address of length len. | 139 | * return a uint16_t that represents the checksum of address of length len. |
@@ -140,7 +151,7 @@ static uint16_t address_checksum(const uint8_t *address, uint32_t len) | |||
140 | return check; | 151 | return check; |
141 | } | 152 | } |
142 | 153 | ||
143 | /* Format: [client_id (32 bytes)][nospam number (4 bytes)][checksum (2 bytes)] | 154 | /* Format: [real_pk (32 bytes)][nospam number (4 bytes)][checksum (2 bytes)] |
144 | * | 155 | * |
145 | * return FRIEND_ADDRESS_SIZE byte address to give to others. | 156 | * return FRIEND_ADDRESS_SIZE byte address to give to others. |
146 | */ | 157 | */ |
@@ -153,19 +164,71 @@ void getaddress(const Messenger *m, uint8_t *address) | |||
153 | memcpy(address + crypto_box_PUBLICKEYBYTES + sizeof(nospam), &checksum, sizeof(checksum)); | 164 | memcpy(address + crypto_box_PUBLICKEYBYTES + sizeof(nospam), &checksum, sizeof(checksum)); |
154 | } | 165 | } |
155 | 166 | ||
156 | /* callback for recv TCP relay nodes. */ | 167 | static int send_online_packet(Messenger *m, int32_t friendnumber) |
157 | static int tcp_relay_node_callback(void *object, uint32_t number, IP_Port ip_port, const uint8_t *public_key) | ||
158 | { | 168 | { |
159 | Messenger *m = object; | 169 | if (friend_not_valid(m, friendnumber)) |
170 | return 0; | ||
160 | 171 | ||
161 | if (friend_not_valid(m, number)) | 172 | uint8_t packet = PACKET_ID_ONLINE; |
162 | return -1; | 173 | return write_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c, |
174 | m->friendlist[friendnumber].friendcon_id), &packet, sizeof(packet), 0) != -1; | ||
175 | } | ||
163 | 176 | ||
164 | if (m->friendlist[number].crypt_connection_id != -1) { | 177 | static int send_offine_packet(Messenger *m, int friendcon_id) |
165 | return add_tcp_relay_peer(m->net_crypto, m->friendlist[number].crypt_connection_id, ip_port, public_key); | 178 | { |
166 | } else { | 179 | uint8_t packet = PACKET_ID_OFFLINE; |
167 | return add_tcp_relay(m->net_crypto, ip_port, public_key); | 180 | return write_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c, friendcon_id), &packet, |
181 | sizeof(packet), 0) != -1; | ||
182 | } | ||
183 | |||
184 | static int handle_status(void *object, int i, uint8_t status); | ||
185 | static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len); | ||
186 | static int handle_custom_lossy_packet(void *object, int friend_num, const uint8_t *packet, uint16_t length); | ||
187 | |||
188 | static int32_t init_new_friend(Messenger *m, const uint8_t *real_pk, uint8_t status) | ||
189 | { | ||
190 | /* Resize the friend list if necessary. */ | ||
191 | if (realloc_friendlist(m, m->numfriends + 1) != 0) | ||
192 | return FAERR_NOMEM; | ||
193 | |||
194 | memset(&(m->friendlist[m->numfriends]), 0, sizeof(Friend)); | ||
195 | |||
196 | int friendcon_id = new_friend_connection(m->fr_c, real_pk); | ||
197 | |||
198 | if (friendcon_id == -1) | ||
199 | return FAERR_NOMEM; | ||
200 | |||
201 | uint32_t i; | ||
202 | |||
203 | for (i = 0; i <= m->numfriends; ++i) { | ||
204 | if (m->friendlist[i].status == NOFRIEND) { | ||
205 | m->friendlist[i].status = status; | ||
206 | m->friendlist[i].friendcon_id = friendcon_id; | ||
207 | m->friendlist[i].friendrequest_lastsent = 0; | ||
208 | id_copy(m->friendlist[i].real_pk, real_pk); | ||
209 | m->friendlist[i].statusmessage_length = 0; | ||
210 | m->friendlist[i].userstatus = USERSTATUS_NONE; | ||
211 | m->friendlist[i].avatar_info_sent = 0; | ||
212 | m->friendlist[i].avatar_recv_data = NULL; | ||
213 | m->friendlist[i].avatar_send_data.bytes_sent = 0; | ||
214 | m->friendlist[i].avatar_send_data.last_reset = 0; | ||
215 | m->friendlist[i].is_typing = 0; | ||
216 | m->friendlist[i].message_id = 0; | ||
217 | friend_connection_callbacks(m->fr_c, friendcon_id, MESSENGER_CALLBACK_INDEX, &handle_status, &handle_packet, | ||
218 | &handle_custom_lossy_packet, m, i); | ||
219 | |||
220 | if (m->numfriends == i) | ||
221 | ++m->numfriends; | ||
222 | |||
223 | if (friend_con_connected(m->fr_c, friendcon_id) == FRIENDCONN_STATUS_CONNECTED) { | ||
224 | send_online_packet(m, i); | ||
225 | } | ||
226 | |||
227 | return i; | ||
228 | } | ||
168 | } | 229 | } |
230 | |||
231 | return FAERR_NOMEM; | ||
169 | } | 232 | } |
170 | 233 | ||
171 | /* | 234 | /* |
@@ -179,7 +242,6 @@ static int tcp_relay_node_callback(void *object, uint32_t number, IP_Port ip_por | |||
179 | * return FAERR_NOMESSAGE if no message (message length must be >= 1 byte). | 242 | * return FAERR_NOMESSAGE if no message (message length must be >= 1 byte). |
180 | * return FAERR_OWNKEY if user's own key. | 243 | * return FAERR_OWNKEY if user's own key. |
181 | * return FAERR_ALREADYSENT if friend request already sent or already a friend. | 244 | * return FAERR_ALREADYSENT if friend request already sent or already a friend. |
182 | * return FAERR_UNKNOWN for unknown error. | ||
183 | * return FAERR_BADCHECKSUM if bad checksum in address. | 245 | * return FAERR_BADCHECKSUM if bad checksum in address. |
184 | * return FAERR_SETNEWNOSPAM if the friend was already there but the nospam was different. | 246 | * return FAERR_SETNEWNOSPAM if the friend was already there but the nospam was different. |
185 | * (the nospam for that friend was set to the new one). | 247 | * (the nospam for that friend was set to the new one). |
@@ -190,10 +252,10 @@ int32_t m_addfriend(Messenger *m, const uint8_t *address, const uint8_t *data, u | |||
190 | if (length > MAX_FRIEND_REQUEST_DATA_SIZE) | 252 | if (length > MAX_FRIEND_REQUEST_DATA_SIZE) |
191 | return FAERR_TOOLONG; | 253 | return FAERR_TOOLONG; |
192 | 254 | ||
193 | uint8_t client_id[crypto_box_PUBLICKEYBYTES]; | 255 | uint8_t real_pk[crypto_box_PUBLICKEYBYTES]; |
194 | id_copy(client_id, address); | 256 | id_copy(real_pk, address); |
195 | 257 | ||
196 | if (!public_key_valid(client_id)) | 258 | if (!public_key_valid(real_pk)) |
197 | return FAERR_BADCHECKSUM; | 259 | return FAERR_BADCHECKSUM; |
198 | 260 | ||
199 | uint16_t check, checksum = address_checksum(address, FRIEND_ADDRESS_SIZE - sizeof(checksum)); | 261 | uint16_t check, checksum = address_checksum(address, FRIEND_ADDRESS_SIZE - sizeof(checksum)); |
@@ -205,10 +267,10 @@ int32_t m_addfriend(Messenger *m, const uint8_t *address, const uint8_t *data, u | |||
205 | if (length < 1) | 267 | if (length < 1) |
206 | return FAERR_NOMESSAGE; | 268 | return FAERR_NOMESSAGE; |
207 | 269 | ||
208 | if (id_equal(client_id, m->net_crypto->self_public_key)) | 270 | if (id_equal(real_pk, m->net_crypto->self_public_key)) |
209 | return FAERR_OWNKEY; | 271 | return FAERR_OWNKEY; |
210 | 272 | ||
211 | int32_t friend_id = getfriend_id(m, client_id); | 273 | int32_t friend_id = getfriend_id(m, real_pk); |
212 | 274 | ||
213 | if (friend_id != -1) { | 275 | if (friend_id != -1) { |
214 | if (m->friendlist[friend_id].status >= FRIEND_CONFIRMED) | 276 | if (m->friendlist[friend_id].status >= FRIEND_CONFIRMED) |
@@ -224,143 +286,32 @@ int32_t m_addfriend(Messenger *m, const uint8_t *address, const uint8_t *data, u | |||
224 | return FAERR_SETNEWNOSPAM; | 286 | return FAERR_SETNEWNOSPAM; |
225 | } | 287 | } |
226 | 288 | ||
227 | /* Resize the friend list if necessary. */ | 289 | int32_t ret = init_new_friend(m, real_pk, FRIEND_ADDED); |
228 | if (realloc_friendlist(m, m->numfriends + 1) != 0) | ||
229 | return FAERR_NOMEM; | ||
230 | |||
231 | memset(&(m->friendlist[m->numfriends]), 0, sizeof(Friend)); | ||
232 | |||
233 | int32_t onion_friendnum = onion_addfriend(m->onion_c, client_id); | ||
234 | |||
235 | if (onion_friendnum == -1) | ||
236 | return FAERR_UNKNOWN; | ||
237 | |||
238 | uint32_t i; | ||
239 | 290 | ||
240 | for (i = 0; i <= m->numfriends; ++i) { | 291 | if (ret < 0) { |
241 | if (m->friendlist[i].status == NOFRIEND) { | 292 | return ret; |
242 | m->friendlist[i].onion_friendnum = onion_friendnum; | ||
243 | m->friendlist[i].status = FRIEND_ADDED; | ||
244 | m->friendlist[i].crypt_connection_id = -1; | ||
245 | m->friendlist[i].friendrequest_lastsent = 0; | ||
246 | m->friendlist[i].friendrequest_timeout = FRIENDREQUEST_TIMEOUT; | ||
247 | id_copy(m->friendlist[i].client_id, client_id); | ||
248 | m->friendlist[i].statusmessage = calloc(1, 1); | ||
249 | m->friendlist[i].statusmessage_length = 1; | ||
250 | m->friendlist[i].userstatus = USERSTATUS_NONE; | ||
251 | m->friendlist[i].is_typing = 0; | ||
252 | memcpy(m->friendlist[i].info, data, length); | ||
253 | m->friendlist[i].info_size = length; | ||
254 | m->friendlist[i].message_id = 0; | ||
255 | memcpy(&(m->friendlist[i].friendrequest_nospam), address + crypto_box_PUBLICKEYBYTES, sizeof(uint32_t)); | ||
256 | recv_tcp_relay_handler(m->onion_c, onion_friendnum, &tcp_relay_node_callback, m, i); | ||
257 | |||
258 | if (m->numfriends == i) | ||
259 | ++m->numfriends; | ||
260 | |||
261 | return i; | ||
262 | } | ||
263 | } | 293 | } |
264 | 294 | ||
265 | return FAERR_UNKNOWN; | 295 | m->friendlist[ret].friendrequest_timeout = FRIENDREQUEST_TIMEOUT; |
266 | } | 296 | memcpy(m->friendlist[ret].info, data, length); |
297 | m->friendlist[ret].info_size = length; | ||
298 | memcpy(&(m->friendlist[ret].friendrequest_nospam), address + crypto_box_PUBLICKEYBYTES, sizeof(uint32_t)); | ||
267 | 299 | ||
268 | int32_t m_addfriend_norequest(Messenger *m, const uint8_t *client_id) | 300 | return ret; |
269 | { | ||
270 | if (getfriend_id(m, client_id) != -1) | ||
271 | return -1; | ||
272 | |||
273 | if (!public_key_valid(client_id)) | ||
274 | return -1; | ||
275 | |||
276 | /* Resize the friend list if necessary. */ | ||
277 | if (realloc_friendlist(m, m->numfriends + 1) != 0) | ||
278 | return -1; | ||
279 | |||
280 | if (id_equal(client_id, m->net_crypto->self_public_key)) | ||
281 | return -1; | ||
282 | |||
283 | memset(&(m->friendlist[m->numfriends]), 0, sizeof(Friend)); | ||
284 | |||
285 | int32_t onion_friendnum = onion_addfriend(m->onion_c, client_id); | ||
286 | |||
287 | if (onion_friendnum == -1) | ||
288 | return -1; | ||
289 | |||
290 | uint32_t i; | ||
291 | |||
292 | for (i = 0; i <= m->numfriends; ++i) { | ||
293 | if (m->friendlist[i].status == NOFRIEND) { | ||
294 | m->friendlist[i].onion_friendnum = onion_friendnum; | ||
295 | m->friendlist[i].status = FRIEND_CONFIRMED; | ||
296 | m->friendlist[i].crypt_connection_id = -1; | ||
297 | m->friendlist[i].friendrequest_lastsent = 0; | ||
298 | id_copy(m->friendlist[i].client_id, client_id); | ||
299 | m->friendlist[i].statusmessage = calloc(1, 1); | ||
300 | m->friendlist[i].statusmessage_length = 1; | ||
301 | m->friendlist[i].userstatus = USERSTATUS_NONE; | ||
302 | m->friendlist[i].is_typing = 0; | ||
303 | m->friendlist[i].message_id = 0; | ||
304 | recv_tcp_relay_handler(m->onion_c, onion_friendnum, &tcp_relay_node_callback, m, i); | ||
305 | |||
306 | if (m->numfriends == i) | ||
307 | ++m->numfriends; | ||
308 | |||
309 | return i; | ||
310 | } | ||
311 | } | ||
312 | |||
313 | return -1; | ||
314 | } | ||
315 | |||
316 | /* Remove a friend. | ||
317 | * | ||
318 | * return 0 if success. | ||
319 | * return -1 if failure. | ||
320 | */ | ||
321 | int m_delfriend(Messenger *m, int32_t friendnumber) | ||
322 | { | ||
323 | if (friend_not_valid(m, friendnumber)) | ||
324 | return -1; | ||
325 | |||
326 | if (m->friendlist[friendnumber].status == FRIEND_ONLINE) | ||
327 | remove_online_friend(m, friendnumber); | ||
328 | |||
329 | onion_delfriend(m->onion_c, m->friendlist[friendnumber].onion_friendnum); | ||
330 | crypto_kill(m->net_crypto, m->friendlist[friendnumber].crypt_connection_id); | ||
331 | free(m->friendlist[friendnumber].statusmessage); | ||
332 | clear_receipts(m, friendnumber); | ||
333 | remove_request_received(&(m->fr), m->friendlist[friendnumber].client_id); | ||
334 | memset(&(m->friendlist[friendnumber]), 0, sizeof(Friend)); | ||
335 | uint32_t i; | ||
336 | |||
337 | for (i = m->numfriends; i != 0; --i) { | ||
338 | if (m->friendlist[i - 1].status != NOFRIEND) | ||
339 | break; | ||
340 | } | ||
341 | |||
342 | m->numfriends = i; | ||
343 | |||
344 | if (realloc_friendlist(m, m->numfriends) != 0) | ||
345 | return FAERR_NOMEM; | ||
346 | |||
347 | return 0; | ||
348 | } | 301 | } |
349 | 302 | ||
350 | int m_get_friend_connectionstatus(const Messenger *m, int32_t friendnumber) | 303 | int32_t m_addfriend_norequest(Messenger *m, const uint8_t *real_pk) |
351 | { | 304 | { |
352 | if (friend_not_valid(m, friendnumber)) | 305 | if (getfriend_id(m, real_pk) != -1) |
353 | return -1; | 306 | return FAERR_ALREADYSENT; |
354 | 307 | ||
355 | return m->friendlist[friendnumber].status == FRIEND_ONLINE; | 308 | if (!public_key_valid(real_pk)) |
356 | } | 309 | return FAERR_BADCHECKSUM; |
357 | 310 | ||
358 | int m_friend_exists(const Messenger *m, int32_t friendnumber) | 311 | if (id_equal(real_pk, m->net_crypto->self_public_key)) |
359 | { | 312 | return FAERR_OWNKEY; |
360 | if (friend_not_valid(m, friendnumber)) | ||
361 | return 0; | ||
362 | 313 | ||
363 | return m->friendlist[friendnumber].status > NOFRIEND; | 314 | return init_new_friend(m, real_pk, FRIEND_CONFIRMED); |
364 | } | 315 | } |
365 | 316 | ||
366 | static int clear_receipts(Messenger *m, int32_t friendnumber) | 317 | static int clear_receipts(Messenger *m, int32_t friendnumber) |
@@ -415,7 +366,7 @@ static int do_receipts(Messenger *m, int32_t friendnumber) | |||
415 | while (receipts) { | 366 | while (receipts) { |
416 | struct Receipts *temp_r = receipts->next; | 367 | struct Receipts *temp_r = receipts->next; |
417 | 368 | ||
418 | if (cryptpacket_received(m->net_crypto, m->friendlist[friendnumber].crypt_connection_id, receipts->packet_num) == -1) | 369 | if (cryptpacket_received(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c, m->friendlist[friendnumber].friendcon_id), receipts->packet_num) == -1) |
419 | break; | 370 | break; |
420 | 371 | ||
421 | if (m->read_receipt) | 372 | if (m->read_receipt) |
@@ -432,6 +383,74 @@ static int do_receipts(Messenger *m, int32_t friendnumber) | |||
432 | return 0; | 383 | return 0; |
433 | } | 384 | } |
434 | 385 | ||
386 | /* Remove a friend. | ||
387 | * | ||
388 | * return 0 if success. | ||
389 | * return -1 if failure. | ||
390 | */ | ||
391 | int m_delfriend(Messenger *m, int32_t friendnumber) | ||
392 | { | ||
393 | if (friend_not_valid(m, friendnumber)) | ||
394 | return -1; | ||
395 | |||
396 | if (m->friendlist[friendnumber].status == FRIEND_ONLINE) | ||
397 | remove_online_friend(m, friendnumber); | ||
398 | |||
399 | free(m->friendlist[friendnumber].avatar_recv_data); | ||
400 | clear_receipts(m, friendnumber); | ||
401 | remove_request_received(&(m->fr), m->friendlist[friendnumber].real_pk); | ||
402 | friend_connection_callbacks(m->fr_c, m->friendlist[friendnumber].friendcon_id, MESSENGER_CALLBACK_INDEX, 0, 0, 0, 0, 0); | ||
403 | kill_friend_connection(m->fr_c, m->friendlist[friendnumber].friendcon_id); | ||
404 | |||
405 | if (friend_con_connected(m->fr_c, m->friendlist[friendnumber].friendcon_id) == FRIENDCONN_STATUS_CONNECTED) { | ||
406 | send_offine_packet(m, m->friendlist[friendnumber].friendcon_id); | ||
407 | } | ||
408 | |||
409 | memset(&(m->friendlist[friendnumber]), 0, sizeof(Friend)); | ||
410 | uint32_t i; | ||
411 | |||
412 | for (i = m->numfriends; i != 0; --i) { | ||
413 | if (m->friendlist[i - 1].status != NOFRIEND) | ||
414 | break; | ||
415 | } | ||
416 | |||
417 | m->numfriends = i; | ||
418 | |||
419 | if (realloc_friendlist(m, m->numfriends) != 0) | ||
420 | return FAERR_NOMEM; | ||
421 | |||
422 | return 0; | ||
423 | } | ||
424 | |||
425 | int m_get_friend_connectionstatus(const Messenger *m, int32_t friendnumber) | ||
426 | { | ||
427 | if (friend_not_valid(m, friendnumber)) | ||
428 | return -1; | ||
429 | |||
430 | if (m->friendlist[friendnumber].status == FRIEND_ONLINE) { | ||
431 | uint8_t direct_connected = 0; | ||
432 | crypto_connection_status(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c, | ||
433 | m->friendlist[friendnumber].friendcon_id), &direct_connected); | ||
434 | |||
435 | if (direct_connected) { | ||
436 | return CONNECTION_UDP; | ||
437 | } else { | ||
438 | return CONNECTION_TCP; | ||
439 | } | ||
440 | } else { | ||
441 | return CONNECTION_NONE; | ||
442 | } | ||
443 | } | ||
444 | |||
445 | int m_friend_exists(const Messenger *m, int32_t friendnumber) | ||
446 | { | ||
447 | if (friend_not_valid(m, friendnumber)) | ||
448 | return 0; | ||
449 | |||
450 | return 1; | ||
451 | } | ||
452 | |||
453 | |||
435 | static uint32_t send_message_generic(Messenger *m, int32_t friendnumber, const uint8_t *message, uint32_t length, | 454 | static uint32_t send_message_generic(Messenger *m, int32_t friendnumber, const uint8_t *message, uint32_t length, |
436 | uint8_t packet_id) | 455 | uint8_t packet_id) |
437 | { | 456 | { |
@@ -447,8 +466,7 @@ static uint32_t send_message_generic(Messenger *m, int32_t friendnumber, const u | |||
447 | if (length != 0) | 466 | if (length != 0) |
448 | memcpy(packet + 1, message, length); | 467 | memcpy(packet + 1, message, length); |
449 | 468 | ||
450 | int64_t packet_num = write_cryptpacket(m->net_crypto, m->friendlist[friendnumber].crypt_connection_id, packet, | 469 | int64_t packet_num = write_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c, m->friendlist[friendnumber].friendcon_id), packet, length + 1, 0); |
451 | length + 1); | ||
452 | 470 | ||
453 | if (packet_num == -1) | 471 | if (packet_num == -1) |
454 | return 0; | 472 | return 0; |
@@ -488,10 +506,10 @@ uint32_t m_sendaction(Messenger *m, int32_t friendnumber, const uint8_t *action, | |||
488 | */ | 506 | */ |
489 | static int m_sendname(const Messenger *m, int32_t friendnumber, const uint8_t *name, uint16_t length) | 507 | static int m_sendname(const Messenger *m, int32_t friendnumber, const uint8_t *name, uint16_t length) |
490 | { | 508 | { |
491 | if (length > MAX_NAME_LENGTH || length == 0) | 509 | if (length > MAX_NAME_LENGTH) |
492 | return 0; | 510 | return 0; |
493 | 511 | ||
494 | return write_cryptpacket_id(m, friendnumber, PACKET_ID_NICKNAME, name, length); | 512 | return write_cryptpacket_id(m, friendnumber, PACKET_ID_NICKNAME, name, length, 0); |
495 | } | 513 | } |
496 | 514 | ||
497 | /* Set the name and name_length of a friend. | 515 | /* Set the name and name_length of a friend. |
@@ -522,20 +540,21 @@ int setfriendname(Messenger *m, int32_t friendnumber, const uint8_t *name, uint1 | |||
522 | */ | 540 | */ |
523 | int setname(Messenger *m, const uint8_t *name, uint16_t length) | 541 | int setname(Messenger *m, const uint8_t *name, uint16_t length) |
524 | { | 542 | { |
525 | if (length > MAX_NAME_LENGTH || length == 0) | 543 | if (length > MAX_NAME_LENGTH) |
526 | return -1; | 544 | return -1; |
527 | 545 | ||
528 | memcpy(m->name, name, length); | 546 | if (m->name_length == length && (length == 0 || memcmp(name, m->name, length) == 0)) |
547 | return 0; | ||
548 | |||
549 | if (length) | ||
550 | memcpy(m->name, name, length); | ||
551 | |||
529 | m->name_length = length; | 552 | m->name_length = length; |
530 | uint32_t i; | 553 | uint32_t i; |
531 | 554 | ||
532 | for (i = 0; i < m->numfriends; ++i) | 555 | for (i = 0; i < m->numfriends; ++i) |
533 | m->friendlist[i].name_sent = 0; | 556 | m->friendlist[i].name_sent = 0; |
534 | 557 | ||
535 | for (i = 0; i < m->numchats; i++) | ||
536 | if (m->chats[i] != NULL) | ||
537 | set_nick(m->chats[i], name, length); /* TODO: remove this (group nicks should not be tied to the global one) */ | ||
538 | |||
539 | return 0; | 558 | return 0; |
540 | } | 559 | } |
541 | 560 | ||
@@ -588,7 +607,12 @@ int m_set_statusmessage(Messenger *m, const uint8_t *status, uint16_t length) | |||
588 | if (length > MAX_STATUSMESSAGE_LENGTH) | 607 | if (length > MAX_STATUSMESSAGE_LENGTH) |
589 | return -1; | 608 | return -1; |
590 | 609 | ||
591 | memcpy(m->statusmessage, status, length); | 610 | if (m->statusmessage_length == length && (length == 0 || memcmp(m->statusmessage, status, length) == 0)) |
611 | return 0; | ||
612 | |||
613 | if (length) | ||
614 | memcpy(m->statusmessage, status, length); | ||
615 | |||
592 | m->statusmessage_length = length; | 616 | m->statusmessage_length = length; |
593 | 617 | ||
594 | uint32_t i; | 618 | uint32_t i; |
@@ -601,9 +625,11 @@ int m_set_statusmessage(Messenger *m, const uint8_t *status, uint16_t length) | |||
601 | 625 | ||
602 | int m_set_userstatus(Messenger *m, uint8_t status) | 626 | int m_set_userstatus(Messenger *m, uint8_t status) |
603 | { | 627 | { |
604 | if (status >= USERSTATUS_INVALID) { | 628 | if (status >= USERSTATUS_INVALID) |
605 | return -1; | 629 | return -1; |
606 | } | 630 | |
631 | if (m->userstatus == status) | ||
632 | return 0; | ||
607 | 633 | ||
608 | m->userstatus = status; | 634 | m->userstatus = status; |
609 | uint32_t i; | 635 | uint32_t i; |
@@ -614,6 +640,149 @@ int m_set_userstatus(Messenger *m, uint8_t status) | |||
614 | return 0; | 640 | return 0; |
615 | } | 641 | } |
616 | 642 | ||
643 | int m_unset_avatar(Messenger *m) | ||
644 | { | ||
645 | if (m->avatar_data != NULL) | ||
646 | free(m->avatar_data); | ||
647 | |||
648 | m->avatar_data = NULL; | ||
649 | m->avatar_data_length = 0; | ||
650 | m->avatar_format = AVATAR_FORMAT_NONE; | ||
651 | memset(m->avatar_hash, 0, AVATAR_HASH_LENGTH); | ||
652 | |||
653 | uint32_t i; | ||
654 | |||
655 | for (i = 0; i < m->numfriends; ++i) | ||
656 | m->friendlist[i].avatar_info_sent = 0; | ||
657 | |||
658 | return 0; | ||
659 | } | ||
660 | |||
661 | int m_set_avatar(Messenger *m, uint8_t format, const uint8_t *data, uint32_t length) | ||
662 | { | ||
663 | if (format == AVATAR_FORMAT_NONE) { | ||
664 | m_unset_avatar(m); | ||
665 | return 0; | ||
666 | } | ||
667 | |||
668 | if (length > AVATAR_MAX_DATA_LENGTH || length == 0) | ||
669 | return -1; | ||
670 | |||
671 | if (data == NULL) | ||
672 | return -1; | ||
673 | |||
674 | uint8_t *tmp = realloc(m->avatar_data, length); | ||
675 | |||
676 | if (tmp == NULL) | ||
677 | return -1; | ||
678 | |||
679 | m->avatar_format = format; | ||
680 | m->avatar_data = tmp; | ||
681 | m->avatar_data_length = length; | ||
682 | memcpy(m->avatar_data, data, length); | ||
683 | |||
684 | m_avatar_hash(m->avatar_hash, m->avatar_data, m->avatar_data_length); | ||
685 | |||
686 | uint32_t i; | ||
687 | |||
688 | for (i = 0; i < m->numfriends; ++i) | ||
689 | m->friendlist[i].avatar_info_sent = 0; | ||
690 | |||
691 | return 0; | ||
692 | } | ||
693 | |||
694 | int m_get_self_avatar(const Messenger *m, uint8_t *format, uint8_t *buf, uint32_t *length, uint32_t maxlen, | ||
695 | uint8_t *hash) | ||
696 | { | ||
697 | if (format) | ||
698 | *format = m->avatar_format; | ||
699 | |||
700 | if (length) | ||
701 | *length = m->avatar_data_length; | ||
702 | |||
703 | if (hash) | ||
704 | memcpy(hash, m->avatar_hash, AVATAR_HASH_LENGTH); | ||
705 | |||
706 | if (buf != NULL && maxlen > 0) { | ||
707 | if (m->avatar_data_length <= maxlen) | ||
708 | memcpy(buf, m->avatar_data, m->avatar_data_length); | ||
709 | else | ||
710 | return -1; | ||
711 | } | ||
712 | |||
713 | return 0; | ||
714 | } | ||
715 | |||
716 | int m_hash(uint8_t *hash, const uint8_t *data, const uint32_t datalen) | ||
717 | { | ||
718 | if (hash == NULL) | ||
719 | return -1; | ||
720 | |||
721 | return crypto_hash_sha256(hash, data, datalen); | ||
722 | } | ||
723 | |||
724 | int m_avatar_hash(uint8_t *hash, const uint8_t *data, const uint32_t datalen) | ||
725 | { | ||
726 | return m_hash(hash, data, datalen); | ||
727 | } | ||
728 | |||
729 | int m_request_avatar_info(const Messenger *m, const int32_t friendnumber) | ||
730 | { | ||
731 | if (friend_not_valid(m, friendnumber)) | ||
732 | return -1; | ||
733 | |||
734 | if (write_cryptpacket_id(m, friendnumber, PACKET_ID_AVATAR_INFO_REQ, 0, 0, 0)) | ||
735 | return 0; | ||
736 | else | ||
737 | return -1; | ||
738 | } | ||
739 | |||
740 | int m_send_avatar_info(const Messenger *m, const int32_t friendnumber) | ||
741 | { | ||
742 | if (friend_not_valid(m, friendnumber)) | ||
743 | return -1; | ||
744 | |||
745 | uint8_t data[sizeof(uint8_t) + AVATAR_HASH_LENGTH]; | ||
746 | data[0] = m->avatar_format; | ||
747 | memcpy(data + 1, m->avatar_hash, AVATAR_HASH_LENGTH); | ||
748 | |||
749 | if (write_cryptpacket_id(m, friendnumber, PACKET_ID_AVATAR_INFO, data, sizeof(data), 0)) | ||
750 | return 0; | ||
751 | else | ||
752 | return -1; | ||
753 | } | ||
754 | |||
755 | int m_request_avatar_data(const Messenger *m, const int32_t friendnumber) | ||
756 | { | ||
757 | if (friend_not_valid(m, friendnumber)) | ||
758 | return -1; | ||
759 | |||
760 | AVATAR_RECEIVEDATA *avrd = m->friendlist[friendnumber].avatar_recv_data; | ||
761 | |||
762 | if (avrd == NULL) { | ||
763 | avrd = calloc(sizeof(AVATAR_RECEIVEDATA), 1); | ||
764 | |||
765 | if (avrd == NULL) | ||
766 | return -1; | ||
767 | |||
768 | avrd->started = 0; | ||
769 | m->friendlist[friendnumber].avatar_recv_data = avrd; | ||
770 | } | ||
771 | |||
772 | if (avrd->started) { | ||
773 | LOGGER_DEBUG("Resetting already started data request. " | ||
774 | "friendnumber == %u", friendnumber); | ||
775 | } | ||
776 | |||
777 | avrd->started = 0; | ||
778 | avrd->bytes_received = 0; | ||
779 | avrd->total_length = 0; | ||
780 | avrd->format = AVATAR_FORMAT_NONE; | ||
781 | |||
782 | return send_avatar_data_control(m, friendnumber, AVATAR_DATACONTROL_REQ); | ||
783 | } | ||
784 | |||
785 | |||
617 | /* return the size of friendnumber's user status. | 786 | /* return the size of friendnumber's user status. |
618 | * Guaranteed to be at most MAX_STATUSMESSAGE_LENGTH. | 787 | * Guaranteed to be at most MAX_STATUSMESSAGE_LENGTH. |
619 | */ | 788 | */ |
@@ -648,12 +817,10 @@ int m_get_self_statusmessage_size(const Messenger *m) | |||
648 | return m->statusmessage_length; | 817 | return m->statusmessage_length; |
649 | } | 818 | } |
650 | 819 | ||
651 | int m_copy_self_statusmessage(const Messenger *m, uint8_t *buf, uint32_t maxlen) | 820 | int m_copy_self_statusmessage(const Messenger *m, uint8_t *buf) |
652 | { | 821 | { |
653 | int msglen = MIN(maxlen, m->statusmessage_length); | 822 | memcpy(buf, m->statusmessage, m->statusmessage_length); |
654 | memcpy(buf, m->statusmessage, msglen); | 823 | return m->statusmessage_length; |
655 | memset(buf + msglen, 0, maxlen - msglen); | ||
656 | return msglen; | ||
657 | } | 824 | } |
658 | 825 | ||
659 | uint8_t m_get_userstatus(const Messenger *m, int32_t friendnumber) | 826 | uint8_t m_get_userstatus(const Messenger *m, int32_t friendnumber) |
@@ -686,20 +853,22 @@ uint64_t m_get_last_online(const Messenger *m, int32_t friendnumber) | |||
686 | int m_set_usertyping(Messenger *m, int32_t friendnumber, uint8_t is_typing) | 853 | int m_set_usertyping(Messenger *m, int32_t friendnumber, uint8_t is_typing) |
687 | 854 | ||
688 | { | 855 | { |
689 | if (is_typing != 0 && is_typing != 1) { | 856 | if (is_typing != 0 && is_typing != 1) |
690 | return -1; | 857 | return -1; |
691 | } | ||
692 | 858 | ||
693 | if (friend_not_valid(m, friendnumber)) | 859 | if (friend_not_valid(m, friendnumber)) |
694 | return -1; | 860 | return -1; |
695 | 861 | ||
862 | if (m->friendlist[friendnumber].user_istyping == is_typing) | ||
863 | return 0; | ||
864 | |||
696 | m->friendlist[friendnumber].user_istyping = is_typing; | 865 | m->friendlist[friendnumber].user_istyping = is_typing; |
697 | m->friendlist[friendnumber].user_istyping_sent = 0; | 866 | m->friendlist[friendnumber].user_istyping_sent = 0; |
698 | 867 | ||
699 | return 0; | 868 | return 0; |
700 | } | 869 | } |
701 | 870 | ||
702 | uint8_t m_get_istyping(const Messenger *m, int32_t friendnumber) | 871 | int m_get_istyping(const Messenger *m, int32_t friendnumber) |
703 | { | 872 | { |
704 | if (friend_not_valid(m, friendnumber)) | 873 | if (friend_not_valid(m, friendnumber)) |
705 | return -1; | 874 | return -1; |
@@ -709,28 +878,18 @@ uint8_t m_get_istyping(const Messenger *m, int32_t friendnumber) | |||
709 | 878 | ||
710 | static int send_statusmessage(const Messenger *m, int32_t friendnumber, const uint8_t *status, uint16_t length) | 879 | static int send_statusmessage(const Messenger *m, int32_t friendnumber, const uint8_t *status, uint16_t length) |
711 | { | 880 | { |
712 | return write_cryptpacket_id(m, friendnumber, PACKET_ID_STATUSMESSAGE, status, length); | 881 | return write_cryptpacket_id(m, friendnumber, PACKET_ID_STATUSMESSAGE, status, length, 0); |
713 | } | 882 | } |
714 | 883 | ||
715 | static int send_userstatus(const Messenger *m, int32_t friendnumber, uint8_t status) | 884 | static int send_userstatus(const Messenger *m, int32_t friendnumber, uint8_t status) |
716 | { | 885 | { |
717 | return write_cryptpacket_id(m, friendnumber, PACKET_ID_USERSTATUS, &status, sizeof(status)); | 886 | return write_cryptpacket_id(m, friendnumber, PACKET_ID_USERSTATUS, &status, sizeof(status), 0); |
718 | } | 887 | } |
719 | 888 | ||
720 | static int send_user_istyping(const Messenger *m, int32_t friendnumber, uint8_t is_typing) | 889 | static int send_user_istyping(const Messenger *m, int32_t friendnumber, uint8_t is_typing) |
721 | { | 890 | { |
722 | uint8_t typing = is_typing; | 891 | uint8_t typing = is_typing; |
723 | return write_cryptpacket_id(m, friendnumber, PACKET_ID_TYPING, &typing, sizeof(typing)); | 892 | return write_cryptpacket_id(m, friendnumber, PACKET_ID_TYPING, &typing, sizeof(typing), 0); |
724 | } | ||
725 | |||
726 | static int send_ping(const Messenger *m, int32_t friendnumber) | ||
727 | { | ||
728 | int ret = write_cryptpacket_id(m, friendnumber, PACKET_ID_ALIVE, 0, 0); | ||
729 | |||
730 | if (ret == 1) | ||
731 | m->friendlist[friendnumber].ping_lastsent = unix_time(); | ||
732 | |||
733 | return ret; | ||
734 | } | 893 | } |
735 | 894 | ||
736 | static int send_relays(const Messenger *m, int32_t friendnumber) | 895 | static int send_relays(const Messenger *m, int32_t friendnumber) |
@@ -742,7 +901,7 @@ static int send_relays(const Messenger *m, int32_t friendnumber) | |||
742 | n = copy_connected_tcp_relays(m->net_crypto, nodes, MAX_SHARED_RELAYS); | 901 | n = copy_connected_tcp_relays(m->net_crypto, nodes, MAX_SHARED_RELAYS); |
743 | length = pack_nodes(data, sizeof(data), nodes, n); | 902 | length = pack_nodes(data, sizeof(data), nodes, n); |
744 | 903 | ||
745 | int ret = write_cryptpacket_id(m, friendnumber, PACKET_ID_SHARE_RELAYS, data, length); | 904 | int ret = write_cryptpacket_id(m, friendnumber, PACKET_ID_SHARE_RELAYS, data, length, 0); |
746 | 905 | ||
747 | if (ret == 1) | 906 | if (ret == 1) |
748 | m->friendlist[friendnumber].share_relays_lastsent = unix_time(); | 907 | m->friendlist[friendnumber].share_relays_lastsent = unix_time(); |
@@ -757,10 +916,12 @@ static int set_friend_statusmessage(const Messenger *m, int32_t friendnumber, co | |||
757 | if (friend_not_valid(m, friendnumber)) | 916 | if (friend_not_valid(m, friendnumber)) |
758 | return -1; | 917 | return -1; |
759 | 918 | ||
760 | uint8_t *newstatus = calloc(length + 1, 1); | 919 | if (length > MAX_STATUSMESSAGE_LENGTH) |
761 | memcpy(newstatus, status, length); | 920 | return -1; |
762 | free(m->friendlist[friendnumber].statusmessage); | 921 | |
763 | m->friendlist[friendnumber].statusmessage = newstatus; | 922 | if (length) |
923 | memcpy(m->friendlist[friendnumber].statusmessage, status, length); | ||
924 | |||
764 | m->friendlist[friendnumber].statusmessage_length = length; | 925 | m->friendlist[friendnumber].statusmessage_length = length; |
765 | return 0; | 926 | return 0; |
766 | } | 927 | } |
@@ -775,75 +936,106 @@ static void set_friend_typing(const Messenger *m, int32_t friendnumber, uint8_t | |||
775 | m->friendlist[friendnumber].is_typing = is_typing; | 936 | m->friendlist[friendnumber].is_typing = is_typing; |
776 | } | 937 | } |
777 | 938 | ||
778 | /* static void (*friend_request)(uint8_t *, uint8_t *, uint16_t); */ | ||
779 | /* Set the function that will be executed when a friend request is received. */ | 939 | /* Set the function that will be executed when a friend request is received. */ |
780 | void m_callback_friendrequest(Messenger *m, void (*function)(Messenger *m, const uint8_t *, const uint8_t *, uint16_t, | 940 | void m_callback_friendrequest(Messenger *m, void (*function)(Messenger *m, const uint8_t *, const uint8_t *, size_t, |
781 | void *), void *userdata) | 941 | void *), void *userdata) |
782 | { | 942 | { |
783 | void (*handle_friendrequest)(void *, const uint8_t *, const uint8_t *, uint16_t, void *) = (void *)function; | 943 | void (*handle_friendrequest)(void *, const uint8_t *, const uint8_t *, size_t, void *) = (void *)function; |
784 | callback_friendrequest(&(m->fr), handle_friendrequest, m, userdata); | 944 | callback_friendrequest(&(m->fr), handle_friendrequest, m, userdata); |
785 | } | 945 | } |
786 | 946 | ||
787 | /* Set the function that will be executed when a message from a friend is received. */ | 947 | /* Set the function that will be executed when a message from a friend is received. */ |
788 | void m_callback_friendmessage(Messenger *m, void (*function)(Messenger *m, int32_t, const uint8_t *, uint16_t, void *), | 948 | void m_callback_friendmessage(Messenger *m, void (*function)(Messenger *m, uint32_t, const uint8_t *, size_t, void *), |
789 | void *userdata) | 949 | void *userdata) |
790 | { | 950 | { |
791 | m->friend_message = function; | 951 | m->friend_message = function; |
792 | m->friend_message_userdata = userdata; | 952 | m->friend_message_userdata = userdata; |
793 | } | 953 | } |
794 | 954 | ||
795 | void m_callback_action(Messenger *m, void (*function)(Messenger *m, int32_t, const uint8_t *, uint16_t, void *), | 955 | void m_callback_action(Messenger *m, void (*function)(Messenger *m, uint32_t, const uint8_t *, size_t, void *), |
796 | void *userdata) | 956 | void *userdata) |
797 | { | 957 | { |
798 | m->friend_action = function; | 958 | m->friend_action = function; |
799 | m->friend_action_userdata = userdata; | 959 | m->friend_action_userdata = userdata; |
800 | } | 960 | } |
801 | 961 | ||
802 | void m_callback_namechange(Messenger *m, void (*function)(Messenger *m, int32_t, const uint8_t *, uint16_t, void *), | 962 | void m_callback_namechange(Messenger *m, void (*function)(Messenger *m, uint32_t, const uint8_t *, size_t, void *), |
803 | void *userdata) | 963 | void *userdata) |
804 | { | 964 | { |
805 | m->friend_namechange = function; | 965 | m->friend_namechange = function; |
806 | m->friend_namechange_userdata = userdata; | 966 | m->friend_namechange_userdata = userdata; |
807 | } | 967 | } |
808 | 968 | ||
809 | void m_callback_statusmessage(Messenger *m, void (*function)(Messenger *m, int32_t, const uint8_t *, uint16_t, void *), | 969 | void m_callback_statusmessage(Messenger *m, void (*function)(Messenger *m, uint32_t, const uint8_t *, size_t, void *), |
810 | void *userdata) | 970 | void *userdata) |
811 | { | 971 | { |
812 | m->friend_statusmessagechange = function; | 972 | m->friend_statusmessagechange = function; |
813 | m->friend_statuschange_userdata = userdata; | 973 | m->friend_statuschange_userdata = userdata; |
814 | } | 974 | } |
815 | 975 | ||
816 | void m_callback_userstatus(Messenger *m, void (*function)(Messenger *m, int32_t, uint8_t, void *), void *userdata) | 976 | void m_callback_userstatus(Messenger *m, void (*function)(Messenger *m, uint32_t, uint8_t, void *), void *userdata) |
817 | { | 977 | { |
818 | m->friend_userstatuschange = function; | 978 | m->friend_userstatuschange = function; |
819 | m->friend_userstatuschange_userdata = userdata; | 979 | m->friend_userstatuschange_userdata = userdata; |
820 | } | 980 | } |
821 | 981 | ||
822 | void m_callback_typingchange(Messenger *m, void(*function)(Messenger *m, int32_t, uint8_t, void *), void *userdata) | 982 | void m_callback_typingchange(Messenger *m, void(*function)(Messenger *m, uint32_t, _Bool, void *), void *userdata) |
823 | { | 983 | { |
824 | m->friend_typingchange = function; | 984 | m->friend_typingchange = function; |
825 | m->friend_typingchange_userdata = userdata; | 985 | m->friend_typingchange_userdata = userdata; |
826 | } | 986 | } |
827 | 987 | ||
828 | void m_callback_read_receipt(Messenger *m, void (*function)(Messenger *m, int32_t, uint32_t, void *), void *userdata) | 988 | void m_callback_read_receipt(Messenger *m, void (*function)(Messenger *m, uint32_t, uint32_t, void *), void *userdata) |
829 | { | 989 | { |
830 | m->read_receipt = function; | 990 | m->read_receipt = function; |
831 | m->read_receipt_userdata = userdata; | 991 | m->read_receipt_userdata = userdata; |
832 | } | 992 | } |
833 | 993 | ||
834 | void m_callback_connectionstatus(Messenger *m, void (*function)(Messenger *m, int32_t, uint8_t, void *), void *userdata) | 994 | void m_callback_connectionstatus(Messenger *m, void (*function)(Messenger *m, uint32_t, uint8_t, void *), |
995 | void *userdata) | ||
835 | { | 996 | { |
836 | m->friend_connectionstatuschange = function; | 997 | m->friend_connectionstatuschange = function; |
837 | m->friend_connectionstatuschange_userdata = userdata; | 998 | m->friend_connectionstatuschange_userdata = userdata; |
838 | } | 999 | } |
839 | 1000 | ||
840 | void m_callback_connectionstatus_internal_av(Messenger *m, void (*function)(Messenger *m, int32_t, uint8_t, void *), | 1001 | void m_callback_connectionstatus_internal_av(Messenger *m, void (*function)(Messenger *m, uint32_t, uint8_t, void *), |
841 | void *userdata) | 1002 | void *userdata) |
842 | { | 1003 | { |
843 | m->friend_connectionstatuschange_internal = function; | 1004 | m->friend_connectionstatuschange_internal = function; |
844 | m->friend_connectionstatuschange_internal_userdata = userdata; | 1005 | m->friend_connectionstatuschange_internal_userdata = userdata; |
845 | } | 1006 | } |
846 | 1007 | ||
1008 | void m_callback_avatar_info(Messenger *m, void (*function)(Messenger *m, uint32_t, uint8_t, uint8_t *, void *), | ||
1009 | void *userdata) | ||
1010 | { | ||
1011 | m->avatar_info_recv = function; | ||
1012 | m->avatar_info_recv_userdata = userdata; | ||
1013 | } | ||
1014 | |||
1015 | void m_callback_avatar_data(Messenger *m, void (*function)(Messenger *m, uint32_t, uint8_t, uint8_t *, uint8_t *, | ||
1016 | uint32_t, void *), void *userdata) | ||
1017 | { | ||
1018 | m->avatar_data_recv = function; | ||
1019 | m->avatar_data_recv_userdata = userdata; | ||
1020 | } | ||
1021 | |||
1022 | static void check_friend_tcp_udp(Messenger *m, int32_t friendnumber) | ||
1023 | { | ||
1024 | int last_connection_udp_tcp = m->friendlist[friendnumber].last_connection_udp_tcp; | ||
1025 | |||
1026 | int ret = m_get_friend_connectionstatus(m, friendnumber); | ||
1027 | |||
1028 | if (ret == -1) | ||
1029 | return; | ||
1030 | |||
1031 | if (last_connection_udp_tcp != ret) { | ||
1032 | if (m->friend_connectionstatuschange) | ||
1033 | m->friend_connectionstatuschange(m, friendnumber, ret, m->friend_connectionstatuschange_userdata); | ||
1034 | } | ||
1035 | |||
1036 | m->friendlist[friendnumber].last_connection_udp_tcp = ret; | ||
1037 | } | ||
1038 | |||
847 | static void break_files(const Messenger *m, int32_t friendnumber); | 1039 | static void break_files(const Messenger *m, int32_t friendnumber); |
848 | static void check_friend_connectionstatus(Messenger *m, int32_t friendnumber, uint8_t status) | 1040 | static void check_friend_connectionstatus(Messenger *m, int32_t friendnumber, uint8_t status) |
849 | { | 1041 | { |
@@ -853,8 +1045,6 @@ static void check_friend_connectionstatus(Messenger *m, int32_t friendnumber, ui | |||
853 | const uint8_t was_online = m->friendlist[friendnumber].status == FRIEND_ONLINE; | 1045 | const uint8_t was_online = m->friendlist[friendnumber].status == FRIEND_ONLINE; |
854 | const uint8_t is_online = status == FRIEND_ONLINE; | 1046 | const uint8_t is_online = status == FRIEND_ONLINE; |
855 | 1047 | ||
856 | onion_set_friend_online(m->onion_c, m->friendlist[friendnumber].onion_friendnum, is_online); | ||
857 | |||
858 | if (is_online != was_online) { | 1048 | if (is_online != was_online) { |
859 | if (was_online) { | 1049 | if (was_online) { |
860 | break_files(m, friendnumber); | 1050 | break_files(m, friendnumber); |
@@ -866,8 +1056,7 @@ static void check_friend_connectionstatus(Messenger *m, int32_t friendnumber, ui | |||
866 | 1056 | ||
867 | m->friendlist[friendnumber].status = status; | 1057 | m->friendlist[friendnumber].status = status; |
868 | 1058 | ||
869 | if (m->friend_connectionstatuschange) | 1059 | check_friend_tcp_udp(m, friendnumber); |
870 | m->friend_connectionstatuschange(m, friendnumber, is_online, m->friend_connectionstatuschange_userdata); | ||
871 | 1060 | ||
872 | if (m->friend_connectionstatuschange_internal) | 1061 | if (m->friend_connectionstatuschange_internal) |
873 | m->friend_connectionstatuschange_internal(m, friendnumber, is_online, | 1062 | m->friend_connectionstatuschange_internal(m, friendnumber, is_online, |
@@ -882,7 +1071,7 @@ void set_friend_status(Messenger *m, int32_t friendnumber, uint8_t status) | |||
882 | } | 1071 | } |
883 | 1072 | ||
884 | static int write_cryptpacket_id(const Messenger *m, int32_t friendnumber, uint8_t packet_id, const uint8_t *data, | 1073 | static int write_cryptpacket_id(const Messenger *m, int32_t friendnumber, uint8_t packet_id, const uint8_t *data, |
885 | uint32_t length) | 1074 | uint32_t length, uint8_t congestion_control) |
886 | { | 1075 | { |
887 | if (friend_not_valid(m, friendnumber)) | 1076 | if (friend_not_valid(m, friendnumber)) |
888 | return 0; | 1077 | return 0; |
@@ -896,463 +1085,31 @@ static int write_cryptpacket_id(const Messenger *m, int32_t friendnumber, uint8_ | |||
896 | if (length != 0) | 1085 | if (length != 0) |
897 | memcpy(packet + 1, data, length); | 1086 | memcpy(packet + 1, data, length); |
898 | 1087 | ||
899 | return write_cryptpacket(m->net_crypto, m->friendlist[friendnumber].crypt_connection_id, packet, length + 1) != -1; | 1088 | return write_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c, |
1089 | m->friendlist[friendnumber].friendcon_id), packet, length + 1, congestion_control) != -1; | ||
900 | } | 1090 | } |
901 | 1091 | ||
902 | /**********GROUP CHATS************/ | 1092 | /**********GROUP CHATS************/ |
903 | 1093 | ||
904 | /* return 1 if the groupnumber is not valid. | ||
905 | * return 0 if the groupnumber is valid. | ||
906 | */ | ||
907 | static uint8_t groupnumber_not_valid(const Messenger *m, int groupnumber) | ||
908 | { | ||
909 | if ((unsigned int)groupnumber >= m->numchats) | ||
910 | return 1; | ||
911 | |||
912 | if (m->chats == NULL) | ||
913 | return 1; | ||
914 | |||
915 | if (m->chats[groupnumber] == NULL) | ||
916 | return 1; | ||
917 | |||
918 | return 0; | ||
919 | } | ||
920 | |||
921 | |||
922 | /* returns valid ip port of connected friend on success | ||
923 | * returns zeroed out IP_Port on failure | ||
924 | */ | ||
925 | static IP_Port get_friend_ipport(const Messenger *m, int32_t friendnumber) | ||
926 | { | ||
927 | IP_Port zero; | ||
928 | memset(&zero, 0, sizeof(zero)); | ||
929 | |||
930 | if (friend_not_valid(m, friendnumber)) | ||
931 | return zero; | ||
932 | |||
933 | int crypt_id = m->friendlist[friendnumber].crypt_connection_id; | ||
934 | |||
935 | uint8_t direct_connected; | ||
936 | |||
937 | if (crypto_connection_status(m->net_crypto, crypt_id, &direct_connected) != CRYPTO_CONN_ESTABLISHED) | ||
938 | return zero; | ||
939 | |||
940 | if (direct_connected == 0) | ||
941 | return zero; | ||
942 | |||
943 | return m->net_crypto->crypto_connections[crypt_id].ip_port; | ||
944 | } | ||
945 | |||
946 | /* returns the group number of the chat with public key group_public_key. | ||
947 | * returns -1 on failure. | ||
948 | */ | ||
949 | static int group_num(const Messenger *m, const uint8_t *group_public_key) | ||
950 | { | ||
951 | uint32_t i; | ||
952 | |||
953 | for (i = 0; i < m->numchats; ++i) { | ||
954 | if (m->chats[i] != NULL) | ||
955 | if (id_equal(m->chats[i]->self_public_key, group_public_key)) | ||
956 | return i; | ||
957 | } | ||
958 | |||
959 | return -1; | ||
960 | } | ||
961 | 1094 | ||
962 | /* Set the callback for group invites. | 1095 | /* Set the callback for group invites. |
963 | * | 1096 | * |
964 | * Function(Messenger *m, int32_t friendnumber, uint8_t *group_public_key, void *userdata) | 1097 | * Function(Messenger *m, uint32_t friendnumber, uint8_t *data, uint16_t length) |
965 | */ | 1098 | */ |
966 | void m_callback_group_invite(Messenger *m, void (*function)(Messenger *m, int32_t, const uint8_t *, void *), | 1099 | void m_callback_group_invite(Messenger *m, void (*function)(Messenger *m, uint32_t, const uint8_t *, uint16_t)) |
967 | void *userdata) | ||
968 | { | 1100 | { |
969 | m->group_invite = function; | 1101 | m->group_invite = function; |
970 | m->group_invite_userdata = userdata; | ||
971 | } | ||
972 | |||
973 | /* Set the callback for group messages. | ||
974 | * | ||
975 | * Function(Tox *tox, int groupnumber, int friendgroupnumber, uint8_t * message, uint16_t length, void *userdata) | ||
976 | */ | ||
977 | void m_callback_group_message(Messenger *m, void (*function)(Messenger *m, int, int, const uint8_t *, uint16_t, void *), | ||
978 | void *userdata) | ||
979 | { | ||
980 | m->group_message = function; | ||
981 | m->group_message_userdata = userdata; | ||
982 | } | ||
983 | |||
984 | /* Set the callback for group actions. | ||
985 | * | ||
986 | * Function(Tox *tox, int groupnumber, int friendgroupnumber, uint8_t * message, uint16_t length, void *userdata) | ||
987 | */ | ||
988 | void m_callback_group_action(Messenger *m, void (*function)(Messenger *m, int, int, const uint8_t *, uint16_t, void *), | ||
989 | void *userdata) | ||
990 | { | ||
991 | m->group_action = function; | ||
992 | m->group_action_userdata = userdata; | ||
993 | } | ||
994 | |||
995 | /* Set callback function for peer name list changes. | ||
996 | * | ||
997 | * It gets called every time the name list changes(new peer/name, deleted peer) | ||
998 | * Function(Tox *tox, int groupnumber, void *userdata) | ||
999 | */ | ||
1000 | void m_callback_group_namelistchange(Messenger *m, void (*function)(Messenger *m, int, int, uint8_t, void *), | ||
1001 | void *userdata) | ||
1002 | { | ||
1003 | m->group_namelistchange = function; | ||
1004 | m->group_namelistchange_userdata = userdata; | ||
1005 | } | ||
1006 | |||
1007 | static int get_chat_num(const Messenger *m, const Group_Chat *chat) | ||
1008 | { | ||
1009 | uint32_t i; | ||
1010 | |||
1011 | for (i = 0; i < m->numchats; ++i) { //TODO: remove this | ||
1012 | if (m->chats[i] == chat) | ||
1013 | return i; | ||
1014 | } | ||
1015 | |||
1016 | return -1; | ||
1017 | } | ||
1018 | |||
1019 | static void group_message_function(Group_Chat *chat, int peer_number, const uint8_t *message, uint16_t length, | ||
1020 | void *userdata) | ||
1021 | { | ||
1022 | Messenger *m = userdata; | ||
1023 | int i = get_chat_num(m, chat); | ||
1024 | |||
1025 | if (i == -1) | ||
1026 | return; | ||
1027 | |||
1028 | uint8_t message_terminated[length + 1]; | ||
1029 | memcpy(message_terminated, message, length); | ||
1030 | message_terminated[length] = 0; /* Force NULL terminator */ | ||
1031 | |||
1032 | if (m->group_message) | ||
1033 | (*m->group_message)(m, i, peer_number, message_terminated, length, m->group_message_userdata); | ||
1034 | } | ||
1035 | |||
1036 | static void group_action_function(Group_Chat *chat, int peer_number, const uint8_t *action, uint16_t length, | ||
1037 | void *userdata) | ||
1038 | { | ||
1039 | Messenger *m = userdata; | ||
1040 | int i = get_chat_num(m, chat); | ||
1041 | |||
1042 | if (i == -1) | ||
1043 | return; | ||
1044 | |||
1045 | uint8_t action_terminated[length + 1]; | ||
1046 | memcpy(action_terminated, action, length); | ||
1047 | action_terminated[length] = 0; /* Force NULL terminator */ | ||
1048 | |||
1049 | if (m->group_action) | ||
1050 | (*m->group_action)(m, i, peer_number, action_terminated, length, m->group_action_userdata); | ||
1051 | } | ||
1052 | |||
1053 | static void group_namelistchange_function(Group_Chat *chat, int peer, uint8_t change, void *userdata) | ||
1054 | { | ||
1055 | Messenger *m = userdata; | ||
1056 | int i = get_chat_num(m, chat); | ||
1057 | |||
1058 | if (i == -1) | ||
1059 | return; | ||
1060 | |||
1061 | if (m->group_namelistchange) | ||
1062 | (*m->group_namelistchange)(m, i, peer, change, m->group_namelistchange_userdata); | ||
1063 | } | ||
1064 | |||
1065 | |||
1066 | /* Creates a new groupchat and puts it in the chats array. | ||
1067 | * | ||
1068 | * return group number on success. | ||
1069 | * return -1 on failure. | ||
1070 | */ | ||
1071 | int add_groupchat(Messenger *m) | ||
1072 | { | ||
1073 | uint32_t i; | ||
1074 | |||
1075 | for (i = 0; i < m->numchats; ++i) { | ||
1076 | if (m->chats[i] == NULL) { | ||
1077 | Group_Chat *newchat = new_groupchat(m->net); | ||
1078 | |||
1079 | if (newchat == NULL) | ||
1080 | return -1; | ||
1081 | |||
1082 | callback_groupmessage(newchat, &group_message_function, m); | ||
1083 | callback_groupaction(newchat, &group_action_function, m); | ||
1084 | callback_namelistchange(newchat, &group_namelistchange_function, m); | ||
1085 | /* TODO: remove this (group nicks should not be tied to the global one) */ | ||
1086 | set_nick(newchat, m->name, m->name_length); | ||
1087 | m->chats[i] = newchat; | ||
1088 | return i; | ||
1089 | } | ||
1090 | } | ||
1091 | |||
1092 | Group_Chat **temp; | ||
1093 | temp = realloc(m->chats, sizeof(Group_Chat *) * (m->numchats + 1)); | ||
1094 | |||
1095 | if (temp == NULL) | ||
1096 | return -1; | ||
1097 | |||
1098 | m->chats = temp; | ||
1099 | temp[m->numchats] = new_groupchat(m->net); | ||
1100 | |||
1101 | if (temp[m->numchats] == NULL) | ||
1102 | return -1; | ||
1103 | |||
1104 | callback_groupmessage(temp[m->numchats], &group_message_function, m); | ||
1105 | callback_groupaction(temp[m->numchats], &group_action_function, m); | ||
1106 | callback_namelistchange(temp[m->numchats], &group_namelistchange_function, m); | ||
1107 | /* TODO: remove this (group nicks should not be tied to the global one) */ | ||
1108 | set_nick(temp[m->numchats], m->name, m->name_length); | ||
1109 | ++m->numchats; | ||
1110 | return (m->numchats - 1); | ||
1111 | } | ||
1112 | |||
1113 | /* Delete a groupchat from the chats array. | ||
1114 | * | ||
1115 | * return 0 on success. | ||
1116 | * return -1 if failure. | ||
1117 | */ | ||
1118 | int del_groupchat(Messenger *m, int groupnumber) | ||
1119 | { | ||
1120 | if ((unsigned int)groupnumber >= m->numchats) | ||
1121 | return -1; | ||
1122 | |||
1123 | if (m->chats == NULL) | ||
1124 | return -1; | ||
1125 | |||
1126 | if (m->chats[groupnumber] == NULL) | ||
1127 | return -1; | ||
1128 | |||
1129 | kill_groupchat(m->chats[groupnumber]); | ||
1130 | m->chats[groupnumber] = NULL; | ||
1131 | |||
1132 | uint32_t i; | ||
1133 | |||
1134 | for (i = m->numchats; i != 0; --i) { | ||
1135 | if (m->chats[i - 1] != NULL) | ||
1136 | break; | ||
1137 | } | ||
1138 | |||
1139 | m->numchats = i; | ||
1140 | |||
1141 | if (i == 0) { | ||
1142 | free(m->chats); | ||
1143 | m->chats = NULL; | ||
1144 | } else { | ||
1145 | Group_Chat **temp = realloc(m->chats, sizeof(Group_Chat *) * i); | ||
1146 | |||
1147 | if (temp != NULL) | ||
1148 | m->chats = temp; | ||
1149 | } | ||
1150 | |||
1151 | return 0; | ||
1152 | } | ||
1153 | |||
1154 | /* Copy the name of peernumber who is in groupnumber to name. | ||
1155 | * name must be at least MAX_NICK_BYTES long. | ||
1156 | * | ||
1157 | * return length of name if success | ||
1158 | * return -1 if failure | ||
1159 | */ | ||
1160 | int m_group_peername(const Messenger *m, int groupnumber, int peernumber, uint8_t *name) | ||
1161 | { | ||
1162 | if ((unsigned int)groupnumber >= m->numchats) | ||
1163 | return -1; | ||
1164 | |||
1165 | if (m->chats == NULL) | ||
1166 | return -1; | ||
1167 | |||
1168 | if (m->chats[groupnumber] == NULL) | ||
1169 | return -1; | ||
1170 | |||
1171 | return group_peername(m->chats[groupnumber], peernumber, name); | ||
1172 | } | ||
1173 | |||
1174 | /* Store the fact that we invited a specific friend. | ||
1175 | */ | ||
1176 | static void group_store_friendinvite(Messenger *m, int32_t friendnumber, int groupnumber) | ||
1177 | { | ||
1178 | /* Add 1 to the groupchat number because 0 (default value in invited_groups) is a valid groupchat number */ | ||
1179 | m->friendlist[friendnumber].invited_groups[m->friendlist[friendnumber].invited_groups_num % MAX_INVITED_GROUPS] = | ||
1180 | groupnumber + 1; | ||
1181 | ++m->friendlist[friendnumber].invited_groups_num; | ||
1182 | } | ||
1183 | |||
1184 | /* return 1 if that friend was invited to the group | ||
1185 | * return 0 if the friend was not or error. | ||
1186 | */ | ||
1187 | static uint8_t group_invited(const Messenger *m, int32_t friendnumber, int groupnumber) | ||
1188 | { | ||
1189 | |||
1190 | uint32_t i; | ||
1191 | uint16_t num = MAX_INVITED_GROUPS; | ||
1192 | |||
1193 | if (MAX_INVITED_GROUPS > m->friendlist[friendnumber].invited_groups_num) | ||
1194 | num = m->friendlist[friendnumber].invited_groups_num; | ||
1195 | |||
1196 | for (i = 0; i < num; ++i) { | ||
1197 | if (m->friendlist[friendnumber].invited_groups[i] == groupnumber + 1) { | ||
1198 | return 1; | ||
1199 | } | ||
1200 | } | ||
1201 | |||
1202 | return 0; | ||
1203 | } | ||
1204 | |||
1205 | /* invite friendnumber to groupnumber | ||
1206 | * return 0 on success | ||
1207 | * return -1 on failure | ||
1208 | */ | ||
1209 | int invite_friend(Messenger *m, int32_t friendnumber, int groupnumber) | ||
1210 | { | ||
1211 | if (friend_not_valid(m, friendnumber) || (unsigned int)groupnumber >= m->numchats) | ||
1212 | return -1; | ||
1213 | |||
1214 | if (m->chats == NULL) | ||
1215 | return -1; | ||
1216 | |||
1217 | if (m->friendlist[friendnumber].status == NOFRIEND || m->chats[groupnumber] == NULL) | ||
1218 | return -1; | ||
1219 | |||
1220 | group_store_friendinvite(m, friendnumber, groupnumber); | ||
1221 | |||
1222 | if (write_cryptpacket_id(m, friendnumber, PACKET_ID_INVITE_GROUPCHAT, m->chats[groupnumber]->self_public_key, | ||
1223 | crypto_box_PUBLICKEYBYTES) == 0) | ||
1224 | return -1; | ||
1225 | |||
1226 | return 0; | ||
1227 | } | 1102 | } |
1228 | 1103 | ||
1229 | 1104 | ||
1230 | /* Join a group (you need to have been invited first.) | 1105 | /* Send a group invite packet. |
1231 | * | 1106 | * |
1232 | * returns group number on success | 1107 | * return 1 on success |
1233 | * returns -1 on failure. | 1108 | * return 0 on failure |
1234 | */ | ||
1235 | int join_groupchat(Messenger *m, int32_t friendnumber, const uint8_t *friend_group_public_key) | ||
1236 | { | ||
1237 | if (friend_not_valid(m, friendnumber)) | ||
1238 | return -1; | ||
1239 | |||
1240 | uint8_t data[crypto_box_PUBLICKEYBYTES * 2]; | ||
1241 | int groupnum = add_groupchat(m); | ||
1242 | |||
1243 | if (groupnum == -1) | ||
1244 | return -1; | ||
1245 | |||
1246 | IP_Port friend_ip = get_friend_ipport(m, friendnumber); | ||
1247 | |||
1248 | if (friend_ip.ip.family == 0) { | ||
1249 | del_groupchat(m, groupnum); | ||
1250 | return -1; | ||
1251 | } | ||
1252 | |||
1253 | id_copy(data, friend_group_public_key); | ||
1254 | id_copy(data + crypto_box_PUBLICKEYBYTES, m->chats[groupnum]->self_public_key); | ||
1255 | |||
1256 | if (write_cryptpacket_id(m, friendnumber, PACKET_ID_JOIN_GROUPCHAT, data, sizeof(data))) { | ||
1257 | chat_bootstrap_nonlazy(m->chats[groupnum], get_friend_ipport(m, friendnumber), | ||
1258 | friend_group_public_key); //TODO: check if ip returned is zero? | ||
1259 | return groupnum; | ||
1260 | } | ||
1261 | |||
1262 | del_groupchat(m, groupnum); | ||
1263 | return -1; | ||
1264 | } | ||
1265 | |||
1266 | |||
1267 | /* send a group message | ||
1268 | * return 0 on success | ||
1269 | * return -1 on failure | ||
1270 | */ | ||
1271 | int group_message_send(const Messenger *m, int groupnumber, const uint8_t *message, uint32_t length) | ||
1272 | { | ||
1273 | if (groupnumber_not_valid(m, groupnumber)) | ||
1274 | return -1; | ||
1275 | |||
1276 | if (group_sendmessage(m->chats[groupnumber], message, length) > 0) | ||
1277 | return 0; | ||
1278 | |||
1279 | return -1; | ||
1280 | } | ||
1281 | |||
1282 | /* send a group action | ||
1283 | * return 0 on success | ||
1284 | * return -1 on failure | ||
1285 | */ | ||
1286 | int group_action_send(const Messenger *m, int groupnumber, const uint8_t *action, uint32_t length) | ||
1287 | { | ||
1288 | if (groupnumber_not_valid(m, groupnumber)) | ||
1289 | return -1; | ||
1290 | |||
1291 | if (group_sendaction(m->chats[groupnumber], action, length) > 0) | ||
1292 | return 0; | ||
1293 | |||
1294 | return -1; | ||
1295 | } | ||
1296 | |||
1297 | /* Return the number of peers in the group chat on success. | ||
1298 | * return -1 on failure | ||
1299 | */ | ||
1300 | int group_number_peers(const Messenger *m, int groupnumber) | ||
1301 | { | ||
1302 | if (groupnumber_not_valid(m, groupnumber)) | ||
1303 | return -1; | ||
1304 | |||
1305 | return group_numpeers(m->chats[groupnumber]); | ||
1306 | } | ||
1307 | |||
1308 | /* List all the peers in the group chat. | ||
1309 | * | ||
1310 | * Copies the names of the peers to the name[length][MAX_NICK_BYTES] array. | ||
1311 | * | ||
1312 | * Copies the lengths of the names to lengths[length] | ||
1313 | * | ||
1314 | * returns the number of peers on success. | ||
1315 | * | ||
1316 | * return -1 on failure. | ||
1317 | */ | 1109 | */ |
1318 | int group_names(const Messenger *m, int groupnumber, uint8_t names[][MAX_NICK_BYTES], uint16_t lengths[], | 1110 | int send_group_invite_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint16_t length) |
1319 | uint16_t length) | ||
1320 | { | 1111 | { |
1321 | if (groupnumber_not_valid(m, groupnumber)) | 1112 | return write_cryptpacket_id(m, friendnumber, PACKET_ID_INVITE_GROUPCHAT, data, length, 0); |
1322 | return -1; | ||
1323 | |||
1324 | return group_client_names(m->chats[groupnumber], names, lengths, length); | ||
1325 | } | ||
1326 | |||
1327 | static int handle_group(void *object, IP_Port source, const uint8_t *packet, uint32_t length) | ||
1328 | { | ||
1329 | Messenger *m = object; | ||
1330 | |||
1331 | if (length < crypto_box_PUBLICKEYBYTES + 1) { | ||
1332 | return 1; | ||
1333 | } | ||
1334 | |||
1335 | uint32_t i; | ||
1336 | |||
1337 | for (i = 0; i < m->numchats; ++i) { | ||
1338 | if (m->chats[i] == NULL) | ||
1339 | continue; | ||
1340 | |||
1341 | if (id_equal(packet + 1, m->chats[i]->self_public_key)) | ||
1342 | return handle_groupchatpacket(m->chats[i], source, packet, length); | ||
1343 | } | ||
1344 | |||
1345 | return 1; | ||
1346 | } | ||
1347 | |||
1348 | static void do_allgroupchats(Messenger *m) | ||
1349 | { | ||
1350 | uint32_t i; | ||
1351 | |||
1352 | for (i = 0; i < m->numchats; ++i) { | ||
1353 | if (m->chats[i] != NULL) | ||
1354 | do_groupchat(m->chats[i]); | ||
1355 | } | ||
1356 | } | 1113 | } |
1357 | 1114 | ||
1358 | /****************FILE SENDING*****************/ | 1115 | /****************FILE SENDING*****************/ |
@@ -1360,9 +1117,10 @@ static void do_allgroupchats(Messenger *m) | |||
1360 | 1117 | ||
1361 | /* Set the callback for file send requests. | 1118 | /* Set the callback for file send requests. |
1362 | * | 1119 | * |
1363 | * Function(Tox *tox, int32_t friendnumber, uint8_t filenumber, uint64_t filesize, uint8_t *filename, uint16_t filename_length, void *userdata) | 1120 | * Function(Tox *tox, uint32_t friendnumber, uint8_t filenumber, uint64_t filesize, uint8_t *filename, uint16_t filename_length, void *userdata) |
1364 | */ | 1121 | */ |
1365 | void callback_file_sendrequest(Messenger *m, void (*function)(Messenger *m, int32_t, uint8_t, uint64_t, const uint8_t *, | 1122 | void callback_file_sendrequest(Messenger *m, void (*function)(Messenger *m, uint32_t, uint8_t, uint64_t, |
1123 | const uint8_t *, | ||
1366 | uint16_t, void *), void *userdata) | 1124 | uint16_t, void *), void *userdata) |
1367 | { | 1125 | { |
1368 | m->file_sendrequest = function; | 1126 | m->file_sendrequest = function; |
@@ -1371,10 +1129,10 @@ void callback_file_sendrequest(Messenger *m, void (*function)(Messenger *m, int3 | |||
1371 | 1129 | ||
1372 | /* Set the callback for file control requests. | 1130 | /* Set the callback for file control requests. |
1373 | * | 1131 | * |
1374 | * Function(Tox *tox, int32_t friendnumber, uint8_t send_receive, uint8_t filenumber, uint8_t control_type, uint8_t *data, uint16_t length, void *userdata) | 1132 | * Function(Tox *tox, uint32_t friendnumber, uint8_t send_receive, uint8_t filenumber, uint8_t control_type, uint8_t *data, uint16_t length, void *userdata) |
1375 | * | 1133 | * |
1376 | */ | 1134 | */ |
1377 | void callback_file_control(Messenger *m, void (*function)(Messenger *m, int32_t, uint8_t, uint8_t, uint8_t, | 1135 | void callback_file_control(Messenger *m, void (*function)(Messenger *m, uint32_t, uint8_t, uint8_t, uint8_t, |
1378 | const uint8_t *, uint16_t, void *), void *userdata) | 1136 | const uint8_t *, uint16_t, void *), void *userdata) |
1379 | { | 1137 | { |
1380 | m->file_filecontrol = function; | 1138 | m->file_filecontrol = function; |
@@ -1383,10 +1141,11 @@ void callback_file_control(Messenger *m, void (*function)(Messenger *m, int32_t, | |||
1383 | 1141 | ||
1384 | /* Set the callback for file data. | 1142 | /* Set the callback for file data. |
1385 | * | 1143 | * |
1386 | * Function(Tox *tox, int32_t friendnumber, uint8_t filenumber, uint8_t *data, uint16_t length, void *userdata) | 1144 | * Function(Tox *tox, uint32_t friendnumber, uint8_t filenumber, uint8_t *data, uint16_t length, void *userdata) |
1387 | * | 1145 | * |
1388 | */ | 1146 | */ |
1389 | void callback_file_data(Messenger *m, void (*function)(Messenger *m, int32_t, uint8_t, const uint8_t *, uint16_t length, | 1147 | void callback_file_data(Messenger *m, void (*function)(Messenger *m, uint32_t, uint8_t, const uint8_t *, |
1148 | uint16_t length, | ||
1390 | void *), void *userdata) | 1149 | void *), void *userdata) |
1391 | { | 1150 | { |
1392 | m->file_filedata = function; | 1151 | m->file_filedata = function; |
@@ -1415,7 +1174,7 @@ int file_sendrequest(const Messenger *m, int32_t friendnumber, uint8_t filenumbe | |||
1415 | memcpy(packet + 1, &filesize, sizeof(filesize)); | 1174 | memcpy(packet + 1, &filesize, sizeof(filesize)); |
1416 | memcpy(packet + 1 + sizeof(filesize), filename, filename_length); | 1175 | memcpy(packet + 1 + sizeof(filesize), filename, filename_length); |
1417 | return write_cryptpacket_id(m, friendnumber, PACKET_ID_FILE_SENDREQUEST, packet, | 1176 | return write_cryptpacket_id(m, friendnumber, PACKET_ID_FILE_SENDREQUEST, packet, |
1418 | 1 + sizeof(filesize) + filename_length); | 1177 | 1 + sizeof(filesize) + filename_length, 0); |
1419 | } | 1178 | } |
1420 | 1179 | ||
1421 | /* Send a file send request. | 1180 | /* Send a file send request. |
@@ -1493,7 +1252,7 @@ int file_control(const Messenger *m, int32_t friendnumber, uint8_t send_receive, | |||
1493 | memcpy(packet + 3, data, length); | 1252 | memcpy(packet + 3, data, length); |
1494 | } | 1253 | } |
1495 | 1254 | ||
1496 | if (write_cryptpacket_id(m, friendnumber, PACKET_ID_FILE_CONTROL, packet, length + 3)) { | 1255 | if (write_cryptpacket_id(m, friendnumber, PACKET_ID_FILE_CONTROL, packet, length + 3, 0)) { |
1497 | if (send_receive == 1) | 1256 | if (send_receive == 1) |
1498 | switch (message_id) { | 1257 | switch (message_id) { |
1499 | case FILECONTROL_ACCEPT: | 1258 | case FILECONTROL_ACCEPT: |
@@ -1555,15 +1314,16 @@ int file_data(const Messenger *m, int32_t friendnumber, uint8_t filenumber, cons | |||
1555 | if (m->friendlist[friendnumber].file_sending[filenumber].status != FILESTATUS_TRANSFERRING) | 1314 | if (m->friendlist[friendnumber].file_sending[filenumber].status != FILESTATUS_TRANSFERRING) |
1556 | return -1; | 1315 | return -1; |
1557 | 1316 | ||
1558 | /* Prevent file sending from filling up the entire buffer preventing messages from being sent. */ | 1317 | /* Prevent file sending from filling up the entire buffer preventing messages from being sent. TODO: remove */ |
1559 | if (crypto_num_free_sendqueue_slots(m->net_crypto, m->friendlist[friendnumber].crypt_connection_id) < MIN_SLOTS_FREE) | 1318 | if (crypto_num_free_sendqueue_slots(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c, |
1319 | m->friendlist[friendnumber].friendcon_id)) < MIN_SLOTS_FREE) | ||
1560 | return -1; | 1320 | return -1; |
1561 | 1321 | ||
1562 | uint8_t packet[MAX_CRYPTO_DATA_SIZE]; | 1322 | uint8_t packet[MAX_CRYPTO_DATA_SIZE]; |
1563 | packet[0] = filenumber; | 1323 | packet[0] = filenumber; |
1564 | memcpy(packet + 1, data, length); | 1324 | memcpy(packet + 1, data, length); |
1565 | 1325 | ||
1566 | if (write_cryptpacket_id(m, friendnumber, PACKET_ID_FILE_DATA, packet, length + 1)) { | 1326 | if (write_cryptpacket_id(m, friendnumber, PACKET_ID_FILE_DATA, packet, length + 1, 1)) { |
1567 | m->friendlist[friendnumber].file_sending[filenumber].transferred += length; | 1327 | m->friendlist[friendnumber].file_sending[filenumber].transferred += length; |
1568 | return 0; | 1328 | return 0; |
1569 | } | 1329 | } |
@@ -1706,7 +1466,7 @@ static int handle_filecontrol(const Messenger *m, int32_t friendnumber, uint8_t | |||
1706 | * | 1466 | * |
1707 | * Function(Messenger *m, int friendnumber, uint8_t *data, uint16_t length, void *userdata) | 1467 | * Function(Messenger *m, int friendnumber, uint8_t *data, uint16_t length, void *userdata) |
1708 | */ | 1468 | */ |
1709 | void m_callback_msi_packet(Messenger *m, void (*function)(Messenger *m, int32_t, const uint8_t *, uint16_t, void *), | 1469 | void m_callback_msi_packet(Messenger *m, void (*function)(Messenger *m, uint32_t, const uint8_t *, uint16_t, void *), |
1710 | void *userdata) | 1470 | void *userdata) |
1711 | { | 1471 | { |
1712 | m->msi_packet = function; | 1472 | m->msi_packet = function; |
@@ -1720,7 +1480,7 @@ void m_callback_msi_packet(Messenger *m, void (*function)(Messenger *m, int32_t, | |||
1720 | */ | 1480 | */ |
1721 | int m_msi_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint16_t length) | 1481 | int m_msi_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint16_t length) |
1722 | { | 1482 | { |
1723 | return write_cryptpacket_id(m, friendnumber, PACKET_ID_MSI, data, length); | 1483 | return write_cryptpacket_id(m, friendnumber, PACKET_ID_MSI, data, length, 0); |
1724 | } | 1484 | } |
1725 | 1485 | ||
1726 | static int handle_custom_lossy_packet(void *object, int friend_num, const uint8_t *packet, uint16_t length) | 1486 | static int handle_custom_lossy_packet(void *object, int friend_num, const uint8_t *packet, uint16_t length) |
@@ -1732,13 +1492,15 @@ static int handle_custom_lossy_packet(void *object, int friend_num, const uint8_ | |||
1732 | 1492 | ||
1733 | if (m->friendlist[friend_num].lossy_packethandlers[packet[0] % PACKET_ID_LOSSY_RANGE_SIZE].function) | 1493 | if (m->friendlist[friend_num].lossy_packethandlers[packet[0] % PACKET_ID_LOSSY_RANGE_SIZE].function) |
1734 | return m->friendlist[friend_num].lossy_packethandlers[packet[0] % PACKET_ID_LOSSY_RANGE_SIZE].function( | 1494 | return m->friendlist[friend_num].lossy_packethandlers[packet[0] % PACKET_ID_LOSSY_RANGE_SIZE].function( |
1735 | m->friendlist[friend_num].lossy_packethandlers[packet[0] % PACKET_ID_LOSSY_RANGE_SIZE].object, packet, length); | 1495 | m, friend_num, packet, length, m->friendlist[friend_num].lossy_packethandlers[packet[0] % |
1496 | PACKET_ID_LOSSY_RANGE_SIZE].object); | ||
1736 | 1497 | ||
1737 | return 1; | 1498 | return 1; |
1738 | } | 1499 | } |
1739 | 1500 | ||
1740 | int custom_lossy_packet_registerhandler(Messenger *m, int32_t friendnumber, uint8_t byte, | 1501 | int custom_lossy_packet_registerhandler(Messenger *m, int32_t friendnumber, uint8_t byte, |
1741 | int (*packet_handler_callback)(void *object, const uint8_t *data, uint32_t len), void *object) | 1502 | int (*packet_handler_callback)(Messenger *m, uint32_t friendnumber, const uint8_t *data, uint32_t len, void *object), |
1503 | void *object) | ||
1742 | { | 1504 | { |
1743 | if (friend_not_valid(m, friendnumber)) | 1505 | if (friend_not_valid(m, friendnumber)) |
1744 | return -1; | 1506 | return -1; |
@@ -1762,10 +1524,8 @@ int send_custom_lossy_packet(const Messenger *m, int32_t friendnumber, const uin | |||
1762 | if (m->friendlist[friendnumber].status != FRIEND_ONLINE) | 1524 | if (m->friendlist[friendnumber].status != FRIEND_ONLINE) |
1763 | return -1; | 1525 | return -1; |
1764 | 1526 | ||
1765 | if (m->friendlist[friendnumber].crypt_connection_id == -1) | 1527 | return send_lossy_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c, |
1766 | return -1; | 1528 | m->friendlist[friendnumber].friendcon_id), data, length); |
1767 | |||
1768 | return send_lossy_cryptpacket(m->net_crypto, m->friendlist[friendnumber].crypt_connection_id, data, length); | ||
1769 | } | 1529 | } |
1770 | 1530 | ||
1771 | static int handle_custom_lossless_packet(void *object, int friend_num, const uint8_t *packet, uint16_t length) | 1531 | static int handle_custom_lossless_packet(void *object, int friend_num, const uint8_t *packet, uint16_t length) |
@@ -1783,13 +1543,15 @@ static int handle_custom_lossless_packet(void *object, int friend_num, const uin | |||
1783 | 1543 | ||
1784 | if (m->friendlist[friend_num].lossless_packethandlers[packet[0] % PACKET_ID_LOSSLESS_RANGE_SIZE].function) | 1544 | if (m->friendlist[friend_num].lossless_packethandlers[packet[0] % PACKET_ID_LOSSLESS_RANGE_SIZE].function) |
1785 | return m->friendlist[friend_num].lossless_packethandlers[packet[0] % PACKET_ID_LOSSLESS_RANGE_SIZE].function( | 1545 | return m->friendlist[friend_num].lossless_packethandlers[packet[0] % PACKET_ID_LOSSLESS_RANGE_SIZE].function( |
1786 | m->friendlist[friend_num].lossless_packethandlers[packet[0] % PACKET_ID_LOSSLESS_RANGE_SIZE].object, packet, length); | 1546 | m, friend_num, packet, length, m->friendlist[friend_num].lossless_packethandlers[packet[0] % |
1547 | PACKET_ID_LOSSLESS_RANGE_SIZE].object); | ||
1787 | 1548 | ||
1788 | return 1; | 1549 | return 1; |
1789 | } | 1550 | } |
1790 | 1551 | ||
1791 | int custom_lossless_packet_registerhandler(Messenger *m, int32_t friendnumber, uint8_t byte, | 1552 | int custom_lossless_packet_registerhandler(Messenger *m, int32_t friendnumber, uint8_t byte, |
1792 | int (*packet_handler_callback)(void *object, const uint8_t *data, uint32_t len), void *object) | 1553 | int (*packet_handler_callback)(Messenger *m, uint32_t friendnumber, const uint8_t *data, uint32_t len, void *object), |
1554 | void *object) | ||
1793 | { | 1555 | { |
1794 | if (friend_not_valid(m, friendnumber)) | 1556 | if (friend_not_valid(m, friendnumber)) |
1795 | return -1; | 1557 | return -1; |
@@ -1811,21 +1573,32 @@ int send_custom_lossless_packet(const Messenger *m, int32_t friendnumber, const | |||
1811 | if (friend_not_valid(m, friendnumber)) | 1573 | if (friend_not_valid(m, friendnumber)) |
1812 | return -1; | 1574 | return -1; |
1813 | 1575 | ||
1814 | if (m->friendlist[friendnumber].status != FRIEND_ONLINE) | 1576 | if (length == 0) |
1577 | return -1; | ||
1578 | |||
1579 | if (data[0] < PACKET_ID_LOSSLESS_RANGE_START) | ||
1815 | return -1; | 1580 | return -1; |
1816 | 1581 | ||
1817 | if (m->friendlist[friendnumber].crypt_connection_id == -1) | 1582 | if (data[0] >= (PACKET_ID_LOSSLESS_RANGE_START + PACKET_ID_LOSSLESS_RANGE_SIZE)) |
1583 | return -1; | ||
1584 | |||
1585 | if (m->friendlist[friendnumber].status != FRIEND_ONLINE) | ||
1818 | return -1; | 1586 | return -1; |
1819 | 1587 | ||
1820 | return write_cryptpacket(m->net_crypto, m->friendlist[friendnumber].crypt_connection_id, data, length) != -1; | 1588 | if (write_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c, |
1589 | m->friendlist[friendnumber].friendcon_id), data, length, 1) == -1) { | ||
1590 | return -1; | ||
1591 | } else { | ||
1592 | return 0; | ||
1593 | } | ||
1821 | } | 1594 | } |
1822 | 1595 | ||
1823 | /* Function to filter out some friend requests*/ | 1596 | /* Function to filter out some friend requests*/ |
1824 | static int friend_already_added(const uint8_t *client_id, void *data) | 1597 | static int friend_already_added(const uint8_t *real_pk, void *data) |
1825 | { | 1598 | { |
1826 | const Messenger *m = data; | 1599 | const Messenger *m = data; |
1827 | 1600 | ||
1828 | if (getfriend_id(m, client_id) == -1) | 1601 | if (getfriend_id(m, real_pk) == -1) |
1829 | return 0; | 1602 | return 0; |
1830 | 1603 | ||
1831 | return -1; | 1604 | return -1; |
@@ -1840,31 +1613,6 @@ static void LANdiscovery(Messenger *m) | |||
1840 | } | 1613 | } |
1841 | } | 1614 | } |
1842 | 1615 | ||
1843 | static int handle_status(void *object, int i, uint8_t status); | ||
1844 | static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len); | ||
1845 | |||
1846 | static int handle_new_connections(void *object, New_Connection *n_c) | ||
1847 | { | ||
1848 | Messenger *m = object; | ||
1849 | int friend_id = getfriend_id(m, n_c->public_key); | ||
1850 | |||
1851 | if (friend_id != -1) { | ||
1852 | if (m->friendlist[friend_id].crypt_connection_id != -1) | ||
1853 | return -1; | ||
1854 | |||
1855 | int id = accept_crypto_connection(m->net_crypto, n_c); | ||
1856 | connection_status_handler(m->net_crypto, id, &handle_status, m, friend_id); | ||
1857 | connection_data_handler(m->net_crypto, id, &handle_packet, m, friend_id); | ||
1858 | connection_lossy_data_handler(m->net_crypto, id, &handle_custom_lossy_packet, m, friend_id); | ||
1859 | m->friendlist[friend_id].crypt_connection_id = id; | ||
1860 | set_friend_status(m, friend_id, FRIEND_CONFIRMED); | ||
1861 | return 0; | ||
1862 | } | ||
1863 | |||
1864 | return -1; | ||
1865 | } | ||
1866 | |||
1867 | |||
1868 | /* Run this at startup. */ | 1616 | /* Run this at startup. */ |
1869 | Messenger *new_messenger(Messenger_Options *options) | 1617 | Messenger *new_messenger(Messenger_Options *options) |
1870 | { | 1618 | { |
@@ -1882,6 +1630,9 @@ Messenger *new_messenger(Messenger_Options *options) | |||
1882 | m->net = new_networking(ip, TOX_PORT_DEFAULT); | 1630 | m->net = new_networking(ip, TOX_PORT_DEFAULT); |
1883 | } | 1631 | } |
1884 | 1632 | ||
1633 | m->avatar_format = AVATAR_FORMAT_NONE; | ||
1634 | m->avatar_data = NULL; | ||
1635 | |||
1885 | if (m->net == NULL) { | 1636 | if (m->net == NULL) { |
1886 | free(m); | 1637 | free(m); |
1887 | return NULL; | 1638 | return NULL; |
@@ -1895,11 +1646,7 @@ Messenger *new_messenger(Messenger_Options *options) | |||
1895 | return NULL; | 1646 | return NULL; |
1896 | } | 1647 | } |
1897 | 1648 | ||
1898 | if (options->proxy_enabled) { | 1649 | m->net_crypto = new_net_crypto(m->dht, &options->proxy_info); |
1899 | m->net_crypto = new_net_crypto(m->dht, &options->proxy_info); | ||
1900 | } else { | ||
1901 | m->net_crypto = new_net_crypto(m->dht, 0); | ||
1902 | } | ||
1903 | 1650 | ||
1904 | if (m->net_crypto == NULL) { | 1651 | if (m->net_crypto == NULL) { |
1905 | kill_networking(m->net); | 1652 | kill_networking(m->net); |
@@ -1908,13 +1655,13 @@ Messenger *new_messenger(Messenger_Options *options) | |||
1908 | return NULL; | 1655 | return NULL; |
1909 | } | 1656 | } |
1910 | 1657 | ||
1911 | new_connection_handler(m->net_crypto, &handle_new_connections, m); | ||
1912 | |||
1913 | m->onion = new_onion(m->dht); | 1658 | m->onion = new_onion(m->dht); |
1914 | m->onion_a = new_onion_announce(m->dht); | 1659 | m->onion_a = new_onion_announce(m->dht); |
1915 | m->onion_c = new_onion_client(m->net_crypto); | 1660 | m->onion_c = new_onion_client(m->net_crypto); |
1661 | m->fr_c = new_friend_connections(m->onion_c); | ||
1916 | 1662 | ||
1917 | if (!(m->onion && m->onion_a && m->onion_c)) { | 1663 | if (!(m->onion && m->onion_a && m->onion_c)) { |
1664 | kill_friend_connections(m->fr_c); | ||
1918 | kill_onion(m->onion); | 1665 | kill_onion(m->onion); |
1919 | kill_onion_announce(m->onion_a); | 1666 | kill_onion_announce(m->onion_a); |
1920 | kill_onion_client(m->onion_c); | 1667 | kill_onion_client(m->onion_c); |
@@ -1926,27 +1673,23 @@ Messenger *new_messenger(Messenger_Options *options) | |||
1926 | } | 1673 | } |
1927 | 1674 | ||
1928 | m->options = *options; | 1675 | m->options = *options; |
1929 | friendreq_init(&(m->fr), m->onion_c); | 1676 | friendreq_init(&(m->fr), m->fr_c); |
1930 | LANdiscovery_init(m->dht); | 1677 | LANdiscovery_init(m->dht); |
1931 | set_nospam(&(m->fr), random_int()); | 1678 | set_nospam(&(m->fr), random_int()); |
1932 | set_filter_function(&(m->fr), &friend_already_added, m); | 1679 | set_filter_function(&(m->fr), &friend_already_added, m); |
1933 | 1680 | ||
1934 | networking_registerhandler(m->net, NET_PACKET_GROUP_CHATS, &handle_group, m); | ||
1935 | |||
1936 | return m; | 1681 | return m; |
1937 | } | 1682 | } |
1938 | 1683 | ||
1939 | /* Run this before closing shop. */ | 1684 | /* Run this before closing shop. */ |
1940 | void kill_messenger(Messenger *m) | 1685 | void kill_messenger(Messenger *m) |
1941 | { | 1686 | { |
1942 | /* FIXME TODO: ideally cleanupMessenger will mirror initMessenger. | 1687 | if (!m) |
1943 | * This requires the other modules to expose cleanup functions. | 1688 | return; |
1944 | */ | ||
1945 | uint32_t i, numchats = m->numchats; | ||
1946 | 1689 | ||
1947 | for (i = 0; i < numchats; ++i) | 1690 | uint32_t i; |
1948 | del_groupchat(m, i); | ||
1949 | 1691 | ||
1692 | kill_friend_connections(m->fr_c); | ||
1950 | kill_onion(m->onion); | 1693 | kill_onion(m->onion); |
1951 | kill_onion_announce(m->onion_a); | 1694 | kill_onion_announce(m->onion_a); |
1952 | kill_onion_client(m->onion_c); | 1695 | kill_onion_client(m->onion_c); |
@@ -1955,10 +1698,11 @@ void kill_messenger(Messenger *m) | |||
1955 | kill_networking(m->net); | 1698 | kill_networking(m->net); |
1956 | 1699 | ||
1957 | for (i = 0; i < m->numfriends; ++i) { | 1700 | for (i = 0; i < m->numfriends; ++i) { |
1701 | free(m->friendlist[i].avatar_recv_data); | ||
1958 | clear_receipts(m, i); | 1702 | clear_receipts(m, i); |
1959 | free(m->friendlist[i].statusmessage); | ||
1960 | } | 1703 | } |
1961 | 1704 | ||
1705 | free(m->avatar_data); | ||
1962 | free(m->friendlist); | 1706 | free(m->friendlist); |
1963 | free(m); | 1707 | free(m); |
1964 | } | 1708 | } |
@@ -1974,7 +1718,7 @@ static void check_friend_request_timed_out(Messenger *m, uint32_t i, uint64_t t) | |||
1974 | 1718 | ||
1975 | if (f->friendrequest_lastsent + f->friendrequest_timeout < t) { | 1719 | if (f->friendrequest_lastsent + f->friendrequest_timeout < t) { |
1976 | set_friend_status(m, i, FRIEND_ADDED); | 1720 | set_friend_status(m, i, FRIEND_ADDED); |
1977 | /* Double the default timeout everytime if friendrequest is assumed | 1721 | /* Double the default timeout every time if friendrequest is assumed |
1978 | * to have been sent unsuccessfully. | 1722 | * to have been sent unsuccessfully. |
1979 | */ | 1723 | */ |
1980 | f->friendrequest_timeout *= 2; | 1724 | f->friendrequest_timeout *= 2; |
@@ -1987,44 +1731,332 @@ static int handle_status(void *object, int i, uint8_t status) | |||
1987 | Messenger *m = object; | 1731 | Messenger *m = object; |
1988 | 1732 | ||
1989 | if (status) { /* Went online. */ | 1733 | if (status) { /* Went online. */ |
1990 | set_friend_status(m, i, FRIEND_ONLINE); | 1734 | send_online_packet(m, i); |
1991 | m->friendlist[i].name_sent = 0; | 1735 | m->friendlist[i].name_sent = 0; |
1992 | m->friendlist[i].userstatus_sent = 0; | 1736 | m->friendlist[i].userstatus_sent = 0; |
1993 | m->friendlist[i].statusmessage_sent = 0; | 1737 | m->friendlist[i].statusmessage_sent = 0; |
1738 | m->friendlist[i].user_istyping_sent = 0; | ||
1739 | m->friendlist[i].avatar_info_sent = 0; | ||
1994 | m->friendlist[i].ping_lastrecv = temp_time; | 1740 | m->friendlist[i].ping_lastrecv = temp_time; |
1995 | } else { /* Went offline. */ | 1741 | } else { /* Went offline. */ |
1996 | m->friendlist[i].crypt_connection_id = -1; | ||
1997 | |||
1998 | if (m->friendlist[i].status == FRIEND_ONLINE) { | 1742 | if (m->friendlist[i].status == FRIEND_ONLINE) { |
1999 | set_friend_status(m, i, FRIEND_CONFIRMED); | 1743 | set_friend_status(m, i, FRIEND_CONFIRMED); |
2000 | } | 1744 | } |
1745 | |||
1746 | /* Clear avatar transfer state */ | ||
1747 | if (m->friendlist[i].avatar_recv_data) { | ||
1748 | free(m->friendlist[i].avatar_recv_data); | ||
1749 | m->friendlist[i].avatar_recv_data = NULL; | ||
1750 | } | ||
1751 | } | ||
1752 | |||
1753 | return 0; | ||
1754 | } | ||
1755 | |||
1756 | |||
1757 | /* Sends an avatar data control packet to the peer. Usually to return status | ||
1758 | * values or request data. | ||
1759 | */ | ||
1760 | static int send_avatar_data_control(const Messenger *m, const uint32_t friendnumber, | ||
1761 | uint8_t op) | ||
1762 | { | ||
1763 | int ret = write_cryptpacket_id(m, friendnumber, PACKET_ID_AVATAR_DATA_CONTROL, | ||
1764 | &op, sizeof(op), 0); | ||
1765 | LOGGER_DEBUG("friendnumber = %u, op = %u, ret = %d", | ||
1766 | friendnumber, op, ret); | ||
1767 | return ret ? 0 : -1; | ||
1768 | } | ||
1769 | |||
1770 | |||
1771 | static int handle_avatar_data_control(Messenger *m, uint32_t friendnumber, | ||
1772 | uint8_t *data, uint32_t data_length) | ||
1773 | { | ||
1774 | if (data_length != 1) { | ||
1775 | LOGGER_DEBUG("Error: PACKET_ID_AVATAR_DATA_CONTROL with bad " | ||
1776 | "data_length = %u, friendnumber = %u", | ||
1777 | data_length, friendnumber); | ||
1778 | send_avatar_data_control(m, friendnumber, AVATAR_DATACONTROL_ERROR); | ||
1779 | return -1; /* Error */ | ||
1780 | } | ||
1781 | |||
1782 | LOGGER_DEBUG("friendnumber = %u, op = %u", friendnumber, data[0]); | ||
1783 | |||
1784 | switch (data[0]) { | ||
1785 | case AVATAR_DATACONTROL_REQ: { | ||
1786 | |||
1787 | /* Check data transfer limits for this friend */ | ||
1788 | AVATAR_SENDDATA *const avsd = &(m->friendlist[friendnumber].avatar_send_data); | ||
1789 | |||
1790 | if (avsd->bytes_sent >= AVATAR_DATA_TRANSFER_LIMIT) { | ||
1791 | /* User reached data limit. Check timeout */ | ||
1792 | uint64_t now = unix_time(); | ||
1793 | |||
1794 | if (avsd->last_reset > 0 | ||
1795 | && (avsd->last_reset + AVATAR_DATA_TRANSFER_TIMEOUT < now)) { | ||
1796 | avsd->bytes_sent = 0; | ||
1797 | avsd->last_reset = now; | ||
1798 | } else { | ||
1799 | /* Friend still rate-limitted. Send an error and stops. */ | ||
1800 | LOGGER_DEBUG("Avatar data transfer limit reached. " | ||
1801 | "friendnumber = %u", friendnumber); | ||
1802 | send_avatar_data_control(m, friendnumber, AVATAR_DATACONTROL_ERROR); | ||
1803 | return 0; | ||
1804 | } | ||
1805 | } | ||
1806 | |||
1807 | /* Start the transmission with a DATA_START message. Format: | ||
1808 | * uint8_t format | ||
1809 | * uint8_t hash[AVATAR_HASH_LENGTH] | ||
1810 | * uint32_t total_length | ||
1811 | */ | ||
1812 | LOGGER_DEBUG("Sending start msg to friend number %u. " | ||
1813 | "m->avatar_format = %u, m->avatar_data_length = %u", | ||
1814 | friendnumber, m->avatar_format, m->avatar_data_length); | ||
1815 | uint8_t start_data[1 + AVATAR_HASH_LENGTH + sizeof(uint32_t)]; | ||
1816 | uint32_t avatar_len = htonl(m->avatar_data_length); | ||
1817 | |||
1818 | start_data[0] = m->avatar_format; | ||
1819 | memcpy(start_data + 1, m->avatar_hash, AVATAR_HASH_LENGTH); | ||
1820 | memcpy(start_data + 1 + AVATAR_HASH_LENGTH, &avatar_len, sizeof(uint32_t)); | ||
1821 | |||
1822 | avsd->bytes_sent += sizeof(start_data); /* For rate limit */ | ||
1823 | |||
1824 | int ret = write_cryptpacket_id(m, friendnumber, PACKET_ID_AVATAR_DATA_START, | ||
1825 | start_data, sizeof(start_data), 0); | ||
1826 | |||
1827 | if (!ret) { | ||
1828 | /* Something went wrong, try to signal the error so the friend | ||
1829 | * can clear up the state. */ | ||
1830 | send_avatar_data_control(m, friendnumber, AVATAR_DATACONTROL_ERROR); | ||
1831 | return 0; | ||
1832 | } | ||
1833 | |||
1834 | /* User have no avatar data, nothing more to do. */ | ||
1835 | if (m->avatar_format == AVATAR_FORMAT_NONE) | ||
1836 | return 0; | ||
1837 | |||
1838 | /* Send the actual avatar data. */ | ||
1839 | uint32_t offset = 0; | ||
1840 | |||
1841 | while (offset < m->avatar_data_length) { | ||
1842 | uint32_t chunk_len = m->avatar_data_length - offset; | ||
1843 | |||
1844 | if (chunk_len > AVATAR_DATA_MAX_CHUNK_SIZE) | ||
1845 | chunk_len = AVATAR_DATA_MAX_CHUNK_SIZE; | ||
1846 | |||
1847 | uint8_t chunk[AVATAR_DATA_MAX_CHUNK_SIZE]; | ||
1848 | memcpy(chunk, m->avatar_data + offset, chunk_len); | ||
1849 | offset += chunk_len; | ||
1850 | avsd->bytes_sent += chunk_len; /* For rate limit */ | ||
1851 | |||
1852 | int ret = write_cryptpacket_id(m, friendnumber, | ||
1853 | PACKET_ID_AVATAR_DATA_PUSH, | ||
1854 | chunk, chunk_len, 0); | ||
1855 | |||
1856 | if (!ret) { | ||
1857 | LOGGER_DEBUG("write_cryptpacket_id failed. ret = %d, " | ||
1858 | "friendnumber = %u, offset = %u", | ||
1859 | ret, friendnumber, offset); | ||
1860 | send_avatar_data_control(m, friendnumber, AVATAR_DATACONTROL_ERROR); | ||
1861 | return -1; | ||
1862 | } | ||
1863 | } | ||
1864 | |||
1865 | return 0; | ||
1866 | } | ||
1867 | |||
1868 | case AVATAR_DATACONTROL_ERROR: { | ||
1869 | if (m->friendlist[friendnumber].avatar_recv_data) { | ||
1870 | /* We were receiving the data, sender detected an error | ||
1871 | (eg. changing avatar) and asked us to stop. */ | ||
1872 | free(m->friendlist[friendnumber].avatar_recv_data); | ||
1873 | m->friendlist[friendnumber].avatar_recv_data = NULL; | ||
1874 | } | ||
1875 | |||
1876 | return 0; | ||
1877 | } | ||
1878 | } | ||
1879 | |||
1880 | return -1; | ||
1881 | } | ||
1882 | |||
1883 | |||
1884 | static int handle_avatar_data_start(Messenger *m, uint32_t friendnumber, | ||
1885 | uint8_t *data, uint32_t data_length) | ||
1886 | { | ||
1887 | LOGGER_DEBUG("data_length = %u, friendnumber = %u", data_length, friendnumber); | ||
1888 | |||
1889 | if (data_length != 1 + AVATAR_HASH_LENGTH + sizeof(uint32_t)) { | ||
1890 | LOGGER_DEBUG("Invalid msg length = %u, friendnumber = %u", | ||
1891 | data_length, friendnumber); | ||
1892 | return -1; | ||
1893 | } | ||
1894 | |||
1895 | AVATAR_RECEIVEDATA *avrd = m->friendlist[friendnumber].avatar_recv_data; | ||
1896 | |||
1897 | if (avrd == NULL) { | ||
1898 | LOGGER_DEBUG("Received an unrequested DATA_START, friendnumber = %u", | ||
1899 | friendnumber); | ||
1900 | return -1; | ||
1901 | } | ||
1902 | |||
1903 | if (avrd->started) { | ||
1904 | /* Already receiving data from this friend. Must be an error | ||
1905 | * or an malicious request, because we zeroed the started bit | ||
1906 | * when we requested the data. */ | ||
1907 | LOGGER_DEBUG("Received an unrequested duplicated DATA_START, " | ||
1908 | "friendnumber = %u", friendnumber); | ||
1909 | return -1; | ||
1910 | } | ||
1911 | |||
1912 | /* Copy data from message to our control structure */ | ||
1913 | avrd->started = 1; | ||
1914 | avrd->format = data[0]; | ||
1915 | memcpy(avrd->hash, data + 1, AVATAR_HASH_LENGTH); | ||
1916 | uint32_t tmp_len; | ||
1917 | memcpy(&tmp_len, data + 1 + AVATAR_HASH_LENGTH, sizeof(uint32_t)); | ||
1918 | avrd->total_length = ntohl(tmp_len); | ||
1919 | avrd->bytes_received = 0; | ||
1920 | |||
1921 | LOGGER_DEBUG("friendnumber = %u, avrd->format = %u, " | ||
1922 | "avrd->total_length = %u, avrd->bytes_received = %u", | ||
1923 | friendnumber, avrd->format, avrd->total_length, | ||
1924 | avrd->bytes_received); | ||
1925 | |||
1926 | if (avrd->total_length > AVATAR_MAX_DATA_LENGTH) { | ||
1927 | /* Invalid data length. Stops. */ | ||
1928 | LOGGER_DEBUG("Error: total_length > MAX_AVATAR_DATA_LENGTH, " | ||
1929 | "friendnumber = %u", friendnumber); | ||
1930 | free(avrd); | ||
1931 | avrd = NULL; | ||
1932 | m->friendlist[friendnumber].avatar_recv_data = NULL; | ||
1933 | return 0; | ||
1934 | } | ||
1935 | |||
1936 | if (avrd->format == AVATAR_FORMAT_NONE || avrd->total_length == 0) { | ||
1937 | /* No real data to receive. Run callback function and finish. */ | ||
1938 | LOGGER_DEBUG("format == NONE, friendnumber = %u", friendnumber); | ||
1939 | |||
1940 | if (m->avatar_data_recv) { | ||
1941 | memset(avrd->hash, 0, AVATAR_HASH_LENGTH); | ||
1942 | (m->avatar_data_recv)(m, friendnumber, avrd->format, avrd->hash, | ||
1943 | NULL, 0, m->avatar_data_recv_userdata); | ||
1944 | } | ||
1945 | |||
1946 | free(avrd); | ||
1947 | avrd = NULL; | ||
1948 | m->friendlist[friendnumber].avatar_recv_data = NULL; | ||
1949 | return 0; | ||
1950 | } | ||
1951 | |||
1952 | /* Waits for more data to be received */ | ||
1953 | return 0; | ||
1954 | } | ||
1955 | |||
1956 | |||
1957 | static int handle_avatar_data_push(Messenger *m, uint32_t friendnumber, | ||
1958 | uint8_t *data, uint32_t data_length) | ||
1959 | { | ||
1960 | LOGGER_DEBUG("friendnumber = %u, data_length = %u", friendnumber, data_length); | ||
1961 | |||
1962 | AVATAR_RECEIVEDATA *avrd = m->friendlist[friendnumber].avatar_recv_data; | ||
1963 | |||
1964 | if (avrd == NULL) { | ||
1965 | /* No active transfer. It must be an error or a malicious request, | ||
1966 | * because we set the avatar_recv_data on the first DATA_START. */ | ||
1967 | LOGGER_DEBUG("Error: avrd == NULL, friendnumber = %u", friendnumber); | ||
1968 | return -1; /* Error */ | ||
1969 | } | ||
1970 | |||
1971 | if (avrd->started == 0) { | ||
1972 | /* Receiving data for a non-started request. Must be an error | ||
1973 | * or an malicious request. */ | ||
1974 | LOGGER_DEBUG("Received an data push for a yet non started data " | ||
1975 | "request. friendnumber = %u", friendnumber); | ||
1976 | return -1; /* Error */ | ||
1977 | } | ||
1978 | |||
1979 | uint32_t new_length = avrd->bytes_received + data_length; | ||
1980 | |||
1981 | if (new_length > avrd->total_length | ||
1982 | || new_length >= AVATAR_MAX_DATA_LENGTH) { | ||
1983 | /* Invalid data length due to error or malice. Stops. */ | ||
1984 | LOGGER_DEBUG("Invalid data length. friendnumber = %u, " | ||
1985 | "new_length = %u, avrd->total_length = %u", | ||
1986 | friendnumber, new_length, avrd->total_length); | ||
1987 | free(avrd); | ||
1988 | m->friendlist[friendnumber].avatar_recv_data = NULL; | ||
1989 | return 0; | ||
1990 | } | ||
1991 | |||
1992 | memcpy(avrd->data + avrd->bytes_received, data, data_length); | ||
1993 | avrd->bytes_received += data_length; | ||
1994 | |||
1995 | if (avrd->bytes_received == avrd->total_length) { | ||
1996 | LOGGER_DEBUG("All data received. friendnumber = %u", friendnumber); | ||
1997 | |||
1998 | /* All data was received. Check if the hashes match. It the | ||
1999 | * requester's responsability to do this. The sender may have done | ||
2000 | * anything with its avatar data between the DATA_START and now. | ||
2001 | */ | ||
2002 | uint8_t cur_hash[AVATAR_HASH_LENGTH]; | ||
2003 | m_avatar_hash(cur_hash, avrd->data, avrd->bytes_received); | ||
2004 | |||
2005 | if (memcmp(cur_hash, avrd->hash, AVATAR_HASH_LENGTH) == 0) { | ||
2006 | /* Avatar successfuly received! */ | ||
2007 | if (m->avatar_data_recv) { | ||
2008 | (m->avatar_data_recv)(m, friendnumber, avrd->format, cur_hash, | ||
2009 | avrd->data, avrd->bytes_received, m->avatar_data_recv_userdata); | ||
2010 | } | ||
2011 | } else { | ||
2012 | LOGGER_DEBUG("Avatar hash error. friendnumber = %u", friendnumber); | ||
2013 | } | ||
2014 | |||
2015 | free(avrd); | ||
2016 | m->friendlist[friendnumber].avatar_recv_data = NULL; | ||
2017 | return 0; | ||
2001 | } | 2018 | } |
2002 | 2019 | ||
2020 | /* Waits for more data to be received */ | ||
2003 | return 0; | 2021 | return 0; |
2004 | } | 2022 | } |
2005 | 2023 | ||
2024 | |||
2025 | |||
2006 | static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len) | 2026 | static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len) |
2007 | { | 2027 | { |
2008 | if (len == 0) | 2028 | if (len == 0) |
2009 | return -1; | 2029 | return -1; |
2010 | 2030 | ||
2011 | Messenger *m = object; | 2031 | Messenger *m = object; |
2012 | uint64_t temp_time = unix_time(); | ||
2013 | uint8_t packet_id = temp[0]; | 2032 | uint8_t packet_id = temp[0]; |
2014 | uint8_t *data = temp + 1; | 2033 | uint8_t *data = temp + 1; |
2015 | uint32_t data_length = len - 1; | 2034 | uint32_t data_length = len - 1; |
2016 | 2035 | ||
2017 | if (m->friendlist[i].status != FRIEND_ONLINE) | 2036 | if (m->friendlist[i].status != FRIEND_ONLINE) { |
2018 | return -1; | 2037 | if (packet_id == PACKET_ID_ONLINE && len == 1) { |
2038 | set_friend_status(m, i, FRIEND_ONLINE); | ||
2039 | send_online_packet(m, i); | ||
2040 | } else if (packet_id == PACKET_ID_NICKNAME || packet_id == PACKET_ID_STATUSMESSAGE | ||
2041 | || packet_id == PACKET_ID_USERSTATUS) { | ||
2042 | /* Some backward compatibility, TODO: remove. */ | ||
2043 | set_friend_status(m, i, FRIEND_ONLINE); | ||
2044 | send_online_packet(m, i); | ||
2045 | } else { | ||
2046 | return -1; | ||
2047 | } | ||
2048 | } | ||
2019 | 2049 | ||
2020 | switch (packet_id) { | 2050 | switch (packet_id) { |
2021 | case PACKET_ID_ALIVE: { | 2051 | case PACKET_ID_OFFLINE: { |
2022 | m->friendlist[i].ping_lastrecv = temp_time; | 2052 | if (data_length != 0) |
2023 | break; | 2053 | break; |
2054 | |||
2055 | set_friend_status(m, i, FRIEND_CONFIRMED); | ||
2024 | } | 2056 | } |
2025 | 2057 | ||
2026 | case PACKET_ID_NICKNAME: { | 2058 | case PACKET_ID_NICKNAME: { |
2027 | if (data_length > MAX_NAME_LENGTH || data_length == 0) | 2059 | if (data_length > MAX_NAME_LENGTH) |
2028 | break; | 2060 | break; |
2029 | 2061 | ||
2030 | /* Make sure the NULL terminator is present. */ | 2062 | /* Make sure the NULL terminator is present. */ |
@@ -2043,7 +2075,7 @@ static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len) | |||
2043 | } | 2075 | } |
2044 | 2076 | ||
2045 | case PACKET_ID_STATUSMESSAGE: { | 2077 | case PACKET_ID_STATUSMESSAGE: { |
2046 | if (data_length == 0 || data_length > MAX_STATUSMESSAGE_LENGTH) | 2078 | if (data_length > MAX_STATUSMESSAGE_LENGTH) |
2047 | break; | 2079 | break; |
2048 | 2080 | ||
2049 | /* Make sure the NULL terminator is present. */ | 2081 | /* Make sure the NULL terminator is present. */ |
@@ -2079,7 +2111,7 @@ static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len) | |||
2079 | if (data_length != 1) | 2111 | if (data_length != 1) |
2080 | break; | 2112 | break; |
2081 | 2113 | ||
2082 | uint8_t typing = data[0]; | 2114 | _Bool typing = !!data[0]; |
2083 | 2115 | ||
2084 | set_friend_typing(m, i, typing); | 2116 | set_friend_typing(m, i, typing); |
2085 | 2117 | ||
@@ -2090,6 +2122,8 @@ static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len) | |||
2090 | } | 2122 | } |
2091 | 2123 | ||
2092 | case PACKET_ID_MESSAGE: { | 2124 | case PACKET_ID_MESSAGE: { |
2125 | const uint8_t *message_id = data; | ||
2126 | |||
2093 | if (data_length == 0) | 2127 | if (data_length == 0) |
2094 | break; | 2128 | break; |
2095 | 2129 | ||
@@ -2108,6 +2142,8 @@ static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len) | |||
2108 | } | 2142 | } |
2109 | 2143 | ||
2110 | case PACKET_ID_ACTION: { | 2144 | case PACKET_ID_ACTION: { |
2145 | const uint8_t *message_id = data; | ||
2146 | |||
2111 | if (data_length == 0) | 2147 | if (data_length == 0) |
2112 | break; | 2148 | break; |
2113 | 2149 | ||
@@ -2126,31 +2162,49 @@ static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len) | |||
2126 | break; | 2162 | break; |
2127 | } | 2163 | } |
2128 | 2164 | ||
2129 | case PACKET_ID_INVITE_GROUPCHAT: { | 2165 | case PACKET_ID_AVATAR_INFO_REQ: { |
2130 | if (data_length != crypto_box_PUBLICKEYBYTES) | 2166 | /* Send our avatar information */ |
2131 | break; | 2167 | m_send_avatar_info(m, i); |
2168 | break; | ||
2169 | } | ||
2132 | 2170 | ||
2133 | if (m->group_invite) | 2171 | case PACKET_ID_AVATAR_INFO: { |
2134 | (*m->group_invite)(m, i, data, m->group_invite_userdata); | 2172 | if (m->avatar_info_recv) { |
2173 | /* | ||
2174 | * A malicious user may send an incomplete avatar info message. | ||
2175 | * Check if it have the correct size for the format: | ||
2176 | * [1 uint8_t: avatar format] [32 uint8_t: hash] | ||
2177 | */ | ||
2178 | if (data_length == AVATAR_HASH_LENGTH + 1) { | ||
2179 | (m->avatar_info_recv)(m, i, data[0], data + 1, m->avatar_info_recv_userdata); | ||
2180 | } | ||
2181 | } | ||
2135 | 2182 | ||
2136 | break; | 2183 | break; |
2137 | } | 2184 | } |
2138 | 2185 | ||
2139 | case PACKET_ID_JOIN_GROUPCHAT: { | 2186 | case PACKET_ID_AVATAR_DATA_CONTROL: { |
2140 | if (data_length != crypto_box_PUBLICKEYBYTES * 2) | 2187 | handle_avatar_data_control(m, i, data, data_length); |
2141 | break; | 2188 | break; |
2189 | } | ||
2142 | 2190 | ||
2143 | int groupnum = group_num(m, data); | 2191 | case PACKET_ID_AVATAR_DATA_START: { |
2192 | handle_avatar_data_start(m, i, data, data_length); | ||
2193 | break; | ||
2194 | } | ||
2144 | 2195 | ||
2145 | if (groupnum == -1) | 2196 | case PACKET_ID_AVATAR_DATA_PUSH: { |
2146 | break; | 2197 | handle_avatar_data_push(m, i, data, data_length); |
2198 | break; | ||
2199 | } | ||
2147 | 2200 | ||
2148 | if (!group_invited(m, i, groupnum)) | 2201 | case PACKET_ID_INVITE_GROUPCHAT: { |
2202 | if (data_length == 0) | ||
2149 | break; | 2203 | break; |
2150 | 2204 | ||
2151 | group_newpeer(m->chats[groupnum], data + crypto_box_PUBLICKEYBYTES); | 2205 | if (m->group_invite) |
2152 | /* This is just there to speedup joining. */ | 2206 | (*m->group_invite)(m, i, data, data_length); |
2153 | chat_bootstrap(m->chats[groupnum], get_friend_ipport(m, i), data + crypto_box_PUBLICKEYBYTES); | 2207 | |
2154 | break; | 2208 | break; |
2155 | } | 2209 | } |
2156 | 2210 | ||
@@ -2233,7 +2287,7 @@ static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len) | |||
2233 | int i; | 2287 | int i; |
2234 | 2288 | ||
2235 | for (i = 0; i < n; i++) { | 2289 | for (i = 0; i < n; i++) { |
2236 | add_tcp_relay(m->net_crypto, nodes[i].ip_port, nodes[i].client_id); | 2290 | add_tcp_relay(m->net_crypto, nodes[i].ip_port, nodes[i].public_key); |
2237 | } | 2291 | } |
2238 | 2292 | ||
2239 | break; | 2293 | break; |
@@ -2248,27 +2302,6 @@ static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len) | |||
2248 | return 0; | 2302 | return 0; |
2249 | } | 2303 | } |
2250 | 2304 | ||
2251 | static int friend_new_connection(Messenger *m, int32_t friendnumber, const uint8_t *real_public_key) | ||
2252 | { | ||
2253 | if (friend_not_valid(m, friendnumber)) | ||
2254 | return -1; | ||
2255 | |||
2256 | if (m->friendlist[friendnumber].crypt_connection_id != -1) { | ||
2257 | return -1; | ||
2258 | } | ||
2259 | |||
2260 | int id = new_crypto_connection(m->net_crypto, real_public_key); | ||
2261 | |||
2262 | if (id == -1) | ||
2263 | return -1; | ||
2264 | |||
2265 | m->friendlist[friendnumber].crypt_connection_id = id; | ||
2266 | connection_status_handler(m->net_crypto, id, &handle_status, m, friendnumber); | ||
2267 | connection_data_handler(m->net_crypto, id, &handle_packet, m, friendnumber); | ||
2268 | connection_lossy_data_handler(m->net_crypto, id, &handle_custom_lossy_packet, m, friendnumber); | ||
2269 | return 0; | ||
2270 | } | ||
2271 | |||
2272 | /* TODO: Make this function not suck. */ | 2305 | /* TODO: Make this function not suck. */ |
2273 | void do_friends(Messenger *m) | 2306 | void do_friends(Messenger *m) |
2274 | { | 2307 | { |
@@ -2277,9 +2310,9 @@ void do_friends(Messenger *m) | |||
2277 | 2310 | ||
2278 | for (i = 0; i < m->numfriends; ++i) { | 2311 | for (i = 0; i < m->numfriends; ++i) { |
2279 | if (m->friendlist[i].status == FRIEND_ADDED) { | 2312 | if (m->friendlist[i].status == FRIEND_ADDED) { |
2280 | int fr = send_friendrequest(m->onion_c, m->friendlist[i].client_id, m->friendlist[i].friendrequest_nospam, | 2313 | int fr = send_friend_request_packet(m->fr_c, m->friendlist[i].friendcon_id, m->friendlist[i].friendrequest_nospam, |
2281 | m->friendlist[i].info, | 2314 | m->friendlist[i].info, |
2282 | m->friendlist[i].info_size); | 2315 | m->friendlist[i].info_size); |
2283 | 2316 | ||
2284 | if (fr >= 0) { | 2317 | if (fr >= 0) { |
2285 | set_friend_status(m, i, FRIEND_REQUESTED); | 2318 | set_friend_status(m, i, FRIEND_REQUESTED); |
@@ -2295,32 +2328,6 @@ void do_friends(Messenger *m) | |||
2295 | */ | 2328 | */ |
2296 | check_friend_request_timed_out(m, i, temp_time); | 2329 | check_friend_request_timed_out(m, i, temp_time); |
2297 | } | 2330 | } |
2298 | |||
2299 | friend_new_connection(m, i, m->friendlist[i].client_id); | ||
2300 | } | ||
2301 | |||
2302 | if (m->friendlist[i].crypt_connection_id != -1) { | ||
2303 | uint8_t dht_public_key1[crypto_box_PUBLICKEYBYTES]; | ||
2304 | uint64_t timestamp1 = onion_getfriend_DHT_pubkey(m->onion_c, m->friendlist[i].onion_friendnum, dht_public_key1); | ||
2305 | uint8_t dht_public_key2[crypto_box_PUBLICKEYBYTES]; | ||
2306 | uint64_t timestamp2 = get_connection_dht_key(m->net_crypto, m->friendlist[i].crypt_connection_id, dht_public_key2); | ||
2307 | |||
2308 | if (timestamp1 > timestamp2) { | ||
2309 | set_connection_dht_public_key(m->net_crypto, m->friendlist[i].crypt_connection_id, dht_public_key1, timestamp1); | ||
2310 | } else if (timestamp1 < timestamp2) { | ||
2311 | onion_set_friend_DHT_pubkey(m->onion_c, m->friendlist[i].onion_friendnum, dht_public_key2, timestamp2); | ||
2312 | } | ||
2313 | |||
2314 | uint8_t direct_connected; | ||
2315 | unsigned int status = crypto_connection_status(m->net_crypto, m->friendlist[i].crypt_connection_id, &direct_connected); | ||
2316 | |||
2317 | if (direct_connected == 0 || status == CRYPTO_CONN_COOKIE_REQUESTING) { | ||
2318 | IP_Port friendip; | ||
2319 | |||
2320 | if (onion_getfriendip(m->onion_c, m->friendlist[i].onion_friendnum, &friendip) == 1) { | ||
2321 | set_direct_ip_port(m->net_crypto, m->friendlist[i].crypt_connection_id, friendip); | ||
2322 | } | ||
2323 | } | ||
2324 | } | 2331 | } |
2325 | 2332 | ||
2326 | if (m->friendlist[i].status == FRIEND_ONLINE) { /* friend is online. */ | 2333 | if (m->friendlist[i].status == FRIEND_ONLINE) { /* friend is online. */ |
@@ -2339,26 +2346,21 @@ void do_friends(Messenger *m) | |||
2339 | m->friendlist[i].userstatus_sent = 1; | 2346 | m->friendlist[i].userstatus_sent = 1; |
2340 | } | 2347 | } |
2341 | 2348 | ||
2349 | if (m->friendlist[i].avatar_info_sent == 0) { | ||
2350 | if (m_send_avatar_info(m, i) == 0) | ||
2351 | m->friendlist[i].avatar_info_sent = 1; | ||
2352 | } | ||
2353 | |||
2342 | if (m->friendlist[i].user_istyping_sent == 0) { | 2354 | if (m->friendlist[i].user_istyping_sent == 0) { |
2343 | if (send_user_istyping(m, i, m->friendlist[i].user_istyping)) | 2355 | if (send_user_istyping(m, i, m->friendlist[i].user_istyping)) |
2344 | m->friendlist[i].user_istyping_sent = 1; | 2356 | m->friendlist[i].user_istyping_sent = 1; |
2345 | } | 2357 | } |
2346 | 2358 | ||
2347 | if (m->friendlist[i].ping_lastsent + FRIEND_PING_INTERVAL < temp_time) { | ||
2348 | send_ping(m, i); | ||
2349 | } | ||
2350 | |||
2351 | if (m->friendlist[i].ping_lastrecv + FRIEND_CONNECTION_TIMEOUT < temp_time) { | ||
2352 | /* If we stopped receiving ping packets, kill it. */ | ||
2353 | crypto_kill(m->net_crypto, m->friendlist[i].crypt_connection_id); | ||
2354 | m->friendlist[i].crypt_connection_id = -1; | ||
2355 | set_friend_status(m, i, FRIEND_CONFIRMED); | ||
2356 | } | ||
2357 | |||
2358 | if (m->friendlist[i].share_relays_lastsent + FRIEND_SHARE_RELAYS_INTERVAL < temp_time) { | 2359 | if (m->friendlist[i].share_relays_lastsent + FRIEND_SHARE_RELAYS_INTERVAL < temp_time) { |
2359 | send_relays(m, i); | 2360 | send_relays(m, i); |
2360 | } | 2361 | } |
2361 | 2362 | ||
2363 | check_friend_tcp_udp(m, i); | ||
2362 | do_receipts(m, i); | 2364 | do_receipts(m, i); |
2363 | } | 2365 | } |
2364 | } | 2366 | } |
@@ -2370,15 +2372,15 @@ void do_friends(Messenger *m) | |||
2370 | #ifdef LOGGING | 2372 | #ifdef LOGGING |
2371 | #define DUMPING_CLIENTS_FRIENDS_EVERY_N_SECONDS 60UL | 2373 | #define DUMPING_CLIENTS_FRIENDS_EVERY_N_SECONDS 60UL |
2372 | static time_t lastdump = 0; | 2374 | static time_t lastdump = 0; |
2373 | static char IDString[CLIENT_ID_SIZE * 2 + 1]; | 2375 | static char IDString[crypto_box_PUBLICKEYBYTES * 2 + 1]; |
2374 | static char *ID2String(const uint8_t *client_id) | 2376 | static char *ID2String(const uint8_t *pk) |
2375 | { | 2377 | { |
2376 | uint32_t i; | 2378 | uint32_t i; |
2377 | 2379 | ||
2378 | for (i = 0; i < CLIENT_ID_SIZE; i++) | 2380 | for (i = 0; i < crypto_box_PUBLICKEYBYTES; i++) |
2379 | sprintf(&IDString[i * 2], "%02X", client_id[i]); | 2381 | sprintf(&IDString[i * 2], "%02X", pk[i]); |
2380 | 2382 | ||
2381 | IDString[CLIENT_ID_SIZE * 2] = 0; | 2383 | IDString[crypto_box_PUBLICKEYBYTES * 2] = 0; |
2382 | return IDString; | 2384 | return IDString; |
2383 | } | 2385 | } |
2384 | #endif | 2386 | #endif |
@@ -2392,7 +2394,7 @@ static char *ID2String(const uint8_t *client_id) | |||
2392 | * | 2394 | * |
2393 | * returns time (in ms) before the next do_messenger() needs to be run on success. | 2395 | * returns time (in ms) before the next do_messenger() needs to be run on success. |
2394 | */ | 2396 | */ |
2395 | uint32_t messenger_run_interval(Messenger *m) | 2397 | uint32_t messenger_run_interval(const Messenger *m) |
2396 | { | 2398 | { |
2397 | uint32_t crypto_interval = crypto_run_interval(m->net_crypto); | 2399 | uint32_t crypto_interval = crypto_run_interval(m->net_crypto); |
2398 | 2400 | ||
@@ -2406,6 +2408,17 @@ uint32_t messenger_run_interval(Messenger *m) | |||
2406 | /* The main loop that needs to be run at least 20 times per second. */ | 2408 | /* The main loop that needs to be run at least 20 times per second. */ |
2407 | void do_messenger(Messenger *m) | 2409 | void do_messenger(Messenger *m) |
2408 | { | 2410 | { |
2411 | // Add the TCP relays, but only if this is the first time calling do_messenger | ||
2412 | if (m->has_added_relays == 0) { | ||
2413 | m->has_added_relays = 1; | ||
2414 | |||
2415 | int i; | ||
2416 | |||
2417 | for (i = 0; i < NUM_SAVED_TCP_RELAYS; ++i) { | ||
2418 | add_tcp_relay(m->net_crypto, m->loaded_relays[i].ip_port, m->loaded_relays[i].public_key); | ||
2419 | } | ||
2420 | } | ||
2421 | |||
2409 | unix_time_update(); | 2422 | unix_time_update(); |
2410 | 2423 | ||
2411 | if (!m->options.udp_disabled) { | 2424 | if (!m->options.udp_disabled) { |
@@ -2415,8 +2428,8 @@ void do_messenger(Messenger *m) | |||
2415 | 2428 | ||
2416 | do_net_crypto(m->net_crypto); | 2429 | do_net_crypto(m->net_crypto); |
2417 | do_onion_client(m->onion_c); | 2430 | do_onion_client(m->onion_c); |
2431 | do_friend_connections(m->fr_c); | ||
2418 | do_friends(m); | 2432 | do_friends(m); |
2419 | do_allgroupchats(m); | ||
2420 | LANdiscovery(m); | 2433 | LANdiscovery(m); |
2421 | 2434 | ||
2422 | #ifdef LOGGING | 2435 | #ifdef LOGGING |
@@ -2427,16 +2440,6 @@ void do_messenger(Messenger *m) | |||
2427 | Assoc_status(m->dht->assoc); | 2440 | Assoc_status(m->dht->assoc); |
2428 | #endif | 2441 | #endif |
2429 | 2442 | ||
2430 | if (m->numchats > 0) { | ||
2431 | size_t c; | ||
2432 | |||
2433 | for (c = 0; c < m->numchats; c++) { | ||
2434 | if (m->chats[c]) | ||
2435 | Assoc_status(m->chats[c]->assoc); | ||
2436 | } | ||
2437 | } | ||
2438 | |||
2439 | |||
2440 | lastdump = unix_time(); | 2443 | lastdump = unix_time(); |
2441 | uint32_t client, last_pinged; | 2444 | uint32_t client, last_pinged; |
2442 | 2445 | ||
@@ -2452,9 +2455,9 @@ void do_messenger(Messenger *m) | |||
2452 | if (last_pinged > 999) | 2455 | if (last_pinged > 999) |
2453 | last_pinged = 999; | 2456 | last_pinged = 999; |
2454 | 2457 | ||
2455 | LOGGER_INFO("C[%2u] %s:%u [%3u] %s", | 2458 | LOGGER_TRACE("C[%2u] %s:%u [%3u] %s", |
2456 | client, ip_ntoa(&assoc->ip_port.ip), ntohs(assoc->ip_port.port), | 2459 | client, ip_ntoa(&assoc->ip_port.ip), ntohs(assoc->ip_port.port), |
2457 | last_pinged, ID2String(cptr->client_id)); | 2460 | last_pinged, ID2String(cptr->client_id)); |
2458 | } | 2461 | } |
2459 | } | 2462 | } |
2460 | 2463 | ||
@@ -2474,7 +2477,7 @@ void do_messenger(Messenger *m) | |||
2474 | continue; | 2477 | continue; |
2475 | 2478 | ||
2476 | for (dhtfriend = 0; dhtfriend < m->dht->num_friends; dhtfriend++) | 2479 | for (dhtfriend = 0; dhtfriend < m->dht->num_friends; dhtfriend++) |
2477 | if (id_equal(m->friendlist[friend].client_id, m->dht->friends_list[dhtfriend].client_id)) { | 2480 | if (id_equal(m->friendlist[friend].real_pk, m->dht->friends_list[dhtfriend].client_id)) { |
2478 | m2dht[friend] = dhtfriend; | 2481 | m2dht[friend] = dhtfriend; |
2479 | break; | 2482 | break; |
2480 | } | 2483 | } |
@@ -2485,7 +2488,7 @@ void do_messenger(Messenger *m) | |||
2485 | dht2m[m2dht[friend]] = friend; | 2488 | dht2m[m2dht[friend]] = friend; |
2486 | 2489 | ||
2487 | if (m->numfriends != m->dht->num_friends) { | 2490 | if (m->numfriends != m->dht->num_friends) { |
2488 | LOGGER_INFO("Friend num in DHT %u != friend num in msger %u\n", m->dht->num_friends, m->numfriends); | 2491 | LOGGER_TRACE("Friend num in DHT %u != friend num in msger %u\n", m->dht->num_friends, m->numfriends); |
2489 | } | 2492 | } |
2490 | 2493 | ||
2491 | uint32_t ping_lastrecv; | 2494 | uint32_t ping_lastrecv; |
@@ -2506,11 +2509,11 @@ void do_messenger(Messenger *m) | |||
2506 | if (ping_lastrecv > 999) | 2509 | if (ping_lastrecv > 999) |
2507 | ping_lastrecv = 999; | 2510 | ping_lastrecv = 999; |
2508 | 2511 | ||
2509 | LOGGER_INFO("F[%2u:%2u] <%s> %02i [%03u] %s", | 2512 | LOGGER_TRACE("F[%2u:%2u] <%s> [%03u] %s", |
2510 | dht2m[friend], friend, msgfptr->name, msgfptr->crypt_connection_id, | 2513 | dht2m[friend], friend, msgfptr->name, |
2511 | ping_lastrecv, ID2String(msgfptr->client_id)); | 2514 | ping_lastrecv, ID2String(msgfptr->real_pk)); |
2512 | } else { | 2515 | } else { |
2513 | LOGGER_INFO("F[--:%2u] %s", friend, ID2String(dhtfptr->client_id)); | 2516 | LOGGER_TRACE("F[--:%2u] %s", friend, ID2String(dhtfptr->client_id)); |
2514 | } | 2517 | } |
2515 | 2518 | ||
2516 | for (client = 0; client < MAX_FRIEND_CLIENTS; client++) { | 2519 | for (client = 0; client < MAX_FRIEND_CLIENTS; client++) { |
@@ -2525,10 +2528,10 @@ void do_messenger(Messenger *m) | |||
2525 | if (last_pinged > 999) | 2528 | if (last_pinged > 999) |
2526 | last_pinged = 999; | 2529 | last_pinged = 999; |
2527 | 2530 | ||
2528 | LOGGER_INFO("F[%2u] => C[%2u] %s:%u [%3u] %s", | 2531 | LOGGER_TRACE("F[%2u] => C[%2u] %s:%u [%3u] %s", |
2529 | friend, client, ip_ntoa(&assoc->ip_port.ip), | 2532 | friend, client, ip_ntoa(&assoc->ip_port.ip), |
2530 | ntohs(assoc->ip_port.port), last_pinged, | 2533 | ntohs(assoc->ip_port.port), last_pinged, |
2531 | ID2String(cptr->client_id)); | 2534 | ID2String(cptr->client_id)); |
2532 | } | 2535 | } |
2533 | } | 2536 | } |
2534 | } | 2537 | } |
@@ -2552,11 +2555,10 @@ void do_messenger(Messenger *m) | |||
2552 | #define MESSENGER_STATE_TYPE_PATH_NODE 11 | 2555 | #define MESSENGER_STATE_TYPE_PATH_NODE 11 |
2553 | 2556 | ||
2554 | #define SAVED_FRIEND_REQUEST_SIZE 1024 | 2557 | #define SAVED_FRIEND_REQUEST_SIZE 1024 |
2555 | #define NUM_SAVED_TCP_RELAYS 8 | ||
2556 | #define NUM_SAVED_PATH_NODES 8 | 2558 | #define NUM_SAVED_PATH_NODES 8 |
2557 | struct SAVED_FRIEND { | 2559 | struct SAVED_FRIEND { |
2558 | uint8_t status; | 2560 | uint8_t status; |
2559 | uint8_t client_id[CLIENT_ID_SIZE]; | 2561 | uint8_t real_pk[crypto_box_PUBLICKEYBYTES]; |
2560 | uint8_t info[SAVED_FRIEND_REQUEST_SIZE]; // the data that is sent during the friend requests we do. | 2562 | uint8_t info[SAVED_FRIEND_REQUEST_SIZE]; // the data that is sent during the friend requests we do. |
2561 | uint16_t info_size; // Length of the info. | 2563 | uint16_t info_size; // Length of the info. |
2562 | uint8_t name[MAX_NAME_LENGTH]; | 2564 | uint8_t name[MAX_NAME_LENGTH]; |
@@ -2583,7 +2585,7 @@ static uint32_t friends_list_save(const Messenger *m, uint8_t *data) | |||
2583 | struct SAVED_FRIEND temp; | 2585 | struct SAVED_FRIEND temp; |
2584 | memset(&temp, 0, sizeof(struct SAVED_FRIEND)); | 2586 | memset(&temp, 0, sizeof(struct SAVED_FRIEND)); |
2585 | temp.status = m->friendlist[i].status; | 2587 | temp.status = m->friendlist[i].status; |
2586 | memcpy(temp.client_id, m->friendlist[i].client_id, CLIENT_ID_SIZE); | 2588 | memcpy(temp.real_pk, m->friendlist[i].real_pk, crypto_box_PUBLICKEYBYTES); |
2587 | 2589 | ||
2588 | if (temp.status < 3) { | 2590 | if (temp.status < 3) { |
2589 | if (m->friendlist[i].info_size > SAVED_FRIEND_REQUEST_SIZE) { | 2591 | if (m->friendlist[i].info_size > SAVED_FRIEND_REQUEST_SIZE) { |
@@ -2629,7 +2631,7 @@ static int friends_list_load(Messenger *m, const uint8_t *data, uint32_t length) | |||
2629 | memcpy(&temp, data + i * sizeof(struct SAVED_FRIEND), sizeof(struct SAVED_FRIEND)); | 2631 | memcpy(&temp, data + i * sizeof(struct SAVED_FRIEND), sizeof(struct SAVED_FRIEND)); |
2630 | 2632 | ||
2631 | if (temp.status >= 3) { | 2633 | if (temp.status >= 3) { |
2632 | int fnum = m_addfriend_norequest(m, temp.client_id); | 2634 | int fnum = m_addfriend_norequest(m, temp.real_pk); |
2633 | 2635 | ||
2634 | if (fnum < 0) | 2636 | if (fnum < 0) |
2635 | continue; | 2637 | continue; |
@@ -2644,7 +2646,7 @@ static int friends_list_load(Messenger *m, const uint8_t *data, uint32_t length) | |||
2644 | } else if (temp.status != 0) { | 2646 | } else if (temp.status != 0) { |
2645 | /* TODO: This is not a good way to do this. */ | 2647 | /* TODO: This is not a good way to do this. */ |
2646 | uint8_t address[FRIEND_ADDRESS_SIZE]; | 2648 | uint8_t address[FRIEND_ADDRESS_SIZE]; |
2647 | id_copy(address, temp.client_id); | 2649 | id_copy(address, temp.real_pk); |
2648 | memcpy(address + crypto_box_PUBLICKEYBYTES, &(temp.friendrequest_nospam), sizeof(uint32_t)); | 2650 | memcpy(address + crypto_box_PUBLICKEYBYTES, &(temp.friendrequest_nospam), sizeof(uint32_t)); |
2649 | uint16_t checksum = address_checksum(address, FRIEND_ADDRESS_SIZE - sizeof(checksum)); | 2651 | uint16_t checksum = address_checksum(address, FRIEND_ADDRESS_SIZE - sizeof(checksum)); |
2650 | memcpy(address + crypto_box_PUBLICKEYBYTES + sizeof(uint32_t), &checksum, sizeof(checksum)); | 2652 | memcpy(address + crypto_box_PUBLICKEYBYTES + sizeof(uint32_t), &checksum, sizeof(checksum)); |
@@ -2673,14 +2675,13 @@ uint32_t messenger_size(const Messenger *m) | |||
2673 | 2675 | ||
2674 | static uint8_t *z_state_save_subheader(uint8_t *data, uint32_t len, uint16_t type) | 2676 | static uint8_t *z_state_save_subheader(uint8_t *data, uint32_t len, uint16_t type) |
2675 | { | 2677 | { |
2676 | uint32_t *data32 = (uint32_t *)data; | 2678 | host_to_lendian32(data, len); |
2677 | data32[0] = len; | 2679 | data += sizeof(uint32_t); |
2678 | data32[1] = (MESSENGER_STATE_COOKIE_TYPE << 16) | type; | 2680 | host_to_lendian32(data, (host_tolendian16(MESSENGER_STATE_COOKIE_TYPE) << 16) | host_tolendian16(type)); |
2679 | data += sizeof(uint32_t) * 2; | 2681 | data += sizeof(uint32_t); |
2680 | return data; | 2682 | return data; |
2681 | } | 2683 | } |
2682 | 2684 | ||
2683 | |||
2684 | /* Save the messenger in data of size Messenger_size(). */ | 2685 | /* Save the messenger in data of size Messenger_size(). */ |
2685 | void messenger_save(const Messenger *m, uint8_t *data) | 2686 | void messenger_save(const Messenger *m, uint8_t *data) |
2686 | { | 2687 | { |
@@ -2780,7 +2781,7 @@ static int messenger_load_state_callback(void *outer, const uint8_t *data, uint3 | |||
2780 | break; | 2781 | break; |
2781 | 2782 | ||
2782 | case MESSENGER_STATE_TYPE_NAME: | 2783 | case MESSENGER_STATE_TYPE_NAME: |
2783 | if ((length > 0) && (length < MAX_NAME_LENGTH)) { | 2784 | if ((length > 0) && (length <= MAX_NAME_LENGTH)) { |
2784 | setname(m, data, length); | 2785 | setname(m, data, length); |
2785 | } | 2786 | } |
2786 | 2787 | ||
@@ -2801,18 +2802,12 @@ static int messenger_load_state_callback(void *outer, const uint8_t *data, uint3 | |||
2801 | break; | 2802 | break; |
2802 | 2803 | ||
2803 | case MESSENGER_STATE_TYPE_TCP_RELAY: { | 2804 | case MESSENGER_STATE_TYPE_TCP_RELAY: { |
2804 | Node_format relays[NUM_SAVED_TCP_RELAYS]; | 2805 | if (length != sizeof(m->loaded_relays)) { |
2805 | |||
2806 | if (length != sizeof(relays)) { | ||
2807 | return -1; | 2806 | return -1; |
2808 | } | 2807 | } |
2809 | 2808 | ||
2810 | memcpy(relays, data, length); | 2809 | memcpy(m->loaded_relays, data, length); |
2811 | uint32_t i; | 2810 | m->has_added_relays = 0; |
2812 | |||
2813 | for (i = 0; i < NUM_SAVED_TCP_RELAYS; ++i) { | ||
2814 | add_tcp_relay(m->net_crypto, relays[i].ip_port, relays[i].client_id); | ||
2815 | } | ||
2816 | 2811 | ||
2817 | break; | 2812 | break; |
2818 | } | 2813 | } |
@@ -2828,7 +2823,7 @@ static int messenger_load_state_callback(void *outer, const uint8_t *data, uint3 | |||
2828 | uint32_t i; | 2823 | uint32_t i; |
2829 | 2824 | ||
2830 | for (i = 0; i < NUM_SAVED_PATH_NODES; ++i) { | 2825 | for (i = 0; i < NUM_SAVED_PATH_NODES; ++i) { |
2831 | onion_add_path_node(m->onion_c, nodes[i].ip_port, nodes[i].client_id); | 2826 | onion_add_bs_path_node(m->onion_c, nodes[i].ip_port, nodes[i].public_key); |
2832 | } | 2827 | } |
2833 | 2828 | ||
2834 | break; | 2829 | break; |
@@ -2892,7 +2887,7 @@ uint32_t get_num_online_friends(const Messenger *m) | |||
2892 | * Otherwise, returns the number of elements copied. | 2887 | * Otherwise, returns the number of elements copied. |
2893 | * If the array was too small, the contents | 2888 | * If the array was too small, the contents |
2894 | * of out_list will be truncated to list_size. */ | 2889 | * of out_list will be truncated to list_size. */ |
2895 | uint32_t copy_friendlist(Messenger const *m, int32_t *out_list, uint32_t list_size) | 2890 | uint32_t copy_friendlist(Messenger const *m, uint32_t *out_list, uint32_t list_size) |
2896 | { | 2891 | { |
2897 | if (!out_list) | 2892 | if (!out_list) |
2898 | return 0; | 2893 | return 0; |
@@ -2917,84 +2912,3 @@ uint32_t copy_friendlist(Messenger const *m, int32_t *out_list, uint32_t list_si | |||
2917 | 2912 | ||
2918 | return ret; | 2913 | return ret; |
2919 | } | 2914 | } |
2920 | |||
2921 | /* Allocate and return a list of valid friend id's. List must be freed by the | ||
2922 | * caller. | ||
2923 | * | ||
2924 | * retun 0 if success. | ||
2925 | * return -1 if failure. | ||
2926 | */ | ||
2927 | int get_friendlist(const Messenger *m, int32_t **out_list, uint32_t *out_list_length) | ||
2928 | { | ||
2929 | uint32_t i; | ||
2930 | |||
2931 | *out_list_length = 0; | ||
2932 | |||
2933 | if (m->numfriends == 0) { | ||
2934 | *out_list = NULL; | ||
2935 | return 0; | ||
2936 | } | ||
2937 | |||
2938 | *out_list = malloc(m->numfriends * sizeof(int32_t)); | ||
2939 | |||
2940 | if (*out_list == NULL) { | ||
2941 | return -1; | ||
2942 | } | ||
2943 | |||
2944 | for (i = 0; i < m->numfriends; i++) { | ||
2945 | if (m->friendlist[i].status > 0) { | ||
2946 | (*out_list)[i] = i; | ||
2947 | (*out_list_length)++; | ||
2948 | } | ||
2949 | } | ||
2950 | |||
2951 | return 0; | ||
2952 | } | ||
2953 | |||
2954 | /* Return the number of chats in the instance m. | ||
2955 | * You should use this to determine how much memory to allocate | ||
2956 | * for copy_chatlist. */ | ||
2957 | uint32_t count_chatlist(const Messenger *m) | ||
2958 | { | ||
2959 | uint32_t ret = 0; | ||
2960 | uint32_t i; | ||
2961 | |||
2962 | for (i = 0; i < m->numchats; i++) { | ||
2963 | if (m->chats[i]) { | ||
2964 | ret++; | ||
2965 | } | ||
2966 | } | ||
2967 | |||
2968 | return ret; | ||
2969 | } | ||
2970 | |||
2971 | /* Copy a list of valid chat IDs into the array out_list. | ||
2972 | * If out_list is NULL, returns 0. | ||
2973 | * Otherwise, returns the number of elements copied. | ||
2974 | * If the array was too small, the contents | ||
2975 | * of out_list will be truncated to list_size. */ | ||
2976 | uint32_t copy_chatlist(const Messenger *m, int *out_list, uint32_t list_size) | ||
2977 | { | ||
2978 | if (!out_list) | ||
2979 | return 0; | ||
2980 | |||
2981 | if (m->numchats == 0) { | ||
2982 | return 0; | ||
2983 | } | ||
2984 | |||
2985 | uint32_t i; | ||
2986 | uint32_t ret = 0; | ||
2987 | |||
2988 | for (i = 0; i < m->numchats; i++) { | ||
2989 | if (ret >= list_size) { | ||
2990 | break; /* Abandon ship */ | ||
2991 | } | ||
2992 | |||
2993 | if (m->chats[i]) { | ||
2994 | out_list[ret] = i; | ||
2995 | ret++; | ||
2996 | } | ||
2997 | } | ||
2998 | |||
2999 | return ret; | ||
3000 | } | ||
diff --git a/toxcore/Messenger.h b/toxcore/Messenger.h index c9f3cf88..0a613c0b 100644 --- a/toxcore/Messenger.h +++ b/toxcore/Messenger.h | |||
@@ -26,38 +26,43 @@ | |||
26 | #ifndef MESSENGER_H | 26 | #ifndef MESSENGER_H |
27 | #define MESSENGER_H | 27 | #define MESSENGER_H |
28 | 28 | ||
29 | #include "net_crypto.h" | ||
30 | #include "DHT.h" | ||
31 | #include "friend_requests.h" | 29 | #include "friend_requests.h" |
32 | #include "LAN_discovery.h" | 30 | #include "LAN_discovery.h" |
33 | #include "group_chats.h" | 31 | #include "friend_connection.h" |
34 | #include "onion_client.h" | ||
35 | 32 | ||
36 | #define MAX_NAME_LENGTH 128 | 33 | #define MAX_NAME_LENGTH 128 |
37 | /* TODO: this must depend on other variable. */ | 34 | /* TODO: this must depend on other variable. */ |
38 | #define MAX_STATUSMESSAGE_LENGTH 1007 | 35 | #define MAX_STATUSMESSAGE_LENGTH 1007 |
36 | #define AVATAR_MAX_DATA_LENGTH 16384 | ||
37 | #define AVATAR_HASH_LENGTH crypto_hash_sha256_BYTES | ||
38 | |||
39 | 39 | ||
40 | #define FRIEND_ADDRESS_SIZE (crypto_box_PUBLICKEYBYTES + sizeof(uint32_t) + sizeof(uint16_t)) | 40 | #define FRIEND_ADDRESS_SIZE (crypto_box_PUBLICKEYBYTES + sizeof(uint32_t) + sizeof(uint16_t)) |
41 | 41 | ||
42 | /* NOTE: Packet ids below 16 must never be used. */ | 42 | /* NOTE: Packet ids below 17 must never be used. */ |
43 | #define PACKET_ID_ALIVE 16 | ||
44 | #define PACKET_ID_SHARE_RELAYS 17 | 43 | #define PACKET_ID_SHARE_RELAYS 17 |
44 | #define PACKET_ID_ONLINE 24 | ||
45 | #define PACKET_ID_OFFLINE 25 | ||
45 | #define PACKET_ID_NICKNAME 48 | 46 | #define PACKET_ID_NICKNAME 48 |
46 | #define PACKET_ID_STATUSMESSAGE 49 | 47 | #define PACKET_ID_STATUSMESSAGE 49 |
47 | #define PACKET_ID_USERSTATUS 50 | 48 | #define PACKET_ID_USERSTATUS 50 |
48 | #define PACKET_ID_TYPING 51 | 49 | #define PACKET_ID_TYPING 51 |
50 | #define PACKET_ID_AVATAR_INFO_REQ 52 | ||
51 | #define PACKET_ID_AVATAR_INFO 53 | ||
52 | #define PACKET_ID_AVATAR_DATA_CONTROL 54 | ||
53 | #define PACKET_ID_AVATAR_DATA_START 55 | ||
54 | #define PACKET_ID_AVATAR_DATA_PUSH 56 | ||
49 | #define PACKET_ID_MESSAGE 64 | 55 | #define PACKET_ID_MESSAGE 64 |
50 | #define PACKET_ID_ACTION 65 | 56 | #define PACKET_ID_ACTION 65 |
51 | #define PACKET_ID_MSI 69 | 57 | #define PACKET_ID_MSI 69 |
52 | #define PACKET_ID_FILE_SENDREQUEST 80 | 58 | #define PACKET_ID_FILE_SENDREQUEST 80 |
53 | #define PACKET_ID_FILE_CONTROL 81 | 59 | #define PACKET_ID_FILE_CONTROL 81 |
54 | #define PACKET_ID_FILE_DATA 82 | 60 | #define PACKET_ID_FILE_DATA 82 |
55 | #define PACKET_ID_INVITE_GROUPCHAT 144 | 61 | #define PACKET_ID_INVITE_GROUPCHAT 96 |
56 | #define PACKET_ID_JOIN_GROUPCHAT 145 | 62 | #define PACKET_ID_ONLINE_PACKET 97 |
57 | #define PACKET_ID_ACCEPT_GROUPCHAT 146 | 63 | #define PACKET_ID_DIRECT_GROUPCHAT 98 |
58 | 64 | #define PACKET_ID_MESSAGE_GROUPCHAT 99 | |
59 | /* Max number of groups we can invite someone at the same time to. */ | 65 | #define PACKET_ID_LOSSY_GROUPCHAT 199 |
60 | #define MAX_INVITED_GROUPS 64 | ||
61 | 66 | ||
62 | /* Max number of tcp relays sent to friends */ | 67 | /* Max number of tcp relays sent to friends */ |
63 | #define MAX_SHARED_RELAYS 16 | 68 | #define MAX_SHARED_RELAYS 16 |
@@ -69,7 +74,6 @@ | |||
69 | typedef struct { | 74 | typedef struct { |
70 | uint8_t ipv6enabled; | 75 | uint8_t ipv6enabled; |
71 | uint8_t udp_disabled; | 76 | uint8_t udp_disabled; |
72 | uint8_t proxy_enabled; | ||
73 | TCP_Proxy_Info proxy_info; | 77 | TCP_Proxy_Info proxy_info; |
74 | } Messenger_Options; | 78 | } Messenger_Options; |
75 | 79 | ||
@@ -97,7 +101,6 @@ enum { | |||
97 | FAERR_NOMESSAGE = -2, | 101 | FAERR_NOMESSAGE = -2, |
98 | FAERR_OWNKEY = -3, | 102 | FAERR_OWNKEY = -3, |
99 | FAERR_ALREADYSENT = -4, | 103 | FAERR_ALREADYSENT = -4, |
100 | FAERR_UNKNOWN = -5, | ||
101 | FAERR_BADCHECKSUM = -6, | 104 | FAERR_BADCHECKSUM = -6, |
102 | FAERR_SETNEWNOSPAM = -7, | 105 | FAERR_SETNEWNOSPAM = -7, |
103 | FAERR_NOMEM = -8 | 106 | FAERR_NOMEM = -8 |
@@ -106,16 +109,23 @@ enum { | |||
106 | /* Default start timeout in seconds between friend requests. */ | 109 | /* Default start timeout in seconds between friend requests. */ |
107 | #define FRIENDREQUEST_TIMEOUT 5; | 110 | #define FRIENDREQUEST_TIMEOUT 5; |
108 | 111 | ||
109 | /* Interval between the sending of ping packets. */ | ||
110 | #define FRIEND_PING_INTERVAL 5 | ||
111 | |||
112 | /* Interval between the sending of tcp relay information */ | 112 | /* Interval between the sending of tcp relay information */ |
113 | #define FRIEND_SHARE_RELAYS_INTERVAL (5 * 60) | 113 | #define FRIEND_SHARE_RELAYS_INTERVAL (5 * 60) |
114 | 114 | ||
115 | /* If no packets are received from friend in this time interval, kill the connection. */ | 115 | /* Must be < MAX_CRYPTO_DATA_SIZE */ |
116 | #define FRIEND_CONNECTION_TIMEOUT (FRIEND_PING_INTERVAL * 3) | 116 | #define AVATAR_DATA_MAX_CHUNK_SIZE (MAX_CRYPTO_DATA_SIZE-1) |
117 | |||
118 | /* Per-friend data limit for avatar data requests */ | ||
119 | #define AVATAR_DATA_TRANSFER_LIMIT (10*AVATAR_MAX_DATA_LENGTH) | ||
120 | #define AVATAR_DATA_TRANSFER_TIMEOUT (60) /* 164kB every 60 seconds is not a lot */ | ||
117 | 121 | ||
118 | 122 | ||
123 | enum { | ||
124 | CONNECTION_NONE, | ||
125 | CONNECTION_TCP, | ||
126 | CONNECTION_UDP | ||
127 | }; | ||
128 | |||
119 | /* USERSTATUS - | 129 | /* USERSTATUS - |
120 | * Represents userstatuses someone can have. | 130 | * Represents userstatuses someone can have. |
121 | */ | 131 | */ |
@@ -128,6 +138,42 @@ typedef enum { | |||
128 | } | 138 | } |
129 | USERSTATUS; | 139 | USERSTATUS; |
130 | 140 | ||
141 | /* AVATAR_FORMAT - | ||
142 | * Data formats for user avatar images | ||
143 | */ | ||
144 | typedef enum { | ||
145 | AVATAR_FORMAT_NONE = 0, | ||
146 | AVATAR_FORMAT_PNG | ||
147 | } | ||
148 | AVATAR_FORMAT; | ||
149 | |||
150 | /* AVATAR_DATACONTROL | ||
151 | * To control avatar data requests (PACKET_ID_AVATAR_DATA_CONTROL) | ||
152 | */ | ||
153 | typedef enum { | ||
154 | AVATAR_DATACONTROL_REQ, | ||
155 | AVATAR_DATACONTROL_ERROR | ||
156 | } | ||
157 | AVATAR_DATACONTROL; | ||
158 | |||
159 | typedef struct { | ||
160 | uint8_t started; | ||
161 | AVATAR_FORMAT format; | ||
162 | uint8_t hash[AVATAR_HASH_LENGTH]; | ||
163 | uint32_t total_length; | ||
164 | uint32_t bytes_received; | ||
165 | uint8_t data[AVATAR_MAX_DATA_LENGTH]; | ||
166 | } | ||
167 | AVATAR_RECEIVEDATA; | ||
168 | |||
169 | typedef struct { | ||
170 | /* Fields only used to limit the network usage from a given friend */ | ||
171 | uint32_t bytes_sent; /* Total bytes send to this user */ | ||
172 | uint64_t last_reset; /* Time the data counter was last reset */ | ||
173 | } | ||
174 | AVATAR_SENDDATA; | ||
175 | |||
176 | |||
131 | struct File_Transfers { | 177 | struct File_Transfers { |
132 | uint64_t size; | 178 | uint64_t size; |
133 | uint64_t transferred; | 179 | uint64_t transferred; |
@@ -153,10 +199,12 @@ enum { | |||
153 | FILECONTROL_RESUME_BROKEN | 199 | FILECONTROL_RESUME_BROKEN |
154 | }; | 200 | }; |
155 | 201 | ||
202 | typedef struct Messenger Messenger; | ||
203 | |||
156 | typedef struct { | 204 | typedef struct { |
157 | uint8_t client_id[CLIENT_ID_SIZE]; | 205 | uint8_t real_pk[crypto_box_PUBLICKEYBYTES]; |
158 | uint32_t onion_friendnum; | 206 | int friendcon_id; |
159 | int crypt_connection_id; | 207 | |
160 | uint64_t friendrequest_lastsent; // Time at which the last friend request was sent. | 208 | uint64_t friendrequest_lastsent; // Time at which the last friend request was sent. |
161 | uint32_t friendrequest_timeout; // The timeout between successful friendrequest sending attempts. | 209 | uint32_t friendrequest_timeout; // The timeout between successful friendrequest sending attempts. |
162 | uint8_t status; // 0 if no friend, 1 if added, 2 if friend request sent, 3 if confirmed friend, 4 if online. | 210 | uint8_t status; // 0 if no friend, 1 if added, 2 if friend request sent, 3 if confirmed friend, 4 if online. |
@@ -164,32 +212,34 @@ typedef struct { | |||
164 | uint8_t name[MAX_NAME_LENGTH]; | 212 | uint8_t name[MAX_NAME_LENGTH]; |
165 | uint16_t name_length; | 213 | uint16_t name_length; |
166 | uint8_t name_sent; // 0 if we didn't send our name to this friend 1 if we have. | 214 | uint8_t name_sent; // 0 if we didn't send our name to this friend 1 if we have. |
167 | uint8_t *statusmessage; | 215 | uint8_t statusmessage[MAX_STATUSMESSAGE_LENGTH]; |
168 | uint16_t statusmessage_length; | 216 | uint16_t statusmessage_length; |
169 | uint8_t statusmessage_sent; | 217 | uint8_t statusmessage_sent; |
170 | USERSTATUS userstatus; | 218 | USERSTATUS userstatus; |
171 | uint8_t userstatus_sent; | 219 | uint8_t userstatus_sent; |
220 | uint8_t avatar_info_sent; | ||
172 | uint8_t user_istyping; | 221 | uint8_t user_istyping; |
173 | uint8_t user_istyping_sent; | 222 | uint8_t user_istyping_sent; |
174 | uint8_t is_typing; | 223 | uint8_t is_typing; |
175 | uint16_t info_size; // Length of the info. | 224 | uint16_t info_size; // Length of the info. |
176 | uint32_t message_id; // a semi-unique id used in read receipts. | 225 | uint32_t message_id; // a semi-unique id used in read receipts. |
177 | uint32_t friendrequest_nospam; // The nospam number used in the friend request. | 226 | uint32_t friendrequest_nospam; // The nospam number used in the friend request. |
178 | uint64_t ping_lastrecv; | 227 | uint64_t ping_lastrecv;//TODO remove |
179 | uint64_t ping_lastsent; | ||
180 | uint64_t share_relays_lastsent; | 228 | uint64_t share_relays_lastsent; |
229 | uint8_t last_connection_udp_tcp; | ||
181 | struct File_Transfers file_sending[MAX_CONCURRENT_FILE_PIPES]; | 230 | struct File_Transfers file_sending[MAX_CONCURRENT_FILE_PIPES]; |
182 | struct File_Transfers file_receiving[MAX_CONCURRENT_FILE_PIPES]; | 231 | struct File_Transfers file_receiving[MAX_CONCURRENT_FILE_PIPES]; |
183 | int invited_groups[MAX_INVITED_GROUPS]; | 232 | |
184 | uint16_t invited_groups_num; | 233 | AVATAR_SENDDATA avatar_send_data; |
234 | AVATAR_RECEIVEDATA *avatar_recv_data; // We are receiving avatar data from this friend. | ||
185 | 235 | ||
186 | struct { | 236 | struct { |
187 | int (*function)(void *object, const uint8_t *data, uint32_t len); | 237 | int (*function)(Messenger *m, uint32_t friendnumber, const uint8_t *data, uint32_t len, void *object); |
188 | void *object; | 238 | void *object; |
189 | } lossy_packethandlers[PACKET_ID_LOSSY_RANGE_SIZE]; | 239 | } lossy_packethandlers[PACKET_ID_LOSSY_RANGE_SIZE]; |
190 | 240 | ||
191 | struct { | 241 | struct { |
192 | int (*function)(void *object, const uint8_t *data, uint32_t len); | 242 | int (*function)(Messenger *m, uint32_t friendnumber, const uint8_t *data, uint32_t len, void *object); |
193 | void *object; | 243 | void *object; |
194 | } lossless_packethandlers[PACKET_ID_LOSSLESS_RANGE_SIZE]; | 244 | } lossless_packethandlers[PACKET_ID_LOSSLESS_RANGE_SIZE]; |
195 | 245 | ||
@@ -198,7 +248,7 @@ typedef struct { | |||
198 | } Friend; | 248 | } Friend; |
199 | 249 | ||
200 | 250 | ||
201 | typedef struct Messenger { | 251 | struct Messenger { |
202 | 252 | ||
203 | Networking_Core *net; | 253 | Networking_Core *net; |
204 | Net_Crypto *net_crypto; | 254 | Net_Crypto *net_crypto; |
@@ -208,6 +258,8 @@ typedef struct Messenger { | |||
208 | Onion_Announce *onion_a; | 258 | Onion_Announce *onion_a; |
209 | Onion_Client *onion_c; | 259 | Onion_Client *onion_c; |
210 | 260 | ||
261 | Friend_Connections *fr_c; | ||
262 | |||
211 | Friend_Requests fr; | 263 | Friend_Requests fr; |
212 | uint8_t name[MAX_NAME_LENGTH]; | 264 | uint8_t name[MAX_NAME_LENGTH]; |
213 | uint16_t name_length; | 265 | uint16_t name_length; |
@@ -217,60 +269,65 @@ typedef struct Messenger { | |||
217 | 269 | ||
218 | USERSTATUS userstatus; | 270 | USERSTATUS userstatus; |
219 | 271 | ||
272 | AVATAR_FORMAT avatar_format; | ||
273 | uint8_t *avatar_data; | ||
274 | uint32_t avatar_data_length; | ||
275 | uint8_t avatar_hash[AVATAR_HASH_LENGTH]; | ||
276 | |||
220 | Friend *friendlist; | 277 | Friend *friendlist; |
221 | uint32_t numfriends; | 278 | uint32_t numfriends; |
222 | 279 | ||
223 | uint32_t numonline_friends; | 280 | uint32_t numonline_friends; |
224 | 281 | ||
225 | Group_Chat **chats; | ||
226 | uint32_t numchats; | ||
227 | |||
228 | uint64_t last_LANdiscovery; | 282 | uint64_t last_LANdiscovery; |
229 | 283 | ||
230 | void (*friend_message)(struct Messenger *m, int32_t, const uint8_t *, uint16_t, void *); | 284 | #define NUM_SAVED_TCP_RELAYS 8 |
285 | uint8_t has_added_relays; // If the first connection has occurred in do_messenger | ||
286 | Node_format loaded_relays[NUM_SAVED_TCP_RELAYS]; // Relays loaded from config | ||
287 | |||
288 | void (*friend_message)(struct Messenger *m, uint32_t, const uint8_t *, size_t, void *); | ||
231 | void *friend_message_userdata; | 289 | void *friend_message_userdata; |
232 | void (*friend_action)(struct Messenger *m, int32_t, const uint8_t *, uint16_t, void *); | 290 | void (*friend_action)(struct Messenger *m, uint32_t, const uint8_t *, size_t, void *); |
233 | void *friend_action_userdata; | 291 | void *friend_action_userdata; |
234 | void (*friend_namechange)(struct Messenger *m, int32_t, const uint8_t *, uint16_t, void *); | 292 | void (*friend_namechange)(struct Messenger *m, uint32_t, const uint8_t *, size_t, void *); |
235 | void *friend_namechange_userdata; | 293 | void *friend_namechange_userdata; |
236 | void (*friend_statusmessagechange)(struct Messenger *m, int32_t, const uint8_t *, uint16_t, void *); | 294 | void (*friend_statusmessagechange)(struct Messenger *m, uint32_t, const uint8_t *, size_t, void *); |
237 | void *friend_statusmessagechange_userdata; | 295 | void *friend_statusmessagechange_userdata; |
238 | void (*friend_userstatuschange)(struct Messenger *m, int32_t, uint8_t, void *); | 296 | void (*friend_userstatuschange)(struct Messenger *m, uint32_t, uint8_t, void *); |
239 | void *friend_userstatuschange_userdata; | 297 | void *friend_userstatuschange_userdata; |
240 | void (*friend_typingchange)(struct Messenger *m, int32_t, uint8_t, void *); | 298 | void (*friend_typingchange)(struct Messenger *m, uint32_t, _Bool, void *); |
241 | void *friend_typingchange_userdata; | 299 | void *friend_typingchange_userdata; |
242 | void (*read_receipt)(struct Messenger *m, int32_t, uint32_t, void *); | 300 | void (*read_receipt)(struct Messenger *m, uint32_t, uint32_t, void *); |
243 | void *read_receipt_userdata; | 301 | void *read_receipt_userdata; |
244 | void (*friend_statuschange)(struct Messenger *m, int32_t, uint8_t, void *); | 302 | void (*friend_statuschange)(struct Messenger *m, uint32_t, uint8_t, void *); |
245 | void *friend_statuschange_userdata; | 303 | void *friend_statuschange_userdata; |
246 | void (*friend_connectionstatuschange)(struct Messenger *m, int32_t, uint8_t, void *); | 304 | void (*friend_connectionstatuschange)(struct Messenger *m, uint32_t, uint8_t, void *); |
247 | void *friend_connectionstatuschange_userdata; | 305 | void *friend_connectionstatuschange_userdata; |
248 | void (*friend_connectionstatuschange_internal)(struct Messenger *m, int32_t, uint8_t, void *); | 306 | void (*friend_connectionstatuschange_internal)(struct Messenger *m, uint32_t, uint8_t, void *); |
249 | void *friend_connectionstatuschange_internal_userdata; | 307 | void *friend_connectionstatuschange_internal_userdata; |
308 | void *avatar_info_recv_userdata; | ||
309 | void (*avatar_info_recv)(struct Messenger *m, uint32_t, uint8_t, uint8_t *, void *); | ||
310 | void *avatar_data_recv_userdata; | ||
311 | void (*avatar_data_recv)(struct Messenger *m, uint32_t, uint8_t, uint8_t *, uint8_t *, uint32_t, void *); | ||
250 | 312 | ||
251 | void (*group_invite)(struct Messenger *m, int32_t, const uint8_t *, void *); | 313 | void *group_chat_object; /* Set by new_groupchats()*/ |
252 | void *group_invite_userdata; | 314 | void (*group_invite)(struct Messenger *m, uint32_t, const uint8_t *, uint16_t); |
253 | void (*group_message)(struct Messenger *m, int, int, const uint8_t *, uint16_t, void *); | 315 | void (*group_message)(struct Messenger *m, uint32_t, const uint8_t *, uint16_t); |
254 | void *group_message_userdata; | ||
255 | void (*group_action)(struct Messenger *m, int, int, const uint8_t *, uint16_t, void *); | ||
256 | void *group_action_userdata; | ||
257 | void (*group_namelistchange)(struct Messenger *m, int, int, uint8_t, void *); | ||
258 | void *group_namelistchange_userdata; | ||
259 | 316 | ||
260 | void (*file_sendrequest)(struct Messenger *m, int32_t, uint8_t, uint64_t, const uint8_t *, uint16_t, void *); | 317 | void (*file_sendrequest)(struct Messenger *m, uint32_t, uint8_t, uint64_t, const uint8_t *, uint16_t, void *); |
261 | void *file_sendrequest_userdata; | 318 | void *file_sendrequest_userdata; |
262 | void (*file_filecontrol)(struct Messenger *m, int32_t, uint8_t, uint8_t, uint8_t, const uint8_t *, uint16_t, void *); | 319 | void (*file_filecontrol)(struct Messenger *m, uint32_t, uint8_t, uint8_t, uint8_t, const uint8_t *, uint16_t, void *); |
263 | void *file_filecontrol_userdata; | 320 | void *file_filecontrol_userdata; |
264 | void (*file_filedata)(struct Messenger *m, int32_t, uint8_t, const uint8_t *, uint16_t length, void *); | 321 | void (*file_filedata)(struct Messenger *m, uint32_t, uint8_t, const uint8_t *, uint16_t length, void *); |
265 | void *file_filedata_userdata; | 322 | void *file_filedata_userdata; |
266 | 323 | ||
267 | void (*msi_packet)(struct Messenger *m, int32_t, const uint8_t *, uint16_t, void *); | 324 | void (*msi_packet)(struct Messenger *m, uint32_t, const uint8_t *, uint16_t, void *); |
268 | void *msi_packet_userdata; | 325 | void *msi_packet_userdata; |
269 | 326 | ||
270 | Messenger_Options options; | 327 | Messenger_Options options; |
271 | } Messenger; | 328 | }; |
272 | 329 | ||
273 | /* Format: [client_id (32 bytes)][nospam number (4 bytes)][checksum (2 bytes)] | 330 | /* Format: [real_pk (32 bytes)][nospam number (4 bytes)][checksum (2 bytes)] |
274 | * | 331 | * |
275 | * return FRIEND_ADDRESS_SIZE byte address to give to others. | 332 | * return FRIEND_ADDRESS_SIZE byte address to give to others. |
276 | */ | 333 | */ |
@@ -286,7 +343,6 @@ void getaddress(const Messenger *m, uint8_t *address); | |||
286 | * return -2 if no message (message length must be >= 1 byte). | 343 | * return -2 if no message (message length must be >= 1 byte). |
287 | * return -3 if user's own key. | 344 | * return -3 if user's own key. |
288 | * return -4 if friend request already sent or already a friend. | 345 | * return -4 if friend request already sent or already a friend. |
289 | * return -5 for unknown error. | ||
290 | * return -6 if bad checksum in address. | 346 | * return -6 if bad checksum in address. |
291 | * return -7 if the friend was already there but the nospam was different. | 347 | * return -7 if the friend was already there but the nospam was different. |
292 | * (the nospam for that friend was set to the new one). | 348 | * (the nospam for that friend was set to the new one). |
@@ -297,22 +353,30 @@ int32_t m_addfriend(Messenger *m, const uint8_t *address, const uint8_t *data, u | |||
297 | 353 | ||
298 | /* Add a friend without sending a friendrequest. | 354 | /* Add a friend without sending a friendrequest. |
299 | * return the friend number if success. | 355 | * return the friend number if success. |
300 | * return -1 if failure. | 356 | * return -3 if user's own key. |
357 | * return -4 if friend request already sent or already a friend. | ||
358 | * return -6 if bad checksum in address. | ||
359 | * return -8 if increasing the friend list size fails. | ||
301 | */ | 360 | */ |
302 | int32_t m_addfriend_norequest(Messenger *m, const uint8_t *client_id); | 361 | int32_t m_addfriend_norequest(Messenger *m, const uint8_t *real_pk); |
303 | 362 | ||
304 | /* return the friend number associated to that client id. | 363 | /* return the friend number associated to that client id. |
305 | * return -1 if no such friend. | 364 | * return -1 if no such friend. |
306 | */ | 365 | */ |
307 | int32_t getfriend_id(const Messenger *m, const uint8_t *client_id); | 366 | int32_t getfriend_id(const Messenger *m, const uint8_t *real_pk); |
308 | 367 | ||
309 | /* Copies the public key associated to that friend id into client_id buffer. | 368 | /* Copies the public key associated to that friend id into real_pk buffer. |
310 | * Make sure that client_id is of size CLIENT_ID_SIZE. | 369 | * Make sure that real_pk is of size crypto_box_PUBLICKEYBYTES. |
311 | * | 370 | * |
312 | * return 0 if success | 371 | * return 0 if success |
313 | * return -1 if failure | 372 | * return -1 if failure |
314 | */ | 373 | */ |
315 | int getclient_id(const Messenger *m, int32_t friendnumber, uint8_t *client_id); | 374 | int get_real_pk(const Messenger *m, int32_t friendnumber, uint8_t *real_pk); |
375 | |||
376 | /* return friend connection id on success. | ||
377 | * return -1 if failure. | ||
378 | */ | ||
379 | int getfriendcon_id(const Messenger *m, int32_t friendnumber); | ||
316 | 380 | ||
317 | /* Remove a friend. | 381 | /* Remove a friend. |
318 | * | 382 | * |
@@ -323,8 +387,9 @@ int m_delfriend(Messenger *m, int32_t friendnumber); | |||
323 | 387 | ||
324 | /* Checks friend's connecting status. | 388 | /* Checks friend's connecting status. |
325 | * | 389 | * |
326 | * return 1 if friend is connected to us (Online). | 390 | * return CONNECTION_UDP (2) if friend is directly connected to us (Online UDP). |
327 | * return 0 if friend is not connected to us (Offline). | 391 | * return CONNECTION_TCP (1) if friend is connected to us (Online TCP). |
392 | * return CONNECTION_NONE (0) if friend is not connected to us (Offline). | ||
328 | * return -1 on failure. | 393 | * return -1 on failure. |
329 | */ | 394 | */ |
330 | int m_get_friend_connectionstatus(const Messenger *m, int32_t friendnumber); | 395 | int m_get_friend_connectionstatus(const Messenger *m, int32_t friendnumber); |
@@ -423,7 +488,7 @@ int m_get_self_statusmessage_size(const Messenger *m); | |||
423 | * retruns -1 on failure. | 488 | * retruns -1 on failure. |
424 | */ | 489 | */ |
425 | int m_copy_statusmessage(const Messenger *m, int32_t friendnumber, uint8_t *buf, uint32_t maxlen); | 490 | int m_copy_statusmessage(const Messenger *m, int32_t friendnumber, uint8_t *buf, uint32_t maxlen); |
426 | int m_copy_self_statusmessage(const Messenger *m, uint8_t *buf, uint32_t maxlen); | 491 | int m_copy_self_statusmessage(const Messenger *m, uint8_t *buf); |
427 | 492 | ||
428 | /* return one of USERSTATUS values. | 493 | /* return one of USERSTATUS values. |
429 | * Values unknown to your application should be represented as USERSTATUS_NONE. | 494 | * Values unknown to your application should be represented as USERSTATUS_NONE. |
@@ -433,6 +498,114 @@ int m_copy_self_statusmessage(const Messenger *m, uint8_t *buf, uint32_t maxlen) | |||
433 | uint8_t m_get_userstatus(const Messenger *m, int32_t friendnumber); | 498 | uint8_t m_get_userstatus(const Messenger *m, int32_t friendnumber); |
434 | uint8_t m_get_self_userstatus(const Messenger *m); | 499 | uint8_t m_get_self_userstatus(const Messenger *m); |
435 | 500 | ||
501 | |||
502 | /* Set the user avatar image data. | ||
503 | * This should be made before connecting, so we will not announce that the user have no avatar | ||
504 | * before setting and announcing a new one, forcing the peers to re-download it. | ||
505 | * | ||
506 | * Notice that the library treats the image as raw data and does not interpret it by any way. | ||
507 | * | ||
508 | * Arguments: | ||
509 | * format - Avatar image format or NONE for user with no avatar (see AVATAR_FORMAT); | ||
510 | * data - pointer to the avatar data (may be NULL it the format is NONE); | ||
511 | * length - length of image data. Must be <= MAX_AVATAR_DATA_LENGTH. | ||
512 | * | ||
513 | * returns 0 on success | ||
514 | * returns -1 on failure. | ||
515 | */ | ||
516 | int m_set_avatar(Messenger *m, uint8_t format, const uint8_t *data, uint32_t length); | ||
517 | |||
518 | /* Unsets the user avatar. | ||
519 | |||
520 | returns 0 on success (currently always returns 0) */ | ||
521 | int m_unset_avatar(Messenger *m); | ||
522 | |||
523 | /* Get avatar data from the current user. | ||
524 | * Copies the current user avatar data to the destination buffer and sets the image format | ||
525 | * accordingly. | ||
526 | * | ||
527 | * If the avatar format is NONE, the buffer 'buf' isleft uninitialized, 'hash' is zeroed, and | ||
528 | * 'length' is set to zero. | ||
529 | * | ||
530 | * If any of the pointers format, buf, length, and hash are NULL, that particular field will be ignored. | ||
531 | * | ||
532 | * Arguments: | ||
533 | * format - destination pointer to the avatar image format (see AVATAR_FORMAT); | ||
534 | * buf - destination buffer to the image data. Must have at least 'maxlen' bytes; | ||
535 | * length - destination pointer to the image data length; | ||
536 | * maxlen - length of the destination buffer 'buf'; | ||
537 | * hash - destination pointer to the avatar hash (it must be exactly AVATAR_HASH_LENGTH bytes long). | ||
538 | * | ||
539 | * returns 0 on success; | ||
540 | * returns -1 on failure. | ||
541 | * | ||
542 | */ | ||
543 | int m_get_self_avatar(const Messenger *m, uint8_t *format, uint8_t *buf, uint32_t *length, uint32_t maxlen, | ||
544 | uint8_t *hash); | ||
545 | |||
546 | /* Generates a cryptographic hash of the given data. | ||
547 | * This function may be used by clients for any purpose, but is provided primarily for | ||
548 | * validating cached avatars. | ||
549 | * This function is a wrapper to internal message-digest functions. | ||
550 | * | ||
551 | * Arguments: | ||
552 | * hash - destination buffer for the hash data, it must be exactly crypto_hash_sha256_BYTES bytes long. | ||
553 | * data - data to be hashed; | ||
554 | * datalen - length of the data; | ||
555 | * | ||
556 | * returns 0 on success | ||
557 | * returns -1 on failure. | ||
558 | */ | ||
559 | int m_hash(uint8_t *hash, const uint8_t *data, const uint32_t datalen); | ||
560 | |||
561 | /* Generates a cryptographic hash of the given avatar data. | ||
562 | * This function is a wrapper to m_hash and specifically provided | ||
563 | * to generate hashes from user avatars that may be memcmp()ed with the values returned by the | ||
564 | * other avatar functions. It is specially important to validate cached avatars. | ||
565 | * | ||
566 | * Arguments: | ||
567 | * hash - destination buffer for the hash data, it must be exactly AVATAR_HASH_LENGTH bytes long. | ||
568 | * data - avatar image data; | ||
569 | * datalen - length of the avatar image data; it must be <= MAX_AVATAR_DATA_LENGTH. | ||
570 | * | ||
571 | * returns 0 on success | ||
572 | * returns -1 on failure. | ||
573 | */ | ||
574 | int m_avatar_hash(uint8_t *hash, const uint8_t *data, const uint32_t datalen); | ||
575 | |||
576 | /* Request avatar information from a friend. | ||
577 | * Asks a friend to provide their avatar information (image format and hash). The friend may | ||
578 | * or may not answer this request and, if answered, the information will be provided through | ||
579 | * the callback 'avatar_info'. | ||
580 | * | ||
581 | * returns 0 on success | ||
582 | * returns -1 on failure. | ||
583 | */ | ||
584 | int m_request_avatar_info(const Messenger *m, const int32_t friendnumber); | ||
585 | |||
586 | /* Send an unrequested avatar information to a friend. | ||
587 | * Sends our avatar format and hash to a friend; he/she can use this information to validate | ||
588 | * an avatar from the cache and may (or not) reply with an avatar data request. | ||
589 | * | ||
590 | * Notice: it is NOT necessary to send these notification after changing the avatar or | ||
591 | * connecting. The library already does this. | ||
592 | * | ||
593 | * returns 0 on success | ||
594 | * returns -1 on failure. | ||
595 | */ | ||
596 | int m_send_avatar_info(const Messenger *m, const int32_t friendnumber); | ||
597 | |||
598 | |||
599 | /* Request the avatar data from a friend. | ||
600 | * Ask a friend to send their avatar data. The friend may or may not answer this request and, | ||
601 | * if answered, the information will be provided in callback 'avatar_data'. | ||
602 | * | ||
603 | * returns 0 on sucess | ||
604 | * returns -1 on failure. | ||
605 | */ | ||
606 | int m_request_avatar_data(const Messenger *m, const int32_t friendnumber); | ||
607 | |||
608 | |||
436 | /* returns timestamp of last time friendnumber was seen online, or 0 if never seen. | 609 | /* returns timestamp of last time friendnumber was seen online, or 0 if never seen. |
437 | * returns -1 on error. | 610 | * returns -1 on error. |
438 | */ | 611 | */ |
@@ -451,53 +624,53 @@ int m_set_usertyping(Messenger *m, int32_t friendnumber, uint8_t is_typing); | |||
451 | * returns 0 if friend is not typing. | 624 | * returns 0 if friend is not typing. |
452 | * returns 1 if friend is typing. | 625 | * returns 1 if friend is typing. |
453 | */ | 626 | */ |
454 | uint8_t m_get_istyping(const Messenger *m, int32_t friendnumber); | 627 | int m_get_istyping(const Messenger *m, int32_t friendnumber); |
455 | 628 | ||
456 | /* Set the function that will be executed when a friend request is received. | 629 | /* Set the function that will be executed when a friend request is received. |
457 | * Function format is function(uint8_t * public_key, uint8_t * data, uint16_t length) | 630 | * Function format is function(uint8_t * public_key, uint8_t * data, size_t length) |
458 | */ | 631 | */ |
459 | void m_callback_friendrequest(Messenger *m, void (*function)(Messenger *m, const uint8_t *, const uint8_t *, uint16_t, | 632 | void m_callback_friendrequest(Messenger *m, void (*function)(Messenger *m, const uint8_t *, const uint8_t *, size_t, |
460 | void *), void *userdata); | 633 | void *), void *userdata); |
461 | 634 | ||
462 | /* Set the function that will be executed when a message from a friend is received. | 635 | /* Set the function that will be executed when a message from a friend is received. |
463 | * Function format is: function(int32_t friendnumber, uint8_t * message, uint32_t length) | 636 | * Function format is: function(uint32_t friendnumber, uint8_t * message, uint32_t length) |
464 | */ | 637 | */ |
465 | void m_callback_friendmessage(Messenger *m, void (*function)(Messenger *m, int32_t, const uint8_t *, uint16_t, void *), | 638 | void m_callback_friendmessage(Messenger *m, void (*function)(Messenger *m, uint32_t, const uint8_t *, size_t, void *), |
466 | void *userdata); | 639 | void *userdata); |
467 | 640 | ||
468 | /* Set the function that will be executed when an action from a friend is received. | 641 | /* Set the function that will be executed when an action from a friend is received. |
469 | * Function format is: function(int32_t friendnumber, uint8_t * action, uint32_t length) | 642 | * Function format is: function(uint32_t friendnumber, uint8_t * action, uint32_t length) |
470 | */ | 643 | */ |
471 | void m_callback_action(Messenger *m, void (*function)(Messenger *m, int32_t, const uint8_t *, uint16_t, void *), | 644 | void m_callback_action(Messenger *m, void (*function)(Messenger *m, uint32_t, const uint8_t *, size_t, void *), |
472 | void *userdata); | 645 | void *userdata); |
473 | 646 | ||
474 | /* Set the callback for name changes. | 647 | /* Set the callback for name changes. |
475 | * Function(int32_t friendnumber, uint8_t *newname, uint16_t length) | 648 | * Function(uint32_t friendnumber, uint8_t *newname, size_t length) |
476 | * You are not responsible for freeing newname. | 649 | * You are not responsible for freeing newname. |
477 | */ | 650 | */ |
478 | void m_callback_namechange(Messenger *m, void (*function)(Messenger *m, int32_t, const uint8_t *, uint16_t, void *), | 651 | void m_callback_namechange(Messenger *m, void (*function)(Messenger *m, uint32_t, const uint8_t *, size_t, void *), |
479 | void *userdata); | 652 | void *userdata); |
480 | 653 | ||
481 | /* Set the callback for status message changes. | 654 | /* Set the callback for status message changes. |
482 | * Function(int32_t friendnumber, uint8_t *newstatus, uint16_t length) | 655 | * Function(uint32_t friendnumber, uint8_t *newstatus, size_t length) |
483 | * | 656 | * |
484 | * You are not responsible for freeing newstatus | 657 | * You are not responsible for freeing newstatus |
485 | */ | 658 | */ |
486 | void m_callback_statusmessage(Messenger *m, void (*function)(Messenger *m, int32_t, const uint8_t *, uint16_t, void *), | 659 | void m_callback_statusmessage(Messenger *m, void (*function)(Messenger *m, uint32_t, const uint8_t *, size_t, void *), |
487 | void *userdata); | 660 | void *userdata); |
488 | 661 | ||
489 | /* Set the callback for status type changes. | 662 | /* Set the callback for status type changes. |
490 | * Function(int32_t friendnumber, USERSTATUS kind) | 663 | * Function(uint32_t friendnumber, USERSTATUS kind) |
491 | */ | 664 | */ |
492 | void m_callback_userstatus(Messenger *m, void (*function)(Messenger *m, int32_t, uint8_t, void *), void *userdata); | 665 | void m_callback_userstatus(Messenger *m, void (*function)(Messenger *m, uint32_t, uint8_t, void *), void *userdata); |
493 | 666 | ||
494 | /* Set the callback for typing changes. | 667 | /* Set the callback for typing changes. |
495 | * Function(int32_t friendnumber, uint8_t is_typing) | 668 | * Function(uint32_t friendnumber, uint8_t is_typing) |
496 | */ | 669 | */ |
497 | void m_callback_typingchange(Messenger *m, void(*function)(Messenger *m, int32_t, uint8_t, void *), void *userdata); | 670 | void m_callback_typingchange(Messenger *m, void(*function)(Messenger *m, uint32_t, _Bool, void *), void *userdata); |
498 | 671 | ||
499 | /* Set the callback for read receipts. | 672 | /* Set the callback for read receipts. |
500 | * Function(int32_t friendnumber, uint32_t receipt) | 673 | * Function(uint32_t friendnumber, uint32_t receipt) |
501 | * | 674 | * |
502 | * If you are keeping a record of returns from m_sendmessage, | 675 | * If you are keeping a record of returns from m_sendmessage, |
503 | * receipt might be one of those values, meaning the message | 676 | * receipt might be one of those values, meaning the message |
@@ -505,10 +678,10 @@ void m_callback_typingchange(Messenger *m, void(*function)(Messenger *m, int32_t | |||
505 | * Since core doesn't track ids for you, receipt may not correspond to any message. | 678 | * Since core doesn't track ids for you, receipt may not correspond to any message. |
506 | * In that case, you should discard it. | 679 | * In that case, you should discard it. |
507 | */ | 680 | */ |
508 | void m_callback_read_receipt(Messenger *m, void (*function)(Messenger *m, int32_t, uint32_t, void *), void *userdata); | 681 | void m_callback_read_receipt(Messenger *m, void (*function)(Messenger *m, uint32_t, uint32_t, void *), void *userdata); |
509 | 682 | ||
510 | /* Set the callback for connection status changes. | 683 | /* Set the callback for connection status changes. |
511 | * function(int32_t friendnumber, uint8_t status) | 684 | * function(uint32_t friendnumber, uint8_t status) |
512 | * | 685 | * |
513 | * Status: | 686 | * Status: |
514 | * 0 -- friend went offline after being previously online. | 687 | * 0 -- friend went offline after being previously online. |
@@ -518,132 +691,96 @@ void m_callback_read_receipt(Messenger *m, void (*function)(Messenger *m, int32_ | |||
518 | * being previously online" part. | 691 | * being previously online" part. |
519 | * It's assumed that when adding friends, their connection status is offline. | 692 | * It's assumed that when adding friends, their connection status is offline. |
520 | */ | 693 | */ |
521 | void m_callback_connectionstatus(Messenger *m, void (*function)(Messenger *m, int32_t, uint8_t, void *), | 694 | void m_callback_connectionstatus(Messenger *m, void (*function)(Messenger *m, uint32_t, uint8_t, void *), |
522 | void *userdata); | 695 | void *userdata); |
523 | /* Same as previous but for internal A/V core usage only */ | 696 | /* Same as previous but for internal A/V core usage only */ |
524 | void m_callback_connectionstatus_internal_av(Messenger *m, void (*function)(Messenger *m, int32_t, uint8_t, void *), | 697 | void m_callback_connectionstatus_internal_av(Messenger *m, void (*function)(Messenger *m, uint32_t, uint8_t, void *), |
525 | void *userdata); | 698 | void *userdata); |
526 | 699 | ||
527 | /**********GROUP CHATS************/ | ||
528 | 700 | ||
529 | /* Set the callback for group invites. | 701 | /* Set the callback function for avatar information. |
702 | * This callback will be called when avatar information are received from friends. These events | ||
703 | * can arrive at anytime, but are usually received uppon connection and in reply of avatar | ||
704 | * information requests. | ||
530 | * | 705 | * |
531 | * Function(Messenger *m, int32_t friendnumber, uint8_t *group_public_key, void *userdata) | 706 | * Function format is: |
532 | */ | 707 | * function(Tox *tox, uint32_t friendnumber, uint8_t format, uint8_t *hash, void *userdata) |
533 | void m_callback_group_invite(Messenger *m, void (*function)(Messenger *m, int32_t, const uint8_t *, void *), | ||
534 | void *userdata); | ||
535 | |||
536 | /* Set the callback for group messages. | ||
537 | * | 708 | * |
538 | * Function(Tox *tox, int groupnumber, int friendgroupnumber, uint8_t * message, uint16_t length, void *userdata) | 709 | * where 'format' is the avatar image format (see AVATAR_FORMAT) and 'hash' is the hash of |
539 | */ | 710 | * the avatar data for caching purposes and it is exactly AVATAR_HASH_LENGTH long. If the |
540 | void m_callback_group_message(Messenger *m, void (*function)(Messenger *m, int, int, const uint8_t *, uint16_t, void *), | 711 | * image format is NONE, the hash is zeroed. |
541 | void *userdata); | ||
542 | |||
543 | /* Set the callback for group actions. | ||
544 | * | 712 | * |
545 | * Function(Tox *tox, int groupnumber, int friendgroupnumber, uint8_t * message, uint16_t length, void *userdata) | ||
546 | */ | 713 | */ |
547 | void m_callback_group_action(Messenger *m, void (*function)(Messenger *m, int, int, const uint8_t *, uint16_t, void *), | 714 | void m_callback_avatar_info(Messenger *m, void (*function)(Messenger *m, uint32_t, uint8_t, uint8_t *, void *), |
548 | void *userdata); | 715 | void *userdata); |
549 | 716 | ||
550 | /* Set callback function for peer name list changes. | ||
551 | * | ||
552 | * It gets called every time the name list changes(new peer/name, deleted peer) | ||
553 | * Function(Tox *tox, int groupnumber, void *userdata) | ||
554 | */ | ||
555 | void m_callback_group_namelistchange(Messenger *m, void (*function)(Messenger *m, int, int, uint8_t, void *), | ||
556 | void *userdata); | ||
557 | 717 | ||
558 | /* Creates a new groupchat and puts it in the chats array. | 718 | /* Set the callback function for avatar data. |
719 | * This callback will be called when the complete avatar data was correctly received from a | ||
720 | * friend. This only happens in reply of a avatar data request (see tox_request_avatar_data); | ||
559 | * | 721 | * |
560 | * return group number on success. | 722 | * Function format is: |
561 | * return -1 on failure. | 723 | * function(Tox *tox, uint32_t friendnumber, uint8_t format, uint8_t *hash, uint8_t *data, uint32_t datalen, void *userdata) |
562 | */ | ||
563 | int add_groupchat(Messenger *m); | ||
564 | |||
565 | /* Delete a groupchat from the chats array. | ||
566 | * | 724 | * |
567 | * return 0 on success. | 725 | * where 'format' is the avatar image format (see AVATAR_FORMAT); 'hash' is the |
568 | * return -1 if failure. | 726 | * locally-calculated cryptographic hash of the avatar data and it is exactly |
569 | */ | 727 | * AVATAR_HASH_LENGTH long; 'data' is the avatar image data and 'datalen' is the length |
570 | int del_groupchat(Messenger *m, int groupnumber); | 728 | * of such data. |
571 | |||
572 | /* Copy the name of peernumber who is in groupnumber to name. | ||
573 | * name must be at least MAX_NICK_BYTES long. | ||
574 | * | 729 | * |
575 | * return length of name if success | 730 | * If format is NONE, 'data' is NULL, 'datalen' is zero, and the hash is zeroed. The hash is |
576 | * return -1 if failure | 731 | * always validated locally with the function tox_avatar_hash and ensured to match the image |
577 | */ | 732 | * data, so this value can be safely used to compare with cached avatars. |
578 | int m_group_peername(const Messenger *m, int groupnumber, int peernumber, uint8_t *name); | ||
579 | |||
580 | /* invite friendnumber to groupnumber | ||
581 | * return 0 on success | ||
582 | * return -1 on failure | ||
583 | */ | ||
584 | int invite_friend(Messenger *m, int32_t friendnumber, int groupnumber); | ||
585 | |||
586 | /* Join a group (you need to have been invited first.) | ||
587 | * | 733 | * |
588 | * returns group number on success | 734 | * WARNING: users MUST treat all avatar image data received from another peer as untrusted and |
589 | * returns -1 on failure. | 735 | * potentially malicious. The library only ensures that the data which arrived is the same the |
736 | * other user sent, and does not interpret or validate any image data. | ||
590 | */ | 737 | */ |
591 | int join_groupchat(Messenger *m, int32_t friendnumber, const uint8_t *friend_group_public_key); | 738 | void m_callback_avatar_data(Messenger *m, void (*function)(Messenger *m, uint32_t, uint8_t, uint8_t *, uint8_t *, |
739 | uint32_t, void *), void *userdata); | ||
592 | 740 | ||
593 | /* send a group message | ||
594 | * return 0 on success | ||
595 | * return -1 on failure | ||
596 | */ | ||
597 | int group_message_send(const Messenger *m, int groupnumber, const uint8_t *message, uint32_t length); | ||
598 | 741 | ||
599 | /* send a group action | ||
600 | * return 0 on success | ||
601 | * return -1 on failure | ||
602 | */ | ||
603 | int group_action_send(const Messenger *m, int groupnumber, const uint8_t *action, uint32_t length); | ||
604 | 742 | ||
605 | /* Return the number of peers in the group chat on success. | 743 | /**********GROUP CHATS************/ |
606 | * return -1 on failure | ||
607 | */ | ||
608 | int group_number_peers(const Messenger *m, int groupnumber); | ||
609 | 744 | ||
610 | /* List all the peers in the group chat. | 745 | /* Set the callback for group invites. |
611 | * | ||
612 | * Copies the names of the peers to the name[length][MAX_NICK_BYTES] array. | ||
613 | * | ||
614 | * Copies the lengths of the names to lengths[length] | ||
615 | * | 746 | * |
616 | * returns the number of peers on success. | 747 | * Function(Messenger *m, uint32_t friendnumber, uint8_t *data, uint16_t length) |
748 | */ | ||
749 | void m_callback_group_invite(Messenger *m, void (*function)(Messenger *m, uint32_t, const uint8_t *, uint16_t)); | ||
750 | |||
751 | /* Send a group invite packet. | ||
617 | * | 752 | * |
618 | * return -1 on failure. | 753 | * return 1 on success |
754 | * return 0 on failure | ||
619 | */ | 755 | */ |
620 | int group_names(const Messenger *m, int groupnumber, uint8_t names[][MAX_NICK_BYTES], uint16_t lengths[], | 756 | int send_group_invite_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint16_t length); |
621 | uint16_t length); | ||
622 | 757 | ||
623 | /****************FILE SENDING*****************/ | 758 | /****************FILE SENDING*****************/ |
624 | 759 | ||
625 | 760 | ||
626 | /* Set the callback for file send requests. | 761 | /* Set the callback for file send requests. |
627 | * | 762 | * |
628 | * Function(Tox *tox, int32_t friendnumber, uint8_t filenumber, uint64_t filesize, uint8_t *filename, uint16_t filename_length, void *userdata) | 763 | * Function(Tox *tox, uint32_t friendnumber, uint8_t filenumber, uint64_t filesize, uint8_t *filename, uint16_t filename_length, void *userdata) |
629 | */ | 764 | */ |
630 | void callback_file_sendrequest(Messenger *m, void (*function)(Messenger *m, int32_t, uint8_t, uint64_t, const uint8_t *, | 765 | void callback_file_sendrequest(Messenger *m, void (*function)(Messenger *m, uint32_t, uint8_t, uint64_t, |
766 | const uint8_t *, | ||
631 | uint16_t, void *), void *userdata); | 767 | uint16_t, void *), void *userdata); |
632 | 768 | ||
633 | /* Set the callback for file control requests. | 769 | /* Set the callback for file control requests. |
634 | * | 770 | * |
635 | * Function(Tox *tox, int32_t friendnumber, uint8_t send_receive, uint8_t filenumber, uint8_t control_type, uint8_t *data, uint16_t length, void *userdata) | 771 | * Function(Tox *tox, uint32_t friendnumber, uint8_t send_receive, uint8_t filenumber, uint8_t control_type, uint8_t *data, uint16_t length, void *userdata) |
636 | * | 772 | * |
637 | */ | 773 | */ |
638 | void callback_file_control(Messenger *m, void (*function)(Messenger *m, int32_t, uint8_t, uint8_t, uint8_t, | 774 | void callback_file_control(Messenger *m, void (*function)(Messenger *m, uint32_t, uint8_t, uint8_t, uint8_t, |
639 | const uint8_t *, uint16_t, void *), void *userdata); | 775 | const uint8_t *, uint16_t, void *), void *userdata); |
640 | 776 | ||
641 | /* Set the callback for file data. | 777 | /* Set the callback for file data. |
642 | * | 778 | * |
643 | * Function(Tox *tox, int32_t friendnumber, uint8_t filenumber, uint8_t *data, uint16_t length, void *userdata) | 779 | * Function(Tox *tox, uint32_t friendnumber, uint8_t filenumber, uint8_t *data, uint16_t length, void *userdata) |
644 | * | 780 | * |
645 | */ | 781 | */ |
646 | void callback_file_data(Messenger *m, void (*function)(Messenger *m, int32_t, uint8_t, const uint8_t *, uint16_t length, | 782 | void callback_file_data(Messenger *m, void (*function)(Messenger *m, uint32_t, uint8_t, const uint8_t *, |
783 | uint16_t length, | ||
647 | void *), void *userdata); | 784 | void *), void *userdata); |
648 | 785 | ||
649 | /* Send a file send request. | 786 | /* Send a file send request. |
@@ -691,9 +828,9 @@ uint64_t file_dataremaining(const Messenger *m, int32_t friendnumber, uint8_t fi | |||
691 | 828 | ||
692 | /* Set the callback for msi packets. | 829 | /* Set the callback for msi packets. |
693 | * | 830 | * |
694 | * Function(Messenger *m, int32_t friendnumber, uint8_t *data, uint16_t length, void *userdata) | 831 | * Function(Messenger *m, uint32_t friendnumber, uint8_t *data, uint16_t length, void *userdata) |
695 | */ | 832 | */ |
696 | void m_callback_msi_packet(Messenger *m, void (*function)(Messenger *m, int32_t, const uint8_t *, uint16_t, void *), | 833 | void m_callback_msi_packet(Messenger *m, void (*function)(Messenger *m, uint32_t, const uint8_t *, uint16_t, void *), |
697 | void *userdata); | 834 | void *userdata); |
698 | 835 | ||
699 | /* Send an msi packet. | 836 | /* Send an msi packet. |
@@ -711,7 +848,8 @@ int m_msi_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, | |||
711 | * return 0 on success. | 848 | * return 0 on success. |
712 | */ | 849 | */ |
713 | int custom_lossy_packet_registerhandler(Messenger *m, int32_t friendnumber, uint8_t byte, | 850 | int custom_lossy_packet_registerhandler(Messenger *m, int32_t friendnumber, uint8_t byte, |
714 | int (*packet_handler_callback)(void *object, const uint8_t *data, uint32_t len), void *object); | 851 | int (*packet_handler_callback)(Messenger *m, uint32_t friendnumber, const uint8_t *data, uint32_t len, void *object), |
852 | void *object); | ||
715 | 853 | ||
716 | /* High level function to send custom lossy packets. | 854 | /* High level function to send custom lossy packets. |
717 | * | 855 | * |
@@ -729,7 +867,8 @@ int send_custom_lossy_packet(const Messenger *m, int32_t friendnumber, const uin | |||
729 | * return 0 on success. | 867 | * return 0 on success. |
730 | */ | 868 | */ |
731 | int custom_lossless_packet_registerhandler(Messenger *m, int32_t friendnumber, uint8_t byte, | 869 | int custom_lossless_packet_registerhandler(Messenger *m, int32_t friendnumber, uint8_t byte, |
732 | int (*packet_handler_callback)(void *object, const uint8_t *data, uint32_t len), void *object); | 870 | int (*packet_handler_callback)(Messenger *m, uint32_t friendnumber, const uint8_t *data, uint32_t len, void *object), |
871 | void *object); | ||
733 | 872 | ||
734 | /* High level function to send custom lossless packets. | 873 | /* High level function to send custom lossless packets. |
735 | * | 874 | * |
@@ -758,7 +897,7 @@ void do_messenger(Messenger *m); | |||
758 | * | 897 | * |
759 | * returns time (in ms) before the next do_messenger() needs to be run on success. | 898 | * returns time (in ms) before the next do_messenger() needs to be run on success. |
760 | */ | 899 | */ |
761 | uint32_t messenger_run_interval(Messenger *m); | 900 | uint32_t messenger_run_interval(const Messenger *m); |
762 | 901 | ||
763 | /* SAVING AND LOADING FUNCTIONS: */ | 902 | /* SAVING AND LOADING FUNCTIONS: */ |
764 | 903 | ||
@@ -784,26 +923,6 @@ uint32_t get_num_online_friends(const Messenger *m); | |||
784 | * Otherwise, returns the number of elements copied. | 923 | * Otherwise, returns the number of elements copied. |
785 | * If the array was too small, the contents | 924 | * If the array was too small, the contents |
786 | * of out_list will be truncated to list_size. */ | 925 | * of out_list will be truncated to list_size. */ |
787 | uint32_t copy_friendlist(const Messenger *m, int32_t *out_list, uint32_t list_size); | 926 | uint32_t copy_friendlist(const Messenger *m, uint32_t *out_list, uint32_t list_size); |
788 | |||
789 | /* Allocate and return a list of valid friend id's. List must be freed by the | ||
790 | * caller. | ||
791 | * | ||
792 | * retun 0 if success. | ||
793 | * return -1 if failure. | ||
794 | */ | ||
795 | int get_friendlist(const Messenger *m, int **out_list, uint32_t *out_list_length); | ||
796 | |||
797 | /* Return the number of chats in the instance m. | ||
798 | * You should use this to determine how much memory to allocate | ||
799 | * for copy_chatlist. */ | ||
800 | uint32_t count_chatlist(const Messenger *m); | ||
801 | |||
802 | /* Copy a list of valid chat IDs into the array out_list. | ||
803 | * If out_list is NULL, returns 0. | ||
804 | * Otherwise, returns the number of elements copied. | ||
805 | * If the array was too small, the contents | ||
806 | * of out_list will be truncated to list_size. */ | ||
807 | uint32_t copy_chatlist(const Messenger *m, int *out_list, uint32_t list_size); | ||
808 | 927 | ||
809 | #endif | 928 | #endif |
diff --git a/toxcore/TCP_client.c b/toxcore/TCP_client.c index f7b208e0..eaa248bf 100644 --- a/toxcore/TCP_client.c +++ b/toxcore/TCP_client.c | |||
@@ -37,10 +37,12 @@ | |||
37 | */ | 37 | */ |
38 | static int connect_sock_to(sock_t sock, IP_Port ip_port, TCP_Proxy_Info *proxy_info) | 38 | static int connect_sock_to(sock_t sock, IP_Port ip_port, TCP_Proxy_Info *proxy_info) |
39 | { | 39 | { |
40 | if (proxy_info) | 40 | if (proxy_info->proxy_type != TCP_PROXY_NONE) { |
41 | ip_port = proxy_info->ip_port; | 41 | ip_port = proxy_info->ip_port; |
42 | } | ||
42 | 43 | ||
43 | struct sockaddr_storage addr = {0}; | 44 | struct sockaddr_storage addr = {0}; |
45 | |||
44 | size_t addrsize; | 46 | size_t addrsize; |
45 | 47 | ||
46 | if (ip_port.ip.family == AF_INET) { | 48 | if (ip_port.ip.family == AF_INET) { |
@@ -66,8 +68,68 @@ static int connect_sock_to(sock_t sock, IP_Port ip_port, TCP_Proxy_Info *proxy_i | |||
66 | return 1; | 68 | return 1; |
67 | } | 69 | } |
68 | 70 | ||
71 | /* return 1 on success. | ||
72 | * return 0 on failure. | ||
73 | */ | ||
74 | static int proxy_http_generate_connection_request(TCP_Client_Connection *TCP_conn) | ||
75 | { | ||
76 | char one[] = "CONNECT "; | ||
77 | char two[] = " HTTP/1.1\nHost: "; | ||
78 | char three[] = "\r\n\r\n"; | ||
79 | |||
80 | char ip[INET6_ADDRSTRLEN]; | ||
81 | |||
82 | if (!ip_parse_addr(&TCP_conn->ip_port.ip, ip, sizeof(ip))) { | ||
83 | return 0; | ||
84 | } | ||
69 | 85 | ||
70 | static void socks5_generate_handshake(TCP_Client_Connection *TCP_conn) | 86 | const uint16_t port = ntohs(TCP_conn->ip_port.port); |
87 | const int written = snprintf((char *)TCP_conn->last_packet, MAX_PACKET_SIZE, "%s%s:%hu%s%s:%hu%s", one, ip, port, two, | ||
88 | ip, port, three); | ||
89 | |||
90 | if (written < 0) { | ||
91 | return 0; | ||
92 | } | ||
93 | |||
94 | TCP_conn->last_packet_length = written; | ||
95 | TCP_conn->last_packet_sent = 0; | ||
96 | |||
97 | return 1; | ||
98 | } | ||
99 | |||
100 | /* return 1 on success. | ||
101 | * return 0 if no data received. | ||
102 | * return -1 on failure (connection refused). | ||
103 | */ | ||
104 | static int proxy_http_read_connection_response(TCP_Client_Connection *TCP_conn) | ||
105 | { | ||
106 | char success[] = "200"; | ||
107 | uint8_t data[16]; // draining works the best if the length is a power of 2 | ||
108 | |||
109 | int ret = read_TCP_packet(TCP_conn->sock, data, sizeof(data) - 1); | ||
110 | |||
111 | if (ret == -1) { | ||
112 | return 0; | ||
113 | } | ||
114 | |||
115 | data[sizeof(data) - 1] = 0; | ||
116 | |||
117 | if (strstr((char *)data, success)) { | ||
118 | // drain all data | ||
119 | unsigned int data_left = TCP_socket_data_recv_buffer(TCP_conn->sock); | ||
120 | |||
121 | if (data_left) { | ||
122 | uint8_t temp_data[data_left]; | ||
123 | read_TCP_packet(TCP_conn->sock, temp_data, data_left); | ||
124 | } | ||
125 | |||
126 | return 1; | ||
127 | } | ||
128 | |||
129 | return -1; | ||
130 | } | ||
131 | |||
132 | static void proxy_socks5_generate_handshake(TCP_Client_Connection *TCP_conn) | ||
71 | { | 133 | { |
72 | TCP_conn->last_packet[0] = 5; /* SOCKSv5 */ | 134 | TCP_conn->last_packet[0] = 5; /* SOCKSv5 */ |
73 | TCP_conn->last_packet[1] = 1; /* number of authentication methods supported */ | 135 | TCP_conn->last_packet[1] = 1; /* number of authentication methods supported */ |
@@ -95,7 +157,7 @@ static int socks5_read_handshake_response(TCP_Client_Connection *TCP_conn) | |||
95 | return -1; | 157 | return -1; |
96 | } | 158 | } |
97 | 159 | ||
98 | static void socks5_generate_connection_request(TCP_Client_Connection *TCP_conn) | 160 | static void proxy_socks5_generate_connection_request(TCP_Client_Connection *TCP_conn) |
99 | { | 161 | { |
100 | TCP_conn->last_packet[0] = 5; /* SOCKSv5 */ | 162 | TCP_conn->last_packet[0] = 5; /* SOCKSv5 */ |
101 | TCP_conn->last_packet[1] = 1; /* command code: establish a TCP/IP stream connection */ | 163 | TCP_conn->last_packet[1] = 1; /* command code: establish a TCP/IP stream connection */ |
@@ -125,7 +187,7 @@ static void socks5_generate_connection_request(TCP_Client_Connection *TCP_conn) | |||
125 | * return 0 if no data received. | 187 | * return 0 if no data received. |
126 | * return -1 on failure (connection refused). | 188 | * return -1 on failure (connection refused). |
127 | */ | 189 | */ |
128 | static int socks5_read_connection_response(TCP_Client_Connection *TCP_conn) | 190 | static int proxy_socks5_read_connection_response(TCP_Client_Connection *TCP_conn) |
129 | { | 191 | { |
130 | if (TCP_conn->ip_port.ip.family == AF_INET) { | 192 | if (TCP_conn->ip_port.ip.family == AF_INET) { |
131 | uint8_t data[4 + sizeof(IP4) + sizeof(uint16_t)]; | 193 | uint8_t data[4 + sizeof(IP4) + sizeof(uint16_t)]; |
@@ -322,7 +384,7 @@ static int write_packet_TCP_secure_connection(TCP_Client_Connection *con, const | |||
322 | 384 | ||
323 | increment_nonce(con->sent_nonce); | 385 | increment_nonce(con->sent_nonce); |
324 | 386 | ||
325 | if (len == sizeof(packet)) { | 387 | if ((unsigned int)len == sizeof(packet)) { |
326 | return 1; | 388 | return 1; |
327 | } | 389 | } |
328 | 390 | ||
@@ -546,8 +608,16 @@ TCP_Client_Connection *new_TCP_connection(IP_Port ip_port, const uint8_t *public | |||
546 | 608 | ||
547 | uint8_t family = ip_port.ip.family; | 609 | uint8_t family = ip_port.ip.family; |
548 | 610 | ||
549 | if (proxy_info) | 611 | TCP_Proxy_Info default_proxyinfo; |
612 | |||
613 | if (proxy_info == NULL) { | ||
614 | default_proxyinfo.proxy_type = TCP_PROXY_NONE; | ||
615 | proxy_info = &default_proxyinfo; | ||
616 | } | ||
617 | |||
618 | if (proxy_info->proxy_type != TCP_PROXY_NONE) { | ||
550 | family = proxy_info->ip_port.ip.family; | 619 | family = proxy_info->ip_port.ip.family; |
620 | } | ||
551 | 621 | ||
552 | sock_t sock = socket(family, SOCK_STREAM, IPPROTO_TCP); | 622 | sock_t sock = socket(family, SOCK_STREAM, IPPROTO_TCP); |
553 | 623 | ||
@@ -577,19 +647,29 @@ TCP_Client_Connection *new_TCP_connection(IP_Port ip_port, const uint8_t *public | |||
577 | memcpy(temp->self_public_key, self_public_key, crypto_box_PUBLICKEYBYTES); | 647 | memcpy(temp->self_public_key, self_public_key, crypto_box_PUBLICKEYBYTES); |
578 | encrypt_precompute(temp->public_key, self_secret_key, temp->shared_key); | 648 | encrypt_precompute(temp->public_key, self_secret_key, temp->shared_key); |
579 | temp->ip_port = ip_port; | 649 | temp->ip_port = ip_port; |
650 | temp->proxy_info = *proxy_info; | ||
580 | 651 | ||
581 | if (proxy_info) { | 652 | switch (proxy_info->proxy_type) { |
582 | temp->status = TCP_CLIENT_PROXY_CONNECTING; | 653 | case TCP_PROXY_HTTP: |
583 | temp->proxy_info = *proxy_info; | 654 | temp->status = TCP_CLIENT_PROXY_HTTP_CONNECTING; |
584 | socks5_generate_handshake(temp); | 655 | proxy_http_generate_connection_request(temp); |
585 | } else { | 656 | break; |
586 | temp->status = TCP_CLIENT_CONNECTING; | ||
587 | 657 | ||
588 | if (generate_handshake(temp) == -1) { | 658 | case TCP_PROXY_SOCKS5: |
589 | kill_sock(sock); | 659 | temp->status = TCP_CLIENT_PROXY_SOCKS5_CONNECTING; |
590 | free(temp); | 660 | proxy_socks5_generate_handshake(temp); |
591 | return NULL; | 661 | break; |
592 | } | 662 | |
663 | case TCP_PROXY_NONE: | ||
664 | temp->status = TCP_CLIENT_CONNECTING; | ||
665 | |||
666 | if (generate_handshake(temp) == -1) { | ||
667 | kill_sock(sock); | ||
668 | free(temp); | ||
669 | return NULL; | ||
670 | } | ||
671 | |||
672 | break; | ||
593 | } | 673 | } |
594 | 674 | ||
595 | temp->kill_at = unix_time() + TCP_CONNECTION_TIMEOUT; | 675 | temp->kill_at = unix_time() + TCP_CONNECTION_TIMEOUT; |
@@ -783,7 +863,23 @@ void do_TCP_connection(TCP_Client_Connection *TCP_connection) | |||
783 | return; | 863 | return; |
784 | } | 864 | } |
785 | 865 | ||
786 | if (TCP_connection->status == TCP_CLIENT_PROXY_CONNECTING) { | 866 | if (TCP_connection->status == TCP_CLIENT_PROXY_HTTP_CONNECTING) { |
867 | if (send_pending_data(TCP_connection) == 0) { | ||
868 | int ret = proxy_http_read_connection_response(TCP_connection); | ||
869 | |||
870 | if (ret == -1) { | ||
871 | TCP_connection->kill_at = 0; | ||
872 | TCP_connection->status = TCP_CLIENT_DISCONNECTED; | ||
873 | } | ||
874 | |||
875 | if (ret == 1) { | ||
876 | generate_handshake(TCP_connection); | ||
877 | TCP_connection->status = TCP_CLIENT_CONNECTING; | ||
878 | } | ||
879 | } | ||
880 | } | ||
881 | |||
882 | if (TCP_connection->status == TCP_CLIENT_PROXY_SOCKS5_CONNECTING) { | ||
787 | if (send_pending_data(TCP_connection) == 0) { | 883 | if (send_pending_data(TCP_connection) == 0) { |
788 | int ret = socks5_read_handshake_response(TCP_connection); | 884 | int ret = socks5_read_handshake_response(TCP_connection); |
789 | 885 | ||
@@ -793,15 +889,15 @@ void do_TCP_connection(TCP_Client_Connection *TCP_connection) | |||
793 | } | 889 | } |
794 | 890 | ||
795 | if (ret == 1) { | 891 | if (ret == 1) { |
796 | socks5_generate_connection_request(TCP_connection); | 892 | proxy_socks5_generate_connection_request(TCP_connection); |
797 | TCP_connection->status = TCP_CLIENT_PROXY_UNCONFIRMED; | 893 | TCP_connection->status = TCP_CLIENT_PROXY_SOCKS5_UNCONFIRMED; |
798 | } | 894 | } |
799 | } | 895 | } |
800 | } | 896 | } |
801 | 897 | ||
802 | if (TCP_connection->status == TCP_CLIENT_PROXY_UNCONFIRMED) { | 898 | if (TCP_connection->status == TCP_CLIENT_PROXY_SOCKS5_UNCONFIRMED) { |
803 | if (send_pending_data(TCP_connection) == 0) { | 899 | if (send_pending_data(TCP_connection) == 0) { |
804 | int ret = socks5_read_connection_response(TCP_connection); | 900 | int ret = proxy_socks5_read_connection_response(TCP_connection); |
805 | 901 | ||
806 | if (ret == -1) { | 902 | if (ret == -1) { |
807 | TCP_connection->kill_at = 0; | 903 | TCP_connection->kill_at = 0; |
diff --git a/toxcore/TCP_client.h b/toxcore/TCP_client.h index 83cb48ba..e37a4ee0 100644 --- a/toxcore/TCP_client.h +++ b/toxcore/TCP_client.h | |||
@@ -29,14 +29,22 @@ | |||
29 | 29 | ||
30 | #define TCP_CONNECTION_TIMEOUT 10 | 30 | #define TCP_CONNECTION_TIMEOUT 10 |
31 | 31 | ||
32 | typedef struct { | 32 | typedef enum { |
33 | TCP_PROXY_NONE, | ||
34 | TCP_PROXY_HTTP, | ||
35 | TCP_PROXY_SOCKS5 | ||
36 | } TCP_PROXY_TYPE; | ||
37 | |||
38 | typedef struct { | ||
33 | IP_Port ip_port; | 39 | IP_Port ip_port; |
40 | uint8_t proxy_type; // a value from TCP_PROXY_TYPE | ||
34 | } TCP_Proxy_Info; | 41 | } TCP_Proxy_Info; |
35 | 42 | ||
36 | enum { | 43 | enum { |
37 | TCP_CLIENT_NO_STATUS, | 44 | TCP_CLIENT_NO_STATUS, |
38 | TCP_CLIENT_PROXY_CONNECTING, | 45 | TCP_CLIENT_PROXY_HTTP_CONNECTING, |
39 | TCP_CLIENT_PROXY_UNCONFIRMED, | 46 | TCP_CLIENT_PROXY_SOCKS5_CONNECTING, |
47 | TCP_CLIENT_PROXY_SOCKS5_UNCONFIRMED, | ||
40 | TCP_CLIENT_CONNECTING, | 48 | TCP_CLIENT_CONNECTING, |
41 | TCP_CLIENT_UNCONFIRMED, | 49 | TCP_CLIENT_UNCONFIRMED, |
42 | TCP_CLIENT_CONFIRMED, | 50 | TCP_CLIENT_CONFIRMED, |
diff --git a/toxcore/TCP_server.c b/toxcore/TCP_server.c index b1f7e04b..e1c1c85c 100644 --- a/toxcore/TCP_server.c +++ b/toxcore/TCP_server.c | |||
@@ -178,14 +178,10 @@ static int del_accepted(TCP_Server *TCP_server, int index) | |||
178 | return 0; | 178 | return 0; |
179 | } | 179 | } |
180 | 180 | ||
181 | /* Read the next two bytes in TCP stream then convert them to | 181 | /* return the amount of data in the tcp recv buffer. |
182 | * length (host byte order). | 182 | * return 0 on failure. |
183 | * | ||
184 | * return length on success | ||
185 | * return 0 if nothing has been read from socket. | ||
186 | * return ~0 on failure. | ||
187 | */ | 183 | */ |
188 | uint16_t read_TCP_length(sock_t sock) | 184 | unsigned int TCP_socket_data_recv_buffer(sock_t sock) |
189 | { | 185 | { |
190 | #if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) | 186 | #if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) |
191 | unsigned long count = 0; | 187 | unsigned long count = 0; |
@@ -195,7 +191,21 @@ uint16_t read_TCP_length(sock_t sock) | |||
195 | ioctl(sock, FIONREAD, &count); | 191 | ioctl(sock, FIONREAD, &count); |
196 | #endif | 192 | #endif |
197 | 193 | ||
198 | if ((unsigned int)count >= sizeof(uint16_t)) { | 194 | return count; |
195 | } | ||
196 | |||
197 | /* Read the next two bytes in TCP stream then convert them to | ||
198 | * length (host byte order). | ||
199 | * | ||
200 | * return length on success | ||
201 | * return 0 if nothing has been read from socket. | ||
202 | * return ~0 on failure. | ||
203 | */ | ||
204 | uint16_t read_TCP_length(sock_t sock) | ||
205 | { | ||
206 | unsigned int count = TCP_socket_data_recv_buffer(sock); | ||
207 | |||
208 | if (count >= sizeof(uint16_t)) { | ||
199 | uint16_t length; | 209 | uint16_t length; |
200 | int len = recv(sock, (uint8_t *)&length, sizeof(uint16_t), MSG_NOSIGNAL); | 210 | int len = recv(sock, (uint8_t *)&length, sizeof(uint16_t), MSG_NOSIGNAL); |
201 | 211 | ||
@@ -223,13 +233,7 @@ uint16_t read_TCP_length(sock_t sock) | |||
223 | */ | 233 | */ |
224 | int read_TCP_packet(sock_t sock, uint8_t *data, uint16_t length) | 234 | int read_TCP_packet(sock_t sock, uint8_t *data, uint16_t length) |
225 | { | 235 | { |
226 | #if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) | 236 | unsigned int count = TCP_socket_data_recv_buffer(sock); |
227 | unsigned long count = 0; | ||
228 | ioctlsocket(sock, FIONREAD, &count); | ||
229 | #else | ||
230 | int count = 0; | ||
231 | ioctl(sock, FIONREAD, &count); | ||
232 | #endif | ||
233 | 237 | ||
234 | if (count >= length) { | 238 | if (count >= length) { |
235 | int len = recv(sock, data, length, MSG_NOSIGNAL); | 239 | int len = recv(sock, data, length, MSG_NOSIGNAL); |
@@ -415,7 +419,7 @@ static int write_packet_TCP_secure_connection(TCP_Secure_Connection *con, const | |||
415 | 419 | ||
416 | increment_nonce(con->sent_nonce); | 420 | increment_nonce(con->sent_nonce); |
417 | 421 | ||
418 | if (len == sizeof(packet)) { | 422 | if ((unsigned int)len == sizeof(packet)) { |
419 | return 1; | 423 | return 1; |
420 | } | 424 | } |
421 | 425 | ||
@@ -805,8 +809,10 @@ static int handle_TCP_packet(TCP_Server *TCP_server, uint32_t con_id, const uint | |||
805 | return -1; | 809 | return -1; |
806 | 810 | ||
807 | IP_Port source; | 811 | IP_Port source; |
812 | source.port = 0; // dummy initialise | ||
808 | source.ip.family = TCP_ONION_FAMILY; | 813 | source.ip.family = TCP_ONION_FAMILY; |
809 | source.ip.ip6.uint32[0] = con_id; | 814 | source.ip.ip6.uint32[0] = con_id; |
815 | source.ip.ip6.uint32[1] = 0; | ||
810 | source.ip.ip6.uint64[1] = con->identifier; | 816 | source.ip.ip6.uint64[1] = con->identifier; |
811 | onion_send_1(TCP_server->onion, data + 1 + crypto_box_NONCEBYTES, length - (1 + crypto_box_NONCEBYTES), source, | 817 | onion_send_1(TCP_server->onion, data + 1 + crypto_box_NONCEBYTES, length - (1 + crypto_box_NONCEBYTES), source, |
812 | data + 1); | 818 | data + 1); |
@@ -1328,5 +1334,6 @@ void kill_TCP_server(TCP_Server *TCP_server) | |||
1328 | #endif | 1334 | #endif |
1329 | 1335 | ||
1330 | free(TCP_server->socks_listening); | 1336 | free(TCP_server->socks_listening); |
1337 | free(TCP_server->accepted_connection_array); | ||
1331 | free(TCP_server); | 1338 | free(TCP_server); |
1332 | } | 1339 | } |
diff --git a/toxcore/TCP_server.h b/toxcore/TCP_server.h index 81507acb..727c4b4e 100644 --- a/toxcore/TCP_server.h +++ b/toxcore/TCP_server.h | |||
@@ -35,7 +35,7 @@ | |||
35 | #define MSG_NOSIGNAL 0 | 35 | #define MSG_NOSIGNAL 0 |
36 | #endif | 36 | #endif |
37 | 37 | ||
38 | #define MAX_INCOMMING_CONNECTIONS 32 | 38 | #define MAX_INCOMMING_CONNECTIONS 256 |
39 | 39 | ||
40 | #define TCP_MAX_BACKLOG MAX_INCOMMING_CONNECTIONS | 40 | #define TCP_MAX_BACKLOG MAX_INCOMMING_CONNECTIONS |
41 | 41 | ||
@@ -154,6 +154,11 @@ void do_TCP_server(TCP_Server *TCP_server); | |||
154 | */ | 154 | */ |
155 | void kill_TCP_server(TCP_Server *TCP_server); | 155 | void kill_TCP_server(TCP_Server *TCP_server); |
156 | 156 | ||
157 | /* return the amount of data in the tcp recv buffer. | ||
158 | * return 0 on failure. | ||
159 | */ | ||
160 | unsigned int TCP_socket_data_recv_buffer(sock_t sock); | ||
161 | |||
157 | /* Read the next two bytes in TCP stream then convert them to | 162 | /* Read the next two bytes in TCP stream then convert them to |
158 | * length (host byte order). | 163 | * length (host byte order). |
159 | * | 164 | * |
diff --git a/toxcore/assoc.c b/toxcore/assoc.c index 4d837aa3..3dbeba51 100644 --- a/toxcore/assoc.c +++ b/toxcore/assoc.c | |||
@@ -831,8 +831,20 @@ Assoc *new_Assoc(size_t bits, size_t entries, const uint8_t *public_id) | |||
831 | /* allocation: preferably few blobs */ | 831 | /* allocation: preferably few blobs */ |
832 | size_t bckt, cix; | 832 | size_t bckt, cix; |
833 | Client_entry *clients = malloc(sizeof(*clients) * assoc->candidates_bucket_count * assoc->candidates_bucket_size); | 833 | Client_entry *clients = malloc(sizeof(*clients) * assoc->candidates_bucket_count * assoc->candidates_bucket_size); |
834 | |||
835 | if (!clients) { | ||
836 | free(assoc); | ||
837 | return NULL; | ||
838 | } | ||
839 | |||
834 | candidates_bucket *lists = malloc(sizeof(*lists) * assoc->candidates_bucket_count); | 840 | candidates_bucket *lists = malloc(sizeof(*lists) * assoc->candidates_bucket_count); |
835 | 841 | ||
842 | if (!lists) { | ||
843 | free(assoc); | ||
844 | free(clients); | ||
845 | return NULL; | ||
846 | } | ||
847 | |||
836 | for (bckt = 0; bckt < assoc->candidates_bucket_count; bckt++) { | 848 | for (bckt = 0; bckt < assoc->candidates_bucket_count; bckt++) { |
837 | candidates_bucket *list = &lists[bckt]; | 849 | candidates_bucket *list = &lists[bckt]; |
838 | 850 | ||
@@ -984,11 +996,11 @@ static char *idpart2str(uint8_t *id, size_t len) | |||
984 | void Assoc_status(const Assoc *assoc) | 996 | void Assoc_status(const Assoc *assoc) |
985 | { | 997 | { |
986 | if (!assoc) { | 998 | if (!assoc) { |
987 | LOGGER_INFO("Assoc status: no assoc"); | 999 | LOGGER_TRACE("Assoc status: no assoc"); |
988 | return; | 1000 | return; |
989 | } | 1001 | } |
990 | 1002 | ||
991 | LOGGER_INFO("[b:p] hash => [id...] used, seen, heard"); | 1003 | LOGGER_TRACE("[b:p] hash => [id...] used, seen, heard"); |
992 | 1004 | ||
993 | size_t bid, cid, total = 0; | 1005 | size_t bid, cid, total = 0; |
994 | 1006 | ||
@@ -1001,20 +1013,20 @@ void Assoc_status(const Assoc *assoc) | |||
1001 | if (entry->hash) { | 1013 | if (entry->hash) { |
1002 | total++; | 1014 | total++; |
1003 | 1015 | ||
1004 | LOGGER_INFO("[%3i:%3i] %08x => [%s...] %i, %i(%c), %i(%c)\n", | 1016 | LOGGER_TRACE("[%3i:%3i] %08x => [%s...] %i, %i(%c), %i(%c)\n", |
1005 | (int)bid, (int)cid, entry->hash, idpart2str(entry->client.client_id, 8), | 1017 | (int)bid, (int)cid, entry->hash, idpart2str(entry->client.client_id, 8), |
1006 | entry->used_at ? (int)(unix_time() - entry->used_at) : 0, | 1018 | entry->used_at ? (int)(unix_time() - entry->used_at) : 0, |
1007 | entry->seen_at ? (int)(unix_time() - entry->seen_at) : 0, | 1019 | entry->seen_at ? (int)(unix_time() - entry->seen_at) : 0, |
1008 | entry->seen_at ? (entry->seen_family == AF_INET ? '4' : (entry->seen_family == AF_INET6 ? '6' : '?')) : '?', | 1020 | entry->seen_at ? (entry->seen_family == AF_INET ? '4' : (entry->seen_family == AF_INET6 ? '6' : '?')) : '?', |
1009 | entry->heard_at ? (int)(unix_time() - entry->heard_at) : 0, | 1021 | entry->heard_at ? (int)(unix_time() - entry->heard_at) : 0, |
1010 | entry->heard_at ? (entry->heard_family == AF_INET ? '4' : (entry->heard_family == AF_INET6 ? '6' : '?')) : '?'); | 1022 | entry->heard_at ? (entry->heard_family == AF_INET ? '4' : (entry->heard_family == AF_INET6 ? '6' : '?')) : '?'); |
1011 | } | 1023 | } |
1012 | } | 1024 | } |
1013 | } | 1025 | } |
1014 | 1026 | ||
1015 | if (total) { | 1027 | if (total) { |
1016 | LOGGER_INFO("Total: %i entries, table usage %i%%.\n", (int)total, | 1028 | LOGGER_TRACE("Total: %i entries, table usage %i%%.\n", (int)total, |
1017 | (int)(total * 100 / (assoc->candidates_bucket_count * assoc->candidates_bucket_size))); | 1029 | (int)(total * 100 / (assoc->candidates_bucket_count * assoc->candidates_bucket_size))); |
1018 | } | 1030 | } |
1019 | } | 1031 | } |
1020 | 1032 | ||
diff --git a/toxcore/crypto_core.c b/toxcore/crypto_core.c index 1799b600..5c99a378 100644 --- a/toxcore/crypto_core.c +++ b/toxcore/crypto_core.c | |||
@@ -33,7 +33,7 @@ | |||
33 | /* Use this instead of memcmp; not vulnerable to timing attacks. | 33 | /* Use this instead of memcmp; not vulnerable to timing attacks. |
34 | returns 0 if both mem locations of length are equal, | 34 | returns 0 if both mem locations of length are equal, |
35 | return -1 if they are not. */ | 35 | return -1 if they are not. */ |
36 | int crypto_cmp(const uint8_t *mem1, const uint8_t *mem2, uint32_t length) | 36 | int crypto_cmp(const uint8_t *mem1, const uint8_t *mem2, size_t length) |
37 | { | 37 | { |
38 | if (length == 16) { | 38 | if (length == 16) { |
39 | return crypto_verify_16(mem1, mem2); | 39 | return crypto_verify_16(mem1, mem2); |
@@ -41,7 +41,8 @@ int crypto_cmp(const uint8_t *mem1, const uint8_t *mem2, uint32_t length) | |||
41 | return crypto_verify_32(mem1, mem2); | 41 | return crypto_verify_32(mem1, mem2); |
42 | } | 42 | } |
43 | 43 | ||
44 | unsigned int i, check = 0; | 44 | unsigned int check = 0; |
45 | size_t i; | ||
45 | 46 | ||
46 | for (i = 0; i < length; ++i) { | 47 | for (i = 0; i < length; ++i) { |
47 | check |= mem1[i] ^ mem2[i]; | 48 | check |= mem1[i] ^ mem2[i]; |
@@ -210,7 +211,7 @@ void new_nonce(uint8_t *nonce) | |||
210 | 211 | ||
211 | /* Create a request to peer. | 212 | /* Create a request to peer. |
212 | * send_public_key and send_secret_key are the pub/secret keys of the sender. | 213 | * send_public_key and send_secret_key are the pub/secret keys of the sender. |
213 | * recv_public_key is public key of reciever. | 214 | * recv_public_key is public key of receiver. |
214 | * packet must be an array of MAX_CRYPTO_REQUEST_SIZE big. | 215 | * packet must be an array of MAX_CRYPTO_REQUEST_SIZE big. |
215 | * Data represents the data we send with the request with length being the length of the data. | 216 | * Data represents the data we send with the request with length being the length of the data. |
216 | * request_id is the id of the request (32 = friend request, 254 = ping request). | 217 | * request_id is the id of the request (32 = friend request, 254 = ping request). |
diff --git a/toxcore/crypto_core.h b/toxcore/crypto_core.h index 7362d49e..decc7fb9 100644 --- a/toxcore/crypto_core.h +++ b/toxcore/crypto_core.h | |||
@@ -43,7 +43,7 @@ | |||
43 | /* Use this instead of memcmp; not vulnerable to timing attacks. | 43 | /* Use this instead of memcmp; not vulnerable to timing attacks. |
44 | returns 0 if both mem locations of length are equal, | 44 | returns 0 if both mem locations of length are equal, |
45 | return -1 if they are not. */ | 45 | return -1 if they are not. */ |
46 | int crypto_cmp(const uint8_t *mem1, const uint8_t *mem2, uint32_t length); | 46 | int crypto_cmp(const uint8_t *mem1, const uint8_t *mem2, size_t length); |
47 | 47 | ||
48 | /* return a random number. | 48 | /* return a random number. |
49 | * | 49 | * |
@@ -122,14 +122,12 @@ void new_nonce(uint8_t *nonce); | |||
122 | 122 | ||
123 | #define CRYPTO_PACKET_FRIEND_REQ 32 /* Friend request crypto packet ID. */ | 123 | #define CRYPTO_PACKET_FRIEND_REQ 32 /* Friend request crypto packet ID. */ |
124 | #define CRYPTO_PACKET_HARDENING 48 /* Hardening crypto packet ID. */ | 124 | #define CRYPTO_PACKET_HARDENING 48 /* Hardening crypto packet ID. */ |
125 | #define CRYPTO_PACKET_DHTPK 156 | ||
125 | #define CRYPTO_PACKET_NAT_PING 254 /* NAT ping crypto packet ID. */ | 126 | #define CRYPTO_PACKET_NAT_PING 254 /* NAT ping crypto packet ID. */ |
126 | #define CRYPTO_PACKET_GROUP_CHAT_GET_NODES 48 /* Group chat get Nodes packet */ | ||
127 | #define CRYPTO_PACKET_GROUP_CHAT_SEND_NODES 49 /* Group chat send Nodes packet */ | ||
128 | #define CRYPTO_PACKET_GROUP_CHAT_BROADCAST 50 /* Group chat broadcast packet */ | ||
129 | 127 | ||
130 | /* Create a request to peer. | 128 | /* Create a request to peer. |
131 | * send_public_key and send_secret_key are the pub/secret keys of the sender. | 129 | * send_public_key and send_secret_key are the pub/secret keys of the sender. |
132 | * recv_public_key is public key of reciever. | 130 | * recv_public_key is public key of receiver. |
133 | * packet must be an array of MAX_CRYPTO_REQUEST_SIZE big. | 131 | * packet must be an array of MAX_CRYPTO_REQUEST_SIZE big. |
134 | * Data represents the data we send with the request with length being the length of the data. | 132 | * Data represents the data we send with the request with length being the length of the data. |
135 | * request_id is the id of the request (32 = friend request, 254 = ping request). | 133 | * request_id is the id of the request (32 = friend request, 254 = ping request). |
diff --git a/toxcore/friend_connection.c b/toxcore/friend_connection.c new file mode 100644 index 00000000..588f0d6a --- /dev/null +++ b/toxcore/friend_connection.c | |||
@@ -0,0 +1,688 @@ | |||
1 | /* friend_connection.c | ||
2 | * | ||
3 | * Connection to friends. | ||
4 | * | ||
5 | * Copyright (C) 2014 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_connection.h" | ||
29 | #include "util.h" | ||
30 | |||
31 | /* return 1 if the friendcon_id is not valid. | ||
32 | * return 0 if the friendcon_id is valid. | ||
33 | */ | ||
34 | static uint8_t friendconn_id_not_valid(const Friend_Connections *fr_c, int friendcon_id) | ||
35 | { | ||
36 | if ((unsigned int)friendcon_id >= fr_c->num_cons) | ||
37 | return 1; | ||
38 | |||
39 | if (fr_c->conns == NULL) | ||
40 | return 1; | ||
41 | |||
42 | if (fr_c->conns[friendcon_id].status == FRIENDCONN_STATUS_NONE) | ||
43 | return 1; | ||
44 | |||
45 | return 0; | ||
46 | } | ||
47 | |||
48 | |||
49 | /* Set the size of the friend connections list to num. | ||
50 | * | ||
51 | * return -1 if realloc fails. | ||
52 | * return 0 if it succeeds. | ||
53 | */ | ||
54 | static int realloc_friendconns(Friend_Connections *fr_c, uint32_t num) | ||
55 | { | ||
56 | if (num == 0) { | ||
57 | free(fr_c->conns); | ||
58 | fr_c->conns = NULL; | ||
59 | return 0; | ||
60 | } | ||
61 | |||
62 | Friend_Conn *newgroup_cons = realloc(fr_c->conns, num * sizeof(Friend_Conn)); | ||
63 | |||
64 | if (newgroup_cons == NULL) | ||
65 | return -1; | ||
66 | |||
67 | fr_c->conns = newgroup_cons; | ||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | /* Create a new empty friend connection. | ||
72 | * | ||
73 | * return -1 on failure. | ||
74 | * return friendcon_id on success. | ||
75 | */ | ||
76 | static int create_friend_conn(Friend_Connections *fr_c) | ||
77 | { | ||
78 | uint32_t i; | ||
79 | |||
80 | for (i = 0; i < fr_c->num_cons; ++i) { | ||
81 | if (fr_c->conns[i].status == FRIENDCONN_STATUS_NONE) | ||
82 | return i; | ||
83 | } | ||
84 | |||
85 | int id = -1; | ||
86 | |||
87 | if (realloc_friendconns(fr_c, fr_c->num_cons + 1) == 0) { | ||
88 | id = fr_c->num_cons; | ||
89 | ++fr_c->num_cons; | ||
90 | memset(&(fr_c->conns[id]), 0, sizeof(Friend_Conn)); | ||
91 | } | ||
92 | |||
93 | return id; | ||
94 | } | ||
95 | |||
96 | /* Wipe a friend connection. | ||
97 | * | ||
98 | * return -1 on failure. | ||
99 | * return 0 on success. | ||
100 | */ | ||
101 | static int wipe_friend_conn(Friend_Connections *fr_c, int friendcon_id) | ||
102 | { | ||
103 | if (friendconn_id_not_valid(fr_c, friendcon_id)) | ||
104 | return -1; | ||
105 | |||
106 | uint32_t i; | ||
107 | memset(&(fr_c->conns[friendcon_id]), 0 , sizeof(Friend_Conn)); | ||
108 | |||
109 | for (i = fr_c->num_cons; i != 0; --i) { | ||
110 | if (fr_c->conns[i - 1].status != FRIENDCONN_STATUS_NONE) | ||
111 | break; | ||
112 | } | ||
113 | |||
114 | if (fr_c->num_cons != i) { | ||
115 | fr_c->num_cons = i; | ||
116 | realloc_friendconns(fr_c, fr_c->num_cons); | ||
117 | } | ||
118 | |||
119 | return 0; | ||
120 | } | ||
121 | |||
122 | static Friend_Conn *get_conn(const Friend_Connections *fr_c, int friendcon_id) | ||
123 | { | ||
124 | if (friendconn_id_not_valid(fr_c, friendcon_id)) | ||
125 | return 0; | ||
126 | |||
127 | return &fr_c->conns[friendcon_id]; | ||
128 | } | ||
129 | |||
130 | /* return friendcon_id corresponding to the real public key on success. | ||
131 | * return -1 on failure. | ||
132 | */ | ||
133 | int getfriend_conn_id_pk(Friend_Connections *fr_c, const uint8_t *real_pk) | ||
134 | { | ||
135 | uint32_t i; | ||
136 | |||
137 | for (i = 0; i < fr_c->num_cons; ++i) { | ||
138 | Friend_Conn *friend_con = get_conn(fr_c, i); | ||
139 | |||
140 | if (friend_con) { | ||
141 | if (memcmp(friend_con->real_public_key, real_pk, crypto_box_PUBLICKEYBYTES) == 0) | ||
142 | return i; | ||
143 | } | ||
144 | } | ||
145 | |||
146 | return -1; | ||
147 | } | ||
148 | |||
149 | /* callback for recv TCP relay nodes. */ | ||
150 | static int tcp_relay_node_callback(void *object, uint32_t number, IP_Port ip_port, const uint8_t *public_key) | ||
151 | { | ||
152 | Friend_Connections *fr_c = object; | ||
153 | Friend_Conn *friend_con = get_conn(fr_c, number); | ||
154 | |||
155 | if (!friend_con) | ||
156 | return -1; | ||
157 | |||
158 | if (friend_con->crypt_connection_id != -1) { | ||
159 | return add_tcp_relay_peer(fr_c->net_crypto, friend_con->crypt_connection_id, ip_port, public_key); | ||
160 | } else { | ||
161 | return add_tcp_relay(fr_c->net_crypto, ip_port, public_key); | ||
162 | } | ||
163 | } | ||
164 | |||
165 | static int friend_new_connection(Friend_Connections *fr_c, int friendcon_id); | ||
166 | /* Callback for DHT ip_port changes. */ | ||
167 | static void dht_ip_callback(void *object, int32_t number, IP_Port ip_port) | ||
168 | { | ||
169 | Friend_Connections *fr_c = object; | ||
170 | Friend_Conn *friend_con = get_conn(fr_c, number); | ||
171 | |||
172 | if (!friend_con) | ||
173 | return; | ||
174 | |||
175 | if (friend_con->crypt_connection_id == -1) { | ||
176 | friend_new_connection(fr_c, number); | ||
177 | } | ||
178 | |||
179 | set_direct_ip_port(fr_c->net_crypto, friend_con->crypt_connection_id, ip_port); | ||
180 | friend_con->dht_ip_port = ip_port; | ||
181 | friend_con->dht_ip_port_lastrecv = unix_time(); | ||
182 | } | ||
183 | |||
184 | /* Callback for dht public key changes. */ | ||
185 | static void dht_pk_callback(void *object, int32_t number, const uint8_t *dht_public_key) | ||
186 | { | ||
187 | Friend_Connections *fr_c = object; | ||
188 | Friend_Conn *friend_con = get_conn(fr_c, number); | ||
189 | |||
190 | if (!friend_con) | ||
191 | return; | ||
192 | |||
193 | friend_con->dht_ping_lastrecv = unix_time(); | ||
194 | |||
195 | if (memcmp(friend_con->dht_temp_pk, dht_public_key, crypto_box_PUBLICKEYBYTES) == 0) | ||
196 | return; | ||
197 | |||
198 | if (friend_con->dht_lock) { | ||
199 | if (DHT_delfriend(fr_c->dht, friend_con->dht_temp_pk, friend_con->dht_lock) != 0) { | ||
200 | printf("a. Could not delete dht peer. Please report this.\n"); | ||
201 | return; | ||
202 | } | ||
203 | |||
204 | friend_con->dht_lock = 0; | ||
205 | } | ||
206 | |||
207 | DHT_addfriend(fr_c->dht, dht_public_key, dht_ip_callback, object, number, &friend_con->dht_lock); | ||
208 | |||
209 | if (friend_con->crypt_connection_id == -1) { | ||
210 | friend_new_connection(fr_c, number); | ||
211 | } | ||
212 | |||
213 | set_connection_dht_public_key(fr_c->net_crypto, friend_con->crypt_connection_id, dht_public_key); | ||
214 | onion_set_friend_DHT_pubkey(fr_c->onion_c, friend_con->onion_friendnum, dht_public_key); | ||
215 | |||
216 | memcpy(friend_con->dht_temp_pk, dht_public_key, crypto_box_PUBLICKEYBYTES); | ||
217 | } | ||
218 | |||
219 | static int handle_status(void *object, int number, uint8_t status) | ||
220 | { | ||
221 | Friend_Connections *fr_c = object; | ||
222 | Friend_Conn *friend_con = get_conn(fr_c, number); | ||
223 | |||
224 | if (!friend_con) | ||
225 | return -1; | ||
226 | |||
227 | if (status) { /* Went online. */ | ||
228 | friend_con->status = FRIENDCONN_STATUS_CONNECTED; | ||
229 | friend_con->ping_lastrecv = unix_time(); | ||
230 | onion_set_friend_online(fr_c->onion_c, friend_con->onion_friendnum, status); | ||
231 | } else { /* Went offline. */ | ||
232 | friend_con->status = FRIENDCONN_STATUS_CONNECTING; | ||
233 | friend_con->crypt_connection_id = -1; | ||
234 | friend_con->dht_ping_lastrecv = unix_time(); | ||
235 | onion_set_friend_online(fr_c->onion_c, friend_con->onion_friendnum, status); | ||
236 | } | ||
237 | |||
238 | unsigned int i; | ||
239 | |||
240 | for (i = 0; i < MAX_FRIEND_CONNECTION_CALLBACKS; ++i) { | ||
241 | if (friend_con->callbacks[i].status_callback) | ||
242 | friend_con->callbacks[i].status_callback(friend_con->callbacks[i].status_callback_object, | ||
243 | friend_con->callbacks[i].status_callback_id, status); | ||
244 | } | ||
245 | |||
246 | return 0; | ||
247 | } | ||
248 | |||
249 | static int handle_packet(void *object, int number, uint8_t *data, uint16_t length) | ||
250 | { | ||
251 | if (length == 0) | ||
252 | return -1; | ||
253 | |||
254 | Friend_Connections *fr_c = object; | ||
255 | Friend_Conn *friend_con = get_conn(fr_c, number); | ||
256 | |||
257 | if (data[0] == PACKET_ID_FRIEND_REQUESTS) { | ||
258 | if (fr_c->fr_request_callback) | ||
259 | fr_c->fr_request_callback(fr_c->fr_request_object, friend_con->real_public_key, data, length); | ||
260 | |||
261 | return 0; | ||
262 | } | ||
263 | |||
264 | if (!friend_con) | ||
265 | return -1; | ||
266 | |||
267 | if (data[0] == PACKET_ID_ALIVE) { | ||
268 | friend_con->ping_lastrecv = unix_time(); | ||
269 | return 0; | ||
270 | } | ||
271 | |||
272 | unsigned int i; | ||
273 | |||
274 | for (i = 0; i < MAX_FRIEND_CONNECTION_CALLBACKS; ++i) { | ||
275 | if (friend_con->callbacks[i].data_callback) | ||
276 | friend_con->callbacks[i].data_callback(friend_con->callbacks[i].data_callback_object, | ||
277 | friend_con->callbacks[i].data_callback_id, data, length); | ||
278 | |||
279 | friend_con = get_conn(fr_c, number); | ||
280 | |||
281 | if (!friend_con) | ||
282 | return -1; | ||
283 | } | ||
284 | |||
285 | return 0; | ||
286 | } | ||
287 | |||
288 | static int handle_lossy_packet(void *object, int number, const uint8_t *data, uint16_t length) | ||
289 | { | ||
290 | if (length == 0) | ||
291 | return -1; | ||
292 | |||
293 | Friend_Connections *fr_c = object; | ||
294 | Friend_Conn *friend_con = get_conn(fr_c, number); | ||
295 | |||
296 | if (!friend_con) | ||
297 | return -1; | ||
298 | |||
299 | unsigned int i; | ||
300 | |||
301 | for (i = 0; i < MAX_FRIEND_CONNECTION_CALLBACKS; ++i) { | ||
302 | if (friend_con->callbacks[i].lossy_data_callback) | ||
303 | friend_con->callbacks[i].lossy_data_callback(friend_con->callbacks[i].lossy_data_callback_object, | ||
304 | friend_con->callbacks[i].lossy_data_callback_id, data, length); | ||
305 | |||
306 | friend_con = get_conn(fr_c, number); | ||
307 | |||
308 | if (!friend_con) | ||
309 | return -1; | ||
310 | } | ||
311 | |||
312 | return 0; | ||
313 | } | ||
314 | |||
315 | static int handle_new_connections(void *object, New_Connection *n_c) | ||
316 | { | ||
317 | Friend_Connections *fr_c = object; | ||
318 | int friendcon_id = getfriend_conn_id_pk(fr_c, n_c->public_key); | ||
319 | Friend_Conn *friend_con = get_conn(fr_c, friendcon_id); | ||
320 | |||
321 | if (friend_con) { | ||
322 | |||
323 | if (friend_con->crypt_connection_id != -1) | ||
324 | return -1; | ||
325 | |||
326 | int id = accept_crypto_connection(fr_c->net_crypto, n_c); | ||
327 | connection_status_handler(fr_c->net_crypto, id, &handle_status, fr_c, friendcon_id); | ||
328 | connection_data_handler(fr_c->net_crypto, id, &handle_packet, fr_c, friendcon_id); | ||
329 | connection_lossy_data_handler(fr_c->net_crypto, id, &handle_lossy_packet, fr_c, friendcon_id); | ||
330 | friend_con->crypt_connection_id = id; | ||
331 | |||
332 | if (n_c->source.ip.family != AF_INET && n_c->source.ip.family != AF_INET6) { | ||
333 | set_direct_ip_port(fr_c->net_crypto, friend_con->crypt_connection_id, friend_con->dht_ip_port); | ||
334 | } else { | ||
335 | friend_con->dht_ip_port = n_c->source; | ||
336 | friend_con->dht_ip_port_lastrecv = unix_time(); | ||
337 | } | ||
338 | |||
339 | dht_pk_callback(fr_c, friendcon_id, n_c->dht_public_key); | ||
340 | |||
341 | nc_dht_pk_callback(fr_c->net_crypto, id, &dht_pk_callback, fr_c, friendcon_id); | ||
342 | return 0; | ||
343 | } | ||
344 | |||
345 | return -1; | ||
346 | } | ||
347 | |||
348 | static int friend_new_connection(Friend_Connections *fr_c, int friendcon_id) | ||
349 | { | ||
350 | Friend_Conn *friend_con = get_conn(fr_c, friendcon_id); | ||
351 | |||
352 | if (!friend_con) | ||
353 | return -1; | ||
354 | |||
355 | if (friend_con->crypt_connection_id != -1) { | ||
356 | return -1; | ||
357 | } | ||
358 | |||
359 | int id = new_crypto_connection(fr_c->net_crypto, friend_con->real_public_key); | ||
360 | |||
361 | if (id == -1) | ||
362 | return -1; | ||
363 | |||
364 | friend_con->crypt_connection_id = id; | ||
365 | connection_status_handler(fr_c->net_crypto, id, &handle_status, fr_c, friendcon_id); | ||
366 | connection_data_handler(fr_c->net_crypto, id, &handle_packet, fr_c, friendcon_id); | ||
367 | connection_lossy_data_handler(fr_c->net_crypto, id, &handle_lossy_packet, fr_c, friendcon_id); | ||
368 | nc_dht_pk_callback(fr_c->net_crypto, id, &dht_pk_callback, fr_c, friendcon_id); | ||
369 | |||
370 | return 0; | ||
371 | } | ||
372 | |||
373 | static int send_ping(const Friend_Connections *fr_c, int friendcon_id) | ||
374 | { | ||
375 | Friend_Conn *friend_con = get_conn(fr_c, friendcon_id); | ||
376 | |||
377 | if (!friend_con) | ||
378 | return -1; | ||
379 | |||
380 | uint8_t ping = PACKET_ID_ALIVE; | ||
381 | int64_t ret = write_cryptpacket(fr_c->net_crypto, friend_con->crypt_connection_id, &ping, sizeof(ping), 0); | ||
382 | |||
383 | if (ret != -1) { | ||
384 | friend_con->ping_lastsent = unix_time(); | ||
385 | return 0; | ||
386 | } | ||
387 | |||
388 | return -1; | ||
389 | } | ||
390 | |||
391 | /* Increases lock_count for the connection with friendcon_id by 1. | ||
392 | * | ||
393 | * return 0 on success. | ||
394 | * return -1 on failure. | ||
395 | */ | ||
396 | int friend_connection_lock(Friend_Connections *fr_c, int friendcon_id) | ||
397 | { | ||
398 | Friend_Conn *friend_con = get_conn(fr_c, friendcon_id); | ||
399 | |||
400 | if (!friend_con) | ||
401 | return -1; | ||
402 | |||
403 | ++friend_con->lock_count; | ||
404 | return 0; | ||
405 | } | ||
406 | |||
407 | /* return FRIENDCONN_STATUS_CONNECTED if the friend is connected. | ||
408 | * return FRIENDCONN_STATUS_CONNECTING if the friend isn't connected. | ||
409 | * return FRIENDCONN_STATUS_NONE on failure. | ||
410 | */ | ||
411 | unsigned int friend_con_connected(Friend_Connections *fr_c, int friendcon_id) | ||
412 | { | ||
413 | Friend_Conn *friend_con = get_conn(fr_c, friendcon_id); | ||
414 | |||
415 | if (!friend_con) | ||
416 | return 0; | ||
417 | |||
418 | return friend_con->status; | ||
419 | } | ||
420 | |||
421 | /* Copy public keys associated to friendcon_id. | ||
422 | * | ||
423 | * return 0 on success. | ||
424 | * return -1 on failure. | ||
425 | */ | ||
426 | int get_friendcon_public_keys(uint8_t *real_pk, uint8_t *dht_temp_pk, Friend_Connections *fr_c, int friendcon_id) | ||
427 | { | ||
428 | Friend_Conn *friend_con = get_conn(fr_c, friendcon_id); | ||
429 | |||
430 | if (!friend_con) | ||
431 | return -1; | ||
432 | |||
433 | if (real_pk) | ||
434 | memcpy(real_pk, friend_con->real_public_key, crypto_box_PUBLICKEYBYTES); | ||
435 | |||
436 | if (dht_temp_pk) | ||
437 | memcpy(dht_temp_pk, friend_con->dht_temp_pk, crypto_box_PUBLICKEYBYTES); | ||
438 | |||
439 | return 0; | ||
440 | } | ||
441 | |||
442 | /* Set temp dht key for connection. | ||
443 | */ | ||
444 | void set_dht_temp_pk(Friend_Connections *fr_c, int friendcon_id, const uint8_t *dht_temp_pk) | ||
445 | { | ||
446 | dht_pk_callback(fr_c, friendcon_id, dht_temp_pk); | ||
447 | } | ||
448 | |||
449 | /* Set the callbacks for the friend connection. | ||
450 | * index is the index (0 to (MAX_FRIEND_CONNECTION_CALLBACKS - 1)) we want the callback to set in the array. | ||
451 | * | ||
452 | * return 0 on success. | ||
453 | * return -1 on failure | ||
454 | */ | ||
455 | int friend_connection_callbacks(Friend_Connections *fr_c, int friendcon_id, unsigned int index, | ||
456 | int (*status_callback)(void *object, int id, uint8_t status), int (*data_callback)(void *object, int id, uint8_t *data, | ||
457 | uint16_t length), int (*lossy_data_callback)(void *object, int id, const uint8_t *data, uint16_t length), void *object, | ||
458 | int number) | ||
459 | { | ||
460 | Friend_Conn *friend_con = get_conn(fr_c, friendcon_id); | ||
461 | |||
462 | if (!friend_con) | ||
463 | return -1; | ||
464 | |||
465 | if (index >= MAX_FRIEND_CONNECTION_CALLBACKS) | ||
466 | return -1; | ||
467 | |||
468 | friend_con->callbacks[index].status_callback = status_callback; | ||
469 | friend_con->callbacks[index].data_callback = data_callback; | ||
470 | friend_con->callbacks[index].lossy_data_callback = lossy_data_callback; | ||
471 | |||
472 | friend_con->callbacks[index].status_callback_object = | ||
473 | friend_con->callbacks[index].data_callback_object = | ||
474 | friend_con->callbacks[index].lossy_data_callback_object = object; | ||
475 | |||
476 | friend_con->callbacks[index].status_callback_id = | ||
477 | friend_con->callbacks[index].data_callback_id = | ||
478 | friend_con->callbacks[index].lossy_data_callback_id = number; | ||
479 | return 0; | ||
480 | } | ||
481 | |||
482 | /* return the crypt_connection_id for the connection. | ||
483 | * | ||
484 | * return crypt_connection_id on success. | ||
485 | * return -1 on failure. | ||
486 | */ | ||
487 | int friend_connection_crypt_connection_id(Friend_Connections *fr_c, int friendcon_id) | ||
488 | { | ||
489 | Friend_Conn *friend_con = get_conn(fr_c, friendcon_id); | ||
490 | |||
491 | if (!friend_con) | ||
492 | return -1; | ||
493 | |||
494 | return friend_con->crypt_connection_id; | ||
495 | } | ||
496 | |||
497 | /* Create a new friend connection. | ||
498 | * If one to that real public key already exists, increase lock count and return it. | ||
499 | * | ||
500 | * return -1 on failure. | ||
501 | * return connection id on success. | ||
502 | */ | ||
503 | int new_friend_connection(Friend_Connections *fr_c, const uint8_t *real_public_key) | ||
504 | { | ||
505 | int friendcon_id = getfriend_conn_id_pk(fr_c, real_public_key); | ||
506 | |||
507 | if (friendcon_id != -1) { | ||
508 | ++fr_c->conns[friendcon_id].lock_count; | ||
509 | return friendcon_id; | ||
510 | } | ||
511 | |||
512 | friendcon_id = create_friend_conn(fr_c); | ||
513 | |||
514 | if (friendcon_id == -1) | ||
515 | return -1; | ||
516 | |||
517 | int32_t onion_friendnum = onion_addfriend(fr_c->onion_c, real_public_key); | ||
518 | |||
519 | if (onion_friendnum == -1) | ||
520 | return -1; | ||
521 | |||
522 | Friend_Conn *friend_con = &fr_c->conns[friendcon_id]; | ||
523 | |||
524 | friend_con->crypt_connection_id = -1; | ||
525 | friend_con->status = FRIENDCONN_STATUS_CONNECTING; | ||
526 | memcpy(friend_con->real_public_key, real_public_key, crypto_box_PUBLICKEYBYTES); | ||
527 | friend_con->onion_friendnum = onion_friendnum; | ||
528 | |||
529 | recv_tcp_relay_handler(fr_c->onion_c, onion_friendnum, &tcp_relay_node_callback, fr_c, friendcon_id); | ||
530 | onion_dht_pk_callback(fr_c->onion_c, onion_friendnum, &dht_pk_callback, fr_c, friendcon_id); | ||
531 | |||
532 | return friendcon_id; | ||
533 | } | ||
534 | |||
535 | /* Kill a friend connection. | ||
536 | * | ||
537 | * return -1 on failure. | ||
538 | * return 0 on success. | ||
539 | */ | ||
540 | int kill_friend_connection(Friend_Connections *fr_c, int friendcon_id) | ||
541 | { | ||
542 | Friend_Conn *friend_con = get_conn(fr_c, friendcon_id); | ||
543 | |||
544 | if (!friend_con) | ||
545 | return -1; | ||
546 | |||
547 | if (friend_con->lock_count) { | ||
548 | --friend_con->lock_count; | ||
549 | return 0; | ||
550 | } | ||
551 | |||
552 | onion_delfriend(fr_c->onion_c, friend_con->onion_friendnum); | ||
553 | crypto_kill(fr_c->net_crypto, friend_con->crypt_connection_id); | ||
554 | |||
555 | if (friend_con->dht_lock) { | ||
556 | DHT_delfriend(fr_c->dht, friend_con->dht_temp_pk, friend_con->dht_lock); | ||
557 | } | ||
558 | |||
559 | return wipe_friend_conn(fr_c, friendcon_id); | ||
560 | } | ||
561 | |||
562 | |||
563 | /* Set friend request callback. | ||
564 | * | ||
565 | * This function will be called every time a friend request packet is received. | ||
566 | */ | ||
567 | void set_friend_request_callback(Friend_Connections *fr_c, int (*fr_request_callback)(void *, const uint8_t *, | ||
568 | const uint8_t *, uint16_t), void *object) | ||
569 | { | ||
570 | fr_c->fr_request_callback = fr_request_callback; | ||
571 | fr_c->fr_request_object = object; | ||
572 | oniondata_registerhandler(fr_c->onion_c, CRYPTO_PACKET_FRIEND_REQ, fr_request_callback, object); | ||
573 | } | ||
574 | |||
575 | /* Send a Friend request packet. | ||
576 | * | ||
577 | * return -1 if failure. | ||
578 | * return 0 if it sent the friend request directly to the friend. | ||
579 | * return the number of peers it was routed through if it did not send it directly. | ||
580 | */ | ||
581 | int send_friend_request_packet(Friend_Connections *fr_c, int friendcon_id, uint32_t nospam_num, const uint8_t *data, | ||
582 | uint16_t length) | ||
583 | { | ||
584 | if (1 + sizeof(nospam_num) + length > ONION_CLIENT_MAX_DATA_SIZE || length == 0) | ||
585 | return -1; | ||
586 | |||
587 | Friend_Conn *friend_con = get_conn(fr_c, friendcon_id); | ||
588 | |||
589 | if (!friend_con) | ||
590 | return -1; | ||
591 | |||
592 | uint8_t packet[1 + sizeof(nospam_num) + length]; | ||
593 | memcpy(packet + 1, &nospam_num, sizeof(nospam_num)); | ||
594 | memcpy(packet + 1 + sizeof(nospam_num), data, length); | ||
595 | |||
596 | if (friend_con->status == FRIENDCONN_STATUS_CONNECTED) { | ||
597 | packet[0] = PACKET_ID_FRIEND_REQUESTS; | ||
598 | return write_cryptpacket(fr_c->net_crypto, friend_con->crypt_connection_id, packet, sizeof(packet), 0) != -1; | ||
599 | } else { | ||
600 | packet[0] = CRYPTO_PACKET_FRIEND_REQ; | ||
601 | int num = send_onion_data(fr_c->onion_c, friend_con->onion_friendnum, packet, sizeof(packet)); | ||
602 | |||
603 | if (num <= 0) | ||
604 | return -1; | ||
605 | |||
606 | return num; | ||
607 | } | ||
608 | } | ||
609 | |||
610 | /* Create new friend_connections instance. */ | ||
611 | Friend_Connections *new_friend_connections(Onion_Client *onion_c) | ||
612 | { | ||
613 | if (!onion_c) | ||
614 | return NULL; | ||
615 | |||
616 | Friend_Connections *temp = calloc(1, sizeof(Friend_Connections)); | ||
617 | |||
618 | if (temp == NULL) | ||
619 | return NULL; | ||
620 | |||
621 | temp->dht = onion_c->dht; | ||
622 | temp->net_crypto = onion_c->c; | ||
623 | temp->onion_c = onion_c; | ||
624 | |||
625 | new_connection_handler(temp->net_crypto, &handle_new_connections, temp); | ||
626 | |||
627 | return temp; | ||
628 | } | ||
629 | |||
630 | /* main friend_connections loop. */ | ||
631 | void do_friend_connections(Friend_Connections *fr_c) | ||
632 | { | ||
633 | uint32_t i; | ||
634 | uint64_t temp_time = unix_time(); | ||
635 | |||
636 | for (i = 0; i < fr_c->num_cons; ++i) { | ||
637 | Friend_Conn *friend_con = get_conn(fr_c, i); | ||
638 | |||
639 | if (friend_con) { | ||
640 | if (friend_con->status == FRIENDCONN_STATUS_CONNECTING) { | ||
641 | if (friend_con->dht_ping_lastrecv + FRIEND_DHT_TIMEOUT < temp_time) { | ||
642 | if (friend_con->dht_lock) { | ||
643 | DHT_delfriend(fr_c->dht, friend_con->dht_temp_pk, friend_con->dht_lock); | ||
644 | friend_con->dht_lock = 0; | ||
645 | } | ||
646 | } | ||
647 | |||
648 | if (friend_con->dht_ip_port_lastrecv + FRIEND_DHT_TIMEOUT < temp_time) { | ||
649 | friend_con->dht_ip_port.ip.family = 0; | ||
650 | } | ||
651 | |||
652 | if (friend_con->dht_lock) { | ||
653 | if (friend_new_connection(fr_c, i) == 0) { | ||
654 | set_connection_dht_public_key(fr_c->net_crypto, friend_con->crypt_connection_id, friend_con->dht_temp_pk); | ||
655 | set_direct_ip_port(fr_c->net_crypto, friend_con->crypt_connection_id, friend_con->dht_ip_port); | ||
656 | } | ||
657 | } | ||
658 | |||
659 | } else if (friend_con->status == FRIENDCONN_STATUS_CONNECTED) { | ||
660 | if (friend_con->ping_lastsent + FRIEND_PING_INTERVAL < temp_time) { | ||
661 | send_ping(fr_c, i); | ||
662 | } | ||
663 | |||
664 | if (friend_con->ping_lastrecv + FRIEND_CONNECTION_TIMEOUT < temp_time) { | ||
665 | /* If we stopped receiving ping packets, kill it. */ | ||
666 | crypto_kill(fr_c->net_crypto, friend_con->crypt_connection_id); | ||
667 | friend_con->crypt_connection_id = -1; | ||
668 | handle_status(fr_c, i, 0); /* Going offline. */ | ||
669 | } | ||
670 | } | ||
671 | } | ||
672 | } | ||
673 | } | ||
674 | |||
675 | /* Free everything related with friend_connections. */ | ||
676 | void kill_friend_connections(Friend_Connections *fr_c) | ||
677 | { | ||
678 | if (!fr_c) | ||
679 | return; | ||
680 | |||
681 | uint32_t i; | ||
682 | |||
683 | for (i = 0; i < fr_c->num_cons; ++i) { | ||
684 | kill_friend_connection(fr_c, i); | ||
685 | } | ||
686 | |||
687 | free(fr_c); | ||
688 | } | ||
diff --git a/toxcore/friend_connection.h b/toxcore/friend_connection.h new file mode 100644 index 00000000..b814eb0c --- /dev/null +++ b/toxcore/friend_connection.h | |||
@@ -0,0 +1,188 @@ | |||
1 | /* friend_connection.h | ||
2 | * | ||
3 | * Connection to friends. | ||
4 | * | ||
5 | * Copyright (C) 2014 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 | |||
25 | #ifndef FRIEND_CONNECTION_H | ||
26 | #define FRIEND_CONNECTION_H | ||
27 | |||
28 | #include "net_crypto.h" | ||
29 | #include "DHT.h" | ||
30 | #include "LAN_discovery.h" | ||
31 | #include "onion_client.h" | ||
32 | |||
33 | |||
34 | #define MAX_FRIEND_CONNECTION_CALLBACKS 2 | ||
35 | #define MESSENGER_CALLBACK_INDEX 0 | ||
36 | #define GROUPCHAT_CALLBACK_INDEX 1 | ||
37 | |||
38 | #define PACKET_ID_ALIVE 16 | ||
39 | #define PACKET_ID_FRIEND_REQUESTS 18 | ||
40 | |||
41 | /* Interval between the sending of ping packets. */ | ||
42 | #define FRIEND_PING_INTERVAL 7 | ||
43 | |||
44 | /* If no packets are received from friend in this time interval, kill the connection. */ | ||
45 | #define FRIEND_CONNECTION_TIMEOUT (FRIEND_PING_INTERVAL * 3) | ||
46 | |||
47 | /* Time before friend is removed from the DHT after last hearing about him. */ | ||
48 | #define FRIEND_DHT_TIMEOUT BAD_NODE_TIMEOUT | ||
49 | |||
50 | |||
51 | enum { | ||
52 | FRIENDCONN_STATUS_NONE, | ||
53 | FRIENDCONN_STATUS_CONNECTING, | ||
54 | FRIENDCONN_STATUS_CONNECTED | ||
55 | }; | ||
56 | |||
57 | typedef struct { | ||
58 | uint8_t status; | ||
59 | |||
60 | uint8_t real_public_key[crypto_box_PUBLICKEYBYTES]; | ||
61 | uint8_t dht_temp_pk[crypto_box_PUBLICKEYBYTES]; | ||
62 | uint16_t dht_lock; | ||
63 | IP_Port dht_ip_port; | ||
64 | uint64_t dht_ping_lastrecv, dht_ip_port_lastrecv; | ||
65 | |||
66 | int onion_friendnum; | ||
67 | int crypt_connection_id; | ||
68 | |||
69 | uint64_t ping_lastrecv, ping_lastsent; | ||
70 | |||
71 | struct { | ||
72 | int (*status_callback)(void *object, int id, uint8_t status); | ||
73 | void *status_callback_object; | ||
74 | int status_callback_id; | ||
75 | |||
76 | int (*data_callback)(void *object, int id, uint8_t *data, uint16_t length); | ||
77 | void *data_callback_object; | ||
78 | int data_callback_id; | ||
79 | |||
80 | int (*lossy_data_callback)(void *object, int id, const uint8_t *data, uint16_t length); | ||
81 | void *lossy_data_callback_object; | ||
82 | int lossy_data_callback_id; | ||
83 | } callbacks[MAX_FRIEND_CONNECTION_CALLBACKS]; | ||
84 | |||
85 | uint16_t lock_count; | ||
86 | } Friend_Conn; | ||
87 | |||
88 | |||
89 | typedef struct { | ||
90 | Net_Crypto *net_crypto; | ||
91 | DHT *dht; | ||
92 | Onion_Client *onion_c; | ||
93 | |||
94 | Friend_Conn *conns; | ||
95 | uint32_t num_cons; | ||
96 | |||
97 | int (*fr_request_callback)(void *object, const uint8_t *source_pubkey, const uint8_t *data, uint16_t len); | ||
98 | void *fr_request_object; | ||
99 | } Friend_Connections; | ||
100 | |||
101 | /* return friendcon_id corresponding to the real public key on success. | ||
102 | * return -1 on failure. | ||
103 | */ | ||
104 | int getfriend_conn_id_pk(Friend_Connections *fr_c, const uint8_t *real_pk); | ||
105 | |||
106 | /* Increases lock_count for the connection with friendcon_id by 1. | ||
107 | * | ||
108 | * return 0 on success. | ||
109 | * return -1 on failure. | ||
110 | */ | ||
111 | int friend_connection_lock(Friend_Connections *fr_c, int friendcon_id); | ||
112 | |||
113 | /* return FRIENDCONN_STATUS_CONNECTED if the friend is connected. | ||
114 | * return FRIENDCONN_STATUS_CONNECTING if the friend isn't connected. | ||
115 | * return FRIENDCONN_STATUS_NONE on failure. | ||
116 | */ | ||
117 | unsigned int friend_con_connected(Friend_Connections *fr_c, int friendcon_id); | ||
118 | |||
119 | /* Copy public keys associated to friendcon_id. | ||
120 | * | ||
121 | * return 0 on success. | ||
122 | * return -1 on failure. | ||
123 | */ | ||
124 | int get_friendcon_public_keys(uint8_t *real_pk, uint8_t *dht_temp_pk, Friend_Connections *fr_c, int friendcon_id); | ||
125 | |||
126 | /* Set temp dht key for connection. | ||
127 | */ | ||
128 | void set_dht_temp_pk(Friend_Connections *fr_c, int friendcon_id, const uint8_t *dht_temp_pk); | ||
129 | |||
130 | /* Set the callbacks for the friend connection. | ||
131 | * index is the index (0 to (MAX_FRIEND_CONNECTION_CALLBACKS - 1)) we want the callback to set in the array. | ||
132 | * | ||
133 | * return 0 on success. | ||
134 | * return -1 on failure | ||
135 | */ | ||
136 | int friend_connection_callbacks(Friend_Connections *fr_c, int friendcon_id, unsigned int index, | ||
137 | int (*status_callback)(void *object, int id, uint8_t status), int (*data_callback)(void *object, int id, uint8_t *data, | ||
138 | uint16_t length), int (*lossy_data_callback)(void *object, int id, const uint8_t *data, uint16_t length), void *object, | ||
139 | int number); | ||
140 | |||
141 | /* return the crypt_connection_id for the connection. | ||
142 | * | ||
143 | * return crypt_connection_id on success. | ||
144 | * return -1 on failure. | ||
145 | */ | ||
146 | int friend_connection_crypt_connection_id(Friend_Connections *fr_c, int friendcon_id); | ||
147 | |||
148 | /* Create a new friend connection. | ||
149 | * If one to that real public key already exists, increase lock count and return it. | ||
150 | * | ||
151 | * return -1 on failure. | ||
152 | * return connection id on success. | ||
153 | */ | ||
154 | int new_friend_connection(Friend_Connections *fr_c, const uint8_t *real_public_key); | ||
155 | |||
156 | /* Kill a friend connection. | ||
157 | * | ||
158 | * return -1 on failure. | ||
159 | * return 0 on success. | ||
160 | */ | ||
161 | int kill_friend_connection(Friend_Connections *fr_c, int friendcon_id); | ||
162 | |||
163 | /* Send a Friend request packet. | ||
164 | * | ||
165 | * return -1 if failure. | ||
166 | * return 0 if it sent the friend request directly to the friend. | ||
167 | * return the number of peers it was routed through if it did not send it directly. | ||
168 | */ | ||
169 | int send_friend_request_packet(Friend_Connections *fr_c, int friendcon_id, uint32_t nospam_num, const uint8_t *data, | ||
170 | uint16_t length); | ||
171 | |||
172 | /* Set friend request callback. | ||
173 | * | ||
174 | * This function will be called every time a friend request is received. | ||
175 | */ | ||
176 | void set_friend_request_callback(Friend_Connections *fr_c, int (*fr_request_callback)(void *, const uint8_t *, | ||
177 | const uint8_t *, uint16_t), void *object); | ||
178 | |||
179 | /* Create new friend_connections instance. */ | ||
180 | Friend_Connections *new_friend_connections(Onion_Client *onion_c); | ||
181 | |||
182 | /* main friend_connections loop. */ | ||
183 | void do_friend_connections(Friend_Connections *fr_c); | ||
184 | |||
185 | /* Free everything related with friend_connections. */ | ||
186 | void kill_friend_connections(Friend_Connections *fr_c); | ||
187 | |||
188 | #endif | ||
diff --git a/toxcore/friend_requests.c b/toxcore/friend_requests.c index a662b629..dae1694a 100644 --- a/toxcore/friend_requests.c +++ b/toxcore/friend_requests.c | |||
@@ -28,37 +28,6 @@ | |||
28 | #include "friend_requests.h" | 28 | #include "friend_requests.h" |
29 | #include "util.h" | 29 | #include "util.h" |
30 | 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 | 31 | ||
63 | /* Set and get the nospam variable used to prevent one type of friend request spam. */ | 32 | /* 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) | 33 | void set_nospam(Friend_Requests *fr, uint32_t num) |
@@ -73,7 +42,7 @@ uint32_t get_nospam(const Friend_Requests *fr) | |||
73 | 42 | ||
74 | 43 | ||
75 | /* Set the function that will be executed when a friend request is received. */ | 44 | /* 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, | 45 | void callback_friendrequest(Friend_Requests *fr, void (*function)(void *, const uint8_t *, const uint8_t *, size_t, |
77 | void *), void *object, void *userdata) | 46 | void *), void *object, void *userdata) |
78 | { | 47 | { |
79 | fr->handle_friendrequest = function; | 48 | fr->handle_friendrequest = function; |
@@ -89,12 +58,12 @@ void set_filter_function(Friend_Requests *fr, int (*function)(const uint8_t *, v | |||
89 | } | 58 | } |
90 | 59 | ||
91 | /* Add to list of received friend requests. */ | 60 | /* Add to list of received friend requests. */ |
92 | static void addto_receivedlist(Friend_Requests *fr, const uint8_t *client_id) | 61 | static void addto_receivedlist(Friend_Requests *fr, const uint8_t *real_pk) |
93 | { | 62 | { |
94 | if (fr->received_requests_index >= MAX_RECEIVED_STORED) | 63 | if (fr->received_requests_index >= MAX_RECEIVED_STORED) |
95 | fr->received_requests_index = 0; | 64 | fr->received_requests_index = 0; |
96 | 65 | ||
97 | id_copy(fr->received_requests[fr->received_requests_index], client_id); | 66 | id_copy(fr->received_requests[fr->received_requests_index], real_pk); |
98 | ++fr->received_requests_index; | 67 | ++fr->received_requests_index; |
99 | } | 68 | } |
100 | 69 | ||
@@ -103,28 +72,28 @@ static void addto_receivedlist(Friend_Requests *fr, const uint8_t *client_id) | |||
103 | * return 0 if it did not. | 72 | * return 0 if it did not. |
104 | * return 1 if it did. | 73 | * return 1 if it did. |
105 | */ | 74 | */ |
106 | static int request_received(Friend_Requests *fr, const uint8_t *client_id) | 75 | static int request_received(Friend_Requests *fr, const uint8_t *real_pk) |
107 | { | 76 | { |
108 | uint32_t i; | 77 | uint32_t i; |
109 | 78 | ||
110 | for (i = 0; i < MAX_RECEIVED_STORED; ++i) | 79 | for (i = 0; i < MAX_RECEIVED_STORED; ++i) |
111 | if (id_equal(fr->received_requests[i], client_id)) | 80 | if (id_equal(fr->received_requests[i], real_pk)) |
112 | return 1; | 81 | return 1; |
113 | 82 | ||
114 | return 0; | 83 | return 0; |
115 | } | 84 | } |
116 | 85 | ||
117 | /* Remove client id from received_requests list. | 86 | /* Remove real pk from received_requests list. |
118 | * | 87 | * |
119 | * return 0 if it removed it successfully. | 88 | * return 0 if it removed it successfully. |
120 | * return -1 if it didn't find it. | 89 | * return -1 if it didn't find it. |
121 | */ | 90 | */ |
122 | int remove_request_received(Friend_Requests *fr, const uint8_t *client_id) | 91 | int remove_request_received(Friend_Requests *fr, const uint8_t *real_pk) |
123 | { | 92 | { |
124 | uint32_t i; | 93 | uint32_t i; |
125 | 94 | ||
126 | for (i = 0; i < MAX_RECEIVED_STORED; ++i) { | 95 | for (i = 0; i < MAX_RECEIVED_STORED; ++i) { |
127 | if (id_equal(fr->received_requests[i], client_id)) { | 96 | if (id_equal(fr->received_requests[i], real_pk)) { |
128 | memset(fr->received_requests[i], 0, crypto_box_PUBLICKEYBYTES); | 97 | memset(fr->received_requests[i], 0, crypto_box_PUBLICKEYBYTES); |
129 | return 0; | 98 | return 0; |
130 | } | 99 | } |
@@ -134,7 +103,7 @@ int remove_request_received(Friend_Requests *fr, const uint8_t *client_id) | |||
134 | } | 103 | } |
135 | 104 | ||
136 | 105 | ||
137 | static int friendreq_handlepacket(void *object, const uint8_t *source_pubkey, const uint8_t *packet, uint32_t length) | 106 | static int friendreq_handlepacket(void *object, const uint8_t *source_pubkey, const uint8_t *packet, uint16_t length) |
138 | { | 107 | { |
139 | Friend_Requests *fr = object; | 108 | Friend_Requests *fr = object; |
140 | 109 | ||
@@ -169,7 +138,7 @@ static int friendreq_handlepacket(void *object, const uint8_t *source_pubkey, co | |||
169 | return 0; | 138 | return 0; |
170 | } | 139 | } |
171 | 140 | ||
172 | void friendreq_init(Friend_Requests *fr, Onion_Client *onion_c) | 141 | void friendreq_init(Friend_Requests *fr, Friend_Connections *fr_c) |
173 | { | 142 | { |
174 | oniondata_registerhandler(onion_c, CRYPTO_PACKET_FRIEND_REQ, &friendreq_handlepacket, fr); | 143 | set_friend_request_callback(fr_c, &friendreq_handlepacket, fr); |
175 | } | 144 | } |
diff --git a/toxcore/friend_requests.h b/toxcore/friend_requests.h index c3e31f36..ae21f7dc 100644 --- a/toxcore/friend_requests.h +++ b/toxcore/friend_requests.h | |||
@@ -24,13 +24,13 @@ | |||
24 | #ifndef FRIEND_REQUESTS_H | 24 | #ifndef FRIEND_REQUESTS_H |
25 | #define FRIEND_REQUESTS_H | 25 | #define FRIEND_REQUESTS_H |
26 | 26 | ||
27 | #include "onion_client.h" | 27 | #include "friend_connection.h" |
28 | 28 | ||
29 | #define MAX_FRIEND_REQUEST_DATA_SIZE (ONION_CLIENT_MAX_DATA_SIZE - (1 + sizeof(uint32_t))) | 29 | #define MAX_FRIEND_REQUEST_DATA_SIZE (ONION_CLIENT_MAX_DATA_SIZE - (1 + sizeof(uint32_t))) |
30 | 30 | ||
31 | typedef struct { | 31 | typedef struct { |
32 | uint32_t nospam; | 32 | uint32_t nospam; |
33 | void (*handle_friendrequest)(void *, const uint8_t *, const uint8_t *, uint16_t, void *); | 33 | void (*handle_friendrequest)(void *, const uint8_t *, const uint8_t *, size_t, void *); |
34 | uint8_t handle_friendrequest_isset; | 34 | uint8_t handle_friendrequest_isset; |
35 | void *handle_friendrequest_object; | 35 | void *handle_friendrequest_object; |
36 | void *handle_friendrequest_userdata; | 36 | void *handle_friendrequest_userdata; |
@@ -47,27 +47,21 @@ typedef struct { | |||
47 | uint16_t received_requests_index; | 47 | uint16_t received_requests_index; |
48 | } Friend_Requests; | 48 | } Friend_Requests; |
49 | 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. */ | 50 | /* 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); | 51 | void set_nospam(Friend_Requests *fr, uint32_t num); |
58 | uint32_t get_nospam(const Friend_Requests *fr); | 52 | uint32_t get_nospam(const Friend_Requests *fr); |
59 | 53 | ||
60 | /* Remove client id from received_requests list. | 54 | /* Remove real_pk from received_requests list. |
61 | * | 55 | * |
62 | * return 0 if it removed it successfully. | 56 | * return 0 if it removed it successfully. |
63 | * return -1 if it didn't find it. | 57 | * return -1 if it didn't find it. |
64 | */ | 58 | */ |
65 | int remove_request_received(Friend_Requests *fr, const uint8_t *client_id); | 59 | int remove_request_received(Friend_Requests *fr, const uint8_t *real_pk); |
66 | 60 | ||
67 | /* Set the function that will be executed when a friend request for us is received. | 61 | /* 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) | 62 | * Function format is function(uint8_t * public_key, uint8_t * data, size_t length, void * userdata) |
69 | */ | 63 | */ |
70 | void callback_friendrequest(Friend_Requests *fr, void (*function)(void *, const uint8_t *, const uint8_t *, uint16_t, | 64 | void callback_friendrequest(Friend_Requests *fr, void (*function)(void *, const uint8_t *, const uint8_t *, size_t, |
71 | void *), void *object, void *userdata); | 65 | void *), void *object, void *userdata); |
72 | 66 | ||
73 | /* Set the function used to check if a friend request should be displayed to the user or not. | 67 | /* Set the function used to check if a friend request should be displayed to the user or not. |
@@ -77,7 +71,7 @@ void callback_friendrequest(Friend_Requests *fr, void (*function)(void *, const | |||
77 | void set_filter_function(Friend_Requests *fr, int (*function)(const uint8_t *, void *), void *userdata); | 71 | void set_filter_function(Friend_Requests *fr, int (*function)(const uint8_t *, void *), void *userdata); |
78 | 72 | ||
79 | /* Sets up friendreq packet handlers. */ | 73 | /* Sets up friendreq packet handlers. */ |
80 | void friendreq_init(Friend_Requests *fr, Onion_Client *onion_c); | 74 | void friendreq_init(Friend_Requests *fr, Friend_Connections *fr_c); |
81 | 75 | ||
82 | 76 | ||
83 | #endif | 77 | #endif |
diff --git a/toxcore/group.c b/toxcore/group.c new file mode 100644 index 00000000..c688ccff --- /dev/null +++ b/toxcore/group.c | |||
@@ -0,0 +1,2322 @@ | |||
1 | /* group.c | ||
2 | * | ||
3 | * Slightly better groupchats implementation. | ||
4 | * | ||
5 | * Copyright (C) 2014 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 "group.h" | ||
29 | #include "util.h" | ||
30 | |||
31 | /* return 1 if the groupnumber is not valid. | ||
32 | * return 0 if the groupnumber is valid. | ||
33 | */ | ||
34 | static uint8_t groupnumber_not_valid(const Group_Chats *g_c, int groupnumber) | ||
35 | { | ||
36 | if ((unsigned int)groupnumber >= g_c->num_chats) | ||
37 | return 1; | ||
38 | |||
39 | if (g_c->chats == NULL) | ||
40 | return 1; | ||
41 | |||
42 | if (g_c->chats[groupnumber].status == GROUPCHAT_STATUS_NONE) | ||
43 | return 1; | ||
44 | |||
45 | return 0; | ||
46 | } | ||
47 | |||
48 | |||
49 | /* Set the size of the groupchat list to num. | ||
50 | * | ||
51 | * return -1 if realloc fails. | ||
52 | * return 0 if it succeeds. | ||
53 | */ | ||
54 | static int realloc_groupchats(Group_Chats *g_c, uint32_t num) | ||
55 | { | ||
56 | if (num == 0) { | ||
57 | free(g_c->chats); | ||
58 | g_c->chats = NULL; | ||
59 | return 0; | ||
60 | } | ||
61 | |||
62 | Group_c *newgroup_chats = realloc(g_c->chats, num * sizeof(Group_c)); | ||
63 | |||
64 | if (newgroup_chats == NULL) | ||
65 | return -1; | ||
66 | |||
67 | g_c->chats = newgroup_chats; | ||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | |||
72 | /* Create a new empty groupchat connection. | ||
73 | * | ||
74 | * return -1 on failure. | ||
75 | * return groupnumber on success. | ||
76 | */ | ||
77 | static int create_group_chat(Group_Chats *g_c) | ||
78 | { | ||
79 | uint32_t i; | ||
80 | |||
81 | for (i = 0; i < g_c->num_chats; ++i) { | ||
82 | if (g_c->chats[i].status == GROUPCHAT_STATUS_NONE) | ||
83 | return i; | ||
84 | } | ||
85 | |||
86 | int id = -1; | ||
87 | |||
88 | if (realloc_groupchats(g_c, g_c->num_chats + 1) == 0) { | ||
89 | id = g_c->num_chats; | ||
90 | ++g_c->num_chats; | ||
91 | memset(&(g_c->chats[id]), 0, sizeof(Group_c)); | ||
92 | } | ||
93 | |||
94 | return id; | ||
95 | } | ||
96 | |||
97 | |||
98 | /* Wipe a groupchat. | ||
99 | * | ||
100 | * return -1 on failure. | ||
101 | * return 0 on success. | ||
102 | */ | ||
103 | static int wipe_group_chat(Group_Chats *g_c, int groupnumber) | ||
104 | { | ||
105 | if (groupnumber_not_valid(g_c, groupnumber)) | ||
106 | return -1; | ||
107 | |||
108 | uint32_t i; | ||
109 | memset(&(g_c->chats[groupnumber]), 0 , sizeof(Group_c)); | ||
110 | |||
111 | for (i = g_c->num_chats; i != 0; --i) { | ||
112 | if (g_c->chats[i - 1].status != GROUPCHAT_STATUS_NONE) | ||
113 | break; | ||
114 | } | ||
115 | |||
116 | if (g_c->num_chats != i) { | ||
117 | g_c->num_chats = i; | ||
118 | realloc_groupchats(g_c, g_c->num_chats); | ||
119 | } | ||
120 | |||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | static Group_c *get_group_c(const Group_Chats *g_c, int groupnumber) | ||
125 | { | ||
126 | if (groupnumber_not_valid(g_c, groupnumber)) | ||
127 | return 0; | ||
128 | |||
129 | return &g_c->chats[groupnumber]; | ||
130 | } | ||
131 | |||
132 | /* | ||
133 | * check if peer with real_pk is in peer array. | ||
134 | * | ||
135 | * return peer index if peer is in chat. | ||
136 | * return -1 if peer is not in chat. | ||
137 | * | ||
138 | * TODO: make this more efficient. | ||
139 | */ | ||
140 | |||
141 | static int peer_in_chat(const Group_c *chat, const uint8_t *real_pk) | ||
142 | { | ||
143 | uint32_t i; | ||
144 | |||
145 | for (i = 0; i < chat->numpeers; ++i) | ||
146 | if (id_equal(chat->group[i].real_pk, real_pk)) | ||
147 | return i; | ||
148 | |||
149 | return -1; | ||
150 | } | ||
151 | |||
152 | /* | ||
153 | * check if group with identifier is in group array. | ||
154 | * | ||
155 | * return group number if peer is in list. | ||
156 | * return -1 if group is not in list. | ||
157 | * | ||
158 | * TODO: make this more efficient and maybe use constant time comparisons? | ||
159 | */ | ||
160 | static int get_group_num(const Group_Chats *g_c, const uint8_t *identifier) | ||
161 | { | ||
162 | uint32_t i; | ||
163 | |||
164 | for (i = 0; i < g_c->num_chats; ++i) | ||
165 | if (memcmp(g_c->chats[i].identifier, identifier, GROUP_IDENTIFIER_LENGTH) == 0) | ||
166 | return i; | ||
167 | |||
168 | return -1; | ||
169 | } | ||
170 | |||
171 | /* | ||
172 | * check if peer with peer_number is in peer array. | ||
173 | * | ||
174 | * return peer number if peer is in chat. | ||
175 | * return -1 if peer is not in chat. | ||
176 | * | ||
177 | * TODO: make this more efficient. | ||
178 | */ | ||
179 | static int get_peer_index(Group_c *g, uint16_t peer_number) | ||
180 | { | ||
181 | uint32_t i; | ||
182 | |||
183 | for (i = 0; i < g->numpeers; ++i) | ||
184 | if (g->group[i].peer_number == peer_number) | ||
185 | return i; | ||
186 | |||
187 | return -1; | ||
188 | } | ||
189 | |||
190 | |||
191 | static uint64_t calculate_comp_value(const uint8_t *pk1, const uint8_t *pk2) | ||
192 | { | ||
193 | uint64_t cmp1 = 0, cmp2 = 0; | ||
194 | |||
195 | unsigned int i; | ||
196 | |||
197 | for (i = 0; i < sizeof(uint64_t); ++i) { | ||
198 | cmp1 = (cmp1 << 8) + (uint64_t)pk1[i]; | ||
199 | cmp2 = (cmp2 << 8) + (uint64_t)pk2[i]; | ||
200 | } | ||
201 | |||
202 | return (cmp1 - cmp2); | ||
203 | } | ||
204 | |||
205 | enum { | ||
206 | GROUPCHAT_CLOSEST_NONE, | ||
207 | GROUPCHAT_CLOSEST_ADDED, | ||
208 | GROUPCHAT_CLOSEST_REMOVED | ||
209 | }; | ||
210 | |||
211 | static int friend_in_close(Group_c *g, int friendcon_id); | ||
212 | static int add_conn_to_groupchat(Group_Chats *g_c, int friendcon_id, int groupnumber, uint8_t closest, uint8_t lock); | ||
213 | |||
214 | static int add_to_closest(Group_Chats *g_c, int groupnumber, const uint8_t *real_pk, const uint8_t *temp_pk) | ||
215 | { | ||
216 | Group_c *g = get_group_c(g_c, groupnumber); | ||
217 | |||
218 | if (!g) | ||
219 | return -1; | ||
220 | |||
221 | if (memcmp(g->real_pk, real_pk, crypto_box_PUBLICKEYBYTES) == 0) | ||
222 | return -1; | ||
223 | |||
224 | unsigned int i; | ||
225 | unsigned int index = DESIRED_CLOSE_CONNECTIONS; | ||
226 | |||
227 | for (i = 0; i < DESIRED_CLOSE_CONNECTIONS; ++i) { | ||
228 | if (g->closest_peers[i].entry && memcmp(real_pk, g->closest_peers[i].real_pk, crypto_box_PUBLICKEYBYTES) == 0) { | ||
229 | return 0; | ||
230 | } | ||
231 | } | ||
232 | |||
233 | for (i = 0; i < DESIRED_CLOSE_CONNECTIONS; ++i) { | ||
234 | if (g->closest_peers[i].entry == 0) { | ||
235 | index = i; | ||
236 | break; | ||
237 | } | ||
238 | } | ||
239 | |||
240 | if (index == DESIRED_CLOSE_CONNECTIONS) { | ||
241 | uint64_t comp_val = calculate_comp_value(g->real_pk, real_pk); | ||
242 | uint64_t comp_d = 0; | ||
243 | |||
244 | for (i = 0; i < (DESIRED_CLOSE_CONNECTIONS / 2); ++i) { | ||
245 | uint64_t comp; | ||
246 | comp = calculate_comp_value(g->real_pk, g->closest_peers[i].real_pk); | ||
247 | |||
248 | if (comp > comp_val && comp > comp_d) { | ||
249 | index = i; | ||
250 | comp_d = comp; | ||
251 | } | ||
252 | } | ||
253 | |||
254 | comp_val = calculate_comp_value(real_pk, g->real_pk); | ||
255 | |||
256 | for (i = (DESIRED_CLOSE_CONNECTIONS / 2); i < DESIRED_CLOSE_CONNECTIONS; ++i) { | ||
257 | uint64_t comp = calculate_comp_value(g->closest_peers[i].real_pk, g->real_pk); | ||
258 | |||
259 | if (comp > comp_val && comp > comp_d) { | ||
260 | index = i; | ||
261 | comp_d = comp; | ||
262 | } | ||
263 | } | ||
264 | } | ||
265 | |||
266 | if (index == DESIRED_CLOSE_CONNECTIONS) { | ||
267 | return -1; | ||
268 | } | ||
269 | |||
270 | uint8_t old_real_pk[crypto_box_PUBLICKEYBYTES]; | ||
271 | uint8_t old_temp_pk[crypto_box_PUBLICKEYBYTES]; | ||
272 | uint8_t old = 0; | ||
273 | |||
274 | if (g->closest_peers[index].entry) { | ||
275 | memcpy(old_real_pk, g->closest_peers[index].real_pk, crypto_box_PUBLICKEYBYTES); | ||
276 | memcpy(old_temp_pk, g->closest_peers[index].temp_pk, crypto_box_PUBLICKEYBYTES); | ||
277 | old = 1; | ||
278 | } | ||
279 | |||
280 | g->closest_peers[index].entry = 1; | ||
281 | memcpy(g->closest_peers[index].real_pk, real_pk, crypto_box_PUBLICKEYBYTES); | ||
282 | memcpy(g->closest_peers[index].temp_pk, temp_pk, crypto_box_PUBLICKEYBYTES); | ||
283 | |||
284 | if (old) { | ||
285 | add_to_closest(g_c, groupnumber, old_real_pk, old_temp_pk); | ||
286 | } | ||
287 | |||
288 | if (!g->changed) | ||
289 | g->changed = GROUPCHAT_CLOSEST_ADDED; | ||
290 | |||
291 | return 0; | ||
292 | } | ||
293 | |||
294 | static unsigned int pk_in_closest_peers(Group_c *g, uint8_t *real_pk) | ||
295 | { | ||
296 | unsigned int i; | ||
297 | |||
298 | for (i = 0; i < DESIRED_CLOSE_CONNECTIONS; ++i) { | ||
299 | if (!g->closest_peers[i].entry) | ||
300 | continue; | ||
301 | |||
302 | if (memcmp(g->closest_peers[i].real_pk, real_pk, crypto_box_PUBLICKEYBYTES) == 0) | ||
303 | return 1; | ||
304 | |||
305 | } | ||
306 | |||
307 | return 0; | ||
308 | } | ||
309 | |||
310 | static int send_packet_online(Friend_Connections *fr_c, int friendcon_id, uint16_t group_num, uint8_t *identifier); | ||
311 | |||
312 | static int connect_to_closest(Group_Chats *g_c, int groupnumber) | ||
313 | { | ||
314 | Group_c *g = get_group_c(g_c, groupnumber); | ||
315 | |||
316 | if (!g) | ||
317 | return -1; | ||
318 | |||
319 | if (!g->changed) | ||
320 | return 0; | ||
321 | |||
322 | unsigned int i; | ||
323 | |||
324 | if (g->changed == GROUPCHAT_CLOSEST_REMOVED) { | ||
325 | for (i = 0; i < g->numpeers; ++i) { | ||
326 | add_to_closest(g_c, groupnumber, g->group[i].real_pk, g->group[i].temp_pk); | ||
327 | } | ||
328 | } | ||
329 | |||
330 | for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) { | ||
331 | if (g->close[i].type == GROUPCHAT_CLOSE_NONE) | ||
332 | continue; | ||
333 | |||
334 | if (!g->close[i].closest) | ||
335 | continue; | ||
336 | |||
337 | uint8_t real_pk[crypto_box_PUBLICKEYBYTES]; | ||
338 | uint8_t dht_temp_pk[crypto_box_PUBLICKEYBYTES]; | ||
339 | get_friendcon_public_keys(real_pk, dht_temp_pk, g_c->fr_c, g->close[i].number); | ||
340 | |||
341 | if (!pk_in_closest_peers(g, real_pk)) { | ||
342 | g->close[i].type = GROUPCHAT_CLOSE_NONE; | ||
343 | kill_friend_connection(g_c->fr_c, g->close[i].number); | ||
344 | } | ||
345 | } | ||
346 | |||
347 | for (i = 0; i < DESIRED_CLOSE_CONNECTIONS; ++i) { | ||
348 | if (!g->closest_peers[i].entry) | ||
349 | continue; | ||
350 | |||
351 | int friendcon_id = getfriend_conn_id_pk(g_c->fr_c, g->closest_peers[i].real_pk); | ||
352 | |||
353 | uint8_t lock = 1; | ||
354 | |||
355 | if (friendcon_id == -1) { | ||
356 | friendcon_id = new_friend_connection(g_c->fr_c, g->closest_peers[i].real_pk); | ||
357 | lock = 0; | ||
358 | |||
359 | if (friendcon_id == -1) { | ||
360 | continue; | ||
361 | } | ||
362 | |||
363 | set_dht_temp_pk(g_c->fr_c, friendcon_id, g->closest_peers[i].temp_pk); | ||
364 | } | ||
365 | |||
366 | add_conn_to_groupchat(g_c, friendcon_id, groupnumber, 1, lock); | ||
367 | |||
368 | if (friend_con_connected(g_c->fr_c, friendcon_id) == FRIENDCONN_STATUS_CONNECTED) { | ||
369 | send_packet_online(g_c->fr_c, friendcon_id, groupnumber, g->identifier); | ||
370 | } | ||
371 | } | ||
372 | |||
373 | g->changed = GROUPCHAT_CLOSEST_NONE; | ||
374 | |||
375 | return 0; | ||
376 | } | ||
377 | |||
378 | /* | ||
379 | * Add a peer to the group chat. | ||
380 | * | ||
381 | * return peer_index if success or peer already in chat. | ||
382 | * return -1 if error. | ||
383 | */ | ||
384 | static int addpeer(Group_Chats *g_c, int groupnumber, const uint8_t *real_pk, const uint8_t *temp_pk, | ||
385 | uint16_t peer_number) | ||
386 | { | ||
387 | Group_c *g = get_group_c(g_c, groupnumber); | ||
388 | |||
389 | if (!g) | ||
390 | return -1; | ||
391 | |||
392 | //TODO | ||
393 | int peer_index = peer_in_chat(g, real_pk); | ||
394 | |||
395 | if (peer_index != -1) { | ||
396 | id_copy(g->group[peer_index].temp_pk, temp_pk); | ||
397 | |||
398 | if (g->group[peer_index].peer_number != peer_number) | ||
399 | return -1; | ||
400 | |||
401 | return peer_index; | ||
402 | } | ||
403 | |||
404 | peer_index = get_peer_index(g, peer_number); | ||
405 | |||
406 | if (peer_index != -1) | ||
407 | return -1; | ||
408 | |||
409 | Group_Peer *temp; | ||
410 | temp = realloc(g->group, sizeof(Group_Peer) * (g->numpeers + 1)); | ||
411 | |||
412 | if (temp == NULL) | ||
413 | return -1; | ||
414 | |||
415 | memset(&(temp[g->numpeers]), 0, sizeof(Group_Peer)); | ||
416 | g->group = temp; | ||
417 | |||
418 | id_copy(g->group[g->numpeers].real_pk, real_pk); | ||
419 | id_copy(g->group[g->numpeers].temp_pk, temp_pk); | ||
420 | g->group[g->numpeers].peer_number = peer_number; | ||
421 | |||
422 | g->group[g->numpeers].last_recv = unix_time(); | ||
423 | ++g->numpeers; | ||
424 | |||
425 | add_to_closest(g_c, groupnumber, real_pk, temp_pk); | ||
426 | |||
427 | if (g_c->peer_namelistchange) | ||
428 | g_c->peer_namelistchange(g_c->m, groupnumber, g->numpeers - 1, CHAT_CHANGE_PEER_ADD, | ||
429 | g_c->group_namelistchange_userdata); | ||
430 | |||
431 | if (g->peer_on_join) | ||
432 | g->peer_on_join(g->object, groupnumber, g->numpeers - 1); | ||
433 | |||
434 | return (g->numpeers - 1); | ||
435 | } | ||
436 | |||
437 | static int remove_close_conn(Group_Chats *g_c, int groupnumber, int friendcon_id) | ||
438 | { | ||
439 | Group_c *g = get_group_c(g_c, groupnumber); | ||
440 | |||
441 | if (!g) | ||
442 | return -1; | ||
443 | |||
444 | uint32_t i; | ||
445 | |||
446 | for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) { | ||
447 | if (g->close[i].type == GROUPCHAT_CLOSE_NONE) | ||
448 | continue; | ||
449 | |||
450 | if (g->close[i].number == (unsigned int)friendcon_id) { | ||
451 | g->close[i].type = GROUPCHAT_CLOSE_NONE; | ||
452 | kill_friend_connection(g_c->fr_c, friendcon_id); | ||
453 | return 0; | ||
454 | } | ||
455 | } | ||
456 | |||
457 | return -1; | ||
458 | } | ||
459 | |||
460 | |||
461 | /* | ||
462 | * Delete a peer from the group chat. | ||
463 | * | ||
464 | * return 0 if success | ||
465 | * return -1 if error. | ||
466 | */ | ||
467 | static int delpeer(Group_Chats *g_c, int groupnumber, int peer_index) | ||
468 | { | ||
469 | Group_c *g = get_group_c(g_c, groupnumber); | ||
470 | |||
471 | if (!g) | ||
472 | return -1; | ||
473 | |||
474 | uint32_t i; | ||
475 | |||
476 | for (i = 0; i < DESIRED_CLOSE_CONNECTIONS; ++i) { /* If peer is in closest_peers list, remove it. */ | ||
477 | if (g->closest_peers[i].entry && id_equal(g->closest_peers[i].real_pk, g->group[peer_index].real_pk)) { | ||
478 | g->closest_peers[i].entry = 0; | ||
479 | g->changed = GROUPCHAT_CLOSEST_REMOVED; | ||
480 | break; | ||
481 | } | ||
482 | } | ||
483 | |||
484 | int friendcon_id = getfriend_conn_id_pk(g_c->fr_c, g->group[peer_index].real_pk); | ||
485 | |||
486 | if (friendcon_id != -1) { | ||
487 | remove_close_conn(g_c, groupnumber, friendcon_id); | ||
488 | } | ||
489 | |||
490 | Group_Peer *temp; | ||
491 | --g->numpeers; | ||
492 | |||
493 | void *peer_object = g->group[peer_index].object; | ||
494 | |||
495 | if (g->numpeers == 0) { | ||
496 | free(g->group); | ||
497 | g->group = NULL; | ||
498 | } else { | ||
499 | if (g->numpeers != (uint32_t)peer_index) | ||
500 | memcpy(&g->group[peer_index], &g->group[g->numpeers], sizeof(Group_Peer)); | ||
501 | |||
502 | temp = realloc(g->group, sizeof(Group_Peer) * (g->numpeers)); | ||
503 | |||
504 | if (temp == NULL) | ||
505 | return -1; | ||
506 | |||
507 | g->group = temp; | ||
508 | } | ||
509 | |||
510 | if (g_c->peer_namelistchange) | ||
511 | g_c->peer_namelistchange(g_c->m, groupnumber, peer_index, CHAT_CHANGE_PEER_DEL, g_c->group_namelistchange_userdata); | ||
512 | |||
513 | if (g->peer_on_leave) | ||
514 | g->peer_on_leave(g->object, groupnumber, peer_index, peer_object); | ||
515 | |||
516 | return 0; | ||
517 | } | ||
518 | |||
519 | static int setnick(Group_Chats *g_c, int groupnumber, int peer_index, const uint8_t *nick, uint16_t nick_len) | ||
520 | { | ||
521 | if (nick_len > MAX_NAME_LENGTH) | ||
522 | return -1; | ||
523 | |||
524 | Group_c *g = get_group_c(g_c, groupnumber); | ||
525 | |||
526 | if (!g) | ||
527 | return -1; | ||
528 | |||
529 | /* same name as already stored? */ | ||
530 | if (g->group[peer_index].nick_len == nick_len) | ||
531 | if (nick_len == 0 || !memcmp(g->group[peer_index].nick, nick, nick_len)) | ||
532 | return 0; | ||
533 | |||
534 | if (nick_len) | ||
535 | memcpy(g->group[peer_index].nick, nick, nick_len); | ||
536 | |||
537 | g->group[peer_index].nick_len = nick_len; | ||
538 | |||
539 | if (g_c->peer_namelistchange) | ||
540 | g_c->peer_namelistchange(g_c->m, groupnumber, peer_index, CHAT_CHANGE_PEER_NAME, g_c->group_namelistchange_userdata); | ||
541 | |||
542 | return 0; | ||
543 | } | ||
544 | |||
545 | static int settitle(Group_Chats *g_c, int groupnumber, int peer_index, const uint8_t *title, uint8_t title_len) | ||
546 | { | ||
547 | if (title_len > MAX_NAME_LENGTH || title_len == 0) | ||
548 | return -1; | ||
549 | |||
550 | Group_c *g = get_group_c(g_c, groupnumber); | ||
551 | |||
552 | if (!g) | ||
553 | return -1; | ||
554 | |||
555 | /* same as already set? */ | ||
556 | if (g->title_len == title_len && !memcmp(g->title, title, title_len)) | ||
557 | return 0; | ||
558 | |||
559 | memcpy(g->title, title, title_len); | ||
560 | g->title_len = title_len; | ||
561 | |||
562 | if (g_c->title_callback) | ||
563 | g_c->title_callback(g_c->m, groupnumber, peer_index, title, title_len, g_c->title_callback_userdata); | ||
564 | |||
565 | return 0; | ||
566 | } | ||
567 | |||
568 | static void set_conns_type_close(Group_Chats *g_c, int groupnumber, int friendcon_id, uint8_t type) | ||
569 | { | ||
570 | Group_c *g = get_group_c(g_c, groupnumber); | ||
571 | |||
572 | if (!g) | ||
573 | return; | ||
574 | |||
575 | uint32_t i; | ||
576 | |||
577 | for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) { | ||
578 | if (g->close[i].type == GROUPCHAT_CLOSE_NONE) | ||
579 | continue; | ||
580 | |||
581 | if (g->close[i].number != (unsigned int)friendcon_id) | ||
582 | continue; | ||
583 | |||
584 | if (type == GROUPCHAT_CLOSE_ONLINE) { | ||
585 | send_packet_online(g_c->fr_c, friendcon_id, groupnumber, g->identifier); | ||
586 | } else { | ||
587 | g->close[i].type = type; | ||
588 | } | ||
589 | } | ||
590 | } | ||
591 | /* Set the type for all close connections with friendcon_id */ | ||
592 | static void set_conns_status_groups(Group_Chats *g_c, int friendcon_id, uint8_t type) | ||
593 | { | ||
594 | uint32_t i; | ||
595 | |||
596 | for (i = 0; i < g_c->num_chats; ++i) { | ||
597 | set_conns_type_close(g_c, i, friendcon_id, type); | ||
598 | } | ||
599 | } | ||
600 | |||
601 | static int handle_status(void *object, int friendcon_id, uint8_t status) | ||
602 | { | ||
603 | Group_Chats *g_c = object; | ||
604 | |||
605 | if (status) { /* Went online */ | ||
606 | set_conns_status_groups(g_c, friendcon_id, GROUPCHAT_CLOSE_ONLINE); | ||
607 | } else { /* Went offline */ | ||
608 | set_conns_status_groups(g_c, friendcon_id, GROUPCHAT_CLOSE_CONNECTION); | ||
609 | //TODO remove timedout connections? | ||
610 | } | ||
611 | |||
612 | return 0; | ||
613 | } | ||
614 | |||
615 | static int handle_packet(void *object, int friendcon_id, uint8_t *data, uint16_t length); | ||
616 | static int handle_lossy(void *object, int friendcon_id, const uint8_t *data, uint16_t length); | ||
617 | |||
618 | /* Add friend to group chat. | ||
619 | * | ||
620 | * return close index on success | ||
621 | * return -1 on failure. | ||
622 | */ | ||
623 | static int add_conn_to_groupchat(Group_Chats *g_c, int friendcon_id, int groupnumber, uint8_t closest, uint8_t lock) | ||
624 | { | ||
625 | Group_c *g = get_group_c(g_c, groupnumber); | ||
626 | |||
627 | if (!g) | ||
628 | return -1; | ||
629 | |||
630 | uint16_t i, ind = MAX_GROUP_CONNECTIONS; | ||
631 | |||
632 | for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) { | ||
633 | if (g->close[i].type == GROUPCHAT_CLOSE_NONE) { | ||
634 | ind = i; | ||
635 | continue; | ||
636 | } | ||
637 | |||
638 | if (g->close[i].number == (uint32_t)friendcon_id) { | ||
639 | g->close[i].closest = closest; | ||
640 | return i; /* Already in list. */ | ||
641 | } | ||
642 | } | ||
643 | |||
644 | if (ind == MAX_GROUP_CONNECTIONS) | ||
645 | return -1; | ||
646 | |||
647 | if (lock) | ||
648 | friend_connection_lock(g_c->fr_c, friendcon_id); | ||
649 | |||
650 | g->close[ind].type = GROUPCHAT_CLOSE_CONNECTION; | ||
651 | g->close[ind].number = friendcon_id; | ||
652 | g->close[ind].closest = closest; | ||
653 | //TODO | ||
654 | friend_connection_callbacks(g_c->m->fr_c, friendcon_id, GROUPCHAT_CALLBACK_INDEX, &handle_status, &handle_packet, | ||
655 | &handle_lossy, g_c, friendcon_id); | ||
656 | |||
657 | return ind; | ||
658 | } | ||
659 | |||
660 | /* Creates a new groupchat and puts it in the chats array. | ||
661 | * | ||
662 | * type is one of GROUPCHAT_TYPE_* | ||
663 | * | ||
664 | * return group number on success. | ||
665 | * return -1 on failure. | ||
666 | */ | ||
667 | int add_groupchat(Group_Chats *g_c, uint8_t type) | ||
668 | { | ||
669 | int groupnumber = create_group_chat(g_c); | ||
670 | |||
671 | if (groupnumber == -1) | ||
672 | return -1; | ||
673 | |||
674 | Group_c *g = &g_c->chats[groupnumber]; | ||
675 | |||
676 | g->status = GROUPCHAT_STATUS_CONNECTED; | ||
677 | g->number_joined = -1; | ||
678 | new_symmetric_key(g->identifier + 1); | ||
679 | g->identifier[0] = type; | ||
680 | g->peer_number = 0; /* Founder is peer 0. */ | ||
681 | memcpy(g->real_pk, g_c->m->net_crypto->self_public_key, crypto_box_PUBLICKEYBYTES); | ||
682 | int peer_index = addpeer(g_c, groupnumber, g->real_pk, g_c->m->dht->self_public_key, 0); | ||
683 | |||
684 | if (peer_index == -1) { | ||
685 | return -1; | ||
686 | } | ||
687 | |||
688 | setnick(g_c, groupnumber, peer_index, g_c->m->name, g_c->m->name_length); | ||
689 | |||
690 | return groupnumber; | ||
691 | } | ||
692 | |||
693 | static int group_kill_peer_send(const Group_Chats *g_c, int groupnumber, uint16_t peer_num); | ||
694 | /* Delete a groupchat from the chats array. | ||
695 | * | ||
696 | * return 0 on success. | ||
697 | * return -1 if failure. | ||
698 | */ | ||
699 | int del_groupchat(Group_Chats *g_c, int groupnumber) | ||
700 | { | ||
701 | Group_c *g = get_group_c(g_c, groupnumber); | ||
702 | |||
703 | if (!g) | ||
704 | return -1; | ||
705 | |||
706 | group_kill_peer_send(g_c, groupnumber, g->peer_number); | ||
707 | |||
708 | unsigned int i; | ||
709 | |||
710 | for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) { | ||
711 | if (g->close[i].type == GROUPCHAT_CLOSE_NONE) | ||
712 | continue; | ||
713 | |||
714 | g->close[i].type = GROUPCHAT_CLOSE_NONE; | ||
715 | kill_friend_connection(g_c->fr_c, g->close[i].number); | ||
716 | } | ||
717 | |||
718 | for (i = 0; i < g->numpeers; ++i) { | ||
719 | if (g->peer_on_leave) | ||
720 | g->peer_on_leave(g->object, groupnumber, i, g->group[i].object); | ||
721 | } | ||
722 | |||
723 | free(g->group); | ||
724 | |||
725 | if (g->group_on_delete) | ||
726 | g->group_on_delete(g->object, groupnumber); | ||
727 | |||
728 | return wipe_group_chat(g_c, groupnumber); | ||
729 | } | ||
730 | |||
731 | /* Copy the public key of peernumber who is in groupnumber to pk. | ||
732 | * pk must be crypto_box_PUBLICKEYBYTES long. | ||
733 | * | ||
734 | * returns 0 on success | ||
735 | * returns -1 on failure | ||
736 | */ | ||
737 | int group_peer_pubkey(const Group_Chats *g_c, int groupnumber, int peernumber, uint8_t *pk) | ||
738 | { | ||
739 | Group_c *g = get_group_c(g_c, groupnumber); | ||
740 | |||
741 | if (!g) | ||
742 | return -1; | ||
743 | |||
744 | if ((uint32_t)peernumber >= g->numpeers) | ||
745 | return -1; | ||
746 | |||
747 | memcpy(pk, g->group[peernumber].real_pk, crypto_box_PUBLICKEYBYTES); | ||
748 | return 0; | ||
749 | } | ||
750 | |||
751 | /* Copy the name of peernumber who is in groupnumber to name. | ||
752 | * name must be at least MAX_NAME_LENGTH long. | ||
753 | * | ||
754 | * return length of name if success | ||
755 | * return -1 if failure | ||
756 | */ | ||
757 | int group_peername(const Group_Chats *g_c, int groupnumber, int peernumber, uint8_t *name) | ||
758 | { | ||
759 | Group_c *g = get_group_c(g_c, groupnumber); | ||
760 | |||
761 | if (!g) | ||
762 | return -1; | ||
763 | |||
764 | if ((uint32_t)peernumber >= g->numpeers) | ||
765 | return -1; | ||
766 | |||
767 | if (g->group[peernumber].nick_len == 0) { | ||
768 | memcpy(name, "Tox User", 8); | ||
769 | return 8; | ||
770 | } | ||
771 | |||
772 | memcpy(name, g->group[peernumber].nick, g->group[peernumber].nick_len); | ||
773 | return g->group[peernumber].nick_len; | ||
774 | } | ||
775 | |||
776 | /* List all the peers in the group chat. | ||
777 | * | ||
778 | * Copies the names of the peers to the name[length][MAX_NAME_LENGTH] array. | ||
779 | * | ||
780 | * Copies the lengths of the names to lengths[length] | ||
781 | * | ||
782 | * returns the number of peers on success. | ||
783 | * | ||
784 | * return -1 on failure. | ||
785 | */ | ||
786 | int group_names(const Group_Chats *g_c, int groupnumber, uint8_t names[][MAX_NAME_LENGTH], uint16_t lengths[], | ||
787 | uint16_t length) | ||
788 | { | ||
789 | Group_c *g = get_group_c(g_c, groupnumber); | ||
790 | |||
791 | if (!g) | ||
792 | return -1; | ||
793 | |||
794 | unsigned int i; | ||
795 | |||
796 | for (i = 0; i < g->numpeers && i < length; ++i) { | ||
797 | lengths[i] = group_peername(g_c, groupnumber, i, names[i]); | ||
798 | } | ||
799 | |||
800 | return i; | ||
801 | } | ||
802 | |||
803 | /* Return the number of peers in the group chat on success. | ||
804 | * return -1 on failure | ||
805 | */ | ||
806 | int group_number_peers(const Group_Chats *g_c, int groupnumber) | ||
807 | { | ||
808 | Group_c *g = get_group_c(g_c, groupnumber); | ||
809 | |||
810 | if (!g) | ||
811 | return -1; | ||
812 | |||
813 | return g->numpeers; | ||
814 | } | ||
815 | |||
816 | /* return 1 if the peernumber corresponds to ours. | ||
817 | * return 0 on failure. | ||
818 | */ | ||
819 | unsigned int group_peernumber_is_ours(const Group_Chats *g_c, int groupnumber, int peernumber) | ||
820 | { | ||
821 | Group_c *g = get_group_c(g_c, groupnumber); | ||
822 | |||
823 | if (!g) | ||
824 | return 0; | ||
825 | |||
826 | if (g->status != GROUPCHAT_STATUS_CONNECTED) | ||
827 | return 0; | ||
828 | |||
829 | if ((uint32_t)peernumber >= g->numpeers) | ||
830 | return 0; | ||
831 | |||
832 | return g->peer_number == g->group[peernumber].peer_number; | ||
833 | } | ||
834 | |||
835 | /* return the type of groupchat (GROUPCHAT_TYPE_) that groupnumber is. | ||
836 | * | ||
837 | * return -1 on failure. | ||
838 | * return type on success. | ||
839 | */ | ||
840 | int group_get_type(const Group_Chats *g_c, int groupnumber) | ||
841 | { | ||
842 | Group_c *g = get_group_c(g_c, groupnumber); | ||
843 | |||
844 | if (!g) | ||
845 | return -1; | ||
846 | |||
847 | return g->identifier[0]; | ||
848 | } | ||
849 | |||
850 | /* Send a group packet to friendcon_id. | ||
851 | * | ||
852 | * return 1 on success | ||
853 | * return 0 on failure | ||
854 | */ | ||
855 | static unsigned int send_packet_group_peer(Friend_Connections *fr_c, int friendcon_id, uint8_t packet_id, | ||
856 | uint16_t group_num, const uint8_t *data, uint16_t length) | ||
857 | { | ||
858 | if (1 + sizeof(uint16_t) + length > MAX_CRYPTO_DATA_SIZE) | ||
859 | return 0; | ||
860 | |||
861 | group_num = htons(group_num); | ||
862 | uint8_t packet[1 + sizeof(uint16_t) + length]; | ||
863 | packet[0] = packet_id; | ||
864 | memcpy(packet + 1, &group_num, sizeof(uint16_t)); | ||
865 | memcpy(packet + 1 + sizeof(uint16_t), data, length); | ||
866 | return write_cryptpacket(fr_c->net_crypto, friend_connection_crypt_connection_id(fr_c, friendcon_id), packet, | ||
867 | sizeof(packet), 0) != -1; | ||
868 | } | ||
869 | |||
870 | /* Send a group lossy packet to friendcon_id. | ||
871 | * | ||
872 | * return 1 on success | ||
873 | * return 0 on failure | ||
874 | */ | ||
875 | static unsigned int send_lossy_group_peer(Friend_Connections *fr_c, int friendcon_id, uint8_t packet_id, | ||
876 | uint16_t group_num, const uint8_t *data, uint16_t length) | ||
877 | { | ||
878 | if (1 + sizeof(uint16_t) + length > MAX_CRYPTO_DATA_SIZE) | ||
879 | return 0; | ||
880 | |||
881 | group_num = htons(group_num); | ||
882 | uint8_t packet[1 + sizeof(uint16_t) + length]; | ||
883 | packet[0] = packet_id; | ||
884 | memcpy(packet + 1, &group_num, sizeof(uint16_t)); | ||
885 | memcpy(packet + 1 + sizeof(uint16_t), data, length); | ||
886 | return send_lossy_cryptpacket(fr_c->net_crypto, friend_connection_crypt_connection_id(fr_c, friendcon_id), packet, | ||
887 | sizeof(packet)) != -1; | ||
888 | } | ||
889 | |||
890 | #define INVITE_PACKET_SIZE (1 + sizeof(uint16_t) + GROUP_IDENTIFIER_LENGTH) | ||
891 | #define INVITE_ID 0 | ||
892 | |||
893 | #define INVITE_RESPONSE_PACKET_SIZE (1 + sizeof(uint16_t) * 2 + GROUP_IDENTIFIER_LENGTH) | ||
894 | #define INVITE_RESPONSE_ID 1 | ||
895 | |||
896 | /* invite friendnumber to groupnumber | ||
897 | * return 0 on success | ||
898 | * return -1 on failure | ||
899 | */ | ||
900 | int invite_friend(Group_Chats *g_c, int32_t friendnumber, int groupnumber) | ||
901 | { | ||
902 | Group_c *g = get_group_c(g_c, groupnumber); | ||
903 | |||
904 | if (!g) | ||
905 | return -1; | ||
906 | |||
907 | uint8_t invite[INVITE_PACKET_SIZE]; | ||
908 | invite[0] = INVITE_ID; | ||
909 | uint16_t groupchat_num = htons((uint16_t)groupnumber); | ||
910 | memcpy(invite + 1, &groupchat_num, sizeof(groupchat_num)); | ||
911 | memcpy(invite + 1 + sizeof(groupchat_num), g->identifier, GROUP_IDENTIFIER_LENGTH); | ||
912 | |||
913 | if (send_group_invite_packet(g_c->m, friendnumber, invite, sizeof(invite))) { | ||
914 | return 0; | ||
915 | } else { | ||
916 | wipe_group_chat(g_c, groupnumber); | ||
917 | return -1; | ||
918 | } | ||
919 | } | ||
920 | |||
921 | static unsigned int send_peer_query(Group_Chats *g_c, int friendcon_id, uint16_t group_num); | ||
922 | |||
923 | /* Join a group (you need to have been invited first.) | ||
924 | * | ||
925 | * expected_type is the groupchat type we expect the chat we are joining is. | ||
926 | * | ||
927 | * returns group number on success | ||
928 | * returns -1 on failure. | ||
929 | */ | ||
930 | int join_groupchat(Group_Chats *g_c, int32_t friendnumber, uint8_t expected_type, const uint8_t *data, uint16_t length) | ||
931 | { | ||
932 | if (length != sizeof(uint16_t) + GROUP_IDENTIFIER_LENGTH) | ||
933 | return -1; | ||
934 | |||
935 | if (data[sizeof(uint16_t)] != expected_type) | ||
936 | return -1; | ||
937 | |||
938 | int friendcon_id = getfriendcon_id(g_c->m, friendnumber); | ||
939 | |||
940 | if (friendcon_id == -1) | ||
941 | return -1; | ||
942 | |||
943 | if (get_group_num(g_c, data + sizeof(uint16_t)) != -1) | ||
944 | return -1; | ||
945 | |||
946 | int groupnumber = create_group_chat(g_c); | ||
947 | |||
948 | if (groupnumber == -1) | ||
949 | return -1; | ||
950 | |||
951 | Group_c *g = &g_c->chats[groupnumber]; | ||
952 | |||
953 | uint16_t group_num = htons(groupnumber); | ||
954 | g->status = GROUPCHAT_STATUS_VALID; | ||
955 | g->number_joined = -1; | ||
956 | memcpy(g->real_pk, g_c->m->net_crypto->self_public_key, crypto_box_PUBLICKEYBYTES); | ||
957 | |||
958 | uint8_t response[INVITE_RESPONSE_PACKET_SIZE]; | ||
959 | response[0] = INVITE_RESPONSE_ID; | ||
960 | memcpy(response + 1, &group_num, sizeof(uint16_t)); | ||
961 | memcpy(response + 1 + sizeof(uint16_t), data, sizeof(uint16_t) + GROUP_IDENTIFIER_LENGTH); | ||
962 | |||
963 | if (send_group_invite_packet(g_c->m, friendnumber, response, sizeof(response))) { | ||
964 | uint16_t other_groupnum; | ||
965 | memcpy(&other_groupnum, data, sizeof(other_groupnum)); | ||
966 | other_groupnum = ntohs(other_groupnum); | ||
967 | memcpy(g->identifier, data + sizeof(uint16_t), GROUP_IDENTIFIER_LENGTH); | ||
968 | int close_index = add_conn_to_groupchat(g_c, friendcon_id, groupnumber, 0, 1); | ||
969 | |||
970 | if (close_index != -1) { | ||
971 | g->close[close_index].group_number = other_groupnum; | ||
972 | g->close[close_index].type = GROUPCHAT_CLOSE_ONLINE; | ||
973 | g->number_joined = friendcon_id; | ||
974 | } | ||
975 | |||
976 | send_peer_query(g_c, friendcon_id, other_groupnum); | ||
977 | return groupnumber; | ||
978 | } else { | ||
979 | g->status = GROUPCHAT_STATUS_NONE; | ||
980 | return -1; | ||
981 | } | ||
982 | } | ||
983 | |||
984 | /* Set the callback for group invites. | ||
985 | * | ||
986 | * Function(Group_Chats *g_c, int32_t friendnumber, uint8_t type, uint8_t *data, uint16_t length, void *userdata) | ||
987 | * | ||
988 | * data of length is what needs to be passed to join_groupchat(). | ||
989 | */ | ||
990 | void g_callback_group_invite(Group_Chats *g_c, void (*function)(Messenger *m, int32_t, uint8_t, const uint8_t *, | ||
991 | uint16_t, void *), void *userdata) | ||
992 | { | ||
993 | g_c->invite_callback = function; | ||
994 | g_c->invite_callback_userdata = userdata; | ||
995 | } | ||
996 | |||
997 | /* Set the callback for group messages. | ||
998 | * | ||
999 | * Function(Group_Chats *g_c, int groupnumber, int friendgroupnumber, uint8_t * message, uint16_t length, void *userdata) | ||
1000 | */ | ||
1001 | void g_callback_group_message(Group_Chats *g_c, void (*function)(Messenger *m, int, int, const uint8_t *, uint16_t, | ||
1002 | void *), void *userdata) | ||
1003 | { | ||
1004 | g_c->message_callback = function; | ||
1005 | g_c->message_callback_userdata = userdata; | ||
1006 | } | ||
1007 | |||
1008 | /* Set the callback for group actions. | ||
1009 | * | ||
1010 | * Function(Group_Chats *g_c, int groupnumber, int friendgroupnumber, uint8_t * message, uint16_t length, void *userdata) | ||
1011 | */ | ||
1012 | void g_callback_group_action(Group_Chats *g_c, void (*function)(Messenger *m, int, int, const uint8_t *, uint16_t, | ||
1013 | void *), void *userdata) | ||
1014 | { | ||
1015 | g_c->action_callback = function; | ||
1016 | g_c->action_callback_userdata = userdata; | ||
1017 | } | ||
1018 | |||
1019 | /* Set handlers for custom lossy packets. | ||
1020 | * | ||
1021 | * NOTE: Handler must return 0 if packet is to be relayed, -1 if the packet should not be relayed. | ||
1022 | * | ||
1023 | * Function(void *group object (set with group_set_object), int groupnumber, int friendgroupnumber, void *group peer object (set with group_peer_set_object), const uint8_t *packet, uint16_t length) | ||
1024 | */ | ||
1025 | void group_lossy_packet_registerhandler(Group_Chats *g_c, uint8_t byte, int (*function)(void *, int, int, void *, | ||
1026 | const uint8_t *, uint16_t)) | ||
1027 | { | ||
1028 | g_c->lossy_packethandlers[byte].function = function; | ||
1029 | } | ||
1030 | |||
1031 | /* Set callback function for peer name list changes. | ||
1032 | * | ||
1033 | * It gets called every time the name list changes(new peer/name, deleted peer) | ||
1034 | * Function(Group_Chats *g_c, int groupnumber, int peernumber, TOX_CHAT_CHANGE change, void *userdata) | ||
1035 | */ | ||
1036 | void g_callback_group_namelistchange(Group_Chats *g_c, void (*function)(Messenger *m, int, int, uint8_t, void *), | ||
1037 | void *userdata) | ||
1038 | { | ||
1039 | g_c->peer_namelistchange = function; | ||
1040 | g_c->group_namelistchange_userdata = userdata; | ||
1041 | } | ||
1042 | |||
1043 | /* Set callback function for title changes. | ||
1044 | * | ||
1045 | * Function(Group_Chats *g_c, int groupnumber, int friendgroupnumber, uint8_t * title, uint8_t length, void *userdata) | ||
1046 | * if friendgroupnumber == -1, then author is unknown (e.g. initial joining the group) | ||
1047 | */ | ||
1048 | void g_callback_group_title(Group_Chats *g_c, void (*function)(Messenger *m, int, int, const uint8_t *, uint8_t, | ||
1049 | void *), void *userdata) | ||
1050 | { | ||
1051 | g_c->title_callback = function; | ||
1052 | g_c->title_callback_userdata = userdata; | ||
1053 | } | ||
1054 | |||
1055 | /* Set a function to be called when a new peer joins a group chat. | ||
1056 | * | ||
1057 | * Function(void *group object (set with group_set_object), int groupnumber, int friendgroupnumber) | ||
1058 | * | ||
1059 | * return 0 on success. | ||
1060 | * return -1 on failure. | ||
1061 | */ | ||
1062 | int callback_groupchat_peer_new(const Group_Chats *g_c, int groupnumber, void (*function)(void *, int, int)) | ||
1063 | { | ||
1064 | Group_c *g = get_group_c(g_c, groupnumber); | ||
1065 | |||
1066 | if (!g) | ||
1067 | return -1; | ||
1068 | |||
1069 | g->peer_on_join = function; | ||
1070 | return 0; | ||
1071 | } | ||
1072 | |||
1073 | /* Set a function to be called when a peer leaves a group chat. | ||
1074 | * | ||
1075 | * Function(void *group object (set with group_set_object), int groupnumber, int friendgroupnumber, void *group peer object (set with group_peer_set_object)) | ||
1076 | * | ||
1077 | * return 0 on success. | ||
1078 | * return -1 on failure. | ||
1079 | */ | ||
1080 | int callback_groupchat_peer_delete(Group_Chats *g_c, int groupnumber, void (*function)(void *, int, int, void *)) | ||
1081 | { | ||
1082 | Group_c *g = get_group_c(g_c, groupnumber); | ||
1083 | |||
1084 | if (!g) | ||
1085 | return -1; | ||
1086 | |||
1087 | g->peer_on_leave = function; | ||
1088 | return 0; | ||
1089 | } | ||
1090 | |||
1091 | /* Set a function to be called when the group chat is deleted. | ||
1092 | * | ||
1093 | * Function(void *group object (set with group_set_object), int groupnumber) | ||
1094 | * | ||
1095 | * return 0 on success. | ||
1096 | * return -1 on failure. | ||
1097 | */ | ||
1098 | int callback_groupchat_delete(Group_Chats *g_c, int groupnumber, void (*function)(void *, int)) | ||
1099 | { | ||
1100 | Group_c *g = get_group_c(g_c, groupnumber); | ||
1101 | |||
1102 | if (!g) | ||
1103 | return -1; | ||
1104 | |||
1105 | g->group_on_delete = function; | ||
1106 | return 0; | ||
1107 | } | ||
1108 | |||
1109 | static unsigned int send_message_group(const Group_Chats *g_c, int groupnumber, uint8_t message_id, const uint8_t *data, | ||
1110 | uint16_t len); | ||
1111 | |||
1112 | #define GROUP_MESSAGE_PING_ID 0 | ||
1113 | int group_ping_send(const Group_Chats *g_c, int groupnumber) | ||
1114 | { | ||
1115 | if (send_message_group(g_c, groupnumber, GROUP_MESSAGE_PING_ID, 0, 0)) { | ||
1116 | return 0; | ||
1117 | } else { | ||
1118 | return -1; | ||
1119 | } | ||
1120 | } | ||
1121 | |||
1122 | #define GROUP_MESSAGE_NEW_PEER_ID 16 | ||
1123 | #define GROUP_MESSAGE_NEW_PEER_LENGTH (sizeof(uint16_t) + crypto_box_PUBLICKEYBYTES * 2) | ||
1124 | /* send a new_peer message | ||
1125 | * return 0 on success | ||
1126 | * return -1 on failure | ||
1127 | */ | ||
1128 | int group_new_peer_send(const Group_Chats *g_c, int groupnumber, uint16_t peer_num, const uint8_t *real_pk, | ||
1129 | uint8_t *temp_pk) | ||
1130 | { | ||
1131 | uint8_t packet[GROUP_MESSAGE_NEW_PEER_LENGTH]; | ||
1132 | |||
1133 | peer_num = htons(peer_num); | ||
1134 | memcpy(packet, &peer_num, sizeof(uint16_t)); | ||
1135 | memcpy(packet + sizeof(uint16_t), real_pk, crypto_box_PUBLICKEYBYTES); | ||
1136 | memcpy(packet + sizeof(uint16_t) + crypto_box_PUBLICKEYBYTES, temp_pk, crypto_box_PUBLICKEYBYTES); | ||
1137 | |||
1138 | if (send_message_group(g_c, groupnumber, GROUP_MESSAGE_NEW_PEER_ID, packet, sizeof(packet))) { | ||
1139 | return 0; | ||
1140 | } else { | ||
1141 | return -1; | ||
1142 | } | ||
1143 | } | ||
1144 | |||
1145 | #define GROUP_MESSAGE_KILL_PEER_ID 17 | ||
1146 | #define GROUP_MESSAGE_KILL_PEER_LENGTH (sizeof(uint16_t)) | ||
1147 | |||
1148 | /* send a kill_peer message | ||
1149 | * return 0 on success | ||
1150 | * return -1 on failure | ||
1151 | */ | ||
1152 | int group_kill_peer_send(const Group_Chats *g_c, int groupnumber, uint16_t peer_num) | ||
1153 | { | ||
1154 | uint8_t packet[GROUP_MESSAGE_KILL_PEER_LENGTH]; | ||
1155 | |||
1156 | peer_num = htons(peer_num); | ||
1157 | memcpy(packet, &peer_num, sizeof(uint16_t)); | ||
1158 | |||
1159 | if (send_message_group(g_c, groupnumber, GROUP_MESSAGE_KILL_PEER_ID, packet, sizeof(packet))) { | ||
1160 | return 0; | ||
1161 | } else { | ||
1162 | return -1; | ||
1163 | } | ||
1164 | } | ||
1165 | |||
1166 | #define GROUP_MESSAGE_NAME_ID 48 | ||
1167 | |||
1168 | /* send a name message | ||
1169 | * return 0 on success | ||
1170 | * return -1 on failure | ||
1171 | */ | ||
1172 | static int group_name_send(const Group_Chats *g_c, int groupnumber, const uint8_t *nick, uint16_t nick_len) | ||
1173 | { | ||
1174 | if (nick_len > MAX_NAME_LENGTH) | ||
1175 | return -1; | ||
1176 | |||
1177 | if (send_message_group(g_c, groupnumber, GROUP_MESSAGE_NAME_ID, nick, nick_len)) { | ||
1178 | return 0; | ||
1179 | } else { | ||
1180 | return -1; | ||
1181 | } | ||
1182 | } | ||
1183 | |||
1184 | #define GROUP_MESSAGE_TITLE_ID 49 | ||
1185 | |||
1186 | /* set the group's title, limited to MAX_NAME_LENGTH | ||
1187 | * return 0 on success | ||
1188 | * return -1 on failure | ||
1189 | */ | ||
1190 | int group_title_send(const Group_Chats *g_c, int groupnumber, const uint8_t *title, uint8_t title_len) | ||
1191 | { | ||
1192 | if (title_len > MAX_NAME_LENGTH || title_len == 0) | ||
1193 | return -1; | ||
1194 | |||
1195 | Group_c *g = get_group_c(g_c, groupnumber); | ||
1196 | |||
1197 | if (!g) | ||
1198 | return -1; | ||
1199 | |||
1200 | /* same as already set? */ | ||
1201 | if (g->title_len == title_len && !memcmp(g->title, title, title_len)) | ||
1202 | return 0; | ||
1203 | |||
1204 | memcpy(g->title, title, title_len); | ||
1205 | g->title_len = title_len; | ||
1206 | |||
1207 | if (g->numpeers == 1) | ||
1208 | return 0; | ||
1209 | |||
1210 | if (send_message_group(g_c, groupnumber, GROUP_MESSAGE_TITLE_ID, title, title_len)) | ||
1211 | return 0; | ||
1212 | else | ||
1213 | return -1; | ||
1214 | } | ||
1215 | |||
1216 | /* Get group title from groupnumber and put it in title. | ||
1217 | * title needs to be a valid memory location with a max_length size of at least MAX_NAME_LENGTH (128) bytes. | ||
1218 | * | ||
1219 | * return length of copied title if success. | ||
1220 | * return -1 if failure. | ||
1221 | */ | ||
1222 | int group_title_get(const Group_Chats *g_c, int groupnumber, uint8_t *title, uint32_t max_length) | ||
1223 | { | ||
1224 | Group_c *g = get_group_c(g_c, groupnumber); | ||
1225 | |||
1226 | if (!g) | ||
1227 | return -1; | ||
1228 | |||
1229 | if (g->title_len == 0 || g->title_len > MAX_NAME_LENGTH) | ||
1230 | return -1; | ||
1231 | |||
1232 | if (max_length > g->title_len) | ||
1233 | max_length = g->title_len; | ||
1234 | |||
1235 | memcpy(title, g->title, max_length); | ||
1236 | return max_length; | ||
1237 | } | ||
1238 | |||
1239 | static void handle_friend_invite_packet(Messenger *m, uint32_t friendnumber, const uint8_t *data, uint16_t length) | ||
1240 | { | ||
1241 | Group_Chats *g_c = m->group_chat_object; | ||
1242 | |||
1243 | if (length <= 1) | ||
1244 | return; | ||
1245 | |||
1246 | const uint8_t *invite_data = data + 1; | ||
1247 | uint16_t invite_length = length - 1; | ||
1248 | |||
1249 | switch (data[0]) { | ||
1250 | case INVITE_ID: { | ||
1251 | if (length != INVITE_PACKET_SIZE) | ||
1252 | return; | ||
1253 | |||
1254 | int groupnumber = get_group_num(g_c, data + 1 + sizeof(uint16_t)); | ||
1255 | |||
1256 | if (groupnumber == -1) { | ||
1257 | if (g_c->invite_callback) | ||
1258 | g_c->invite_callback(m, friendnumber, *(invite_data + sizeof(uint16_t)), invite_data, invite_length, | ||
1259 | g_c->invite_callback_userdata); | ||
1260 | |||
1261 | return; | ||
1262 | } | ||
1263 | |||
1264 | break; | ||
1265 | } | ||
1266 | |||
1267 | case INVITE_RESPONSE_ID: { | ||
1268 | if (length != INVITE_RESPONSE_PACKET_SIZE) | ||
1269 | return; | ||
1270 | |||
1271 | uint16_t other_groupnum, groupnum; | ||
1272 | memcpy(&groupnum, data + 1 + sizeof(uint16_t), sizeof(uint16_t)); | ||
1273 | groupnum = ntohs(groupnum); | ||
1274 | |||
1275 | Group_c *g = get_group_c(g_c, groupnum); | ||
1276 | |||
1277 | if (!g) | ||
1278 | return; | ||
1279 | |||
1280 | if (memcmp(data + 1 + sizeof(uint16_t) * 2, g->identifier, GROUP_IDENTIFIER_LENGTH) != 0) | ||
1281 | return; | ||
1282 | |||
1283 | uint16_t peer_number = rand(); /* TODO: what if two people enter the group at the same time and | ||
1284 | are given the same peer_number by different nodes? */ | ||
1285 | |||
1286 | unsigned int tries = 0; | ||
1287 | |||
1288 | while (get_peer_index(g, peer_number) != -1) { | ||
1289 | peer_number = rand(); | ||
1290 | ++tries; | ||
1291 | |||
1292 | if (tries > 32) | ||
1293 | return; | ||
1294 | } | ||
1295 | |||
1296 | memcpy(&other_groupnum, data + 1, sizeof(uint16_t)); | ||
1297 | other_groupnum = ntohs(other_groupnum); | ||
1298 | |||
1299 | int friendcon_id = getfriendcon_id(m, friendnumber); | ||
1300 | uint8_t real_pk[crypto_box_PUBLICKEYBYTES], temp_pk[crypto_box_PUBLICKEYBYTES]; | ||
1301 | get_friendcon_public_keys(real_pk, temp_pk, g_c->fr_c, friendcon_id); | ||
1302 | |||
1303 | addpeer(g_c, groupnum, real_pk, temp_pk, peer_number); | ||
1304 | int close_index = add_conn_to_groupchat(g_c, friendcon_id, groupnum, 0, 1); | ||
1305 | |||
1306 | if (close_index != -1) { | ||
1307 | g->close[close_index].group_number = other_groupnum; | ||
1308 | g->close[close_index].type = GROUPCHAT_CLOSE_ONLINE; | ||
1309 | } | ||
1310 | |||
1311 | group_new_peer_send(g_c, groupnum, peer_number, real_pk, temp_pk); | ||
1312 | break; | ||
1313 | } | ||
1314 | |||
1315 | default: | ||
1316 | return; | ||
1317 | } | ||
1318 | } | ||
1319 | |||
1320 | /* Find index of friend in the close list; | ||
1321 | * | ||
1322 | * returns index on success | ||
1323 | * returns -1 on failure. | ||
1324 | */ | ||
1325 | static int friend_in_close(Group_c *g, int friendcon_id) | ||
1326 | { | ||
1327 | unsigned int i; | ||
1328 | |||
1329 | for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) { | ||
1330 | if (g->close[i].type == GROUPCHAT_CLOSE_NONE) | ||
1331 | continue; | ||
1332 | |||
1333 | if (g->close[i].number != (uint32_t)friendcon_id) | ||
1334 | continue; | ||
1335 | |||
1336 | return i; | ||
1337 | } | ||
1338 | |||
1339 | return -1; | ||
1340 | } | ||
1341 | |||
1342 | /* return number of connected close connections. | ||
1343 | */ | ||
1344 | static unsigned int count_close_connected(Group_c *g) | ||
1345 | { | ||
1346 | unsigned int i, count = 0; | ||
1347 | |||
1348 | for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) { | ||
1349 | if (g->close[i].type == GROUPCHAT_CLOSE_ONLINE) { | ||
1350 | ++count; | ||
1351 | } | ||
1352 | } | ||
1353 | |||
1354 | return count; | ||
1355 | } | ||
1356 | |||
1357 | #define ONLINE_PACKET_DATA_SIZE (sizeof(uint16_t) + GROUP_IDENTIFIER_LENGTH) | ||
1358 | |||
1359 | static int send_packet_online(Friend_Connections *fr_c, int friendcon_id, uint16_t group_num, uint8_t *identifier) | ||
1360 | { | ||
1361 | uint8_t packet[1 + ONLINE_PACKET_DATA_SIZE]; | ||
1362 | group_num = htons(group_num); | ||
1363 | packet[0] = PACKET_ID_ONLINE_PACKET; | ||
1364 | memcpy(packet + 1, &group_num, sizeof(uint16_t)); | ||
1365 | memcpy(packet + 1 + sizeof(uint16_t), identifier, GROUP_IDENTIFIER_LENGTH); | ||
1366 | return write_cryptpacket(fr_c->net_crypto, friend_connection_crypt_connection_id(fr_c, friendcon_id), packet, | ||
1367 | sizeof(packet), 0) != -1; | ||
1368 | } | ||
1369 | |||
1370 | static unsigned int send_peer_kill(Group_Chats *g_c, int friendcon_id, uint16_t group_num); | ||
1371 | |||
1372 | static int handle_packet_online(Group_Chats *g_c, int friendcon_id, uint8_t *data, uint16_t length) | ||
1373 | { | ||
1374 | if (length != ONLINE_PACKET_DATA_SIZE) | ||
1375 | return -1; | ||
1376 | |||
1377 | int groupnumber = get_group_num(g_c, data + sizeof(uint16_t)); | ||
1378 | uint16_t other_groupnum; | ||
1379 | memcpy(&other_groupnum, data, sizeof(uint16_t)); | ||
1380 | other_groupnum = ntohs(other_groupnum); | ||
1381 | |||
1382 | Group_c *g = get_group_c(g_c, groupnumber); | ||
1383 | |||
1384 | if (!g) | ||
1385 | return -1; | ||
1386 | |||
1387 | int index = friend_in_close(g, friendcon_id); | ||
1388 | |||
1389 | if (index == -1) | ||
1390 | return -1; | ||
1391 | |||
1392 | if (g->close[index].type == GROUPCHAT_CLOSE_ONLINE) { | ||
1393 | return -1; | ||
1394 | } | ||
1395 | |||
1396 | if (count_close_connected(g) == 0) { | ||
1397 | send_peer_query(g_c, friendcon_id, other_groupnum); | ||
1398 | } | ||
1399 | |||
1400 | g->close[index].group_number = other_groupnum; | ||
1401 | g->close[index].type = GROUPCHAT_CLOSE_ONLINE; | ||
1402 | send_packet_online(g_c->fr_c, friendcon_id, groupnumber, g->identifier); | ||
1403 | |||
1404 | if (g->number_joined != -1 && count_close_connected(g) >= DESIRED_CLOSE_CONNECTIONS) { | ||
1405 | int fr_close_index = friend_in_close(g, g->number_joined); | ||
1406 | |||
1407 | if (fr_close_index == -1) | ||
1408 | return -1; | ||
1409 | |||
1410 | if (!g->close[fr_close_index].closest) { | ||
1411 | g->close[fr_close_index].type = GROUPCHAT_CLOSE_NONE; | ||
1412 | send_peer_kill(g_c, g->close[fr_close_index].number, g->close[fr_close_index].group_number); | ||
1413 | kill_friend_connection(g_c->fr_c, g->close[fr_close_index].number); | ||
1414 | g->number_joined = -1; | ||
1415 | } | ||
1416 | } | ||
1417 | |||
1418 | return 0; | ||
1419 | } | ||
1420 | |||
1421 | #define PEER_KILL_ID 1 | ||
1422 | #define PEER_QUERY_ID 8 | ||
1423 | #define PEER_RESPONSE_ID 9 | ||
1424 | #define PEER_TITLE_ID 10 | ||
1425 | // we could send title with invite, but then if it changes between sending and accepting inv, joinee won't see it | ||
1426 | |||
1427 | /* return 1 on success. | ||
1428 | * return 0 on failure | ||
1429 | */ | ||
1430 | static unsigned int send_peer_kill(Group_Chats *g_c, int friendcon_id, uint16_t group_num) | ||
1431 | { | ||
1432 | uint8_t packet[1]; | ||
1433 | packet[0] = PEER_KILL_ID; | ||
1434 | return send_packet_group_peer(g_c->fr_c, friendcon_id, PACKET_ID_DIRECT_GROUPCHAT, group_num, packet, sizeof(packet)); | ||
1435 | } | ||
1436 | |||
1437 | |||
1438 | /* return 1 on success. | ||
1439 | * return 0 on failure | ||
1440 | */ | ||
1441 | static unsigned int send_peer_query(Group_Chats *g_c, int friendcon_id, uint16_t group_num) | ||
1442 | { | ||
1443 | uint8_t packet[1]; | ||
1444 | packet[0] = PEER_QUERY_ID; | ||
1445 | return send_packet_group_peer(g_c->fr_c, friendcon_id, PACKET_ID_DIRECT_GROUPCHAT, group_num, packet, sizeof(packet)); | ||
1446 | } | ||
1447 | |||
1448 | /* return number of peers sent on success. | ||
1449 | * return 0 on failure. | ||
1450 | */ | ||
1451 | static unsigned int send_peers(Group_Chats *g_c, int groupnumber, int friendcon_id, uint16_t group_num) | ||
1452 | { | ||
1453 | Group_c *g = get_group_c(g_c, groupnumber); | ||
1454 | |||
1455 | if (!g) | ||
1456 | return -1; | ||
1457 | |||
1458 | uint8_t packet[MAX_CRYPTO_DATA_SIZE - (1 + sizeof(uint16_t))]; | ||
1459 | packet[0] = PEER_RESPONSE_ID; | ||
1460 | uint8_t *p = packet + 1; | ||
1461 | |||
1462 | uint16_t sent = 0; | ||
1463 | unsigned int i; | ||
1464 | |||
1465 | for (i = 0; i < g->numpeers; ++i) { | ||
1466 | if ((p - packet) + sizeof(uint16_t) + crypto_box_PUBLICKEYBYTES * 2 + 1 + g->group[i].nick_len > sizeof(packet)) { | ||
1467 | if (send_packet_group_peer(g_c->fr_c, friendcon_id, PACKET_ID_DIRECT_GROUPCHAT, group_num, packet, (p - packet))) { | ||
1468 | sent = i; | ||
1469 | } else { | ||
1470 | return sent; | ||
1471 | } | ||
1472 | |||
1473 | p = packet + 1; | ||
1474 | } | ||
1475 | |||
1476 | uint16_t peer_num = htons(g->group[i].peer_number); | ||
1477 | memcpy(p, &peer_num, sizeof(peer_num)); | ||
1478 | p += sizeof(peer_num); | ||
1479 | memcpy(p, g->group[i].real_pk, crypto_box_PUBLICKEYBYTES); | ||
1480 | p += crypto_box_PUBLICKEYBYTES; | ||
1481 | memcpy(p, g->group[i].temp_pk, crypto_box_PUBLICKEYBYTES); | ||
1482 | p += crypto_box_PUBLICKEYBYTES; | ||
1483 | *p = g->group[i].nick_len; | ||
1484 | p += 1; | ||
1485 | memcpy(p, g->group[i].nick, g->group[i].nick_len); | ||
1486 | p += g->group[i].nick_len; | ||
1487 | } | ||
1488 | |||
1489 | if (sent != i) { | ||
1490 | if (send_packet_group_peer(g_c->fr_c, friendcon_id, PACKET_ID_DIRECT_GROUPCHAT, group_num, packet, (p - packet))) { | ||
1491 | sent = i; | ||
1492 | } | ||
1493 | } | ||
1494 | |||
1495 | if (g->title_len) { | ||
1496 | uint8_t Packet[1 + g->title_len]; | ||
1497 | Packet[0] = PEER_TITLE_ID; | ||
1498 | memcpy(Packet + 1, g->title, g->title_len); | ||
1499 | send_packet_group_peer(g_c->fr_c, friendcon_id, PACKET_ID_DIRECT_GROUPCHAT, group_num, Packet, sizeof(Packet)); | ||
1500 | } | ||
1501 | |||
1502 | return sent; | ||
1503 | } | ||
1504 | |||
1505 | static int handle_send_peers(Group_Chats *g_c, int groupnumber, const uint8_t *data, uint16_t length) | ||
1506 | { | ||
1507 | if (length == 0) | ||
1508 | return -1; | ||
1509 | |||
1510 | Group_c *g = get_group_c(g_c, groupnumber); | ||
1511 | |||
1512 | if (!g) | ||
1513 | return -1; | ||
1514 | |||
1515 | const uint8_t *d = data; | ||
1516 | |||
1517 | while ((length - (d - data)) >= sizeof(uint16_t) + crypto_box_PUBLICKEYBYTES * 2 + 1) { | ||
1518 | uint16_t peer_num; | ||
1519 | memcpy(&peer_num, d, sizeof(peer_num)); | ||
1520 | peer_num = ntohs(peer_num); | ||
1521 | d += sizeof(uint16_t); | ||
1522 | int peer_index = addpeer(g_c, groupnumber, d, d + crypto_box_PUBLICKEYBYTES, peer_num); | ||
1523 | |||
1524 | if (peer_index == -1) | ||
1525 | return -1; | ||
1526 | |||
1527 | if (g->status == GROUPCHAT_STATUS_VALID | ||
1528 | && memcmp(d, g_c->m->net_crypto->self_public_key, crypto_box_PUBLICKEYBYTES) == 0) { | ||
1529 | g->peer_number = peer_num; | ||
1530 | g->status = GROUPCHAT_STATUS_CONNECTED; | ||
1531 | group_name_send(g_c, groupnumber, g_c->m->name, g_c->m->name_length); | ||
1532 | } | ||
1533 | |||
1534 | d += crypto_box_PUBLICKEYBYTES * 2; | ||
1535 | uint8_t name_length = *d; | ||
1536 | d += 1; | ||
1537 | |||
1538 | if (name_length > (length - (d - data)) || name_length > MAX_NAME_LENGTH) | ||
1539 | return -1; | ||
1540 | |||
1541 | setnick(g_c, groupnumber, peer_index, d, name_length); | ||
1542 | d += name_length; | ||
1543 | } | ||
1544 | |||
1545 | return 0; | ||
1546 | } | ||
1547 | |||
1548 | static void handle_direct_packet(Group_Chats *g_c, int groupnumber, const uint8_t *data, uint16_t length, | ||
1549 | int close_index) | ||
1550 | { | ||
1551 | if (length == 0) | ||
1552 | return; | ||
1553 | |||
1554 | switch (data[0]) { | ||
1555 | case PEER_KILL_ID: { | ||
1556 | Group_c *g = get_group_c(g_c, groupnumber); | ||
1557 | |||
1558 | if (!g) | ||
1559 | return; | ||
1560 | |||
1561 | if (!g->close[close_index].closest) { | ||
1562 | g->close[close_index].type = GROUPCHAT_CLOSE_NONE; | ||
1563 | kill_friend_connection(g_c->fr_c, g->close[close_index].number); | ||
1564 | } | ||
1565 | } | ||
1566 | |||
1567 | break; | ||
1568 | |||
1569 | case PEER_QUERY_ID: { | ||
1570 | Group_c *g = get_group_c(g_c, groupnumber); | ||
1571 | |||
1572 | if (!g) | ||
1573 | return; | ||
1574 | |||
1575 | send_peers(g_c, groupnumber, g->close[close_index].number, g->close[close_index].group_number); | ||
1576 | } | ||
1577 | |||
1578 | break; | ||
1579 | |||
1580 | case PEER_RESPONSE_ID: { | ||
1581 | handle_send_peers(g_c, groupnumber, data + 1, length - 1); | ||
1582 | } | ||
1583 | |||
1584 | break; | ||
1585 | |||
1586 | case PEER_TITLE_ID: { | ||
1587 | settitle(g_c, groupnumber, -1, data + 1, length - 1); | ||
1588 | } | ||
1589 | |||
1590 | break; | ||
1591 | } | ||
1592 | } | ||
1593 | |||
1594 | #define MIN_MESSAGE_PACKET_LEN (sizeof(uint16_t) * 2 + sizeof(uint32_t) + 1) | ||
1595 | |||
1596 | /* Send message to all close except receiver (if receiver isn't -1) | ||
1597 | * NOTE: this function appends the group chat number to the data passed to it. | ||
1598 | * | ||
1599 | * return number of messages sent. | ||
1600 | */ | ||
1601 | static unsigned int send_message_all_close(const Group_Chats *g_c, int groupnumber, const uint8_t *data, | ||
1602 | uint16_t length, int receiver) | ||
1603 | { | ||
1604 | Group_c *g = get_group_c(g_c, groupnumber); | ||
1605 | |||
1606 | if (!g) | ||
1607 | return 0; | ||
1608 | |||
1609 | uint16_t i, sent = 0; | ||
1610 | |||
1611 | for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) { | ||
1612 | if (g->close[i].type != GROUPCHAT_CLOSE_ONLINE) | ||
1613 | continue; | ||
1614 | |||
1615 | if ((int)i == receiver) | ||
1616 | continue; | ||
1617 | |||
1618 | if (send_packet_group_peer(g_c->fr_c, g->close[i].number, PACKET_ID_MESSAGE_GROUPCHAT, g->close[i].group_number, data, | ||
1619 | length)) | ||
1620 | ++sent; | ||
1621 | } | ||
1622 | |||
1623 | return sent; | ||
1624 | } | ||
1625 | |||
1626 | /* Send lossy message to all close except receiver (if receiver isn't -1) | ||
1627 | * NOTE: this function appends the group chat number to the data passed to it. | ||
1628 | * | ||
1629 | * return number of messages sent. | ||
1630 | */ | ||
1631 | static unsigned int send_lossy_all_close(const Group_Chats *g_c, int groupnumber, const uint8_t *data, uint16_t length, | ||
1632 | int receiver) | ||
1633 | { | ||
1634 | Group_c *g = get_group_c(g_c, groupnumber); | ||
1635 | |||
1636 | if (!g) | ||
1637 | return 0; | ||
1638 | |||
1639 | unsigned int i, sent = 0, num_connected_closest = 0, connected_closest[DESIRED_CLOSE_CONNECTIONS]; | ||
1640 | |||
1641 | for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) { | ||
1642 | if (g->close[i].type != GROUPCHAT_CLOSE_ONLINE) | ||
1643 | continue; | ||
1644 | |||
1645 | if ((int)i == receiver) | ||
1646 | continue; | ||
1647 | |||
1648 | if (g->close[i].closest) { | ||
1649 | connected_closest[num_connected_closest] = i; | ||
1650 | ++num_connected_closest; | ||
1651 | continue; | ||
1652 | } | ||
1653 | |||
1654 | if (send_lossy_group_peer(g_c->fr_c, g->close[i].number, PACKET_ID_LOSSY_GROUPCHAT, g->close[i].group_number, data, | ||
1655 | length)) | ||
1656 | ++sent; | ||
1657 | } | ||
1658 | |||
1659 | if (!num_connected_closest) { | ||
1660 | return sent; | ||
1661 | } | ||
1662 | |||
1663 | unsigned int to_send = 0; | ||
1664 | uint64_t comp_val_old = ~0; | ||
1665 | |||
1666 | for (i = 0; i < num_connected_closest; ++i) { | ||
1667 | uint8_t real_pk[crypto_box_PUBLICKEYBYTES]; | ||
1668 | uint8_t dht_temp_pk[crypto_box_PUBLICKEYBYTES]; | ||
1669 | get_friendcon_public_keys(real_pk, dht_temp_pk, g_c->fr_c, g->close[connected_closest[i]].number); | ||
1670 | uint64_t comp_val = calculate_comp_value(g->real_pk, real_pk); | ||
1671 | |||
1672 | if (comp_val < comp_val_old) { | ||
1673 | to_send = connected_closest[i]; | ||
1674 | comp_val_old = comp_val; | ||
1675 | } | ||
1676 | } | ||
1677 | |||
1678 | if (send_lossy_group_peer(g_c->fr_c, g->close[to_send].number, PACKET_ID_LOSSY_GROUPCHAT, | ||
1679 | g->close[to_send].group_number, data, length)) { | ||
1680 | ++sent; | ||
1681 | } | ||
1682 | |||
1683 | unsigned int to_send_other = 0; | ||
1684 | comp_val_old = ~0; | ||
1685 | |||
1686 | for (i = 0; i < num_connected_closest; ++i) { | ||
1687 | uint8_t real_pk[crypto_box_PUBLICKEYBYTES]; | ||
1688 | uint8_t dht_temp_pk[crypto_box_PUBLICKEYBYTES]; | ||
1689 | get_friendcon_public_keys(real_pk, dht_temp_pk, g_c->fr_c, g->close[connected_closest[i]].number); | ||
1690 | uint64_t comp_val = calculate_comp_value(real_pk, g->real_pk); | ||
1691 | |||
1692 | if (comp_val < comp_val_old) { | ||
1693 | to_send_other = connected_closest[i]; | ||
1694 | comp_val_old = comp_val; | ||
1695 | } | ||
1696 | } | ||
1697 | |||
1698 | if (to_send_other == to_send) { | ||
1699 | return sent; | ||
1700 | } | ||
1701 | |||
1702 | if (send_lossy_group_peer(g_c->fr_c, g->close[to_send_other].number, PACKET_ID_LOSSY_GROUPCHAT, | ||
1703 | g->close[to_send_other].group_number, data, length)) { | ||
1704 | ++sent; | ||
1705 | } | ||
1706 | |||
1707 | return sent; | ||
1708 | } | ||
1709 | |||
1710 | #define MAX_GROUP_MESSAGE_DATA_LEN (MAX_CRYPTO_DATA_SIZE - (1 + MIN_MESSAGE_PACKET_LEN)) | ||
1711 | |||
1712 | /* Send data of len with message_id to groupnumber. | ||
1713 | * | ||
1714 | * return number of peers it was sent to on success. | ||
1715 | * return 0 on failure. | ||
1716 | */ | ||
1717 | static unsigned int send_message_group(const Group_Chats *g_c, int groupnumber, uint8_t message_id, const uint8_t *data, | ||
1718 | uint16_t len) | ||
1719 | { | ||
1720 | if (len > MAX_GROUP_MESSAGE_DATA_LEN) | ||
1721 | return 0; | ||
1722 | |||
1723 | Group_c *g = get_group_c(g_c, groupnumber); | ||
1724 | |||
1725 | if (!g) | ||
1726 | return 0; | ||
1727 | |||
1728 | if (g->status != GROUPCHAT_STATUS_CONNECTED) | ||
1729 | return 0; | ||
1730 | |||
1731 | uint8_t packet[sizeof(uint16_t) + sizeof(uint32_t) + 1 + len]; | ||
1732 | uint16_t peer_num = htons(g->peer_number); | ||
1733 | memcpy(packet, &peer_num, sizeof(peer_num)); | ||
1734 | |||
1735 | ++g->message_number; | ||
1736 | |||
1737 | if (!g->message_number) | ||
1738 | ++g->message_number; | ||
1739 | |||
1740 | uint32_t message_num = htonl(g->message_number); | ||
1741 | memcpy(packet + sizeof(uint16_t), &message_num, sizeof(message_num)); | ||
1742 | |||
1743 | packet[sizeof(uint16_t) + sizeof(uint32_t)] = message_id; | ||
1744 | |||
1745 | if (len) | ||
1746 | memcpy(packet + sizeof(uint16_t) + sizeof(uint32_t) + 1, data, len); | ||
1747 | |||
1748 | return send_message_all_close(g_c, groupnumber, packet, sizeof(packet), -1); | ||
1749 | } | ||
1750 | |||
1751 | /* send a group message | ||
1752 | * return 0 on success | ||
1753 | * return -1 on failure | ||
1754 | */ | ||
1755 | int group_message_send(const Group_Chats *g_c, int groupnumber, const uint8_t *message, uint16_t length) | ||
1756 | { | ||
1757 | if (send_message_group(g_c, groupnumber, PACKET_ID_MESSAGE, message, length)) { | ||
1758 | return 0; | ||
1759 | } else { | ||
1760 | return -1; | ||
1761 | } | ||
1762 | } | ||
1763 | |||
1764 | /* send a group action | ||
1765 | * return 0 on success | ||
1766 | * return -1 on failure | ||
1767 | */ | ||
1768 | int group_action_send(const Group_Chats *g_c, int groupnumber, const uint8_t *action, uint16_t length) | ||
1769 | { | ||
1770 | if (send_message_group(g_c, groupnumber, PACKET_ID_ACTION, action, length)) { | ||
1771 | return 0; | ||
1772 | } else { | ||
1773 | return -1; | ||
1774 | } | ||
1775 | } | ||
1776 | |||
1777 | /* High level function to send custom lossy packets. | ||
1778 | * | ||
1779 | * return -1 on failure. | ||
1780 | * return 0 on success. | ||
1781 | */ | ||
1782 | int send_group_lossy_packet(const Group_Chats *g_c, int groupnumber, const uint8_t *data, uint16_t length) | ||
1783 | { | ||
1784 | //TODO: length check here? | ||
1785 | Group_c *g = get_group_c(g_c, groupnumber); | ||
1786 | |||
1787 | if (!g) | ||
1788 | return -1; | ||
1789 | |||
1790 | uint8_t packet[sizeof(uint16_t) * 2 + length]; | ||
1791 | uint16_t peer_number = htons(g->peer_number); | ||
1792 | memcpy(packet, &peer_number, sizeof(uint16_t)); | ||
1793 | uint16_t message_num = htons(g->lossy_message_number); | ||
1794 | memcpy(packet + sizeof(uint16_t), &message_num, sizeof(uint16_t)); | ||
1795 | memcpy(packet + sizeof(uint16_t) * 2, data, length); | ||
1796 | |||
1797 | if (send_lossy_all_close(g_c, groupnumber, packet, sizeof(packet), -1) == 0) { | ||
1798 | return -1; | ||
1799 | } | ||
1800 | |||
1801 | ++g->lossy_message_number; | ||
1802 | return 0; | ||
1803 | } | ||
1804 | |||
1805 | static void handle_message_packet_group(Group_Chats *g_c, int groupnumber, const uint8_t *data, uint16_t length, | ||
1806 | int close_index) | ||
1807 | { | ||
1808 | if (length < sizeof(uint16_t) + sizeof(uint32_t) + 1) | ||
1809 | return; | ||
1810 | |||
1811 | Group_c *g = get_group_c(g_c, groupnumber); | ||
1812 | |||
1813 | if (!g) | ||
1814 | return; | ||
1815 | |||
1816 | uint16_t peer_number; | ||
1817 | memcpy(&peer_number, data, sizeof(uint16_t)); | ||
1818 | peer_number = ntohs(peer_number); | ||
1819 | |||
1820 | int index = get_peer_index(g, peer_number); | ||
1821 | |||
1822 | if (index == -1) { | ||
1823 | /* We don't know the peer this packet came from so we query the list of peers from that peer. | ||
1824 | (They would not have relayed it if they didn't know the peer.) */ | ||
1825 | send_peer_query(g_c, g->close[close_index].number, g->close[close_index].group_number); | ||
1826 | return; | ||
1827 | } | ||
1828 | |||
1829 | uint32_t message_number; | ||
1830 | memcpy(&message_number, data + sizeof(uint16_t), sizeof(message_number)); | ||
1831 | message_number = ntohl(message_number); | ||
1832 | |||
1833 | if (g->group[index].last_message_number == 0) { | ||
1834 | g->group[index].last_message_number = message_number; | ||
1835 | } else if (message_number - g->group[index].last_message_number > 64 || | ||
1836 | message_number == g->group[index].last_message_number) { | ||
1837 | return; | ||
1838 | } | ||
1839 | |||
1840 | g->group[index].last_message_number = message_number; | ||
1841 | |||
1842 | uint8_t message_id = data[sizeof(uint16_t) + sizeof(message_number)]; | ||
1843 | const uint8_t *msg_data = data + sizeof(uint16_t) + sizeof(message_number) + 1; | ||
1844 | uint16_t msg_data_len = length - (sizeof(uint16_t) + sizeof(message_number) + 1); | ||
1845 | |||
1846 | switch (message_id) { | ||
1847 | case GROUP_MESSAGE_PING_ID: { | ||
1848 | if (msg_data_len != 0) | ||
1849 | return; | ||
1850 | |||
1851 | g->group[index].last_recv = unix_time(); | ||
1852 | } | ||
1853 | break; | ||
1854 | |||
1855 | case GROUP_MESSAGE_NEW_PEER_ID: { | ||
1856 | if (msg_data_len != GROUP_MESSAGE_NEW_PEER_LENGTH) | ||
1857 | return; | ||
1858 | |||
1859 | uint16_t new_peer_number; | ||
1860 | memcpy(&new_peer_number, msg_data, sizeof(uint16_t)); | ||
1861 | new_peer_number = ntohs(new_peer_number); | ||
1862 | addpeer(g_c, groupnumber, msg_data + sizeof(uint16_t), msg_data + sizeof(uint16_t) + crypto_box_PUBLICKEYBYTES, | ||
1863 | new_peer_number); | ||
1864 | } | ||
1865 | break; | ||
1866 | |||
1867 | case GROUP_MESSAGE_KILL_PEER_ID: { | ||
1868 | if (msg_data_len != GROUP_MESSAGE_KILL_PEER_LENGTH) | ||
1869 | return; | ||
1870 | |||
1871 | uint16_t kill_peer_number; | ||
1872 | memcpy(&kill_peer_number, msg_data, sizeof(uint16_t)); | ||
1873 | kill_peer_number = ntohs(kill_peer_number); | ||
1874 | |||
1875 | if (peer_number == kill_peer_number) { | ||
1876 | delpeer(g_c, groupnumber, index); | ||
1877 | } else { | ||
1878 | return; | ||
1879 | //TODO | ||
1880 | } | ||
1881 | } | ||
1882 | break; | ||
1883 | |||
1884 | case GROUP_MESSAGE_NAME_ID: { | ||
1885 | if (setnick(g_c, groupnumber, index, msg_data, msg_data_len) == -1) | ||
1886 | return; | ||
1887 | } | ||
1888 | break; | ||
1889 | |||
1890 | case GROUP_MESSAGE_TITLE_ID: { | ||
1891 | if (settitle(g_c, groupnumber, index, msg_data, msg_data_len) == -1) | ||
1892 | return; | ||
1893 | } | ||
1894 | break; | ||
1895 | |||
1896 | case PACKET_ID_MESSAGE: { | ||
1897 | if (msg_data_len == 0) | ||
1898 | return; | ||
1899 | |||
1900 | uint8_t newmsg[msg_data_len + 1]; | ||
1901 | memcpy(newmsg, msg_data, msg_data_len); | ||
1902 | newmsg[msg_data_len] = 0; | ||
1903 | |||
1904 | //TODO | ||
1905 | if (g_c->message_callback) | ||
1906 | g_c->message_callback(g_c->m, groupnumber, index, newmsg, msg_data_len, g_c->message_callback_userdata); | ||
1907 | |||
1908 | break; | ||
1909 | } | ||
1910 | |||
1911 | case PACKET_ID_ACTION: { | ||
1912 | if (msg_data_len == 0) | ||
1913 | return; | ||
1914 | |||
1915 | uint8_t newmsg[msg_data_len + 1]; | ||
1916 | memcpy(newmsg, msg_data, msg_data_len); | ||
1917 | newmsg[msg_data_len] = 0; | ||
1918 | |||
1919 | //TODO | ||
1920 | if (g_c->action_callback) | ||
1921 | g_c->action_callback(g_c->m, groupnumber, index, newmsg, msg_data_len, g_c->action_callback_userdata); | ||
1922 | |||
1923 | break; | ||
1924 | } | ||
1925 | |||
1926 | default: | ||
1927 | return; | ||
1928 | } | ||
1929 | |||
1930 | send_message_all_close(g_c, groupnumber, data, length, -1/*TODO close_index*/); | ||
1931 | } | ||
1932 | |||
1933 | static int handle_packet(void *object, int friendcon_id, uint8_t *data, uint16_t length) | ||
1934 | { | ||
1935 | Group_Chats *g_c = object; | ||
1936 | |||
1937 | if (length < 1 + sizeof(uint16_t) + 1) | ||
1938 | return -1; | ||
1939 | |||
1940 | if (data[0] == PACKET_ID_ONLINE_PACKET) { | ||
1941 | return handle_packet_online(g_c, friendcon_id, data + 1, length - 1); | ||
1942 | } | ||
1943 | |||
1944 | if (data[0] != PACKET_ID_DIRECT_GROUPCHAT && data[0] != PACKET_ID_MESSAGE_GROUPCHAT) | ||
1945 | return -1; | ||
1946 | |||
1947 | uint16_t groupnumber; | ||
1948 | memcpy(&groupnumber, data + 1, sizeof(uint16_t)); | ||
1949 | groupnumber = ntohs(groupnumber); | ||
1950 | Group_c *g = get_group_c(g_c, groupnumber); | ||
1951 | |||
1952 | if (!g) | ||
1953 | return -1; | ||
1954 | |||
1955 | int index = friend_in_close(g, friendcon_id); | ||
1956 | |||
1957 | if (index == -1) | ||
1958 | return -1; | ||
1959 | |||
1960 | switch (data[0]) { | ||
1961 | case PACKET_ID_DIRECT_GROUPCHAT: { | ||
1962 | handle_direct_packet(g_c, groupnumber, data + 1 + sizeof(uint16_t), length - (1 + sizeof(uint16_t)), index); | ||
1963 | break; | ||
1964 | } | ||
1965 | |||
1966 | case PACKET_ID_MESSAGE_GROUPCHAT: { | ||
1967 | handle_message_packet_group(g_c, groupnumber, data + 1 + sizeof(uint16_t), length - (1 + sizeof(uint16_t)), index); | ||
1968 | break; | ||
1969 | } | ||
1970 | |||
1971 | default: { | ||
1972 | return 0; | ||
1973 | } | ||
1974 | } | ||
1975 | |||
1976 | return 0; | ||
1977 | } | ||
1978 | |||
1979 | /* Did we already receive the lossy packet or not. | ||
1980 | * | ||
1981 | * return -1 on failure. | ||
1982 | * return 0 if packet was not received. | ||
1983 | * return 1 if packet was received. | ||
1984 | * | ||
1985 | * TODO: test this | ||
1986 | */ | ||
1987 | static unsigned int lossy_packet_not_received(Group_c *g, int peer_index, uint16_t message_number) | ||
1988 | { | ||
1989 | if (peer_index == -1) | ||
1990 | return -1; | ||
1991 | |||
1992 | if (g->group[peer_index].bottom_lossy_number == g->group[peer_index].top_lossy_number) { | ||
1993 | g->group[peer_index].top_lossy_number = message_number; | ||
1994 | g->group[peer_index].bottom_lossy_number = (message_number - MAX_LOSSY_COUNT) + 1; | ||
1995 | g->group[peer_index].recv_lossy[message_number % MAX_LOSSY_COUNT] = 1; | ||
1996 | return 0; | ||
1997 | } | ||
1998 | |||
1999 | if ((uint16_t)(message_number - g->group[peer_index].bottom_lossy_number) < MAX_LOSSY_COUNT) { | ||
2000 | if (g->group[peer_index].recv_lossy[message_number % MAX_LOSSY_COUNT]) { | ||
2001 | return 1; | ||
2002 | } | ||
2003 | |||
2004 | g->group[peer_index].recv_lossy[message_number % MAX_LOSSY_COUNT] = 1; | ||
2005 | return 0; | ||
2006 | } | ||
2007 | |||
2008 | if ((uint16_t)(message_number - g->group[peer_index].bottom_lossy_number) > (1 << 15)) | ||
2009 | return -1; | ||
2010 | |||
2011 | uint16_t top_distance = message_number - g->group[peer_index].top_lossy_number; | ||
2012 | |||
2013 | if (top_distance >= MAX_LOSSY_COUNT) { | ||
2014 | memset(g->group[peer_index].recv_lossy, 0, sizeof(g->group[peer_index].recv_lossy)); | ||
2015 | g->group[peer_index].top_lossy_number = message_number; | ||
2016 | g->group[peer_index].bottom_lossy_number = (message_number - MAX_LOSSY_COUNT) + 1; | ||
2017 | g->group[peer_index].recv_lossy[message_number % MAX_LOSSY_COUNT] = 1; | ||
2018 | return 0; | ||
2019 | } | ||
2020 | |||
2021 | if (top_distance < MAX_LOSSY_COUNT) { | ||
2022 | unsigned int i; | ||
2023 | |||
2024 | for (i = g->group[peer_index].bottom_lossy_number; i != (g->group[peer_index].bottom_lossy_number + top_distance); | ||
2025 | ++i) { | ||
2026 | g->group[peer_index].recv_lossy[i % MAX_LOSSY_COUNT] = 0; | ||
2027 | } | ||
2028 | |||
2029 | g->group[peer_index].top_lossy_number = message_number; | ||
2030 | g->group[peer_index].bottom_lossy_number = (message_number - MAX_LOSSY_COUNT) + 1; | ||
2031 | g->group[peer_index].recv_lossy[message_number % MAX_LOSSY_COUNT] = 1; | ||
2032 | return 0; | ||
2033 | } | ||
2034 | |||
2035 | return -1; | ||
2036 | } | ||
2037 | |||
2038 | static int handle_lossy(void *object, int friendcon_id, const uint8_t *data, uint16_t length) | ||
2039 | { | ||
2040 | Group_Chats *g_c = object; | ||
2041 | |||
2042 | if (length < 1 + sizeof(uint16_t) * 3 + 1) | ||
2043 | return -1; | ||
2044 | |||
2045 | if (data[0] != PACKET_ID_LOSSY_GROUPCHAT) | ||
2046 | return -1; | ||
2047 | |||
2048 | uint16_t groupnumber, peer_number, message_number; | ||
2049 | memcpy(&groupnumber, data + 1, sizeof(uint16_t)); | ||
2050 | memcpy(&peer_number, data + 1 + sizeof(uint16_t), sizeof(uint16_t)); | ||
2051 | memcpy(&message_number, data + 1 + sizeof(uint16_t) * 2, sizeof(uint16_t)); | ||
2052 | groupnumber = ntohs(groupnumber); | ||
2053 | peer_number = ntohs(peer_number); | ||
2054 | message_number = ntohs(message_number); | ||
2055 | |||
2056 | Group_c *g = get_group_c(g_c, groupnumber); | ||
2057 | |||
2058 | if (!g) | ||
2059 | return -1; | ||
2060 | |||
2061 | int index = friend_in_close(g, friendcon_id); | ||
2062 | |||
2063 | if (index == -1) | ||
2064 | return -1; | ||
2065 | |||
2066 | if (peer_number == g->peer_number) | ||
2067 | return -1; | ||
2068 | |||
2069 | int peer_index = get_peer_index(g, peer_number); | ||
2070 | |||
2071 | if (peer_index == -1) | ||
2072 | return -1; | ||
2073 | |||
2074 | if (lossy_packet_not_received(g, peer_index, message_number)) | ||
2075 | return -1; | ||
2076 | |||
2077 | const uint8_t *lossy_data = data + 1 + sizeof(uint16_t) * 3; | ||
2078 | uint16_t lossy_length = length - (1 + sizeof(uint16_t) * 3); | ||
2079 | uint8_t message_id = lossy_data[0]; | ||
2080 | ++lossy_data; | ||
2081 | --lossy_length; | ||
2082 | |||
2083 | if (g_c->lossy_packethandlers[message_id].function) { | ||
2084 | if (g_c->lossy_packethandlers[message_id].function(g->object, groupnumber, peer_index, g->group[peer_index].object, | ||
2085 | lossy_data, lossy_length) == -1) { | ||
2086 | return -1; | ||
2087 | } | ||
2088 | } else { | ||
2089 | return -1; | ||
2090 | } | ||
2091 | |||
2092 | send_lossy_all_close(g_c, groupnumber, data + 1 + sizeof(uint16_t), length - (1 + sizeof(uint16_t)), index); | ||
2093 | return 0; | ||
2094 | } | ||
2095 | |||
2096 | /* Set the object that is tied to the group chat. | ||
2097 | * | ||
2098 | * return 0 on success. | ||
2099 | * return -1 on failure | ||
2100 | */ | ||
2101 | int group_set_object(const Group_Chats *g_c, int groupnumber, void *object) | ||
2102 | { | ||
2103 | Group_c *g = get_group_c(g_c, groupnumber); | ||
2104 | |||
2105 | if (!g) | ||
2106 | return -1; | ||
2107 | |||
2108 | g->object = object; | ||
2109 | return 0; | ||
2110 | } | ||
2111 | |||
2112 | /* Set the object that is tied to the group peer. | ||
2113 | * | ||
2114 | * return 0 on success. | ||
2115 | * return -1 on failure | ||
2116 | */ | ||
2117 | int group_peer_set_object(const Group_Chats *g_c, int groupnumber, int peernumber, void *object) | ||
2118 | { | ||
2119 | Group_c *g = get_group_c(g_c, groupnumber); | ||
2120 | |||
2121 | if (!g) | ||
2122 | return -1; | ||
2123 | |||
2124 | if ((uint32_t)peernumber >= g->numpeers) | ||
2125 | return -1; | ||
2126 | |||
2127 | g->group[peernumber].object = object; | ||
2128 | return 0; | ||
2129 | } | ||
2130 | |||
2131 | /* Return the object tide to the group chat previously set by group_set_object. | ||
2132 | * | ||
2133 | * return NULL on failure. | ||
2134 | * return object on success. | ||
2135 | */ | ||
2136 | void *group_get_object(const Group_Chats *g_c, int groupnumber) | ||
2137 | { | ||
2138 | Group_c *g = get_group_c(g_c, groupnumber); | ||
2139 | |||
2140 | if (!g) | ||
2141 | return NULL; | ||
2142 | |||
2143 | return g->object; | ||
2144 | } | ||
2145 | |||
2146 | /* Return the object tide to the group chat peer previously set by group_peer_set_object. | ||
2147 | * | ||
2148 | * return NULL on failure. | ||
2149 | * return object on success. | ||
2150 | */ | ||
2151 | void *group_peer_get_object(const Group_Chats *g_c, int groupnumber, int peernumber) | ||
2152 | { | ||
2153 | Group_c *g = get_group_c(g_c, groupnumber); | ||
2154 | |||
2155 | if (!g) | ||
2156 | return NULL; | ||
2157 | |||
2158 | if ((uint32_t)peernumber >= g->numpeers) | ||
2159 | return NULL; | ||
2160 | |||
2161 | return g->group[peernumber].object; | ||
2162 | } | ||
2163 | |||
2164 | /* Interval in seconds to send ping messages */ | ||
2165 | #define GROUP_PING_INTERVAL 20 | ||
2166 | |||
2167 | static int ping_groupchat(Group_Chats *g_c, int groupnumber) | ||
2168 | { | ||
2169 | Group_c *g = get_group_c(g_c, groupnumber); | ||
2170 | |||
2171 | if (!g) | ||
2172 | return -1; | ||
2173 | |||
2174 | if (is_timeout(g->last_sent_ping, GROUP_PING_INTERVAL)) { | ||
2175 | if (group_ping_send(g_c, groupnumber) != -1) /* Ping */ | ||
2176 | g->last_sent_ping = unix_time(); | ||
2177 | } | ||
2178 | |||
2179 | return 0; | ||
2180 | } | ||
2181 | |||
2182 | static int groupchat_clear_timedout(Group_Chats *g_c, int groupnumber) | ||
2183 | { | ||
2184 | Group_c *g = get_group_c(g_c, groupnumber); | ||
2185 | |||
2186 | if (!g) | ||
2187 | return -1; | ||
2188 | |||
2189 | uint32_t i; | ||
2190 | |||
2191 | for (i = 0; i < g->numpeers; ++i) { | ||
2192 | if (g->peer_number != g->group[i].peer_number && is_timeout(g->group[i].last_recv, GROUP_PING_INTERVAL * 3)) { | ||
2193 | delpeer(g_c, groupnumber, i); | ||
2194 | } | ||
2195 | |||
2196 | if (g->group == NULL || i >= g->numpeers) | ||
2197 | break; | ||
2198 | } | ||
2199 | |||
2200 | return 0; | ||
2201 | } | ||
2202 | |||
2203 | /* Send current name (set in messenger) to all online groups. | ||
2204 | */ | ||
2205 | void send_name_all_groups(Group_Chats *g_c) | ||
2206 | { | ||
2207 | unsigned int i; | ||
2208 | |||
2209 | for (i = 0; i < g_c->num_chats; ++i) { | ||
2210 | Group_c *g = get_group_c(g_c, i); | ||
2211 | |||
2212 | if (!g) | ||
2213 | continue; | ||
2214 | |||
2215 | if (g->status == GROUPCHAT_STATUS_CONNECTED) { | ||
2216 | group_name_send(g_c, i, g_c->m->name, g_c->m->name_length); | ||
2217 | } | ||
2218 | } | ||
2219 | } | ||
2220 | |||
2221 | /* Create new groupchat instance. */ | ||
2222 | Group_Chats *new_groupchats(Messenger *m) | ||
2223 | { | ||
2224 | if (!m) | ||
2225 | return NULL; | ||
2226 | |||
2227 | Group_Chats *temp = calloc(1, sizeof(Group_Chats)); | ||
2228 | |||
2229 | if (temp == NULL) | ||
2230 | return NULL; | ||
2231 | |||
2232 | temp->m = m; | ||
2233 | temp->fr_c = m->fr_c; | ||
2234 | m->group_chat_object = temp; | ||
2235 | m_callback_group_invite(m, &handle_friend_invite_packet); | ||
2236 | |||
2237 | return temp; | ||
2238 | } | ||
2239 | |||
2240 | /* main groupchats loop. */ | ||
2241 | void do_groupchats(Group_Chats *g_c) | ||
2242 | { | ||
2243 | unsigned int i; | ||
2244 | |||
2245 | for (i = 0; i < g_c->num_chats; ++i) { | ||
2246 | Group_c *g = get_group_c(g_c, i); | ||
2247 | |||
2248 | if (!g) | ||
2249 | continue; | ||
2250 | |||
2251 | if (g->status == GROUPCHAT_STATUS_CONNECTED) { | ||
2252 | connect_to_closest(g_c, i); | ||
2253 | ping_groupchat(g_c, i); | ||
2254 | groupchat_clear_timedout(g_c, i); | ||
2255 | } | ||
2256 | } | ||
2257 | |||
2258 | //TODO | ||
2259 | } | ||
2260 | |||
2261 | /* Free everything related with group chats. */ | ||
2262 | void kill_groupchats(Group_Chats *g_c) | ||
2263 | { | ||
2264 | unsigned int i; | ||
2265 | |||
2266 | for (i = 0; i < g_c->num_chats; ++i) { | ||
2267 | del_groupchat(g_c, i); | ||
2268 | } | ||
2269 | |||
2270 | m_callback_group_invite(g_c->m, NULL); | ||
2271 | g_c->m->group_chat_object = 0; | ||
2272 | free(g_c); | ||
2273 | } | ||
2274 | |||
2275 | /* Return the number of chats in the instance m. | ||
2276 | * You should use this to determine how much memory to allocate | ||
2277 | * for copy_chatlist. | ||
2278 | */ | ||
2279 | uint32_t count_chatlist(Group_Chats *g_c) | ||
2280 | { | ||
2281 | uint32_t ret = 0; | ||
2282 | uint32_t i; | ||
2283 | |||
2284 | for (i = 0; i < g_c->num_chats; i++) { | ||
2285 | if (g_c->chats[i].status != GROUPCHAT_STATUS_NONE) { | ||
2286 | ret++; | ||
2287 | } | ||
2288 | } | ||
2289 | |||
2290 | return ret; | ||
2291 | } | ||
2292 | |||
2293 | /* Copy a list of valid chat IDs into the array out_list. | ||
2294 | * If out_list is NULL, returns 0. | ||
2295 | * Otherwise, returns the number of elements copied. | ||
2296 | * If the array was too small, the contents | ||
2297 | * of out_list will be truncated to list_size. */ | ||
2298 | uint32_t copy_chatlist(Group_Chats *g_c, int32_t *out_list, uint32_t list_size) | ||
2299 | { | ||
2300 | if (!out_list) { | ||
2301 | return 0; | ||
2302 | } | ||
2303 | |||
2304 | if (g_c->num_chats == 0) { | ||
2305 | return 0; | ||
2306 | } | ||
2307 | |||
2308 | uint32_t i, ret = 0; | ||
2309 | |||
2310 | for (i = 0; i < g_c->num_chats; ++i) { | ||
2311 | if (ret >= list_size) { | ||
2312 | break; /* Abandon ship */ | ||
2313 | } | ||
2314 | |||
2315 | if (g_c->chats[i].status > GROUPCHAT_STATUS_NONE) { | ||
2316 | out_list[ret] = i; | ||
2317 | ret++; | ||
2318 | } | ||
2319 | } | ||
2320 | |||
2321 | return ret; | ||
2322 | } | ||
diff --git a/toxcore/group.h b/toxcore/group.h new file mode 100644 index 00000000..8ae0e40e --- /dev/null +++ b/toxcore/group.h | |||
@@ -0,0 +1,380 @@ | |||
1 | /* group.h | ||
2 | * | ||
3 | * Slightly better groupchats implementation. | ||
4 | * | ||
5 | * Copyright (C) 2014 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 | |||
25 | #ifndef GROUP_H | ||
26 | #define GROUP_H | ||
27 | |||
28 | #include "Messenger.h" | ||
29 | |||
30 | enum { | ||
31 | GROUPCHAT_STATUS_NONE, | ||
32 | GROUPCHAT_STATUS_VALID, | ||
33 | GROUPCHAT_STATUS_CONNECTED | ||
34 | }; | ||
35 | |||
36 | enum { | ||
37 | GROUPCHAT_TYPE_TEXT, | ||
38 | GROUPCHAT_TYPE_AV | ||
39 | }; | ||
40 | |||
41 | #define MAX_LOSSY_COUNT 256 | ||
42 | |||
43 | typedef struct { | ||
44 | uint8_t real_pk[crypto_box_PUBLICKEYBYTES]; | ||
45 | uint8_t temp_pk[crypto_box_PUBLICKEYBYTES]; | ||
46 | |||
47 | uint64_t last_recv; | ||
48 | uint32_t last_message_number; | ||
49 | |||
50 | uint8_t nick[MAX_NAME_LENGTH]; | ||
51 | uint8_t nick_len; | ||
52 | |||
53 | uint16_t peer_number; | ||
54 | |||
55 | uint8_t recv_lossy[MAX_LOSSY_COUNT]; | ||
56 | uint16_t bottom_lossy_number, top_lossy_number; | ||
57 | |||
58 | void *object; | ||
59 | } Group_Peer; | ||
60 | |||
61 | #define DESIRED_CLOSE_CONNECTIONS 4 | ||
62 | #define MAX_GROUP_CONNECTIONS 16 | ||
63 | #define GROUP_IDENTIFIER_LENGTH (1 + crypto_box_KEYBYTES) /* type + crypto_box_KEYBYTES so we can use new_symmetric_key(...) to fill it */ | ||
64 | |||
65 | enum { | ||
66 | GROUPCHAT_CLOSE_NONE, | ||
67 | GROUPCHAT_CLOSE_CONNECTION, | ||
68 | GROUPCHAT_CLOSE_ONLINE | ||
69 | }; | ||
70 | |||
71 | typedef struct { | ||
72 | uint8_t status; | ||
73 | |||
74 | Group_Peer *group; | ||
75 | uint32_t numpeers; | ||
76 | |||
77 | struct { | ||
78 | uint8_t type; /* GROUPCHAT_CLOSE_* */ | ||
79 | uint8_t closest; | ||
80 | uint32_t number; | ||
81 | uint16_t group_number; | ||
82 | } close[MAX_GROUP_CONNECTIONS]; | ||
83 | |||
84 | uint8_t real_pk[crypto_box_PUBLICKEYBYTES]; | ||
85 | struct { | ||
86 | uint8_t entry; | ||
87 | uint8_t real_pk[crypto_box_PUBLICKEYBYTES]; | ||
88 | uint8_t temp_pk[crypto_box_PUBLICKEYBYTES]; | ||
89 | } closest_peers[DESIRED_CLOSE_CONNECTIONS]; | ||
90 | uint8_t changed; | ||
91 | |||
92 | uint8_t identifier[GROUP_IDENTIFIER_LENGTH]; | ||
93 | |||
94 | uint8_t title[MAX_NAME_LENGTH]; | ||
95 | uint8_t title_len; | ||
96 | |||
97 | uint32_t message_number; | ||
98 | uint16_t lossy_message_number; | ||
99 | uint16_t peer_number; | ||
100 | |||
101 | uint64_t last_sent_ping; | ||
102 | |||
103 | int number_joined; /* friendcon_id of person that invited us to the chat. (-1 means none) */ | ||
104 | |||
105 | void *object; | ||
106 | |||
107 | void (*peer_on_join)(void *, int, int); | ||
108 | void (*peer_on_leave)(void *, int, int, void *); | ||
109 | void (*group_on_delete)(void *, int); | ||
110 | } Group_c; | ||
111 | |||
112 | typedef struct { | ||
113 | Messenger *m; | ||
114 | Friend_Connections *fr_c; | ||
115 | |||
116 | Group_c *chats; | ||
117 | uint32_t num_chats; | ||
118 | |||
119 | void (*invite_callback)(Messenger *m, int32_t, uint8_t, const uint8_t *, uint16_t, void *); | ||
120 | void *invite_callback_userdata; | ||
121 | void (*message_callback)(Messenger *m, int, int, const uint8_t *, uint16_t, void *); | ||
122 | void *message_callback_userdata; | ||
123 | void (*action_callback)(Messenger *m, int, int, const uint8_t *, uint16_t, void *); | ||
124 | void *action_callback_userdata; | ||
125 | void (*peer_namelistchange)(Messenger *m, int, int, uint8_t, void *); | ||
126 | void *group_namelistchange_userdata; | ||
127 | void (*title_callback)(Messenger *m, int, int, const uint8_t *, uint8_t, void *); | ||
128 | void *title_callback_userdata; | ||
129 | |||
130 | struct { | ||
131 | int (*function)(void *, int, int, void *, const uint8_t *, uint16_t); | ||
132 | } lossy_packethandlers[256]; | ||
133 | } Group_Chats; | ||
134 | |||
135 | /* Set the callback for group invites. | ||
136 | * | ||
137 | * Function(Group_Chats *g_c, int32_t friendnumber, uint8_t type, uint8_t *data, uint16_t length, void *userdata) | ||
138 | * | ||
139 | * data of length is what needs to be passed to join_groupchat(). | ||
140 | */ | ||
141 | void g_callback_group_invite(Group_Chats *g_c, void (*function)(Messenger *m, int32_t, uint8_t, const uint8_t *, | ||
142 | uint16_t, void *), void *userdata); | ||
143 | |||
144 | /* Set the callback for group messages. | ||
145 | * | ||
146 | * Function(Group_Chats *g_c, int groupnumber, int friendgroupnumber, uint8_t * message, uint16_t length, void *userdata) | ||
147 | */ | ||
148 | void g_callback_group_message(Group_Chats *g_c, void (*function)(Messenger *m, int, int, const uint8_t *, uint16_t, | ||
149 | void *), void *userdata); | ||
150 | |||
151 | /* Set the callback for group actions. | ||
152 | * | ||
153 | * Function(Group_Chats *g_c, int groupnumber, int friendgroupnumber, uint8_t * message, uint16_t length, void *userdata) | ||
154 | */ | ||
155 | void g_callback_group_action(Group_Chats *g_c, void (*function)(Messenger *m, int, int, const uint8_t *, uint16_t, | ||
156 | void *), void *userdata); | ||
157 | |||
158 | /* Set callback function for title changes. | ||
159 | * | ||
160 | * Function(Group_Chats *g_c, int groupnumber, int friendgroupnumber, uint8_t * title, uint8_t length, void *userdata) | ||
161 | * if friendgroupnumber == -1, then author is unknown (e.g. initial joining the group) | ||
162 | */ | ||
163 | void g_callback_group_title(Group_Chats *g_c, void (*function)(Messenger *m, int, int, const uint8_t *, uint8_t, | ||
164 | void *), void *userdata); | ||
165 | |||
166 | /* Set callback function for peer name list changes. | ||
167 | * | ||
168 | * It gets called every time the name list changes(new peer/name, deleted peer) | ||
169 | * Function(Group_Chats *g_c, int groupnumber, int peernumber, TOX_CHAT_CHANGE change, void *userdata) | ||
170 | */ | ||
171 | enum { | ||
172 | CHAT_CHANGE_PEER_ADD, | ||
173 | CHAT_CHANGE_PEER_DEL, | ||
174 | CHAT_CHANGE_PEER_NAME, | ||
175 | }; | ||
176 | void g_callback_group_namelistchange(Group_Chats *g_c, void (*function)(Messenger *m, int, int, uint8_t, void *), | ||
177 | void *userdata); | ||
178 | |||
179 | /* Creates a new groupchat and puts it in the chats array. | ||
180 | * | ||
181 | * type is one of GROUPCHAT_TYPE_* | ||
182 | * | ||
183 | * return group number on success. | ||
184 | * return -1 on failure. | ||
185 | */ | ||
186 | int add_groupchat(Group_Chats *g_c, uint8_t type); | ||
187 | |||
188 | /* Delete a groupchat from the chats array. | ||
189 | * | ||
190 | * return 0 on success. | ||
191 | * return -1 if failure. | ||
192 | */ | ||
193 | int del_groupchat(Group_Chats *g_c, int groupnumber); | ||
194 | |||
195 | /* Copy the public key of peernumber who is in groupnumber to pk. | ||
196 | * pk must be crypto_box_PUBLICKEYBYTES long. | ||
197 | * | ||
198 | * returns 0 on success | ||
199 | * returns -1 on failure | ||
200 | */ | ||
201 | int group_peer_pubkey(const Group_Chats *g_c, int groupnumber, int peernumber, uint8_t *pk); | ||
202 | |||
203 | /* Copy the name of peernumber who is in groupnumber to name. | ||
204 | * name must be at least MAX_NAME_LENGTH long. | ||
205 | * | ||
206 | * return length of name if success | ||
207 | * return -1 if failure | ||
208 | */ | ||
209 | int group_peername(const Group_Chats *g_c, int groupnumber, int peernumber, uint8_t *name); | ||
210 | |||
211 | /* invite friendnumber to groupnumber | ||
212 | * return 0 on success | ||
213 | * return -1 on failure | ||
214 | */ | ||
215 | int invite_friend(Group_Chats *g_c, int32_t friendnumber, int groupnumber); | ||
216 | |||
217 | /* Join a group (you need to have been invited first.) | ||
218 | * | ||
219 | * expected_type is the groupchat type we expect the chat we are joining is. | ||
220 | * | ||
221 | * returns group number on success | ||
222 | * returns -1 on failure. | ||
223 | */ | ||
224 | int join_groupchat(Group_Chats *g_c, int32_t friendnumber, uint8_t expected_type, const uint8_t *data, uint16_t length); | ||
225 | |||
226 | /* send a group message | ||
227 | * return 0 on success | ||
228 | * return -1 on failure | ||
229 | */ | ||
230 | int group_message_send(const Group_Chats *g_c, int groupnumber, const uint8_t *message, uint16_t length); | ||
231 | |||
232 | /* send a group action | ||
233 | * return 0 on success | ||
234 | * return -1 on failure | ||
235 | */ | ||
236 | int group_action_send(const Group_Chats *g_c, int groupnumber, const uint8_t *action, uint16_t length); | ||
237 | |||
238 | /* set the group's title, limited to MAX_NAME_LENGTH | ||
239 | * return 0 on success | ||
240 | * return -1 on failure | ||
241 | */ | ||
242 | int group_title_send(const Group_Chats *g_c, int groupnumber, const uint8_t *title, uint8_t title_len); | ||
243 | |||
244 | |||
245 | /* Get group title from groupnumber and put it in title. | ||
246 | * title needs to be a valid memory location with a max_length size of at least MAX_NAME_LENGTH (128) bytes. | ||
247 | * | ||
248 | * return length of copied title if success. | ||
249 | * return -1 if failure. | ||
250 | */ | ||
251 | int group_title_get(const Group_Chats *g_c, int groupnumber, uint8_t *title, uint32_t max_length); | ||
252 | |||
253 | /* Return the number of peers in the group chat on success. | ||
254 | * return -1 on failure | ||
255 | */ | ||
256 | int group_number_peers(const Group_Chats *g_c, int groupnumber); | ||
257 | |||
258 | /* return 1 if the peernumber corresponds to ours. | ||
259 | * return 0 on failure. | ||
260 | */ | ||
261 | unsigned int group_peernumber_is_ours(const Group_Chats *g_c, int groupnumber, int peernumber); | ||
262 | |||
263 | /* List all the peers in the group chat. | ||
264 | * | ||
265 | * Copies the names of the peers to the name[length][MAX_NAME_LENGTH] array. | ||
266 | * | ||
267 | * Copies the lengths of the names to lengths[length] | ||
268 | * | ||
269 | * returns the number of peers on success. | ||
270 | * | ||
271 | * return -1 on failure. | ||
272 | */ | ||
273 | int group_names(const Group_Chats *g_c, int groupnumber, uint8_t names[][MAX_NAME_LENGTH], uint16_t lengths[], | ||
274 | uint16_t length); | ||
275 | |||
276 | /* Set handlers for custom lossy packets. | ||
277 | * | ||
278 | * NOTE: Handler must return 0 if packet is to be relayed, -1 if the packet should not be relayed. | ||
279 | * | ||
280 | * Function(void *group object (set with group_set_object), int groupnumber, int friendgroupnumber, void *group peer object (set with group_peer_set_object), const uint8_t *packet, uint16_t length) | ||
281 | */ | ||
282 | void group_lossy_packet_registerhandler(Group_Chats *g_c, uint8_t byte, int (*function)(void *, int, int, void *, | ||
283 | const uint8_t *, uint16_t)); | ||
284 | |||
285 | /* High level function to send custom lossy packets. | ||
286 | * | ||
287 | * return -1 on failure. | ||
288 | * return 0 on success. | ||
289 | */ | ||
290 | int send_group_lossy_packet(const Group_Chats *g_c, int groupnumber, const uint8_t *data, uint16_t length); | ||
291 | |||
292 | /* Return the number of chats in the instance m. | ||
293 | * You should use this to determine how much memory to allocate | ||
294 | * for copy_chatlist. | ||
295 | */ | ||
296 | uint32_t count_chatlist(Group_Chats *g_c); | ||
297 | |||
298 | /* Copy a list of valid chat IDs into the array out_list. | ||
299 | * If out_list is NULL, returns 0. | ||
300 | * Otherwise, returns the number of elements copied. | ||
301 | * If the array was too small, the contents | ||
302 | * of out_list will be truncated to list_size. */ | ||
303 | uint32_t copy_chatlist(Group_Chats *g_c, int32_t *out_list, uint32_t list_size); | ||
304 | |||
305 | /* return the type of groupchat (GROUPCHAT_TYPE_) that groupnumber is. | ||
306 | * | ||
307 | * return -1 on failure. | ||
308 | * return type on success. | ||
309 | */ | ||
310 | int group_get_type(const Group_Chats *g_c, int groupnumber); | ||
311 | |||
312 | /* Send current name (set in messenger) to all online groups. | ||
313 | */ | ||
314 | void send_name_all_groups(Group_Chats *g_c); | ||
315 | |||
316 | /* Set the object that is tied to the group chat. | ||
317 | * | ||
318 | * return 0 on success. | ||
319 | * return -1 on failure | ||
320 | */ | ||
321 | int group_set_object(const Group_Chats *g_c, int groupnumber, void *object); | ||
322 | |||
323 | /* Set the object that is tied to the group peer. | ||
324 | * | ||
325 | * return 0 on success. | ||
326 | * return -1 on failure | ||
327 | */ | ||
328 | int group_peer_set_object(const Group_Chats *g_c, int groupnumber, int peernumber, void *object); | ||
329 | |||
330 | /* Return the object tide to the group chat previously set by group_set_object. | ||
331 | * | ||
332 | * return NULL on failure. | ||
333 | * return object on success. | ||
334 | */ | ||
335 | void *group_get_object(const Group_Chats *g_c, int groupnumber); | ||
336 | |||
337 | /* Return the object tide to the group chat peer previously set by group_peer_set_object. | ||
338 | * | ||
339 | * return NULL on failure. | ||
340 | * return object on success. | ||
341 | */ | ||
342 | void *group_peer_get_object(const Group_Chats *g_c, int groupnumber, int peernumber); | ||
343 | |||
344 | /* Set a function to be called when a new peer joins a group chat. | ||
345 | * | ||
346 | * Function(void *group object (set with group_set_object), int groupnumber, int friendgroupnumber) | ||
347 | * | ||
348 | * return 0 on success. | ||
349 | * return -1 on failure. | ||
350 | */ | ||
351 | int callback_groupchat_peer_new(const Group_Chats *g_c, int groupnumber, void (*function)(void *, int, int)); | ||
352 | |||
353 | /* Set a function to be called when a peer leaves a group chat. | ||
354 | * | ||
355 | * Function(void *group object (set with group_set_object), int groupnumber, int friendgroupnumber, void *group peer object (set with group_peer_set_object)) | ||
356 | * | ||
357 | * return 0 on success. | ||
358 | * return -1 on failure. | ||
359 | */ | ||
360 | int callback_groupchat_peer_delete(Group_Chats *g_c, int groupnumber, void (*function)(void *, int, int, void *)); | ||
361 | |||
362 | /* Set a function to be called when the group chat is deleted. | ||
363 | * | ||
364 | * Function(void *group object (set with group_set_object), int groupnumber) | ||
365 | * | ||
366 | * return 0 on success. | ||
367 | * return -1 on failure. | ||
368 | */ | ||
369 | int callback_groupchat_delete(Group_Chats *g_c, int groupnumber, void (*function)(void *, int)); | ||
370 | |||
371 | /* Create new groupchat instance. */ | ||
372 | Group_Chats *new_groupchats(Messenger *m); | ||
373 | |||
374 | /* main groupchats loop. */ | ||
375 | void do_groupchats(Group_Chats *g_c); | ||
376 | |||
377 | /* Free everything related with group chats. */ | ||
378 | void kill_groupchats(Group_Chats *g_c); | ||
379 | |||
380 | #endif | ||
diff --git a/toxcore/group_chats.c b/toxcore/group_chats.c deleted file mode 100644 index 77fa6acd..00000000 --- a/toxcore/group_chats.c +++ /dev/null | |||
@@ -1,837 +0,0 @@ | |||
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 | int ok = 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 | } | ||
diff --git a/toxcore/group_chats.h b/toxcore/group_chats.h deleted file mode 100644 index 1a7a2e04..00000000 --- a/toxcore/group_chats.h +++ /dev/null | |||
@@ -1,199 +0,0 @@ | |||
1 | /* group_chats.h | ||
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 | #ifndef GROUP_CHATS_H | ||
26 | #define GROUP_CHATS_H | ||
27 | |||
28 | #define MAX_NICK_BYTES 128 | ||
29 | |||
30 | typedef struct { | ||
31 | uint8_t client_id[crypto_box_PUBLICKEYBYTES]; | ||
32 | uint64_t pingid; | ||
33 | uint64_t last_pinged; | ||
34 | IP_Port ping_via; | ||
35 | |||
36 | uint64_t last_recv; | ||
37 | uint64_t last_recv_msgping; | ||
38 | uint32_t last_message_number; | ||
39 | |||
40 | uint8_t nick[MAX_NICK_BYTES]; | ||
41 | uint16_t nick_len; | ||
42 | |||
43 | uint8_t deleted; | ||
44 | uint64_t deleted_time; | ||
45 | } Group_Peer; | ||
46 | |||
47 | typedef struct { | ||
48 | uint8_t client_id[crypto_box_PUBLICKEYBYTES]; | ||
49 | IP_Port ip_port; | ||
50 | uint64_t last_recv; | ||
51 | } Group_Close; | ||
52 | |||
53 | #define GROUP_CLOSE_CONNECTIONS 6 | ||
54 | |||
55 | typedef struct Group_Chat { | ||
56 | Networking_Core *net; | ||
57 | uint8_t self_public_key[crypto_box_PUBLICKEYBYTES]; | ||
58 | uint8_t self_secret_key[crypto_box_SECRETKEYBYTES]; | ||
59 | |||
60 | Group_Peer *group; | ||
61 | Group_Close close[GROUP_CLOSE_CONNECTIONS]; | ||
62 | uint32_t numpeers; | ||
63 | |||
64 | uint32_t message_number; | ||
65 | void (*group_message)(struct Group_Chat *m, int, const uint8_t *, uint16_t, void *); | ||
66 | void *group_message_userdata; | ||
67 | void (*group_action)(struct Group_Chat *m, int, const uint8_t *, uint16_t, void *); | ||
68 | void *group_action_userdata; | ||
69 | void (*peer_namelistchange)(struct Group_Chat *m, int peer, uint8_t change, void *); | ||
70 | void *group_namelistchange_userdata; | ||
71 | |||
72 | uint64_t last_sent_ping; | ||
73 | |||
74 | uint8_t nick[MAX_NICK_BYTES]; | ||
75 | uint16_t nick_len; | ||
76 | uint64_t last_sent_nick; | ||
77 | |||
78 | struct Assoc *assoc; | ||
79 | } Group_Chat; | ||
80 | |||
81 | #define GROUP_CHAT_PING 0 | ||
82 | #define GROUP_CHAT_NEW_PEER 16 | ||
83 | #define GROUP_CHAT_QUIT 24 | ||
84 | #define GROUP_CHAT_PEER_NICK 48 | ||
85 | #define GROUP_CHAT_CHAT_MESSAGE 64 | ||
86 | #define GROUP_CHAT_ACTION 63 | ||
87 | |||
88 | /* Copy the name of peernum to name. | ||
89 | * name must be at least MAX_NICK_BYTES long. | ||
90 | * | ||
91 | * return length of name if success | ||
92 | * return -1 if failure | ||
93 | */ | ||
94 | int group_peername(const Group_Chat *chat, int peernum, uint8_t *name); | ||
95 | |||
96 | /* | ||
97 | * Set callback function for chat messages. | ||
98 | * | ||
99 | * format of function is: function(Group_Chat *chat, peer number, message, message length, userdata) | ||
100 | */ | ||
101 | void callback_groupmessage(Group_Chat *chat, void (*function)(Group_Chat *chat, int, const uint8_t *, uint16_t, void *), | ||
102 | void *userdata); | ||
103 | |||
104 | /* | ||
105 | * Set callback function for actions. | ||
106 | * | ||
107 | * format of function is: function(Group_Chat *chat, peer number, action, action length, userdata) | ||
108 | */ | ||
109 | void callback_groupaction(Group_Chat *chat, void (*function)(Group_Chat *chat, int, const uint8_t *, uint16_t, void *), | ||
110 | void *userdata); | ||
111 | |||
112 | /* | ||
113 | * Set callback function for peer name list changes. | ||
114 | * | ||
115 | * It gets called every time the name list changes(new peer/name, deleted peer) | ||
116 | * | ||
117 | * format of function is: function(Group_Chat *chat, userdata) | ||
118 | */ | ||
119 | typedef enum { | ||
120 | CHAT_CHANGE_PEER_ADD, | ||
121 | CHAT_CHANGE_PEER_DEL, | ||
122 | CHAT_CHANGE_PEER_NAME, | ||
123 | } CHAT_CHANGE; | ||
124 | |||
125 | void callback_namelistchange(Group_Chat *chat, void (*function)(Group_Chat *chat, int peer, uint8_t change, void *), | ||
126 | void *userdata); | ||
127 | |||
128 | /* | ||
129 | * Send a message to the group. | ||
130 | * | ||
131 | * returns the number of peers it has sent it to. | ||
132 | */ | ||
133 | uint32_t group_sendmessage(Group_Chat *chat, const uint8_t *message, uint32_t length); | ||
134 | |||
135 | /* | ||
136 | * Send an action to the group. | ||
137 | * | ||
138 | * returns the number of peers it has sent it to. | ||
139 | */ | ||
140 | uint32_t group_sendaction(Group_Chat *chat, const uint8_t *action, uint32_t length); | ||
141 | |||
142 | /* | ||
143 | * Set our nick for this group. | ||
144 | * | ||
145 | * returns -1 on failure, 0 on success. | ||
146 | */ | ||
147 | int set_nick(Group_Chat *chat, const uint8_t *nick, uint16_t nick_len); | ||
148 | |||
149 | /* | ||
150 | * Tell everyone about a new peer (a person we are inviting for example.) | ||
151 | * | ||
152 | */ | ||
153 | uint32_t group_newpeer(Group_Chat *chat, const uint8_t *client_id); | ||
154 | |||
155 | |||
156 | /* Create a new group chat. | ||
157 | * | ||
158 | * Returns a new group chat instance if success. | ||
159 | * | ||
160 | * Returns a NULL pointer if fail. | ||
161 | */ | ||
162 | Group_Chat *new_groupchat(Networking_Core *net); | ||
163 | |||
164 | |||
165 | /* Return the number of peers in the group chat. | ||
166 | */ | ||
167 | uint32_t group_numpeers(const Group_Chat *chat); | ||
168 | |||
169 | /* List all the peers in the group chat. | ||
170 | * | ||
171 | * Copies the names of the peers to the name[length][MAX_NICK_BYTES] array. | ||
172 | * | ||
173 | * returns the number of peers. | ||
174 | */ | ||
175 | uint32_t group_client_names(const Group_Chat *chat, uint8_t names[][MAX_NICK_BYTES], uint16_t lengths[], | ||
176 | uint16_t length); | ||
177 | |||
178 | /* Kill a group chat | ||
179 | * | ||
180 | * Frees the memory and everything. | ||
181 | */ | ||
182 | void kill_groupchat(Group_Chat *chat); | ||
183 | |||
184 | /* | ||
185 | * This is the main loop. | ||
186 | */ | ||
187 | void do_groupchat(Group_Chat *chat); | ||
188 | |||
189 | /* if we receive a group chat packet we call this function so it can be handled. | ||
190 | return 0 if packet is handled correctly. | ||
191 | return 1 if it didn't handle the packet or if the packet was shit. */ | ||
192 | int handle_groupchatpacket(Group_Chat *chat, IP_Port source, const uint8_t *packet, uint32_t length); | ||
193 | |||
194 | |||
195 | void chat_bootstrap(Group_Chat *chat, IP_Port ip_port, const uint8_t *client_id); | ||
196 | void chat_bootstrap_nonlazy(Group_Chat *chat, IP_Port ip_port, const uint8_t *client_id); | ||
197 | |||
198 | |||
199 | #endif | ||
diff --git a/toxcore/logger.c b/toxcore/logger.c index 48a2f303..e8aef7e0 100644 --- a/toxcore/logger.c +++ b/toxcore/logger.c | |||
@@ -1,8 +1,6 @@ | |||
1 | /* logger.c | 1 | /* logger.c |
2 | * | 2 | * |
3 | * Wrapping logger functions in nice macros | 3 | * Copyright (C) 2013, 2015 Tox project All Rights Reserved. |
4 | * | ||
5 | * Copyright (C) 2013 Tox project All Rights Reserved. | ||
6 | * | 4 | * |
7 | * This file is part of Tox. | 5 | * This file is part of Tox. |
8 | * | 6 | * |
@@ -26,10 +24,7 @@ | |||
26 | #endif /* HAVE_CONFIG_H */ | 24 | #endif /* HAVE_CONFIG_H */ |
27 | 25 | ||
28 | #include "logger.h" | 26 | #include "logger.h" |
29 | 27 | #include "crypto_core.h" /* for random_int() */ | |
30 | #ifdef LOGGING | ||
31 | |||
32 | #include "network.h" /* for time */ | ||
33 | 28 | ||
34 | #include <stdio.h> | 29 | #include <stdio.h> |
35 | #include <errno.h> | 30 | #include <errno.h> |
@@ -37,117 +32,206 @@ | |||
37 | #include <stdarg.h> | 32 | #include <stdarg.h> |
38 | #include <inttypes.h> | 33 | #include <inttypes.h> |
39 | #include <time.h> | 34 | #include <time.h> |
35 | #include <pthread.h> | ||
40 | 36 | ||
41 | #if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) | 37 | #if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) |
42 | #define strerror_r(errno,buf,len) strerror_s(buf,len,errno) | 38 | # define getpid() ((unsigned) GetCurrentProcessId()) |
39 | # define SFILE(FILE__M) (strrchr(FILE__M, '\\') ? strrchr(FILE__M, '\\') + 1 : FILE__M) | ||
40 | # define WIN_CR "\r" | ||
41 | #else | ||
42 | # define SFILE(FILE__M) (strrchr(FILE__M, '/') ? strrchr(FILE__M, '/') + 1 : FILE__M) | ||
43 | # define WIN_CR "" | ||
43 | #endif | 44 | #endif |
44 | 45 | ||
45 | static struct logger_config { | 46 | |
47 | struct logger { | ||
46 | FILE *log_file; | 48 | FILE *log_file; |
47 | LoggerLevel level; | 49 | LOG_LEVEL level; |
48 | uint64_t start_time; /* Time when lib loaded */ | 50 | uint64_t start_time; /* Time when lib loaded */ |
49 | } | 51 | char *id; |
50 | logger = { | 52 | |
51 | NULL, | 53 | /* Allocate these once */ |
52 | DEBUG, | 54 | char *tstr; |
53 | 0 | 55 | char *posstr; |
56 | char *msg; | ||
57 | |||
58 | /* For thread synchronisation */ | ||
59 | pthread_mutex_t mutex[1]; | ||
54 | }; | 60 | }; |
55 | 61 | ||
56 | void __attribute__((destructor)) terminate_logger() | 62 | Logger *global = NULL; |
57 | { | 63 | |
58 | if ( !logger.log_file ) return; | 64 | const char *LOG_LEVEL_STR [] = { |
65 | [LOG_TRACE] = "TRACE", | ||
66 | [LOG_DEBUG] = "DEBUG", | ||
67 | [LOG_INFO] = "INFO" , | ||
68 | [LOG_WARNING] = "WARN" , | ||
69 | [LOG_ERROR] = "ERROR", | ||
70 | }; | ||
59 | 71 | ||
60 | time_t tim = time(NULL); | 72 | char *strtime(char *dest, size_t max_len) |
73 | { | ||
74 | time_t timer; | ||
75 | struct tm *tm_info; | ||
61 | 76 | ||
62 | logger_write(ERROR, "\n============== Closing logger [%u] ==============\n" | 77 | time(&timer); |
63 | "Time: %s", logger_get_pid(), asctime(localtime(&tim))); | 78 | tm_info = localtime(&timer); |
64 | 79 | ||
65 | fclose(logger.log_file); | 80 | strftime(dest, max_len, "%m:%d %H:%M:%S", tm_info); |
81 | return dest; | ||
66 | } | 82 | } |
67 | 83 | ||
68 | unsigned logger_get_pid() | 84 | |
85 | /** | ||
86 | * Public Functions | ||
87 | */ | ||
88 | Logger *logger_new (const char *file_name, LOG_LEVEL level, const char *id) | ||
69 | { | 89 | { |
70 | return | 90 | #ifndef LOGGING /* Disabled */ |
71 | #if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) | 91 | return NULL; |
72 | GetCurrentProcessId(); | ||
73 | #else | ||
74 | getpid(); | ||
75 | #endif | 92 | #endif |
76 | } | ||
77 | 93 | ||
78 | const char *logger_stringify_level(LoggerLevel level) | 94 | Logger *retu = calloc(1, sizeof(Logger)); |
79 | { | ||
80 | static const char *strings [] = { | ||
81 | "INFO", | ||
82 | "DEBUG", | ||
83 | "WARNING", | ||
84 | "ERROR" | ||
85 | }; | ||
86 | |||
87 | return strings[level]; | ||
88 | } | ||
89 | 95 | ||
96 | if (!retu) | ||
97 | return NULL; | ||
90 | 98 | ||
91 | int logger_init(const char *file_name, LoggerLevel level) | 99 | if ( pthread_mutex_init(retu->mutex, NULL) != 0 ) { |
92 | { | 100 | free(retu); |
93 | char *final_l = calloc(sizeof(char), strlen(file_name) + 32); | 101 | return NULL; |
94 | sprintf(final_l, "%s"/*.%u"*/, file_name/*, logger_get_pid()*/); | 102 | } |
95 | 103 | ||
96 | if ( logger.log_file ) { | 104 | if (!(retu->log_file = fopen(file_name, "ab"))) { |
97 | fprintf(stderr, "Error opening logger name: %s with level %d: file already opened!\n", final_l, level); | 105 | fprintf(stderr, "Error opening logger file: %s; info: %s" WIN_CR "\n", file_name, strerror(errno)); |
98 | free (final_l); | 106 | free(retu); |
99 | return -1; | 107 | pthread_mutex_destroy(retu->mutex); |
108 | return NULL; | ||
100 | } | 109 | } |
101 | 110 | ||
102 | logger.log_file = fopen(final_l, "ab"); | 111 | if (!(retu->tstr = calloc(16, sizeof (char))) || |
112 | !(retu->posstr = calloc(300, sizeof (char))) || | ||
113 | !(retu->msg = calloc(4096, sizeof (char))) ) | ||
114 | goto FAILURE; | ||
115 | |||
116 | if (id) { | ||
117 | if (!(retu->id = calloc(strlen(id) + 1, 1))) | ||
118 | goto FAILURE; | ||
103 | 119 | ||
104 | if ( logger.log_file == NULL ) { | 120 | strcpy(retu->id, id); |
105 | fprintf(stderr, "Error opening logger file: %s; info: %s\n", final_l, strerror(errno)); | 121 | } else { |
122 | if (!(retu->id = malloc(8))) | ||
123 | goto FAILURE; | ||
106 | 124 | ||
107 | free (final_l); | 125 | snprintf(retu->id, 8, "%u", random_int()); |
108 | return -1; | ||
109 | } | 126 | } |
110 | 127 | ||
128 | retu->level = level; | ||
129 | retu->start_time = current_time_monotonic(); | ||
111 | 130 | ||
112 | logger.level = level; | 131 | fprintf(retu->log_file, "Successfully created and running logger id: %s; time: %s" WIN_CR "\n", |
113 | logger.start_time = current_time_monotonic(); | 132 | retu->id, strtime(retu->tstr, 16)); |
114 | 133 | ||
134 | return retu; | ||
115 | 135 | ||
116 | time_t tim = time(NULL); | 136 | FAILURE: |
117 | logger_write(ERROR, "\n============== Starting logger [%u] ==============\n" | 137 | fprintf(stderr, "Failed to create logger!" WIN_CR "\n"); |
118 | "Time: %s", logger_get_pid(), asctime(localtime(&tim))); | 138 | pthread_mutex_destroy(retu->mutex); |
139 | fclose(retu->log_file); | ||
140 | free(retu->tstr); | ||
141 | free(retu->posstr); | ||
142 | free(retu->msg); | ||
143 | free(retu->id); | ||
144 | free(retu); | ||
145 | return NULL; | ||
146 | } | ||
119 | 147 | ||
148 | void logger_kill(Logger *log) | ||
149 | { | ||
150 | #ifndef LOGGING /* Disabled */ | ||
151 | return; | ||
152 | #endif | ||
120 | 153 | ||
154 | if (!log) | ||
155 | return; | ||
156 | |||
157 | pthread_mutex_lock(log->mutex); | ||
158 | free(log->id); | ||
159 | free(log->tstr); | ||
160 | free(log->posstr); | ||
161 | free(log->msg); | ||
162 | |||
163 | if (fclose(log->log_file) != 0 ) | ||
164 | perror("Could not close log file"); | ||
165 | |||
166 | pthread_mutex_unlock(log->mutex); | ||
167 | pthread_mutex_destroy(log->mutex); | ||
121 | 168 | ||
122 | free (final_l); | 169 | free(log); |
123 | return 0; | ||
124 | } | 170 | } |
125 | 171 | ||
172 | void logger_kill_global(void) | ||
173 | { | ||
174 | logger_kill(global); | ||
175 | global = NULL; | ||
176 | } | ||
126 | 177 | ||
127 | void logger_write (LoggerLevel level, const char *format, ...) | 178 | void logger_set_global(Logger *log) |
128 | { | 179 | { |
129 | if (logger.log_file == NULL) { | 180 | #ifndef LOGGING /* Disabled */ |
130 | /*fprintf(stderr, "Logger file is NULL!\n");*/ | 181 | return; |
131 | return; | 182 | #endif |
132 | } | ||
133 | 183 | ||
134 | if (logger.level > level) return; /* Don't print some levels xuh */ | 184 | global = log; |
185 | } | ||
135 | 186 | ||
136 | va_list _arg; | 187 | Logger *logger_get_global(void) |
137 | va_start (_arg, format); | 188 | { |
138 | vfprintf (logger.log_file, format, _arg); | 189 | #ifndef LOGGING /* Disabled */ |
139 | va_end (_arg); | 190 | return NULL; |
191 | #endif | ||
140 | 192 | ||
141 | fflush(logger.log_file); | 193 | return global; |
142 | } | 194 | } |
143 | 195 | ||
144 | char *logger_timestr(char *dest, size_t max_size) | 196 | void logger_write (Logger *log, LOG_LEVEL level, const char *file, int line, const char *format, ...) |
145 | { | 197 | { |
146 | uint64_t diff = (current_time_monotonic() - logger.start_time); /* ms */ | 198 | #ifndef LOGGING /* Disabled */ |
147 | snprintf(dest, max_size, "%"PRIu64"", diff); | 199 | return; |
200 | #endif | ||
148 | 201 | ||
149 | return dest; | 202 | static const char *logger_format = |
150 | } | 203 | "%s " /* Logger id string */ |
204 | "%-16s" /* Time string of format: %m:%d %H:%M:%S */ | ||
205 | "%u " /* Thread id */ | ||
206 | "%-5s " /* Logger lever string */ | ||
207 | "%-20s " /* File:line string */ | ||
208 | "- %s" /* Output message */ | ||
209 | WIN_CR "\n"; /* Every new print new line */ | ||
210 | |||
211 | |||
212 | Logger *this_log = log ? log : global; | ||
213 | |||
214 | if (!this_log) | ||
215 | return; | ||
151 | 216 | ||
217 | /* Don't print levels lesser than set one */ | ||
218 | if (this_log->level > level) | ||
219 | return; | ||
220 | |||
221 | pthread_mutex_lock(this_log->mutex); | ||
222 | |||
223 | /* Set position str */ | ||
224 | snprintf(this_log->posstr, 300, "%s:%d", SFILE(file), line); | ||
152 | 225 | ||
153 | #endif /* LOGGING */ | 226 | /* Set message */ |
227 | va_list args; | ||
228 | va_start (args, format); | ||
229 | vsnprintf(this_log->msg, 4096, format, args); | ||
230 | va_end (args); | ||
231 | |||
232 | fprintf(this_log->log_file, logger_format, this_log->id, strtime(this_log->tstr, 16), pthread_self(), | ||
233 | LOG_LEVEL_STR[level], this_log->posstr, this_log->msg); | ||
234 | fflush(this_log->log_file); | ||
235 | |||
236 | pthread_mutex_unlock(this_log->mutex); | ||
237 | } | ||
diff --git a/toxcore/logger.h b/toxcore/logger.h index 56fe086d..0513b32c 100644 --- a/toxcore/logger.h +++ b/toxcore/logger.h | |||
@@ -1,7 +1,5 @@ | |||
1 | /* logger.h | 1 | /* logger.h |
2 | * | 2 | * |
3 | * Wrapping logger functions in nice macros | ||
4 | * | ||
5 | * Copyright (C) 2013 Tox project All Rights Reserved. | 3 | * Copyright (C) 2013 Tox project All Rights Reserved. |
6 | * | 4 | * |
7 | * This file is part of Tox. | 5 | * This file is part of Tox. |
@@ -22,63 +20,74 @@ | |||
22 | */ | 20 | */ |
23 | 21 | ||
24 | 22 | ||
25 | #ifndef __TOXLOGGER | 23 | #ifndef TOXLOGGER_H |
26 | #define __TOXLOGGER | 24 | #define TOXLOGGER_H |
27 | 25 | ||
28 | #include <string.h> | 26 | #include <string.h> |
29 | 27 | ||
30 | #ifdef LOGGING | 28 | /* In case these are undefined; define 'empty' */ |
31 | 29 | #ifndef LOGGER_OUTPUT_FILE | |
32 | typedef enum _LoggerLevel { | 30 | # define LOGGER_OUTPUT_FILE "" |
33 | INFO, | 31 | #endif |
34 | DEBUG, | ||
35 | WARNING, | ||
36 | ERROR | ||
37 | } LoggerLevel; | ||
38 | 32 | ||
39 | /* | 33 | #ifndef LOGGER_LEVEL |
40 | * Set 'level' as the lowest printable level | 34 | # define LOGGER_LEVEL LOG_ERROR |
41 | */ | ||
42 | int logger_init(const char *file_name, LoggerLevel level); | ||
43 | const char *logger_stringify_level(LoggerLevel level); | ||
44 | unsigned logger_get_pid(); | ||
45 | void logger_write (LoggerLevel level, const char *format, ...); | ||
46 | char *logger_timestr (char *dest, size_t max_size); | ||
47 | |||
48 | #if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) | ||
49 | #define _SFILE (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__) | ||
50 | #else | ||
51 | #define _SFILE (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) | ||
52 | #endif | 35 | #endif |
53 | 36 | ||
54 | #define WRITE_FORMAT(__LEVEL__, format) char __time__[20]; char* the_str = calloc(sizeof(char), strlen(format)+ 500); sprintf(the_str, "\n[%u] [%s] [%s] [%s:%d %s()] %s", \ | ||
55 | logger_get_pid(), logger_stringify_level(__LEVEL__), logger_timestr(__time__, 20), _SFILE, __LINE__, __func__, format) | ||
56 | 37 | ||
57 | /* Use these macros */ | 38 | typedef enum { |
39 | LOG_TRACE, | ||
40 | LOG_DEBUG, | ||
41 | LOG_INFO, | ||
42 | LOG_WARNING, | ||
43 | LOG_ERROR | ||
44 | } LOG_LEVEL; | ||
58 | 45 | ||
59 | #define LOGGER_INIT(name, level) logger_init(name, level); | 46 | typedef struct logger Logger; |
60 | #define LOGGER_INFO(format, ...) do { WRITE_FORMAT(INFO, format); logger_write( INFO, the_str, ##__VA_ARGS__ ); free(the_str); } while (0) | ||
61 | #define LOGGER_DEBUG(format, ...) do { WRITE_FORMAT(DEBUG, format); logger_write( DEBUG, the_str, ##__VA_ARGS__ ); free(the_str); } while (0) | ||
62 | #define LOGGER_WARNING(format, ...) do { WRITE_FORMAT(WARNING, format); logger_write( WARNING, the_str, ##__VA_ARGS__ ); free(the_str); } while (0) | ||
63 | #define LOGGER_ERROR(format, ...) do { WRITE_FORMAT(ERROR, format); logger_write( ERROR, the_str, ##__VA_ARGS__ ); free(the_str); } while (0) | ||
64 | 47 | ||
65 | /* To do some checks or similar only when logging use this */ | 48 | /** |
66 | #define LOGGER_SCOPE(__SCOPE_DO__) do { __SCOPE_DO__ } while(0) | 49 | * Set 'level' as the lowest printable level. If id == NULL, random number is used. |
50 | */ | ||
51 | Logger *logger_new (const char *file_name, LOG_LEVEL level, const char *id); | ||
67 | 52 | ||
68 | #else | 53 | void logger_kill (Logger *log); |
54 | void logger_kill_global (void); | ||
69 | 55 | ||
56 | /** | ||
57 | * Global logger setter and getter. | ||
58 | */ | ||
59 | void logger_set_global (Logger *log); | ||
60 | Logger *logger_get_global (void); | ||
70 | 61 | ||
71 | #define LOGGER_INIT(name, level) do {} while(0) | 62 | /** |
72 | #define LOGGER_INFO(format, ...) do {} while(0) | 63 | * Main write function. If logging disabled does nothing. If log == NULL uses global logger. |
73 | #define LOGGER_DEBUG(format, ...) do {} while(0) | 64 | */ |
74 | #define LOGGER_WARNING(format, ...) do {} while(0) | 65 | void logger_write (Logger *log, LOG_LEVEL level, const char *file, int line, const char *format, ...); |
75 | #define LOGGER_ERROR(format, ...) do {} while(0) | ||
76 | 66 | ||
77 | #define LOGGER_SCOPE(__SCOPE_DO__) do {} while(0) | ||
78 | 67 | ||
68 | /* To do some checks or similar only when logging, use this */ | ||
69 | #ifdef LOGGING | ||
70 | # define LOGGER_SCOPE(__SCOPE_DO__) do { __SCOPE_DO__ } while(0) | ||
71 | # define LOGGER_WRITE(log, level, format, ...) \ | ||
72 | logger_write(log, level, __FILE__, __LINE__, format, ##__VA_ARGS__ ) | ||
73 | #else | ||
74 | # define LOGGER_SCOPE(__SCOPE_DO__) do {} while(0) | ||
75 | # define LOGGER_WRITE(log, level, format, ...) do {} while(0) | ||
79 | #endif /* LOGGING */ | 76 | #endif /* LOGGING */ |
80 | 77 | ||
78 | /* To log with an logger */ | ||
79 | #define LOGGER_TRACE_(log, format, ...) LOGGER_WRITE(log, LOG_TRACE, format, ##__VA_ARGS__ ) | ||
80 | #define LOGGER_DEBUG_(log, format, ...) LOGGER_WRITE(log, LOG_DEBUG, format, ##__VA_ARGS__ ) | ||
81 | #define LOGGER_INFO_(log, format, ...) LOGGER_WRITE(log, LOG_INFO, format, ##__VA_ARGS__ ) | ||
82 | #define LOGGER_WARNING_(log, format, ...) LOGGER_WRITE(log, LOG_WARNING, format, ##__VA_ARGS__ ) | ||
83 | #define LOGGER_ERROR_(log, format, ...) LOGGER_WRITE(log, LOG_ERROR, format, ##__VA_ARGS__ ) | ||
81 | 84 | ||
85 | /* To log with the global logger */ | ||
86 | #define LOGGER_TRACE(format, ...) LOGGER_TRACE_(NULL, format, ##__VA_ARGS__) | ||
87 | #define LOGGER_DEBUG(format, ...) LOGGER_DEBUG_(NULL, format, ##__VA_ARGS__) | ||
88 | #define LOGGER_INFO(format, ...) LOGGER_INFO_(NULL, format, ##__VA_ARGS__) | ||
89 | #define LOGGER_WARNING(format, ...) LOGGER_WARNING_(NULL, format, ##__VA_ARGS__) | ||
90 | #define LOGGER_ERROR(format, ...) LOGGER_ERROR_(NULL, format, ##__VA_ARGS__) | ||
82 | 91 | ||
83 | 92 | ||
84 | #endif /* __TOXLOGGER */ | 93 | #endif /* TOXLOGGER_H */ |
diff --git a/toxcore/net_crypto.c b/toxcore/net_crypto.c index ea04d71c..bd5616a2 100644 --- a/toxcore/net_crypto.c +++ b/toxcore/net_crypto.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include "net_crypto.h" | 31 | #include "net_crypto.h" |
32 | #include "util.h" | 32 | #include "util.h" |
33 | #include "math.h" | 33 | #include "math.h" |
34 | #include "logger.h" | ||
34 | 35 | ||
35 | static uint8_t crypt_connection_id_not_valid(const Net_Crypto *c, int crypt_connection_id) | 36 | static uint8_t crypt_connection_id_not_valid(const Net_Crypto *c, int crypt_connection_id) |
36 | { | 37 | { |
@@ -182,7 +183,7 @@ static int handle_cookie_request(const Net_Crypto *c, uint8_t *request_plain, ui | |||
182 | 183 | ||
183 | /* Handle the cookie request packet (for raw UDP) | 184 | /* Handle the cookie request packet (for raw UDP) |
184 | */ | 185 | */ |
185 | static int udp_handle_cookie_request(void *object, IP_Port source, const uint8_t *packet, uint32_t length) | 186 | static int udp_handle_cookie_request(void *object, IP_Port source, const uint8_t *packet, uint16_t length) |
186 | { | 187 | { |
187 | Net_Crypto *c = object; | 188 | Net_Crypto *c = object; |
188 | uint8_t request_plain[COOKIE_REQUEST_PLAIN_LENGTH]; | 189 | uint8_t request_plain[COOKIE_REQUEST_PLAIN_LENGTH]; |
@@ -206,7 +207,7 @@ static int udp_handle_cookie_request(void *object, IP_Port source, const uint8_t | |||
206 | /* Handle the cookie request packet (for TCP) | 207 | /* Handle the cookie request packet (for TCP) |
207 | */ | 208 | */ |
208 | static int tcp_handle_cookie_request(const Net_Crypto *c, TCP_Client_Connection *TCP_con, uint8_t conn_id, | 209 | static int tcp_handle_cookie_request(const Net_Crypto *c, TCP_Client_Connection *TCP_con, uint8_t conn_id, |
209 | const uint8_t *packet, uint32_t length) | 210 | const uint8_t *packet, uint16_t length) |
210 | { | 211 | { |
211 | uint8_t request_plain[COOKIE_REQUEST_PLAIN_LENGTH]; | 212 | uint8_t request_plain[COOKIE_REQUEST_PLAIN_LENGTH]; |
212 | uint8_t shared_key[crypto_box_BEFORENMBYTES]; | 213 | uint8_t shared_key[crypto_box_BEFORENMBYTES]; |
@@ -229,7 +230,7 @@ static int tcp_handle_cookie_request(const Net_Crypto *c, TCP_Client_Connection | |||
229 | /* Handle the cookie request packet (for TCP oob packets) | 230 | /* Handle the cookie request packet (for TCP oob packets) |
230 | */ | 231 | */ |
231 | static int tcp_oob_handle_cookie_request(const Net_Crypto *c, TCP_Client_Connection *TCP_con, | 232 | static int tcp_oob_handle_cookie_request(const Net_Crypto *c, TCP_Client_Connection *TCP_con, |
232 | const uint8_t *dht_public_key, const uint8_t *packet, uint32_t length) | 233 | const uint8_t *dht_public_key, const uint8_t *packet, uint16_t length) |
233 | { | 234 | { |
234 | uint8_t request_plain[COOKIE_REQUEST_PLAIN_LENGTH]; | 235 | uint8_t request_plain[COOKIE_REQUEST_PLAIN_LENGTH]; |
235 | uint8_t shared_key[crypto_box_BEFORENMBYTES]; | 236 | uint8_t shared_key[crypto_box_BEFORENMBYTES]; |
@@ -260,7 +261,7 @@ static int tcp_oob_handle_cookie_request(const Net_Crypto *c, TCP_Client_Connect | |||
260 | * return -1 on failure. | 261 | * return -1 on failure. |
261 | * return COOKIE_LENGTH on success. | 262 | * return COOKIE_LENGTH on success. |
262 | */ | 263 | */ |
263 | static int handle_cookie_response(uint8_t *cookie, uint64_t *number, const uint8_t *packet, uint32_t length, | 264 | static int handle_cookie_response(uint8_t *cookie, uint64_t *number, const uint8_t *packet, uint16_t length, |
264 | const uint8_t *shared_key) | 265 | const uint8_t *shared_key) |
265 | { | 266 | { |
266 | if (length != COOKIE_RESPONSE_LENGTH) | 267 | if (length != COOKIE_RESPONSE_LENGTH) |
@@ -334,7 +335,7 @@ static int create_crypto_handshake(const Net_Crypto *c, uint8_t *packet, const u | |||
334 | * return 0 on success. | 335 | * return 0 on success. |
335 | */ | 336 | */ |
336 | static int handle_crypto_handshake(const Net_Crypto *c, uint8_t *nonce, uint8_t *session_pk, uint8_t *peer_real_pk, | 337 | static int handle_crypto_handshake(const Net_Crypto *c, uint8_t *nonce, uint8_t *session_pk, uint8_t *peer_real_pk, |
337 | uint8_t *dht_public_key, uint8_t *cookie, const uint8_t *packet, uint32_t length, const uint8_t *expected_real_pk) | 338 | uint8_t *dht_public_key, uint8_t *cookie, const uint8_t *packet, uint16_t length, const uint8_t *expected_real_pk) |
338 | { | 339 | { |
339 | if (length != HANDSHAKE_PACKET_LENGTH) | 340 | if (length != HANDSHAKE_PACKET_LENGTH) |
340 | return -1; | 341 | return -1; |
@@ -395,13 +396,17 @@ static int send_packet_to(Net_Crypto *c, int crypt_connection_id, const uint8_t | |||
395 | 396 | ||
396 | int direct_send_attempt = 0; | 397 | int direct_send_attempt = 0; |
397 | 398 | ||
399 | pthread_mutex_lock(&conn->mutex); | ||
400 | |||
398 | //TODO: on bad networks, direct connections might not last indefinitely. | 401 | //TODO: on bad networks, direct connections might not last indefinitely. |
399 | if (conn->ip_port.ip.family != 0) { | 402 | if (conn->ip_port.ip.family != 0) { |
400 | uint8_t direct_connected = 0; | 403 | uint8_t direct_connected = 0; |
401 | crypto_connection_status(c, crypt_connection_id, &direct_connected); | 404 | crypto_connection_status(c, crypt_connection_id, &direct_connected); |
402 | 405 | ||
403 | if (direct_connected && (uint32_t)sendpacket(c->dht->net, conn->ip_port, data, length) == length) | 406 | if (direct_connected && (uint32_t)sendpacket(c->dht->net, conn->ip_port, data, length) == length) { |
407 | pthread_mutex_unlock(&conn->mutex); | ||
404 | return 0; | 408 | return 0; |
409 | } | ||
405 | 410 | ||
406 | //TODO: a better way of sending packets directly to confirm the others ip. | 411 | //TODO: a better way of sending packets directly to confirm the others ip. |
407 | if (length < 96 || data[0] == NET_PACKET_COOKIE_REQUEST || data[0] == NET_PACKET_CRYPTO_HS) { | 412 | if (length < 96 || data[0] == NET_PACKET_COOKIE_REQUEST || data[0] == NET_PACKET_CRYPTO_HS) { |
@@ -411,40 +416,53 @@ static int send_packet_to(Net_Crypto *c, int crypt_connection_id, const uint8_t | |||
411 | 416 | ||
412 | } | 417 | } |
413 | 418 | ||
419 | pthread_mutex_unlock(&conn->mutex); | ||
420 | |||
414 | //TODO: detect and kill bad relays. | 421 | //TODO: detect and kill bad relays. |
415 | uint32_t i; | 422 | uint32_t i; |
416 | 423 | ||
417 | unsigned int r = crypt_connection_id; | 424 | unsigned int r; |
418 | 425 | ||
419 | for (i = 0; i < MAX_TCP_CONNECTIONS; ++i) { | 426 | if (!conn->last_relay_sentto) { |
420 | pthread_mutex_lock(&c->tcp_mutex); | 427 | r = rand(); |
428 | } else { | ||
429 | r = conn->last_relay_sentto - 1; | ||
430 | } | ||
421 | 431 | ||
422 | int ret = 0; | 432 | if (conn->num_tcp_online) { |
433 | for (i = 0; i < MAX_TCP_CONNECTIONS; ++i) { | ||
434 | pthread_mutex_lock(&c->tcp_mutex); | ||
423 | 435 | ||
424 | if (conn->status_tcp[(i + r) % MAX_TCP_CONNECTIONS] == STATUS_TCP_ONLINE) {/* friend is connected to this relay. */ | 436 | unsigned int tcp_index = (i + r) % MAX_TCP_CONNECTIONS; |
425 | ret = send_data(c->tcp_connections[(i + r) % MAX_TCP_CONNECTIONS], conn->con_number_tcp[(i + r) % MAX_TCP_CONNECTIONS], | 437 | int ret = 0; |
426 | data, length); | ||
427 | } | ||
428 | 438 | ||
429 | pthread_mutex_unlock(&c->tcp_mutex); | 439 | if (conn->status_tcp[tcp_index] == STATUS_TCP_ONLINE) {/* friend is connected to this relay. */ |
440 | ret = send_data(c->tcp_connections[tcp_index], conn->con_number_tcp[tcp_index], data, length); | ||
441 | } | ||
430 | 442 | ||
431 | if (ret == 1) { | 443 | pthread_mutex_unlock(&c->tcp_mutex); |
432 | return 0; | 444 | |
445 | if (ret == 1) { | ||
446 | conn->last_relay_sentto = tcp_index + 1; | ||
447 | return 0; | ||
448 | } | ||
433 | } | 449 | } |
434 | } | 450 | } |
435 | 451 | ||
436 | for (i = 0; i < MAX_TCP_CONNECTIONS; ++i) { | 452 | for (i = 0; i < MAX_TCP_CONNECTIONS; ++i) { |
437 | pthread_mutex_lock(&c->tcp_mutex); | 453 | pthread_mutex_lock(&c->tcp_mutex); |
438 | 454 | ||
455 | unsigned int tcp_index = (i + r) % MAX_TCP_CONNECTIONS; | ||
439 | int ret = 0; | 456 | int ret = 0; |
440 | 457 | ||
441 | if (conn->status_tcp[(i + r) % MAX_TCP_CONNECTIONS] == STATUS_TCP_INVISIBLE) { | 458 | if (conn->status_tcp[tcp_index] == STATUS_TCP_INVISIBLE) { |
442 | ret = send_oob_packet(c->tcp_connections[(i + r) % MAX_TCP_CONNECTIONS], conn->dht_public_key, data, length); | 459 | ret = send_oob_packet(c->tcp_connections[tcp_index], conn->dht_public_key, data, length); |
443 | } | 460 | } |
444 | 461 | ||
445 | pthread_mutex_unlock(&c->tcp_mutex); | 462 | pthread_mutex_unlock(&c->tcp_mutex); |
446 | 463 | ||
447 | if (ret == 1) { | 464 | if (ret == 1) { |
465 | conn->last_relay_sentto = tcp_index + 1; | ||
448 | return 0; | 466 | return 0; |
449 | } | 467 | } |
450 | } | 468 | } |
@@ -590,6 +608,23 @@ static int clear_buffer_until(Packets_Array *array, uint32_t number) | |||
590 | return 0; | 608 | return 0; |
591 | } | 609 | } |
592 | 610 | ||
611 | static int clear_buffer(Packets_Array *array) | ||
612 | { | ||
613 | uint32_t i; | ||
614 | |||
615 | for (i = array->buffer_start; i != array->buffer_end; ++i) { | ||
616 | uint32_t num = i % CRYPTO_PACKET_BUFFER_SIZE; | ||
617 | |||
618 | if (array->buffer[num]) { | ||
619 | free(array->buffer[num]); | ||
620 | array->buffer[num] = NULL; | ||
621 | } | ||
622 | } | ||
623 | |||
624 | array->buffer_start = i; | ||
625 | return 0; | ||
626 | } | ||
627 | |||
593 | /* Set array buffer end to number. | 628 | /* Set array buffer end to number. |
594 | * | 629 | * |
595 | * return -1 on failure. | 630 | * return -1 on failure. |
@@ -657,7 +692,7 @@ static int generate_request_packet(uint8_t *data, uint16_t length, const Packets | |||
657 | } | 692 | } |
658 | 693 | ||
659 | /* Handle a request data packet. | 694 | /* Handle a request data packet. |
660 | * Remove all the packets the other recieved from the array. | 695 | * Remove all the packets the other received from the array. |
661 | * | 696 | * |
662 | * return -1 on failure. | 697 | * return -1 on failure. |
663 | * return number of requested packets on success. | 698 | * return number of requested packets on success. |
@@ -746,9 +781,9 @@ static int send_data_packet(Net_Crypto *c, int crypt_connection_id, const uint8_ | |||
746 | } | 781 | } |
747 | 782 | ||
748 | increment_nonce(conn->sent_nonce); | 783 | increment_nonce(conn->sent_nonce); |
749 | int ret = send_packet_to(c, crypt_connection_id, packet, sizeof(packet)); | ||
750 | pthread_mutex_unlock(&conn->mutex); | 784 | pthread_mutex_unlock(&conn->mutex); |
751 | return ret; | 785 | |
786 | return send_packet_to(c, crypt_connection_id, packet, sizeof(packet)); | ||
752 | } | 787 | } |
753 | 788 | ||
754 | /* Creates and sends a data packet with buffer_start and num to the peer using the fastest route. | 789 | /* Creates and sends a data packet with buffer_start and num to the peer using the fastest route. |
@@ -757,7 +792,7 @@ static int send_data_packet(Net_Crypto *c, int crypt_connection_id, const uint8_ | |||
757 | * return 0 on success. | 792 | * return 0 on success. |
758 | */ | 793 | */ |
759 | static int send_data_packet_helper(Net_Crypto *c, int crypt_connection_id, uint32_t buffer_start, uint32_t num, | 794 | static int send_data_packet_helper(Net_Crypto *c, int crypt_connection_id, uint32_t buffer_start, uint32_t num, |
760 | const uint8_t *data, uint32_t length) | 795 | const uint8_t *data, uint16_t length) |
761 | { | 796 | { |
762 | if (length == 0 || length > MAX_CRYPTO_DATA_SIZE) | 797 | if (length == 0 || length > MAX_CRYPTO_DATA_SIZE) |
763 | return -1; | 798 | return -1; |
@@ -777,7 +812,8 @@ static int send_data_packet_helper(Net_Crypto *c, int crypt_connection_id, uint3 | |||
777 | /* return -1 if data could not be put in packet queue. | 812 | /* return -1 if data could not be put in packet queue. |
778 | * return positive packet number if data was put into the queue. | 813 | * return positive packet number if data was put into the queue. |
779 | */ | 814 | */ |
780 | static int64_t send_lossless_packet(Net_Crypto *c, int crypt_connection_id, const uint8_t *data, uint32_t length) | 815 | static int64_t send_lossless_packet(Net_Crypto *c, int crypt_connection_id, const uint8_t *data, uint16_t length, |
816 | uint8_t congestion_control) | ||
781 | { | 817 | { |
782 | if (length == 0 || length > MAX_CRYPTO_DATA_SIZE) | 818 | if (length == 0 || length > MAX_CRYPTO_DATA_SIZE) |
783 | return -1; | 819 | return -1; |
@@ -796,35 +832,51 @@ static int64_t send_lossless_packet(Net_Crypto *c, int crypt_connection_id, cons | |||
796 | uint32_t packet_num = conn->send_array.buffer_end - 1; | 832 | uint32_t packet_num = conn->send_array.buffer_end - 1; |
797 | int ret = get_data_pointer(&conn->send_array, &dt, packet_num); | 833 | int ret = get_data_pointer(&conn->send_array, &dt, packet_num); |
798 | 834 | ||
835 | uint8_t send_failed = 0; | ||
836 | |||
799 | if (ret == 1) { | 837 | if (ret == 1) { |
800 | if (!dt->time) { | 838 | if (!dt->time) { |
801 | if (send_data_packet_helper(c, crypt_connection_id, conn->recv_array.buffer_start, packet_num, dt->data, | 839 | if (send_data_packet_helper(c, crypt_connection_id, conn->recv_array.buffer_start, packet_num, dt->data, |
802 | dt->length) != 0) { | 840 | dt->length) != 0) { |
803 | return -1; | 841 | if (congestion_control) { |
842 | return -1; | ||
843 | } else { | ||
844 | send_failed = 1; | ||
845 | } | ||
846 | } else { | ||
847 | dt->time = temp_time; | ||
804 | } | 848 | } |
805 | |||
806 | dt->time = temp_time; | ||
807 | } | 849 | } |
808 | } | 850 | } |
851 | |||
852 | if (!send_failed) { | ||
853 | conn->maximum_speed_reached = 0; | ||
854 | } | ||
809 | } | 855 | } |
810 | 856 | ||
811 | Packet_Data dt; | 857 | Packet_Data dt; |
812 | dt.time = temp_time; | 858 | dt.time = 0; |
813 | dt.length = length; | 859 | dt.length = length; |
814 | memcpy(dt.data, data, length); | 860 | memcpy(dt.data, data, length); |
861 | pthread_mutex_lock(&conn->mutex); | ||
815 | int64_t packet_num = add_data_end_of_buffer(&conn->send_array, &dt); | 862 | int64_t packet_num = add_data_end_of_buffer(&conn->send_array, &dt); |
863 | pthread_mutex_unlock(&conn->mutex); | ||
816 | 864 | ||
817 | if (packet_num == -1) | 865 | if (packet_num == -1) |
818 | return -1; | 866 | return -1; |
819 | 867 | ||
820 | conn->maximum_speed_reached = 0; | 868 | if (!congestion_control && conn->maximum_speed_reached) { |
869 | return packet_num; | ||
870 | } | ||
821 | 871 | ||
822 | if (send_data_packet_helper(c, crypt_connection_id, conn->recv_array.buffer_start, packet_num, data, length) != 0) { | 872 | if (send_data_packet_helper(c, crypt_connection_id, conn->recv_array.buffer_start, packet_num, data, length) == 0) { |
823 | Packet_Data *dt1 = NULL; | 873 | Packet_Data *dt1 = NULL; |
824 | get_data_pointer(&conn->send_array, &dt1, packet_num); | 874 | |
825 | dt1->time = 0; | 875 | if (get_data_pointer(&conn->send_array, &dt1, packet_num) == 1) |
876 | dt1->time = temp_time; | ||
877 | } else { | ||
826 | conn->maximum_speed_reached = 1; | 878 | conn->maximum_speed_reached = 1; |
827 | fprintf(stderr, "send_data_packet failed\n"); | 879 | LOGGER_ERROR("send_data_packet failed\n"); |
828 | } | 880 | } |
829 | 881 | ||
830 | return packet_num; | 882 | return packet_num; |
@@ -1070,7 +1122,7 @@ static int send_kill_packet(Net_Crypto *c, int crypt_connection_id) | |||
1070 | &kill_packet, sizeof(kill_packet)); | 1122 | &kill_packet, sizeof(kill_packet)); |
1071 | } | 1123 | } |
1072 | 1124 | ||
1073 | /* Handle a recieved data packet. | 1125 | /* Handle a received data packet. |
1074 | * | 1126 | * |
1075 | * return -1 on failure. | 1127 | * return -1 on failure. |
1076 | * return 0 on success. | 1128 | * return 0 on success. |
@@ -1144,10 +1196,24 @@ static int handle_data_packet_helper(const Net_Crypto *c, int crypt_connection_i | |||
1144 | if (add_data_to_buffer(&conn->recv_array, num, &dt) != 0) | 1196 | if (add_data_to_buffer(&conn->recv_array, num, &dt) != 0) |
1145 | return -1; | 1197 | return -1; |
1146 | 1198 | ||
1147 | while (read_data_beg_buffer(&conn->recv_array, &dt) != -1) { | 1199 | |
1200 | while (1) { | ||
1201 | pthread_mutex_lock(&conn->mutex); | ||
1202 | int ret = read_data_beg_buffer(&conn->recv_array, &dt); | ||
1203 | pthread_mutex_unlock(&conn->mutex); | ||
1204 | |||
1205 | if (ret == -1) | ||
1206 | break; | ||
1207 | |||
1148 | if (conn->connection_data_callback) | 1208 | if (conn->connection_data_callback) |
1149 | conn->connection_data_callback(conn->connection_data_callback_object, conn->connection_data_callback_id, dt.data, | 1209 | conn->connection_data_callback(conn->connection_data_callback_object, conn->connection_data_callback_id, dt.data, |
1150 | dt.length); | 1210 | dt.length); |
1211 | |||
1212 | /* conn might get killed in callback. */ | ||
1213 | conn = get_crypto_connection(c, crypt_connection_id); | ||
1214 | |||
1215 | if (conn == 0) | ||
1216 | return -1; | ||
1151 | } | 1217 | } |
1152 | 1218 | ||
1153 | /* Packet counter. */ | 1219 | /* Packet counter. */ |
@@ -1155,11 +1221,12 @@ static int handle_data_packet_helper(const Net_Crypto *c, int crypt_connection_i | |||
1155 | } else if (real_data[0] >= PACKET_ID_LOSSY_RANGE_START && | 1221 | } else if (real_data[0] >= PACKET_ID_LOSSY_RANGE_START && |
1156 | real_data[0] < (PACKET_ID_LOSSY_RANGE_START + PACKET_ID_LOSSY_RANGE_SIZE)) { | 1222 | real_data[0] < (PACKET_ID_LOSSY_RANGE_START + PACKET_ID_LOSSY_RANGE_SIZE)) { |
1157 | 1223 | ||
1224 | set_buffer_end(&conn->recv_array, num); | ||
1225 | |||
1158 | if (conn->connection_lossy_data_callback) | 1226 | if (conn->connection_lossy_data_callback) |
1159 | conn->connection_lossy_data_callback(conn->connection_lossy_data_callback_object, | 1227 | conn->connection_lossy_data_callback(conn->connection_lossy_data_callback_object, |
1160 | conn->connection_lossy_data_callback_id, real_data, real_length); | 1228 | conn->connection_lossy_data_callback_id, real_data, real_length); |
1161 | 1229 | ||
1162 | set_buffer_end(&conn->recv_array, num); | ||
1163 | } else { | 1230 | } else { |
1164 | return -1; | 1231 | return -1; |
1165 | } | 1232 | } |
@@ -1167,7 +1234,7 @@ static int handle_data_packet_helper(const Net_Crypto *c, int crypt_connection_i | |||
1167 | return 0; | 1234 | return 0; |
1168 | } | 1235 | } |
1169 | 1236 | ||
1170 | /* Handle a packet that was recieved for the connection. | 1237 | /* Handle a packet that was received for the connection. |
1171 | * | 1238 | * |
1172 | * return -1 on failure. | 1239 | * return -1 on failure. |
1173 | * return 0 on success. | 1240 | * return 0 on success. |
@@ -1223,7 +1290,11 @@ static int handle_packet_connection(Net_Crypto *c, int crypt_connection_id, cons | |||
1223 | 1290 | ||
1224 | conn->status = CRYPTO_CONN_NOT_CONFIRMED; | 1291 | conn->status = CRYPTO_CONN_NOT_CONFIRMED; |
1225 | /* Status needs to be CRYPTO_CONN_NOT_CONFIRMED for this to work. */ | 1292 | /* Status needs to be CRYPTO_CONN_NOT_CONFIRMED for this to work. */ |
1226 | set_connection_dht_public_key(c, crypt_connection_id, dht_public_key, current_time_monotonic()); | 1293 | set_connection_dht_public_key(c, crypt_connection_id, dht_public_key); |
1294 | |||
1295 | if (conn->dht_pk_callback) | ||
1296 | conn->dht_pk_callback(conn->dht_pk_callback_object, conn->dht_pk_callback_number, dht_public_key); | ||
1297 | |||
1227 | } else { | 1298 | } else { |
1228 | return -1; | 1299 | return -1; |
1229 | } | 1300 | } |
@@ -1299,10 +1370,14 @@ static int create_crypto_connection(Net_Crypto *c) | |||
1299 | int id = -1; | 1370 | int id = -1; |
1300 | 1371 | ||
1301 | if (realloc_cryptoconnection(c, c->crypto_connections_length + 1) == 0) { | 1372 | if (realloc_cryptoconnection(c, c->crypto_connections_length + 1) == 0) { |
1302 | memset(&(c->crypto_connections[c->crypto_connections_length]), 0, sizeof(Crypto_Connection)); | ||
1303 | id = c->crypto_connections_length; | 1373 | id = c->crypto_connections_length; |
1304 | pthread_mutex_init(&c->crypto_connections[id].mutex, NULL); | ||
1305 | ++c->crypto_connections_length; | 1374 | ++c->crypto_connections_length; |
1375 | memset(&(c->crypto_connections[id]), 0, sizeof(Crypto_Connection)); | ||
1376 | |||
1377 | if (pthread_mutex_init(&c->crypto_connections[id].mutex, NULL) != 0) { | ||
1378 | pthread_mutex_unlock(&c->connections_mutex); | ||
1379 | return -1; | ||
1380 | } | ||
1306 | } | 1381 | } |
1307 | 1382 | ||
1308 | pthread_mutex_unlock(&c->connections_mutex); | 1383 | pthread_mutex_unlock(&c->connections_mutex); |
@@ -1320,12 +1395,18 @@ static int wipe_crypto_connection(Net_Crypto *c, int crypt_connection_id) | |||
1320 | return -1; | 1395 | return -1; |
1321 | 1396 | ||
1322 | uint32_t i; | 1397 | uint32_t i; |
1323 | pthread_mutex_destroy(&c->crypto_connections[crypt_connection_id].mutex); | 1398 | |
1399 | /* Keep mutex, only destroy it when connection is realloced out. */ | ||
1400 | pthread_mutex_t mutex = c->crypto_connections[crypt_connection_id].mutex; | ||
1324 | memset(&(c->crypto_connections[crypt_connection_id]), 0 , sizeof(Crypto_Connection)); | 1401 | memset(&(c->crypto_connections[crypt_connection_id]), 0 , sizeof(Crypto_Connection)); |
1402 | c->crypto_connections[crypt_connection_id].mutex = mutex; | ||
1325 | 1403 | ||
1326 | for (i = c->crypto_connections_length; i != 0; --i) { | 1404 | for (i = c->crypto_connections_length; i != 0; --i) { |
1327 | if (c->crypto_connections[i - 1].status != CRYPTO_CONN_NO_CONNECTION) | 1405 | if (c->crypto_connections[i - 1].status == CRYPTO_CONN_NO_CONNECTION) { |
1406 | pthread_mutex_destroy(&c->crypto_connections[i - 1].mutex); | ||
1407 | } else { | ||
1328 | break; | 1408 | break; |
1409 | } | ||
1329 | } | 1410 | } |
1330 | 1411 | ||
1331 | if (c->crypto_connections_length != i) { | 1412 | if (c->crypto_connections_length != i) { |
@@ -1373,7 +1454,7 @@ static int getcryptconnection_id_dht_pubkey(const Net_Crypto *c, const uint8_t * | |||
1373 | } | 1454 | } |
1374 | 1455 | ||
1375 | /* Add a source to the crypto connection. | 1456 | /* Add a source to the crypto connection. |
1376 | * This is to be used only when we have recieved a packet from that source. | 1457 | * This is to be used only when we have received a packet from that source. |
1377 | * | 1458 | * |
1378 | * return -1 on failure. | 1459 | * return -1 on failure. |
1379 | * return positive number on success. | 1460 | * return positive number on success. |
@@ -1456,7 +1537,11 @@ static int handle_new_connection_handshake(Net_Crypto *c, IP_Port source, const | |||
1456 | if (create_send_handshake(c, crypt_connection_id, n_c.cookie, n_c.dht_public_key) == 0) { | 1537 | if (create_send_handshake(c, crypt_connection_id, n_c.cookie, n_c.dht_public_key) == 0) { |
1457 | conn->status = CRYPTO_CONN_NOT_CONFIRMED; | 1538 | conn->status = CRYPTO_CONN_NOT_CONFIRMED; |
1458 | /* Status needs to be CRYPTO_CONN_NOT_CONFIRMED for this to work. */ | 1539 | /* Status needs to be CRYPTO_CONN_NOT_CONFIRMED for this to work. */ |
1459 | set_connection_dht_public_key(c, crypt_connection_id, n_c.dht_public_key, current_time_monotonic()); | 1540 | set_connection_dht_public_key(c, crypt_connection_id, n_c.dht_public_key); |
1541 | |||
1542 | if (conn->dht_pk_callback) | ||
1543 | conn->dht_pk_callback(conn->dht_pk_callback_object, conn->dht_pk_callback_number, n_c.dht_public_key); | ||
1544 | |||
1460 | ret = 0; | 1545 | ret = 0; |
1461 | } | 1546 | } |
1462 | } | 1547 | } |
@@ -1505,7 +1590,7 @@ int accept_crypto_connection(Net_Crypto *c, New_Connection *n_c) | |||
1505 | 1590 | ||
1506 | conn->status = CRYPTO_CONN_NOT_CONFIRMED; | 1591 | conn->status = CRYPTO_CONN_NOT_CONFIRMED; |
1507 | /* Status needs to be CRYPTO_CONN_NOT_CONFIRMED for this to work. */ | 1592 | /* Status needs to be CRYPTO_CONN_NOT_CONFIRMED for this to work. */ |
1508 | set_connection_dht_public_key(c, crypt_connection_id, n_c->dht_public_key, current_time_monotonic()); | 1593 | set_connection_dht_public_key(c, crypt_connection_id, n_c->dht_public_key); |
1509 | conn->packet_send_rate = CRYPTO_PACKET_MIN_RATE; | 1594 | conn->packet_send_rate = CRYPTO_PACKET_MIN_RATE; |
1510 | conn->packets_left = CRYPTO_MIN_QUEUE_LENGTH; | 1595 | conn->packets_left = CRYPTO_MIN_QUEUE_LENGTH; |
1511 | crypto_connection_add_source(c, crypt_connection_id, n_c->source); | 1596 | crypto_connection_add_source(c, crypt_connection_id, n_c->source); |
@@ -1544,6 +1629,25 @@ int new_crypto_connection(Net_Crypto *c, const uint8_t *real_public_key) | |||
1544 | return crypt_connection_id; | 1629 | return crypt_connection_id; |
1545 | } | 1630 | } |
1546 | 1631 | ||
1632 | /* Set the status for the TCP connection for conn in location to status. | ||
1633 | */ | ||
1634 | static void set_conn_tcp_status(Crypto_Connection *conn, unsigned int location, unsigned int status) | ||
1635 | { | ||
1636 | if (conn->status_tcp[location] == status) { | ||
1637 | return; | ||
1638 | } | ||
1639 | |||
1640 | if (conn->status_tcp[location] == STATUS_TCP_ONLINE) { | ||
1641 | --conn->num_tcp_online; | ||
1642 | } | ||
1643 | |||
1644 | if (status == STATUS_TCP_ONLINE) { | ||
1645 | ++conn->num_tcp_online; | ||
1646 | } | ||
1647 | |||
1648 | conn->status_tcp[location] = status; | ||
1649 | } | ||
1650 | |||
1547 | /* Disconnect peer from all associated TCP connections. | 1651 | /* Disconnect peer from all associated TCP connections. |
1548 | * | 1652 | * |
1549 | * return -1 on failure. | 1653 | * return -1 on failure. |
@@ -1562,7 +1666,7 @@ static int disconnect_peer_tcp(Net_Crypto *c, int crypt_connection_id) | |||
1562 | if (conn->status_tcp[i] != STATUS_TCP_NULL) { | 1666 | if (conn->status_tcp[i] != STATUS_TCP_NULL) { |
1563 | pthread_mutex_lock(&c->tcp_mutex); | 1667 | pthread_mutex_lock(&c->tcp_mutex); |
1564 | send_disconnect_request(c->tcp_connections[i], conn->con_number_tcp[i]); | 1668 | send_disconnect_request(c->tcp_connections[i], conn->con_number_tcp[i]); |
1565 | conn->status_tcp[i] = STATUS_TCP_NULL; | 1669 | set_conn_tcp_status(conn, i, STATUS_TCP_NULL); |
1566 | conn->con_number_tcp[i] = 0; | 1670 | conn->con_number_tcp[i] = 0; |
1567 | pthread_mutex_unlock(&c->tcp_mutex); | 1671 | pthread_mutex_unlock(&c->tcp_mutex); |
1568 | } | 1672 | } |
@@ -1601,9 +1705,9 @@ static int connect_peer_tcp(Net_Crypto *c, int crypt_connection_id) | |||
1601 | /* Copy friends DHT public key into dht_key. | 1705 | /* Copy friends DHT public key into dht_key. |
1602 | * | 1706 | * |
1603 | * return 0 on failure (no key copied). | 1707 | * return 0 on failure (no key copied). |
1604 | * return timestamp on success (key copied). | 1708 | * return 1 on success (key copied). |
1605 | */ | 1709 | */ |
1606 | uint64_t get_connection_dht_key(const Net_Crypto *c, int crypt_connection_id, uint8_t *dht_public_key) | 1710 | unsigned int get_connection_dht_key(const Net_Crypto *c, int crypt_connection_id, uint8_t *dht_public_key) |
1607 | { | 1711 | { |
1608 | Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); | 1712 | Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); |
1609 | 1713 | ||
@@ -1614,28 +1718,22 @@ uint64_t get_connection_dht_key(const Net_Crypto *c, int crypt_connection_id, ui | |||
1614 | return 0; | 1718 | return 0; |
1615 | 1719 | ||
1616 | memcpy(dht_public_key, conn->dht_public_key, crypto_box_PUBLICKEYBYTES); | 1720 | memcpy(dht_public_key, conn->dht_public_key, crypto_box_PUBLICKEYBYTES); |
1617 | return conn->dht_public_key_timestamp; | 1721 | return 1; |
1618 | } | 1722 | } |
1619 | 1723 | ||
1620 | 1724 | ||
1621 | /* Set the DHT public key of the crypto connection. | 1725 | /* Set the DHT public key of the crypto connection. |
1622 | * timestamp is the time (current_time_monotonic()) at which the key was last confirmed belonging to | ||
1623 | * the other peer. | ||
1624 | * | 1726 | * |
1625 | * return -1 on failure. | 1727 | * return -1 on failure. |
1626 | * return 0 on success. | 1728 | * return 0 on success. |
1627 | */ | 1729 | */ |
1628 | int set_connection_dht_public_key(Net_Crypto *c, int crypt_connection_id, const uint8_t *dht_public_key, | 1730 | int set_connection_dht_public_key(Net_Crypto *c, int crypt_connection_id, const uint8_t *dht_public_key) |
1629 | uint64_t timestamp) | ||
1630 | { | 1731 | { |
1631 | Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); | 1732 | Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); |
1632 | 1733 | ||
1633 | if (conn == 0) | 1734 | if (conn == 0) |
1634 | return -1; | 1735 | return -1; |
1635 | 1736 | ||
1636 | if (timestamp <= conn->dht_public_key_timestamp) | ||
1637 | return -1; | ||
1638 | |||
1639 | if (conn->dht_public_key_set == 1 && memcmp(conn->dht_public_key, dht_public_key, crypto_box_PUBLICKEYBYTES) == 0) | 1737 | if (conn->dht_public_key_set == 1 && memcmp(conn->dht_public_key, dht_public_key, crypto_box_PUBLICKEYBYTES) == 0) |
1640 | return -1; | 1738 | return -1; |
1641 | 1739 | ||
@@ -1645,7 +1743,6 @@ int set_connection_dht_public_key(Net_Crypto *c, int crypt_connection_id, const | |||
1645 | 1743 | ||
1646 | memcpy(conn->dht_public_key, dht_public_key, crypto_box_PUBLICKEYBYTES); | 1744 | memcpy(conn->dht_public_key, dht_public_key, crypto_box_PUBLICKEYBYTES); |
1647 | conn->dht_public_key_set = 1; | 1745 | conn->dht_public_key_set = 1; |
1648 | conn->dht_public_key_timestamp = timestamp; | ||
1649 | 1746 | ||
1650 | if (conn->status == CRYPTO_CONN_COOKIE_REQUESTING) { | 1747 | if (conn->status == CRYPTO_CONN_COOKIE_REQUESTING) { |
1651 | conn->cookie_request_number = random_64b(); | 1748 | conn->cookie_request_number = random_64b(); |
@@ -1675,7 +1772,15 @@ int set_direct_ip_port(Net_Crypto *c, int crypt_connection_id, IP_Port ip_port) | |||
1675 | if (conn == 0) | 1772 | if (conn == 0) |
1676 | return -1; | 1773 | return -1; |
1677 | 1774 | ||
1775 | if (ip_port.ip.family != AF_INET && ip_port.ip.family != AF_INET6) | ||
1776 | return -1; | ||
1777 | |||
1678 | if (!ipport_equal(&ip_port, &conn->ip_port)) { | 1778 | if (!ipport_equal(&ip_port, &conn->ip_port)) { |
1779 | if ((UDP_DIRECT_TIMEOUT + conn->direct_lastrecv_time) > current_time_monotonic()) { | ||
1780 | if (LAN_ip(ip_port.ip) == 0 && LAN_ip(conn->ip_port.ip) == 0 && conn->ip_port.port == ip_port.port) | ||
1781 | return -1; | ||
1782 | } | ||
1783 | |||
1679 | if (bs_list_add(&c->ip_port_list, &ip_port, crypt_connection_id)) { | 1784 | if (bs_list_add(&c->ip_port_list, &ip_port, crypt_connection_id)) { |
1680 | bs_list_remove(&c->ip_port_list, &conn->ip_port, crypt_connection_id); | 1785 | bs_list_remove(&c->ip_port_list, &conn->ip_port, crypt_connection_id); |
1681 | conn->ip_port = ip_port; | 1786 | conn->ip_port = ip_port; |
@@ -1716,13 +1821,13 @@ static int tcp_response_callback(void *object, uint8_t connection_id, const uint | |||
1716 | uint32_t i; | 1821 | uint32_t i; |
1717 | 1822 | ||
1718 | for (i = 0; i < conn->num_tcp_relays; ++i) { | 1823 | for (i = 0; i < conn->num_tcp_relays; ++i) { |
1719 | if (memcmp(TCP_con->public_key, conn->tcp_relays[i].client_id, crypto_box_PUBLICKEYBYTES) == 0) { | 1824 | if (memcmp(TCP_con->public_key, conn->tcp_relays[i].public_key, crypto_box_PUBLICKEYBYTES) == 0) { |
1720 | conn->status_tcp[location] = STATUS_TCP_INVISIBLE; | 1825 | set_conn_tcp_status(conn, location, STATUS_TCP_INVISIBLE); |
1721 | return 0; | 1826 | return 0; |
1722 | } | 1827 | } |
1723 | } | 1828 | } |
1724 | 1829 | ||
1725 | conn->status_tcp[location] = STATUS_TCP_OFFLINE; | 1830 | set_conn_tcp_status(conn, location, STATUS_TCP_OFFLINE); |
1726 | return 0; | 1831 | return 0; |
1727 | } | 1832 | } |
1728 | 1833 | ||
@@ -1745,9 +1850,9 @@ static int tcp_status_callback(void *object, uint32_t number, uint8_t connection | |||
1745 | return -1; | 1850 | return -1; |
1746 | 1851 | ||
1747 | if (status == 1) { | 1852 | if (status == 1) { |
1748 | conn->status_tcp[location] = STATUS_TCP_OFFLINE; | 1853 | set_conn_tcp_status(conn, location, STATUS_TCP_OFFLINE); |
1749 | } else if (status == 2) { | 1854 | } else if (status == 2) { |
1750 | conn->status_tcp[location] = STATUS_TCP_ONLINE; | 1855 | set_conn_tcp_status(conn, location, STATUS_TCP_ONLINE); |
1751 | } | 1856 | } |
1752 | 1857 | ||
1753 | conn->con_number_tcp[location] = connection_id; | 1858 | conn->con_number_tcp[location] = connection_id; |
@@ -1772,7 +1877,11 @@ static int tcp_data_callback(void *object, uint32_t number, uint8_t connection_i | |||
1772 | if (conn == 0) | 1877 | if (conn == 0) |
1773 | return -1; | 1878 | return -1; |
1774 | 1879 | ||
1775 | if (handle_packet_connection(c, number, data, length) != 0) | 1880 | pthread_mutex_unlock(&c->tcp_mutex); |
1881 | int ret = handle_packet_connection(c, number, data, length); | ||
1882 | pthread_mutex_lock(&c->tcp_mutex); | ||
1883 | |||
1884 | if (ret != 0) | ||
1776 | return -1; | 1885 | return -1; |
1777 | 1886 | ||
1778 | //TODO detect and kill bad TCP connections. | 1887 | //TODO detect and kill bad TCP connections. |
@@ -1796,11 +1905,12 @@ static int tcp_oob_callback(void *object, const uint8_t *public_key, const uint8 | |||
1796 | 1905 | ||
1797 | if (crypt_connection_id == -1) { | 1906 | if (crypt_connection_id == -1) { |
1798 | IP_Port source; | 1907 | IP_Port source; |
1908 | source.port = 0; | ||
1799 | source.ip.family = TCP_FAMILY; | 1909 | source.ip.family = TCP_FAMILY; |
1800 | source.ip.ip6.uint32[0] = location; | 1910 | source.ip.ip6.uint32[0] = location; |
1801 | 1911 | ||
1802 | if (data[0] != NET_PACKET_CRYPTO_HS) { | 1912 | if (data[0] != NET_PACKET_CRYPTO_HS) { |
1803 | fprintf(stderr, "tcp snhappen %u\n", data[0]); | 1913 | LOGGER_DEBUG("tcp snhappen %u\n", data[0]); |
1804 | return -1; | 1914 | return -1; |
1805 | } | 1915 | } |
1806 | 1916 | ||
@@ -1810,7 +1920,11 @@ static int tcp_oob_callback(void *object, const uint8_t *public_key, const uint8 | |||
1810 | return 0; | 1920 | return 0; |
1811 | } | 1921 | } |
1812 | 1922 | ||
1813 | if (handle_packet_connection(c, crypt_connection_id, data, length) != 0) | 1923 | pthread_mutex_unlock(&c->tcp_mutex); |
1924 | int ret = handle_packet_connection(c, crypt_connection_id, data, length); | ||
1925 | pthread_mutex_lock(&c->tcp_mutex); | ||
1926 | |||
1927 | if (ret != 0) | ||
1814 | return -1; | 1928 | return -1; |
1815 | 1929 | ||
1816 | return 0; | 1930 | return 0; |
@@ -1886,7 +2000,7 @@ int add_tcp_relay_peer(Net_Crypto *c, int crypt_connection_id, IP_Port ip_port, | |||
1886 | uint32_t i; | 2000 | uint32_t i; |
1887 | 2001 | ||
1888 | for (i = 0; i < conn->num_tcp_relays; ++i) { | 2002 | for (i = 0; i < conn->num_tcp_relays; ++i) { |
1889 | if (memcmp(conn->tcp_relays[i].client_id, public_key, crypto_box_PUBLICKEYBYTES) == 0) { | 2003 | if (memcmp(conn->tcp_relays[i].public_key, public_key, crypto_box_PUBLICKEYBYTES) == 0) { |
1890 | conn->tcp_relays[i].ip_port = ip_port; | 2004 | conn->tcp_relays[i].ip_port = ip_port; |
1891 | return 0; | 2005 | return 0; |
1892 | } | 2006 | } |
@@ -1895,10 +2009,10 @@ int add_tcp_relay_peer(Net_Crypto *c, int crypt_connection_id, IP_Port ip_port, | |||
1895 | if (conn->num_tcp_relays == MAX_TCP_RELAYS_PEER) { | 2009 | if (conn->num_tcp_relays == MAX_TCP_RELAYS_PEER) { |
1896 | uint16_t index = rand() % MAX_TCP_RELAYS_PEER; | 2010 | uint16_t index = rand() % MAX_TCP_RELAYS_PEER; |
1897 | conn->tcp_relays[index].ip_port = ip_port; | 2011 | conn->tcp_relays[index].ip_port = ip_port; |
1898 | memcpy(conn->tcp_relays[index].client_id, public_key, crypto_box_PUBLICKEYBYTES); | 2012 | memcpy(conn->tcp_relays[index].public_key, public_key, crypto_box_PUBLICKEYBYTES); |
1899 | } else { | 2013 | } else { |
1900 | conn->tcp_relays[conn->num_tcp_relays].ip_port = ip_port; | 2014 | conn->tcp_relays[conn->num_tcp_relays].ip_port = ip_port; |
1901 | memcpy(conn->tcp_relays[conn->num_tcp_relays].client_id, public_key, crypto_box_PUBLICKEYBYTES); | 2015 | memcpy(conn->tcp_relays[conn->num_tcp_relays].public_key, public_key, crypto_box_PUBLICKEYBYTES); |
1902 | ++conn->num_tcp_relays; | 2016 | ++conn->num_tcp_relays; |
1903 | } | 2017 | } |
1904 | 2018 | ||
@@ -1908,7 +2022,7 @@ int add_tcp_relay_peer(Net_Crypto *c, int crypt_connection_id, IP_Port ip_port, | |||
1908 | 2022 | ||
1909 | if (memcmp(c->tcp_connections[i]->public_key, public_key, crypto_box_PUBLICKEYBYTES) == 0) { | 2023 | if (memcmp(c->tcp_connections[i]->public_key, public_key, crypto_box_PUBLICKEYBYTES) == 0) { |
1910 | if (conn->status_tcp[i] == STATUS_TCP_OFFLINE) | 2024 | if (conn->status_tcp[i] == STATUS_TCP_OFFLINE) |
1911 | conn->status_tcp[i] = STATUS_TCP_INVISIBLE; | 2025 | set_conn_tcp_status(conn, i, STATUS_TCP_INVISIBLE); |
1912 | } | 2026 | } |
1913 | } | 2027 | } |
1914 | 2028 | ||
@@ -1938,13 +2052,8 @@ int add_tcp_relay(Net_Crypto *c, IP_Port ip_port, const uint8_t *public_key) | |||
1938 | 2052 | ||
1939 | for (i = 0; i < MAX_TCP_CONNECTIONS; ++i) { | 2053 | for (i = 0; i < MAX_TCP_CONNECTIONS; ++i) { |
1940 | if (c->tcp_connections_new[i] == NULL) { | 2054 | if (c->tcp_connections_new[i] == NULL) { |
1941 | if (c->proxy_set) { | 2055 | c->tcp_connections_new[i] = new_TCP_connection(ip_port, public_key, c->dht->self_public_key, c->dht->self_secret_key, |
1942 | c->tcp_connections_new[i] = new_TCP_connection(ip_port, public_key, c->dht->self_public_key, c->dht->self_secret_key, | 2056 | &c->proxy_info); |
1943 | &c->proxy_info); | ||
1944 | } else { | ||
1945 | c->tcp_connections_new[i] = new_TCP_connection(ip_port, public_key, c->dht->self_public_key, c->dht->self_secret_key, | ||
1946 | 0); | ||
1947 | } | ||
1948 | 2057 | ||
1949 | return 0; | 2058 | return 0; |
1950 | } | 2059 | } |
@@ -1953,30 +2062,51 @@ int add_tcp_relay(Net_Crypto *c, IP_Port ip_port, const uint8_t *public_key) | |||
1953 | return -1; | 2062 | return -1; |
1954 | } | 2063 | } |
1955 | 2064 | ||
1956 | /* Send an onion packet via a random connected TCP relay. | 2065 | /* Return a random TCP connection number for use in send_tcp_onion_request. |
1957 | * | 2066 | * |
1958 | * return 0 on success. | 2067 | * TODO: This number is just the index of an array that the elements can |
2068 | * change without warning. | ||
2069 | * | ||
2070 | * return TCP connection number on success. | ||
1959 | * return -1 on failure. | 2071 | * return -1 on failure. |
1960 | */ | 2072 | */ |
1961 | int send_tcp_onion_request(Net_Crypto *c, const uint8_t *data, uint16_t length) | 2073 | int get_random_tcp_con_number(Net_Crypto *c) |
1962 | { | 2074 | { |
1963 | unsigned int i, r = rand(); | 2075 | unsigned int i, r = rand(); |
1964 | 2076 | ||
1965 | for (i = 0; i < MAX_TCP_CONNECTIONS; ++i) { | 2077 | for (i = 0; i < MAX_TCP_CONNECTIONS; ++i) { |
1966 | if (c->tcp_connections[(i + r) % MAX_TCP_CONNECTIONS]) { | 2078 | if (c->tcp_connections[(i + r) % MAX_TCP_CONNECTIONS]) { |
1967 | pthread_mutex_lock(&c->tcp_mutex); | 2079 | return (i + r) % MAX_TCP_CONNECTIONS; |
1968 | int ret = send_onion_request(c->tcp_connections[(i + r) % MAX_TCP_CONNECTIONS], data, length); | ||
1969 | pthread_mutex_unlock(&c->tcp_mutex); | ||
1970 | |||
1971 | if (ret == 1) | ||
1972 | return 0; | ||
1973 | } | 2080 | } |
1974 | } | 2081 | } |
1975 | 2082 | ||
1976 | return -1; | 2083 | return -1; |
1977 | } | 2084 | } |
1978 | 2085 | ||
1979 | /* Set the function to be called when an onion response packet is recieved by one of the TCP connections. | 2086 | /* Send an onion packet via the TCP relay corresponding to TCP_conn_number. |
2087 | * | ||
2088 | * return 0 on success. | ||
2089 | * return -1 on failure. | ||
2090 | */ | ||
2091 | int send_tcp_onion_request(Net_Crypto *c, unsigned int TCP_conn_number, const uint8_t *data, uint16_t length) | ||
2092 | { | ||
2093 | if (TCP_conn_number > MAX_TCP_CONNECTIONS) { | ||
2094 | return -1; | ||
2095 | } | ||
2096 | |||
2097 | if (c->tcp_connections[TCP_conn_number]) { | ||
2098 | pthread_mutex_lock(&c->tcp_mutex); | ||
2099 | int ret = send_onion_request(c->tcp_connections[TCP_conn_number], data, length); | ||
2100 | pthread_mutex_unlock(&c->tcp_mutex); | ||
2101 | |||
2102 | if (ret == 1) | ||
2103 | return 0; | ||
2104 | } | ||
2105 | |||
2106 | return -1; | ||
2107 | } | ||
2108 | |||
2109 | /* Set the function to be called when an onion response packet is received by one of the TCP connections. | ||
1980 | */ | 2110 | */ |
1981 | void tcp_onion_response_handler(Net_Crypto *c, int (*tcp_onion_callback)(void *object, const uint8_t *data, | 2111 | void tcp_onion_response_handler(Net_Crypto *c, int (*tcp_onion_callback)(void *object, const uint8_t *data, |
1982 | uint16_t length), void *object) | 2112 | uint16_t length), void *object) |
@@ -2001,7 +2131,7 @@ unsigned int copy_connected_tcp_relays(const Net_Crypto *c, Node_format *tcp_rel | |||
2001 | 2131 | ||
2002 | for (i = 0; i < MAX_TCP_CONNECTIONS; ++i) { | 2132 | for (i = 0; i < MAX_TCP_CONNECTIONS; ++i) { |
2003 | if (c->tcp_connections[i] != NULL) { | 2133 | if (c->tcp_connections[i] != NULL) { |
2004 | memcpy(tcp_relays[copied].client_id, c->tcp_connections[i]->public_key, crypto_box_PUBLICKEYBYTES); | 2134 | memcpy(tcp_relays[copied].public_key, c->tcp_connections[i]->public_key, crypto_box_PUBLICKEYBYTES); |
2005 | tcp_relays[copied].ip_port = c->tcp_connections[i]->ip_port; | 2135 | tcp_relays[copied].ip_port = c->tcp_connections[i]->ip_port; |
2006 | 2136 | ||
2007 | if (tcp_relays[copied].ip_port.ip.family == AF_INET) { | 2137 | if (tcp_relays[copied].ip_port.ip.family == AF_INET) { |
@@ -2076,7 +2206,9 @@ static void do_tcp(Net_Crypto *c) | |||
2076 | if (c->tcp_connections_new[i] == NULL) | 2206 | if (c->tcp_connections_new[i] == NULL) |
2077 | continue; | 2207 | continue; |
2078 | 2208 | ||
2209 | pthread_mutex_lock(&c->tcp_mutex); | ||
2079 | do_TCP_connection(c->tcp_connections_new[i]); | 2210 | do_TCP_connection(c->tcp_connections_new[i]); |
2211 | pthread_mutex_unlock(&c->tcp_mutex); | ||
2080 | 2212 | ||
2081 | if (c->tcp_connections_new[i]->status == TCP_CLIENT_CONFIRMED) { | 2213 | if (c->tcp_connections_new[i]->status == TCP_CLIENT_CONFIRMED) { |
2082 | pthread_mutex_lock(&c->tcp_mutex); | 2214 | pthread_mutex_lock(&c->tcp_mutex); |
@@ -2110,7 +2242,7 @@ static void clear_disconnected_tcp_peer(Crypto_Connection *conn, uint32_t number | |||
2110 | if (number >= MAX_TCP_CONNECTIONS) | 2242 | if (number >= MAX_TCP_CONNECTIONS) |
2111 | return; | 2243 | return; |
2112 | 2244 | ||
2113 | conn->status_tcp[number] = STATUS_TCP_NULL; | 2245 | set_conn_tcp_status(conn, number, STATUS_TCP_NULL); |
2114 | conn->con_number_tcp[number] = 0; | 2246 | conn->con_number_tcp[number] = 0; |
2115 | } | 2247 | } |
2116 | 2248 | ||
@@ -2226,6 +2358,29 @@ int connection_lossy_data_handler(Net_Crypto *c, int crypt_connection_id, | |||
2226 | return 0; | 2358 | return 0; |
2227 | } | 2359 | } |
2228 | 2360 | ||
2361 | |||
2362 | /* Set the function for this friend that will be callbacked with object and number | ||
2363 | * when that friend gives us his DHT temporary public key. | ||
2364 | * | ||
2365 | * object and number will be passed as argument to this function. | ||
2366 | * | ||
2367 | * return -1 on failure. | ||
2368 | * return 0 on success. | ||
2369 | */ | ||
2370 | int nc_dht_pk_callback(Net_Crypto *c, int crypt_connection_id, void (*function)(void *data, int32_t number, | ||
2371 | const uint8_t *dht_public_key), void *object, uint32_t number) | ||
2372 | { | ||
2373 | Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); | ||
2374 | |||
2375 | if (conn == 0) | ||
2376 | return -1; | ||
2377 | |||
2378 | conn->dht_pk_callback = function; | ||
2379 | conn->dht_pk_callback_object = object; | ||
2380 | conn->dht_pk_callback_number = number; | ||
2381 | return 0; | ||
2382 | } | ||
2383 | |||
2229 | /* Get the crypto connection id from the ip_port. | 2384 | /* Get the crypto connection id from the ip_port. |
2230 | * | 2385 | * |
2231 | * return -1 on failure. | 2386 | * return -1 on failure. |
@@ -2246,7 +2401,7 @@ static int crypto_id_ip_port(const Net_Crypto *c, IP_Port ip_port) | |||
2246 | * Crypto data packets. | 2401 | * Crypto data packets. |
2247 | * | 2402 | * |
2248 | */ | 2403 | */ |
2249 | static int udp_handle_packet(void *object, IP_Port source, const uint8_t *packet, uint32_t length) | 2404 | static int udp_handle_packet(void *object, IP_Port source, const uint8_t *packet, uint16_t length) |
2250 | { | 2405 | { |
2251 | if (length <= CRYPTO_MIN_PACKET_SIZE || length > MAX_CRYPTO_PACKET_SIZE) | 2406 | if (length <= CRYPTO_MIN_PACKET_SIZE || length > MAX_CRYPTO_PACKET_SIZE) |
2252 | return 1; | 2407 | return 1; |
@@ -2272,13 +2427,15 @@ static int udp_handle_packet(void *object, IP_Port source, const uint8_t *packet | |||
2272 | if (conn == 0) | 2427 | if (conn == 0) |
2273 | return -1; | 2428 | return -1; |
2274 | 2429 | ||
2430 | pthread_mutex_lock(&conn->mutex); | ||
2275 | conn->direct_lastrecv_time = current_time_monotonic(); | 2431 | conn->direct_lastrecv_time = current_time_monotonic(); |
2432 | pthread_mutex_unlock(&conn->mutex); | ||
2276 | return 0; | 2433 | return 0; |
2277 | } | 2434 | } |
2278 | 2435 | ||
2279 | /* The dT for the average packet recieving rate calculations. | 2436 | /* The dT for the average packet receiving rate calculations. |
2280 | Also used as the */ | 2437 | Also used as the */ |
2281 | #define PACKET_COUNTER_AVERAGE_INTERVAL 100 | 2438 | #define PACKET_COUNTER_AVERAGE_INTERVAL 50 |
2282 | 2439 | ||
2283 | /* Ratio of recv queue size / recv packet rate (in seconds) times | 2440 | /* Ratio of recv queue size / recv packet rate (in seconds) times |
2284 | * the number of ms between request packets to send at that ratio | 2441 | * the number of ms between request packets to send at that ratio |
@@ -2334,7 +2491,7 @@ static void send_crypto_packets(Net_Crypto *c) | |||
2334 | conn->packet_counter_set = temp_time; | 2491 | conn->packet_counter_set = temp_time; |
2335 | 2492 | ||
2336 | uint32_t packets_sent = conn->packets_sent; | 2493 | uint32_t packets_sent = conn->packets_sent; |
2337 | conn->packets_sent = conn->packets_resent = 0; | 2494 | conn->packets_sent = 0; |
2338 | 2495 | ||
2339 | /* conjestion control | 2496 | /* conjestion control |
2340 | calculate a new value of conn->packet_send_rate based on some data | 2497 | calculate a new value of conn->packet_send_rate based on some data |
@@ -2361,7 +2518,7 @@ static void send_crypto_packets(Net_Crypto *c) | |||
2361 | double min_speed = 1000.0 * (((double)(total_sent)) / ((double)(CONGESTION_QUEUE_ARRAY_SIZE) * | 2518 | double min_speed = 1000.0 * (((double)(total_sent)) / ((double)(CONGESTION_QUEUE_ARRAY_SIZE) * |
2362 | PACKET_COUNTER_AVERAGE_INTERVAL)); | 2519 | PACKET_COUNTER_AVERAGE_INTERVAL)); |
2363 | 2520 | ||
2364 | conn->packet_send_rate = min_speed * 1.3; | 2521 | conn->packet_send_rate = min_speed * 1.2; |
2365 | 2522 | ||
2366 | if (conn->packet_send_rate < CRYPTO_PACKET_MIN_RATE) { | 2523 | if (conn->packet_send_rate < CRYPTO_PACKET_MIN_RATE) { |
2367 | conn->packet_send_rate = CRYPTO_PACKET_MIN_RATE; | 2524 | conn->packet_send_rate = CRYPTO_PACKET_MIN_RATE; |
@@ -2375,8 +2532,8 @@ static void send_crypto_packets(Net_Crypto *c) | |||
2375 | } else if (((1000.0 / conn->packet_send_rate) + conn->last_packets_left_set) < temp_time) { | 2532 | } else if (((1000.0 / conn->packet_send_rate) + conn->last_packets_left_set) < temp_time) { |
2376 | uint32_t num_packets = conn->packet_send_rate * ((double)(temp_time - conn->last_packets_left_set) / 1000.0) + 0.5; | 2533 | uint32_t num_packets = conn->packet_send_rate * ((double)(temp_time - conn->last_packets_left_set) / 1000.0) + 0.5; |
2377 | 2534 | ||
2378 | if (conn->packets_left > num_packets * 2 + CRYPTO_MIN_QUEUE_LENGTH) { | 2535 | if (conn->packets_left > num_packets * 4 + CRYPTO_MIN_QUEUE_LENGTH) { |
2379 | conn->packets_left = num_packets * 2 + CRYPTO_MIN_QUEUE_LENGTH; | 2536 | conn->packets_left = num_packets * 4 + CRYPTO_MIN_QUEUE_LENGTH; |
2380 | } else { | 2537 | } else { |
2381 | conn->packets_left += num_packets; | 2538 | conn->packets_left += num_packets; |
2382 | } | 2539 | } |
@@ -2388,7 +2545,6 @@ static void send_crypto_packets(Net_Crypto *c) | |||
2388 | 2545 | ||
2389 | if (ret != -1) { | 2546 | if (ret != -1) { |
2390 | conn->packets_left -= ret; | 2547 | conn->packets_left -= ret; |
2391 | conn->packets_resent += ret; | ||
2392 | } | 2548 | } |
2393 | 2549 | ||
2394 | if (conn->packet_send_rate > CRYPTO_PACKET_MIN_RATE * 1.5) { | 2550 | if (conn->packet_send_rate > CRYPTO_PACKET_MIN_RATE * 1.5) { |
@@ -2438,9 +2594,10 @@ uint32_t crypto_num_free_sendqueue_slots(const Net_Crypto *c, int crypt_connecti | |||
2438 | * return -1 if data could not be put in packet queue. | 2594 | * return -1 if data could not be put in packet queue. |
2439 | * return positive packet number if data was put into the queue. | 2595 | * return positive packet number if data was put into the queue. |
2440 | * | 2596 | * |
2441 | * The first byte of data must be in the CRYPTO_RESERVED_PACKETS to PACKET_ID_LOSSY_RANGE_START range. | 2597 | * congestion_control: should congestion control apply to this packet? |
2442 | */ | 2598 | */ |
2443 | int64_t write_cryptpacket(Net_Crypto *c, int crypt_connection_id, const uint8_t *data, uint32_t length) | 2599 | int64_t write_cryptpacket(Net_Crypto *c, int crypt_connection_id, const uint8_t *data, uint16_t length, |
2600 | uint8_t congestion_control) | ||
2444 | { | 2601 | { |
2445 | if (length == 0) | 2602 | if (length == 0) |
2446 | return -1; | 2603 | return -1; |
@@ -2459,16 +2616,19 @@ int64_t write_cryptpacket(Net_Crypto *c, int crypt_connection_id, const uint8_t | |||
2459 | if (conn->status != CRYPTO_CONN_ESTABLISHED) | 2616 | if (conn->status != CRYPTO_CONN_ESTABLISHED) |
2460 | return -1; | 2617 | return -1; |
2461 | 2618 | ||
2462 | if (conn->packets_left == 0) | 2619 | if (congestion_control && conn->packets_left == 0) |
2463 | return -1; | 2620 | return -1; |
2464 | 2621 | ||
2465 | int64_t ret = send_lossless_packet(c, crypt_connection_id, data, length); | 2622 | int64_t ret = send_lossless_packet(c, crypt_connection_id, data, length, congestion_control); |
2466 | 2623 | ||
2467 | if (ret == -1) | 2624 | if (ret == -1) |
2468 | return -1; | 2625 | return -1; |
2469 | 2626 | ||
2470 | --conn->packets_left; | 2627 | if (congestion_control) { |
2471 | conn->packets_sent++; | 2628 | --conn->packets_left; |
2629 | conn->packets_sent++; | ||
2630 | } | ||
2631 | |||
2472 | return ret; | 2632 | return ret; |
2473 | } | 2633 | } |
2474 | 2634 | ||
@@ -2501,7 +2661,7 @@ int cryptpacket_received(Net_Crypto *c, int crypt_connection_id, uint32_t packet | |||
2501 | * | 2661 | * |
2502 | * Sends a lossy cryptopacket. (first byte must in the PACKET_ID_LOSSY_RANGE_*) | 2662 | * Sends a lossy cryptopacket. (first byte must in the PACKET_ID_LOSSY_RANGE_*) |
2503 | */ | 2663 | */ |
2504 | int send_lossy_cryptpacket(Net_Crypto *c, int crypt_connection_id, const uint8_t *data, uint32_t length) | 2664 | int send_lossy_cryptpacket(Net_Crypto *c, int crypt_connection_id, const uint8_t *data, uint16_t length) |
2505 | { | 2665 | { |
2506 | if (length == 0 || length > MAX_CRYPTO_DATA_SIZE) | 2666 | if (length == 0 || length > MAX_CRYPTO_DATA_SIZE) |
2507 | return -1; | 2667 | return -1; |
@@ -2521,8 +2681,11 @@ int send_lossy_cryptpacket(Net_Crypto *c, int crypt_connection_id, const uint8_t | |||
2521 | int ret = -1; | 2681 | int ret = -1; |
2522 | 2682 | ||
2523 | if (conn) { | 2683 | if (conn) { |
2524 | ret = send_data_packet_helper(c, crypt_connection_id, conn->recv_array.buffer_start, conn->send_array.buffer_end, data, | 2684 | pthread_mutex_lock(&conn->mutex); |
2525 | length); | 2685 | uint32_t buffer_start = conn->recv_array.buffer_start; |
2686 | uint32_t buffer_end = conn->send_array.buffer_end; | ||
2687 | pthread_mutex_unlock(&conn->mutex); | ||
2688 | ret = send_data_packet_helper(c, crypt_connection_id, buffer_start, buffer_end, data, length); | ||
2526 | } | 2689 | } |
2527 | 2690 | ||
2528 | pthread_mutex_lock(&c->connections_mutex); | 2691 | pthread_mutex_lock(&c->connections_mutex); |
@@ -2559,6 +2722,9 @@ int crypto_kill(Net_Crypto *c, int crypt_connection_id) | |||
2559 | 2722 | ||
2560 | disconnect_peer_tcp(c, crypt_connection_id); | 2723 | disconnect_peer_tcp(c, crypt_connection_id); |
2561 | bs_list_remove(&c->ip_port_list, &conn->ip_port, crypt_connection_id); | 2724 | bs_list_remove(&c->ip_port_list, &conn->ip_port, crypt_connection_id); |
2725 | clear_temp_packet(c, crypt_connection_id); | ||
2726 | clear_buffer(&conn->send_array); | ||
2727 | clear_buffer(&conn->recv_array); | ||
2562 | ret = wipe_crypto_connection(c, crypt_connection_id); | 2728 | ret = wipe_crypto_connection(c, crypt_connection_id); |
2563 | } | 2729 | } |
2564 | 2730 | ||
@@ -2624,6 +2790,12 @@ Net_Crypto *new_net_crypto(DHT *dht, TCP_Proxy_Info *proxy_info) | |||
2624 | if (temp == NULL) | 2790 | if (temp == NULL) |
2625 | return NULL; | 2791 | return NULL; |
2626 | 2792 | ||
2793 | if (create_recursive_mutex(&temp->tcp_mutex) != 0 || | ||
2794 | pthread_mutex_init(&temp->connections_mutex, NULL) != 0) { | ||
2795 | free(temp); | ||
2796 | return NULL; | ||
2797 | } | ||
2798 | |||
2627 | temp->dht = dht; | 2799 | temp->dht = dht; |
2628 | 2800 | ||
2629 | new_keys(temp); | 2801 | new_keys(temp); |
@@ -2638,16 +2810,7 @@ Net_Crypto *new_net_crypto(DHT *dht, TCP_Proxy_Info *proxy_info) | |||
2638 | 2810 | ||
2639 | bs_list_init(&temp->ip_port_list, sizeof(IP_Port), 8); | 2811 | bs_list_init(&temp->ip_port_list, sizeof(IP_Port), 8); |
2640 | 2812 | ||
2641 | pthread_mutexattr_t attr; | 2813 | temp->proxy_info = *proxy_info; |
2642 | pthread_mutexattr_init(&attr); | ||
2643 | pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); | ||
2644 | pthread_mutex_init(&temp->tcp_mutex, &attr); | ||
2645 | pthread_mutex_init(&temp->connections_mutex, NULL); | ||
2646 | |||
2647 | if (proxy_info) { | ||
2648 | temp->proxy_info = *proxy_info; | ||
2649 | temp->proxy_set = 1; | ||
2650 | } | ||
2651 | 2814 | ||
2652 | return temp; | 2815 | return temp; |
2653 | } | 2816 | } |
diff --git a/toxcore/net_crypto.h b/toxcore/net_crypto.h index d750080f..7e59475e 100644 --- a/toxcore/net_crypto.h +++ b/toxcore/net_crypto.h | |||
@@ -25,47 +25,52 @@ | |||
25 | #define NET_CRYPTO_H | 25 | #define NET_CRYPTO_H |
26 | 26 | ||
27 | #include "DHT.h" | 27 | #include "DHT.h" |
28 | #include "LAN_discovery.h" | ||
28 | #include "TCP_client.h" | 29 | #include "TCP_client.h" |
29 | #include <pthread.h> | 30 | #include <pthread.h> |
30 | 31 | ||
31 | #define CRYPTO_CONN_NO_CONNECTION 0 | 32 | #define CRYPTO_CONN_NO_CONNECTION 0 |
32 | #define CRYPTO_CONN_COOKIE_REQUESTING 1 //send cookie request packets | 33 | #define CRYPTO_CONN_COOKIE_REQUESTING 1 //send cookie request packets |
33 | #define CRYPTO_CONN_HANDSHAKE_SENT 2 //send handshake packets | 34 | #define CRYPTO_CONN_HANDSHAKE_SENT 2 //send handshake packets |
34 | #define CRYPTO_CONN_NOT_CONFIRMED 3 //send handshake packets | 35 | #define CRYPTO_CONN_NOT_CONFIRMED 3 //send handshake packets, we have received one from the other |
35 | #define CRYPTO_CONN_ESTABLISHED 4 | 36 | #define CRYPTO_CONN_ESTABLISHED 4 |
36 | #define CRYPTO_CONN_TIMED_OUT 5 | 37 | #define CRYPTO_CONN_TIMED_OUT 5 |
37 | 38 | ||
39 | /* Maximum size of receiving and sending packet buffers. */ | ||
38 | #define CRYPTO_PACKET_BUFFER_SIZE 16384 /* Must be a power of 2 */ | 40 | #define CRYPTO_PACKET_BUFFER_SIZE 16384 /* Must be a power of 2 */ |
39 | 41 | ||
40 | /* Minimum packet rate per second. */ | 42 | /* Minimum packet rate per second. */ |
41 | #define CRYPTO_PACKET_MIN_RATE 16.0 | 43 | #define CRYPTO_PACKET_MIN_RATE 8.0 |
42 | 44 | ||
43 | /* Minimum packet queue max length. */ | 45 | /* Minimum packet queue max length. */ |
44 | #define CRYPTO_MIN_QUEUE_LENGTH 16 | 46 | #define CRYPTO_MIN_QUEUE_LENGTH 64 |
45 | 47 | ||
48 | /* Maximum total size of packets that net_crypto sends. */ | ||
46 | #define MAX_CRYPTO_PACKET_SIZE 1400 | 49 | #define MAX_CRYPTO_PACKET_SIZE 1400 |
47 | 50 | ||
48 | #define CRYPTO_DATA_PACKET_MIN_SIZE (1 + sizeof(uint16_t) + (sizeof(uint32_t) + sizeof(uint32_t)) + crypto_box_MACBYTES) | 51 | #define CRYPTO_DATA_PACKET_MIN_SIZE (1 + sizeof(uint16_t) + (sizeof(uint32_t) + sizeof(uint32_t)) + crypto_box_MACBYTES) |
49 | 52 | ||
50 | /* Max size of data in packets TODO*/ | 53 | /* Max size of data in packets */ |
51 | #define MAX_CRYPTO_DATA_SIZE (MAX_CRYPTO_PACKET_SIZE - CRYPTO_DATA_PACKET_MIN_SIZE) | 54 | #define MAX_CRYPTO_DATA_SIZE (MAX_CRYPTO_PACKET_SIZE - CRYPTO_DATA_PACKET_MIN_SIZE) |
52 | 55 | ||
53 | /* Interval in ms between sending cookie request/handshake packets. */ | 56 | /* Interval in ms between sending cookie request/handshake packets. */ |
54 | #define CRYPTO_SEND_PACKET_INTERVAL 500 | 57 | #define CRYPTO_SEND_PACKET_INTERVAL 1000 |
58 | |||
55 | /* The maximum number of times we try to send the cookie request and handshake | 59 | /* The maximum number of times we try to send the cookie request and handshake |
56 | before giving up. */ | 60 | before giving up. */ |
57 | #define MAX_NUM_SENDPACKET_TRIES 8 | 61 | #define MAX_NUM_SENDPACKET_TRIES 8 |
58 | 62 | ||
59 | /* The timeout of no recieved UDP packets before the direct UDP connection is considered dead. */ | 63 | /* The timeout of no received UDP packets before the direct UDP connection is considered dead. */ |
60 | #define UDP_DIRECT_TIMEOUT (MAX_NUM_SENDPACKET_TRIES * CRYPTO_SEND_PACKET_INTERVAL * 2) | 64 | #define UDP_DIRECT_TIMEOUT (MAX_NUM_SENDPACKET_TRIES * CRYPTO_SEND_PACKET_INTERVAL) |
61 | 65 | ||
62 | #define PACKET_ID_PADDING 0 | 66 | #define PACKET_ID_PADDING 0 /* Denotes padding */ |
63 | #define PACKET_ID_REQUEST 1 | 67 | #define PACKET_ID_REQUEST 1 /* Used to request unreceived packets */ |
64 | #define PACKET_ID_KILL 2 | 68 | #define PACKET_ID_KILL 2 /* Used to kill connection */ |
65 | 69 | ||
70 | /* Packet ids 0 to CRYPTO_RESERVED_PACKETS - 1 are reserved for use by net_crypto. */ | ||
66 | #define CRYPTO_RESERVED_PACKETS 16 | 71 | #define CRYPTO_RESERVED_PACKETS 16 |
67 | 72 | ||
68 | #define MAX_TCP_CONNECTIONS 32 | 73 | #define MAX_TCP_CONNECTIONS 64 |
69 | #define MAX_TCP_RELAYS_PEER 4 | 74 | #define MAX_TCP_RELAYS_PEER 4 |
70 | 75 | ||
71 | #define STATUS_TCP_NULL 0 | 76 | #define STATUS_TCP_NULL 0 |
@@ -79,8 +84,9 @@ | |||
79 | 84 | ||
80 | #define CRYPTO_MAX_PADDING 8 /* All packets will be padded a number of bytes based on this number. */ | 85 | #define CRYPTO_MAX_PADDING 8 /* All packets will be padded a number of bytes based on this number. */ |
81 | 86 | ||
82 | 87 | /* Base current transfer speed on last CONGESTION_QUEUE_ARRAY_SIZE number of points taken | |
83 | #define CONGESTION_QUEUE_ARRAY_SIZE 8 | 88 | at the dT defined in net_crypto.c */ |
89 | #define CONGESTION_QUEUE_ARRAY_SIZE 24 | ||
84 | 90 | ||
85 | typedef struct { | 91 | typedef struct { |
86 | uint64_t time; | 92 | uint64_t time; |
@@ -111,7 +117,6 @@ typedef struct { | |||
111 | uint64_t cookie_request_number; /* number used in the cookie request packets for this connection */ | 117 | uint64_t cookie_request_number; /* number used in the cookie request packets for this connection */ |
112 | uint8_t dht_public_key[crypto_box_PUBLICKEYBYTES]; /* The dht public key of the peer */ | 118 | uint8_t dht_public_key[crypto_box_PUBLICKEYBYTES]; /* The dht public key of the peer */ |
113 | uint8_t dht_public_key_set; /* True if the dht public key is set, false if it isn't. */ | 119 | uint8_t dht_public_key_set; /* True if the dht public key is set, false if it isn't. */ |
114 | uint64_t dht_public_key_timestamp; /* Timestamp of the last time we confirmed the key was correct. */ | ||
115 | 120 | ||
116 | uint8_t *temp_packet; /* Where the cookie request/handshake packet is stored while it is being sent. */ | 121 | uint8_t *temp_packet; /* Where the cookie request/handshake packet is stored while it is being sent. */ |
117 | uint16_t temp_packet_length; | 122 | uint16_t temp_packet_length; |
@@ -148,12 +153,14 @@ typedef struct { | |||
148 | 153 | ||
149 | uint32_t last_sendqueue_size[CONGESTION_QUEUE_ARRAY_SIZE], last_sendqueue_counter; | 154 | uint32_t last_sendqueue_size[CONGESTION_QUEUE_ARRAY_SIZE], last_sendqueue_counter; |
150 | long signed int last_num_packets_sent[CONGESTION_QUEUE_ARRAY_SIZE]; | 155 | long signed int last_num_packets_sent[CONGESTION_QUEUE_ARRAY_SIZE]; |
151 | uint32_t packets_sent, packets_resent; | 156 | uint32_t packets_sent; |
152 | 157 | ||
153 | uint8_t killed; /* set to 1 to kill the connection. */ | 158 | uint8_t killed; /* set to 1 to kill the connection. */ |
154 | 159 | ||
155 | uint8_t status_tcp[MAX_TCP_CONNECTIONS]; /* set to one of STATUS_TCP_* */ | 160 | uint8_t status_tcp[MAX_TCP_CONNECTIONS]; /* set to one of STATUS_TCP_* */ |
156 | uint8_t con_number_tcp[MAX_TCP_CONNECTIONS]; | 161 | uint8_t con_number_tcp[MAX_TCP_CONNECTIONS]; |
162 | unsigned int last_relay_sentto; | ||
163 | unsigned int num_tcp_online; | ||
157 | 164 | ||
158 | Node_format tcp_relays[MAX_TCP_RELAYS_PEER]; | 165 | Node_format tcp_relays[MAX_TCP_RELAYS_PEER]; |
159 | uint16_t num_tcp_relays; | 166 | uint16_t num_tcp_relays; |
@@ -161,6 +168,10 @@ typedef struct { | |||
161 | uint8_t maximum_speed_reached; | 168 | uint8_t maximum_speed_reached; |
162 | 169 | ||
163 | pthread_mutex_t mutex; | 170 | pthread_mutex_t mutex; |
171 | |||
172 | void (*dht_pk_callback)(void *data, int32_t number, const uint8_t *dht_public_key); | ||
173 | void *dht_pk_callback_object; | ||
174 | uint32_t dht_pk_callback_number; | ||
164 | } Crypto_Connection; | 175 | } Crypto_Connection; |
165 | 176 | ||
166 | typedef struct { | 177 | typedef struct { |
@@ -204,7 +215,6 @@ typedef struct { | |||
204 | int (*tcp_onion_callback)(void *object, const uint8_t *data, uint16_t length); | 215 | int (*tcp_onion_callback)(void *object, const uint8_t *data, uint16_t length); |
205 | void *tcp_onion_callback_object; | 216 | void *tcp_onion_callback_object; |
206 | 217 | ||
207 | uint8_t proxy_set; | ||
208 | TCP_Proxy_Info proxy_info; | 218 | TCP_Proxy_Info proxy_info; |
209 | } Net_Crypto; | 219 | } Net_Crypto; |
210 | 220 | ||
@@ -236,19 +246,16 @@ int new_crypto_connection(Net_Crypto *c, const uint8_t *real_public_key); | |||
236 | /* Copy friends DHT public key into dht_key. | 246 | /* Copy friends DHT public key into dht_key. |
237 | * | 247 | * |
238 | * return 0 on failure (no key copied). | 248 | * return 0 on failure (no key copied). |
239 | * return timestamp on success (key copied). | 249 | * return 1 on success (key copied). |
240 | */ | 250 | */ |
241 | uint64_t get_connection_dht_key(const Net_Crypto *c, int crypt_connection_id, uint8_t *dht_public_key); | 251 | unsigned int get_connection_dht_key(const Net_Crypto *c, int crypt_connection_id, uint8_t *dht_public_key); |
242 | 252 | ||
243 | /* Set the DHT public key of the crypto connection. | 253 | /* Set the DHT public key of the crypto connection. |
244 | * timestamp is the time (current_time_monotonic()) at which the key was last confirmed belonging to | ||
245 | * the other peer. | ||
246 | * | 254 | * |
247 | * return -1 on failure. | 255 | * return -1 on failure. |
248 | * return 0 on success. | 256 | * return 0 on success. |
249 | */ | 257 | */ |
250 | int set_connection_dht_public_key(Net_Crypto *c, int crypt_connection_id, const uint8_t *dht_public_key, | 258 | int set_connection_dht_public_key(Net_Crypto *c, int crypt_connection_id, const uint8_t *dht_public_key); |
251 | uint64_t timestamp); | ||
252 | 259 | ||
253 | /* Set the direct ip of the crypto connection. | 260 | /* Set the direct ip of the crypto connection. |
254 | * | 261 | * |
@@ -294,6 +301,17 @@ int connection_lossy_data_handler(Net_Crypto *c, int crypt_connection_id, | |||
294 | int (*connection_lossy_data_callback)(void *object, int id, const uint8_t *data, uint16_t length), void *object, | 301 | int (*connection_lossy_data_callback)(void *object, int id, const uint8_t *data, uint16_t length), void *object, |
295 | int id); | 302 | int id); |
296 | 303 | ||
304 | /* Set the function for this friend that will be callbacked with object and number | ||
305 | * when that friend gives us his DHT temporary public key. | ||
306 | * | ||
307 | * object and number will be passed as argument to this function. | ||
308 | * | ||
309 | * return -1 on failure. | ||
310 | * return 0 on success. | ||
311 | */ | ||
312 | int nc_dht_pk_callback(Net_Crypto *c, int crypt_connection_id, void (*function)(void *data, int32_t number, | ||
313 | const uint8_t *dht_public_key), void *object, uint32_t number); | ||
314 | |||
297 | /* returns the number of packet slots left in the sendbuffer. | 315 | /* returns the number of packet slots left in the sendbuffer. |
298 | * return 0 if failure. | 316 | * return 0 if failure. |
299 | */ | 317 | */ |
@@ -305,8 +323,11 @@ uint32_t crypto_num_free_sendqueue_slots(const Net_Crypto *c, int crypt_connecti | |||
305 | * return positive packet number if data was put into the queue. | 323 | * return positive packet number if data was put into the queue. |
306 | * | 324 | * |
307 | * The first byte of data must be in the CRYPTO_RESERVED_PACKETS to PACKET_ID_LOSSY_RANGE_START range. | 325 | * The first byte of data must be in the CRYPTO_RESERVED_PACKETS to PACKET_ID_LOSSY_RANGE_START range. |
326 | * | ||
327 | * congestion_control: should congestion control apply to this packet? | ||
308 | */ | 328 | */ |
309 | int64_t write_cryptpacket(Net_Crypto *c, int crypt_connection_id, const uint8_t *data, uint32_t length); | 329 | int64_t write_cryptpacket(Net_Crypto *c, int crypt_connection_id, const uint8_t *data, uint16_t length, |
330 | uint8_t congestion_control); | ||
310 | 331 | ||
311 | /* Check if packet_number was received by the other side. | 332 | /* Check if packet_number was received by the other side. |
312 | * | 333 | * |
@@ -322,7 +343,7 @@ int cryptpacket_received(Net_Crypto *c, int crypt_connection_id, uint32_t packet | |||
322 | * | 343 | * |
323 | * Sends a lossy cryptopacket. (first byte must in the PACKET_ID_LOSSY_RANGE_*) | 344 | * Sends a lossy cryptopacket. (first byte must in the PACKET_ID_LOSSY_RANGE_*) |
324 | */ | 345 | */ |
325 | int send_lossy_cryptpacket(Net_Crypto *c, int crypt_connection_id, const uint8_t *data, uint32_t length); | 346 | int send_lossy_cryptpacket(Net_Crypto *c, int crypt_connection_id, const uint8_t *data, uint16_t length); |
326 | 347 | ||
327 | /* Add a tcp relay, associating it to a crypt_connection_id. | 348 | /* Add a tcp relay, associating it to a crypt_connection_id. |
328 | * | 349 | * |
@@ -338,17 +359,24 @@ int add_tcp_relay_peer(Net_Crypto *c, int crypt_connection_id, IP_Port ip_port, | |||
338 | */ | 359 | */ |
339 | int add_tcp_relay(Net_Crypto *c, IP_Port ip_port, const uint8_t *public_key); | 360 | int add_tcp_relay(Net_Crypto *c, IP_Port ip_port, const uint8_t *public_key); |
340 | 361 | ||
341 | /* Set the function to be called when an onion response packet is recieved by one of the TCP connections. | 362 | /* Set the function to be called when an onion response packet is received by one of the TCP connections. |
342 | */ | 363 | */ |
343 | void tcp_onion_response_handler(Net_Crypto *c, int (*tcp_onion_callback)(void *object, const uint8_t *data, | 364 | void tcp_onion_response_handler(Net_Crypto *c, int (*tcp_onion_callback)(void *object, const uint8_t *data, |
344 | uint16_t length), void *object); | 365 | uint16_t length), void *object); |
345 | 366 | ||
346 | /* Send an onion packet via a random connected TCP relay. | 367 | /* Return a random TCP connection number for use in send_tcp_onion_request. |
368 | * | ||
369 | * return TCP connection number on success. | ||
370 | * return -1 on failure. | ||
371 | */ | ||
372 | int get_random_tcp_con_number(Net_Crypto *c); | ||
373 | |||
374 | /* Send an onion packet via the TCP relay corresponding to TCP_conn_number. | ||
347 | * | 375 | * |
348 | * return 0 on success. | 376 | * return 0 on success. |
349 | * return -1 on failure. | 377 | * return -1 on failure. |
350 | */ | 378 | */ |
351 | int send_tcp_onion_request(Net_Crypto *c, const uint8_t *data, uint16_t length); | 379 | int send_tcp_onion_request(Net_Crypto *c, unsigned int TCP_conn_number, const uint8_t *data, uint16_t length); |
352 | 380 | ||
353 | /* Copy a maximum of num TCP relays we are connected to to tcp_relays. | 381 | /* Copy a maximum of num TCP relays we are connected to to tcp_relays. |
354 | * NOTE that the family of the copied ip ports will be set to TCP_INET or TCP_INET6. | 382 | * NOTE that the family of the copied ip ports will be set to TCP_INET or TCP_INET6. |
diff --git a/toxcore/network.c b/toxcore/network.c index 43030a08..deccbb63 100644 --- a/toxcore/network.c +++ b/toxcore/network.c | |||
@@ -264,15 +264,15 @@ uint64_t current_time_monotonic(void) | |||
264 | #define loglogdata(__message__, __buffer__, __buflen__, __ip_port__, __res__) \ | 264 | #define loglogdata(__message__, __buffer__, __buflen__, __ip_port__, __res__) \ |
265 | (__ip_port__) .ip; \ | 265 | (__ip_port__) .ip; \ |
266 | if (__res__ < 0) /* Windows doesn't necessarily know %zu */ \ | 266 | if (__res__ < 0) /* Windows doesn't necessarily know %zu */ \ |
267 | LOGGER_INFO("[%2u] %s %3hu%c %s:%hu (%u: %s) | %04x%04x", \ | 267 | LOGGER_TRACE("[%2u] %s %3hu%c %s:%hu (%u: %s) | %04x%04x", \ |
268 | __buffer__[0], __message__, (__buflen__ < 999 ? (uint16_t)__buflen__ : 999), 'E', \ | 268 | __buffer__[0], __message__, (__buflen__ < 999 ? (uint16_t)__buflen__ : 999), 'E', \ |
269 | ip_ntoa(&((__ip_port__).ip)), ntohs((__ip_port__).port), errno, strerror(errno), data_0(__buflen__, __buffer__), data_1(__buflen__, __buffer__)); \ | 269 | ip_ntoa(&((__ip_port__).ip)), ntohs((__ip_port__).port), errno, strerror(errno), data_0(__buflen__, __buffer__), data_1(__buflen__, __buffer__)); \ |
270 | else if ((__res__ > 0) && ((size_t)__res__ <= __buflen__)) \ | 270 | else if ((__res__ > 0) && ((size_t)__res__ <= __buflen__)) \ |
271 | LOGGER_INFO("[%2u] %s %3zu%c %s:%hu (%u: %s) | %04x%04x", \ | 271 | LOGGER_TRACE("[%2u] %s %3zu%c %s:%hu (%u: %s) | %04x%04x", \ |
272 | __buffer__[0], __message__, (__res__ < 999 ? (size_t)__res__ : 999), ((size_t)__res__ < __buflen__ ? '<' : '='), \ | 272 | __buffer__[0], __message__, (__res__ < 999 ? (size_t)__res__ : 999), ((size_t)__res__ < __buflen__ ? '<' : '='), \ |
273 | ip_ntoa(&((__ip_port__).ip)), ntohs((__ip_port__).port), 0, "OK", data_0(__buflen__, __buffer__), data_1(__buflen__, __buffer__)); \ | 273 | ip_ntoa(&((__ip_port__).ip)), ntohs((__ip_port__).port), 0, "OK", data_0(__buflen__, __buffer__), data_1(__buflen__, __buffer__)); \ |
274 | else /* empty or overwrite */ \ | 274 | else /* empty or overwrite */ \ |
275 | LOGGER_INFO("[%2u] %s %zu%c%zu %s:%hu (%u: %s) | %04x%04x", \ | 275 | LOGGER_TRACE("[%2u] %s %zu%c%zu %s:%hu (%u: %s) | %04x%04x", \ |
276 | __buffer__[0], __message__, (size_t)__res__, (!__res__ ? '!' : '>'), __buflen__, \ | 276 | __buffer__[0], __message__, (size_t)__res__, (!__res__ ? '!' : '>'), __buflen__, \ |
277 | ip_ntoa(&((__ip_port__).ip)), ntohs((__ip_port__).port), 0, "OK", data_0(__buflen__, __buffer__), data_1(__buflen__, __buffer__)); | 277 | ip_ntoa(&((__ip_port__).ip)), ntohs((__ip_port__).port), 0, "OK", data_0(__buflen__, __buffer__), data_1(__buflen__, __buffer__)); |
278 | 278 | ||
@@ -281,7 +281,7 @@ uint64_t current_time_monotonic(void) | |||
281 | /* Basic network functions: | 281 | /* Basic network functions: |
282 | * Function to send packet(data) of length length to ip_port. | 282 | * Function to send packet(data) of length length to ip_port. |
283 | */ | 283 | */ |
284 | int sendpacket(Networking_Core *net, IP_Port ip_port, const uint8_t *data, uint32_t length) | 284 | int sendpacket(Networking_Core *net, IP_Port ip_port, const uint8_t *data, uint16_t length) |
285 | { | 285 | { |
286 | if (net->family == 0) /* Socket not initialized */ | 286 | if (net->family == 0) /* Socket not initialized */ |
287 | return -1; | 287 | return -1; |
@@ -518,6 +518,12 @@ Networking_Core *new_networking(IP ip, uint16_t port) | |||
518 | int broadcast = 1; | 518 | int broadcast = 1; |
519 | setsockopt(temp->sock, SOL_SOCKET, SO_BROADCAST, (char *)&broadcast, sizeof(broadcast)); | 519 | setsockopt(temp->sock, SOL_SOCKET, SO_BROADCAST, (char *)&broadcast, sizeof(broadcast)); |
520 | 520 | ||
521 | /* iOS UDP sockets are weird and apparently can SIGPIPE */ | ||
522 | if (!set_socket_nosigpipe(temp->sock)) { | ||
523 | kill_networking(temp); | ||
524 | return NULL; | ||
525 | } | ||
526 | |||
521 | /* Set socket nonblocking. */ | 527 | /* Set socket nonblocking. */ |
522 | if (!set_socket_nonblock(temp->sock)) { | 528 | if (!set_socket_nonblock(temp->sock)) { |
523 | kill_networking(temp); | 529 | kill_networking(temp); |
@@ -750,34 +756,12 @@ void ipport_copy(IP_Port *target, const IP_Port *source) | |||
750 | memcpy(target, source, sizeof(IP_Port)); | 756 | memcpy(target, source, sizeof(IP_Port)); |
751 | }; | 757 | }; |
752 | 758 | ||
753 | /* packing and unpacking functions */ | ||
754 | void ip_pack(uint8_t *data, const IP *source) | ||
755 | { | ||
756 | data[0] = source->family; | ||
757 | memcpy(data + 1, &source->ip6, SIZE_IP6); | ||
758 | } | ||
759 | |||
760 | void ip_unpack(IP *target, const uint8_t *data) | ||
761 | { | ||
762 | target->family = data[0]; | ||
763 | memcpy(&target->ip6, data + 1, SIZE_IP6); | ||
764 | } | ||
765 | |||
766 | void ipport_pack(uint8_t *data, const IP_Port *source) | ||
767 | { | ||
768 | ip_pack(data, &source->ip); | ||
769 | memcpy(data + SIZE_IP, &source->port, SIZE_PORT); | ||
770 | } | ||
771 | |||
772 | void ipport_unpack(IP_Port *target, const uint8_t *data) | ||
773 | { | ||
774 | ip_unpack(&target->ip, data); | ||
775 | memcpy(&target->port, data + SIZE_IP, SIZE_PORT); | ||
776 | } | ||
777 | |||
778 | /* ip_ntoa | 759 | /* ip_ntoa |
779 | * converts ip into a string | 760 | * converts ip into a string |
780 | * uses a static buffer, so mustn't used multiple times in the same output | 761 | * uses a static buffer, so mustn't used multiple times in the same output |
762 | * | ||
763 | * IPv6 addresses are enclosed into square brackets, i.e. "[IPv6]" | ||
764 | * writes error message into the buffer on error | ||
781 | */ | 765 | */ |
782 | /* there would be INET6_ADDRSTRLEN, but it might be too short for the error message */ | 766 | /* there would be INET6_ADDRSTRLEN, but it might be too short for the error message */ |
783 | static char addresstext[96]; | 767 | static char addresstext[96]; |
@@ -810,6 +794,38 @@ const char *ip_ntoa(const IP *ip) | |||
810 | } | 794 | } |
811 | 795 | ||
812 | /* | 796 | /* |
797 | * ip_parse_addr | ||
798 | * parses IP structure into an address string | ||
799 | * | ||
800 | * input | ||
801 | * ip: ip of AF_INET or AF_INET6 families | ||
802 | * length: length of the address buffer | ||
803 | * Must be at least INET_ADDRSTRLEN for AF_INET | ||
804 | * and INET6_ADDRSTRLEN for AF_INET6 | ||
805 | * | ||
806 | * output | ||
807 | * address: dotted notation (IPv4: quad, IPv6: 16) or colon notation (IPv6) | ||
808 | * | ||
809 | * returns 1 on success, 0 on failure | ||
810 | */ | ||
811 | int ip_parse_addr(const IP *ip, char *address, size_t length) | ||
812 | { | ||
813 | if (!address || !ip) { | ||
814 | return 0; | ||
815 | } | ||
816 | |||
817 | if (ip->family == AF_INET) { | ||
818 | struct in_addr *addr = (struct in_addr *)&ip->ip4; | ||
819 | return inet_ntop(ip->family, addr, address, length) != NULL; | ||
820 | } else if (ip->family == AF_INET6) { | ||
821 | struct in6_addr *addr = (struct in6_addr *)&ip->ip6; | ||
822 | return inet_ntop(ip->family, addr, address, length) != NULL; | ||
823 | } | ||
824 | |||
825 | return 0; | ||
826 | } | ||
827 | |||
828 | /* | ||
813 | * addr_parse_ip | 829 | * addr_parse_ip |
814 | * directly parses the input into an IP structure | 830 | * directly parses the input into an IP structure |
815 | * tries IPv4 first, then IPv6 | 831 | * tries IPv4 first, then IPv6 |
diff --git a/toxcore/network.h b/toxcore/network.h index 1f4b757c..15e1c0a4 100644 --- a/toxcore/network.h +++ b/toxcore/network.h | |||
@@ -92,12 +92,11 @@ typedef int sock_t; | |||
92 | #endif | 92 | #endif |
93 | #endif | 93 | #endif |
94 | 94 | ||
95 | #define MAX_UDP_PACKET_SIZE 65507 | 95 | #define MAX_UDP_PACKET_SIZE 2048 |
96 | 96 | ||
97 | #define NET_PACKET_PING_REQUEST 0 /* Ping request packet ID. */ | 97 | #define NET_PACKET_PING_REQUEST 0 /* Ping request packet ID. */ |
98 | #define NET_PACKET_PING_RESPONSE 1 /* Ping response packet ID. */ | 98 | #define NET_PACKET_PING_RESPONSE 1 /* Ping response packet ID. */ |
99 | #define NET_PACKET_GET_NODES 2 /* Get nodes request packet ID. */ | 99 | #define NET_PACKET_GET_NODES 2 /* Get nodes request packet ID. */ |
100 | #define NET_PACKET_SEND_NODES 3 /* Send nodes response packet ID for IPv4 addresses. */ | ||
101 | #define NET_PACKET_SEND_NODES_IPV6 4 /* Send nodes response packet ID for other addresses. */ | 100 | #define NET_PACKET_SEND_NODES_IPV6 4 /* Send nodes response packet ID for other addresses. */ |
102 | #define NET_PACKET_COOKIE_REQUEST 24 /* Cookie request packet */ | 101 | #define NET_PACKET_COOKIE_REQUEST 24 /* Cookie request packet */ |
103 | #define NET_PACKET_COOKIE_RESPONSE 25 /* Cookie response packet */ | 102 | #define NET_PACKET_COOKIE_RESPONSE 25 /* Cookie response packet */ |
@@ -105,7 +104,6 @@ typedef int sock_t; | |||
105 | #define NET_PACKET_CRYPTO_DATA 27 /* Crypto data packet */ | 104 | #define NET_PACKET_CRYPTO_DATA 27 /* Crypto data packet */ |
106 | #define NET_PACKET_CRYPTO 32 /* Encrypted data packet ID. */ | 105 | #define NET_PACKET_CRYPTO 32 /* Encrypted data packet ID. */ |
107 | #define NET_PACKET_LAN_DISCOVERY 33 /* LAN discovery packet ID. */ | 106 | #define NET_PACKET_LAN_DISCOVERY 33 /* LAN discovery packet ID. */ |
108 | #define NET_PACKET_GROUP_CHATS 48 /* Group chats packet ID. */ | ||
109 | 107 | ||
110 | /* See: docs/Prevent_Tracking.txt and onion.{c, h} */ | 108 | /* See: docs/Prevent_Tracking.txt and onion.{c, h} */ |
111 | #define NET_PACKET_ONION_SEND_INITIAL 128 | 109 | #define NET_PACKET_ONION_SEND_INITIAL 128 |
@@ -135,8 +133,7 @@ typedef int sock_t; | |||
135 | #define TCP_INET6 (AF_INET6 + 3) | 133 | #define TCP_INET6 (AF_INET6 + 3) |
136 | #define TCP_FAMILY (AF_INET6 + 4) | 134 | #define TCP_FAMILY (AF_INET6 + 4) |
137 | 135 | ||
138 | typedef union __attribute__ ((__packed__)) | 136 | typedef union { |
139 | { | ||
140 | uint8_t uint8[4]; | 137 | uint8_t uint8[4]; |
141 | uint16_t uint16[2]; | 138 | uint16_t uint16[2]; |
142 | uint32_t uint32; | 139 | uint32_t uint32; |
@@ -144,8 +141,7 @@ typedef union __attribute__ ((__packed__)) | |||
144 | } | 141 | } |
145 | IP4; | 142 | IP4; |
146 | 143 | ||
147 | typedef union __attribute__ ((__packed__)) | 144 | typedef union { |
148 | { | ||
149 | uint8_t uint8[16]; | 145 | uint8_t uint8[16]; |
150 | uint16_t uint16[8]; | 146 | uint16_t uint16[8]; |
151 | uint32_t uint32[4]; | 147 | uint32_t uint32[4]; |
@@ -154,8 +150,7 @@ typedef union __attribute__ ((__packed__)) | |||
154 | } | 150 | } |
155 | IP6; | 151 | IP6; |
156 | 152 | ||
157 | typedef struct __attribute__ ((__packed__)) | 153 | typedef struct { |
158 | { | ||
159 | uint8_t family; | 154 | uint8_t family; |
160 | union { | 155 | union { |
161 | IP4 ip4; | 156 | IP4 ip4; |
@@ -164,8 +159,7 @@ typedef struct __attribute__ ((__packed__)) | |||
164 | } | 159 | } |
165 | IP; | 160 | IP; |
166 | 161 | ||
167 | typedef struct __attribute__ ((__packed__)) __attribute__((gcc_struct)) | 162 | typedef struct { |
168 | { | ||
169 | IP ip; | 163 | IP ip; |
170 | uint16_t port; | 164 | uint16_t port; |
171 | } | 165 | } |
@@ -185,10 +179,30 @@ IP_Port; | |||
185 | /* ip_ntoa | 179 | /* ip_ntoa |
186 | * converts ip into a string | 180 | * converts ip into a string |
187 | * uses a static buffer, so mustn't used multiple times in the same output | 181 | * uses a static buffer, so mustn't used multiple times in the same output |
182 | * | ||
183 | * IPv6 addresses are enclosed into square brackets, i.e. "[IPv6]" | ||
184 | * writes error message into the buffer on error | ||
188 | */ | 185 | */ |
189 | const char *ip_ntoa(const IP *ip); | 186 | const char *ip_ntoa(const IP *ip); |
190 | 187 | ||
191 | /* | 188 | /* |
189 | * ip_parse_addr | ||
190 | * parses IP structure into an address string | ||
191 | * | ||
192 | * input | ||
193 | * ip: ip of AF_INET or AF_INET6 families | ||
194 | * length: length of the address buffer | ||
195 | * Must be at least INET_ADDRSTRLEN for AF_INET | ||
196 | * and INET6_ADDRSTRLEN for AF_INET6 | ||
197 | * | ||
198 | * output | ||
199 | * address: dotted notation (IPv4: quad, IPv6: 16) or colon notation (IPv6) | ||
200 | * | ||
201 | * returns 1 on success, 0 on failure | ||
202 | */ | ||
203 | int ip_parse_addr(const IP *ip, char *address, size_t length); | ||
204 | |||
205 | /* | ||
192 | * addr_parse_ip | 206 | * addr_parse_ip |
193 | * directly parses the input into an IP structure | 207 | * directly parses the input into an IP structure |
194 | * tries IPv4 first, then IPv6 | 208 | * tries IPv4 first, then IPv6 |
@@ -232,16 +246,6 @@ void ip_copy(IP *target, const IP *source); | |||
232 | /* copies an ip_port structure */ | 246 | /* copies an ip_port structure */ |
233 | void ipport_copy(IP_Port *target, const IP_Port *source); | 247 | void ipport_copy(IP_Port *target, const IP_Port *source); |
234 | 248 | ||
235 | |||
236 | /* packs IP into data, writes SIZE_IP bytes to data */ | ||
237 | void ip_pack(uint8_t *data, const IP *source); | ||
238 | /* unpacks IP from data, reads SIZE_IP bytes from data */ | ||
239 | void ip_unpack(IP *target, const uint8_t *data); | ||
240 | /* packs IP_Port into data, writes SIZE_IPPORT bytes to data */ | ||
241 | void ipport_pack(uint8_t *data, const IP_Port *source); | ||
242 | /* unpacks IP_Port from data, reads SIZE_IPPORT bytes to data */ | ||
243 | void ipport_unpack(IP_Port *target, const uint8_t *data); | ||
244 | |||
245 | /* | 249 | /* |
246 | * addr_resolve(): | 250 | * addr_resolve(): |
247 | * uses getaddrinfo to resolve an address into an IP address | 251 | * uses getaddrinfo to resolve an address into an IP address |
@@ -282,7 +286,7 @@ int addr_resolve_or_parse_ip(const char *address, IP *to, IP *extra); | |||
282 | * Packet data is put into data. | 286 | * Packet data is put into data. |
283 | * Packet length is put into length. | 287 | * Packet length is put into length. |
284 | */ | 288 | */ |
285 | typedef int (*packet_handler_callback)(void *object, IP_Port ip_port, const uint8_t *data, uint32_t len); | 289 | typedef int (*packet_handler_callback)(void *object, IP_Port ip_port, const uint8_t *data, uint16_t len); |
286 | 290 | ||
287 | typedef struct { | 291 | typedef struct { |
288 | packet_handler_callback function; | 292 | packet_handler_callback function; |
@@ -343,7 +347,7 @@ uint64_t current_time_monotonic(void); | |||
343 | /* Basic network functions: */ | 347 | /* Basic network functions: */ |
344 | 348 | ||
345 | /* Function to send packet(data) of length length to ip_port. */ | 349 | /* Function to send packet(data) of length length to ip_port. */ |
346 | int sendpacket(Networking_Core *net, IP_Port ip_port, const uint8_t *data, uint32_t length); | 350 | int sendpacket(Networking_Core *net, IP_Port ip_port, const uint8_t *data, uint16_t length); |
347 | 351 | ||
348 | /* Function to call when packet beginning with byte is received. */ | 352 | /* Function to call when packet beginning with byte is received. */ |
349 | void networking_registerhandler(Networking_Core *net, uint8_t byte, packet_handler_callback cb, void *object); | 353 | void networking_registerhandler(Networking_Core *net, uint8_t byte, packet_handler_callback cb, void *object); |
@@ -356,8 +360,8 @@ void networking_poll(Networking_Core *net); | |||
356 | * ip must be in network order EX: 127.0.0.1 = (7F000001). | 360 | * ip must be in network order EX: 127.0.0.1 = (7F000001). |
357 | * port is in host byte order (this means don't worry about it). | 361 | * port is in host byte order (this means don't worry about it). |
358 | * | 362 | * |
359 | * return 0 if no problems. | 363 | * return Networking_Core object if no problems |
360 | * return -1 if there were problems. | 364 | * return NULL if there are problems. |
361 | */ | 365 | */ |
362 | Networking_Core *new_networking(IP ip, uint16_t port); | 366 | Networking_Core *new_networking(IP ip, uint16_t port); |
363 | 367 | ||
diff --git a/toxcore/onion.c b/toxcore/onion.c index 938b861e..c6093f0c 100644 --- a/toxcore/onion.c +++ b/toxcore/onion.c | |||
@@ -45,6 +45,63 @@ static void change_symmetric_key(Onion *onion) | |||
45 | } | 45 | } |
46 | } | 46 | } |
47 | 47 | ||
48 | /* packing and unpacking functions */ | ||
49 | static void ip_pack(uint8_t *data, IP source) | ||
50 | { | ||
51 | to_net_family(&source); | ||
52 | |||
53 | data[0] = source.family; | ||
54 | |||
55 | if (source.family == TOX_AF_INET || source.family == TOX_TCP_INET) { | ||
56 | memset(data + 1, 0, SIZE_IP6); | ||
57 | memcpy(data + 1, source.ip4.uint8, SIZE_IP4); | ||
58 | } else { | ||
59 | memcpy(data + 1, source.ip6.uint8, SIZE_IP6); | ||
60 | } | ||
61 | } | ||
62 | |||
63 | /* return 0 on success, -1 on failure. */ | ||
64 | static int ip_unpack(IP *target, const uint8_t *data, unsigned int data_size, _Bool disable_family_check) | ||
65 | { | ||
66 | if (data_size < (1 + SIZE_IP6)) | ||
67 | return -1; | ||
68 | |||
69 | target->family = data[0]; | ||
70 | |||
71 | if (target->family == TOX_AF_INET || target->family == TOX_TCP_INET) { | ||
72 | memcpy(target->ip4.uint8, data + 1, SIZE_IP4); | ||
73 | } else { | ||
74 | memcpy(target->ip6.uint8, data + 1, SIZE_IP6); | ||
75 | } | ||
76 | |||
77 | if (!disable_family_check) { | ||
78 | return to_host_family(target); | ||
79 | } else { | ||
80 | to_host_family(target); | ||
81 | return 0; | ||
82 | } | ||
83 | } | ||
84 | |||
85 | static void ipport_pack(uint8_t *data, const IP_Port *source) | ||
86 | { | ||
87 | ip_pack(data, source->ip); | ||
88 | memcpy(data + SIZE_IP, &source->port, SIZE_PORT); | ||
89 | } | ||
90 | |||
91 | /* return 0 on success, -1 on failure. */ | ||
92 | static int ipport_unpack(IP_Port *target, const uint8_t *data, unsigned int data_size, _Bool disable_family_check) | ||
93 | { | ||
94 | if (data_size < (SIZE_IP + SIZE_PORT)) | ||
95 | return -1; | ||
96 | |||
97 | if (ip_unpack(&target->ip, data, data_size, disable_family_check) == -1) | ||
98 | return -1; | ||
99 | |||
100 | memcpy(&target->port, data + SIZE_IP, SIZE_PORT); | ||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | |||
48 | /* Create a new onion path. | 105 | /* Create a new onion path. |
49 | * | 106 | * |
50 | * Create a new onion path out of nodes (nodes is a list of 3 nodes) | 107 | * Create a new onion path out of nodes (nodes is a list of 3 nodes) |
@@ -59,31 +116,51 @@ int create_onion_path(const DHT *dht, Onion_Path *new_path, const Node_format *n | |||
59 | if (!new_path || !nodes) | 116 | if (!new_path || !nodes) |
60 | return -1; | 117 | return -1; |
61 | 118 | ||
62 | encrypt_precompute(nodes[0].client_id, dht->self_secret_key, new_path->shared_key1); | 119 | encrypt_precompute(nodes[0].public_key, dht->self_secret_key, new_path->shared_key1); |
63 | memcpy(new_path->public_key1, dht->self_public_key, crypto_box_PUBLICKEYBYTES); | 120 | memcpy(new_path->public_key1, dht->self_public_key, crypto_box_PUBLICKEYBYTES); |
64 | 121 | ||
65 | uint8_t random_public_key[crypto_box_PUBLICKEYBYTES]; | 122 | uint8_t random_public_key[crypto_box_PUBLICKEYBYTES]; |
66 | uint8_t random_secret_key[crypto_box_SECRETKEYBYTES]; | 123 | uint8_t random_secret_key[crypto_box_SECRETKEYBYTES]; |
67 | 124 | ||
68 | crypto_box_keypair(random_public_key, random_secret_key); | 125 | crypto_box_keypair(random_public_key, random_secret_key); |
69 | encrypt_precompute(nodes[1].client_id, random_secret_key, new_path->shared_key2); | 126 | encrypt_precompute(nodes[1].public_key, random_secret_key, new_path->shared_key2); |
70 | memcpy(new_path->public_key2, random_public_key, crypto_box_PUBLICKEYBYTES); | 127 | memcpy(new_path->public_key2, random_public_key, crypto_box_PUBLICKEYBYTES); |
71 | 128 | ||
72 | crypto_box_keypair(random_public_key, random_secret_key); | 129 | crypto_box_keypair(random_public_key, random_secret_key); |
73 | encrypt_precompute(nodes[2].client_id, random_secret_key, new_path->shared_key3); | 130 | encrypt_precompute(nodes[2].public_key, random_secret_key, new_path->shared_key3); |
74 | memcpy(new_path->public_key3, random_public_key, crypto_box_PUBLICKEYBYTES); | 131 | memcpy(new_path->public_key3, random_public_key, crypto_box_PUBLICKEYBYTES); |
75 | 132 | ||
76 | new_path->ip_port1 = nodes[0].ip_port; | 133 | new_path->ip_port1 = nodes[0].ip_port; |
77 | new_path->ip_port2 = nodes[1].ip_port; | 134 | new_path->ip_port2 = nodes[1].ip_port; |
78 | new_path->ip_port3 = nodes[2].ip_port; | 135 | new_path->ip_port3 = nodes[2].ip_port; |
79 | 136 | ||
80 | /* to_net_family(&new_path->ip_port1.ip); */ | 137 | memcpy(new_path->node_public_key1, nodes[0].public_key, crypto_box_PUBLICKEYBYTES); |
81 | to_net_family(&new_path->ip_port2.ip); | 138 | memcpy(new_path->node_public_key2, nodes[1].public_key, crypto_box_PUBLICKEYBYTES); |
82 | to_net_family(&new_path->ip_port3.ip); | 139 | memcpy(new_path->node_public_key3, nodes[2].public_key, crypto_box_PUBLICKEYBYTES); |
83 | 140 | ||
84 | return 0; | 141 | return 0; |
85 | } | 142 | } |
86 | 143 | ||
144 | /* Dump nodes in onion path to nodes of length num_nodes; | ||
145 | * | ||
146 | * return -1 on failure. | ||
147 | * return 0 on success. | ||
148 | */ | ||
149 | int onion_path_to_nodes(Node_format *nodes, unsigned int num_nodes, const Onion_Path *path) | ||
150 | { | ||
151 | if (num_nodes < 3) | ||
152 | return -1; | ||
153 | |||
154 | nodes[0].ip_port = path->ip_port1; | ||
155 | nodes[1].ip_port = path->ip_port2; | ||
156 | nodes[2].ip_port = path->ip_port3; | ||
157 | |||
158 | memcpy(nodes[0].public_key, path->node_public_key1, crypto_box_PUBLICKEYBYTES); | ||
159 | memcpy(nodes[1].public_key, path->node_public_key2, crypto_box_PUBLICKEYBYTES); | ||
160 | memcpy(nodes[2].public_key, path->node_public_key3, crypto_box_PUBLICKEYBYTES); | ||
161 | return 0; | ||
162 | } | ||
163 | |||
87 | /* Create a onion packet. | 164 | /* Create a onion packet. |
88 | * | 165 | * |
89 | * Use Onion_Path path to create packet for data of length to dest. | 166 | * Use Onion_Path path to create packet for data of length to dest. |
@@ -94,15 +171,13 @@ int create_onion_path(const DHT *dht, Onion_Path *new_path, const Node_format *n | |||
94 | * return length of created packet on success. | 171 | * return length of created packet on success. |
95 | */ | 172 | */ |
96 | int create_onion_packet(uint8_t *packet, uint16_t max_packet_length, const Onion_Path *path, IP_Port dest, | 173 | int create_onion_packet(uint8_t *packet, uint16_t max_packet_length, const Onion_Path *path, IP_Port dest, |
97 | const uint8_t *data, uint32_t length) | 174 | const uint8_t *data, uint16_t length) |
98 | { | 175 | { |
99 | if (1 + length + SEND_1 > max_packet_length || length == 0) | 176 | if (1 + length + SEND_1 > max_packet_length || length == 0) |
100 | return -1; | 177 | return -1; |
101 | 178 | ||
102 | to_net_family(&dest.ip); | ||
103 | uint8_t step1[SIZE_IPPORT + length]; | 179 | uint8_t step1[SIZE_IPPORT + length]; |
104 | 180 | ||
105 | |||
106 | ipport_pack(step1, &dest); | 181 | ipport_pack(step1, &dest); |
107 | memcpy(step1 + SIZE_IPPORT, data, length); | 182 | memcpy(step1 + SIZE_IPPORT, data, length); |
108 | 183 | ||
@@ -116,7 +191,7 @@ int create_onion_packet(uint8_t *packet, uint16_t max_packet_length, const Onion | |||
116 | int len = encrypt_data_symmetric(path->shared_key3, nonce, step1, sizeof(step1), | 191 | int len = encrypt_data_symmetric(path->shared_key3, nonce, step1, sizeof(step1), |
117 | step2 + SIZE_IPPORT + crypto_box_PUBLICKEYBYTES); | 192 | step2 + SIZE_IPPORT + crypto_box_PUBLICKEYBYTES); |
118 | 193 | ||
119 | if ((uint32_t)len != SIZE_IPPORT + length + crypto_box_MACBYTES) | 194 | if (len != SIZE_IPPORT + length + crypto_box_MACBYTES) |
120 | return -1; | 195 | return -1; |
121 | 196 | ||
122 | uint8_t step3[SIZE_IPPORT + SEND_BASE * 2 + length]; | 197 | uint8_t step3[SIZE_IPPORT + SEND_BASE * 2 + length]; |
@@ -125,7 +200,7 @@ int create_onion_packet(uint8_t *packet, uint16_t max_packet_length, const Onion | |||
125 | len = encrypt_data_symmetric(path->shared_key2, nonce, step2, sizeof(step2), | 200 | len = encrypt_data_symmetric(path->shared_key2, nonce, step2, sizeof(step2), |
126 | step3 + SIZE_IPPORT + crypto_box_PUBLICKEYBYTES); | 201 | step3 + SIZE_IPPORT + crypto_box_PUBLICKEYBYTES); |
127 | 202 | ||
128 | if ((uint32_t)len != SIZE_IPPORT + SEND_BASE + length + crypto_box_MACBYTES) | 203 | if (len != SIZE_IPPORT + SEND_BASE + length + crypto_box_MACBYTES) |
129 | return -1; | 204 | return -1; |
130 | 205 | ||
131 | packet[0] = NET_PACKET_ONION_SEND_INITIAL; | 206 | packet[0] = NET_PACKET_ONION_SEND_INITIAL; |
@@ -135,7 +210,7 @@ int create_onion_packet(uint8_t *packet, uint16_t max_packet_length, const Onion | |||
135 | len = encrypt_data_symmetric(path->shared_key1, nonce, step3, sizeof(step3), | 210 | len = encrypt_data_symmetric(path->shared_key1, nonce, step3, sizeof(step3), |
136 | packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES); | 211 | packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES); |
137 | 212 | ||
138 | if ((uint32_t)len != SIZE_IPPORT + SEND_BASE * 2 + length + crypto_box_MACBYTES) | 213 | if (len != SIZE_IPPORT + SEND_BASE * 2 + length + crypto_box_MACBYTES) |
139 | return -1; | 214 | return -1; |
140 | 215 | ||
141 | return 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + len; | 216 | return 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + len; |
@@ -151,15 +226,13 @@ int create_onion_packet(uint8_t *packet, uint16_t max_packet_length, const Onion | |||
151 | * return length of created packet on success. | 226 | * return length of created packet on success. |
152 | */ | 227 | */ |
153 | int create_onion_packet_tcp(uint8_t *packet, uint16_t max_packet_length, const Onion_Path *path, IP_Port dest, | 228 | int create_onion_packet_tcp(uint8_t *packet, uint16_t max_packet_length, const Onion_Path *path, IP_Port dest, |
154 | const uint8_t *data, uint32_t length) | 229 | const uint8_t *data, uint16_t length) |
155 | { | 230 | { |
156 | if (crypto_box_NONCEBYTES + SIZE_IPPORT + SEND_BASE * 2 + length > max_packet_length || length == 0) | 231 | if (crypto_box_NONCEBYTES + SIZE_IPPORT + SEND_BASE * 2 + length > max_packet_length || length == 0) |
157 | return -1; | 232 | return -1; |
158 | 233 | ||
159 | to_net_family(&dest.ip); | ||
160 | uint8_t step1[SIZE_IPPORT + length]; | 234 | uint8_t step1[SIZE_IPPORT + length]; |
161 | 235 | ||
162 | |||
163 | ipport_pack(step1, &dest); | 236 | ipport_pack(step1, &dest); |
164 | memcpy(step1 + SIZE_IPPORT, data, length); | 237 | memcpy(step1 + SIZE_IPPORT, data, length); |
165 | 238 | ||
@@ -173,7 +246,7 @@ int create_onion_packet_tcp(uint8_t *packet, uint16_t max_packet_length, const O | |||
173 | int len = encrypt_data_symmetric(path->shared_key3, nonce, step1, sizeof(step1), | 246 | int len = encrypt_data_symmetric(path->shared_key3, nonce, step1, sizeof(step1), |
174 | step2 + SIZE_IPPORT + crypto_box_PUBLICKEYBYTES); | 247 | step2 + SIZE_IPPORT + crypto_box_PUBLICKEYBYTES); |
175 | 248 | ||
176 | if ((uint32_t)len != SIZE_IPPORT + length + crypto_box_MACBYTES) | 249 | if (len != SIZE_IPPORT + length + crypto_box_MACBYTES) |
177 | return -1; | 250 | return -1; |
178 | 251 | ||
179 | ipport_pack(packet + crypto_box_NONCEBYTES, &path->ip_port2); | 252 | ipport_pack(packet + crypto_box_NONCEBYTES, &path->ip_port2); |
@@ -181,7 +254,7 @@ int create_onion_packet_tcp(uint8_t *packet, uint16_t max_packet_length, const O | |||
181 | len = encrypt_data_symmetric(path->shared_key2, nonce, step2, sizeof(step2), | 254 | len = encrypt_data_symmetric(path->shared_key2, nonce, step2, sizeof(step2), |
182 | packet + crypto_box_NONCEBYTES + SIZE_IPPORT + crypto_box_PUBLICKEYBYTES); | 255 | packet + crypto_box_NONCEBYTES + SIZE_IPPORT + crypto_box_PUBLICKEYBYTES); |
183 | 256 | ||
184 | if ((uint32_t)len != SIZE_IPPORT + SEND_BASE + length + crypto_box_MACBYTES) | 257 | if (len != SIZE_IPPORT + SEND_BASE + length + crypto_box_MACBYTES) |
185 | return -1; | 258 | return -1; |
186 | 259 | ||
187 | memcpy(packet, nonce, crypto_box_NONCEBYTES); | 260 | memcpy(packet, nonce, crypto_box_NONCEBYTES); |
@@ -197,7 +270,7 @@ int create_onion_packet_tcp(uint8_t *packet, uint16_t max_packet_length, const O | |||
197 | * return -1 on failure. | 270 | * return -1 on failure. |
198 | * return 0 on success. | 271 | * return 0 on success. |
199 | */ | 272 | */ |
200 | int send_onion_packet(Networking_Core *net, const Onion_Path *path, IP_Port dest, const uint8_t *data, uint32_t length) | 273 | int send_onion_packet(Networking_Core *net, const Onion_Path *path, IP_Port dest, const uint8_t *data, uint16_t length) |
201 | { | 274 | { |
202 | uint8_t packet[ONION_MAX_PACKET_SIZE]; | 275 | uint8_t packet[ONION_MAX_PACKET_SIZE]; |
203 | int len = create_onion_packet(packet, sizeof(packet), path, dest, data, length); | 276 | int len = create_onion_packet(packet, sizeof(packet), path, dest, data, length); |
@@ -217,7 +290,7 @@ int send_onion_packet(Networking_Core *net, const Onion_Path *path, IP_Port dest | |||
217 | * return -1 on failure. | 290 | * return -1 on failure. |
218 | * return 0 on success. | 291 | * return 0 on success. |
219 | */ | 292 | */ |
220 | int send_onion_response(Networking_Core *net, IP_Port dest, const uint8_t *data, uint32_t length, const uint8_t *ret) | 293 | int send_onion_response(Networking_Core *net, IP_Port dest, const uint8_t *data, uint16_t length, const uint8_t *ret) |
221 | { | 294 | { |
222 | if (length > ONION_RESPONSE_MAX_DATA_SIZE || length == 0) | 295 | if (length > ONION_RESPONSE_MAX_DATA_SIZE || length == 0) |
223 | return -1; | 296 | return -1; |
@@ -233,7 +306,7 @@ int send_onion_response(Networking_Core *net, IP_Port dest, const uint8_t *data, | |||
233 | return 0; | 306 | return 0; |
234 | } | 307 | } |
235 | 308 | ||
236 | static int handle_send_initial(void *object, IP_Port source, const uint8_t *packet, uint32_t length) | 309 | static int handle_send_initial(void *object, IP_Port source, const uint8_t *packet, uint16_t length) |
237 | { | 310 | { |
238 | Onion *onion = object; | 311 | Onion *onion = object; |
239 | 312 | ||
@@ -251,13 +324,13 @@ static int handle_send_initial(void *object, IP_Port source, const uint8_t *pack | |||
251 | int len = decrypt_data_symmetric(shared_key, packet + 1, packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES, | 324 | int len = decrypt_data_symmetric(shared_key, packet + 1, packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES, |
252 | length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES), plain); | 325 | length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES), plain); |
253 | 326 | ||
254 | if ((uint32_t)len != length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + crypto_box_MACBYTES)) | 327 | if (len != length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + crypto_box_MACBYTES)) |
255 | return 1; | 328 | return 1; |
256 | 329 | ||
257 | return onion_send_1(onion, plain, len, source, packet + 1); | 330 | return onion_send_1(onion, plain, len, source, packet + 1); |
258 | } | 331 | } |
259 | 332 | ||
260 | int onion_send_1(const Onion *onion, const uint8_t *plain, uint32_t len, IP_Port source, const uint8_t *nonce) | 333 | int onion_send_1(const Onion *onion, const uint8_t *plain, uint16_t len, IP_Port source, const uint8_t *nonce) |
261 | { | 334 | { |
262 | if (len > ONION_MAX_PACKET_SIZE + SIZE_IPPORT - (1 + crypto_box_NONCEBYTES + ONION_RETURN_1)) | 335 | if (len > ONION_MAX_PACKET_SIZE + SIZE_IPPORT - (1 + crypto_box_NONCEBYTES + ONION_RETURN_1)) |
263 | return 1; | 336 | return 1; |
@@ -266,8 +339,9 @@ int onion_send_1(const Onion *onion, const uint8_t *plain, uint32_t len, IP_Port | |||
266 | return 1; | 339 | return 1; |
267 | 340 | ||
268 | IP_Port send_to; | 341 | IP_Port send_to; |
269 | ipport_unpack(&send_to, plain); | 342 | |
270 | to_host_family(&send_to.ip); | 343 | if (ipport_unpack(&send_to, plain, len, 0) == -1) |
344 | return 1; | ||
271 | 345 | ||
272 | uint8_t ip_port[SIZE_IPPORT]; | 346 | uint8_t ip_port[SIZE_IPPORT]; |
273 | ipport_pack(ip_port, &source); | 347 | ipport_pack(ip_port, &source); |
@@ -276,7 +350,7 @@ int onion_send_1(const Onion *onion, const uint8_t *plain, uint32_t len, IP_Port | |||
276 | data[0] = NET_PACKET_ONION_SEND_1; | 350 | data[0] = NET_PACKET_ONION_SEND_1; |
277 | memcpy(data + 1, nonce, crypto_box_NONCEBYTES); | 351 | memcpy(data + 1, nonce, crypto_box_NONCEBYTES); |
278 | memcpy(data + 1 + crypto_box_NONCEBYTES, plain + SIZE_IPPORT, len - SIZE_IPPORT); | 352 | memcpy(data + 1 + crypto_box_NONCEBYTES, plain + SIZE_IPPORT, len - SIZE_IPPORT); |
279 | uint32_t data_len = 1 + crypto_box_NONCEBYTES + (len - SIZE_IPPORT); | 353 | uint16_t data_len = 1 + crypto_box_NONCEBYTES + (len - SIZE_IPPORT); |
280 | uint8_t *ret_part = data + data_len; | 354 | uint8_t *ret_part = data + data_len; |
281 | new_nonce(ret_part); | 355 | new_nonce(ret_part); |
282 | len = encrypt_data_symmetric(onion->secret_symmetric_key, ret_part, ip_port, SIZE_IPPORT, | 356 | len = encrypt_data_symmetric(onion->secret_symmetric_key, ret_part, ip_port, SIZE_IPPORT, |
@@ -293,7 +367,7 @@ int onion_send_1(const Onion *onion, const uint8_t *plain, uint32_t len, IP_Port | |||
293 | return 0; | 367 | return 0; |
294 | } | 368 | } |
295 | 369 | ||
296 | static int handle_send_1(void *object, IP_Port source, const uint8_t *packet, uint32_t length) | 370 | static int handle_send_1(void *object, IP_Port source, const uint8_t *packet, uint16_t length) |
297 | { | 371 | { |
298 | Onion *onion = object; | 372 | Onion *onion = object; |
299 | 373 | ||
@@ -311,18 +385,19 @@ static int handle_send_1(void *object, IP_Port source, const uint8_t *packet, ui | |||
311 | int len = decrypt_data_symmetric(shared_key, packet + 1, packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES, | 385 | int len = decrypt_data_symmetric(shared_key, packet + 1, packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES, |
312 | length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + RETURN_1), plain); | 386 | length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + RETURN_1), plain); |
313 | 387 | ||
314 | if ((uint32_t)len != length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + RETURN_1 + crypto_box_MACBYTES)) | 388 | if (len != length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + RETURN_1 + crypto_box_MACBYTES)) |
315 | return 1; | 389 | return 1; |
316 | 390 | ||
317 | IP_Port send_to; | 391 | IP_Port send_to; |
318 | ipport_unpack(&send_to, plain); | 392 | |
319 | to_host_family(&send_to.ip); | 393 | if (ipport_unpack(&send_to, plain, len, 0) == -1) |
394 | return 1; | ||
320 | 395 | ||
321 | uint8_t data[ONION_MAX_PACKET_SIZE]; | 396 | uint8_t data[ONION_MAX_PACKET_SIZE]; |
322 | data[0] = NET_PACKET_ONION_SEND_2; | 397 | data[0] = NET_PACKET_ONION_SEND_2; |
323 | memcpy(data + 1, packet + 1, crypto_box_NONCEBYTES); | 398 | memcpy(data + 1, packet + 1, crypto_box_NONCEBYTES); |
324 | memcpy(data + 1 + crypto_box_NONCEBYTES, plain + SIZE_IPPORT, len - SIZE_IPPORT); | 399 | memcpy(data + 1 + crypto_box_NONCEBYTES, plain + SIZE_IPPORT, len - SIZE_IPPORT); |
325 | uint32_t data_len = 1 + crypto_box_NONCEBYTES + (len - SIZE_IPPORT); | 400 | uint16_t data_len = 1 + crypto_box_NONCEBYTES + (len - SIZE_IPPORT); |
326 | uint8_t *ret_part = data + data_len; | 401 | uint8_t *ret_part = data + data_len; |
327 | new_nonce(ret_part); | 402 | new_nonce(ret_part); |
328 | uint8_t ret_data[RETURN_1 + SIZE_IPPORT]; | 403 | uint8_t ret_data[RETURN_1 + SIZE_IPPORT]; |
@@ -342,7 +417,7 @@ static int handle_send_1(void *object, IP_Port source, const uint8_t *packet, ui | |||
342 | return 0; | 417 | return 0; |
343 | } | 418 | } |
344 | 419 | ||
345 | static int handle_send_2(void *object, IP_Port source, const uint8_t *packet, uint32_t length) | 420 | static int handle_send_2(void *object, IP_Port source, const uint8_t *packet, uint16_t length) |
346 | { | 421 | { |
347 | Onion *onion = object; | 422 | Onion *onion = object; |
348 | 423 | ||
@@ -360,16 +435,17 @@ static int handle_send_2(void *object, IP_Port source, const uint8_t *packet, ui | |||
360 | int len = decrypt_data_symmetric(shared_key, packet + 1, packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES, | 435 | int len = decrypt_data_symmetric(shared_key, packet + 1, packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES, |
361 | length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + RETURN_2), plain); | 436 | length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + RETURN_2), plain); |
362 | 437 | ||
363 | if ((uint32_t)len != length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + RETURN_2 + crypto_box_MACBYTES)) | 438 | if (len != length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + RETURN_2 + crypto_box_MACBYTES)) |
364 | return 1; | 439 | return 1; |
365 | 440 | ||
366 | IP_Port send_to; | 441 | IP_Port send_to; |
367 | ipport_unpack(&send_to, plain); | 442 | |
368 | to_host_family(&send_to.ip); | 443 | if (ipport_unpack(&send_to, plain, len, 0) == -1) |
444 | return 1; | ||
369 | 445 | ||
370 | uint8_t data[ONION_MAX_PACKET_SIZE]; | 446 | uint8_t data[ONION_MAX_PACKET_SIZE]; |
371 | memcpy(data, plain + SIZE_IPPORT, len - SIZE_IPPORT); | 447 | memcpy(data, plain + SIZE_IPPORT, len - SIZE_IPPORT); |
372 | uint32_t data_len = (len - SIZE_IPPORT); | 448 | uint16_t data_len = (len - SIZE_IPPORT); |
373 | uint8_t *ret_part = data + (len - SIZE_IPPORT); | 449 | uint8_t *ret_part = data + (len - SIZE_IPPORT); |
374 | new_nonce(ret_part); | 450 | new_nonce(ret_part); |
375 | uint8_t ret_data[RETURN_2 + SIZE_IPPORT]; | 451 | uint8_t ret_data[RETURN_2 + SIZE_IPPORT]; |
@@ -390,7 +466,7 @@ static int handle_send_2(void *object, IP_Port source, const uint8_t *packet, ui | |||
390 | } | 466 | } |
391 | 467 | ||
392 | 468 | ||
393 | static int handle_recv_3(void *object, IP_Port source, const uint8_t *packet, uint32_t length) | 469 | static int handle_recv_3(void *object, IP_Port source, const uint8_t *packet, uint16_t length) |
394 | { | 470 | { |
395 | Onion *onion = object; | 471 | Onion *onion = object; |
396 | 472 | ||
@@ -410,13 +486,15 @@ static int handle_recv_3(void *object, IP_Port source, const uint8_t *packet, ui | |||
410 | return 1; | 486 | return 1; |
411 | 487 | ||
412 | IP_Port send_to; | 488 | IP_Port send_to; |
413 | ipport_unpack(&send_to, plain); | 489 | |
490 | if (ipport_unpack(&send_to, plain, len, 0) == -1) | ||
491 | return 1; | ||
414 | 492 | ||
415 | uint8_t data[ONION_MAX_PACKET_SIZE]; | 493 | uint8_t data[ONION_MAX_PACKET_SIZE]; |
416 | data[0] = NET_PACKET_ONION_RECV_2; | 494 | data[0] = NET_PACKET_ONION_RECV_2; |
417 | memcpy(data + 1, plain + SIZE_IPPORT, RETURN_2); | 495 | memcpy(data + 1, plain + SIZE_IPPORT, RETURN_2); |
418 | memcpy(data + 1 + RETURN_2, packet + 1 + RETURN_3, length - (1 + RETURN_3)); | 496 | memcpy(data + 1 + RETURN_2, packet + 1 + RETURN_3, length - (1 + RETURN_3)); |
419 | uint32_t data_len = 1 + RETURN_2 + (length - (1 + RETURN_3)); | 497 | uint16_t data_len = 1 + RETURN_2 + (length - (1 + RETURN_3)); |
420 | 498 | ||
421 | if ((uint32_t)sendpacket(onion->net, send_to, data, data_len) != data_len) | 499 | if ((uint32_t)sendpacket(onion->net, send_to, data, data_len) != data_len) |
422 | return 1; | 500 | return 1; |
@@ -424,7 +502,7 @@ static int handle_recv_3(void *object, IP_Port source, const uint8_t *packet, ui | |||
424 | return 0; | 502 | return 0; |
425 | } | 503 | } |
426 | 504 | ||
427 | static int handle_recv_2(void *object, IP_Port source, const uint8_t *packet, uint32_t length) | 505 | static int handle_recv_2(void *object, IP_Port source, const uint8_t *packet, uint16_t length) |
428 | { | 506 | { |
429 | Onion *onion = object; | 507 | Onion *onion = object; |
430 | 508 | ||
@@ -444,13 +522,15 @@ static int handle_recv_2(void *object, IP_Port source, const uint8_t *packet, ui | |||
444 | return 1; | 522 | return 1; |
445 | 523 | ||
446 | IP_Port send_to; | 524 | IP_Port send_to; |
447 | ipport_unpack(&send_to, plain); | 525 | |
526 | if (ipport_unpack(&send_to, plain, len, 0) == -1) | ||
527 | return 1; | ||
448 | 528 | ||
449 | uint8_t data[ONION_MAX_PACKET_SIZE]; | 529 | uint8_t data[ONION_MAX_PACKET_SIZE]; |
450 | data[0] = NET_PACKET_ONION_RECV_1; | 530 | data[0] = NET_PACKET_ONION_RECV_1; |
451 | memcpy(data + 1, plain + SIZE_IPPORT, RETURN_1); | 531 | memcpy(data + 1, plain + SIZE_IPPORT, RETURN_1); |
452 | memcpy(data + 1 + RETURN_1, packet + 1 + RETURN_2, length - (1 + RETURN_2)); | 532 | memcpy(data + 1 + RETURN_1, packet + 1 + RETURN_2, length - (1 + RETURN_2)); |
453 | uint32_t data_len = 1 + RETURN_1 + (length - (1 + RETURN_2)); | 533 | uint16_t data_len = 1 + RETURN_1 + (length - (1 + RETURN_2)); |
454 | 534 | ||
455 | if ((uint32_t)sendpacket(onion->net, send_to, data, data_len) != data_len) | 535 | if ((uint32_t)sendpacket(onion->net, send_to, data, data_len) != data_len) |
456 | return 1; | 536 | return 1; |
@@ -458,7 +538,7 @@ static int handle_recv_2(void *object, IP_Port source, const uint8_t *packet, ui | |||
458 | return 0; | 538 | return 0; |
459 | } | 539 | } |
460 | 540 | ||
461 | static int handle_recv_1(void *object, IP_Port source, const uint8_t *packet, uint32_t length) | 541 | static int handle_recv_1(void *object, IP_Port source, const uint8_t *packet, uint16_t length) |
462 | { | 542 | { |
463 | Onion *onion = object; | 543 | Onion *onion = object; |
464 | 544 | ||
@@ -478,9 +558,11 @@ static int handle_recv_1(void *object, IP_Port source, const uint8_t *packet, ui | |||
478 | return 1; | 558 | return 1; |
479 | 559 | ||
480 | IP_Port send_to; | 560 | IP_Port send_to; |
481 | ipport_unpack(&send_to, plain); | ||
482 | 561 | ||
483 | uint32_t data_len = length - (1 + RETURN_1); | 562 | if (ipport_unpack(&send_to, plain, len, 1) == -1) |
563 | return 1; | ||
564 | |||
565 | uint16_t data_len = length - (1 + RETURN_1); | ||
484 | 566 | ||
485 | if (onion->recv_1_function && send_to.ip.family != AF_INET && send_to.ip.family != AF_INET6) | 567 | if (onion->recv_1_function && send_to.ip.family != AF_INET && send_to.ip.family != AF_INET6) |
486 | return onion->recv_1_function(onion->callback_object, send_to, packet + (1 + RETURN_1), data_len); | 568 | return onion->recv_1_function(onion->callback_object, send_to, packet + (1 + RETURN_1), data_len); |
diff --git a/toxcore/onion.h b/toxcore/onion.h index e8e7042c..b05d2c8c 100644 --- a/toxcore/onion.h +++ b/toxcore/onion.h | |||
@@ -63,8 +63,13 @@ typedef struct { | |||
63 | uint8_t public_key3[crypto_box_PUBLICKEYBYTES]; | 63 | uint8_t public_key3[crypto_box_PUBLICKEYBYTES]; |
64 | 64 | ||
65 | IP_Port ip_port1; | 65 | IP_Port ip_port1; |
66 | uint8_t node_public_key1[crypto_box_PUBLICKEYBYTES]; | ||
67 | |||
66 | IP_Port ip_port2; | 68 | IP_Port ip_port2; |
69 | uint8_t node_public_key2[crypto_box_PUBLICKEYBYTES]; | ||
70 | |||
67 | IP_Port ip_port3; | 71 | IP_Port ip_port3; |
72 | uint8_t node_public_key3[crypto_box_PUBLICKEYBYTES]; | ||
68 | 73 | ||
69 | uint32_t path_num; | 74 | uint32_t path_num; |
70 | } Onion_Path; | 75 | } Onion_Path; |
@@ -80,6 +85,13 @@ typedef struct { | |||
80 | */ | 85 | */ |
81 | int create_onion_path(const DHT *dht, Onion_Path *new_path, const Node_format *nodes); | 86 | int create_onion_path(const DHT *dht, Onion_Path *new_path, const Node_format *nodes); |
82 | 87 | ||
88 | /* Dump nodes in onion path to nodes of length num_nodes; | ||
89 | * | ||
90 | * return -1 on failure. | ||
91 | * return 0 on success. | ||
92 | */ | ||
93 | int onion_path_to_nodes(Node_format *nodes, unsigned int num_nodes, const Onion_Path *path); | ||
94 | |||
83 | /* Create a onion packet. | 95 | /* Create a onion packet. |
84 | * | 96 | * |
85 | * Use Onion_Path path to create packet for data of length to dest. | 97 | * Use Onion_Path path to create packet for data of length to dest. |
@@ -90,7 +102,7 @@ int create_onion_path(const DHT *dht, Onion_Path *new_path, const Node_format *n | |||
90 | * return length of created packet on success. | 102 | * return length of created packet on success. |
91 | */ | 103 | */ |
92 | int create_onion_packet(uint8_t *packet, uint16_t max_packet_length, const Onion_Path *path, IP_Port dest, | 104 | int create_onion_packet(uint8_t *packet, uint16_t max_packet_length, const Onion_Path *path, IP_Port dest, |
93 | const uint8_t *data, uint32_t length); | 105 | const uint8_t *data, uint16_t length); |
94 | 106 | ||
95 | 107 | ||
96 | /* Create a onion packet to be sent over tcp. | 108 | /* Create a onion packet to be sent over tcp. |
@@ -103,7 +115,7 @@ int create_onion_packet(uint8_t *packet, uint16_t max_packet_length, const Onion | |||
103 | * return length of created packet on success. | 115 | * return length of created packet on success. |
104 | */ | 116 | */ |
105 | int create_onion_packet_tcp(uint8_t *packet, uint16_t max_packet_length, const Onion_Path *path, IP_Port dest, | 117 | int create_onion_packet_tcp(uint8_t *packet, uint16_t max_packet_length, const Onion_Path *path, IP_Port dest, |
106 | const uint8_t *data, uint32_t length); | 118 | const uint8_t *data, uint16_t length); |
107 | 119 | ||
108 | /* Create and send a onion packet. | 120 | /* Create and send a onion packet. |
109 | * | 121 | * |
@@ -113,7 +125,7 @@ int create_onion_packet_tcp(uint8_t *packet, uint16_t max_packet_length, const O | |||
113 | * return -1 on failure. | 125 | * return -1 on failure. |
114 | * return 0 on success. | 126 | * return 0 on success. |
115 | */ | 127 | */ |
116 | int send_onion_packet(Networking_Core *net, const Onion_Path *path, IP_Port dest, const uint8_t *data, uint32_t length); | 128 | int send_onion_packet(Networking_Core *net, const Onion_Path *path, IP_Port dest, const uint8_t *data, uint16_t length); |
117 | 129 | ||
118 | /* Create and send a onion response sent initially to dest with. | 130 | /* Create and send a onion response sent initially to dest with. |
119 | * Maximum length of data is ONION_RESPONSE_MAX_DATA_SIZE. | 131 | * Maximum length of data is ONION_RESPONSE_MAX_DATA_SIZE. |
@@ -121,7 +133,7 @@ int send_onion_packet(Networking_Core *net, const Onion_Path *path, IP_Port dest | |||
121 | * return -1 on failure. | 133 | * return -1 on failure. |
122 | * return 0 on success. | 134 | * return 0 on success. |
123 | */ | 135 | */ |
124 | int send_onion_response(Networking_Core *net, IP_Port dest, const uint8_t *data, uint32_t length, const uint8_t *ret); | 136 | int send_onion_response(Networking_Core *net, IP_Port dest, const uint8_t *data, uint16_t length, const uint8_t *ret); |
125 | 137 | ||
126 | /* Function to handle/send received decrypted versions of the packet sent with send_onion_packet. | 138 | /* Function to handle/send received decrypted versions of the packet sent with send_onion_packet. |
127 | * | 139 | * |
@@ -133,11 +145,11 @@ int send_onion_response(Networking_Core *net, IP_Port dest, const uint8_t *data, | |||
133 | * Source family must be set to something else than AF_INET6 or AF_INET so that the callback gets called | 145 | * Source family must be set to something else than AF_INET6 or AF_INET so that the callback gets called |
134 | * when the response is received. | 146 | * when the response is received. |
135 | */ | 147 | */ |
136 | int onion_send_1(const Onion *onion, const uint8_t *plain, uint32_t len, IP_Port source, const uint8_t *nonce); | 148 | int onion_send_1(const Onion *onion, const uint8_t *plain, uint16_t len, IP_Port source, const uint8_t *nonce); |
137 | 149 | ||
138 | /* Set the callback to be called when the dest ip_port doesn't have AF_INET6 or AF_INET as the family. | 150 | /* Set the callback to be called when the dest ip_port doesn't have AF_INET6 or AF_INET as the family. |
139 | * | 151 | * |
140 | * Format: function(void *object, IP_Port dest, uint8_t *data, uint32_t length) | 152 | * Format: function(void *object, IP_Port dest, uint8_t *data, uint16_t length) |
141 | */ | 153 | */ |
142 | void set_callback_handle_recv_1(Onion *onion, int (*function)(void *, IP_Port, const uint8_t *, uint16_t), | 154 | void set_callback_handle_recv_1(Onion *onion, int (*function)(void *, IP_Port, const uint8_t *, uint16_t), |
143 | void *object); | 155 | void *object); |
diff --git a/toxcore/onion_announce.c b/toxcore/onion_announce.c index f5c38eea..25f3e0f8 100644 --- a/toxcore/onion_announce.c +++ b/toxcore/onion_announce.c | |||
@@ -108,8 +108,8 @@ int create_data_request(uint8_t *packet, uint16_t max_packet_length, const uint8 | |||
108 | int len = encrypt_data(encrypt_public_key, random_secret_key, packet + 1 + crypto_box_PUBLICKEYBYTES, data, length, | 108 | int len = encrypt_data(encrypt_public_key, random_secret_key, packet + 1 + crypto_box_PUBLICKEYBYTES, data, length, |
109 | packet + 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES); | 109 | packet + 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES); |
110 | 110 | ||
111 | if (1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + | 111 | if (1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + len != DATA_REQUEST_MIN_SIZE + |
112 | (uint32_t)len != DATA_REQUEST_MIN_SIZE + length) | 112 | length) |
113 | return -1; | 113 | return -1; |
114 | 114 | ||
115 | return DATA_REQUEST_MIN_SIZE + length; | 115 | return DATA_REQUEST_MIN_SIZE + length; |
@@ -134,7 +134,7 @@ int send_announce_request(Networking_Core *net, const Onion_Path *path, Node_for | |||
134 | uint64_t sendback_data) | 134 | uint64_t sendback_data) |
135 | { | 135 | { |
136 | uint8_t request[ONION_ANNOUNCE_REQUEST_SIZE]; | 136 | uint8_t request[ONION_ANNOUNCE_REQUEST_SIZE]; |
137 | int len = create_announce_request(request, sizeof(request), dest.client_id, public_key, secret_key, ping_id, client_id, | 137 | int len = create_announce_request(request, sizeof(request), dest.public_key, public_key, secret_key, ping_id, client_id, |
138 | data_public_key, sendback_data); | 138 | data_public_key, sendback_data); |
139 | 139 | ||
140 | if (len != sizeof(request)) | 140 | if (len != sizeof(request)) |
@@ -178,6 +178,9 @@ int send_data_request(Networking_Core *net, const Onion_Path *path, IP_Port dest | |||
178 | uint8_t packet[ONION_MAX_PACKET_SIZE]; | 178 | uint8_t packet[ONION_MAX_PACKET_SIZE]; |
179 | len = create_onion_packet(packet, sizeof(packet), path, dest, request, len); | 179 | len = create_onion_packet(packet, sizeof(packet), path, dest, request, len); |
180 | 180 | ||
181 | if (len == -1) | ||
182 | return -1; | ||
183 | |||
181 | if (sendpacket(net, path->ip_port1, packet, len) != len) | 184 | if (sendpacket(net, path->ip_port1, packet, len) != len) |
182 | return -1; | 185 | return -1; |
183 | 186 | ||
@@ -204,7 +207,7 @@ static void generate_ping_id(const Onion_Announce *onion_a, uint64_t time, const | |||
204 | */ | 207 | */ |
205 | static int in_entries(const Onion_Announce *onion_a, const uint8_t *public_key) | 208 | static int in_entries(const Onion_Announce *onion_a, const uint8_t *public_key) |
206 | { | 209 | { |
207 | uint32_t i; | 210 | unsigned int i; |
208 | 211 | ||
209 | for (i = 0; i < ONION_ANNOUNCE_MAX_ENTRIES; ++i) { | 212 | for (i = 0; i < ONION_ANNOUNCE_MAX_ENTRIES; ++i) { |
210 | if (!is_timeout(onion_a->entries[i].time, ONION_ANNOUNCE_TIMEOUT) | 213 | if (!is_timeout(onion_a->entries[i].time, ONION_ANNOUNCE_TIMEOUT) |
@@ -255,7 +258,7 @@ static int add_to_entries(Onion_Announce *onion_a, IP_Port ret_ip_port, const ui | |||
255 | 258 | ||
256 | int pos = in_entries(onion_a, public_key); | 259 | int pos = in_entries(onion_a, public_key); |
257 | 260 | ||
258 | uint32_t i; | 261 | unsigned int i; |
259 | 262 | ||
260 | if (pos == -1) { | 263 | if (pos == -1) { |
261 | for (i = 0; i < ONION_ANNOUNCE_MAX_ENTRIES; ++i) { | 264 | for (i = 0; i < ONION_ANNOUNCE_MAX_ENTRIES; ++i) { |
@@ -283,7 +286,7 @@ static int add_to_entries(Onion_Announce *onion_a, IP_Port ret_ip_port, const ui | |||
283 | return in_entries(onion_a, public_key); | 286 | return in_entries(onion_a, public_key); |
284 | } | 287 | } |
285 | 288 | ||
286 | static int handle_announce_request(void *object, IP_Port source, const uint8_t *packet, uint32_t length) | 289 | static int handle_announce_request(void *object, IP_Port source, const uint8_t *packet, uint16_t length) |
287 | { | 290 | { |
288 | Onion_Announce *onion_a = object; | 291 | Onion_Announce *onion_a = object; |
289 | 292 | ||
@@ -322,8 +325,8 @@ static int handle_announce_request(void *object, IP_Port source, const uint8_t * | |||
322 | 325 | ||
323 | /*Respond with a announce response packet*/ | 326 | /*Respond with a announce response packet*/ |
324 | Node_format nodes_list[MAX_SENT_NODES]; | 327 | Node_format nodes_list[MAX_SENT_NODES]; |
325 | uint32_t num_nodes = get_close_nodes(onion_a->dht, plain + ONION_PING_ID_SIZE, nodes_list, 0, LAN_ip(source.ip) == 0, | 328 | unsigned int num_nodes = get_close_nodes(onion_a->dht, plain + ONION_PING_ID_SIZE, nodes_list, 0, |
326 | 1); | 329 | LAN_ip(source.ip) == 0, 1); |
327 | uint8_t nonce[crypto_box_NONCEBYTES]; | 330 | uint8_t nonce[crypto_box_NONCEBYTES]; |
328 | random_nonce(nonce); | 331 | random_nonce(nonce); |
329 | 332 | ||
@@ -333,10 +336,14 @@ static int handle_announce_request(void *object, IP_Port source, const uint8_t * | |||
333 | pl[0] = 0; | 336 | pl[0] = 0; |
334 | memcpy(pl + 1, ping_id2, ONION_PING_ID_SIZE); | 337 | memcpy(pl + 1, ping_id2, ONION_PING_ID_SIZE); |
335 | } else { | 338 | } else { |
336 | if (memcmp(onion_a->entries[index].public_key, packet_public_key, crypto_box_PUBLICKEYBYTES) == 0 | 339 | if (memcmp(onion_a->entries[index].public_key, packet_public_key, crypto_box_PUBLICKEYBYTES) == 0) { |
337 | && memcmp(onion_a->entries[index].data_public_key, data_public_key, crypto_box_PUBLICKEYBYTES) != 0) { | 340 | if (memcmp(onion_a->entries[index].data_public_key, data_public_key, crypto_box_PUBLICKEYBYTES) != 0) { |
338 | pl[0] = 0; | 341 | pl[0] = 0; |
339 | memcpy(pl + 1, ping_id2, ONION_PING_ID_SIZE); | 342 | memcpy(pl + 1, ping_id2, ONION_PING_ID_SIZE); |
343 | } else { | ||
344 | pl[0] = 2; | ||
345 | memcpy(pl + 1, ping_id2, ONION_PING_ID_SIZE); | ||
346 | } | ||
340 | } else { | 347 | } else { |
341 | pl[0] = 1; | 348 | pl[0] = 1; |
342 | memcpy(pl + 1, onion_a->entries[index].data_public_key, crypto_box_PUBLICKEYBYTES); | 349 | memcpy(pl + 1, onion_a->entries[index].data_public_key, crypto_box_PUBLICKEYBYTES); |
@@ -372,7 +379,7 @@ static int handle_announce_request(void *object, IP_Port source, const uint8_t * | |||
372 | return 0; | 379 | return 0; |
373 | } | 380 | } |
374 | 381 | ||
375 | static int handle_data_request(void *object, IP_Port source, const uint8_t *packet, uint32_t length) | 382 | static int handle_data_request(void *object, IP_Port source, const uint8_t *packet, uint16_t length) |
376 | { | 383 | { |
377 | Onion_Announce *onion_a = object; | 384 | Onion_Announce *onion_a = object; |
378 | 385 | ||
diff --git a/toxcore/onion_announce.h b/toxcore/onion_announce.h index f2ba3715..36ffe767 100644 --- a/toxcore/onion_announce.h +++ b/toxcore/onion_announce.h | |||
@@ -25,7 +25,7 @@ | |||
25 | 25 | ||
26 | #include "onion.h" | 26 | #include "onion.h" |
27 | 27 | ||
28 | #define ONION_ANNOUNCE_MAX_ENTRIES 48 | 28 | #define ONION_ANNOUNCE_MAX_ENTRIES 64 |
29 | #define ONION_ANNOUNCE_TIMEOUT 300 | 29 | #define ONION_ANNOUNCE_TIMEOUT 300 |
30 | #define ONION_PING_ID_SIZE crypto_hash_sha256_BYTES | 30 | #define ONION_PING_ID_SIZE crypto_hash_sha256_BYTES |
31 | 31 | ||
diff --git a/toxcore/onion_client.c b/toxcore/onion_client.c index fb725ef6..3643cb2f 100644 --- a/toxcore/onion_client.c +++ b/toxcore/onion_client.c | |||
@@ -33,12 +33,42 @@ | |||
33 | #define ANNOUNCE_ARRAY_SIZE 256 | 33 | #define ANNOUNCE_ARRAY_SIZE 256 |
34 | #define ANNOUNCE_TIMEOUT 10 | 34 | #define ANNOUNCE_TIMEOUT 10 |
35 | 35 | ||
36 | /* Add a node to the path_nodes bootstrap array. | ||
37 | * | ||
38 | * return -1 on failure | ||
39 | * return 0 on success | ||
40 | */ | ||
41 | int onion_add_bs_path_node(Onion_Client *onion_c, IP_Port ip_port, const uint8_t *public_key) | ||
42 | { | ||
43 | if (ip_port.ip.family != AF_INET && ip_port.ip.family != AF_INET6) | ||
44 | return -1; | ||
45 | |||
46 | unsigned int i; | ||
47 | |||
48 | for (i = 0; i < MAX_PATH_NODES; ++i) { | ||
49 | if (memcmp(public_key, onion_c->path_nodes_bs[i].public_key, crypto_box_PUBLICKEYBYTES) == 0) | ||
50 | return -1; | ||
51 | } | ||
52 | |||
53 | onion_c->path_nodes_bs[onion_c->path_nodes_index_bs % MAX_PATH_NODES].ip_port = ip_port; | ||
54 | memcpy(onion_c->path_nodes_bs[onion_c->path_nodes_index_bs % MAX_PATH_NODES].public_key, public_key, | ||
55 | crypto_box_PUBLICKEYBYTES); | ||
56 | |||
57 | uint16_t last = onion_c->path_nodes_index_bs; | ||
58 | ++onion_c->path_nodes_index_bs; | ||
59 | |||
60 | if (onion_c->path_nodes_index_bs < last) | ||
61 | onion_c->path_nodes_index_bs = MAX_PATH_NODES + 1; | ||
62 | |||
63 | return 0; | ||
64 | } | ||
65 | |||
36 | /* Add a node to the path_nodes array. | 66 | /* Add a node to the path_nodes array. |
37 | * | 67 | * |
38 | * return -1 on failure | 68 | * return -1 on failure |
39 | * return 0 on success | 69 | * return 0 on success |
40 | */ | 70 | */ |
41 | int onion_add_path_node(Onion_Client *onion_c, IP_Port ip_port, const uint8_t *client_id) | 71 | static int onion_add_path_node(Onion_Client *onion_c, IP_Port ip_port, const uint8_t *public_key) |
42 | { | 72 | { |
43 | if (ip_port.ip.family != AF_INET && ip_port.ip.family != AF_INET6) | 73 | if (ip_port.ip.family != AF_INET && ip_port.ip.family != AF_INET6) |
44 | return -1; | 74 | return -1; |
@@ -46,12 +76,13 @@ int onion_add_path_node(Onion_Client *onion_c, IP_Port ip_port, const uint8_t *c | |||
46 | unsigned int i; | 76 | unsigned int i; |
47 | 77 | ||
48 | for (i = 0; i < MAX_PATH_NODES; ++i) { | 78 | for (i = 0; i < MAX_PATH_NODES; ++i) { |
49 | if (memcmp(client_id, onion_c->path_nodes[i].client_id, crypto_box_PUBLICKEYBYTES) == 0) | 79 | if (memcmp(public_key, onion_c->path_nodes[i].public_key, crypto_box_PUBLICKEYBYTES) == 0) |
50 | return -1; | 80 | return -1; |
51 | } | 81 | } |
52 | 82 | ||
53 | onion_c->path_nodes[onion_c->path_nodes_index % MAX_PATH_NODES].ip_port = ip_port; | 83 | onion_c->path_nodes[onion_c->path_nodes_index % MAX_PATH_NODES].ip_port = ip_port; |
54 | memcpy(onion_c->path_nodes[onion_c->path_nodes_index % MAX_PATH_NODES].client_id, client_id, crypto_box_PUBLICKEYBYTES); | 84 | memcpy(onion_c->path_nodes[onion_c->path_nodes_index % MAX_PATH_NODES].public_key, public_key, |
85 | crypto_box_PUBLICKEYBYTES); | ||
55 | 86 | ||
56 | uint16_t last = onion_c->path_nodes_index; | 87 | uint16_t last = onion_c->path_nodes_index; |
57 | ++onion_c->path_nodes_index; | 88 | ++onion_c->path_nodes_index; |
@@ -103,20 +134,39 @@ static uint16_t random_nodes_path_onion(const Onion_Client *onion_c, Node_format | |||
103 | 134 | ||
104 | //if (DHT_non_lan_connected(onion_c->dht)) { | 135 | //if (DHT_non_lan_connected(onion_c->dht)) { |
105 | if (DHT_isconnected(onion_c->dht)) { | 136 | if (DHT_isconnected(onion_c->dht)) { |
106 | if (num_nodes < 3) | 137 | if (num_nodes == 0) |
107 | return random_nodes_path(onion_c->dht, nodes, max_num); | 138 | return 0; |
108 | 139 | ||
109 | for (i = 0; i < max_num; ++i) { | 140 | for (i = 0; i < max_num; ++i) { |
110 | nodes[i] = onion_c->path_nodes[rand() % num_nodes]; | 141 | nodes[i] = onion_c->path_nodes[rand() % num_nodes]; |
111 | } | 142 | } |
112 | } else { | 143 | } else { |
113 | if (num_nodes == 0) | 144 | int random_tcp = get_random_tcp_con_number(onion_c->c); |
145 | |||
146 | if (random_tcp == -1) { | ||
114 | return 0; | 147 | return 0; |
148 | } | ||
115 | 149 | ||
116 | nodes[0].ip_port.ip.family = TCP_FAMILY; | 150 | if (num_nodes >= 2) { |
151 | nodes[0].ip_port.ip.family = TCP_FAMILY; | ||
152 | nodes[0].ip_port.ip.ip4.uint32 = random_tcp; | ||
117 | 153 | ||
118 | for (i = 1; i < max_num; ++i) { | 154 | for (i = 1; i < max_num; ++i) { |
119 | nodes[i] = onion_c->path_nodes[rand() % num_nodes]; | 155 | nodes[i] = onion_c->path_nodes[rand() % num_nodes]; |
156 | } | ||
157 | } else { | ||
158 | unsigned int num_nodes_bs = (onion_c->path_nodes_index_bs < MAX_PATH_NODES) ? onion_c->path_nodes_index_bs : | ||
159 | MAX_PATH_NODES; | ||
160 | |||
161 | if (num_nodes_bs == 0) | ||
162 | return 0; | ||
163 | |||
164 | nodes[0].ip_port.ip.family = TCP_FAMILY; | ||
165 | nodes[0].ip_port.ip.ip4.uint32 = random_tcp; | ||
166 | |||
167 | for (i = 1; i < max_num; ++i) { | ||
168 | nodes[i] = onion_c->path_nodes_bs[rand() % num_nodes_bs]; | ||
169 | } | ||
120 | } | 170 | } |
121 | } | 171 | } |
122 | 172 | ||
@@ -129,7 +179,7 @@ static uint16_t random_nodes_path_onion(const Onion_Client *onion_c, Node_format | |||
129 | */ | 179 | */ |
130 | static int is_path_used(const Onion_Client_Paths *onion_paths, const Node_format *nodes) | 180 | static int is_path_used(const Onion_Client_Paths *onion_paths, const Node_format *nodes) |
131 | { | 181 | { |
132 | uint32_t i; | 182 | unsigned int i; |
133 | 183 | ||
134 | for (i = 0; i < NUMBER_ONION_PATHS; ++i) { | 184 | for (i = 0; i < NUMBER_ONION_PATHS; ++i) { |
135 | if (is_timeout(onion_paths->last_path_success[i], ONION_PATH_TIMEOUT)) { | 185 | if (is_timeout(onion_paths->last_path_success[i], ONION_PATH_TIMEOUT)) { |
@@ -149,7 +199,7 @@ static int is_path_used(const Onion_Client_Paths *onion_paths, const Node_format | |||
149 | } | 199 | } |
150 | 200 | ||
151 | /* Create a new path or use an old suitable one (if pathnum is valid) | 201 | /* Create a new path or use an old suitable one (if pathnum is valid) |
152 | * or a rondom one from onion_paths. | 202 | * or a random one from onion_paths. |
153 | * | 203 | * |
154 | * return -1 on failure | 204 | * return -1 on failure |
155 | * return 0 on success | 205 | * return 0 on success |
@@ -162,7 +212,8 @@ static int random_path(const Onion_Client *onion_c, Onion_Client_Paths *onion_pa | |||
162 | if (pathnum >= NUMBER_ONION_PATHS) | 212 | if (pathnum >= NUMBER_ONION_PATHS) |
163 | pathnum = rand() % NUMBER_ONION_PATHS; | 213 | pathnum = rand() % NUMBER_ONION_PATHS; |
164 | 214 | ||
165 | if (is_timeout(onion_paths->last_path_success[pathnum], ONION_PATH_TIMEOUT) | 215 | if ((onion_paths->last_path_success[pathnum] + ONION_PATH_TIMEOUT < onion_paths->last_path_used[pathnum] |
216 | && onion_paths->last_path_used_times[pathnum] >= ONION_PATH_MAX_NO_RESPONSE_USES) | ||
166 | || is_timeout(onion_paths->path_creation_time[pathnum], ONION_PATH_MAX_LIFETIME)) { | 217 | || is_timeout(onion_paths->path_creation_time[pathnum], ONION_PATH_MAX_LIFETIME)) { |
167 | Node_format nodes[3]; | 218 | Node_format nodes[3]; |
168 | 219 | ||
@@ -177,6 +228,8 @@ static int random_path(const Onion_Client *onion_c, Onion_Client_Paths *onion_pa | |||
177 | 228 | ||
178 | onion_paths->last_path_success[pathnum] = unix_time() + ONION_PATH_FIRST_TIMEOUT - ONION_PATH_TIMEOUT; | 229 | onion_paths->last_path_success[pathnum] = unix_time() + ONION_PATH_FIRST_TIMEOUT - ONION_PATH_TIMEOUT; |
179 | onion_paths->path_creation_time[pathnum] = unix_time(); | 230 | onion_paths->path_creation_time[pathnum] = unix_time(); |
231 | onion_paths->last_path_used_times[pathnum] = ONION_PATH_MAX_NO_RESPONSE_USES / 2; | ||
232 | |||
180 | uint32_t path_num = rand(); | 233 | uint32_t path_num = rand(); |
181 | path_num /= NUMBER_ONION_PATHS; | 234 | path_num /= NUMBER_ONION_PATHS; |
182 | path_num *= NUMBER_ONION_PATHS; | 235 | path_num *= NUMBER_ONION_PATHS; |
@@ -188,6 +241,8 @@ static int random_path(const Onion_Client *onion_c, Onion_Client_Paths *onion_pa | |||
188 | } | 241 | } |
189 | } | 242 | } |
190 | 243 | ||
244 | ++onion_paths->last_path_used_times[pathnum]; | ||
245 | onion_paths->last_path_used[pathnum] = unix_time(); | ||
191 | memcpy(path, &onion_paths->paths[pathnum], sizeof(Onion_Path)); | 246 | memcpy(path, &onion_paths->paths[pathnum], sizeof(Onion_Path)); |
192 | return 0; | 247 | return 0; |
193 | } | 248 | } |
@@ -203,13 +258,26 @@ static uint32_t set_path_timeouts(Onion_Client *onion_c, uint32_t num, uint32_t | |||
203 | Onion_Client_Paths *onion_paths; | 258 | Onion_Client_Paths *onion_paths; |
204 | 259 | ||
205 | if (num == 0) { | 260 | if (num == 0) { |
206 | onion_paths = &onion_c->onion_paths; | 261 | onion_paths = &onion_c->onion_paths_self; |
207 | } else { | 262 | } else { |
208 | onion_paths = &onion_c->friends_list[num - 1].onion_paths; | 263 | onion_paths = &onion_c->onion_paths_friends; |
209 | } | 264 | } |
210 | 265 | ||
211 | if (onion_paths->paths[path_num % NUMBER_ONION_PATHS].path_num == path_num) { | 266 | if (onion_paths->paths[path_num % NUMBER_ONION_PATHS].path_num == path_num) { |
212 | onion_paths->last_path_success[path_num % NUMBER_ONION_PATHS] = unix_time(); | 267 | onion_paths->last_path_success[path_num % NUMBER_ONION_PATHS] = unix_time(); |
268 | onion_paths->last_path_used_times[path_num % NUMBER_ONION_PATHS] = 0; | ||
269 | |||
270 | unsigned int path_len = 3; | ||
271 | Node_format nodes[path_len]; | ||
272 | |||
273 | if (onion_path_to_nodes(nodes, path_len, &onion_paths->paths[path_num % NUMBER_ONION_PATHS]) == 0) { | ||
274 | unsigned int i; | ||
275 | |||
276 | for (i = 0; i < path_len; ++i) { | ||
277 | onion_add_path_node(onion_c, nodes[i].ip_port, nodes[i].public_key); | ||
278 | } | ||
279 | } | ||
280 | |||
213 | return path_num % NUMBER_ONION_PATHS; | 281 | return path_num % NUMBER_ONION_PATHS; |
214 | } | 282 | } |
215 | 283 | ||
@@ -222,7 +290,7 @@ static uint32_t set_path_timeouts(Onion_Client *onion_c, uint32_t num, uint32_t | |||
222 | * return 0 on success. | 290 | * return 0 on success. |
223 | */ | 291 | */ |
224 | static int send_onion_packet_tcp_udp(const Onion_Client *onion_c, const Onion_Path *path, IP_Port dest, | 292 | static int send_onion_packet_tcp_udp(const Onion_Client *onion_c, const Onion_Path *path, IP_Port dest, |
225 | const uint8_t *data, uint32_t length) | 293 | const uint8_t *data, uint16_t length) |
226 | { | 294 | { |
227 | if (path->ip_port1.ip.family == AF_INET || path->ip_port1.ip.family == AF_INET6) { | 295 | if (path->ip_port1.ip.family == AF_INET || path->ip_port1.ip.family == AF_INET6) { |
228 | uint8_t packet[ONION_MAX_PACKET_SIZE]; | 296 | uint8_t packet[ONION_MAX_PACKET_SIZE]; |
@@ -231,7 +299,7 @@ static int send_onion_packet_tcp_udp(const Onion_Client *onion_c, const Onion_Pa | |||
231 | if (len == -1) | 299 | if (len == -1) |
232 | return -1; | 300 | return -1; |
233 | 301 | ||
234 | if ((uint32_t)sendpacket(onion_c->net, path->ip_port1, packet, len) != len) | 302 | if (sendpacket(onion_c->net, path->ip_port1, packet, len) != len) |
235 | return -1; | 303 | return -1; |
236 | 304 | ||
237 | return 0; | 305 | return 0; |
@@ -242,7 +310,7 @@ static int send_onion_packet_tcp_udp(const Onion_Client *onion_c, const Onion_Pa | |||
242 | if (len == -1) | 310 | if (len == -1) |
243 | return -1; | 311 | return -1; |
244 | 312 | ||
245 | return send_tcp_onion_request(onion_c->c, packet, len); | 313 | return send_tcp_onion_request(onion_c->c, path->ip_port1.ip.ip4.uint32, packet, len); |
246 | } else { | 314 | } else { |
247 | return -1; | 315 | return -1; |
248 | } | 316 | } |
@@ -318,10 +386,10 @@ static int client_send_announce_request(Onion_Client *onion_c, uint32_t num, IP_ | |||
318 | Onion_Path path; | 386 | Onion_Path path; |
319 | 387 | ||
320 | if (num == 0) { | 388 | if (num == 0) { |
321 | if (random_path(onion_c, &onion_c->onion_paths, pathnum, &path) == -1) | 389 | if (random_path(onion_c, &onion_c->onion_paths_self, pathnum, &path) == -1) |
322 | return -1; | 390 | return -1; |
323 | } else { | 391 | } else { |
324 | if (random_path(onion_c, &onion_c->friends_list[num - 1].onion_paths, pathnum, &path) == -1) | 392 | if (random_path(onion_c, &onion_c->onion_paths_friends, pathnum, &path) == -1) |
325 | return -1; | 393 | return -1; |
326 | } | 394 | } |
327 | 395 | ||
@@ -333,9 +401,6 @@ static int client_send_announce_request(Onion_Client *onion_c, uint32_t num, IP_ | |||
333 | if (ping_id == NULL) | 401 | if (ping_id == NULL) |
334 | ping_id = zero_ping_id; | 402 | ping_id = zero_ping_id; |
335 | 403 | ||
336 | Node_format dest_node; | ||
337 | dest_node.ip_port = dest; | ||
338 | memcpy(dest_node.client_id, dest_pubkey, crypto_box_PUBLICKEYBYTES); | ||
339 | uint8_t request[ONION_ANNOUNCE_REQUEST_SIZE]; | 404 | uint8_t request[ONION_ANNOUNCE_REQUEST_SIZE]; |
340 | int len; | 405 | int len; |
341 | 406 | ||
@@ -345,7 +410,7 @@ static int client_send_announce_request(Onion_Client *onion_c, uint32_t num, IP_ | |||
345 | 410 | ||
346 | } else { | 411 | } else { |
347 | len = create_announce_request(request, sizeof(request), dest_pubkey, onion_c->friends_list[num - 1].temp_public_key, | 412 | len = create_announce_request(request, sizeof(request), dest_pubkey, onion_c->friends_list[num - 1].temp_public_key, |
348 | onion_c->friends_list[num - 1].temp_secret_key, ping_id, onion_c->friends_list[num - 1].real_client_id, zero_ping_id, | 413 | onion_c->friends_list[num - 1].temp_secret_key, ping_id, onion_c->friends_list[num - 1].real_public_key, zero_ping_id, |
349 | sendback); | 414 | sendback); |
350 | } | 415 | } |
351 | 416 | ||
@@ -374,7 +439,7 @@ static int cmp_entry(const void *a, const void *b) | |||
374 | if (t2) | 439 | if (t2) |
375 | return 1; | 440 | return 1; |
376 | 441 | ||
377 | int close = id_closest(cmp_public_key, entry1.client_id, entry2.client_id); | 442 | int close = id_closest(cmp_public_key, entry1.public_key, entry2.public_key); |
378 | 443 | ||
379 | if (close == 1) | 444 | if (close == 1) |
380 | return 1; | 445 | return 1; |
@@ -398,28 +463,31 @@ static int client_add_to_list(Onion_Client *onion_c, uint32_t num, const uint8_t | |||
398 | list_nodes = onion_c->clients_announce_list; | 463 | list_nodes = onion_c->clients_announce_list; |
399 | reference_id = onion_c->c->self_public_key; | 464 | reference_id = onion_c->c->self_public_key; |
400 | 465 | ||
401 | if (is_stored && memcmp(pingid_or_key, onion_c->temp_public_key, crypto_box_PUBLICKEYBYTES) != 0) { | 466 | if (is_stored == 1 && memcmp(pingid_or_key, onion_c->temp_public_key, crypto_box_PUBLICKEYBYTES) != 0) { |
402 | is_stored = 0; | 467 | is_stored = 0; |
403 | } | 468 | } |
404 | 469 | ||
405 | } else { | 470 | } else { |
471 | if (is_stored >= 2) | ||
472 | return -1; | ||
473 | |||
406 | list_nodes = onion_c->friends_list[num - 1].clients_list; | 474 | list_nodes = onion_c->friends_list[num - 1].clients_list; |
407 | reference_id = onion_c->friends_list[num - 1].real_client_id; | 475 | reference_id = onion_c->friends_list[num - 1].real_public_key; |
408 | } | 476 | } |
409 | 477 | ||
410 | memcpy(cmp_public_key, reference_id, crypto_box_PUBLICKEYBYTES); | 478 | memcpy(cmp_public_key, reference_id, crypto_box_PUBLICKEYBYTES); |
411 | qsort(list_nodes, MAX_ONION_CLIENTS, sizeof(Onion_Node), cmp_entry); | 479 | qsort(list_nodes, MAX_ONION_CLIENTS, sizeof(Onion_Node), cmp_entry); |
412 | 480 | ||
413 | int index = -1, stored = 0; | 481 | int index = -1, stored = 0; |
414 | uint32_t i; | 482 | unsigned int i; |
415 | 483 | ||
416 | if (is_timeout(list_nodes[0].timestamp, ONION_NODE_TIMEOUT) | 484 | if (is_timeout(list_nodes[0].timestamp, ONION_NODE_TIMEOUT) |
417 | || id_closest(reference_id, list_nodes[0].client_id, public_key) == 2) { | 485 | || id_closest(reference_id, list_nodes[0].public_key, public_key) == 2) { |
418 | index = 0; | 486 | index = 0; |
419 | } | 487 | } |
420 | 488 | ||
421 | for (i = 0; i < MAX_ONION_CLIENTS; ++i) { | 489 | for (i = 0; i < MAX_ONION_CLIENTS; ++i) { |
422 | if (memcmp(list_nodes[i].client_id, public_key, crypto_box_PUBLICKEYBYTES) == 0) { | 490 | if (memcmp(list_nodes[i].public_key, public_key, crypto_box_PUBLICKEYBYTES) == 0) { |
423 | index = i; | 491 | index = i; |
424 | stored = 1; | 492 | stored = 1; |
425 | break; | 493 | break; |
@@ -429,13 +497,13 @@ static int client_add_to_list(Onion_Client *onion_c, uint32_t num, const uint8_t | |||
429 | if (index == -1) | 497 | if (index == -1) |
430 | return 0; | 498 | return 0; |
431 | 499 | ||
432 | memcpy(list_nodes[index].client_id, public_key, CLIENT_ID_SIZE); | 500 | memcpy(list_nodes[index].public_key, public_key, crypto_box_PUBLICKEYBYTES); |
433 | list_nodes[index].ip_port = ip_port; | 501 | list_nodes[index].ip_port = ip_port; |
434 | 502 | ||
435 | //TODO: remove this and find a better source of nodes to use for paths. | 503 | //TODO: remove this and find a better source of nodes to use for paths. |
436 | onion_add_path_node(onion_c, ip_port, public_key); | 504 | onion_add_path_node(onion_c, ip_port, public_key); |
437 | 505 | ||
438 | if (is_stored) { | 506 | if (is_stored == 1) { |
439 | memcpy(list_nodes[index].data_public_key, pingid_or_key, crypto_box_PUBLICKEYBYTES); | 507 | memcpy(list_nodes[index].data_public_key, pingid_or_key, crypto_box_PUBLICKEYBYTES); |
440 | } else { | 508 | } else { |
441 | memcpy(list_nodes[index].ping_id, pingid_or_key, ONION_PING_ID_SIZE); | 509 | memcpy(list_nodes[index].ping_id, pingid_or_key, ONION_PING_ID_SIZE); |
@@ -451,17 +519,17 @@ static int client_add_to_list(Onion_Client *onion_c, uint32_t num, const uint8_t | |||
451 | return 0; | 519 | return 0; |
452 | } | 520 | } |
453 | 521 | ||
454 | static int good_to_ping(Last_Pinged *last_pinged, uint8_t *last_pinged_index, const uint8_t *client_id) | 522 | static int good_to_ping(Last_Pinged *last_pinged, uint8_t *last_pinged_index, const uint8_t *public_key) |
455 | { | 523 | { |
456 | uint32_t i; | 524 | unsigned int i; |
457 | 525 | ||
458 | for (i = 0; i < MAX_STORED_PINGED_NODES; ++i) { | 526 | for (i = 0; i < MAX_STORED_PINGED_NODES; ++i) { |
459 | if (!is_timeout(last_pinged[i].timestamp, MIN_NODE_PING_TIME)) | 527 | if (!is_timeout(last_pinged[i].timestamp, MIN_NODE_PING_TIME)) |
460 | if (memcmp(last_pinged[i].client_id, client_id, crypto_box_PUBLICKEYBYTES) == 0) | 528 | if (memcmp(last_pinged[i].public_key, public_key, crypto_box_PUBLICKEYBYTES) == 0) |
461 | return 0; | 529 | return 0; |
462 | } | 530 | } |
463 | 531 | ||
464 | memcpy(last_pinged[*last_pinged_index % MAX_STORED_PINGED_NODES].client_id, client_id, crypto_box_PUBLICKEYBYTES); | 532 | memcpy(last_pinged[*last_pinged_index % MAX_STORED_PINGED_NODES].public_key, public_key, crypto_box_PUBLICKEYBYTES); |
465 | last_pinged[*last_pinged_index % MAX_STORED_PINGED_NODES].timestamp = unix_time(); | 533 | last_pinged[*last_pinged_index % MAX_STORED_PINGED_NODES].timestamp = unix_time(); |
466 | ++*last_pinged_index; | 534 | ++*last_pinged_index; |
467 | return 1; | 535 | return 1; |
@@ -489,12 +557,12 @@ static int client_ping_nodes(Onion_Client *onion_c, uint32_t num, const Node_for | |||
489 | last_pinged_index = &onion_c->last_pinged_index; | 557 | last_pinged_index = &onion_c->last_pinged_index; |
490 | } else { | 558 | } else { |
491 | list_nodes = onion_c->friends_list[num - 1].clients_list; | 559 | list_nodes = onion_c->friends_list[num - 1].clients_list; |
492 | reference_id = onion_c->friends_list[num - 1].real_client_id; | 560 | reference_id = onion_c->friends_list[num - 1].real_public_key; |
493 | last_pinged = onion_c->friends_list[num - 1].last_pinged; | 561 | last_pinged = onion_c->friends_list[num - 1].last_pinged; |
494 | last_pinged_index = &onion_c->friends_list[num - 1].last_pinged_index; | 562 | last_pinged_index = &onion_c->friends_list[num - 1].last_pinged_index; |
495 | } | 563 | } |
496 | 564 | ||
497 | uint32_t i, j; | 565 | unsigned int i, j; |
498 | int lan_ips_accepted = (LAN_ip(source.ip) == 0); | 566 | int lan_ips_accepted = (LAN_ip(source.ip) == 0); |
499 | 567 | ||
500 | for (i = 0; i < num_nodes; ++i) { | 568 | for (i = 0; i < num_nodes; ++i) { |
@@ -504,16 +572,16 @@ static int client_ping_nodes(Onion_Client *onion_c, uint32_t num, const Node_for | |||
504 | continue; | 572 | continue; |
505 | 573 | ||
506 | if (is_timeout(list_nodes[0].timestamp, ONION_NODE_TIMEOUT) | 574 | if (is_timeout(list_nodes[0].timestamp, ONION_NODE_TIMEOUT) |
507 | || id_closest(reference_id, list_nodes[0].client_id, nodes[i].client_id) == 2) { | 575 | || id_closest(reference_id, list_nodes[0].public_key, nodes[i].public_key) == 2) { |
508 | /* check if node is already in list. */ | 576 | /* check if node is already in list. */ |
509 | for (j = 0; j < MAX_ONION_CLIENTS; ++j) { | 577 | for (j = 0; j < MAX_ONION_CLIENTS; ++j) { |
510 | if (memcmp(list_nodes[j].client_id, nodes[i].client_id, crypto_box_PUBLICKEYBYTES) == 0) { | 578 | if (memcmp(list_nodes[j].public_key, nodes[i].public_key, crypto_box_PUBLICKEYBYTES) == 0) { |
511 | break; | 579 | break; |
512 | } | 580 | } |
513 | } | 581 | } |
514 | 582 | ||
515 | if (j == MAX_ONION_CLIENTS && good_to_ping(last_pinged, last_pinged_index, nodes[i].client_id)) { | 583 | if (j == MAX_ONION_CLIENTS && good_to_ping(last_pinged, last_pinged_index, nodes[i].public_key)) { |
516 | client_send_announce_request(onion_c, num, nodes[i].ip_port, nodes[i].client_id, NULL, ~0); | 584 | client_send_announce_request(onion_c, num, nodes[i].ip_port, nodes[i].public_key, NULL, ~0); |
517 | } | 585 | } |
518 | } | 586 | } |
519 | } | 587 | } |
@@ -521,7 +589,7 @@ static int client_ping_nodes(Onion_Client *onion_c, uint32_t num, const Node_for | |||
521 | return 0; | 589 | return 0; |
522 | } | 590 | } |
523 | 591 | ||
524 | static int handle_announce_response(void *object, IP_Port source, const uint8_t *packet, uint32_t length) | 592 | static int handle_announce_response(void *object, IP_Port source, const uint8_t *packet, uint16_t length) |
525 | { | 593 | { |
526 | Onion_Client *onion_c = object; | 594 | Onion_Client *onion_c = object; |
527 | 595 | ||
@@ -572,12 +640,14 @@ static int handle_announce_response(void *object, IP_Port source, const uint8_t | |||
572 | return 1; | 640 | return 1; |
573 | } | 641 | } |
574 | 642 | ||
643 | //TODO: LAN vs non LAN ips?, if we are connected only to LAN, are we offline? | ||
644 | onion_c->last_packet_recv = unix_time(); | ||
575 | return 0; | 645 | return 0; |
576 | } | 646 | } |
577 | 647 | ||
578 | #define DATA_IN_RESPONSE_MIN_SIZE ONION_DATA_IN_RESPONSE_MIN_SIZE | 648 | #define DATA_IN_RESPONSE_MIN_SIZE ONION_DATA_IN_RESPONSE_MIN_SIZE |
579 | 649 | ||
580 | static int handle_data_response(void *object, IP_Port source, const uint8_t *packet, uint32_t length) | 650 | static int handle_data_response(void *object, IP_Port source, const uint8_t *packet, uint16_t length) |
581 | { | 651 | { |
582 | Onion_Client *onion_c = object; | 652 | Onion_Client *onion_c = object; |
583 | 653 | ||
@@ -609,17 +679,16 @@ static int handle_data_response(void *object, IP_Port source, const uint8_t *pac | |||
609 | sizeof(plain)); | 679 | sizeof(plain)); |
610 | } | 680 | } |
611 | 681 | ||
612 | #define FAKEID_DATA_ID 156 | 682 | #define DHTPK_DATA_MIN_LENGTH (1 + sizeof(uint64_t) + crypto_box_PUBLICKEYBYTES) |
613 | #define FAKEID_DATA_MIN_LENGTH (1 + sizeof(uint64_t) + crypto_box_PUBLICKEYBYTES) | 683 | #define DHTPK_DATA_MAX_LENGTH (DHTPK_DATA_MIN_LENGTH + sizeof(Node_format)*MAX_SENT_NODES) |
614 | #define FAKEID_DATA_MAX_LENGTH (FAKEID_DATA_MIN_LENGTH + sizeof(Node_format)*MAX_SENT_NODES) | 684 | static int handle_dhtpk_announce(void *object, const uint8_t *source_pubkey, const uint8_t *data, uint16_t length) |
615 | static int handle_fakeid_announce(void *object, const uint8_t *source_pubkey, const uint8_t *data, uint32_t length) | ||
616 | { | 685 | { |
617 | Onion_Client *onion_c = object; | 686 | Onion_Client *onion_c = object; |
618 | 687 | ||
619 | if (length < FAKEID_DATA_MIN_LENGTH) | 688 | if (length < DHTPK_DATA_MIN_LENGTH) |
620 | return 1; | 689 | return 1; |
621 | 690 | ||
622 | if (length > FAKEID_DATA_MAX_LENGTH) | 691 | if (length > DHTPK_DATA_MAX_LENGTH) |
623 | return 1; | 692 | return 1; |
624 | 693 | ||
625 | int friend_num = onion_friend_num(onion_c, source_pubkey); | 694 | int friend_num = onion_friend_num(onion_c, source_pubkey); |
@@ -635,10 +704,15 @@ static int handle_fakeid_announce(void *object, const uint8_t *source_pubkey, co | |||
635 | return 1; | 704 | return 1; |
636 | 705 | ||
637 | onion_c->friends_list[friend_num].last_noreplay = no_replay; | 706 | onion_c->friends_list[friend_num].last_noreplay = no_replay; |
638 | onion_set_friend_DHT_pubkey(onion_c, friend_num, data + 1 + sizeof(uint64_t), current_time_monotonic()); | 707 | |
708 | if (onion_c->friends_list[friend_num].dht_pk_callback) | ||
709 | onion_c->friends_list[friend_num].dht_pk_callback(onion_c->friends_list[friend_num].dht_pk_callback_object, | ||
710 | onion_c->friends_list[friend_num].dht_pk_callback_number, data + 1 + sizeof(uint64_t)); | ||
711 | |||
712 | onion_set_friend_DHT_pubkey(onion_c, friend_num, data + 1 + sizeof(uint64_t)); | ||
639 | onion_c->friends_list[friend_num].last_seen = unix_time(); | 713 | onion_c->friends_list[friend_num].last_seen = unix_time(); |
640 | 714 | ||
641 | uint16_t len_nodes = length - FAKEID_DATA_MIN_LENGTH; | 715 | uint16_t len_nodes = length - DHTPK_DATA_MIN_LENGTH; |
642 | 716 | ||
643 | if (len_nodes != 0) { | 717 | if (len_nodes != 0) { |
644 | Node_format nodes[MAX_SENT_NODES]; | 718 | Node_format nodes[MAX_SENT_NODES]; |
@@ -654,12 +728,12 @@ static int handle_fakeid_announce(void *object, const uint8_t *source_pubkey, co | |||
654 | uint8_t family = nodes[i].ip_port.ip.family; | 728 | uint8_t family = nodes[i].ip_port.ip.family; |
655 | 729 | ||
656 | if (family == AF_INET || family == AF_INET6) { | 730 | if (family == AF_INET || family == AF_INET6) { |
657 | DHT_getnodes(onion_c->dht, &nodes[i].ip_port, nodes[i].client_id, onion_c->friends_list[friend_num].fake_client_id); | 731 | DHT_getnodes(onion_c->dht, &nodes[i].ip_port, nodes[i].public_key, onion_c->friends_list[friend_num].dht_public_key); |
658 | } else if (family == TCP_INET || family == TCP_INET6) { | 732 | } else if (family == TCP_INET || family == TCP_INET6) { |
659 | if (onion_c->friends_list[friend_num].tcp_relay_node_callback) { | 733 | if (onion_c->friends_list[friend_num].tcp_relay_node_callback) { |
660 | void *obj = onion_c->friends_list[friend_num].tcp_relay_node_callback_object; | 734 | void *obj = onion_c->friends_list[friend_num].tcp_relay_node_callback_object; |
661 | uint32_t number = onion_c->friends_list[friend_num].tcp_relay_node_callback_number; | 735 | uint32_t number = onion_c->friends_list[friend_num].tcp_relay_node_callback_number; |
662 | onion_c->friends_list[friend_num].tcp_relay_node_callback(obj, number, nodes[i].ip_port, nodes[i].client_id); | 736 | onion_c->friends_list[friend_num].tcp_relay_node_callback(obj, number, nodes[i].ip_port, nodes[i].public_key); |
663 | } | 737 | } |
664 | } | 738 | } |
665 | } | 739 | } |
@@ -693,7 +767,7 @@ static int handle_tcp_onion(void *object, const uint8_t *data, uint16_t length) | |||
693 | * return the number of packets sent on success | 767 | * return the number of packets sent on success |
694 | * return -1 on failure. | 768 | * return -1 on failure. |
695 | */ | 769 | */ |
696 | int send_onion_data(const Onion_Client *onion_c, int friend_num, const uint8_t *data, uint32_t length) | 770 | int send_onion_data(Onion_Client *onion_c, int friend_num, const uint8_t *data, uint16_t length) |
697 | { | 771 | { |
698 | if ((uint32_t)friend_num >= onion_c->num_friends) | 772 | if ((uint32_t)friend_num >= onion_c->num_friends) |
699 | return -1; | 773 | return -1; |
@@ -704,19 +778,7 @@ int send_onion_data(const Onion_Client *onion_c, int friend_num, const uint8_t * | |||
704 | if (length == 0) | 778 | if (length == 0) |
705 | return -1; | 779 | return -1; |
706 | 780 | ||
707 | uint8_t nonce[crypto_box_NONCEBYTES]; | 781 | unsigned int i, good_nodes[MAX_ONION_CLIENTS], num_good = 0, num_nodes = 0; |
708 | random_nonce(nonce); | ||
709 | |||
710 | uint8_t packet[DATA_IN_RESPONSE_MIN_SIZE + length]; | ||
711 | memcpy(packet, onion_c->c->self_public_key, crypto_box_PUBLICKEYBYTES); | ||
712 | int len = encrypt_data(onion_c->friends_list[friend_num].real_client_id, onion_c->c->self_secret_key, nonce, data, | ||
713 | length, packet + crypto_box_PUBLICKEYBYTES); | ||
714 | |||
715 | if ((uint32_t)len + crypto_box_PUBLICKEYBYTES != sizeof(packet)) | ||
716 | return -1; | ||
717 | |||
718 | uint32_t i, good_nodes[MAX_ONION_CLIENTS], num_good = 0, num_nodes = 0; | ||
719 | Onion_Path path[MAX_ONION_CLIENTS]; | ||
720 | Onion_Node *list_nodes = onion_c->friends_list[friend_num].clients_list; | 782 | Onion_Node *list_nodes = onion_c->friends_list[friend_num].clients_list; |
721 | 783 | ||
722 | for (i = 0; i < MAX_ONION_CLIENTS; ++i) { | 784 | for (i = 0; i < MAX_ONION_CLIENTS; ++i) { |
@@ -726,9 +788,6 @@ int send_onion_data(const Onion_Client *onion_c, int friend_num, const uint8_t * | |||
726 | ++num_nodes; | 788 | ++num_nodes; |
727 | 789 | ||
728 | if (list_nodes[i].is_stored) { | 790 | if (list_nodes[i].is_stored) { |
729 | if (random_path(onion_c, &onion_c->friends_list[friend_num].onion_paths, ~0, &path[num_good]) == -1) | ||
730 | continue; | ||
731 | |||
732 | good_nodes[num_good] = i; | 791 | good_nodes[num_good] = i; |
733 | ++num_good; | 792 | ++num_good; |
734 | } | 793 | } |
@@ -737,36 +796,52 @@ int send_onion_data(const Onion_Client *onion_c, int friend_num, const uint8_t * | |||
737 | if (num_good < (num_nodes / 4) + 1) | 796 | if (num_good < (num_nodes / 4) + 1) |
738 | return -1; | 797 | return -1; |
739 | 798 | ||
740 | uint32_t good = 0; | 799 | uint8_t nonce[crypto_box_NONCEBYTES]; |
800 | random_nonce(nonce); | ||
801 | |||
802 | uint8_t packet[DATA_IN_RESPONSE_MIN_SIZE + length]; | ||
803 | memcpy(packet, onion_c->c->self_public_key, crypto_box_PUBLICKEYBYTES); | ||
804 | int len = encrypt_data(onion_c->friends_list[friend_num].real_public_key, onion_c->c->self_secret_key, nonce, data, | ||
805 | length, packet + crypto_box_PUBLICKEYBYTES); | ||
806 | |||
807 | if ((uint32_t)len + crypto_box_PUBLICKEYBYTES != sizeof(packet)) | ||
808 | return -1; | ||
809 | |||
810 | unsigned int good = 0; | ||
741 | 811 | ||
742 | for (i = 0; i < num_good; ++i) { | 812 | for (i = 0; i < num_good; ++i) { |
813 | Onion_Path path; | ||
814 | |||
815 | if (random_path(onion_c, &onion_c->onion_paths_friends, ~0, &path) == -1) | ||
816 | continue; | ||
817 | |||
743 | uint8_t o_packet[ONION_MAX_PACKET_SIZE]; | 818 | uint8_t o_packet[ONION_MAX_PACKET_SIZE]; |
744 | len = create_data_request(o_packet, sizeof(o_packet), onion_c->friends_list[friend_num].real_client_id, | 819 | len = create_data_request(o_packet, sizeof(o_packet), onion_c->friends_list[friend_num].real_public_key, |
745 | list_nodes[good_nodes[i]].data_public_key, nonce, packet, sizeof(packet)); | 820 | list_nodes[good_nodes[i]].data_public_key, nonce, packet, sizeof(packet)); |
746 | 821 | ||
747 | if (len == -1) | 822 | if (len == -1) |
748 | continue; | 823 | continue; |
749 | 824 | ||
750 | if (send_onion_packet_tcp_udp(onion_c, &path[i], list_nodes[good_nodes[i]].ip_port, o_packet, len) == 0) | 825 | if (send_onion_packet_tcp_udp(onion_c, &path, list_nodes[good_nodes[i]].ip_port, o_packet, len) == 0) |
751 | ++good; | 826 | ++good; |
752 | } | 827 | } |
753 | 828 | ||
754 | return good; | 829 | return good; |
755 | } | 830 | } |
756 | 831 | ||
757 | /* Try to send the fakeid via the DHT instead of onion | 832 | /* Try to send the dht public key via the DHT instead of onion |
758 | * | 833 | * |
759 | * Even if this function succeeds, the friend might not receive any data. | 834 | * Even if this function succeeds, the friend might not receive any data. |
760 | * | 835 | * |
761 | * return the number of packets sent on success | 836 | * return the number of packets sent on success |
762 | * return -1 on failure. | 837 | * return -1 on failure. |
763 | */ | 838 | */ |
764 | static int send_dht_fakeid(const Onion_Client *onion_c, int friend_num, const uint8_t *data, uint32_t length) | 839 | static int send_dht_dhtpk(const Onion_Client *onion_c, int friend_num, const uint8_t *data, uint16_t length) |
765 | { | 840 | { |
766 | if ((uint32_t)friend_num >= onion_c->num_friends) | 841 | if ((uint32_t)friend_num >= onion_c->num_friends) |
767 | return -1; | 842 | return -1; |
768 | 843 | ||
769 | if (!onion_c->friends_list[friend_num].is_fake_clientid) | 844 | if (!onion_c->friends_list[friend_num].know_dht_public_key) |
770 | return -1; | 845 | return -1; |
771 | 846 | ||
772 | uint8_t nonce[crypto_box_NONCEBYTES]; | 847 | uint8_t nonce[crypto_box_NONCEBYTES]; |
@@ -775,7 +850,7 @@ static int send_dht_fakeid(const Onion_Client *onion_c, int friend_num, const ui | |||
775 | uint8_t temp[DATA_IN_RESPONSE_MIN_SIZE + crypto_box_NONCEBYTES + length]; | 850 | uint8_t temp[DATA_IN_RESPONSE_MIN_SIZE + crypto_box_NONCEBYTES + length]; |
776 | memcpy(temp, onion_c->c->self_public_key, crypto_box_PUBLICKEYBYTES); | 851 | memcpy(temp, onion_c->c->self_public_key, crypto_box_PUBLICKEYBYTES); |
777 | memcpy(temp + crypto_box_PUBLICKEYBYTES, nonce, crypto_box_NONCEBYTES); | 852 | memcpy(temp + crypto_box_PUBLICKEYBYTES, nonce, crypto_box_NONCEBYTES); |
778 | int len = encrypt_data(onion_c->friends_list[friend_num].real_client_id, onion_c->c->self_secret_key, nonce, data, | 853 | int len = encrypt_data(onion_c->friends_list[friend_num].real_public_key, onion_c->c->self_secret_key, nonce, data, |
779 | length, temp + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES); | 854 | length, temp + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES); |
780 | 855 | ||
781 | if ((uint32_t)len + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES != sizeof(temp)) | 856 | if ((uint32_t)len + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES != sizeof(temp)) |
@@ -783,37 +858,37 @@ static int send_dht_fakeid(const Onion_Client *onion_c, int friend_num, const ui | |||
783 | 858 | ||
784 | uint8_t packet[MAX_CRYPTO_REQUEST_SIZE]; | 859 | uint8_t packet[MAX_CRYPTO_REQUEST_SIZE]; |
785 | len = create_request(onion_c->dht->self_public_key, onion_c->dht->self_secret_key, packet, | 860 | len = create_request(onion_c->dht->self_public_key, onion_c->dht->self_secret_key, packet, |
786 | onion_c->friends_list[friend_num].fake_client_id, temp, sizeof(temp), FAKEID_DATA_ID); | 861 | onion_c->friends_list[friend_num].dht_public_key, temp, sizeof(temp), CRYPTO_PACKET_DHTPK); |
787 | 862 | ||
788 | if (len == -1) | 863 | if (len == -1) |
789 | return -1; | 864 | return -1; |
790 | 865 | ||
791 | return route_tofriend(onion_c->dht, onion_c->friends_list[friend_num].fake_client_id, packet, len); | 866 | return route_tofriend(onion_c->dht, onion_c->friends_list[friend_num].dht_public_key, packet, len); |
792 | } | 867 | } |
793 | 868 | ||
794 | static int handle_dht_fakeid(void *object, IP_Port source, const uint8_t *source_pubkey, const uint8_t *packet, | 869 | static int handle_dht_dhtpk(void *object, IP_Port source, const uint8_t *source_pubkey, const uint8_t *packet, |
795 | uint32_t length) | 870 | uint16_t length) |
796 | { | 871 | { |
797 | Onion_Client *onion_c = object; | 872 | Onion_Client *onion_c = object; |
798 | 873 | ||
799 | if (length < FAKEID_DATA_MIN_LENGTH + DATA_IN_RESPONSE_MIN_SIZE + crypto_box_NONCEBYTES) | 874 | if (length < DHTPK_DATA_MIN_LENGTH + DATA_IN_RESPONSE_MIN_SIZE + crypto_box_NONCEBYTES) |
800 | return 1; | 875 | return 1; |
801 | 876 | ||
802 | if (length > FAKEID_DATA_MAX_LENGTH + DATA_IN_RESPONSE_MIN_SIZE + crypto_box_NONCEBYTES) | 877 | if (length > DHTPK_DATA_MAX_LENGTH + DATA_IN_RESPONSE_MIN_SIZE + crypto_box_NONCEBYTES) |
803 | return 1; | 878 | return 1; |
804 | 879 | ||
805 | uint8_t plain[FAKEID_DATA_MAX_LENGTH]; | 880 | uint8_t plain[DHTPK_DATA_MAX_LENGTH]; |
806 | int len = decrypt_data(packet, onion_c->c->self_secret_key, packet + crypto_box_PUBLICKEYBYTES, | 881 | int len = decrypt_data(packet, onion_c->c->self_secret_key, packet + crypto_box_PUBLICKEYBYTES, |
807 | packet + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES, | 882 | packet + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES, |
808 | length - (crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES), plain); | 883 | length - (crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES), plain); |
809 | 884 | ||
810 | if ((uint32_t)len != length - (DATA_IN_RESPONSE_MIN_SIZE + crypto_box_NONCEBYTES)) | 885 | if (len != length - (DATA_IN_RESPONSE_MIN_SIZE + crypto_box_NONCEBYTES)) |
811 | return 1; | 886 | return 1; |
812 | 887 | ||
813 | if (memcmp(source_pubkey, plain + 1 + sizeof(uint64_t), crypto_box_PUBLICKEYBYTES) != 0) | 888 | if (memcmp(source_pubkey, plain + 1 + sizeof(uint64_t), crypto_box_PUBLICKEYBYTES) != 0) |
814 | return 1; | 889 | return 1; |
815 | 890 | ||
816 | return handle_fakeid_announce(onion_c, packet, plain, len); | 891 | return handle_dhtpk_announce(onion_c, packet, plain, len); |
817 | } | 892 | } |
818 | /* Send the packets to tell our friends what our DHT public key is. | 893 | /* Send the packets to tell our friends what our DHT public key is. |
819 | * | 894 | * |
@@ -824,13 +899,13 @@ static int handle_dht_fakeid(void *object, IP_Port source, const uint8_t *source | |||
824 | * return the number of packets sent on success | 899 | * return the number of packets sent on success |
825 | * return -1 on failure. | 900 | * return -1 on failure. |
826 | */ | 901 | */ |
827 | static int send_fakeid_announce(const Onion_Client *onion_c, uint16_t friend_num, uint8_t onion_dht_both) | 902 | static int send_dhtpk_announce(Onion_Client *onion_c, uint16_t friend_num, uint8_t onion_dht_both) |
828 | { | 903 | { |
829 | if (friend_num >= onion_c->num_friends) | 904 | if (friend_num >= onion_c->num_friends) |
830 | return -1; | 905 | return -1; |
831 | 906 | ||
832 | uint8_t data[FAKEID_DATA_MAX_LENGTH]; | 907 | uint8_t data[DHTPK_DATA_MAX_LENGTH]; |
833 | data[0] = FAKEID_DATA_ID; | 908 | data[0] = ONION_DATA_DHTPK; |
834 | uint64_t no_replay = unix_time(); | 909 | uint64_t no_replay = unix_time(); |
835 | host_to_net((uint8_t *)&no_replay, sizeof(no_replay)); | 910 | host_to_net((uint8_t *)&no_replay, sizeof(no_replay)); |
836 | memcpy(data + 1, &no_replay, sizeof(no_replay)); | 911 | memcpy(data + 1, &no_replay, sizeof(no_replay)); |
@@ -842,7 +917,7 @@ static int send_fakeid_announce(const Onion_Client *onion_c, uint16_t friend_num | |||
842 | int nodes_len = 0; | 917 | int nodes_len = 0; |
843 | 918 | ||
844 | if (num_nodes != 0) { | 919 | if (num_nodes != 0) { |
845 | nodes_len = pack_nodes(data + FAKEID_DATA_MIN_LENGTH, FAKEID_DATA_MAX_LENGTH - FAKEID_DATA_MIN_LENGTH, nodes, | 920 | nodes_len = pack_nodes(data + DHTPK_DATA_MIN_LENGTH, DHTPK_DATA_MAX_LENGTH - DHTPK_DATA_MIN_LENGTH, nodes, |
846 | num_nodes); | 921 | num_nodes); |
847 | 922 | ||
848 | if (nodes_len <= 0) | 923 | if (nodes_len <= 0) |
@@ -852,10 +927,10 @@ static int send_fakeid_announce(const Onion_Client *onion_c, uint16_t friend_num | |||
852 | int num1 = -1, num2 = -1; | 927 | int num1 = -1, num2 = -1; |
853 | 928 | ||
854 | if (onion_dht_both != 1) | 929 | if (onion_dht_both != 1) |
855 | num1 = send_onion_data(onion_c, friend_num, data, FAKEID_DATA_MIN_LENGTH + nodes_len); | 930 | num1 = send_onion_data(onion_c, friend_num, data, DHTPK_DATA_MIN_LENGTH + nodes_len); |
856 | 931 | ||
857 | if (onion_dht_both != 0) | 932 | if (onion_dht_both != 0) |
858 | num2 = send_dht_fakeid(onion_c, friend_num, data, FAKEID_DATA_MIN_LENGTH + nodes_len); | 933 | num2 = send_dht_dhtpk(onion_c, friend_num, data, DHTPK_DATA_MIN_LENGTH + nodes_len); |
859 | 934 | ||
860 | if (num1 == -1) | 935 | if (num1 == -1) |
861 | return num2; | 936 | return num2; |
@@ -871,15 +946,15 @@ static int send_fakeid_announce(const Onion_Client *onion_c, uint16_t friend_num | |||
871 | * return -1 on failure. | 946 | * return -1 on failure. |
872 | * return friend number on success. | 947 | * return friend number on success. |
873 | */ | 948 | */ |
874 | int onion_friend_num(const Onion_Client *onion_c, const uint8_t *client_id) | 949 | int onion_friend_num(const Onion_Client *onion_c, const uint8_t *public_key) |
875 | { | 950 | { |
876 | uint32_t i; | 951 | unsigned int i; |
877 | 952 | ||
878 | for (i = 0; i < onion_c->num_friends; ++i) { | 953 | for (i = 0; i < onion_c->num_friends; ++i) { |
879 | if (onion_c->friends_list[i].status == 0) | 954 | if (onion_c->friends_list[i].status == 0) |
880 | continue; | 955 | continue; |
881 | 956 | ||
882 | if (memcmp(client_id, onion_c->friends_list[i].real_client_id, crypto_box_PUBLICKEYBYTES) == 0) | 957 | if (memcmp(public_key, onion_c->friends_list[i].real_public_key, crypto_box_PUBLICKEYBYTES) == 0) |
883 | return i; | 958 | return i; |
884 | } | 959 | } |
885 | 960 | ||
@@ -913,14 +988,14 @@ static int realloc_onion_friends(Onion_Client *onion_c, uint32_t num) | |||
913 | * return -1 on failure. | 988 | * return -1 on failure. |
914 | * return the friend number on success or if the friend was already added. | 989 | * return the friend number on success or if the friend was already added. |
915 | */ | 990 | */ |
916 | int onion_addfriend(Onion_Client *onion_c, const uint8_t *client_id) | 991 | int onion_addfriend(Onion_Client *onion_c, const uint8_t *public_key) |
917 | { | 992 | { |
918 | int num = onion_friend_num(onion_c, client_id); | 993 | int num = onion_friend_num(onion_c, public_key); |
919 | 994 | ||
920 | if (num != -1) | 995 | if (num != -1) |
921 | return num; | 996 | return num; |
922 | 997 | ||
923 | uint32_t i, index = ~0; | 998 | unsigned int i, index = ~0; |
924 | 999 | ||
925 | for (i = 0; i < onion_c->num_friends; ++i) { | 1000 | for (i = 0; i < onion_c->num_friends; ++i) { |
926 | if (onion_c->friends_list[i].status == 0) { | 1001 | if (onion_c->friends_list[i].status == 0) { |
@@ -939,7 +1014,7 @@ int onion_addfriend(Onion_Client *onion_c, const uint8_t *client_id) | |||
939 | } | 1014 | } |
940 | 1015 | ||
941 | onion_c->friends_list[index].status = 1; | 1016 | onion_c->friends_list[index].status = 1; |
942 | memcpy(onion_c->friends_list[index].real_client_id, client_id, crypto_box_PUBLICKEYBYTES); | 1017 | memcpy(onion_c->friends_list[index].real_public_key, public_key, crypto_box_PUBLICKEYBYTES); |
943 | crypto_box_keypair(onion_c->friends_list[index].temp_public_key, onion_c->friends_list[index].temp_secret_key); | 1018 | crypto_box_keypair(onion_c->friends_list[index].temp_public_key, onion_c->friends_list[index].temp_secret_key); |
944 | return index; | 1019 | return index; |
945 | } | 1020 | } |
@@ -954,11 +1029,11 @@ int onion_delfriend(Onion_Client *onion_c, int friend_num) | |||
954 | if ((uint32_t)friend_num >= onion_c->num_friends) | 1029 | if ((uint32_t)friend_num >= onion_c->num_friends) |
955 | return -1; | 1030 | return -1; |
956 | 1031 | ||
957 | if (onion_c->friends_list[friend_num].is_fake_clientid) | 1032 | //if (onion_c->friends_list[friend_num].know_dht_public_key) |
958 | DHT_delfriend(onion_c->dht, onion_c->friends_list[friend_num].fake_client_id); | 1033 | // DHT_delfriend(onion_c->dht, onion_c->friends_list[friend_num].dht_public_key, 0); |
959 | 1034 | ||
960 | memset(&(onion_c->friends_list[friend_num]), 0, sizeof(Onion_Friend)); | 1035 | memset(&(onion_c->friends_list[friend_num]), 0, sizeof(Onion_Friend)); |
961 | uint32_t i; | 1036 | unsigned int i; |
962 | 1037 | ||
963 | for (i = onion_c->num_friends; i != 0; --i) { | 1038 | for (i = onion_c->num_friends; i != 0; --i) { |
964 | if (onion_c->friends_list[i - 1].status != 0) | 1039 | if (onion_c->friends_list[i - 1].status != 0) |
@@ -993,40 +1068,50 @@ int recv_tcp_relay_handler(Onion_Client *onion_c, int friend_num, int (*tcp_rela | |||
993 | return 0; | 1068 | return 0; |
994 | } | 1069 | } |
995 | 1070 | ||
996 | /* Set a friends DHT public key. | 1071 | /* Set the function for this friend that will be callbacked with object and number |
997 | * timestamp is the time (current_time_monotonic()) at which the key was last confirmed belonging to | 1072 | * when that friend gives us his DHT temporary public key. |
998 | * the other peer. | 1073 | * |
1074 | * object and number will be passed as argument to this function. | ||
999 | * | 1075 | * |
1000 | * return -1 on failure. | 1076 | * return -1 on failure. |
1001 | * return 0 on success. | 1077 | * return 0 on success. |
1002 | */ | 1078 | */ |
1003 | int onion_set_friend_DHT_pubkey(Onion_Client *onion_c, int friend_num, const uint8_t *dht_key, uint64_t timestamp) | 1079 | int onion_dht_pk_callback(Onion_Client *onion_c, int friend_num, void (*function)(void *data, int32_t number, |
1080 | const uint8_t *dht_public_key), void *object, uint32_t number) | ||
1004 | { | 1081 | { |
1005 | if ((uint32_t)friend_num >= onion_c->num_friends) | 1082 | if ((uint32_t)friend_num >= onion_c->num_friends) |
1006 | return -1; | 1083 | return -1; |
1007 | 1084 | ||
1008 | if (onion_c->friends_list[friend_num].status == 0) | 1085 | onion_c->friends_list[friend_num].dht_pk_callback = function; |
1086 | onion_c->friends_list[friend_num].dht_pk_callback_object = object; | ||
1087 | onion_c->friends_list[friend_num].dht_pk_callback_number = number; | ||
1088 | return 0; | ||
1089 | } | ||
1090 | |||
1091 | /* Set a friends DHT public key. | ||
1092 | * | ||
1093 | * return -1 on failure. | ||
1094 | * return 0 on success. | ||
1095 | */ | ||
1096 | int onion_set_friend_DHT_pubkey(Onion_Client *onion_c, int friend_num, const uint8_t *dht_key) | ||
1097 | { | ||
1098 | if ((uint32_t)friend_num >= onion_c->num_friends) | ||
1009 | return -1; | 1099 | return -1; |
1010 | 1100 | ||
1011 | if (onion_c->friends_list[friend_num].fake_client_id_timestamp >= timestamp) | 1101 | if (onion_c->friends_list[friend_num].status == 0) |
1012 | return -1; | 1102 | return -1; |
1013 | 1103 | ||
1014 | if (onion_c->friends_list[friend_num].is_fake_clientid) { | 1104 | if (onion_c->friends_list[friend_num].know_dht_public_key) { |
1015 | if (memcmp(dht_key, onion_c->friends_list[friend_num].fake_client_id, crypto_box_PUBLICKEYBYTES) == 0) { | 1105 | if (memcmp(dht_key, onion_c->friends_list[friend_num].dht_public_key, crypto_box_PUBLICKEYBYTES) == 0) { |
1016 | return -1; | 1106 | return -1; |
1017 | } | 1107 | } |
1018 | 1108 | ||
1019 | DHT_delfriend(onion_c->dht, onion_c->friends_list[friend_num].fake_client_id); | 1109 | onion_c->friends_list[friend_num].know_dht_public_key = 0; |
1020 | } | ||
1021 | |||
1022 | if (DHT_addfriend(onion_c->dht, dht_key) == 1) { | ||
1023 | return -1; | ||
1024 | } | 1110 | } |
1025 | 1111 | ||
1026 | onion_c->friends_list[friend_num].last_seen = unix_time(); | 1112 | onion_c->friends_list[friend_num].last_seen = unix_time(); |
1027 | onion_c->friends_list[friend_num].is_fake_clientid = 1; | 1113 | onion_c->friends_list[friend_num].know_dht_public_key = 1; |
1028 | onion_c->friends_list[friend_num].fake_client_id_timestamp = timestamp; | 1114 | memcpy(onion_c->friends_list[friend_num].dht_public_key, dht_key, crypto_box_PUBLICKEYBYTES); |
1029 | memcpy(onion_c->friends_list[friend_num].fake_client_id, dht_key, crypto_box_PUBLICKEYBYTES); | ||
1030 | 1115 | ||
1031 | return 0; | 1116 | return 0; |
1032 | } | 1117 | } |
@@ -1034,9 +1119,9 @@ int onion_set_friend_DHT_pubkey(Onion_Client *onion_c, int friend_num, const uin | |||
1034 | /* Copy friends DHT public key into dht_key. | 1119 | /* Copy friends DHT public key into dht_key. |
1035 | * | 1120 | * |
1036 | * return 0 on failure (no key copied). | 1121 | * return 0 on failure (no key copied). |
1037 | * return timestamp on success (key copied). | 1122 | * return 1 on success (key copied). |
1038 | */ | 1123 | */ |
1039 | uint64_t onion_getfriend_DHT_pubkey(const Onion_Client *onion_c, int friend_num, uint8_t *dht_key) | 1124 | unsigned int onion_getfriend_DHT_pubkey(const Onion_Client *onion_c, int friend_num, uint8_t *dht_key) |
1040 | { | 1125 | { |
1041 | if ((uint32_t)friend_num >= onion_c->num_friends) | 1126 | if ((uint32_t)friend_num >= onion_c->num_friends) |
1042 | return 0; | 1127 | return 0; |
@@ -1044,18 +1129,18 @@ uint64_t onion_getfriend_DHT_pubkey(const Onion_Client *onion_c, int friend_num, | |||
1044 | if (onion_c->friends_list[friend_num].status == 0) | 1129 | if (onion_c->friends_list[friend_num].status == 0) |
1045 | return 0; | 1130 | return 0; |
1046 | 1131 | ||
1047 | if (!onion_c->friends_list[friend_num].is_fake_clientid) | 1132 | if (!onion_c->friends_list[friend_num].know_dht_public_key) |
1048 | return 0; | 1133 | return 0; |
1049 | 1134 | ||
1050 | memcpy(dht_key, onion_c->friends_list[friend_num].fake_client_id, crypto_box_PUBLICKEYBYTES); | 1135 | memcpy(dht_key, onion_c->friends_list[friend_num].dht_public_key, crypto_box_PUBLICKEYBYTES); |
1051 | return onion_c->friends_list[friend_num].fake_client_id_timestamp; | 1136 | return 1; |
1052 | } | 1137 | } |
1053 | 1138 | ||
1054 | /* Get the ip of friend friendnum and put it in ip_port | 1139 | /* Get the ip of friend friendnum and put it in ip_port |
1055 | * | 1140 | * |
1056 | * return -1, -- if client_id does NOT refer to a friend | 1141 | * return -1, -- if public_key does NOT refer to a friend |
1057 | * return 0, -- if client_id refers to a friend and we failed to find the friend (yet) | 1142 | * return 0, -- if public_key refers to a friend and we failed to find the friend (yet) |
1058 | * return 1, ip if client_id refers to a friend and we found him | 1143 | * return 1, ip if public_key refers to a friend and we found him |
1059 | * | 1144 | * |
1060 | */ | 1145 | */ |
1061 | int onion_getfriendip(const Onion_Client *onion_c, int friend_num, IP_Port *ip_port) | 1146 | int onion_getfriendip(const Onion_Client *onion_c, int friend_num, IP_Port *ip_port) |
@@ -1089,8 +1174,10 @@ int onion_set_friend_online(Onion_Client *onion_c, int friend_num, uint8_t is_on | |||
1089 | onion_c->friends_list[friend_num].is_online = is_online; | 1174 | onion_c->friends_list[friend_num].is_online = is_online; |
1090 | 1175 | ||
1091 | /* This should prevent some clock related issues */ | 1176 | /* This should prevent some clock related issues */ |
1092 | if (!is_online) | 1177 | if (!is_online) { |
1093 | onion_c->friends_list[friend_num].last_noreplay = 0; | 1178 | onion_c->friends_list[friend_num].last_noreplay = 0; |
1179 | onion_c->friends_list[friend_num].run_count = 0; | ||
1180 | } | ||
1094 | 1181 | ||
1095 | return 0; | 1182 | return 0; |
1096 | } | 1183 | } |
@@ -1098,23 +1185,35 @@ int onion_set_friend_online(Onion_Client *onion_c, int friend_num, uint8_t is_on | |||
1098 | static void populate_path_nodes(Onion_Client *onion_c) | 1185 | static void populate_path_nodes(Onion_Client *onion_c) |
1099 | { | 1186 | { |
1100 | Node_format nodes_list[MAX_SENT_NODES]; | 1187 | Node_format nodes_list[MAX_SENT_NODES]; |
1101 | uint8_t client_id[crypto_box_PUBLICKEYBYTES]; | 1188 | uint8_t public_key[crypto_box_PUBLICKEYBYTES]; |
1102 | uint32_t random_num = rand(); | 1189 | uint32_t random_num = rand(); |
1103 | memcpy(client_id, &random_num, sizeof(random_num)); | 1190 | memcpy(public_key, &random_num, sizeof(random_num)); |
1191 | |||
1192 | unsigned int num_nodes = get_close_nodes(onion_c->dht, public_key, nodes_list, (rand() % 2) ? AF_INET : AF_INET6, 1, 0); | ||
1193 | unsigned int i; | ||
1104 | 1194 | ||
1105 | uint32_t num_nodes = get_close_nodes(onion_c->dht, client_id, nodes_list, (rand() % 2) ? AF_INET : AF_INET6, 1, 0); | 1195 | for (i = 0; i < num_nodes; ++i) { |
1196 | onion_add_path_node(onion_c, nodes_list[i].ip_port, nodes_list[i].public_key); | ||
1197 | } | ||
1198 | } | ||
1199 | |||
1200 | static void populate_path_nodes_tcp(Onion_Client *onion_c) | ||
1201 | { | ||
1202 | Node_format nodes_list[MAX_SENT_NODES]; | ||
1203 | |||
1204 | unsigned int num_nodes = copy_connected_tcp_relays(onion_c->c, nodes_list, MAX_SENT_NODES);; | ||
1106 | unsigned int i; | 1205 | unsigned int i; |
1107 | 1206 | ||
1108 | for (i = 0; i < num_nodes; ++i) { | 1207 | for (i = 0; i < num_nodes; ++i) { |
1109 | onion_add_path_node(onion_c, nodes_list[i].ip_port, nodes_list[i].client_id); | 1208 | onion_add_path_node(onion_c, nodes_list[i].ip_port, nodes_list[i].public_key); |
1110 | } | 1209 | } |
1111 | } | 1210 | } |
1112 | 1211 | ||
1113 | #define ANNOUNCE_FRIEND (ONION_NODE_PING_INTERVAL * 3) | 1212 | #define ANNOUNCE_FRIEND (ONION_NODE_PING_INTERVAL * 6) |
1114 | #define ANNOUNCE_FRIEND_BEGINNING 5 | 1213 | #define ANNOUNCE_FRIEND_BEGINNING 3 |
1115 | #define FRIEND_ONION_NODE_TIMEOUT (ONION_NODE_TIMEOUT * 3) | 1214 | #define FRIEND_ONION_NODE_TIMEOUT (ONION_NODE_TIMEOUT * 6) |
1116 | 1215 | ||
1117 | #define RUN_COUNT_FRIEND_ANNOUNCE_BEGINNING 15 | 1216 | #define RUN_COUNT_FRIEND_ANNOUNCE_BEGINNING 17 |
1118 | 1217 | ||
1119 | static void do_friend(Onion_Client *onion_c, uint16_t friendnum) | 1218 | static void do_friend(Onion_Client *onion_c, uint16_t friendnum) |
1120 | { | 1219 | { |
@@ -1124,18 +1223,15 @@ static void do_friend(Onion_Client *onion_c, uint16_t friendnum) | |||
1124 | if (onion_c->friends_list[friendnum].status == 0) | 1223 | if (onion_c->friends_list[friendnum].status == 0) |
1125 | return; | 1224 | return; |
1126 | 1225 | ||
1127 | uint32_t interval = ANNOUNCE_FRIEND; | 1226 | unsigned int interval = ANNOUNCE_FRIEND; |
1128 | 1227 | ||
1129 | if (onion_c->friends_list[friendnum].run_count < RUN_COUNT_FRIEND_ANNOUNCE_BEGINNING) | 1228 | if (onion_c->friends_list[friendnum].run_count < RUN_COUNT_FRIEND_ANNOUNCE_BEGINNING) |
1130 | interval = ANNOUNCE_FRIEND_BEGINNING; | 1229 | interval = ANNOUNCE_FRIEND_BEGINNING; |
1131 | 1230 | ||
1132 | uint32_t i, count = 0; | 1231 | unsigned int i, count = 0; |
1133 | Onion_Node *list_nodes = onion_c->friends_list[friendnum].clients_list; | 1232 | Onion_Node *list_nodes = onion_c->friends_list[friendnum].clients_list; |
1134 | 1233 | ||
1135 | if (!onion_c->friends_list[friendnum].is_online) { | 1234 | if (!onion_c->friends_list[friendnum].is_online) { |
1136 | |||
1137 | ++onion_c->friends_list[friendnum].run_count; | ||
1138 | |||
1139 | for (i = 0; i < MAX_ONION_CLIENTS; ++i) { | 1235 | for (i = 0; i < MAX_ONION_CLIENTS; ++i) { |
1140 | if (is_timeout(list_nodes[i].timestamp, FRIEND_ONION_NODE_TIMEOUT)) | 1236 | if (is_timeout(list_nodes[i].timestamp, FRIEND_ONION_NODE_TIMEOUT)) |
1141 | continue; | 1237 | continue; |
@@ -1149,7 +1245,7 @@ static void do_friend(Onion_Client *onion_c, uint16_t friendnum) | |||
1149 | } | 1245 | } |
1150 | 1246 | ||
1151 | if (is_timeout(list_nodes[i].last_pinged, interval)) { | 1247 | if (is_timeout(list_nodes[i].last_pinged, interval)) { |
1152 | if (client_send_announce_request(onion_c, friendnum + 1, list_nodes[i].ip_port, list_nodes[i].client_id, 0, ~0) == 0) { | 1248 | if (client_send_announce_request(onion_c, friendnum + 1, list_nodes[i].ip_port, list_nodes[i].public_key, 0, ~0) == 0) { |
1153 | list_nodes[i].last_pinged = unix_time(); | 1249 | list_nodes[i].last_pinged = unix_time(); |
1154 | } | 1250 | } |
1155 | } | 1251 | } |
@@ -1169,40 +1265,27 @@ static void do_friend(Onion_Client *onion_c, uint16_t friendnum) | |||
1169 | for (j = 0; j < n; ++j) { | 1265 | for (j = 0; j < n; ++j) { |
1170 | unsigned int num = rand() % num_nodes; | 1266 | unsigned int num = rand() % num_nodes; |
1171 | client_send_announce_request(onion_c, friendnum + 1, onion_c->path_nodes[num].ip_port, | 1267 | client_send_announce_request(onion_c, friendnum + 1, onion_c->path_nodes[num].ip_port, |
1172 | onion_c->path_nodes[num].client_id, 0, ~0); | 1268 | onion_c->path_nodes[num].public_key, 0, ~0); |
1173 | } | 1269 | } |
1270 | |||
1271 | ++onion_c->friends_list[friendnum].run_count; | ||
1174 | } | 1272 | } |
1273 | } else { | ||
1274 | ++onion_c->friends_list[friendnum].run_count; | ||
1175 | } | 1275 | } |
1176 | 1276 | ||
1177 | /* send packets to friend telling them our fake DHT id. */ | 1277 | /* send packets to friend telling them our DHT public key. */ |
1178 | if (is_timeout(onion_c->friends_list[friendnum].last_fakeid_onion_sent, ONION_FAKEID_INTERVAL)) | 1278 | if (is_timeout(onion_c->friends_list[friendnum].last_dht_pk_onion_sent, ONION_DHTPK_SEND_INTERVAL)) |
1179 | if (send_fakeid_announce(onion_c, friendnum, 0) >= 1) | 1279 | if (send_dhtpk_announce(onion_c, friendnum, 0) >= 1) |
1180 | onion_c->friends_list[friendnum].last_fakeid_onion_sent = unix_time(); | 1280 | onion_c->friends_list[friendnum].last_dht_pk_onion_sent = unix_time(); |
1181 | 1281 | ||
1182 | if (is_timeout(onion_c->friends_list[friendnum].last_fakeid_dht_sent, DHT_FAKEID_INTERVAL)) | 1282 | if (is_timeout(onion_c->friends_list[friendnum].last_dht_pk_dht_sent, DHT_DHTPK_SEND_INTERVAL)) |
1183 | if (send_fakeid_announce(onion_c, friendnum, 1) >= 1) | 1283 | if (send_dhtpk_announce(onion_c, friendnum, 1) >= 1) |
1184 | onion_c->friends_list[friendnum].last_fakeid_dht_sent = unix_time(); | 1284 | onion_c->friends_list[friendnum].last_dht_pk_dht_sent = unix_time(); |
1185 | 1285 | ||
1186 | } | 1286 | } |
1187 | } | 1287 | } |
1188 | 1288 | ||
1189 | /* Timeout before which a peer is considered dead and removed from the DHT search. */ | ||
1190 | #define DEAD_ONION_TIMEOUT (10 * 60) | ||
1191 | |||
1192 | static void cleanup_friend(Onion_Client *onion_c, uint16_t friendnum) | ||
1193 | { | ||
1194 | if (friendnum >= onion_c->num_friends) | ||
1195 | return; | ||
1196 | |||
1197 | if (onion_c->friends_list[friendnum].status == 0) | ||
1198 | return; | ||
1199 | |||
1200 | if (onion_c->friends_list[friendnum].is_fake_clientid && !onion_c->friends_list[friendnum].is_online | ||
1201 | && is_timeout(onion_c->friends_list[friendnum].last_seen, DEAD_ONION_TIMEOUT)) { | ||
1202 | onion_c->friends_list[friendnum].is_fake_clientid = 0; | ||
1203 | DHT_delfriend(onion_c->dht, onion_c->friends_list[friendnum].fake_client_id); | ||
1204 | } | ||
1205 | } | ||
1206 | 1289 | ||
1207 | /* Function to call when onion data packet with contents beginning with byte is received. */ | 1290 | /* Function to call when onion data packet with contents beginning with byte is received. */ |
1208 | void oniondata_registerhandler(Onion_Client *onion_c, uint8_t byte, oniondata_handler_callback cb, void *object) | 1291 | void oniondata_registerhandler(Onion_Client *onion_c, uint8_t byte, oniondata_handler_callback cb, void *object) |
@@ -1211,12 +1294,12 @@ void oniondata_registerhandler(Onion_Client *onion_c, uint8_t byte, oniondata_ha | |||
1211 | onion_c->Onion_Data_Handlers[byte].object = object; | 1294 | onion_c->Onion_Data_Handlers[byte].object = object; |
1212 | } | 1295 | } |
1213 | 1296 | ||
1214 | #define ANNOUNCE_INTERVAL_NOT_ANNOUNCED 5 | 1297 | #define ANNOUNCE_INTERVAL_NOT_ANNOUNCED 3 |
1215 | #define ANNOUNCE_INTERVAL_ANNOUNCED ONION_NODE_PING_INTERVAL | 1298 | #define ANNOUNCE_INTERVAL_ANNOUNCED ONION_NODE_PING_INTERVAL |
1216 | 1299 | ||
1217 | static void do_announce(Onion_Client *onion_c) | 1300 | static void do_announce(Onion_Client *onion_c) |
1218 | { | 1301 | { |
1219 | uint32_t i, count = 0; | 1302 | unsigned int i, count = 0; |
1220 | Onion_Node *list_nodes = onion_c->clients_announce_list; | 1303 | Onion_Node *list_nodes = onion_c->clients_announce_list; |
1221 | 1304 | ||
1222 | for (i = 0; i < MAX_ONION_CLIENTS; ++i) { | 1305 | for (i = 0; i < MAX_ONION_CLIENTS; ++i) { |
@@ -1231,14 +1314,14 @@ static void do_announce(Onion_Client *onion_c) | |||
1231 | continue; | 1314 | continue; |
1232 | } | 1315 | } |
1233 | 1316 | ||
1234 | uint32_t interval = ANNOUNCE_INTERVAL_NOT_ANNOUNCED; | 1317 | unsigned int interval = ANNOUNCE_INTERVAL_NOT_ANNOUNCED; |
1235 | 1318 | ||
1236 | if (list_nodes[i].is_stored) { | 1319 | if (list_nodes[i].is_stored) { |
1237 | interval = ANNOUNCE_INTERVAL_ANNOUNCED; | 1320 | interval = ANNOUNCE_INTERVAL_ANNOUNCED; |
1238 | } | 1321 | } |
1239 | 1322 | ||
1240 | if (is_timeout(list_nodes[i].last_pinged, interval)) { | 1323 | if (is_timeout(list_nodes[i].last_pinged, interval)) { |
1241 | if (client_send_announce_request(onion_c, 0, list_nodes[i].ip_port, list_nodes[i].client_id, | 1324 | if (client_send_announce_request(onion_c, 0, list_nodes[i].ip_port, list_nodes[i].public_key, |
1242 | list_nodes[i].ping_id, list_nodes[i].path_used) == 0) { | 1325 | list_nodes[i].ping_id, list_nodes[i].path_used) == 0) { |
1243 | list_nodes[i].last_pinged = unix_time(); | 1326 | list_nodes[i].last_pinged = unix_time(); |
1244 | } | 1327 | } |
@@ -1246,37 +1329,45 @@ static void do_announce(Onion_Client *onion_c) | |||
1246 | } | 1329 | } |
1247 | 1330 | ||
1248 | if (count != MAX_ONION_CLIENTS) { | 1331 | if (count != MAX_ONION_CLIENTS) { |
1249 | if (count < (uint32_t)rand() % MAX_ONION_CLIENTS) { | 1332 | unsigned int num_nodes; |
1333 | Node_format *path_nodes; | ||
1250 | 1334 | ||
1251 | unsigned int num_nodes = (onion_c->path_nodes_index < MAX_PATH_NODES) ? onion_c->path_nodes_index : MAX_PATH_NODES; | 1335 | if (rand() % 2 == 0 || onion_c->path_nodes_index == 0) { |
1336 | num_nodes = (onion_c->path_nodes_index_bs < MAX_PATH_NODES) ? onion_c->path_nodes_index_bs : MAX_PATH_NODES; | ||
1337 | path_nodes = onion_c->path_nodes_bs; | ||
1338 | } else { | ||
1339 | num_nodes = (onion_c->path_nodes_index < MAX_PATH_NODES) ? onion_c->path_nodes_index : MAX_PATH_NODES; | ||
1340 | path_nodes = onion_c->path_nodes; | ||
1341 | } | ||
1252 | 1342 | ||
1343 | if (count < (uint32_t)rand() % MAX_ONION_CLIENTS) { | ||
1253 | if (num_nodes != 0) { | 1344 | if (num_nodes != 0) { |
1254 | unsigned int num = rand() % num_nodes; | 1345 | for (i = 0; i < (MAX_ONION_CLIENTS / 2); ++i) { |
1255 | client_send_announce_request(onion_c, 0, onion_c->path_nodes[num].ip_port, onion_c->path_nodes[num].client_id, 0, ~0); | 1346 | unsigned int num = rand() % num_nodes; |
1347 | client_send_announce_request(onion_c, 0, path_nodes[num].ip_port, path_nodes[num].public_key, 0, ~0); | ||
1348 | } | ||
1256 | } | 1349 | } |
1257 | } | 1350 | } |
1258 | } | 1351 | } |
1259 | } | 1352 | } |
1260 | 1353 | ||
1261 | #define NODE_POPULATE_TIMES 4 | ||
1262 | |||
1263 | void do_onion_client(Onion_Client *onion_c) | 1354 | void do_onion_client(Onion_Client *onion_c) |
1264 | { | 1355 | { |
1265 | uint32_t i; | 1356 | unsigned int i; |
1266 | 1357 | ||
1267 | if (onion_c->last_run == unix_time()) | 1358 | if (onion_c->last_run == unix_time()) |
1268 | return; | 1359 | return; |
1269 | 1360 | ||
1270 | for (i = 0; i < NODE_POPULATE_TIMES; ++i) | 1361 | populate_path_nodes(onion_c); |
1271 | populate_path_nodes(onion_c); | ||
1272 | 1362 | ||
1273 | do_announce(onion_c); | 1363 | do_announce(onion_c); |
1274 | 1364 | ||
1275 | if (onion_isconnected(onion_c)) { | 1365 | if (onion_isconnected(onion_c)) { |
1276 | for (i = 0; i < onion_c->num_friends; ++i) { | 1366 | for (i = 0; i < onion_c->num_friends; ++i) { |
1277 | do_friend(onion_c, i); | 1367 | do_friend(onion_c, i); |
1278 | cleanup_friend(onion_c, i); | ||
1279 | } | 1368 | } |
1369 | } else { | ||
1370 | populate_path_nodes_tcp(onion_c); | ||
1280 | } | 1371 | } |
1281 | 1372 | ||
1282 | onion_c->last_run = unix_time(); | 1373 | onion_c->last_run = unix_time(); |
@@ -1304,8 +1395,8 @@ Onion_Client *new_onion_client(Net_Crypto *c) | |||
1304 | crypto_box_keypair(onion_c->temp_public_key, onion_c->temp_secret_key); | 1395 | crypto_box_keypair(onion_c->temp_public_key, onion_c->temp_secret_key); |
1305 | networking_registerhandler(onion_c->net, NET_PACKET_ANNOUNCE_RESPONSE, &handle_announce_response, onion_c); | 1396 | networking_registerhandler(onion_c->net, NET_PACKET_ANNOUNCE_RESPONSE, &handle_announce_response, onion_c); |
1306 | networking_registerhandler(onion_c->net, NET_PACKET_ONION_DATA_RESPONSE, &handle_data_response, onion_c); | 1397 | networking_registerhandler(onion_c->net, NET_PACKET_ONION_DATA_RESPONSE, &handle_data_response, onion_c); |
1307 | oniondata_registerhandler(onion_c, FAKEID_DATA_ID, &handle_fakeid_announce, onion_c); | 1398 | oniondata_registerhandler(onion_c, ONION_DATA_DHTPK, &handle_dhtpk_announce, onion_c); |
1308 | cryptopacket_registerhandler(onion_c->dht, FAKEID_DATA_ID, &handle_dht_fakeid, onion_c); | 1399 | cryptopacket_registerhandler(onion_c->dht, CRYPTO_PACKET_DHTPK, &handle_dht_dhtpk, onion_c); |
1309 | tcp_onion_response_handler(onion_c->c, &handle_tcp_onion, onion_c); | 1400 | tcp_onion_response_handler(onion_c->c, &handle_tcp_onion, onion_c); |
1310 | 1401 | ||
1311 | return onion_c; | 1402 | return onion_c; |
@@ -1320,8 +1411,8 @@ void kill_onion_client(Onion_Client *onion_c) | |||
1320 | realloc_onion_friends(onion_c, 0); | 1411 | realloc_onion_friends(onion_c, 0); |
1321 | networking_registerhandler(onion_c->net, NET_PACKET_ANNOUNCE_RESPONSE, NULL, NULL); | 1412 | networking_registerhandler(onion_c->net, NET_PACKET_ANNOUNCE_RESPONSE, NULL, NULL); |
1322 | networking_registerhandler(onion_c->net, NET_PACKET_ONION_DATA_RESPONSE, NULL, NULL); | 1413 | networking_registerhandler(onion_c->net, NET_PACKET_ONION_DATA_RESPONSE, NULL, NULL); |
1323 | oniondata_registerhandler(onion_c, FAKEID_DATA_ID, NULL, NULL); | 1414 | oniondata_registerhandler(onion_c, ONION_DATA_DHTPK, NULL, NULL); |
1324 | cryptopacket_registerhandler(onion_c->dht, FAKEID_DATA_ID, NULL, NULL); | 1415 | cryptopacket_registerhandler(onion_c->dht, CRYPTO_PACKET_DHTPK, NULL, NULL); |
1325 | tcp_onion_response_handler(onion_c->c, NULL, NULL); | 1416 | tcp_onion_response_handler(onion_c->c, NULL, NULL); |
1326 | memset(onion_c, 0, sizeof(Onion_Client)); | 1417 | memset(onion_c, 0, sizeof(Onion_Client)); |
1327 | free(onion_c); | 1418 | free(onion_c); |
@@ -1333,10 +1424,34 @@ void kill_onion_client(Onion_Client *onion_c) | |||
1333 | */ | 1424 | */ |
1334 | int onion_isconnected(const Onion_Client *onion_c) | 1425 | int onion_isconnected(const Onion_Client *onion_c) |
1335 | { | 1426 | { |
1336 | unsigned int i; | 1427 | unsigned int i, num = 0, announced = 0; |
1428 | |||
1429 | if (is_timeout(onion_c->last_packet_recv, ONION_OFFLINE_TIMEOUT)) | ||
1430 | return 0; | ||
1431 | |||
1432 | if (onion_c->path_nodes_index == 0) | ||
1433 | return 0; | ||
1337 | 1434 | ||
1338 | for (i = 0; i < MAX_ONION_CLIENTS; ++i) { | 1435 | for (i = 0; i < MAX_ONION_CLIENTS; ++i) { |
1339 | if (!is_timeout(onion_c->clients_announce_list[i].timestamp, ONION_NODE_TIMEOUT)) | 1436 | if (!is_timeout(onion_c->clients_announce_list[i].timestamp, ONION_NODE_TIMEOUT)) { |
1437 | ++num; | ||
1438 | |||
1439 | if (onion_c->clients_announce_list[i].is_stored) { | ||
1440 | ++announced; | ||
1441 | } | ||
1442 | } | ||
1443 | } | ||
1444 | |||
1445 | unsigned int pnodes = onion_c->path_nodes_index; | ||
1446 | |||
1447 | if (pnodes > MAX_ONION_CLIENTS) { | ||
1448 | pnodes = MAX_ONION_CLIENTS; | ||
1449 | } | ||
1450 | |||
1451 | /* Consider ourselves online if we are announced to half or more nodes | ||
1452 | we are connected to */ | ||
1453 | if (num && announced) { | ||
1454 | if ((num / 2) <= announced && (pnodes / 2) <= num) | ||
1340 | return 1; | 1455 | return 1; |
1341 | } | 1456 | } |
1342 | 1457 | ||
diff --git a/toxcore/onion_client.h b/toxcore/onion_client.h index cf0975d3..6851d929 100644 --- a/toxcore/onion_client.h +++ b/toxcore/onion_client.h | |||
@@ -29,28 +29,38 @@ | |||
29 | #include "ping_array.h" | 29 | #include "ping_array.h" |
30 | 30 | ||
31 | #define MAX_ONION_CLIENTS 8 | 31 | #define MAX_ONION_CLIENTS 8 |
32 | #define ONION_NODE_PING_INTERVAL 30 | 32 | #define ONION_NODE_PING_INTERVAL 20 |
33 | #define ONION_NODE_TIMEOUT (ONION_NODE_PING_INTERVAL * 4) | 33 | #define ONION_NODE_TIMEOUT (ONION_NODE_PING_INTERVAL * 3) |
34 | 34 | ||
35 | /* The interval in seconds at which to tell our friends where we are */ | 35 | /* The interval in seconds at which to tell our friends where we are */ |
36 | #define ONION_FAKEID_INTERVAL 30 | 36 | #define ONION_DHTPK_SEND_INTERVAL 30 |
37 | #define DHT_FAKEID_INTERVAL 20 | 37 | #define DHT_DHTPK_SEND_INTERVAL 20 |
38 | 38 | ||
39 | #define NUMBER_ONION_PATHS 3 | 39 | #define NUMBER_ONION_PATHS 6 |
40 | 40 | ||
41 | /* The timeout the first time the path is added and | 41 | /* The timeout the first time the path is added and |
42 | then for all the next consecutive times */ | 42 | then for all the next consecutive times */ |
43 | #define ONION_PATH_FIRST_TIMEOUT 5 | 43 | #define ONION_PATH_FIRST_TIMEOUT 4 |
44 | #define ONION_PATH_TIMEOUT 30 | 44 | #define ONION_PATH_TIMEOUT 10 |
45 | #define ONION_PATH_MAX_LIFETIME 600 | 45 | #define ONION_PATH_MAX_LIFETIME 1200 |
46 | #define ONION_PATH_MAX_NO_RESPONSE_USES 4 | ||
46 | 47 | ||
47 | #define MAX_STORED_PINGED_NODES 9 | 48 | #define MAX_STORED_PINGED_NODES 9 |
48 | #define MIN_NODE_PING_TIME 10 | 49 | #define MIN_NODE_PING_TIME 10 |
49 | 50 | ||
50 | #define MAX_PATH_NODES 32 | 51 | #define MAX_PATH_NODES 32 |
51 | 52 | ||
53 | /* If no packets are received within that interval tox will | ||
54 | * be considered offline. | ||
55 | */ | ||
56 | #define ONION_OFFLINE_TIMEOUT (ONION_NODE_PING_INTERVAL * 1.25) | ||
57 | |||
58 | /* Onion data packet ids. */ | ||
59 | #define ONION_DATA_FRIEND_REQ CRYPTO_PACKET_FRIEND_REQ | ||
60 | #define ONION_DATA_DHTPK CRYPTO_PACKET_DHTPK | ||
61 | |||
52 | typedef struct { | 62 | typedef struct { |
53 | uint8_t client_id[CLIENT_ID_SIZE]; | 63 | uint8_t public_key[crypto_box_PUBLICKEYBYTES]; |
54 | IP_Port ip_port; | 64 | IP_Port ip_port; |
55 | uint8_t ping_id[ONION_PING_ID_SIZE]; | 65 | uint8_t ping_id[ONION_PING_ID_SIZE]; |
56 | uint8_t data_public_key[crypto_box_PUBLICKEYBYTES]; | 66 | uint8_t data_public_key[crypto_box_PUBLICKEYBYTES]; |
@@ -66,11 +76,14 @@ typedef struct { | |||
66 | typedef struct { | 76 | typedef struct { |
67 | Onion_Path paths[NUMBER_ONION_PATHS]; | 77 | Onion_Path paths[NUMBER_ONION_PATHS]; |
68 | uint64_t last_path_success[NUMBER_ONION_PATHS]; | 78 | uint64_t last_path_success[NUMBER_ONION_PATHS]; |
79 | uint64_t last_path_used[NUMBER_ONION_PATHS]; | ||
69 | uint64_t path_creation_time[NUMBER_ONION_PATHS]; | 80 | uint64_t path_creation_time[NUMBER_ONION_PATHS]; |
81 | /* number of times used without success. */ | ||
82 | unsigned int last_path_used_times[NUMBER_ONION_PATHS]; | ||
70 | } Onion_Client_Paths; | 83 | } Onion_Client_Paths; |
71 | 84 | ||
72 | typedef struct { | 85 | typedef struct { |
73 | uint8_t client_id[CLIENT_ID_SIZE]; | 86 | uint8_t public_key[crypto_box_PUBLICKEYBYTES]; |
74 | uint64_t timestamp; | 87 | uint64_t timestamp; |
75 | } Last_Pinged; | 88 | } Last_Pinged; |
76 | 89 | ||
@@ -78,24 +91,21 @@ typedef struct { | |||
78 | uint8_t status; /* 0 if friend is not valid, 1 if friend is valid.*/ | 91 | uint8_t status; /* 0 if friend is not valid, 1 if friend is valid.*/ |
79 | uint8_t is_online; /* Set by the onion_set_friend_status function. */ | 92 | uint8_t is_online; /* Set by the onion_set_friend_status function. */ |
80 | 93 | ||
81 | uint8_t is_fake_clientid; /* 0 if we don't know the fake client id of the other 1 if we do. */ | 94 | uint8_t know_dht_public_key; /* 0 if we don't know the dht public key of the other, 1 if we do. */ |
82 | uint64_t fake_client_id_timestamp; | 95 | uint8_t dht_public_key[crypto_box_PUBLICKEYBYTES]; |
83 | uint8_t fake_client_id[crypto_box_PUBLICKEYBYTES]; | 96 | uint8_t real_public_key[crypto_box_PUBLICKEYBYTES]; |
84 | uint8_t real_client_id[crypto_box_PUBLICKEYBYTES]; | ||
85 | 97 | ||
86 | Onion_Node clients_list[MAX_ONION_CLIENTS]; | 98 | Onion_Node clients_list[MAX_ONION_CLIENTS]; |
87 | uint8_t temp_public_key[crypto_box_PUBLICKEYBYTES]; | 99 | uint8_t temp_public_key[crypto_box_PUBLICKEYBYTES]; |
88 | uint8_t temp_secret_key[crypto_box_SECRETKEYBYTES]; | 100 | uint8_t temp_secret_key[crypto_box_SECRETKEYBYTES]; |
89 | 101 | ||
90 | uint64_t last_fakeid_onion_sent; | 102 | uint64_t last_dht_pk_onion_sent; |
91 | uint64_t last_fakeid_dht_sent; | 103 | uint64_t last_dht_pk_dht_sent; |
92 | 104 | ||
93 | uint64_t last_noreplay; | 105 | uint64_t last_noreplay; |
94 | 106 | ||
95 | uint64_t last_seen; | 107 | uint64_t last_seen; |
96 | 108 | ||
97 | Onion_Client_Paths onion_paths; | ||
98 | |||
99 | Last_Pinged last_pinged[MAX_STORED_PINGED_NODES]; | 109 | Last_Pinged last_pinged[MAX_STORED_PINGED_NODES]; |
100 | uint8_t last_pinged_index; | 110 | uint8_t last_pinged_index; |
101 | 111 | ||
@@ -103,11 +113,15 @@ typedef struct { | |||
103 | void *tcp_relay_node_callback_object; | 113 | void *tcp_relay_node_callback_object; |
104 | uint32_t tcp_relay_node_callback_number; | 114 | uint32_t tcp_relay_node_callback_number; |
105 | 115 | ||
116 | void (*dht_pk_callback)(void *data, int32_t number, const uint8_t *dht_public_key); | ||
117 | void *dht_pk_callback_object; | ||
118 | uint32_t dht_pk_callback_number; | ||
119 | |||
106 | uint32_t run_count; | 120 | uint32_t run_count; |
107 | } Onion_Friend; | 121 | } Onion_Friend; |
108 | 122 | ||
109 | typedef int (*oniondata_handler_callback)(void *object, const uint8_t *source_pubkey, const uint8_t *data, | 123 | typedef int (*oniondata_handler_callback)(void *object, const uint8_t *source_pubkey, const uint8_t *data, |
110 | uint32_t len); | 124 | uint16_t len); |
111 | 125 | ||
112 | typedef struct { | 126 | typedef struct { |
113 | DHT *dht; | 127 | DHT *dht; |
@@ -118,7 +132,8 @@ typedef struct { | |||
118 | 132 | ||
119 | Onion_Node clients_announce_list[MAX_ONION_CLIENTS]; | 133 | Onion_Node clients_announce_list[MAX_ONION_CLIENTS]; |
120 | 134 | ||
121 | Onion_Client_Paths onion_paths; | 135 | Onion_Client_Paths onion_paths_self; |
136 | Onion_Client_Paths onion_paths_friends; | ||
122 | 137 | ||
123 | uint8_t secret_symmetric_key[crypto_box_KEYBYTES]; | 138 | uint8_t secret_symmetric_key[crypto_box_KEYBYTES]; |
124 | uint64_t last_run; | 139 | uint64_t last_run; |
@@ -131,21 +146,26 @@ typedef struct { | |||
131 | Node_format path_nodes[MAX_PATH_NODES]; | 146 | Node_format path_nodes[MAX_PATH_NODES]; |
132 | uint16_t path_nodes_index; | 147 | uint16_t path_nodes_index; |
133 | 148 | ||
149 | Node_format path_nodes_bs[MAX_PATH_NODES]; | ||
150 | uint16_t path_nodes_index_bs; | ||
151 | |||
134 | Ping_Array announce_ping_array; | 152 | Ping_Array announce_ping_array; |
135 | uint8_t last_pinged_index; | 153 | uint8_t last_pinged_index; |
136 | struct { | 154 | struct { |
137 | oniondata_handler_callback function; | 155 | oniondata_handler_callback function; |
138 | void *object; | 156 | void *object; |
139 | } Onion_Data_Handlers[256]; | 157 | } Onion_Data_Handlers[256]; |
158 | |||
159 | uint64_t last_packet_recv; | ||
140 | } Onion_Client; | 160 | } Onion_Client; |
141 | 161 | ||
142 | 162 | ||
143 | /* Add a node to the path_nodes array. | 163 | /* Add a node to the path_nodes bootstrap array. |
144 | * | 164 | * |
145 | * return -1 on failure | 165 | * return -1 on failure |
146 | * return 0 on success | 166 | * return 0 on success |
147 | */ | 167 | */ |
148 | int onion_add_path_node(Onion_Client *onion_c, IP_Port ip_port, const uint8_t *client_id); | 168 | int onion_add_bs_path_node(Onion_Client *onion_c, IP_Port ip_port, const uint8_t *public_key); |
149 | 169 | ||
150 | /* Put up to max_num nodes in nodes. | 170 | /* Put up to max_num nodes in nodes. |
151 | * | 171 | * |
@@ -158,14 +178,14 @@ uint16_t onion_backup_nodes(const Onion_Client *onion_c, Node_format *nodes, uin | |||
158 | * return -1 on failure. | 178 | * return -1 on failure. |
159 | * return the friend number on success or if the friend was already added. | 179 | * return the friend number on success or if the friend was already added. |
160 | */ | 180 | */ |
161 | int onion_friend_num(const Onion_Client *onion_c, const uint8_t *client_id); | 181 | int onion_friend_num(const Onion_Client *onion_c, const uint8_t *public_key); |
162 | 182 | ||
163 | /* Add a friend who we want to connect to. | 183 | /* Add a friend who we want to connect to. |
164 | * | 184 | * |
165 | * return -1 on failure. | 185 | * return -1 on failure. |
166 | * return the friend number on success. | 186 | * return the friend number on success. |
167 | */ | 187 | */ |
168 | int onion_addfriend(Onion_Client *onion_c, const uint8_t *client_id); | 188 | int onion_addfriend(Onion_Client *onion_c, const uint8_t *public_key); |
169 | 189 | ||
170 | /* Delete a friend. | 190 | /* Delete a friend. |
171 | * | 191 | * |
@@ -187,9 +207,9 @@ int onion_set_friend_online(Onion_Client *onion_c, int friend_num, uint8_t is_on | |||
187 | 207 | ||
188 | /* Get the ip of friend friendnum and put it in ip_port | 208 | /* Get the ip of friend friendnum and put it in ip_port |
189 | * | 209 | * |
190 | * return -1, -- if client_id does NOT refer to a friend | 210 | * return -1, -- if public_key does NOT refer to a friend |
191 | * return 0, -- if client_id refers to a friend and we failed to find the friend (yet) | 211 | * return 0, -- if public_key refers to a friend and we failed to find the friend (yet) |
192 | * return 1, ip if client_id refers to a friend and we found him | 212 | * return 1, ip if public_key refers to a friend and we found him |
193 | * | 213 | * |
194 | */ | 214 | */ |
195 | int onion_getfriendip(const Onion_Client *onion_c, int friend_num, IP_Port *ip_port); | 215 | int onion_getfriendip(const Onion_Client *onion_c, int friend_num, IP_Port *ip_port); |
@@ -205,6 +225,18 @@ int onion_getfriendip(const Onion_Client *onion_c, int friend_num, IP_Port *ip_p | |||
205 | int recv_tcp_relay_handler(Onion_Client *onion_c, int friend_num, int (*tcp_relay_node_callback)(void *object, | 225 | int recv_tcp_relay_handler(Onion_Client *onion_c, int friend_num, int (*tcp_relay_node_callback)(void *object, |
206 | uint32_t number, IP_Port ip_port, const uint8_t *public_key), void *object, uint32_t number); | 226 | uint32_t number, IP_Port ip_port, const uint8_t *public_key), void *object, uint32_t number); |
207 | 227 | ||
228 | |||
229 | /* Set the function for this friend that will be callbacked with object and number | ||
230 | * when that friend gives us his DHT temporary public key. | ||
231 | * | ||
232 | * object and number will be passed as argument to this function. | ||
233 | * | ||
234 | * return -1 on failure. | ||
235 | * return 0 on success. | ||
236 | */ | ||
237 | int onion_dht_pk_callback(Onion_Client *onion_c, int friend_num, void (*function)(void *data, int32_t number, | ||
238 | const uint8_t *dht_public_key), void *object, uint32_t number); | ||
239 | |||
208 | /* Set a friends DHT public key. | 240 | /* Set a friends DHT public key. |
209 | * timestamp is the time (current_time_monotonic()) at which the key was last confirmed belonging to | 241 | * timestamp is the time (current_time_monotonic()) at which the key was last confirmed belonging to |
210 | * the other peer. | 242 | * the other peer. |
@@ -212,14 +244,14 @@ int recv_tcp_relay_handler(Onion_Client *onion_c, int friend_num, int (*tcp_rela | |||
212 | * return -1 on failure. | 244 | * return -1 on failure. |
213 | * return 0 on success. | 245 | * return 0 on success. |
214 | */ | 246 | */ |
215 | int onion_set_friend_DHT_pubkey(Onion_Client *onion_c, int friend_num, const uint8_t *dht_key, uint64_t timestamp); | 247 | int onion_set_friend_DHT_pubkey(Onion_Client *onion_c, int friend_num, const uint8_t *dht_key); |
216 | 248 | ||
217 | /* Copy friends DHT public key into dht_key. | 249 | /* Copy friends DHT public key into dht_key. |
218 | * | 250 | * |
219 | * return 0 on failure (no key copied). | 251 | * return 0 on failure (no key copied). |
220 | * return timestamp on success (key copied). | 252 | * return 1 on success (key copied). |
221 | */ | 253 | */ |
222 | uint64_t onion_getfriend_DHT_pubkey(const Onion_Client *onion_c, int friend_num, uint8_t *dht_key); | 254 | unsigned int onion_getfriend_DHT_pubkey(const Onion_Client *onion_c, int friend_num, uint8_t *dht_key); |
223 | 255 | ||
224 | #define ONION_DATA_IN_RESPONSE_MIN_SIZE (crypto_box_PUBLICKEYBYTES + crypto_box_MACBYTES) | 256 | #define ONION_DATA_IN_RESPONSE_MIN_SIZE (crypto_box_PUBLICKEYBYTES + crypto_box_MACBYTES) |
225 | #define ONION_CLIENT_MAX_DATA_SIZE (MAX_DATA_REQUEST_SIZE - ONION_DATA_IN_RESPONSE_MIN_SIZE) | 257 | #define ONION_CLIENT_MAX_DATA_SIZE (MAX_DATA_REQUEST_SIZE - ONION_DATA_IN_RESPONSE_MIN_SIZE) |
@@ -233,7 +265,7 @@ uint64_t onion_getfriend_DHT_pubkey(const Onion_Client *onion_c, int friend_num, | |||
233 | * return the number of packets sent on success | 265 | * return the number of packets sent on success |
234 | * return -1 on failure. | 266 | * return -1 on failure. |
235 | */ | 267 | */ |
236 | int send_onion_data(const Onion_Client *onion_c, int friend_num, const uint8_t *data, uint32_t length); | 268 | int send_onion_data(Onion_Client *onion_c, int friend_num, const uint8_t *data, uint16_t length); |
237 | 269 | ||
238 | /* Function to call when onion data packet with contents beginning with byte is received. */ | 270 | /* Function to call when onion data packet with contents beginning with byte is received. */ |
239 | void oniondata_registerhandler(Onion_Client *onion_c, uint8_t byte, oniondata_handler_callback cb, void *object); | 271 | void oniondata_registerhandler(Onion_Client *onion_c, uint8_t byte, oniondata_handler_callback cb, void *object); |
diff --git a/toxcore/ping.c b/toxcore/ping.c index e00036af..1c3564a3 100644 --- a/toxcore/ping.c +++ b/toxcore/ping.c | |||
@@ -39,10 +39,10 @@ | |||
39 | #define PING_NUM_MAX 512 | 39 | #define PING_NUM_MAX 512 |
40 | 40 | ||
41 | /* Maximum newly announced nodes to ping per TIME_TO_PING seconds. */ | 41 | /* Maximum newly announced nodes to ping per TIME_TO_PING seconds. */ |
42 | #define MAX_TO_PING 8 | 42 | #define MAX_TO_PING 16 |
43 | 43 | ||
44 | /* Ping newly announced nodes to ping per TIME_TO_PING seconds*/ | 44 | /* Ping newly announced nodes to ping per TIME_TO_PING seconds*/ |
45 | #define TIME_TO_PING 8 | 45 | #define TIME_TO_PING 4 |
46 | 46 | ||
47 | 47 | ||
48 | struct PING { | 48 | struct PING { |
@@ -129,7 +129,7 @@ static int send_ping_response(PING *ping, IP_Port ipp, const uint8_t *client_id, | |||
129 | return sendpacket(ping->dht->net, ipp, pk, sizeof(pk)); | 129 | return sendpacket(ping->dht->net, ipp, pk, sizeof(pk)); |
130 | } | 130 | } |
131 | 131 | ||
132 | static int handle_ping_request(void *_dht, IP_Port source, const uint8_t *packet, uint32_t length) | 132 | static int handle_ping_request(void *_dht, IP_Port source, const uint8_t *packet, uint16_t length) |
133 | { | 133 | { |
134 | DHT *dht = _dht; | 134 | DHT *dht = _dht; |
135 | int rc; | 135 | int rc; |
@@ -168,7 +168,7 @@ static int handle_ping_request(void *_dht, IP_Port source, const uint8_t *packet | |||
168 | return 0; | 168 | return 0; |
169 | } | 169 | } |
170 | 170 | ||
171 | static int handle_ping_response(void *_dht, IP_Port source, const uint8_t *packet, uint32_t length) | 171 | static int handle_ping_response(void *_dht, IP_Port source, const uint8_t *packet, uint16_t length) |
172 | { | 172 | { |
173 | DHT *dht = _dht; | 173 | DHT *dht = _dht; |
174 | int rc; | 174 | int rc; |
@@ -225,7 +225,7 @@ static int handle_ping_response(void *_dht, IP_Port source, const uint8_t *packe | |||
225 | * return 1 if it is. | 225 | * return 1 if it is. |
226 | * return 0 if it isn't. | 226 | * return 0 if it isn't. |
227 | */ | 227 | */ |
228 | static int in_list(const Client_data *list, uint32_t length, const uint8_t *client_id, IP_Port ip_port) | 228 | static int in_list(const Client_data *list, uint16_t length, const uint8_t *client_id, IP_Port ip_port) |
229 | { | 229 | { |
230 | uint32_t i; | 230 | uint32_t i; |
231 | 231 | ||
@@ -269,12 +269,12 @@ int add_to_ping(PING *ping, const uint8_t *client_id, IP_Port ip_port) | |||
269 | 269 | ||
270 | for (i = 0; i < MAX_TO_PING; ++i) { | 270 | for (i = 0; i < MAX_TO_PING; ++i) { |
271 | if (!ip_isset(&ping->to_ping[i].ip_port.ip)) { | 271 | if (!ip_isset(&ping->to_ping[i].ip_port.ip)) { |
272 | memcpy(ping->to_ping[i].client_id, client_id, CLIENT_ID_SIZE); | 272 | memcpy(ping->to_ping[i].public_key, client_id, CLIENT_ID_SIZE); |
273 | ipport_copy(&ping->to_ping[i].ip_port, &ip_port); | 273 | ipport_copy(&ping->to_ping[i].ip_port, &ip_port); |
274 | return 0; | 274 | return 0; |
275 | } | 275 | } |
276 | 276 | ||
277 | if (memcmp(ping->to_ping[i].client_id, client_id, CLIENT_ID_SIZE) == 0) { | 277 | if (memcmp(ping->to_ping[i].public_key, client_id, CLIENT_ID_SIZE) == 0) { |
278 | return -1; | 278 | return -1; |
279 | } | 279 | } |
280 | } | 280 | } |
@@ -282,8 +282,8 @@ int add_to_ping(PING *ping, const uint8_t *client_id, IP_Port ip_port) | |||
282 | uint32_t r = rand(); | 282 | uint32_t r = rand(); |
283 | 283 | ||
284 | for (i = 0; i < MAX_TO_PING; ++i) { | 284 | for (i = 0; i < MAX_TO_PING; ++i) { |
285 | if (id_closest(ping->dht->self_public_key, ping->to_ping[(i + r) % MAX_TO_PING].client_id, client_id) == 2) { | 285 | if (id_closest(ping->dht->self_public_key, ping->to_ping[(i + r) % MAX_TO_PING].public_key, client_id) == 2) { |
286 | memcpy(ping->to_ping[(i + r) % MAX_TO_PING].client_id, client_id, CLIENT_ID_SIZE); | 286 | memcpy(ping->to_ping[(i + r) % MAX_TO_PING].public_key, client_id, CLIENT_ID_SIZE); |
287 | ipport_copy(&ping->to_ping[(i + r) % MAX_TO_PING].ip_port, &ip_port); | 287 | ipport_copy(&ping->to_ping[(i + r) % MAX_TO_PING].ip_port, &ip_port); |
288 | return 0; | 288 | return 0; |
289 | } | 289 | } |
@@ -301,6 +301,9 @@ void do_to_ping(PING *ping) | |||
301 | if (!is_timeout(ping->last_to_ping, TIME_TO_PING)) | 301 | if (!is_timeout(ping->last_to_ping, TIME_TO_PING)) |
302 | return; | 302 | return; |
303 | 303 | ||
304 | if (!ip_isset(&ping->to_ping[0].ip_port.ip)) | ||
305 | return; | ||
306 | |||
304 | ping->last_to_ping = unix_time(); | 307 | ping->last_to_ping = unix_time(); |
305 | uint32_t i; | 308 | uint32_t i; |
306 | 309 | ||
@@ -308,7 +311,7 @@ void do_to_ping(PING *ping) | |||
308 | if (!ip_isset(&ping->to_ping[i].ip_port.ip)) | 311 | if (!ip_isset(&ping->to_ping[i].ip_port.ip)) |
309 | return; | 312 | return; |
310 | 313 | ||
311 | send_ping_request(ping, ping->to_ping[i].ip_port, ping->to_ping[i].client_id); | 314 | send_ping_request(ping, ping->to_ping[i].ip_port, ping->to_ping[i].public_key); |
312 | ip_reset(&ping->to_ping[i].ip_port.ip); | 315 | ip_reset(&ping->to_ping[i].ip_port.ip); |
313 | } | 316 | } |
314 | } | 317 | } |
diff --git a/toxcore/tox.c b/toxcore/tox.c index ca87bbe1..db100459 100644 --- a/toxcore/tox.c +++ b/toxcore/tox.c | |||
@@ -26,831 +26,685 @@ | |||
26 | #endif | 26 | #endif |
27 | 27 | ||
28 | #include "Messenger.h" | 28 | #include "Messenger.h" |
29 | #include "group.h" | ||
29 | #include "logger.h" | 30 | #include "logger.h" |
30 | 31 | ||
31 | #define __TOX_DEFINED__ | 32 | #include "../toxencryptsave/defines.h" |
33 | |||
34 | #define TOX_DEFINED | ||
32 | typedef struct Messenger Tox; | 35 | typedef struct Messenger Tox; |
33 | 36 | ||
34 | #include "tox.h" | 37 | #include "tox.h" |
35 | 38 | ||
36 | /* | 39 | #define SET_ERROR_PARAMETER(param, x) {if(param) {*param = x;}} |
37 | * returns a FRIEND_ADDRESS_SIZE byte address to give to others. | ||
38 | * Format: [client_id (32 bytes)][nospam number (4 bytes)][checksum (2 bytes)] | ||
39 | * | ||
40 | */ | ||
41 | void tox_get_address(const Tox *tox, uint8_t *address) | ||
42 | { | ||
43 | const Messenger *m = tox; | ||
44 | getaddress(m, address); | ||
45 | } | ||
46 | 40 | ||
47 | /* | 41 | uint32_t tox_version_major(void) |
48 | * Add a friend. | ||
49 | * Set the data that will be sent along with friend request. | ||
50 | * address is the address of the friend (returned by getaddress of the friend you wish to add) it must be FRIEND_ADDRESS_SIZE bytes. TODO: add checksum. | ||
51 | * data is the data and length is the length. | ||
52 | * | ||
53 | * return the friend number if success. | ||
54 | * return FA_TOOLONG if message length is too long. | ||
55 | * return FAERR_NOMESSAGE if no message (message length must be >= 1 byte). | ||
56 | * return FAERR_OWNKEY if user's own key. | ||
57 | * return FAERR_ALREADYSENT if friend request already sent or already a friend. | ||
58 | * return FAERR_UNKNOWN for unknown error. | ||
59 | * return FAERR_BADCHECKSUM if bad checksum in address. | ||
60 | * return FAERR_SETNEWNOSPAM if the friend was already there but the nospam was different. | ||
61 | * (the nospam for that friend was set to the new one). | ||
62 | * return FAERR_NOMEM if increasing the friend list size fails. | ||
63 | */ | ||
64 | int32_t tox_add_friend(Tox *tox, const uint8_t *address, const uint8_t *data, uint16_t length) | ||
65 | { | 42 | { |
66 | Messenger *m = tox; | 43 | return 0; |
67 | return m_addfriend(m, address, data, length); | ||
68 | } | 44 | } |
69 | 45 | ||
70 | /* Add a friend without sending a friendrequest. | 46 | uint32_t tox_version_minor(void) |
71 | * | ||
72 | * return the friend number if success. | ||
73 | * return -1 if failure. | ||
74 | */ | ||
75 | int32_t tox_add_friend_norequest(Tox *tox, const uint8_t *client_id) | ||
76 | { | 47 | { |
77 | Messenger *m = tox; | 48 | return 0; |
78 | return m_addfriend_norequest(m, client_id); | ||
79 | } | 49 | } |
80 | 50 | ||
81 | /* return the friend number associated to that client id. | 51 | uint32_t tox_version_patch(void) |
82 | * return -1 if no such friend. | ||
83 | */ | ||
84 | int32_t tox_get_friend_number(const Tox *tox, const uint8_t *client_id) | ||
85 | { | 52 | { |
86 | const Messenger *m = tox; | 53 | return 0; |
87 | return getfriend_id(m, client_id); | ||
88 | } | 54 | } |
89 | 55 | ||
90 | /* Copies the public key associated to that friend id into client_id buffer. | 56 | bool tox_version_is_compatible(uint32_t major, uint32_t minor, uint32_t patch) |
91 | * Make sure that client_id is of size CLIENT_ID_SIZE. | ||
92 | * | ||
93 | * return 0 if success. | ||
94 | * return -1 if failure. | ||
95 | */ | ||
96 | int tox_get_client_id(const Tox *tox, int32_t friendnumber, uint8_t *client_id) | ||
97 | { | 57 | { |
98 | const Messenger *m = tox; | 58 | //TODO |
99 | return getclient_id(m, friendnumber, client_id); | 59 | return 1; |
100 | } | 60 | } |
101 | 61 | ||
102 | /* Remove a friend. */ | ||
103 | int tox_del_friend(Tox *tox, int32_t friendnumber) | ||
104 | { | ||
105 | Messenger *m = tox; | ||
106 | return m_delfriend(m, friendnumber); | ||
107 | } | ||
108 | 62 | ||
109 | /* Checks friend's connecting status. | 63 | void tox_options_default(struct Tox_Options *options) |
110 | * | ||
111 | * return 1 if friend is connected to us (Online). | ||
112 | * return 0 if friend is not connected to us (Offline). | ||
113 | * return -1 on failure. | ||
114 | */ | ||
115 | int tox_get_friend_connection_status(const Tox *tox, int32_t friendnumber) | ||
116 | { | 64 | { |
117 | const Messenger *m = tox; | 65 | if (options) { |
118 | return m_get_friend_connectionstatus(m, friendnumber); | 66 | memset(options, 0, sizeof(struct Tox_Options)); |
67 | options->ipv6_enabled = 1; | ||
68 | options->udp_enabled = 1; | ||
69 | options->proxy_type = TOX_PROXY_TYPE_NONE; | ||
70 | } | ||
119 | } | 71 | } |
120 | 72 | ||
121 | /* Checks if there exists a friend with given friendnumber. | 73 | struct Tox_Options *tox_options_new(TOX_ERR_OPTIONS_NEW *error) |
122 | * | ||
123 | * return 1 if friend exists. | ||
124 | * return 0 if friend doesn't exist. | ||
125 | */ | ||
126 | int tox_friend_exists(const Tox *tox, int32_t friendnumber) | ||
127 | { | 74 | { |
128 | const Messenger *m = tox; | 75 | struct Tox_Options *options = calloc(sizeof(struct Tox_Options), 1); |
129 | return m_friend_exists(m, friendnumber); | 76 | |
77 | if (options) { | ||
78 | SET_ERROR_PARAMETER(error, TOX_ERR_OPTIONS_NEW_OK); | ||
79 | return options; | ||
80 | } | ||
81 | |||
82 | SET_ERROR_PARAMETER(error, TOX_ERR_OPTIONS_NEW_MALLOC); | ||
83 | return NULL; | ||
130 | } | 84 | } |
131 | 85 | ||
132 | /* Send a text chat message to an online friend. | 86 | void tox_options_free(struct Tox_Options *options) |
133 | * return the message id if packet was successfully put into the send queue. | ||
134 | * return 0 if it was not. | ||
135 | * | ||
136 | * You will want to retain the return value, it will be passed to your read_receipt callback | ||
137 | * if one is received. | ||
138 | */ | ||
139 | uint32_t tox_send_message(Tox *tox, int32_t friendnumber, const uint8_t *message, uint32_t length) | ||
140 | { | 87 | { |
141 | Messenger *m = tox; | 88 | free(options); |
142 | return m_sendmessage(m, friendnumber, message, length); | ||
143 | } | 89 | } |
144 | 90 | ||
145 | /* Send an action to an online friend. | 91 | Tox *tox_new(const struct Tox_Options *options, const uint8_t *data, size_t length, TOX_ERR_NEW *error) |
146 | * | ||
147 | * return the message id if packet was successfully put into the send queue. | ||
148 | * return 0 if it was not. | ||
149 | * | ||
150 | * You will want to retain the return value, it will be passed to your read_receipt callback | ||
151 | * if one is received. | ||
152 | */ | ||
153 | uint32_t tox_send_action(Tox *tox, int32_t friendnumber, const uint8_t *action, uint32_t length) | ||
154 | { | 92 | { |
155 | Messenger *m = tox; | 93 | if (!logger_get_global()) |
156 | return m_sendaction(m, friendnumber, action, length); | 94 | logger_set_global(logger_new(LOGGER_OUTPUT_FILE, LOGGER_LEVEL, "toxcore")); |
95 | |||
96 | if (data) { | ||
97 | if (memcmp(data, TOX_ENC_SAVE_MAGIC_NUMBER, TOX_ENC_SAVE_MAGIC_LENGTH) == 0) { | ||
98 | SET_ERROR_PARAMETER(error, TOX_ERR_NEW_LOAD_ENCRYPTED); | ||
99 | return NULL; | ||
100 | } | ||
101 | } | ||
102 | |||
103 | Messenger_Options m_options = {0}; | ||
104 | |||
105 | if (options == NULL) { | ||
106 | m_options.ipv6enabled = TOX_ENABLE_IPV6_DEFAULT; | ||
107 | } else { | ||
108 | m_options.ipv6enabled = options->ipv6_enabled; | ||
109 | m_options.udp_disabled = !options->udp_enabled; | ||
110 | |||
111 | switch (options->proxy_type) { | ||
112 | case TOX_PROXY_TYPE_HTTP: | ||
113 | m_options.proxy_info.proxy_type = TCP_PROXY_HTTP; | ||
114 | break; | ||
115 | |||
116 | case TOX_PROXY_TYPE_SOCKS5: | ||
117 | m_options.proxy_info.proxy_type = TCP_PROXY_SOCKS5; | ||
118 | break; | ||
119 | |||
120 | case TOX_PROXY_TYPE_NONE: | ||
121 | m_options.proxy_info.proxy_type = TCP_PROXY_NONE; | ||
122 | break; | ||
123 | |||
124 | default: | ||
125 | SET_ERROR_PARAMETER(error, TOX_ERR_PROXY_TYPE); | ||
126 | return NULL; | ||
127 | } | ||
128 | |||
129 | if (m_options.proxy_info.proxy_type != TCP_PROXY_NONE) { | ||
130 | if (options->proxy_port == 0) { | ||
131 | SET_ERROR_PARAMETER(error, TOX_ERR_NEW_PROXY_BAD_PORT); | ||
132 | return NULL; | ||
133 | } | ||
134 | |||
135 | ip_init(&m_options.proxy_info.ip_port.ip, m_options.ipv6enabled); | ||
136 | |||
137 | if (m_options.ipv6enabled) | ||
138 | m_options.proxy_info.ip_port.ip.family = AF_UNSPEC; | ||
139 | |||
140 | if (!addr_resolve_or_parse_ip(options->proxy_address, &m_options.proxy_info.ip_port.ip, NULL)) { | ||
141 | SET_ERROR_PARAMETER(error, TOX_ERR_NEW_PROXY_BAD_HOST); | ||
142 | //TODO: TOX_ERR_NEW_PROXY_NOT_FOUND if domain. | ||
143 | return NULL; | ||
144 | } | ||
145 | |||
146 | m_options.proxy_info.ip_port.port = htons(options->proxy_port); | ||
147 | } | ||
148 | } | ||
149 | |||
150 | Messenger *m = new_messenger(&m_options); | ||
151 | //TODO: TOX_ERR_NEW_MALLOC | ||
152 | //TODO: TOX_ERR_NEW_PORT_ALLOC | ||
153 | |||
154 | if (!new_groupchats(m)) { | ||
155 | kill_messenger(m); | ||
156 | SET_ERROR_PARAMETER(error, TOX_ERR_NEW_MALLOC); | ||
157 | return NULL; | ||
158 | } | ||
159 | |||
160 | if (messenger_load(m, data, length) == -1) { | ||
161 | /* TODO: uncomment this when tox is stable. | ||
162 | tox_kill(m); | ||
163 | SET_ERROR_PARAMETER(error, TOX_ERR_NEW_LOAD_BAD_FORMAT); | ||
164 | return NULL; | ||
165 | */ | ||
166 | } | ||
167 | |||
168 | SET_ERROR_PARAMETER(error, TOX_ERR_NEW_OK); | ||
169 | return m; | ||
157 | } | 170 | } |
158 | 171 | ||
159 | /* Set our nickname. | 172 | void tox_kill(Tox *tox) |
160 | * name must be a string of maximum MAX_NAME_LENGTH length. | ||
161 | * length must be at least 1 byte. | ||
162 | * length is the length of name with the NULL terminator. | ||
163 | * | ||
164 | * return 0 if success. | ||
165 | * return -1 if failure. | ||
166 | */ | ||
167 | int tox_set_name(Tox *tox, const uint8_t *name, uint16_t length) | ||
168 | { | 173 | { |
169 | Messenger *m = tox; | 174 | Messenger *m = tox; |
170 | return setname(m, name, length); | 175 | kill_groupchats(m->group_chat_object); |
176 | kill_messenger(m); | ||
177 | logger_kill_global(); | ||
171 | } | 178 | } |
172 | 179 | ||
173 | /* Get your nickname. | 180 | size_t tox_save_size(const Tox *tox) |
174 | * m - The messenger context to use. | ||
175 | * name - Pointer to a string for the name. (must be at least MAX_NAME_LENGTH) | ||
176 | * | ||
177 | * return length of the name. | ||
178 | * return 0 on error. | ||
179 | */ | ||
180 | uint16_t tox_get_self_name(const Tox *tox, uint8_t *name) | ||
181 | { | 181 | { |
182 | const Messenger *m = tox; | 182 | const Messenger *m = tox; |
183 | return getself_name(m, name); | 183 | return messenger_size(m); |
184 | } | 184 | } |
185 | 185 | ||
186 | /* Get name of friendnumber and put it in name. | 186 | void tox_save(const Tox *tox, uint8_t *data) |
187 | * name needs to be a valid memory location with a size of at least MAX_NAME_LENGTH (128) bytes. | ||
188 | * | ||
189 | * return length of name (with the NULL terminator) if success. | ||
190 | * return -1 if failure. | ||
191 | */ | ||
192 | int tox_get_name(const Tox *tox, int32_t friendnumber, uint8_t *name) | ||
193 | { | 187 | { |
194 | const Messenger *m = tox; | 188 | if (data) { |
195 | return getname(m, friendnumber, name); | 189 | const Messenger *m = tox; |
190 | messenger_save(m, data); | ||
191 | } | ||
196 | } | 192 | } |
197 | 193 | ||
198 | /* returns the length of name on success. | 194 | static int address_to_ip(Messenger *m, const char *address, IP_Port *ip_port, IP_Port *ip_port_v4) |
199 | * returns -1 on failure. | ||
200 | */ | ||
201 | int tox_get_name_size(const Tox *tox, int32_t friendnumber) | ||
202 | { | 195 | { |
203 | const Messenger *m = tox; | 196 | if (!addr_parse_ip(address, &ip_port->ip)) { |
204 | return m_get_name_size(m, friendnumber); | 197 | if (m->options.udp_disabled) { /* Disable DNS when udp is disabled. */ |
205 | } | 198 | return -1; |
199 | } | ||
206 | 200 | ||
207 | int tox_get_self_name_size(const Tox *tox) | 201 | IP *ip_extra = NULL; |
208 | { | 202 | ip_init(&ip_port->ip, m->options.ipv6enabled); |
209 | const Messenger *m = tox; | 203 | |
210 | return m_get_self_name_size(m); | 204 | if (m->options.ipv6enabled && ip_port_v4) { |
205 | /* setup for getting BOTH: an IPv6 AND an IPv4 address */ | ||
206 | ip_port->ip.family = AF_UNSPEC; | ||
207 | ip_reset(&ip_port_v4->ip); | ||
208 | ip_extra = &ip_port_v4->ip; | ||
209 | } | ||
210 | |||
211 | if (!addr_resolve(address, &ip_port->ip, ip_extra)) { | ||
212 | return -1; | ||
213 | } | ||
214 | } | ||
215 | |||
216 | return 0; | ||
211 | } | 217 | } |
212 | 218 | ||
213 | /* Set our user status; | 219 | bool tox_bootstrap(Tox *tox, const char *address, uint16_t port, const uint8_t *public_key, TOX_ERR_BOOTSTRAP *error) |
214 | * you are responsible for freeing status after. | ||
215 | * | ||
216 | * return 0 on success, -1 on failure. | ||
217 | */ | ||
218 | int tox_set_status_message(Tox *tox, const uint8_t *status, uint16_t length) | ||
219 | { | 220 | { |
221 | if (!address || !public_key) { | ||
222 | SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_NULL); | ||
223 | return 0; | ||
224 | } | ||
225 | |||
220 | Messenger *m = tox; | 226 | Messenger *m = tox; |
221 | return m_set_statusmessage(m, status, length); | 227 | bool ret = tox_add_tcp_relay(tox, address, port, public_key, error); |
228 | |||
229 | if (!ret) { | ||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | if (m->options.udp_disabled) { | ||
234 | return ret; | ||
235 | } else { /* DHT only works on UDP. */ | ||
236 | if (DHT_bootstrap_from_address(m->dht, address, m->options.ipv6enabled, htons(port), public_key) == 0) { | ||
237 | SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_BAD_ADDRESS); | ||
238 | return 0; | ||
239 | } | ||
240 | |||
241 | SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_OK); | ||
242 | return 1; | ||
243 | } | ||
222 | } | 244 | } |
223 | 245 | ||
224 | int tox_set_user_status(Tox *tox, uint8_t status) | 246 | bool tox_add_tcp_relay(Tox *tox, const char *address, uint16_t port, const uint8_t *public_key, |
247 | TOX_ERR_BOOTSTRAP *error) | ||
225 | { | 248 | { |
249 | if (!address || !public_key) { | ||
250 | SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_NULL); | ||
251 | return 0; | ||
252 | } | ||
253 | |||
226 | Messenger *m = tox; | 254 | Messenger *m = tox; |
227 | return m_set_userstatus(m, status); | 255 | IP_Port ip_port, ip_port_v4; |
228 | } | ||
229 | 256 | ||
230 | /* returns the length of status message on success. | 257 | if (port == 0) { |
231 | * returns -1 on failure. | 258 | SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_BAD_PORT); |
232 | */ | 259 | return 0; |
233 | int tox_get_status_message_size(const Tox *tox, int32_t friendnumber) | 260 | } |
234 | { | ||
235 | const Messenger *m = tox; | ||
236 | return m_get_statusmessage_size(m, friendnumber); | ||
237 | } | ||
238 | 261 | ||
239 | int tox_get_self_status_message_size(const Tox *tox) | 262 | if (address_to_ip(m, address, &ip_port, &ip_port_v4) == -1) { |
240 | { | 263 | SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_BAD_ADDRESS); |
241 | const Messenger *m = tox; | 264 | return 0; |
242 | return m_get_self_statusmessage_size(m); | 265 | } |
266 | |||
267 | ip_port.port = htons(port); | ||
268 | add_tcp_relay(m->net_crypto, ip_port, public_key); | ||
269 | onion_add_bs_path_node(m->onion_c, ip_port, public_key); //TODO: move this | ||
270 | |||
271 | SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_OK); | ||
272 | return 1; | ||
243 | } | 273 | } |
244 | 274 | ||
245 | /* Copy friendnumber's status message into buf, truncating if size is over maxlen. | 275 | TOX_CONNECTION tox_get_connection_status(const Tox *tox) |
246 | * Get the size you need to allocate from m_get_statusmessage_size. | ||
247 | * The self variant will copy our own status message. | ||
248 | */ | ||
249 | int tox_get_status_message(const Tox *tox, int32_t friendnumber, uint8_t *buf, uint32_t maxlen) | ||
250 | { | 276 | { |
251 | const Messenger *m = tox; | 277 | const Messenger *m = tox; |
252 | return m_copy_statusmessage(m, friendnumber, buf, maxlen); | 278 | |
279 | if (onion_isconnected(m->onion_c)) { | ||
280 | if (DHT_non_lan_connected(m->dht)) { | ||
281 | return TOX_CONNECTION_UDP; | ||
282 | } | ||
283 | |||
284 | return TOX_CONNECTION_TCP; | ||
285 | } | ||
286 | |||
287 | return TOX_CONNECTION_NONE; | ||
253 | } | 288 | } |
254 | 289 | ||
255 | int tox_get_self_status_message(const Tox *tox, uint8_t *buf, uint32_t maxlen) | 290 | |
291 | void tox_callback_connection_status(Tox *tox, tox_connection_status_cb *function, void *user_data) | ||
256 | { | 292 | { |
257 | const Messenger *m = tox; | 293 | //TODO |
258 | return m_copy_self_statusmessage(m, buf, maxlen); | ||
259 | } | 294 | } |
260 | 295 | ||
261 | /* Return one of USERSTATUS values. | 296 | uint32_t tox_iteration_interval(const Tox *tox) |
262 | * Values unknown to your application should be represented as USERSTATUS_NONE. | ||
263 | * As above, the self variant will return our own USERSTATUS. | ||
264 | * If friendnumber is invalid, this shall return USERSTATUS_INVALID. | ||
265 | */ | ||
266 | uint8_t tox_get_user_status(const Tox *tox, int32_t friendnumber) | ||
267 | { | 297 | { |
268 | const Messenger *m = tox; | 298 | const Messenger *m = tox; |
269 | return m_get_userstatus(m, friendnumber); | 299 | return messenger_run_interval(m); |
270 | } | 300 | } |
271 | 301 | ||
272 | uint8_t tox_get_self_user_status(const Tox *tox) | 302 | void tox_iteration(Tox *tox) |
273 | { | 303 | { |
274 | const Messenger *m = tox; | 304 | Messenger *m = tox; |
275 | return m_get_self_userstatus(m); | 305 | do_messenger(m); |
306 | do_groupchats(m->group_chat_object); | ||
276 | } | 307 | } |
277 | 308 | ||
278 | /* returns timestamp of last time friendnumber was seen online, or 0 if never seen. | 309 | void tox_self_get_address(const Tox *tox, uint8_t *address) |
279 | * returns -1 on error. | ||
280 | */ | ||
281 | uint64_t tox_get_last_online(const Tox *tox, int32_t friendnumber) | ||
282 | { | 310 | { |
283 | const Messenger *m = tox; | 311 | if (address) { |
284 | return m_get_last_online(m, friendnumber); | 312 | const Messenger *m = tox; |
313 | getaddress(m, address); | ||
314 | } | ||
285 | } | 315 | } |
286 | 316 | ||
287 | /* Set our typing status for a friend. | 317 | void tox_self_set_nospam(Tox *tox, uint32_t nospam) |
288 | * You are responsible for turning it on or off. | ||
289 | * | ||
290 | * returns 0 on success. | ||
291 | * returns -1 on failure. | ||
292 | */ | ||
293 | int tox_set_user_is_typing(Tox *tox, int32_t friendnumber, uint8_t is_typing) | ||
294 | { | 318 | { |
295 | Messenger *m = tox; | 319 | Messenger *m = tox; |
296 | return m_set_usertyping(m, friendnumber, is_typing); | 320 | set_nospam(&(m->fr), nospam); |
297 | } | 321 | } |
298 | 322 | ||
299 | /* Get the typing status of a friend. | 323 | uint32_t tox_self_get_nospam(const Tox *tox) |
300 | * | ||
301 | * returns 0 if friend is not typing. | ||
302 | * returns 1 if friend is typing. | ||
303 | */ | ||
304 | uint8_t tox_get_is_typing(const Tox *tox, int32_t friendnumber) | ||
305 | { | 324 | { |
306 | const Messenger *m = tox; | 325 | const Messenger *m = tox; |
307 | return m_get_istyping(m, friendnumber); | 326 | return get_nospam(&(m->fr)); |
308 | } | 327 | } |
309 | 328 | ||
310 | /* Return the number of friends in the instance m. | 329 | void tox_self_get_public_key(const Tox *tox, uint8_t *public_key) |
311 | * You should use this to determine how much memory to allocate | ||
312 | * for copy_friendlist. */ | ||
313 | uint32_t tox_count_friendlist(const Tox *tox) | ||
314 | { | 330 | { |
315 | const Messenger *m = tox; | 331 | const Messenger *m = tox; |
316 | return count_friendlist(m); | ||
317 | } | ||
318 | 332 | ||
319 | /* Return the number of online friends in the instance m. */ | 333 | if (public_key) |
320 | uint32_t tox_get_num_online_friends(const Tox *tox) | 334 | memcpy(public_key, m->net_crypto->self_public_key, crypto_box_PUBLICKEYBYTES); |
321 | { | ||
322 | const Messenger *m = tox; | ||
323 | return get_num_online_friends(m); | ||
324 | } | 335 | } |
325 | 336 | ||
326 | /* Copy a list of valid friend IDs into the array out_list. | 337 | void tox_self_get_private_key(const Tox *tox, uint8_t *private_key) |
327 | * If out_list is NULL, returns 0. | ||
328 | * Otherwise, returns the number of elements copied. | ||
329 | * If the array was too small, the contents | ||
330 | * of out_list will be truncated to list_size. */ | ||
331 | uint32_t tox_get_friendlist(const Tox *tox, int32_t *out_list, uint32_t list_size) | ||
332 | { | 338 | { |
333 | const Messenger *m = tox; | 339 | const Messenger *m = tox; |
334 | return copy_friendlist(m, out_list, list_size); | ||
335 | } | ||
336 | 340 | ||
337 | /* Set the function that will be executed when a friend request is received. | 341 | if (private_key) |
338 | * Function format is function(uint8_t * public_key, uint8_t * data, uint16_t length) | 342 | memcpy(private_key, m->net_crypto->self_secret_key, crypto_box_SECRETKEYBYTES); |
339 | */ | ||
340 | void tox_callback_friend_request(Tox *tox, void (*function)(Tox *tox, const uint8_t *, const uint8_t *, uint16_t, | ||
341 | void *), void *userdata) | ||
342 | { | ||
343 | Messenger *m = tox; | ||
344 | m_callback_friendrequest(m, function, userdata); | ||
345 | } | 343 | } |
346 | 344 | ||
347 | 345 | bool tox_self_set_name(Tox *tox, const uint8_t *name, size_t length, TOX_ERR_SET_INFO *error) | |
348 | /* Set the function that will be executed when a message from a friend is received. | ||
349 | * Function format is: function(int32_t friendnumber, uint8_t * message, uint32_t length) | ||
350 | */ | ||
351 | void tox_callback_friend_message(Tox *tox, void (*function)(Messenger *tox, int32_t, const uint8_t *, uint16_t, void *), | ||
352 | void *userdata) | ||
353 | { | 346 | { |
354 | Messenger *m = tox; | 347 | if (!name && length != 0) { |
355 | m_callback_friendmessage(m, function, userdata); | 348 | SET_ERROR_PARAMETER(error, TOX_ERR_SET_INFO_NULL); |
356 | } | 349 | return 0; |
350 | } | ||
357 | 351 | ||
358 | /* Set the function that will be executed when an action from a friend is received. | ||
359 | * function format is: function(int32_t friendnumber, uint8_t * action, uint32_t length) | ||
360 | */ | ||
361 | void tox_callback_friend_action(Tox *tox, void (*function)(Messenger *tox, int32_t, const uint8_t *, uint16_t, void *), | ||
362 | void *userdata) | ||
363 | { | ||
364 | Messenger *m = tox; | 352 | Messenger *m = tox; |
365 | m_callback_action(m, function, userdata); | 353 | |
354 | if (setname(m, name, length) == 0) { | ||
355 | //TODO: function to set different per group names? | ||
356 | send_name_all_groups(m->group_chat_object); | ||
357 | SET_ERROR_PARAMETER(error, TOX_ERR_SET_INFO_OK); | ||
358 | return 1; | ||
359 | } else { | ||
360 | SET_ERROR_PARAMETER(error, TOX_ERR_SET_INFO_TOO_LONG); | ||
361 | return 0; | ||
362 | } | ||
366 | } | 363 | } |
367 | 364 | ||
368 | /* Set the callback for name changes. | 365 | size_t tox_self_get_name_size(const Tox *tox) |
369 | * function(int32_t friendnumber, uint8_t *newname, uint16_t length) | ||
370 | * You are not responsible for freeing newname. | ||
371 | */ | ||
372 | void tox_callback_name_change(Tox *tox, void (*function)(Messenger *tox, int32_t, const uint8_t *, uint16_t, void *), | ||
373 | void *userdata) | ||
374 | { | 366 | { |
375 | Messenger *m = tox; | 367 | const Messenger *m = tox; |
376 | m_callback_namechange(m, function, userdata); | 368 | return m_get_self_name_size(m); |
377 | } | 369 | } |
378 | 370 | ||
379 | /* Set the callback for status message changes. | 371 | void tox_self_get_name(const Tox *tox, uint8_t *name) |
380 | * function(int32_t friendnumber, uint8_t *newstatus, uint16_t length) | ||
381 | * You are not responsible for freeing newstatus. | ||
382 | */ | ||
383 | void tox_callback_status_message(Tox *tox, void (*function)(Messenger *tox, int32_t, const uint8_t *, uint16_t, void *), | ||
384 | void *userdata) | ||
385 | { | 372 | { |
386 | Messenger *m = tox; | 373 | if (name) { |
387 | m_callback_statusmessage(m, function, userdata); | 374 | const Messenger *m = tox; |
375 | getself_name(m, name); | ||
376 | } | ||
388 | } | 377 | } |
389 | 378 | ||
390 | /* Set the callback for status type changes. | 379 | bool tox_self_set_status_message(Tox *tox, const uint8_t *status, size_t length, TOX_ERR_SET_INFO *error) |
391 | * function(int32_t friendnumber, USERSTATUS kind) | ||
392 | */ | ||
393 | void tox_callback_user_status(Tox *tox, void (*function)(Messenger *tox, int32_t, uint8_t, void *), | ||
394 | void *userdata) | ||
395 | { | 380 | { |
381 | if (!status && length != 0) { | ||
382 | SET_ERROR_PARAMETER(error, TOX_ERR_SET_INFO_NULL); | ||
383 | return 0; | ||
384 | } | ||
385 | |||
396 | Messenger *m = tox; | 386 | Messenger *m = tox; |
397 | m_callback_userstatus(m, function, userdata); | 387 | |
388 | if (m_set_statusmessage(m, status, length) == 0) { | ||
389 | SET_ERROR_PARAMETER(error, TOX_ERR_SET_INFO_OK); | ||
390 | return 1; | ||
391 | } else { | ||
392 | SET_ERROR_PARAMETER(error, TOX_ERR_SET_INFO_TOO_LONG); | ||
393 | return 0; | ||
394 | } | ||
398 | } | 395 | } |
399 | 396 | ||
400 | /* Set the callback for typing changes. | 397 | size_t tox_self_get_status_message_size(const Tox *tox) |
401 | * function (int32_t friendnumber, uint8_t is_typing) | ||
402 | */ | ||
403 | void tox_callback_typing_change(Tox *tox, void (*function)(Messenger *tox, int32_t, uint8_t, void *), void *userdata) | ||
404 | { | 398 | { |
405 | Messenger *m = tox; | 399 | const Messenger *m = tox; |
406 | m_callback_typingchange(m, function, userdata); | 400 | return m_get_self_statusmessage_size(m); |
407 | } | 401 | } |
408 | 402 | ||
409 | /* Set the callback for read receipts. | 403 | void tox_self_get_status_message(const Tox *tox, uint8_t *status) |
410 | * function(int32_t friendnumber, uint32_t receipt) | ||
411 | * | ||
412 | * If you are keeping a record of returns from m_sendmessage; | ||
413 | * receipt might be one of those values, meaning the message | ||
414 | * has been received on the other side. | ||
415 | * Since core doesn't track ids for you, receipt may not correspond to any message. | ||
416 | * in that case, you should discard it. | ||
417 | */ | ||
418 | void tox_callback_read_receipt(Tox *tox, void (*function)(Messenger *tox, int32_t, uint32_t, void *), void *userdata) | ||
419 | { | 404 | { |
420 | Messenger *m = tox; | 405 | if (status) { |
421 | m_callback_read_receipt(m, function, userdata); | 406 | const Messenger *m = tox; |
407 | m_copy_self_statusmessage(m, status); | ||
408 | } | ||
422 | } | 409 | } |
423 | 410 | ||
424 | /* Set the callback for connection status changes. | 411 | void tox_self_set_status(Tox *tox, TOX_STATUS user_status) |
425 | * function(int32_t friendnumber, uint8_t status) | ||
426 | * | ||
427 | * Status: | ||
428 | * 0 -- friend went offline after being previously online | ||
429 | * 1 -- friend went online | ||
430 | * | ||
431 | * NOTE: this callback is not called when adding friends, thus the "after | ||
432 | * being previously online" part. It's assumed that when adding friends, | ||
433 | * their connection status is offline. | ||
434 | */ | ||
435 | void tox_callback_connection_status(Tox *tox, void (*function)(Messenger *tox, int32_t, uint8_t, void *), | ||
436 | void *userdata) | ||
437 | { | 412 | { |
438 | Messenger *m = tox; | 413 | Messenger *m = tox; |
439 | m_callback_connectionstatus(m, function, userdata); | 414 | m_set_userstatus(m, user_status); |
440 | } | 415 | } |
441 | 416 | ||
442 | /**********ADVANCED FUNCTIONS (If you don't know what they do you can safely ignore them.) ************/ | 417 | TOX_STATUS tox_self_get_status(const Tox *tox) |
443 | |||
444 | /* Functions to get/set the nospam part of the id. | ||
445 | */ | ||
446 | uint32_t tox_get_nospam(const Tox *tox) | ||
447 | { | 418 | { |
448 | const Messenger *m = tox; | 419 | const Messenger *m = tox; |
449 | return get_nospam(&(m->fr)); | 420 | return m_get_self_userstatus(m); |
450 | } | 421 | } |
451 | 422 | ||
452 | void tox_set_nospam(Tox *tox, uint32_t nospam) | 423 | static void set_friend_error(int32_t ret, TOX_ERR_FRIEND_ADD *error) |
453 | { | 424 | { |
454 | Messenger *m = tox; | 425 | switch (ret) { |
455 | set_nospam(&(m->fr), nospam); | 426 | case FAERR_TOOLONG: |
456 | } | 427 | SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_TOO_LONG); |
428 | break; | ||
457 | 429 | ||
458 | /* Copy the public and secret key from the Tox object. | 430 | case FAERR_NOMESSAGE: |
459 | public_key and secret_key must be 32 bytes big. | 431 | SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_NO_MESSAGE); |
460 | if the pointer is NULL, no data will be copied to it.*/ | 432 | break; |
461 | void tox_get_keys(Tox *tox, uint8_t *public_key, uint8_t *secret_key) | ||
462 | { | ||
463 | Messenger *m = tox; | ||
464 | 433 | ||
465 | if (public_key) | 434 | case FAERR_OWNKEY: |
466 | memcpy(public_key, m->net_crypto->self_public_key, crypto_box_PUBLICKEYBYTES); | 435 | SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_OWN_KEY); |
436 | break; | ||
467 | 437 | ||
468 | if (secret_key) | 438 | case FAERR_ALREADYSENT: |
469 | memcpy(secret_key, m->net_crypto->self_secret_key, crypto_box_SECRETKEYBYTES); | 439 | SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_ALREADY_SENT); |
470 | } | 440 | break; |
471 | 441 | ||
472 | /**********GROUP CHAT FUNCTIONS: WARNING Group chats will be rewritten so this might change ************/ | 442 | case FAERR_BADCHECKSUM: |
443 | SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_BAD_CHECKSUM); | ||
444 | break; | ||
473 | 445 | ||
474 | /* Set the callback for group invites. | 446 | case FAERR_SETNEWNOSPAM: |
475 | * | 447 | SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_SET_NEW_NOSPAM); |
476 | * Function(Tox *tox, int32_t friendnumber, uint8_t *group_public_key, void *userdata) | 448 | break; |
477 | */ | ||
478 | void tox_callback_group_invite(Tox *tox, void (*function)(Messenger *tox, int32_t, const uint8_t *, void *), | ||
479 | void *userdata) | ||
480 | { | ||
481 | Messenger *m = tox; | ||
482 | m_callback_group_invite(m, function, userdata); | ||
483 | } | ||
484 | 449 | ||
485 | /* Set the callback for group messages. | 450 | case FAERR_NOMEM: |
486 | * | 451 | SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_MALLOC); |
487 | * Function(Tox *tox, int groupnumber, int friendgroupnumber, uint8_t * message, uint16_t length, void *userdata) | 452 | break; |
488 | */ | ||
489 | void tox_callback_group_message(Tox *tox, void (*function)(Messenger *tox, int, int, const uint8_t *, uint16_t, void *), | ||
490 | void *userdata) | ||
491 | { | ||
492 | Messenger *m = tox; | ||
493 | m_callback_group_message(m, function, userdata); | ||
494 | } | ||
495 | 453 | ||
496 | /* Set the callback for group actions. | 454 | } |
497 | * | ||
498 | * Function(Tox *tox, int groupnumber, int friendgroupnumber, uint8_t * action, uint16_t length, void *userdata) | ||
499 | */ | ||
500 | void tox_callback_group_action(Tox *tox, void (*function)(Messenger *tox, int, int, const uint8_t *, uint16_t, void *), | ||
501 | void *userdata) | ||
502 | { | ||
503 | Messenger *m = tox; | ||
504 | m_callback_group_action(m, function, userdata); | ||
505 | } | 455 | } |
506 | 456 | ||
507 | /* Set callback function for peer name list changes. | 457 | uint32_t tox_friend_add(Tox *tox, const uint8_t *address, const uint8_t *message, size_t length, |
508 | * | 458 | TOX_ERR_FRIEND_ADD *error) |
509 | * It gets called every time the name list changes(new peer/name, deleted peer) | ||
510 | * Function(Tox *tox, int groupnumber, void *userdata) | ||
511 | */ | ||
512 | void tox_callback_group_namelist_change(Tox *tox, void (*function)(Tox *tox, int, int, uint8_t, void *), void *userdata) | ||
513 | { | 459 | { |
460 | if (!address || !message) { | ||
461 | SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_NULL); | ||
462 | return UINT32_MAX; | ||
463 | } | ||
464 | |||
514 | Messenger *m = tox; | 465 | Messenger *m = tox; |
515 | m_callback_group_namelistchange(m, function, userdata); | 466 | int32_t ret = m_addfriend(m, address, message, length); |
467 | |||
468 | if (ret >= 0) { | ||
469 | SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_OK); | ||
470 | return ret; | ||
471 | } | ||
472 | |||
473 | set_friend_error(ret, error); | ||
474 | return UINT32_MAX; | ||
516 | } | 475 | } |
517 | 476 | ||
518 | /* Creates a new groupchat and puts it in the chats array. | 477 | uint32_t tox_friend_add_norequest(Tox *tox, const uint8_t *public_key, TOX_ERR_FRIEND_ADD *error) |
519 | * | ||
520 | * return group number on success. | ||
521 | * return -1 on failure. | ||
522 | */ | ||
523 | int tox_add_groupchat(Tox *tox) | ||
524 | { | 478 | { |
479 | if (!public_key) { | ||
480 | SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_NULL); | ||
481 | return UINT32_MAX; | ||
482 | } | ||
483 | |||
525 | Messenger *m = tox; | 484 | Messenger *m = tox; |
526 | return add_groupchat(m); | 485 | int32_t ret = m_addfriend_norequest(m, public_key); |
486 | |||
487 | if (ret >= 0) { | ||
488 | SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_OK); | ||
489 | return ret; | ||
490 | } | ||
491 | |||
492 | set_friend_error(ret, error); | ||
493 | return UINT32_MAX; | ||
527 | } | 494 | } |
528 | /* Delete a groupchat from the chats array. | 495 | |
529 | * | 496 | bool tox_friend_delete(Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_DELETE *error) |
530 | * return 0 on success. | ||
531 | * return -1 if failure. | ||
532 | */ | ||
533 | int tox_del_groupchat(Tox *tox, int groupnumber) | ||
534 | { | 497 | { |
535 | Messenger *m = tox; | 498 | Messenger *m = tox; |
536 | return del_groupchat(m, groupnumber); | 499 | int ret = m_delfriend(m, friend_number); |
500 | |||
501 | //TODO handle if realloc fails? | ||
502 | if (ret == -1) { | ||
503 | SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_DELETE_FRIEND_NOT_FOUND); | ||
504 | return 0; | ||
505 | } | ||
506 | |||
507 | SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_DELETE_OK); | ||
508 | return 1; | ||
537 | } | 509 | } |
538 | 510 | ||
539 | /* Copy the name of peernumber who is in groupnumber to name. | 511 | uint32_t tox_friend_by_public_key(const Tox *tox, const uint8_t *public_key, TOX_ERR_FRIEND_BY_PUBLIC_KEY *error) |
540 | * name must be at least MAX_NICK_BYTES long. | ||
541 | * | ||
542 | * return length of name if success | ||
543 | * return -1 if failure | ||
544 | */ | ||
545 | int tox_group_peername(const Tox *tox, int groupnumber, int peernumber, uint8_t *name) | ||
546 | { | 512 | { |
513 | if (!public_key) { | ||
514 | SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_BY_PUBLIC_KEY_NULL); | ||
515 | return UINT32_MAX; | ||
516 | } | ||
517 | |||
547 | const Messenger *m = tox; | 518 | const Messenger *m = tox; |
548 | return m_group_peername(m, groupnumber, peernumber, name); | 519 | int32_t ret = getfriend_id(m, public_key); |
549 | } | ||
550 | /* invite friendnumber to groupnumber | ||
551 | * return 0 on success | ||
552 | * return -1 on failure | ||
553 | */ | ||
554 | int tox_invite_friend(Tox *tox, int32_t friendnumber, int groupnumber) | ||
555 | { | ||
556 | Messenger *m = tox; | ||
557 | return invite_friend(m, friendnumber, groupnumber); | ||
558 | } | ||
559 | /* Join a group (you need to have been invited first.) | ||
560 | * | ||
561 | * returns group number on success | ||
562 | * returns -1 on failure. | ||
563 | */ | ||
564 | int tox_join_groupchat(Tox *tox, int32_t friendnumber, const uint8_t *friend_group_public_key) | ||
565 | { | ||
566 | Messenger *m = tox; | ||
567 | return join_groupchat(m, friendnumber, friend_group_public_key); | ||
568 | } | ||
569 | 520 | ||
570 | /* send a group message | 521 | if (ret == -1) { |
571 | * return 0 on success | 522 | SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_BY_PUBLIC_KEY_NOT_FOUND); |
572 | * return -1 on failure | 523 | return UINT32_MAX; |
573 | */ | 524 | } |
574 | int tox_group_message_send(Tox *tox, int groupnumber, const uint8_t *message, uint32_t length) | 525 | |
575 | { | 526 | SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_BY_PUBLIC_KEY_OK); |
576 | Messenger *m = tox; | 527 | return ret; |
577 | return group_message_send(m, groupnumber, message, length); | ||
578 | } | 528 | } |
579 | 529 | ||
580 | /* send a group action | 530 | bool tox_friend_get_public_key(const Tox *tox, uint32_t friend_number, uint8_t *public_key, |
581 | * return 0 on success | 531 | TOX_ERR_FRIEND_GET_PUBLIC_KEY *error) |
582 | * return -1 on failure | ||
583 | */ | ||
584 | int tox_group_action_send(Tox *tox, int groupnumber, const uint8_t *action, uint32_t length) | ||
585 | { | 532 | { |
586 | Messenger *m = tox; | 533 | if (!public_key) { |
587 | return group_action_send(m, groupnumber, action, length); | 534 | SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_GET_PUBLIC_KEY_NULL); |
535 | return 0; | ||
536 | } | ||
537 | |||
538 | const Messenger *m = tox; | ||
539 | |||
540 | if (get_real_pk(m, friend_number, public_key) == -1) { | ||
541 | SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_GET_PUBLIC_KEY_FRIEND_NOT_FOUND); | ||
542 | return 0; | ||
543 | } | ||
544 | |||
545 | SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_GET_PUBLIC_KEY_OK); | ||
546 | return 1; | ||
588 | } | 547 | } |
589 | 548 | ||
590 | /* Return the number of peers in the group chat on success. | 549 | bool tox_friend_exists(const Tox *tox, uint32_t friend_number) |
591 | * return -1 on failure | ||
592 | */ | ||
593 | int tox_group_number_peers(const Tox *tox, int groupnumber) | ||
594 | { | 550 | { |
595 | const Messenger *m = tox; | 551 | const Messenger *m = tox; |
596 | return group_number_peers(m, groupnumber); | 552 | return m_friend_exists(m, friend_number); |
597 | } | 553 | } |
598 | 554 | ||
599 | /* List all the peers in the group chat. | 555 | size_t tox_friend_list_size(const Tox *tox) |
600 | * | ||
601 | * Copies the names of the peers to the name[length][MAX_NICK_BYTES] array. | ||
602 | * | ||
603 | * Copies the lengths of the names to lengths[length] | ||
604 | * | ||
605 | * returns the number of peers on success. | ||
606 | * | ||
607 | * return -1 on failure. | ||
608 | */ | ||
609 | int tox_group_get_names(const Tox *tox, int groupnumber, uint8_t names[][TOX_MAX_NAME_LENGTH], uint16_t lengths[], | ||
610 | uint16_t length) | ||
611 | { | 556 | { |
612 | const Messenger *m = tox; | 557 | const Messenger *m = tox; |
613 | return group_names(m, groupnumber, names, lengths, length); | 558 | return count_friendlist(m); |
614 | } | 559 | } |
615 | 560 | ||
616 | /* Return the number of chats in the instance m. | 561 | void tox_friend_list(const Tox *tox, uint32_t *list) |
617 | * You should use this to determine how much memory to allocate | ||
618 | * for copy_chatlist. */ | ||
619 | uint32_t tox_count_chatlist(const Tox *tox) | ||
620 | { | 562 | { |
621 | const Messenger *m = tox; | 563 | if (list) { |
622 | return count_chatlist(m); | 564 | const Messenger *m = tox; |
565 | //TODO: size parameter? | ||
566 | copy_friendlist(m, list, tox_friend_list_size(tox)); | ||
567 | } | ||
623 | } | 568 | } |
624 | 569 | ||
625 | /* Copy a list of valid chat IDs into the array out_list. | 570 | size_t tox_friend_get_name_size(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_QUERY *error) |
626 | * If out_list is NULL, returns 0. | ||
627 | * Otherwise, returns the number of elements copied. | ||
628 | * If the array was too small, the contents | ||
629 | * of out_list will be truncated to list_size. */ | ||
630 | uint32_t tox_get_chatlist(const Tox *tox, int *out_list, uint32_t list_size) | ||
631 | { | 571 | { |
632 | const Messenger *m = tox; | 572 | const Messenger *m = tox; |
633 | return copy_chatlist(m, out_list, list_size); | 573 | int ret = m_get_name_size(m, friend_number); |
574 | |||
575 | if (ret == -1) { | ||
576 | SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND); | ||
577 | return SIZE_MAX; | ||
578 | } | ||
579 | |||
580 | SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_OK); | ||
581 | return ret; | ||
634 | } | 582 | } |
635 | 583 | ||
584 | bool tox_friend_get_name(const Tox *tox, uint32_t friend_number, uint8_t *name, TOX_ERR_FRIEND_QUERY *error) | ||
585 | { | ||
586 | if (!name) { | ||
587 | SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_NULL); | ||
588 | return 0; | ||
589 | } | ||
636 | 590 | ||
637 | /****************FILE SENDING FUNCTIONS*****************/ | 591 | const Messenger *m = tox; |
592 | int ret = getname(m, friend_number, name); | ||
638 | 593 | ||
594 | if (ret == -1) { | ||
595 | SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND); | ||
596 | return 0; | ||
597 | } | ||
639 | 598 | ||
640 | /* Set the callback for file send requests. | 599 | SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_OK); |
641 | * | 600 | return 1; |
642 | * Function(Tox *tox, int32_t friendnumber, uint8_t filenumber, uint64_t filesize, uint8_t *filename, uint16_t filename_length, void *userdata) | ||
643 | */ | ||
644 | void tox_callback_file_send_request(Tox *tox, void (*function)(Messenger *tox, int32_t, uint8_t, uint64_t, | ||
645 | const uint8_t *, uint16_t, void *), void *userdata) | ||
646 | { | ||
647 | Messenger *m = tox; | ||
648 | callback_file_sendrequest(m, function, userdata); | ||
649 | } | 601 | } |
650 | /* Set the callback for file control requests. | ||
651 | * | ||
652 | * Function(Tox *tox, int32_t friendnumber, uint8_t send_receive, uint8_t filenumber, uint8_t control_type, uint8_t *data, uint16_t length, void *userdata) | ||
653 | * | ||
654 | */ | ||
655 | void tox_callback_file_control(Tox *tox, void (*function)(Messenger *tox, int32_t, uint8_t, uint8_t, uint8_t, | ||
656 | const uint8_t *, uint16_t, void *), void *userdata) | ||
657 | { | ||
658 | Messenger *m = tox; | ||
659 | callback_file_control(m, function, userdata); | ||
660 | } | ||
661 | /* Set the callback for file data. | ||
662 | * | ||
663 | * Function(Tox *tox, int32_t friendnumber, uint8_t filenumber, uint8_t *data, uint16_t length, void *userdata) | ||
664 | * | ||
665 | */ | ||
666 | void tox_callback_file_data(Tox *tox, void (*function)(Messenger *tox, int32_t, uint8_t, const uint8_t *, | ||
667 | uint16_t length, void *), void *userdata) | ||
668 | 602 | ||
603 | void tox_callback_friend_name(Tox *tox, tox_friend_name_cb *function, void *user_data) | ||
669 | { | 604 | { |
670 | Messenger *m = tox; | 605 | Messenger *m = tox; |
671 | callback_file_data(m, function, userdata); | 606 | m_callback_friendmessage(m, function, user_data); |
672 | } | ||
673 | /* Send a file send request. | ||
674 | * Maximum filename length is 255 bytes. | ||
675 | * return file number on success | ||
676 | * return -1 on failure | ||
677 | */ | ||
678 | int tox_new_file_sender(Tox *tox, int32_t friendnumber, uint64_t filesize, const uint8_t *filename, | ||
679 | uint16_t filename_length) | ||
680 | { | ||
681 | Messenger *m = tox; | ||
682 | return new_filesender(m, friendnumber, filesize, filename, filename_length); | ||
683 | } | ||
684 | /* Send a file control request. | ||
685 | * send_receive is 0 if we want the control packet to target a sending file, 1 if it targets a receiving file. | ||
686 | * | ||
687 | * return 0 on success | ||
688 | * return -1 on failure | ||
689 | */ | ||
690 | int tox_file_send_control(Tox *tox, int32_t friendnumber, uint8_t send_receive, uint8_t filenumber, uint8_t message_id, | ||
691 | const uint8_t *data, uint16_t length) | ||
692 | { | ||
693 | Messenger *m = tox; | ||
694 | return file_control(m, friendnumber, send_receive, filenumber, message_id, data, length); | ||
695 | } | ||
696 | /* Send file data. | ||
697 | * | ||
698 | * return 0 on success | ||
699 | * return -1 on failure | ||
700 | */ | ||
701 | int tox_file_send_data(Tox *tox, int32_t friendnumber, uint8_t filenumber, const uint8_t *data, uint16_t length) | ||
702 | { | ||
703 | Messenger *m = tox; | ||
704 | return file_data(m, friendnumber, filenumber, data, length); | ||
705 | } | 607 | } |
706 | 608 | ||
707 | /* Returns the recommended/maximum size of the filedata you send with tox_file_send_data() | 609 | size_t tox_friend_get_status_message_size(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_QUERY *error) |
708 | * | ||
709 | * return size on success | ||
710 | * return -1 on failure (currently will never return -1) | ||
711 | */ | ||
712 | int tox_file_data_size(const Tox *tox, int32_t friendnumber) | ||
713 | { | 610 | { |
714 | return MAX_CRYPTO_DATA_SIZE - 2; | 611 | const Messenger *m = tox; |
612 | int ret = m_get_statusmessage_size(m, friend_number); | ||
613 | |||
614 | if (ret == -1) { | ||
615 | SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND); | ||
616 | return SIZE_MAX; | ||
617 | } | ||
618 | |||
619 | SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_OK); | ||
620 | return ret; | ||
715 | } | 621 | } |
716 | 622 | ||
717 | /* Give the number of bytes left to be sent/received. | 623 | bool tox_friend_get_status_message(const Tox *tox, uint32_t friend_number, uint8_t *message, |
718 | * | 624 | TOX_ERR_FRIEND_QUERY *error) |
719 | * send_receive is 0 if we want the sending files, 1 if we want the receiving. | ||
720 | * | ||
721 | * return number of bytes remaining to be sent/received on success | ||
722 | * return 0 on failure | ||
723 | */ | ||
724 | uint64_t tox_file_data_remaining(const Tox *tox, int32_t friendnumber, uint8_t filenumber, uint8_t send_receive) | ||
725 | { | 625 | { |
726 | const Messenger *m = tox; | 626 | if (!message) { |
727 | return file_dataremaining(m, friendnumber, filenumber, send_receive); | 627 | SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_NULL); |
728 | } | 628 | return 0; |
629 | } | ||
729 | 630 | ||
730 | /***************END OF FILE SENDING FUNCTIONS******************/ | 631 | const Messenger *m = tox; |
632 | //TODO: size parameter? | ||
633 | int ret = m_copy_statusmessage(m, friend_number, message, m_get_statusmessage_size(m, friend_number)); | ||
731 | 634 | ||
732 | /* TODO: expose this properly. */ | 635 | if (ret == -1) { |
733 | static int tox_add_tcp_relay(Tox *tox, const char *address, uint8_t ipv6enabled, uint16_t port, | 636 | SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND); |
734 | const uint8_t *public_key) | ||
735 | { | ||
736 | Messenger *m = tox; | ||
737 | IP_Port ip_port_v64; | ||
738 | IP *ip_extra = NULL; | ||
739 | IP_Port ip_port_v4; | ||
740 | ip_init(&ip_port_v64.ip, ipv6enabled); | ||
741 | |||
742 | if (ipv6enabled) { | ||
743 | /* setup for getting BOTH: an IPv6 AND an IPv4 address */ | ||
744 | ip_port_v64.ip.family = AF_UNSPEC; | ||
745 | ip_reset(&ip_port_v4.ip); | ||
746 | ip_extra = &ip_port_v4.ip; | ||
747 | } | ||
748 | |||
749 | if (addr_resolve_or_parse_ip(address, &ip_port_v64.ip, ip_extra)) { | ||
750 | ip_port_v64.port = port; | ||
751 | add_tcp_relay(m->net_crypto, ip_port_v64, public_key); | ||
752 | onion_add_path_node(m->onion_c, ip_port_v64, public_key); //TODO: move this | ||
753 | return 1; | ||
754 | } else { | ||
755 | return 0; | 637 | return 0; |
756 | } | 638 | } |
639 | |||
640 | SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_OK); | ||
641 | return 1; | ||
757 | } | 642 | } |
758 | 643 | ||
759 | int tox_bootstrap_from_address(Tox *tox, const char *address, uint16_t port, const uint8_t *public_key) | 644 | void tox_callback_friend_status_message(Tox *tox, tox_friend_status_message_cb *function, void *user_data) |
760 | { | 645 | { |
761 | Messenger *m = tox; | 646 | Messenger *m = tox; |
762 | tox_add_tcp_relay(tox, address, m->options.ipv6enabled, htons(port), public_key); | 647 | m_callback_statusmessage(m, function, user_data); |
763 | return DHT_bootstrap_from_address(m->dht, address, m->options.ipv6enabled, htons(port), public_key); | ||
764 | } | 648 | } |
765 | 649 | ||
766 | /* return 0 if we are not connected to the DHT. | 650 | TOX_STATUS tox_friend_get_status(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_QUERY *error) |
767 | * return 1 if we are. | ||
768 | */ | ||
769 | int tox_isconnected(const Tox *tox) | ||
770 | { | 651 | { |
771 | const Messenger *m = tox; | 652 | const Messenger *m = tox; |
772 | return onion_isconnected(m->onion_c); | 653 | |
654 | int ret = m_get_userstatus(m, friend_number); | ||
655 | |||
656 | if (ret == USERSTATUS_INVALID) { | ||
657 | SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND); | ||
658 | return TOX_STATUS_INVALID; | ||
659 | } | ||
660 | |||
661 | SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_OK); | ||
662 | return ret; | ||
773 | } | 663 | } |
774 | 664 | ||
775 | /* Return the time in milliseconds before tox_do() should be called again | 665 | void tox_callback_friend_status(Tox *tox, tox_friend_status_cb *function, void *user_data) |
776 | * for optimal performance. | ||
777 | * | ||
778 | * returns time (in ms) before the next tox_do() needs to be run on success. | ||
779 | */ | ||
780 | uint32_t tox_do_interval(Tox *tox) | ||
781 | { | 666 | { |
782 | Messenger *m = tox; | 667 | Messenger *m = tox; |
783 | return messenger_run_interval(m); | 668 | m_callback_userstatus(m, function, user_data); |
784 | } | 669 | } |
785 | 670 | ||
786 | /* Run this at startup. | 671 | TOX_CONNECTION tox_friend_get_connection_status(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_QUERY *error) |
787 | * | ||
788 | * return allocated instance of tox on success. | ||
789 | * return 0 if there are problems. | ||
790 | */ | ||
791 | Tox *tox_new(Tox_Options *options) | ||
792 | { | 672 | { |
793 | LOGGER_INIT(LOGGER_OUTPUT_FILE, LOGGER_LEVEL); | 673 | const Messenger *m = tox; |
794 | Messenger_Options m_options = {0}; | ||
795 | |||
796 | if (options == NULL) { | ||
797 | m_options.ipv6enabled = TOX_ENABLE_IPV6_DEFAULT; | ||
798 | } else { | ||
799 | m_options.ipv6enabled = options->ipv6enabled; | ||
800 | m_options.udp_disabled = options->udp_disabled; | ||
801 | m_options.proxy_enabled = options->proxy_enabled; | ||
802 | |||
803 | if (m_options.proxy_enabled) { | ||
804 | ip_init(&m_options.proxy_info.ip_port.ip, m_options.ipv6enabled); | ||
805 | |||
806 | if (m_options.ipv6enabled) | ||
807 | m_options.proxy_info.ip_port.ip.family = AF_UNSPEC; | ||
808 | 674 | ||
809 | if (!addr_resolve_or_parse_ip(options->proxy_address, &m_options.proxy_info.ip_port.ip, NULL)) | 675 | int ret = m_get_friend_connectionstatus(m, friend_number); |
810 | return NULL; | ||
811 | 676 | ||
812 | m_options.proxy_info.ip_port.port = htons(options->proxy_port); | 677 | if (ret == -1) { |
813 | } | 678 | SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND); |
679 | return TOX_CONNECTION_NONE; | ||
814 | } | 680 | } |
815 | 681 | ||
816 | return new_messenger(&m_options); | 682 | SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_OK); |
683 | return ret; | ||
817 | } | 684 | } |
818 | 685 | ||
819 | /* Run this before closing shop. | 686 | void tox_callback_friend_connection_status(Tox *tox, tox_friend_connection_status_cb *function, void *user_data) |
820 | * Free all datastructures. | ||
821 | */ | ||
822 | void tox_kill(Tox *tox) | ||
823 | { | 687 | { |
824 | Messenger *m = tox; | 688 | Messenger *m = tox; |
825 | kill_messenger(m); | 689 | m_callback_connectionstatus(m, function, user_data); |
826 | } | 690 | } |
827 | 691 | ||
828 | /* The main loop that needs to be run at least 20 times per second. */ | 692 | bool tox_friend_get_typing(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_QUERY *error) |
829 | void tox_do(Tox *tox) | ||
830 | { | ||
831 | Messenger *m = tox; | ||
832 | do_messenger(m); | ||
833 | } | ||
834 | |||
835 | /* SAVING AND LOADING FUNCTIONS: */ | ||
836 | |||
837 | /* return size of the messenger data (for saving). */ | ||
838 | uint32_t tox_size(const Tox *tox) | ||
839 | { | 693 | { |
840 | const Messenger *m = tox; | 694 | const Messenger *m = tox; |
841 | return messenger_size(m); | 695 | int ret = m_get_istyping(m, friend_number); |
842 | } | ||
843 | 696 | ||
844 | /* Save the messenger in data (must be allocated memory of size Messenger_size()). */ | 697 | if (ret == -1) { |
845 | void tox_save(const Tox *tox, uint8_t *data) | 698 | SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND); |
846 | { | 699 | return 0; |
847 | const Messenger *m = tox; | 700 | } |
848 | messenger_save(m, data); | 701 | |
702 | SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_OK); | ||
703 | return !!ret; | ||
849 | } | 704 | } |
850 | 705 | ||
851 | /* Load the messenger from data of size length. */ | 706 | void tox_callback_friend_typing(Tox *tox, tox_friend_typing_cb *function, void *user_data) |
852 | int tox_load(Tox *tox, const uint8_t *data, uint32_t length) | ||
853 | { | 707 | { |
854 | Messenger *m = tox; | 708 | Messenger *m = tox; |
855 | return messenger_load(m, data, length); | 709 | m_callback_typingchange(m, function, user_data); |
856 | } | 710 | } |
diff --git a/toxcore/tox.h b/toxcore/tox.h index 08c2b3a2..2acc70ea 100644 --- a/toxcore/tox.h +++ b/toxcore/tox.h | |||
@@ -24,650 +24,1893 @@ | |||
24 | #ifndef TOX_H | 24 | #ifndef TOX_H |
25 | #define TOX_H | 25 | #define TOX_H |
26 | 26 | ||
27 | #include <stdbool.h> | ||
28 | #include <stddef.h> | ||
27 | #include <stdint.h> | 29 | #include <stdint.h> |
28 | 30 | ||
29 | |||
30 | #ifdef __cplusplus | 31 | #ifdef __cplusplus |
31 | extern "C" { | 32 | extern "C" { |
32 | #endif | 33 | #endif |
33 | 34 | ||
34 | #define TOX_MAX_NAME_LENGTH 128 | 35 | /** \page core Public core API for Tox clients. |
35 | 36 | * | |
36 | /* Maximum length of single messages after which they should be split. */ | 37 | * Every function that can fail takes a function-specific error code pointer |
37 | #define TOX_MAX_MESSAGE_LENGTH 1372 | 38 | * that can be used to diagnose problems with the Tox state or the function |
38 | #define TOX_MAX_STATUSMESSAGE_LENGTH 1007 | 39 | * arguments. The error code pointer can be NULL, which does not influence the |
39 | #define TOX_CLIENT_ID_SIZE 32 | 40 | * function's behaviour, but can be done if the reason for failure is irrelevant |
40 | 41 | * to the client. | |
41 | #define TOX_FRIEND_ADDRESS_SIZE (TOX_CLIENT_ID_SIZE + sizeof(uint32_t) + sizeof(uint16_t)) | 42 | * |
42 | 43 | * The exception to this rule are simple allocation functions whose only failure | |
43 | #define TOX_ENABLE_IPV6_DEFAULT 1 | 44 | * mode is allocation failure. They return NULL in that case, and do not set an |
45 | * error code. | ||
46 | * | ||
47 | * Every error code type has an OK value to which functions will set their error | ||
48 | * code value on success. Clients can keep their error code uninitialised before | ||
49 | * passing it to a function. The library guarantees that after returning, the | ||
50 | * value pointed to by the error code pointer has been initialised. | ||
51 | * | ||
52 | * Functions with pointer parameters often have a NULL error code, meaning they | ||
53 | * could not perform any operation, because one of the required parameters was | ||
54 | * NULL. Some functions operate correctly or are defined as effectless on NULL. | ||
55 | * | ||
56 | * Some functions additionally return a value outside their | ||
57 | * return type domain, or a bool containing true on success and false on | ||
58 | * failure. | ||
59 | * | ||
60 | * All functions that take a Tox instance pointer will cause undefined behaviour | ||
61 | * when passed a NULL Tox pointer. | ||
62 | * | ||
63 | * All integer values are expected in host byte order. | ||
64 | * | ||
65 | * Functions with parameters with enum types cause unspecified behaviour if the | ||
66 | * enumeration value is outside the valid range of the type. If possible, the | ||
67 | * function will try to use a sane default, but there will be no error code, | ||
68 | * and one possible action for the function to take is to have no effect. | ||
69 | */ | ||
44 | 70 | ||
45 | /* Errors for m_addfriend | 71 | /** \subsection events Events and callbacks |
46 | * FAERR - Friend Add Error | 72 | * |
73 | * Events are handled by callbacks. One callback can be registered per event. | ||
74 | * All events have a callback function type named `tox_${event}_cb` and a | ||
75 | * function to register it named `tox_callback_${event}`. Passing a NULL | ||
76 | * callback will result in no callback being registered for that event. Only | ||
77 | * one callback per event can be registered, so if a client needs multiple | ||
78 | * event listeners, it needs to implement the dispatch functionality itself. | ||
47 | */ | 79 | */ |
48 | enum { | ||
49 | TOX_FAERR_TOOLONG = -1, | ||
50 | TOX_FAERR_NOMESSAGE = -2, | ||
51 | TOX_FAERR_OWNKEY = -3, | ||
52 | TOX_FAERR_ALREADYSENT = -4, | ||
53 | TOX_FAERR_UNKNOWN = -5, | ||
54 | TOX_FAERR_BADCHECKSUM = -6, | ||
55 | TOX_FAERR_SETNEWNOSPAM = -7, | ||
56 | TOX_FAERR_NOMEM = -8 | ||
57 | }; | ||
58 | 80 | ||
59 | /* USERSTATUS - | 81 | /** \subsection threading Threading implications |
60 | * Represents userstatuses someone can have. | 82 | * |
83 | * It is possible to run multiple concurrent threads with a Tox instance for | ||
84 | * each thread. It is also possible to run all Tox instances in the same thread. | ||
85 | * A common way to run Tox (multiple or single instance) is to have one thread | ||
86 | * running a simple tox_iteration loop, sleeping for tox_iteration_interval | ||
87 | * milliseconds on each iteration. | ||
88 | * | ||
89 | * If you want to access a single Tox instance from multiple threads, access | ||
90 | * to the instance must be synchronised. While multiple threads can concurrently | ||
91 | * access multiple different Tox instances, no more than one API function can | ||
92 | * operate on a single instance at any given time. | ||
93 | * | ||
94 | * Functions that write to variable length byte arrays will always have a size | ||
95 | * function associated with them. The result of this size function is only valid | ||
96 | * until another mutating function (one that takes a pointer to non-const Tox) | ||
97 | * is called. Thus, clients must ensure that no other thread calls a mutating | ||
98 | * function between the call to the size function and the call to the retrieval | ||
99 | * function. | ||
100 | * | ||
101 | * E.g. to get the current nickname, one would write | ||
102 | * | ||
103 | * \code | ||
104 | * size_t length = tox_self_get_name_size(tox); | ||
105 | * uint8_t *name = malloc(length); | ||
106 | * if (!name) abort(); | ||
107 | * tox_self_get_name(tox, name); | ||
108 | * \endcode | ||
109 | * | ||
110 | * If any other thread calls tox_self_set_name while this thread is allocating | ||
111 | * memory, the length will have become invalid, and the call to | ||
112 | * tox_self_get_name may cause undefined behaviour. | ||
61 | */ | 113 | */ |
62 | typedef enum { | ||
63 | TOX_USERSTATUS_NONE, | ||
64 | TOX_USERSTATUS_AWAY, | ||
65 | TOX_USERSTATUS_BUSY, | ||
66 | TOX_USERSTATUS_INVALID | ||
67 | } | ||
68 | TOX_USERSTATUS; | ||
69 | 114 | ||
70 | #ifndef __TOX_DEFINED__ | 115 | #ifndef TOX_DEFINED |
71 | #define __TOX_DEFINED__ | 116 | #define TOX_DEFINED |
117 | /** | ||
118 | * The Tox instance type. All the state associated with a connection is held | ||
119 | * within the instance. Multiple instances can exist and operate concurrently. | ||
120 | * The maximum number of Tox instances that can exist on a single network | ||
121 | * device is limited. Note that this is not just a per-process limit, since the | ||
122 | * limiting factor is the number of usable ports on a device. | ||
123 | */ | ||
72 | typedef struct Tox Tox; | 124 | typedef struct Tox Tox; |
73 | #endif | 125 | #endif |
74 | 126 | ||
75 | /* NOTE: Strings in Tox are all UTF-8, (This means that there is no terminating NULL character.) | 127 | |
128 | /******************************************************************************* | ||
76 | * | 129 | * |
77 | * The exact buffer you send will be received at the other end without modification. | 130 | * :: API version |
78 | * | 131 | * |
79 | * Do not treat Tox strings as C strings. | 132 | ******************************************************************************/ |
133 | |||
134 | |||
135 | /** | ||
136 | * The major version number. Incremented when the API or ABI changes in an | ||
137 | * incompatible way. | ||
138 | */ | ||
139 | #define TOX_VERSION_MAJOR 0u | ||
140 | /** | ||
141 | * The minor version number. Incremented when functionality is added without | ||
142 | * breaking the API or ABI. Set to 0 when the major version number is | ||
143 | * incremented. | ||
144 | */ | ||
145 | #define TOX_VERSION_MINOR 0u | ||
146 | /** | ||
147 | * The patch or revision number. Incremented when bugfixes are applied without | ||
148 | * changing any functionality or API or ABI. | ||
149 | */ | ||
150 | #define TOX_VERSION_PATCH 0u | ||
151 | |||
152 | /** | ||
153 | * A macro to check at preprocessing time whether the client code is compatible | ||
154 | * with the installed version of Tox. | ||
80 | */ | 155 | */ |
156 | #define TOX_VERSION_IS_API_COMPATIBLE(MAJOR, MINOR, PATCH) \ | ||
157 | (TOX_VERSION_MAJOR == MAJOR && \ | ||
158 | (TOX_VERSION_MINOR > MINOR || \ | ||
159 | (TOX_VERSION_MINOR == MINOR && \ | ||
160 | TOX_VERSION_PATCH >= PATCH))) | ||
161 | |||
162 | /** | ||
163 | * A macro to make compilation fail if the client code is not compatible with | ||
164 | * the installed version of Tox. | ||
165 | */ | ||
166 | #define TOX_VERSION_REQUIRE(MAJOR, MINOR, PATCH) \ | ||
167 | typedef char tox_required_version[TOX_IS_COMPATIBLE(MAJOR, MINOR, PATCH) ? 1 : -1] | ||
168 | |||
81 | 169 | ||
82 | /* return TOX_FRIEND_ADDRESS_SIZE byte address to give to others. | 170 | /** |
83 | * format: [client_id (32 bytes)][nospam number (4 bytes)][checksum (2 bytes)] | 171 | * Return the major version number of the library. Can be used to display the |
172 | * Tox library version or to check whether the client is compatible with the | ||
173 | * dynamically linked version of Tox. | ||
84 | */ | 174 | */ |
85 | void tox_get_address(const Tox *tox, uint8_t *address); | 175 | uint32_t tox_version_major(void); |
86 | 176 | ||
87 | /* Add a friend. | 177 | /** |
88 | * Set the data that will be sent along with friend request. | 178 | * Return the minor version number of the library. |
89 | * address is the address of the friend (returned by getaddress of the friend you wish to add) it must be TOX_FRIEND_ADDRESS_SIZE bytes. TODO: add checksum. | 179 | */ |
90 | * data is the data and length is the length. | 180 | uint32_t tox_version_minor(void); |
181 | |||
182 | /** | ||
183 | * Return the patch number of the library. | ||
184 | */ | ||
185 | uint32_t tox_version_patch(void); | ||
186 | |||
187 | /** | ||
188 | * Return whether the compiled library version is compatible with the passed | ||
189 | * version numbers. | ||
190 | */ | ||
191 | bool tox_version_is_compatible(uint32_t major, uint32_t minor, uint32_t patch); | ||
192 | |||
193 | /** | ||
194 | * A convenience macro to call tox_version_is_compatible with the currently | ||
195 | * compiling API version. | ||
196 | */ | ||
197 | #define TOX_VERSION_IS_ABI_COMPATIBLE() \ | ||
198 | tox_version_is_compatible(TOX_VERSION_MAJOR, TOX_VERSION_MINOR, TOX_VERSION_PATCH) | ||
199 | |||
200 | |||
201 | /******************************************************************************* | ||
202 | * | ||
203 | * :: Numeric constants | ||
91 | * | 204 | * |
92 | * return the friend number if success. | 205 | ******************************************************************************/ |
93 | * return TOX_FAERR_TOOLONG if message length is too long. | 206 | |
94 | * return TOX_FAERR_NOMESSAGE if no message (message length must be >= 1 byte). | 207 | |
95 | * return TOX_FAERR_OWNKEY if user's own key. | 208 | /** |
96 | * return TOX_FAERR_ALREADYSENT if friend request already sent or already a friend. | 209 | * The size of a Tox Public Key in bytes. |
97 | * return TOX_FAERR_UNKNOWN for unknown error. | ||
98 | * return TOX_FAERR_BADCHECKSUM if bad checksum in address. | ||
99 | * return TOX_FAERR_SETNEWNOSPAM if the friend was already there but the nospam was different. | ||
100 | * (the nospam for that friend was set to the new one). | ||
101 | * return TOX_FAERR_NOMEM if increasing the friend list size fails. | ||
102 | */ | 210 | */ |
103 | int32_t tox_add_friend(Tox *tox, const uint8_t *address, const uint8_t *data, uint16_t length); | 211 | #define TOX_PUBLIC_KEY_SIZE 32 |
104 | 212 | ||
213 | /** | ||
214 | * The size of a Tox address in bytes. Tox addresses are in the format | ||
215 | * [Public Key (TOX_PUBLIC_KEY_SIZE bytes)][nospam (4 bytes)][checksum (2 bytes)]. | ||
216 | * | ||
217 | * The checksum is computed over the Public Key and the nospam value. The first | ||
218 | * byte is an XOR of all the even bytes (0, 2, 4, ...), the second byte is an | ||
219 | * XOR of all the odd bytes (1, 3, 5, ...) of the Public Key and nospam. | ||
220 | */ | ||
221 | #define TOX_ADDRESS_SIZE (TOX_PUBLIC_KEY_SIZE + sizeof(uint32_t) + sizeof(uint16_t)) | ||
222 | |||
223 | /** | ||
224 | * Maximum length of a nickname in bytes. | ||
225 | */ | ||
226 | #define TOX_MAX_NAME_LENGTH 128 | ||
227 | |||
228 | /** | ||
229 | * Maximum length of a status message in bytes. | ||
230 | */ | ||
231 | #define TOX_MAX_STATUS_MESSAGE_LENGTH 1007 | ||
105 | 232 | ||
106 | /* Add a friend without sending a friendrequest. | 233 | /** |
107 | * return the friend number if success. | 234 | * Maximum length of a friend request message in bytes. |
108 | * return -1 if failure. | ||
109 | */ | 235 | */ |
110 | int32_t tox_add_friend_norequest(Tox *tox, const uint8_t *client_id); | 236 | #define TOX_MAX_FRIEND_REQUEST_LENGTH 1016 |
111 | 237 | ||
112 | /* return the friend number associated to that client id. | 238 | /** |
113 | return -1 if no such friend */ | 239 | * Maximum length of a single message after which it should be split. |
114 | int32_t tox_get_friend_number(const Tox *tox, const uint8_t *client_id); | 240 | */ |
241 | #define TOX_MAX_MESSAGE_LENGTH 1372 | ||
115 | 242 | ||
116 | /* Copies the public key associated to that friend id into client_id buffer. | 243 | /** |
117 | * Make sure that client_id is of size CLIENT_ID_SIZE. | 244 | * Maximum size of custom packets. TODO: should be LENGTH? |
118 | * return 0 if success. | ||
119 | * return -1 if failure. | ||
120 | */ | 245 | */ |
121 | int tox_get_client_id(const Tox *tox, int32_t friendnumber, uint8_t *client_id); | 246 | #define TOX_MAX_CUSTOM_PACKET_SIZE 1373 |
122 | 247 | ||
123 | /* Remove a friend. | 248 | /** |
249 | * The number of bytes in a hash generated by tox_hash. | ||
250 | */ | ||
251 | #define TOX_HASH_LENGTH /*crypto_hash_sha256_BYTES*/ 32 | ||
252 | |||
253 | /******************************************************************************* | ||
254 | * | ||
255 | * :: Global enumerations | ||
124 | * | 256 | * |
125 | * return 0 if success. | 257 | ******************************************************************************/ |
126 | * return -1 if failure. | 258 | |
259 | |||
260 | /** | ||
261 | * Represents the possible statuses a client can have. | ||
127 | */ | 262 | */ |
128 | int tox_del_friend(Tox *tox, int32_t friendnumber); | 263 | enum TOX_STATUS { |
264 | /** | ||
265 | * User is online and available. | ||
266 | */ | ||
267 | TOX_STATUS_NONE, | ||
268 | /** | ||
269 | * User is away. Clients can set this e.g. after a user defined | ||
270 | * inactivity time. | ||
271 | */ | ||
272 | TOX_STATUS_AWAY, | ||
273 | /** | ||
274 | * User is busy. Signals to other clients that this client does not | ||
275 | * currently wish to communicate. | ||
276 | */ | ||
277 | TOX_STATUS_BUSY, | ||
278 | /** | ||
279 | * Invalid status used when function returns an error. | ||
280 | */ | ||
281 | TOX_STATUS_INVALID | ||
282 | }; | ||
283 | typedef uint8_t TOX_STATUS; | ||
129 | 284 | ||
130 | /* Checks friend's connecting status. | 285 | /******************************************************************************* |
131 | * | 286 | * |
132 | * return 1 if friend is connected to us (Online). | 287 | * :: Startup options |
133 | * return 0 if friend is not connected to us (Offline). | 288 | * |
134 | * return -1 on failure. | 289 | ******************************************************************************/ |
290 | |||
291 | |||
292 | enum TOX_PROXY_TYPE { | ||
293 | /** | ||
294 | * Don't use a proxy. | ||
295 | */ | ||
296 | TOX_PROXY_TYPE_NONE, | ||
297 | /** | ||
298 | * HTTP proxy using CONNECT. | ||
299 | */ | ||
300 | TOX_PROXY_TYPE_HTTP, | ||
301 | /** | ||
302 | * SOCKS proxy for simple socket pipes. | ||
303 | */ | ||
304 | TOX_PROXY_TYPE_SOCKS5 | ||
305 | }; | ||
306 | typedef uint8_t TOX_PROXY_TYPE; | ||
307 | |||
308 | /** | ||
309 | * This struct contains all the startup options for Tox. You can either allocate | ||
310 | * this object yourself, and pass it to tox_options_default, or call | ||
311 | * tox_options_new to get a new default options object. | ||
135 | */ | 312 | */ |
136 | int tox_get_friend_connection_status(const Tox *tox, int32_t friendnumber); | 313 | struct Tox_Options { |
314 | /** | ||
315 | * The type of socket to create. | ||
316 | * | ||
317 | * If this is set to false, an IPv4 socket is created, which subsequently | ||
318 | * only allows IPv4 communication. | ||
319 | * If it is set to true, an IPv6 socket is created, allowing both IPv4 and | ||
320 | * IPv6 communication. | ||
321 | */ | ||
322 | bool ipv6_enabled; | ||
323 | |||
324 | /** | ||
325 | * Enable the use of UDP communication when available. | ||
326 | * | ||
327 | * Setting this to false will force Tox to use TCP only. Communications will | ||
328 | * need to be relayed through a TCP relay node, potentially slowing them down. | ||
329 | * Disabling UDP support is necessary when using anonymous proxies or Tor. | ||
330 | */ | ||
331 | bool udp_enabled; | ||
332 | |||
333 | /** | ||
334 | * Pass communications through a proxy. | ||
335 | */ | ||
336 | TOX_PROXY_TYPE proxy_type; | ||
337 | |||
338 | /** | ||
339 | * The IP address or DNS name of the proxy to be used. | ||
340 | * | ||
341 | * If used, this must be non-NULL and be a valid DNS name. The name must not | ||
342 | * exceed 255 characters, and be in a NUL-terminated C string format | ||
343 | * (255 chars + 1 NUL byte). | ||
344 | * | ||
345 | * This member is ignored (it can be NULL) if proxy_enabled is false. | ||
346 | */ | ||
347 | const char *proxy_address; | ||
348 | |||
349 | /** | ||
350 | * The port to use to connect to the proxy server. | ||
351 | * | ||
352 | * Ports must be in the range (1, 65535). The value is ignored if | ||
353 | * proxy_enabled is false. | ||
354 | */ | ||
355 | uint16_t proxy_port; | ||
356 | }; | ||
137 | 357 | ||
138 | /* Checks if there exists a friend with given friendnumber. | 358 | |
359 | /** | ||
360 | * Initialises a Tox_Options object with the default options. | ||
361 | * | ||
362 | * The result of this function is independent of the original options. All | ||
363 | * values will be overwritten, no values will be read (so it is permissible | ||
364 | * to pass an uninitialised object). | ||
365 | * | ||
366 | * If options is NULL, this function has no effect. | ||
139 | * | 367 | * |
140 | * return 1 if friend exists. | 368 | * @param options An options object to be filled with default options. |
141 | * return 0 if friend doesn't exist. | ||
142 | */ | 369 | */ |
143 | int tox_friend_exists(const Tox *tox, int32_t friendnumber); | 370 | void tox_options_default(struct Tox_Options *options); |
144 | 371 | ||
145 | /* Send a text chat message to an online friend. | 372 | |
373 | enum TOX_ERR_OPTIONS_NEW { | ||
374 | TOX_ERR_OPTIONS_NEW_OK, | ||
375 | /** | ||
376 | * The function failed to allocate enough memory for the options struct. | ||
377 | */ | ||
378 | TOX_ERR_OPTIONS_NEW_MALLOC | ||
379 | }; | ||
380 | typedef uint8_t TOX_ERR_OPTIONS_NEW; | ||
381 | |||
382 | /** | ||
383 | * Allocates a new Tox_Options object and initialises it with the default | ||
384 | * options. This function can be used to preserve long term ABI compatibility by | ||
385 | * giving the responsibility of allocation and deallocation to the Tox library. | ||
146 | * | 386 | * |
147 | * return the message id if packet was successfully put into the send queue. | 387 | * Objects returned from this function must be freed using the tox_options_free |
148 | * return 0 if it was not. | 388 | * function. |
149 | * | 389 | * |
150 | * maximum length of messages is TOX_MAX_MESSAGE_LENGTH, your client must split larger messages | 390 | * @return A new Tox_Options object with default options or NULL on failure. |
151 | * or else sending them will not work. No the core will not split messages for you because that | 391 | */ |
152 | * requires me to parse UTF-8. | 392 | struct Tox_Options *tox_options_new(TOX_ERR_OPTIONS_NEW *error); |
393 | |||
394 | |||
395 | /** | ||
396 | * Releases all resources associated with an options objects. | ||
153 | * | 397 | * |
154 | * You will want to retain the return value, it will be passed to your read_receipt callback | 398 | * Passing a pointer that was not returned by tox_options_new results in |
155 | * if one is received. | 399 | * undefined behaviour. |
156 | */ | 400 | */ |
157 | uint32_t tox_send_message(Tox *tox, int32_t friendnumber, const uint8_t *message, uint32_t length); | 401 | void tox_options_free(struct Tox_Options *options); |
402 | |||
403 | |||
404 | /******************************************************************************* | ||
405 | * | ||
406 | * :: Creation and destruction | ||
407 | * | ||
408 | ******************************************************************************/ | ||
409 | |||
410 | |||
411 | enum TOX_ERR_NEW { | ||
412 | TOX_ERR_NEW_OK, | ||
413 | TOX_ERR_NEW_NULL, | ||
414 | /** | ||
415 | * The function was unable to allocate enough memory to store the internal | ||
416 | * structures for the Tox object. | ||
417 | */ | ||
418 | TOX_ERR_NEW_MALLOC, | ||
419 | /** | ||
420 | * The function was unable to bind to a port. This may mean that all ports | ||
421 | * have already been bound, e.g. by other Tox instances, or it may mean | ||
422 | * a permission error. You may be able to gather more information from errno. | ||
423 | */ | ||
424 | TOX_ERR_NEW_PORT_ALLOC, | ||
425 | /** | ||
426 | * proxy_type was invalid. | ||
427 | */ | ||
428 | TOX_ERR_PROXY_TYPE, | ||
429 | /** | ||
430 | * proxy_type was valid but the proxy_address passed had an invalid format | ||
431 | * or was NULL. | ||
432 | */ | ||
433 | TOX_ERR_NEW_PROXY_BAD_HOST, | ||
434 | /** | ||
435 | * proxy_type was valid, but the proxy_port was invalid. | ||
436 | */ | ||
437 | TOX_ERR_NEW_PROXY_BAD_PORT, | ||
438 | /** | ||
439 | * The proxy address passed could not be resolved. | ||
440 | */ | ||
441 | TOX_ERR_NEW_PROXY_NOT_FOUND, | ||
442 | /** | ||
443 | * The byte array to be loaded contained an encrypted save. | ||
444 | */ | ||
445 | TOX_ERR_NEW_LOAD_ENCRYPTED, | ||
446 | /** | ||
447 | * The data format was invalid. This can happen when loading data that was | ||
448 | * saved by an older version of Tox, or when the data has been corrupted. | ||
449 | * When loading from badly formatted data, some data may have been loaded, | ||
450 | * and the rest is discarded. Passing an invalid length parameter also | ||
451 | * causes this error. | ||
452 | */ | ||
453 | TOX_ERR_NEW_LOAD_BAD_FORMAT | ||
454 | }; | ||
455 | typedef uint8_t TOX_ERR_NEW; | ||
158 | 456 | ||
159 | /* Send an action to an online friend. | 457 | /** |
458 | * @brief Creates and initialises a new Tox instance with the options passed. | ||
459 | * | ||
460 | * This function will bring the instance into a valid state. Running the event | ||
461 | * loop with a new instance will operate correctly. | ||
462 | * | ||
463 | * If the data parameter is not NULL, this function will load the Tox instance | ||
464 | * from a byte array previously filled by tox_save. | ||
160 | * | 465 | * |
161 | * return the message id if packet was successfully put into the send queue. | 466 | * If loading failed or succeeded only partially, the new or partially loaded |
162 | * return 0 if it was not. | 467 | * instance is returned and an error code is set. |
163 | * | 468 | * |
164 | * maximum length of actions is TOX_MAX_MESSAGE_LENGTH, your client must split larger actions | 469 | * @param options An options object as described above. If this parameter is |
165 | * or else sending them will not work. No the core will not split actions for you because that | 470 | * NULL, the default options are used. |
166 | * requires me to parse UTF-8. | 471 | * @param data A byte array containing data previously stored by tox_save. |
472 | * @param length The length of the byte array data. If this parameter is 0, the | ||
473 | * data parameter is ignored. | ||
167 | * | 474 | * |
168 | * You will want to retain the return value, it will be passed to your read_receipt callback | 475 | * @see tox_iteration for the event loop. |
169 | * if one is received. | ||
170 | */ | 476 | */ |
171 | uint32_t tox_send_action(Tox *tox, int32_t friendnumber, const uint8_t *action, uint32_t length); | 477 | Tox *tox_new(const struct Tox_Options *options, const uint8_t *data, size_t length, TOX_ERR_NEW *error); |
172 | 478 | ||
173 | /* Set our nickname. | 479 | |
174 | * name must be a string of maximum MAX_NAME_LENGTH length. | 480 | /** |
175 | * length must be at least 1 byte. | 481 | * Releases all resources associated with the Tox instance and disconnects from |
176 | * length is the length of name with the NULL terminator. | 482 | * the network. |
177 | * | 483 | * |
178 | * return 0 if success. | 484 | * After calling this function, the Tox pointer becomes invalid. No other |
179 | * return -1 if failure. | 485 | * functions can be called, and the pointer value can no longer be read. |
180 | */ | 486 | */ |
181 | int tox_set_name(Tox *tox, const uint8_t *name, uint16_t length); | 487 | void tox_kill(Tox *tox); |
182 | 488 | ||
183 | /* | 489 | |
184 | * Get your nickname. | 490 | /** |
185 | * m - The messenger context to use. | 491 | * Calculates the number of bytes required to store the tox instance with |
186 | * name - needs to be a valid memory location with a size of at least MAX_NAME_LENGTH (128) bytes. | 492 | * tox_save. This function cannot fail. The result is always greater than 0. |
187 | * | 493 | * |
188 | * return length of name. | 494 | * @see threading for concurrency implications. |
189 | * return 0 on error. | ||
190 | */ | 495 | */ |
191 | uint16_t tox_get_self_name(const Tox *tox, uint8_t *name); | 496 | size_t tox_save_size(const Tox *tox); |
192 | 497 | ||
193 | /* Get name of friendnumber and put it in name. | 498 | /** |
194 | * name needs to be a valid memory location with a size of at least MAX_NAME_LENGTH (128) bytes. | 499 | * Store all information associated with the tox instance to a byte array. |
195 | * | 500 | * |
196 | * return length of name if success. | 501 | * @param data A memory region large enough to store the tox instance data. |
197 | * return -1 if failure. | 502 | * Call tox_save_size to find the number of bytes required. If this parameter |
503 | * is NULL, this function has no effect. | ||
198 | */ | 504 | */ |
199 | int tox_get_name(const Tox *tox, int32_t friendnumber, uint8_t *name); | 505 | void tox_save(const Tox *tox, uint8_t *data); |
200 | 506 | ||
201 | /* returns the length of name on success. | 507 | |
202 | * returns -1 on failure. | 508 | /******************************************************************************* |
509 | * | ||
510 | * :: Connection lifecycle and event loop | ||
511 | * | ||
512 | ******************************************************************************/ | ||
513 | |||
514 | |||
515 | enum TOX_ERR_BOOTSTRAP { | ||
516 | TOX_ERR_BOOTSTRAP_OK, | ||
517 | TOX_ERR_BOOTSTRAP_NULL, | ||
518 | /** | ||
519 | * The address could not be resolved to an IP address, or the IP address | ||
520 | * passed was invalid. | ||
521 | */ | ||
522 | TOX_ERR_BOOTSTRAP_BAD_ADDRESS, | ||
523 | /** | ||
524 | * The port passed was invalid. The valid port range is (1, 65535). | ||
525 | */ | ||
526 | TOX_ERR_BOOTSTRAP_BAD_PORT | ||
527 | }; | ||
528 | typedef uint8_t TOX_ERR_BOOTSTRAP; | ||
529 | |||
530 | /** | ||
531 | * Sends a "get nodes" request to the given bootstrap node with IP, port, and | ||
532 | * public key to setup connections. | ||
533 | * | ||
534 | * This function will attempt to connect to the node using UDP and TCP at the | ||
535 | * same time. | ||
536 | * | ||
537 | * Tox will use the node as a TCP relay in case Tox_Options.udp_enabled was | ||
538 | * false, and also to connect to friends that are in TCP-only mode. Tox will | ||
539 | * also use the TCP connection when NAT hole punching is slow, and later switch | ||
540 | * to UDP if hole punching succeeds. | ||
541 | * | ||
542 | * @param address The hostname or IP address (IPv4 or IPv6) of the node. | ||
543 | * @param port The port on the host on which the bootstrap Tox instance is | ||
544 | * listening. | ||
545 | * @param public_key The long term public key of the bootstrap node | ||
546 | * (TOX_PUBLIC_KEY_SIZE bytes). | ||
547 | * @return true on success. | ||
203 | */ | 548 | */ |
204 | int tox_get_name_size(const Tox *tox, int32_t friendnumber); | 549 | bool tox_bootstrap(Tox *tox, const char *address, uint16_t port, const uint8_t *public_key, TOX_ERR_BOOTSTRAP *error); |
205 | int tox_get_self_name_size(const Tox *tox); | 550 | |
206 | 551 | ||
207 | /* Set our user status. | 552 | /** |
553 | * Adds additional host:port pair as TCP relay. | ||
208 | * | 554 | * |
209 | * userstatus must be one of TOX_USERSTATUS values. | 555 | * This function can be used to initiate TCP connections to different ports on |
210 | * max length of the status is TOX_MAX_STATUSMESSAGE_LENGTH. | 556 | * the same bootstrap node, or to add TCP relays without using them as |
557 | * bootstrap nodes. | ||
211 | * | 558 | * |
212 | * returns 0 on success. | 559 | * @param address The hostname or IP address (IPv4 or IPv6) of the TCP relay. |
213 | * returns -1 on failure. | 560 | * @param port The port on the host on which the TCP relay is listening. |
561 | * @param public_key The long term public key of the TCP relay | ||
562 | * (TOX_PUBLIC_KEY_SIZE bytes). | ||
563 | * @return true on success. | ||
214 | */ | 564 | */ |
215 | int tox_set_status_message(Tox *tox, const uint8_t *status, uint16_t length); | 565 | bool tox_add_tcp_relay(Tox *tox, const char *address, uint16_t port, const uint8_t *public_key, |
216 | int tox_set_user_status(Tox *tox, uint8_t userstatus); | 566 | TOX_ERR_BOOTSTRAP *error); |
567 | |||
568 | |||
569 | enum TOX_CONNECTION { | ||
570 | /** | ||
571 | * There is no connection. This instance, or the friend the state change is | ||
572 | * about, is now offline. | ||
573 | */ | ||
574 | TOX_CONNECTION_NONE, | ||
575 | /** | ||
576 | * A TCP connection has been established. For the own instance, this means it | ||
577 | * is connected through a TCP relay, only. For a friend, this means that the | ||
578 | * connection to that particular friend goes through a TCP relay. | ||
579 | */ | ||
580 | TOX_CONNECTION_TCP, | ||
581 | /** | ||
582 | * A UDP connection has been established. For the own instance, this means it | ||
583 | * is able to send UDP packets to DHT nodes, but may still be connected to | ||
584 | * a TCP relay. For a friend, this means that the connection to that | ||
585 | * particular friend was built using direct UDP packets. | ||
586 | */ | ||
587 | TOX_CONNECTION_UDP | ||
588 | }; | ||
589 | typedef uint8_t TOX_CONNECTION; | ||
217 | 590 | ||
218 | /* returns the length of status message on success. | 591 | /** |
219 | * returns -1 on failure. | 592 | * Return whether we are connected to the DHT. The return value is equal to the |
593 | * last value received through the `connection_status` callback. | ||
220 | */ | 594 | */ |
221 | int tox_get_status_message_size(const Tox *tox, int32_t friendnumber); | 595 | TOX_CONNECTION tox_get_connection_status(const Tox *tox); |
222 | int tox_get_self_status_message_size(const Tox *tox); | ||
223 | 596 | ||
224 | /* Copy friendnumber's status message into buf, truncating if size is over maxlen. | 597 | /** |
225 | * Get the size you need to allocate from m_get_statusmessage_size. | 598 | * The function type for the `connection_status` callback. |
226 | * The self variant will copy our own status message. | ||
227 | * | 599 | * |
228 | * returns the length of the copied data on success | 600 | * @param connection_status Equal to the return value of |
229 | * retruns -1 on failure. | 601 | * tox_get_connection_status. |
230 | */ | 602 | */ |
231 | int tox_get_status_message(const Tox *tox, int32_t friendnumber, uint8_t *buf, uint32_t maxlen); | 603 | typedef void tox_connection_status_cb(Tox *tox, TOX_CONNECTION connection_status, void *user_data); |
232 | int tox_get_self_status_message(const Tox *tox, uint8_t *buf, uint32_t maxlen); | ||
233 | 604 | ||
234 | /* return one of TOX_USERSTATUS values. | 605 | /** |
235 | * Values unknown to your application should be represented as TOX_USERSTATUS_NONE. | 606 | * Set the callback for the `connection_status` event. Pass NULL to unset. |
236 | * As above, the self variant will return our own TOX_USERSTATUS. | 607 | * |
237 | * If friendnumber is invalid, this shall return TOX_USERSTATUS_INVALID. | 608 | * This event is triggered whenever there is a change in the DHT connection |
609 | * state. When disconnected, a client may choose to call tox_bootstrap again, to | ||
610 | * reconnect to the DHT. Note that this state may frequently change for short | ||
611 | * amounts of time. Clients should therefore not immediately bootstrap on | ||
612 | * receiving a disconnect. | ||
613 | * | ||
614 | * TODO: how long should a client wait before bootstrapping again? | ||
238 | */ | 615 | */ |
239 | uint8_t tox_get_user_status(const Tox *tox, int32_t friendnumber); | 616 | void tox_callback_connection_status(Tox *tox, tox_connection_status_cb *function, void *user_data); |
240 | uint8_t tox_get_self_user_status(const Tox *tox); | ||
241 | 617 | ||
242 | 618 | ||
243 | /* returns timestamp of last time friendnumber was seen online, or 0 if never seen. | 619 | /** |
244 | * returns -1 on error. | 620 | * Return the time in milliseconds before tox_iteration() should be called again |
621 | * for optimal performance. | ||
245 | */ | 622 | */ |
246 | uint64_t tox_get_last_online(const Tox *tox, int32_t friendnumber); | 623 | uint32_t tox_iteration_interval(const Tox *tox); |
247 | 624 | ||
248 | /* Set our typing status for a friend. | 625 | |
249 | * You are responsible for turning it on or off. | 626 | /** |
250 | * | 627 | * The main loop that needs to be run in intervals of tox_iteration_interval() |
251 | * returns 0 on success. | 628 | * milliseconds. |
252 | * returns -1 on failure. | ||
253 | */ | 629 | */ |
254 | int tox_set_user_is_typing(Tox *tox, int32_t friendnumber, uint8_t is_typing); | 630 | void tox_iteration(Tox *tox); |
631 | |||
255 | 632 | ||
256 | /* Get the typing status of a friend. | 633 | /******************************************************************************* |
634 | * | ||
635 | * :: Internal client information (Tox address/id) | ||
257 | * | 636 | * |
258 | * returns 0 if friend is not typing. | 637 | ******************************************************************************/ |
259 | * returns 1 if friend is typing. | 638 | |
639 | |||
640 | /** | ||
641 | * Writes the Tox friend address of the client to a byte array. The address is | ||
642 | * not in human-readable format. If a client wants to display the address, | ||
643 | * formatting is required. | ||
644 | * | ||
645 | * @param address A memory region of at least TOX_ADDRESS_SIZE bytes. If this | ||
646 | * parameter is NULL, this function has no effect. | ||
647 | * @see TOX_ADDRESS_SIZE for the address format. | ||
260 | */ | 648 | */ |
261 | uint8_t tox_get_is_typing(const Tox *tox, int32_t friendnumber); | 649 | void tox_self_get_address(const Tox *tox, uint8_t *address); |
262 | 650 | ||
263 | /* Return the number of friends in the instance m. | ||
264 | * You should use this to determine how much memory to allocate | ||
265 | * for copy_friendlist. */ | ||
266 | uint32_t tox_count_friendlist(const Tox *tox); | ||
267 | 651 | ||
268 | /* Return the number of online friends in the instance m. */ | 652 | /** |
269 | uint32_t tox_get_num_online_friends(const Tox *tox); | 653 | * Set the 4-byte nospam part of the address. |
654 | * | ||
655 | * @param nospam Any 32 bit unsigned integer. | ||
656 | */ | ||
657 | void tox_self_set_nospam(Tox *tox, uint32_t nospam); | ||
270 | 658 | ||
271 | /* Copy a list of valid friend IDs into the array out_list. | 659 | /** |
272 | * If out_list is NULL, returns 0. | 660 | * Get the 4-byte nospam part of the address. |
273 | * Otherwise, returns the number of elements copied. | 661 | */ |
274 | * If the array was too small, the contents | 662 | uint32_t tox_self_get_nospam(const Tox *tox); |
275 | * of out_list will be truncated to list_size. */ | ||
276 | uint32_t tox_get_friendlist(const Tox *tox, int32_t *out_list, uint32_t list_size); | ||
277 | 663 | ||
278 | /* Set the function that will be executed when a friend request is received. | 664 | /** |
279 | * Function format is function(Tox *tox, uint8_t * public_key, uint8_t * data, uint16_t length, void *userdata) | 665 | * Copy the Tox Public Key (long term public key) from the Tox object. |
666 | * | ||
667 | * @param public_key A memory region of at least TOX_PUBLIC_KEY_SIZE bytes. If | ||
668 | * this parameter is NULL, this function has no effect. | ||
280 | */ | 669 | */ |
281 | void tox_callback_friend_request(Tox *tox, void (*function)(Tox *tox, const uint8_t *, const uint8_t *, uint16_t, | 670 | void tox_self_get_public_key(const Tox *tox, uint8_t *public_key); |
282 | void *), void *userdata); | ||
283 | 671 | ||
284 | /* Set the function that will be executed when a message from a friend is received. | 672 | /** |
285 | * Function format is: function(Tox *tox, int32_t friendnumber, uint8_t * message, uint16_t length, void *userdata) | 673 | * Copy the private key from the Tox object. |
674 | * | ||
675 | * @param private_key A memory region of at least TOX_PUBLIC_KEY_SIZE bytes. If | ||
676 | * this parameter is NULL, this function has no effect. | ||
286 | */ | 677 | */ |
287 | void tox_callback_friend_message(Tox *tox, void (*function)(Tox *tox, int32_t, const uint8_t *, uint16_t, void *), | 678 | void tox_self_get_private_key(const Tox *tox, uint8_t *private_key); |
288 | void *userdata); | 679 | |
289 | 680 | ||
290 | /* Set the function that will be executed when an action from a friend is received. | 681 | /******************************************************************************* |
291 | * Function format is: function(Tox *tox, int32_t friendnumber, uint8_t * action, uint16_t length, void *userdata) | 682 | * |
683 | * :: User-visible client information (nickname/status) | ||
684 | * | ||
685 | ******************************************************************************/ | ||
686 | |||
687 | |||
688 | /** | ||
689 | * Common error codes for all functions that set a piece of user-visible | ||
690 | * client information. | ||
292 | */ | 691 | */ |
293 | void tox_callback_friend_action(Tox *tox, void (*function)(Tox *tox, int32_t, const uint8_t *, uint16_t, void *), | 692 | enum TOX_ERR_SET_INFO { |
294 | void *userdata); | 693 | TOX_ERR_SET_INFO_OK, |
694 | TOX_ERR_SET_INFO_NULL, | ||
695 | /** | ||
696 | * Information length exceeded maximum permissible size. | ||
697 | */ | ||
698 | TOX_ERR_SET_INFO_TOO_LONG | ||
699 | }; | ||
700 | typedef uint8_t TOX_ERR_SET_INFO; | ||
295 | 701 | ||
296 | /* Set the callback for name changes. | 702 | /** |
297 | * function(Tox *tox, int32_t friendnumber, uint8_t *newname, uint16_t length, void *userdata) | 703 | * Set the nickname for the Tox client. |
298 | * You are not responsible for freeing newname | 704 | * |
705 | * Nickname length cannot exceed TOX_MAX_NAME_LENGTH. If length is 0, the name | ||
706 | * parameter is ignored (it can be NULL), and the nickname is set back to empty. | ||
707 | * | ||
708 | * @param name A byte array containing the new nickname. | ||
709 | * @param length The size of the name byte array. | ||
710 | * | ||
711 | * @return true on success. | ||
299 | */ | 712 | */ |
300 | void tox_callback_name_change(Tox *tox, void (*function)(Tox *tox, int32_t, const uint8_t *, uint16_t, void *), | 713 | bool tox_self_set_name(Tox *tox, const uint8_t *name, size_t length, TOX_ERR_SET_INFO *error); |
301 | void *userdata); | ||
302 | 714 | ||
303 | /* Set the callback for status message changes. | 715 | /** |
304 | * function(Tox *tox, int32_t friendnumber, uint8_t *newstatus, uint16_t length, void *userdata) | 716 | * Return the length of the current nickname as passed to tox_self_set_name. |
305 | * You are not responsible for freeing newstatus. | 717 | * |
718 | * If no nickname was set before calling this function, the name is empty, | ||
719 | * and this function returns 0. | ||
720 | * | ||
721 | * @see threading for concurrency implications. | ||
306 | */ | 722 | */ |
307 | void tox_callback_status_message(Tox *tox, void (*function)(Tox *tox, int32_t, const uint8_t *, uint16_t, void *), | 723 | size_t tox_self_get_name_size(const Tox *tox); |
308 | void *userdata); | ||
309 | 724 | ||
310 | /* Set the callback for status type changes. | 725 | /** |
311 | * function(Tox *tox, int32_t friendnumber, uint8_t TOX_USERSTATUS, void *userdata) | 726 | * Write the nickname set by tox_self_set_name to a byte array. |
727 | * | ||
728 | * If no nickname was set before calling this function, the name is empty, | ||
729 | * and this function has no effect. | ||
730 | * | ||
731 | * Call tox_self_get_name_size to find out how much memory to allocate for | ||
732 | * the result. | ||
733 | * | ||
734 | * @param name A valid memory location large enough to hold the nickname. | ||
735 | * If this parameter is NULL, the function has no effect. | ||
312 | */ | 736 | */ |
313 | void tox_callback_user_status(Tox *tox, void (*function)(Tox *tox, int32_t, uint8_t, void *), void *userdata); | 737 | void tox_self_get_name(const Tox *tox, uint8_t *name); |
314 | 738 | ||
315 | /* Set the callback for typing changes. | 739 | /** |
316 | * function (Tox *tox, int32_t friendnumber, uint8_t is_typing, void *userdata) | 740 | * Set the client's status message. |
741 | * | ||
742 | * Status message length cannot exceed TOX_MAX_STATUS_MESSAGE_LENGTH. If | ||
743 | * length is 0, the status parameter is ignored (it can be NULL), and the | ||
744 | * user status is set back to empty. | ||
317 | */ | 745 | */ |
318 | void tox_callback_typing_change(Tox *tox, void (*function)(Tox *tox, int32_t, uint8_t, void *), void *userdata); | 746 | bool tox_self_set_status_message(Tox *tox, const uint8_t *status, size_t length, TOX_ERR_SET_INFO *error); |
319 | 747 | ||
320 | /* Set the callback for read receipts. | 748 | /** |
321 | * function(Tox *tox, int32_t friendnumber, uint32_t receipt, void *userdata) | 749 | * Return the length of the current status message as passed to |
750 | * tox_self_set_status_message. | ||
751 | * | ||
752 | * If no status message was set before calling this function, the status | ||
753 | * is empty, and this function returns 0. | ||
322 | * | 754 | * |
323 | * If you are keeping a record of returns from m_sendmessage; | 755 | * @see threading for concurrency implications. |
324 | * receipt might be one of those values, meaning the message | ||
325 | * has been received on the other side. | ||
326 | * Since core doesn't track ids for you, receipt may not correspond to any message. | ||
327 | * In that case, you should discard it. | ||
328 | */ | 756 | */ |
329 | void tox_callback_read_receipt(Tox *tox, void (*function)(Tox *tox, int32_t, uint32_t, void *), void *userdata); | 757 | size_t tox_self_get_status_message_size(const Tox *tox); |
330 | 758 | ||
331 | /* Set the callback for connection status changes. | 759 | /** |
332 | * function(Tox *tox, int32_t friendnumber, uint8_t status, void *userdata) | 760 | * Write the status message set by tox_self_set_status_message to a byte array. |
333 | * | 761 | * |
334 | * Status: | 762 | * If no status message was set before calling this function, the status is |
335 | * 0 -- friend went offline after being previously online | 763 | * empty, and this function has no effect. |
336 | * 1 -- friend went online | ||
337 | * | 764 | * |
338 | * NOTE: This callback is not called when adding friends, thus the "after | 765 | * Call tox_self_status_message_size to find out how much memory to allocate for |
339 | * being previously online" part. it's assumed that when adding friends, | 766 | * the result. |
340 | * their connection status is offline. | 767 | * |
768 | * @param status A valid memory location large enough to hold the status message. | ||
769 | * If this parameter is NULL, the function has no effect. | ||
341 | */ | 770 | */ |
342 | void tox_callback_connection_status(Tox *tox, void (*function)(Tox *tox, int32_t, uint8_t, void *), void *userdata); | 771 | void tox_self_get_status_message(const Tox *tox, uint8_t *status); |
343 | 772 | ||
344 | 773 | ||
345 | /**********ADVANCED FUNCTIONS (If you don't know what they do you can safely ignore them.) ************/ | 774 | /** |
775 | * Set the client's user status. | ||
776 | * | ||
777 | * @param user_status One of the user statuses listed in the enumeration above. | ||
778 | */ | ||
779 | void tox_self_set_status(Tox *tox, TOX_STATUS user_status); | ||
346 | 780 | ||
347 | /* Functions to get/set the nospam part of the id. | 781 | /** |
782 | * Returns the client's user status. | ||
348 | */ | 783 | */ |
349 | uint32_t tox_get_nospam(const Tox *tox); | 784 | TOX_STATUS tox_self_get_status(const Tox *tox); |
350 | void tox_set_nospam(Tox *tox, uint32_t nospam); | 785 | |
786 | |||
787 | /******************************************************************************* | ||
788 | * | ||
789 | * :: Friend list management | ||
790 | * | ||
791 | ******************************************************************************/ | ||
792 | |||
793 | |||
794 | enum TOX_ERR_FRIEND_ADD { | ||
795 | TOX_ERR_FRIEND_ADD_OK, | ||
796 | TOX_ERR_FRIEND_ADD_NULL, | ||
797 | /** | ||
798 | * The length of the friend request message exceeded | ||
799 | * TOX_MAX_FRIEND_REQUEST_LENGTH. | ||
800 | */ | ||
801 | TOX_ERR_FRIEND_ADD_TOO_LONG, | ||
802 | /** | ||
803 | * The friend request message was empty. This, and the TOO_LONG code will | ||
804 | * never be returned from tox_friend_add_norequest. | ||
805 | */ | ||
806 | TOX_ERR_FRIEND_ADD_NO_MESSAGE, | ||
807 | /** | ||
808 | * The friend address belongs to the sending client. | ||
809 | */ | ||
810 | TOX_ERR_FRIEND_ADD_OWN_KEY, | ||
811 | /** | ||
812 | * A friend request has already been sent, or the address belongs to a friend | ||
813 | * that is already on the friend list. | ||
814 | */ | ||
815 | TOX_ERR_FRIEND_ADD_ALREADY_SENT, | ||
816 | /** | ||
817 | * The friend address checksum failed. | ||
818 | */ | ||
819 | TOX_ERR_FRIEND_ADD_BAD_CHECKSUM, | ||
820 | /** | ||
821 | * The friend was already there, but the nospam value was different. | ||
822 | */ | ||
823 | TOX_ERR_FRIEND_ADD_SET_NEW_NOSPAM, | ||
824 | /** | ||
825 | * A memory allocation failed when trying to increase the friend list size. | ||
826 | */ | ||
827 | TOX_ERR_FRIEND_ADD_MALLOC | ||
828 | }; | ||
829 | typedef uint8_t TOX_ERR_FRIEND_ADD; | ||
351 | 830 | ||
352 | /* Copy the public and secret key from the Tox object. | 831 | /** |
353 | public_key and secret_key must be 32 bytes big. | 832 | * Add a friend to the friend list and send a friend request. |
354 | if the pointer is NULL, no data will be copied to it.*/ | 833 | * |
355 | void tox_get_keys(Tox *tox, uint8_t *public_key, uint8_t *secret_key); | 834 | * A friend request message must be at least 1 byte long and at most |
835 | * TOX_MAX_FRIEND_REQUEST_LENGTH. | ||
836 | * | ||
837 | * Friend numbers are unique identifiers used in all functions that operate on | ||
838 | * friends. Once added, a friend number is stable for the lifetime of the Tox | ||
839 | * object. After saving the state and reloading it, the friend numbers may not | ||
840 | * be the same as before. Deleting a friend creates a gap in the friend number | ||
841 | * set, which is filled by the next adding of a friend. | ||
842 | * | ||
843 | * If more than INT32_MAX friends are added, this function causes undefined | ||
844 | * behaviour. | ||
845 | * | ||
846 | * @param address The address of the friend (returned by tox_self_get_address of | ||
847 | * the friend you wish to add) it must be TOX_ADDRESS_SIZE bytes. | ||
848 | * @param message The message that will be sent along with the friend request. | ||
849 | * @param length The length of the data byte array. | ||
850 | * | ||
851 | * @return the friend number on success, UINT32_MAX on failure. | ||
852 | */ | ||
853 | uint32_t tox_friend_add(Tox *tox, const uint8_t *address, const uint8_t *message, size_t length, | ||
854 | TOX_ERR_FRIEND_ADD *error); | ||
356 | 855 | ||
357 | /**********GROUP CHAT FUNCTIONS: WARNING Group chats will be rewritten so this might change ************/ | ||
358 | 856 | ||
359 | /* Set the callback for group invites. | 857 | /** |
858 | * Add a friend without sending a friend request. | ||
360 | * | 859 | * |
361 | * Function(Tox *tox, int friendnumber, uint8_t *group_public_key, void *userdata) | 860 | * This function is used to add a friend in response to a friend request. If the |
861 | * client receives a friend request, it can be reasonably sure that the other | ||
862 | * client added this client as a friend, eliminating the need for a friend | ||
863 | * request. | ||
864 | * | ||
865 | * This function is also useful in a situation where both instances are | ||
866 | * controlled by the same entity, so that this entity can perform the mutual | ||
867 | * friend adding. In this case, there is no need for a friend request, either. | ||
868 | * | ||
869 | * @param public_key A byte array of length TOX_PUBLIC_KEY_SIZE containing the | ||
870 | * Public Key (not the Address) of the friend to add. | ||
871 | * | ||
872 | * @return the friend number on success, UINT32_MAX on failure. | ||
873 | * @see tox_friend_add for a more detailed description of friend numbers. | ||
362 | */ | 874 | */ |
363 | void tox_callback_group_invite(Tox *tox, void (*function)(Tox *tox, int32_t, const uint8_t *, void *), void *userdata); | 875 | uint32_t tox_friend_add_norequest(Tox *tox, const uint8_t *public_key, TOX_ERR_FRIEND_ADD *error); |
364 | 876 | ||
365 | /* Set the callback for group messages. | 877 | |
878 | enum TOX_ERR_FRIEND_DELETE { | ||
879 | TOX_ERR_FRIEND_DELETE_OK, | ||
880 | /** | ||
881 | * There was no friend with the given friend number. No friends were deleted. | ||
882 | */ | ||
883 | TOX_ERR_FRIEND_DELETE_FRIEND_NOT_FOUND | ||
884 | }; | ||
885 | typedef uint8_t TOX_ERR_FRIEND_DELETE; | ||
886 | |||
887 | /** | ||
888 | * Remove a friend from the friend list. | ||
889 | * | ||
890 | * This does not notify the friend of their deletion. After calling this | ||
891 | * function, this client will appear offline to the friend and no communication | ||
892 | * can occur between the two. | ||
366 | * | 893 | * |
367 | * Function(Tox *tox, int groupnumber, int friendgroupnumber, uint8_t * message, uint16_t length, void *userdata) | 894 | * @friend_number Friend number for the friend to be deleted. |
895 | * | ||
896 | * @return true on success. | ||
368 | */ | 897 | */ |
369 | void tox_callback_group_message(Tox *tox, void (*function)(Tox *tox, int, int, const uint8_t *, uint16_t, void *), | 898 | bool tox_friend_delete(Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_DELETE *error); |
370 | void *userdata); | 899 | |
371 | 900 | ||
372 | /* Set the callback for group actions. | 901 | /******************************************************************************* |
373 | * | 902 | * |
374 | * Function(Tox *tox, int groupnumber, int friendgroupnumber, uint8_t * action, uint16_t length, void *userdata) | 903 | * :: Friend list queries |
904 | * | ||
905 | ******************************************************************************/ | ||
906 | |||
907 | |||
908 | enum TOX_ERR_FRIEND_BY_PUBLIC_KEY { | ||
909 | TOX_ERR_FRIEND_BY_PUBLIC_KEY_OK, | ||
910 | TOX_ERR_FRIEND_BY_PUBLIC_KEY_NULL, | ||
911 | /** | ||
912 | * No friend with the given Public Key exists on the friend list. | ||
913 | */ | ||
914 | TOX_ERR_FRIEND_BY_PUBLIC_KEY_NOT_FOUND | ||
915 | }; | ||
916 | typedef uint8_t TOX_ERR_FRIEND_BY_PUBLIC_KEY; | ||
917 | |||
918 | /** | ||
919 | * Return the friend number associated with that Public Key. | ||
920 | * | ||
921 | * @return the friend number on success, UINT32_MAX on failure. | ||
922 | * @param public_key A byte array containing the Public Key. | ||
375 | */ | 923 | */ |
376 | void tox_callback_group_action(Tox *tox, void (*function)(Tox *tox, int, int, const uint8_t *, uint16_t, void *), | 924 | uint32_t tox_friend_by_public_key(const Tox *tox, const uint8_t *public_key, TOX_ERR_FRIEND_BY_PUBLIC_KEY *error); |
377 | void *userdata); | 925 | |
926 | |||
927 | enum TOX_ERR_FRIEND_GET_PUBLIC_KEY { | ||
928 | TOX_ERR_FRIEND_GET_PUBLIC_KEY_OK, | ||
929 | TOX_ERR_FRIEND_GET_PUBLIC_KEY_NULL, | ||
930 | /** | ||
931 | * No friend with the given number exists on the friend list. | ||
932 | */ | ||
933 | TOX_ERR_FRIEND_GET_PUBLIC_KEY_FRIEND_NOT_FOUND | ||
934 | }; | ||
935 | typedef uint8_t TOX_ERR_FRIEND_GET_PUBLIC_KEY; | ||
378 | 936 | ||
379 | /* Set callback function for peer name list changes. | 937 | /** |
938 | * Copies the Public Key associated with a given friend number to a byte array. | ||
380 | * | 939 | * |
381 | * It gets called every time the name list changes(new peer/name, deleted peer) | 940 | * @param friend_number The friend number you want the Public Key of. |
382 | * Function(Tox *tox, int groupnumber, int peernumber, TOX_CHAT_CHANGE change, void *userdata) | 941 | * @param public_key A memory region of at least TOX_PUBLIC_KEY_SIZE bytes. If |
942 | * this parameter is NULL, this function has no effect. | ||
943 | * | ||
944 | * @return true on success. | ||
383 | */ | 945 | */ |
384 | typedef enum { | 946 | bool tox_friend_get_public_key(const Tox *tox, uint32_t friend_number, uint8_t *public_key, |
385 | TOX_CHAT_CHANGE_PEER_ADD, | 947 | TOX_ERR_FRIEND_GET_PUBLIC_KEY *error); |
386 | TOX_CHAT_CHANGE_PEER_DEL, | 948 | |
387 | TOX_CHAT_CHANGE_PEER_NAME, | ||
388 | } TOX_CHAT_CHANGE; | ||
389 | 949 | ||
390 | void tox_callback_group_namelist_change(Tox *tox, void (*function)(Tox *tox, int, int, uint8_t, void *), | 950 | /** |
391 | void *userdata); | 951 | * Checks if a friend with the given friend number exists and returns true if |
952 | * it does. | ||
953 | */ | ||
954 | bool tox_friend_exists(const Tox *tox, uint32_t friend_number); | ||
392 | 955 | ||
393 | /* Creates a new groupchat and puts it in the chats array. | 956 | |
957 | /** | ||
958 | * Return the number of friends on the friend list. | ||
394 | * | 959 | * |
395 | * return group number on success. | 960 | * This function can be used to determine how much memory to allocate for |
396 | * return -1 on failure. | 961 | * tox_friend_list. |
397 | */ | 962 | */ |
398 | int tox_add_groupchat(Tox *tox); | 963 | size_t tox_friend_list_size(const Tox *tox); |
964 | |||
399 | 965 | ||
400 | /* Delete a groupchat from the chats array. | 966 | /** |
967 | * Copy a list of valid friend numbers into an array. | ||
401 | * | 968 | * |
402 | * return 0 on success. | 969 | * Call tox_friend_list_size to determine the number of elements to allocate. |
403 | * return -1 if failure. | 970 | * |
971 | * @param list A memory region with enough space to hold the friend list. If | ||
972 | * this parameter is NULL, this function has no effect. | ||
404 | */ | 973 | */ |
405 | int tox_del_groupchat(Tox *tox, int groupnumber); | 974 | void tox_friend_list(const Tox *tox, uint32_t *list); |
975 | |||
406 | 976 | ||
407 | /* Copy the name of peernumber who is in groupnumber to name. | 977 | |
408 | * name must be at least TOX_MAX_NAME_LENGTH long. | 978 | /******************************************************************************* |
979 | * | ||
980 | * :: Friend-specific state queries (can also be received through callbacks) | ||
409 | * | 981 | * |
410 | * return length of name if success | 982 | ******************************************************************************/ |
411 | * return -1 if failure | 983 | |
984 | |||
985 | /** | ||
986 | * Common error codes for friend state query functions. | ||
412 | */ | 987 | */ |
413 | int tox_group_peername(const Tox *tox, int groupnumber, int peernumber, uint8_t *name); | 988 | enum TOX_ERR_FRIEND_QUERY { |
989 | TOX_ERR_FRIEND_QUERY_OK, | ||
990 | /** | ||
991 | * The pointer parameter for storing the query result (name, message) was | ||
992 | * NULL. Unlike the `_self_` variants of these functions, which have no effect | ||
993 | * when a parameter is NULL, these functions return an error in that case. | ||
994 | */ | ||
995 | TOX_ERR_FRIEND_QUERY_NULL, | ||
996 | /** | ||
997 | * The friend_number did not designate a valid friend. | ||
998 | */ | ||
999 | TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND | ||
1000 | }; | ||
1001 | typedef uint8_t TOX_ERR_FRIEND_QUERY; | ||
414 | 1002 | ||
415 | /* invite friendnumber to groupnumber | 1003 | /** |
416 | * return 0 on success | 1004 | * Return the length of the friend's name. If the friend number is invalid, the |
417 | * return -1 on failure | 1005 | * return value is SIZE_MAX. |
1006 | * | ||
1007 | * The return value is equal to the `length` argument received by the last | ||
1008 | * `friend_name` callback. | ||
418 | */ | 1009 | */ |
419 | int tox_invite_friend(Tox *tox, int32_t friendnumber, int groupnumber); | 1010 | size_t tox_friend_get_name_size(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_QUERY *error); |
420 | 1011 | ||
421 | /* Join a group (you need to have been invited first.) | 1012 | /** |
1013 | * Write the name of the friend designated by the given friend number to a byte | ||
1014 | * array. | ||
1015 | * | ||
1016 | * Call tox_friend_get_name_size to determine the allocation size for the `name` | ||
1017 | * parameter. | ||
422 | * | 1018 | * |
423 | * returns group number on success | 1019 | * The data written to `name` is equal to the data received by the last |
424 | * returns -1 on failure. | 1020 | * `friend_name` callback. |
1021 | * | ||
1022 | * @param name A valid memory region large enough to store the friend's name. | ||
1023 | * | ||
1024 | * @return true on success. | ||
425 | */ | 1025 | */ |
426 | int tox_join_groupchat(Tox *tox, int32_t friendnumber, const uint8_t *friend_group_public_key); | 1026 | bool tox_friend_get_name(const Tox *tox, uint32_t friend_number, uint8_t *name, TOX_ERR_FRIEND_QUERY *error); |
427 | 1027 | ||
428 | /* send a group message | 1028 | /** |
429 | * return 0 on success | 1029 | * The function type for the `friend_name` callback. |
430 | * return -1 on failure | 1030 | * |
1031 | * @param friend_number The friend number of the friend whose name changed. | ||
1032 | * @param name A byte array containing the same data as | ||
1033 | * tox_friend_get_name would write to its `name` parameter. | ||
1034 | * @param length A value equal to the return value of | ||
1035 | * tox_friend_get_name_size. | ||
431 | */ | 1036 | */ |
432 | int tox_group_message_send(Tox *tox, int groupnumber, const uint8_t *message, uint32_t length); | 1037 | typedef void tox_friend_name_cb(Tox *tox, uint32_t friend_number, const uint8_t *name, size_t length, void *user_data); |
433 | 1038 | ||
434 | /* send a group action | 1039 | /** |
435 | * return 0 on success | 1040 | * Set the callback for the `friend_name` event. Pass NULL to unset. |
436 | * return -1 on failure | 1041 | * |
1042 | * This event is triggered when a friend changes their name. | ||
437 | */ | 1043 | */ |
438 | int tox_group_action_send(Tox *tox, int groupnumber, const uint8_t *action, uint32_t length); | 1044 | void tox_callback_friend_name(Tox *tox, tox_friend_name_cb *function, void *user_data); |
1045 | |||
439 | 1046 | ||
440 | /* Return the number of peers in the group chat on success. | 1047 | /** |
441 | * return -1 on failure | 1048 | * Return the length of the friend's status message. If the friend number is |
1049 | * invalid, the return value is SIZE_MAX. | ||
442 | */ | 1050 | */ |
443 | int tox_group_number_peers(const Tox *tox, int groupnumber); | 1051 | size_t tox_friend_get_status_message_size(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_QUERY *error); |
444 | 1052 | ||
445 | /* List all the peers in the group chat. | 1053 | /** |
1054 | * Write the name of the friend designated by the given friend number to a byte | ||
1055 | * array. | ||
446 | * | 1056 | * |
447 | * Copies the names of the peers to the name[length][TOX_MAX_NAME_LENGTH] array. | 1057 | * Call tox_friend_get_name_size to determine the allocation size for the `name` |
1058 | * parameter. | ||
448 | * | 1059 | * |
449 | * Copies the lengths of the names to lengths[length] | 1060 | * The data written to `message` is equal to the data received by the last |
1061 | * `friend_status_message` callback. | ||
450 | * | 1062 | * |
451 | * returns the number of peers on success. | 1063 | * @param name A valid memory region large enough to store the friend's name. |
1064 | */ | ||
1065 | bool tox_friend_get_status_message(const Tox *tox, uint32_t friend_number, uint8_t *message, | ||
1066 | TOX_ERR_FRIEND_QUERY *error); | ||
1067 | |||
1068 | /** | ||
1069 | * The function type for the `friend_status_message` callback. | ||
1070 | * | ||
1071 | * @param friend_number The friend number of the friend whose status message | ||
1072 | * changed. | ||
1073 | * @param message A byte array containing the same data as | ||
1074 | * tox_friend_get_status_message would write to its `message` parameter. | ||
1075 | * @param length A value equal to the return value of | ||
1076 | * tox_friend_get_status_message_size. | ||
1077 | */ | ||
1078 | typedef void tox_friend_status_message_cb(Tox *tox, uint32_t friend_number, const uint8_t *message, size_t length, | ||
1079 | void *user_data); | ||
1080 | |||
1081 | /** | ||
1082 | * Set the callback for the `friend_status_message` event. Pass NULL to unset. | ||
452 | * | 1083 | * |
453 | * return -1 on failure. | 1084 | * This event is triggered when a friend changes their name. |
454 | */ | 1085 | */ |
455 | int tox_group_get_names(const Tox *tox, int groupnumber, uint8_t names[][TOX_MAX_NAME_LENGTH], uint16_t lengths[], | 1086 | void tox_callback_friend_status_message(Tox *tox, tox_friend_status_message_cb *function, void *user_data); |
456 | uint16_t length); | ||
457 | 1087 | ||
458 | /* Return the number of chats in the instance m. | ||
459 | * You should use this to determine how much memory to allocate | ||
460 | * for copy_chatlist. */ | ||
461 | uint32_t tox_count_chatlist(const Tox *tox); | ||
462 | 1088 | ||
463 | /* Copy a list of valid chat IDs into the array out_list. | 1089 | /** |
464 | * If out_list is NULL, returns 0. | 1090 | * Return the friend's user status (away/busy/...). If the friend number is |
465 | * Otherwise, returns the number of elements copied. | 1091 | * invalid, the return value is unspecified. |
466 | * If the array was too small, the contents | 1092 | * |
467 | * of out_list will be truncated to list_size. */ | 1093 | * The status returned is equal to the last status received through the |
468 | uint32_t tox_get_chatlist(const Tox *tox, int *out_list, uint32_t list_size); | 1094 | * `friend_status` callback. |
1095 | */ | ||
1096 | TOX_STATUS tox_friend_get_status(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_QUERY *error); | ||
469 | 1097 | ||
1098 | /** | ||
1099 | * The function type for the `friend_status` callback. | ||
1100 | * | ||
1101 | * @param friend_number The friend number of the friend whose user status | ||
1102 | * changed. | ||
1103 | * @param status The new user status. | ||
1104 | */ | ||
1105 | typedef void tox_friend_status_cb(Tox *tox, uint32_t friend_number, TOX_STATUS status, void *user_data); | ||
470 | 1106 | ||
471 | /****************FILE SENDING FUNCTIONS*****************/ | 1107 | /** |
472 | /* NOTE: This how to will be updated. | 1108 | * Set the callback for the `friend_status` event. Pass NULL to unset. |
473 | * | 1109 | * |
474 | * HOW TO SEND FILES CORRECTLY: | 1110 | * This event is triggered when a friend changes their user status. |
475 | * 1. Use tox_new_file_sender(...) to create a new file sender. | 1111 | */ |
476 | * 2. Wait for the callback set with tox_callback_file_control(...) to be called with receive_send == 1 and control_type == TOX_FILECONTROL_ACCEPT | 1112 | void tox_callback_friend_status(Tox *tox, tox_friend_status_cb *function, void *user_data); |
477 | * 3. Send the data with tox_file_send_data(...) with chunk size tox_file_data_size(...) | 1113 | |
478 | * 4. When sending is done, send a tox_file_send_control(...) with send_receive = 0 and message_id = TOX_FILECONTROL_FINISHED | 1114 | |
479 | * 5. when the callback set with tox_callback_file_control(...) is called with receive_send == 1 and control_type == TOX_FILECONTROL_FINISHED | 1115 | /** |
480 | * the other person has received the file correctly. | 1116 | * Check whether a friend is currently connected to this client. |
481 | * | 1117 | * |
482 | * HOW TO RECEIVE FILES CORRECTLY: | 1118 | * The result of this function is equal to the last value received by the |
483 | * 1. wait for the callback set with tox_callback_file_send_request(...) | 1119 | * `friend_connection_status` callback. |
484 | * 2. accept or refuse the connection with tox_file_send_control(...) with send_receive = 1 and message_id = TOX_FILECONTROL_ACCEPT or TOX_FILECONTROL_KILL | ||
485 | * 3. save all the data received with the callback set with tox_callback_file_data(...) to a file. | ||
486 | * 4. when the callback set with tox_callback_file_control(...) is called with receive_send == 0 and control_type == TOX_FILECONTROL_FINISHED | ||
487 | * the file is done transferring. | ||
488 | * 5. send a tox_file_send_control(...) with send_receive = 1 and message_id = TOX_FILECONTROL_FINISHED to confirm that we did receive the file. | ||
489 | * | 1120 | * |
490 | * tox_file_data_remaining(...) can be used to know how many bytes are left to send/receive. | 1121 | * @param friend_number The friend number for which to query the connection |
1122 | * status. | ||
491 | * | 1123 | * |
492 | * If the connection breaks during file sending (The other person goes offline without pausing the sending and then comes back) | 1124 | * @return the friend's connection status as it was received through the |
493 | * the receiver must send a control packet with send_receive == 1 message_id = TOX_FILECONTROL_RESUME_BROKEN and the data being | 1125 | * `friend_connection_status` event. |
494 | * a uint64_t (in host byte order) containing the number of bytes received. | 1126 | */ |
1127 | TOX_CONNECTION tox_friend_get_connection_status(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_QUERY *error); | ||
1128 | |||
1129 | /** | ||
1130 | * The function type for the `friend_connection_status` callback. | ||
495 | * | 1131 | * |
496 | * If the sender receives this packet, he must send a control packet with send_receive == 0 and control_type == TOX_FILECONTROL_ACCEPT | 1132 | * @param friend_number The friend number of the friend whose connection status |
497 | * then he must start sending file data from the position (data , uint64_t in host byte order) received in the TOX_FILECONTROL_RESUME_BROKEN packet. | 1133 | * changed. |
1134 | * @param connection_status The result of calling | ||
1135 | * tox_friend_get_connection_status on the passed friend_number. | ||
1136 | */ | ||
1137 | typedef void tox_friend_connection_status_cb(Tox *tox, uint32_t friend_number, TOX_CONNECTION connection_status, | ||
1138 | void *user_data); | ||
1139 | |||
1140 | /** | ||
1141 | * Set the callback for the `friend_connection_status` event. Pass NULL to | ||
1142 | * unset. | ||
1143 | * | ||
1144 | * This event is triggered when a friend goes offline after having been online, | ||
1145 | * or when a friend goes online. | ||
1146 | * | ||
1147 | * This callback is not called when adding friends. It is assumed that when | ||
1148 | * adding friends, their connection status is offline. | ||
1149 | */ | ||
1150 | void tox_callback_friend_connection_status(Tox *tox, tox_friend_connection_status_cb *function, void *user_data); | ||
1151 | |||
1152 | |||
1153 | /** | ||
1154 | * Check whether a friend is currently typing a message. | ||
498 | * | 1155 | * |
499 | * To pause a file transfer send a control packet with control_type == TOX_FILECONTROL_PAUSE. | 1156 | * @param friend_number The friend number for which to query the typing status. |
500 | * To unpause a file transfer send a control packet with control_type == TOX_FILECONTROL_ACCEPT. | ||
501 | * | 1157 | * |
502 | * If you receive a control packet with receive_send == 1 and control_type == TOX_FILECONTROL_PAUSE, you must stop sending filenumber until the other | 1158 | * @return true if the friend is typing. |
503 | * person sends a control packet with send_receive == 0 and control_type == TOX_FILECONTROL_ACCEPT with the filenumber being a paused filenumber. | 1159 | * @return false if the friend is not typing, or the friend number was |
1160 | * invalid. Inspect the error code to determine which case it is. | ||
1161 | */ | ||
1162 | bool tox_friend_get_typing(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_QUERY *error); | ||
1163 | |||
1164 | /** | ||
1165 | * The function type for the `friend_typing` callback. | ||
504 | * | 1166 | * |
505 | * If you receive a control packet with receive_send == 0 and control_type == TOX_FILECONTROL_PAUSE, it means the sender of filenumber has paused the | 1167 | * @param friend_number The friend number of the friend who started or stopped |
506 | * transfer and will resume it later with a control packet with send_receive == 1 and control_type == TOX_FILECONTROL_ACCEPT for that file number. | 1168 | * typing. |
1169 | * @param is_typing The result of calling tox_friend_get_typing on the passed | ||
1170 | * friend_number. | ||
1171 | */ | ||
1172 | typedef void tox_friend_typing_cb(Tox *tox, uint32_t friend_number, bool is_typing, void *user_data); | ||
1173 | |||
1174 | /** | ||
1175 | * Set the callback for the `friend_typing` event. Pass NULL to unset. | ||
507 | * | 1176 | * |
508 | * More to come... | 1177 | * This event is triggered when a friend starts or stops typing. |
509 | */ | 1178 | */ |
1179 | void tox_callback_friend_typing(Tox *tox, tox_friend_typing_cb *function, void *user_data); | ||
1180 | |||
1181 | |||
1182 | /******************************************************************************* | ||
1183 | * | ||
1184 | * :: Sending private messages | ||
1185 | * | ||
1186 | ******************************************************************************/ | ||
510 | 1187 | ||
511 | enum { | 1188 | |
512 | TOX_FILECONTROL_ACCEPT, | 1189 | enum TOX_ERR_SET_TYPING { |
513 | TOX_FILECONTROL_PAUSE, | 1190 | TOX_ERR_SET_TYPING_OK, |
514 | TOX_FILECONTROL_KILL, | 1191 | /** |
515 | TOX_FILECONTROL_FINISHED, | 1192 | * The friend number did not designate a valid friend. |
516 | TOX_FILECONTROL_RESUME_BROKEN | 1193 | */ |
1194 | TOX_ERR_SET_TYPING_FRIEND_NOT_FOUND | ||
517 | }; | 1195 | }; |
518 | /* Set the callback for file send requests. | 1196 | typedef uint8_t TOX_ERR_SET_TYPING; |
1197 | |||
1198 | /** | ||
1199 | * Set the client's typing status for a friend. | ||
1200 | * | ||
1201 | * The client is responsible for turning it on or off. | ||
519 | * | 1202 | * |
520 | * Function(Tox *tox, int32_t friendnumber, uint8_t filenumber, uint64_t filesize, uint8_t *filename, uint16_t filename_length, void *userdata) | 1203 | * @param friend_number The friend to which the client is typing a message. |
1204 | * @param is_typing The typing status. True means the client is typing. | ||
1205 | * | ||
1206 | * @return true on success. | ||
521 | */ | 1207 | */ |
522 | void tox_callback_file_send_request(Tox *tox, void (*function)(Tox *m, int32_t, uint8_t, uint64_t, const uint8_t *, | 1208 | bool tox_self_set_typing(Tox *tox, uint32_t friend_number, bool is_typing, TOX_ERR_SET_TYPING *error); |
523 | uint16_t, void *), void *userdata); | 1209 | |
1210 | |||
1211 | enum TOX_ERR_SEND_MESSAGE { | ||
1212 | TOX_ERR_SEND_MESSAGE_OK, | ||
1213 | TOX_ERR_SEND_MESSAGE_NULL, | ||
1214 | /** | ||
1215 | * The friend number did not designate a valid friend. | ||
1216 | */ | ||
1217 | TOX_ERR_SEND_MESSAGE_FRIEND_NOT_FOUND, | ||
1218 | /** | ||
1219 | * This client is currently not connected to the friend. | ||
1220 | */ | ||
1221 | TOX_ERR_SEND_MESSAGE_FRIEND_NOT_CONNECTED, | ||
1222 | /** | ||
1223 | * An allocation error occurred while increasing the send queue size. | ||
1224 | */ | ||
1225 | TOX_ERR_SEND_MESSAGE_SENDQ, | ||
1226 | /** | ||
1227 | * Message length exceeded TOX_MAX_MESSAGE_LENGTH. | ||
1228 | */ | ||
1229 | TOX_ERR_SEND_MESSAGE_TOO_LONG, | ||
1230 | /** | ||
1231 | * Attempted to send a zero-length message. | ||
1232 | */ | ||
1233 | TOX_ERR_SEND_MESSAGE_EMPTY | ||
1234 | }; | ||
1235 | typedef uint8_t TOX_ERR_SEND_MESSAGE; | ||
524 | 1236 | ||
525 | /* Set the callback for file control requests. | 1237 | /** |
1238 | * Send a text chat message to an online friend. | ||
526 | * | 1239 | * |
527 | * receive_send is 1 if the message is for a slot on which we are currently sending a file and 0 if the message | 1240 | * This function creates a chat message packet and pushes it into the send |
528 | * is for a slot on which we are receiving the file | 1241 | * queue. |
529 | * | 1242 | * |
530 | * Function(Tox *tox, int32_t friendnumber, uint8_t receive_send, uint8_t filenumber, uint8_t control_type, uint8_t *data, uint16_t length, void *userdata) | 1243 | * The message length may not exceed TOX_MAX_MESSAGE_LENGTH. Larger messages |
1244 | * must be split by the client and sent as separate messages. Other clients can | ||
1245 | * then reassemble the fragments. Messages may not be empty. | ||
1246 | * | ||
1247 | * The return value of this function is the message ID. If a read receipt is | ||
1248 | * received, the triggered `read_receipt` event will be passed this message ID. | ||
1249 | * | ||
1250 | * Message IDs are unique per friend. The first message ID is 0. Message IDs are | ||
1251 | * incremented by 1 each time a message is sent. If UINT32_MAX messages were | ||
1252 | * sent, the next message ID is 0. | ||
1253 | */ | ||
1254 | uint32_t tox_send_message(Tox *tox, uint32_t friend_number, const uint8_t *message, size_t length, | ||
1255 | TOX_ERR_SEND_MESSAGE *error); | ||
1256 | |||
1257 | |||
1258 | /** | ||
1259 | * Send an action to an online friend. | ||
1260 | * | ||
1261 | * This is similar to /me (CTCP ACTION) on IRC. | ||
1262 | * | ||
1263 | * Message ID space is shared between tox_send_message and tox_send_action. This | ||
1264 | * means that sending a message will cause the next message ID from sending an | ||
1265 | * action will be incremented. | ||
1266 | * | ||
1267 | * @see tox_send_message for more details. | ||
1268 | */ | ||
1269 | uint32_t tox_send_action(Tox *tox, uint32_t friend_number, const uint8_t *action, size_t length, | ||
1270 | TOX_ERR_SEND_MESSAGE *error); | ||
1271 | |||
1272 | |||
1273 | /** | ||
1274 | * The function type for the `read_receipt` callback. | ||
1275 | * | ||
1276 | * @param friend_number The friend number of the friend who received the message. | ||
1277 | * @param message_id The message ID as returned from tox_send_message or | ||
1278 | * tox_send_action corresponding to the message sent. | ||
1279 | */ | ||
1280 | typedef void tox_read_receipt_cb(Tox *tox, uint32_t friend_number, uint32_t message_id, void *user_data); | ||
1281 | |||
1282 | /** | ||
1283 | * Set the callback for the `read_receipt` event. Pass NULL to unset. | ||
1284 | * | ||
1285 | * This event is triggered when a read receipt is received from a friend. This | ||
1286 | * normally means that the message has been received by the friend, however a | ||
1287 | * friend can send a read receipt with any message ID in it, so the number | ||
1288 | * received here may not correspond to any message sent through tox_send_message | ||
1289 | * or tox_send_action. In that case, the receipt should be discarded. | ||
1290 | */ | ||
1291 | void tox_callback_read_receipt(Tox *tox, tox_read_receipt_cb *function, void *user_data); | ||
1292 | |||
1293 | |||
1294 | /******************************************************************************* | ||
1295 | * | ||
1296 | * :: Receiving private messages and friend requests | ||
1297 | * | ||
1298 | ******************************************************************************/ | ||
1299 | |||
1300 | |||
1301 | /** | ||
1302 | * The function type for the `friend_request` callback. | ||
1303 | * | ||
1304 | * @param public_key The Public Key of the user who sent the friend request. | ||
1305 | * @param time_delta A delta in seconds between when the message was composed | ||
1306 | * and when it is being transmitted. For messages that are sent immediately, | ||
1307 | * it will be 0. If a message was written and couldn't be sent immediately | ||
1308 | * (due to a connection failure, for example), the time_delta is an | ||
1309 | * approximation of when it was composed. | ||
1310 | * @param message The message they sent along with the request. | ||
1311 | * @param length The size of the message byte array. | ||
1312 | */ | ||
1313 | typedef void tox_friend_request_cb(Tox *tox, const uint8_t *public_key, /*uint32_t time_delta, */const uint8_t *message, | ||
1314 | size_t length, void *user_data); | ||
1315 | |||
1316 | /** | ||
1317 | * Set the callback for the `friend_request` event. Pass NULL to unset. | ||
1318 | * | ||
1319 | * This event is triggered when a friend request is received. | ||
1320 | */ | ||
1321 | void tox_callback_friend_request(Tox *tox, tox_friend_request_cb *function, void *user_data); | ||
1322 | |||
1323 | |||
1324 | /** | ||
1325 | * The function type for the `friend_message` callback. | ||
1326 | * | ||
1327 | * @param friend_number The friend number of the friend who sent the message. | ||
1328 | * @param time_delta Time between composition and sending. | ||
1329 | * @param message The message data they sent. | ||
1330 | * @param length The size of the message byte array. | ||
1331 | * | ||
1332 | * @see tox_friend_request_cb for more information on time_delta. | ||
1333 | */ | ||
1334 | typedef void tox_friend_message_cb(Tox *tox, uint32_t friend_number, /*uint32_t time_delta, */const uint8_t *message, | ||
1335 | size_t length, void *user_data); | ||
1336 | |||
1337 | /** | ||
1338 | * Set the callback for the `friend_message` event. Pass NULL to unset. | ||
531 | * | 1339 | * |
1340 | * This event is triggered when a message from a friend is received. | ||
532 | */ | 1341 | */ |
533 | void tox_callback_file_control(Tox *tox, void (*function)(Tox *m, int32_t, uint8_t, uint8_t, uint8_t, const uint8_t *, | 1342 | void tox_callback_friend_message(Tox *tox, tox_friend_message_cb *function, void *user_data); |
534 | uint16_t, void *), void *userdata); | 1343 | |
535 | 1344 | ||
536 | /* Set the callback for file data. | 1345 | /** |
1346 | * The function type for the `friend_action` callback. | ||
537 | * | 1347 | * |
538 | * Function(Tox *tox, int32_t friendnumber, uint8_t filenumber, uint8_t *data, uint16_t length, void *userdata) | 1348 | * @param friend_number The friend number of the friend who sent the action. |
1349 | * @param time_delta Time between composition and sending. | ||
1350 | * @param action The action message data they sent. | ||
1351 | * @param length The size of the action byte array. | ||
539 | * | 1352 | * |
1353 | * @see tox_friend_request_cb for more information on time_delta. | ||
540 | */ | 1354 | */ |
541 | void tox_callback_file_data(Tox *tox, void (*function)(Tox *m, int32_t, uint8_t, const uint8_t *, uint16_t length, | 1355 | typedef void tox_friend_action_cb(Tox *tox, uint32_t friend_number, /*uint32_t time_delta, */const uint8_t *action, |
542 | void *), void *userdata); | 1356 | size_t length, void *user_data); |
543 | 1357 | ||
1358 | /** | ||
1359 | * Set the callback for the `friend_action` event. Pass NULL to unset. | ||
1360 | * | ||
1361 | * This event is triggered when an action from a friend is received. | ||
1362 | */ | ||
1363 | void tox_callback_friend_action(Tox *tox, tox_friend_action_cb *function, void *user_data); | ||
1364 | |||
1365 | |||
1366 | |||
1367 | /******************************************************************************* | ||
1368 | * | ||
1369 | * :: File transmission: common between sending and receiving | ||
1370 | * | ||
1371 | ******************************************************************************/ | ||
1372 | |||
1373 | |||
1374 | enum TOX_FILE_KIND { | ||
1375 | /** | ||
1376 | * Arbitrary file data. Clients can choose to handle it based on the file name | ||
1377 | * or magic or any other way they choose. | ||
1378 | */ | ||
1379 | TOX_FILE_KIND_DATA, | ||
1380 | /** | ||
1381 | * Avatar data. This consists of tox_hash(image) + image. | ||
1382 | * | ||
1383 | * Avatars can be sent at any time the client wishes. Generally, a client will | ||
1384 | * send the avatar to a friend when that friend comes online, and to all | ||
1385 | * friends when the avatar changed. A client can save some traffic by | ||
1386 | * remembering which friend received the updated avatar already and only send | ||
1387 | * it if the friend has an out of date avatar. | ||
1388 | * | ||
1389 | * Clients who receive avatar send requests can reject it (by sending | ||
1390 | * TOX_FILE_CONTROL_CANCEL before any other controls), or accept it (by | ||
1391 | * sending TOX_FILE_CONTROL_RESUME). The first chunk will contain the hash in | ||
1392 | * its first TOX_HASH_LENGTH bytes. A client can compare this hash with a | ||
1393 | * saved hash and send TOX_FILE_CONTROL_CANCEL to terminate the avatar | ||
1394 | * transfer if it matches. | ||
1395 | */ | ||
1396 | TOX_FILE_KIND_AVATAR | ||
1397 | }; | ||
1398 | typedef uint8_t TOX_FILE_KIND; | ||
544 | 1399 | ||
545 | /* Send a file send request. | 1400 | /** |
546 | * Maximum filename length is 255 bytes. | 1401 | * Generates a cryptographic hash of the given data. |
547 | * return file number on success | 1402 | * |
548 | * return -1 on failure | 1403 | * This function may be used by clients for any purpose, but is provided |
1404 | * primarily for validating cached avatars. This use is highly recommended to | ||
1405 | * avoid unnecessary avatar updates. | ||
1406 | * | ||
1407 | * If length is zero or data is NULL, the hash will contain all zero. If hash is | ||
1408 | * NULL, the function returns false, otherwise it returns true. | ||
1409 | * | ||
1410 | * This function is a wrapper to internal message-digest functions. | ||
1411 | * | ||
1412 | * @param hash A valid memory location the hash data. It must be at least | ||
1413 | * TOX_HASH_LENGTH bytes in size. | ||
1414 | * @param data Data to be hashed or NULL. | ||
1415 | * @param length Size of the data array or 0. | ||
1416 | * | ||
1417 | * @return true if hash was not NULL. | ||
549 | */ | 1418 | */ |
550 | int tox_new_file_sender(Tox *tox, int32_t friendnumber, uint64_t filesize, const uint8_t *filename, | 1419 | bool tox_hash(uint8_t *hash, const uint8_t *data, size_t length); |
551 | uint16_t filename_length); | 1420 | |
1421 | |||
1422 | enum TOX_FILE_CONTROL { | ||
1423 | /** | ||
1424 | * Sent by the receiving side to accept a file send request. Also sent after a | ||
1425 | * TOX_FILE_CONTROL_PAUSE command to continue sending or receiving. | ||
1426 | */ | ||
1427 | TOX_FILE_CONTROL_RESUME, | ||
1428 | /** | ||
1429 | * Sent by clients to pause the file transfer. The initial state of a file | ||
1430 | * transfer is always paused on the receiving side and running on the sending | ||
1431 | * side. If both the sending and receiving side pause the transfer, then both | ||
1432 | * need to send TOX_FILE_CONTROL_RESUME for the transfer to resume. | ||
1433 | */ | ||
1434 | TOX_FILE_CONTROL_PAUSE, | ||
1435 | /** | ||
1436 | * Sent by the receiving side to reject a file send request before any other | ||
1437 | * commands are sent. Also sent by either side to terminate a file transfer. | ||
1438 | */ | ||
1439 | TOX_FILE_CONTROL_CANCEL | ||
1440 | }; | ||
1441 | typedef uint8_t TOX_FILE_CONTROL; | ||
1442 | |||
1443 | enum TOX_ERR_FILE_CONTROL { | ||
1444 | TOX_ERR_FILE_CONTROL_OK, | ||
1445 | /** | ||
1446 | * The friend_number passed did not designate a valid friend. | ||
1447 | */ | ||
1448 | TOX_ERR_FILE_CONTROL_FRIEND_NOT_FOUND, | ||
1449 | /** | ||
1450 | * This client is currently not connected to the friend. | ||
1451 | */ | ||
1452 | TOX_ERR_FILE_CONTROL_FRIEND_NOT_CONNECTED, | ||
1453 | /** | ||
1454 | * No file transfer with the given file number was found for the given friend. | ||
1455 | */ | ||
1456 | TOX_ERR_FILE_CONTROL_NOT_FOUND, | ||
1457 | /** | ||
1458 | * A RESUME control was sent, but the file transfer is running normally. | ||
1459 | */ | ||
1460 | TOX_ERR_FILE_CONTROL_NOT_PAUSED, | ||
1461 | /** | ||
1462 | * A RESUME control was sent, but the file transfer was paused by the other | ||
1463 | * party. Only the party that paused the transfer can resume it. | ||
1464 | */ | ||
1465 | TOX_ERR_FILE_CONTROL_DENIED, | ||
1466 | /** | ||
1467 | * A PAUSE control was sent, but the file transfer was already paused. | ||
1468 | */ | ||
1469 | TOX_ERR_FILE_CONTROL_ALREADY_PAUSED | ||
1470 | }; | ||
1471 | typedef uint8_t TOX_ERR_FILE_CONTROL; | ||
552 | 1472 | ||
553 | /* Send a file control request. | 1473 | /** |
1474 | * Sends a file control command to a friend for a given file transfer. | ||
554 | * | 1475 | * |
555 | * send_receive is 0 if we want the control packet to target a file we are currently sending, | 1476 | * @param friend_number The friend number of the friend the file is being |
556 | * 1 if it targets a file we are currently receiving. | 1477 | * transferred to. |
1478 | * @param file_number The friend-specific identifier for the file transfer. | ||
1479 | * @param control The control command to send. | ||
557 | * | 1480 | * |
558 | * return 0 on success | 1481 | * @return true on success. |
559 | * return -1 on failure | ||
560 | */ | 1482 | */ |
561 | int tox_file_send_control(Tox *tox, int32_t friendnumber, uint8_t send_receive, uint8_t filenumber, uint8_t message_id, | 1483 | bool tox_file_control(Tox *tox, uint32_t friend_number, uint32_t file_number, TOX_FILE_CONTROL control, |
562 | const uint8_t *data, uint16_t length); | 1484 | TOX_ERR_FILE_CONTROL *error); |
1485 | |||
563 | 1486 | ||
564 | /* Send file data. | 1487 | /** |
1488 | * The function type for the `file_control` callback. | ||
565 | * | 1489 | * |
566 | * return 0 on success | 1490 | * When receiving TOX_FILE_CONTROL_CANCEL, the client should release the |
567 | * return -1 on failure | 1491 | * resources associated with the file number and consider the transfer failed. |
1492 | * | ||
1493 | * @param friend_number The friend number of the friend who is sending the file. | ||
1494 | * @param file_number The friend-specific file number the data received is | ||
1495 | * associated with. | ||
1496 | * @param control The file control command received. | ||
568 | */ | 1497 | */ |
569 | int tox_file_send_data(Tox *tox, int32_t friendnumber, uint8_t filenumber, const uint8_t *data, uint16_t length); | 1498 | typedef void tox_file_control_cb(Tox *tox, uint32_t friend_number, uint32_t file_number, TOX_FILE_CONTROL control, |
1499 | void *user_data); | ||
570 | 1500 | ||
571 | /* Returns the recommended/maximum size of the filedata you send with tox_file_send_data() | 1501 | /** |
1502 | * Set the callback for the `file_control` event. Pass NULL to unset. | ||
572 | * | 1503 | * |
573 | * return size on success | 1504 | * This event is triggered when a file control command is received from a |
574 | * return -1 on failure (currently will never return -1) | 1505 | * friend. |
575 | */ | 1506 | */ |
576 | int tox_file_data_size(const Tox *tox, int32_t friendnumber); | 1507 | void tox_callback_file_control(Tox *tox, tox_file_control_cb *function, void *user_data); |
1508 | |||
1509 | |||
1510 | /******************************************************************************* | ||
1511 | * | ||
1512 | * :: File transmission: sending | ||
1513 | * | ||
1514 | ******************************************************************************/ | ||
1515 | |||
1516 | |||
1517 | enum TOX_ERR_FILE_SEND { | ||
1518 | TOX_ERR_FILE_SEND_OK, | ||
1519 | TOX_ERR_FILE_SEND_NULL, | ||
1520 | /** | ||
1521 | * The friend_number passed did not designate a valid friend. | ||
1522 | */ | ||
1523 | TOX_ERR_FILE_SEND_FRIEND_NOT_FOUND, | ||
1524 | /** | ||
1525 | * This client is currently not connected to the friend. | ||
1526 | */ | ||
1527 | TOX_ERR_FILE_SEND_FRIEND_NOT_CONNECTED, | ||
1528 | /** | ||
1529 | * Filename length was 0. | ||
1530 | */ | ||
1531 | TOX_ERR_FILE_SEND_NAME_EMPTY, | ||
1532 | /** | ||
1533 | * Filename length exceeded 255 bytes. | ||
1534 | */ | ||
1535 | TOX_ERR_FILE_SEND_NAME_TOO_LONG, | ||
1536 | /** | ||
1537 | * Too many ongoing transfers. The maximum number of concurrent file transfers | ||
1538 | * is 256 per friend per direction (sending and receiving). | ||
1539 | */ | ||
1540 | TOX_ERR_FILE_SEND_TOO_MANY | ||
1541 | }; | ||
1542 | typedef uint8_t TOX_ERR_FILE_SEND; | ||
1543 | |||
1544 | /** | ||
1545 | * Send a file transmission request. | ||
1546 | * | ||
1547 | * Maximum filename length is 255 bytes. The filename should generally just be | ||
1548 | * a file name, not a path with directory names. | ||
1549 | * | ||
1550 | * If a non-zero file size is provided, this can be used by both sides to | ||
1551 | * determine the sending progress. File size can be set to zero for streaming | ||
1552 | * data of unknown size. | ||
1553 | * | ||
1554 | * File transmission occurs in chunks, which are requested through the | ||
1555 | * `file_request_chunk` event. | ||
1556 | * | ||
1557 | * File numbers are stable across tox_save/tox_load cycles, so that file | ||
1558 | * transfers can be resumed when a client restarts. The client needs to | ||
1559 | * associate (friend Public Key, file number) with the local path of the file and | ||
1560 | * persist this information to support resuming of transfers across restarts. | ||
1561 | * | ||
1562 | * If the file contents change during a transfer, the behaviour is unspecified | ||
1563 | * in general. What will actually happen depends on the mode in which the file | ||
1564 | * was modified and how the client determines the file size. | ||
1565 | * | ||
1566 | * - If the file size was increased | ||
1567 | * - and sending mode was streaming (file_size = 0), the behaviour will be as | ||
1568 | * expected. | ||
1569 | * - and sending mode was file (file_size != 0), the file_request_chunk | ||
1570 | * callback will receive length = 0 when Core thinks the file transfer has | ||
1571 | * finished. If the client remembers the file size as it was when sending | ||
1572 | * the request, it will terminate the transfer normally. If the client | ||
1573 | * re-reads the size, it will think the friend cancelled the transfer. | ||
1574 | * - If the file size was decreased | ||
1575 | * - and sending mode was streaming, the behaviour is as expected. | ||
1576 | * - and sending mode was file, the callback will return 0 at the new | ||
1577 | * (earlier) end-of-file, signalling to the friend that the transfer was | ||
1578 | * cancelled. | ||
1579 | * - If the file contents were modified | ||
1580 | * - at a position before the current read, the two files (local and remote) | ||
1581 | * will differ after the transfer terminates. | ||
1582 | * - at a position after the current read, the file transfer will succeed as | ||
1583 | * expected. | ||
1584 | * - In either case, both sides will regard the transfer as complete and | ||
1585 | * successful. | ||
1586 | * | ||
1587 | * @param friend_number The friend number of the friend the file send request | ||
1588 | * should be sent to. | ||
1589 | * @param kind The meaning of the file to be sent. | ||
1590 | * @param file_size Size in bytes of the file the client wants to send, 0 if | ||
1591 | * unknown or streaming. | ||
1592 | * @param filename Name of the file. Does not need to be the actual name. This | ||
1593 | * name will be sent along with the file send request. | ||
1594 | * @param filename_length Size in bytes of the filename. | ||
1595 | * | ||
1596 | * @return A file number used as an identifier in subsequent callbacks. This | ||
1597 | * number is per friend. File numbers are reused after a transfer terminates. | ||
1598 | */ | ||
1599 | uint32_t tox_file_send(Tox *tox, uint32_t friend_number, TOX_FILE_KIND kind, uint64_t file_size, | ||
1600 | const uint8_t *filename, size_t filename_length, TOX_ERR_FILE_SEND *error); | ||
1601 | |||
1602 | |||
1603 | enum TOX_ERR_FILE_SEND_CHUNK { | ||
1604 | TOX_ERR_FILE_SEND_CHUNK_OK, | ||
1605 | /** | ||
1606 | * The length parameter was non-zero, but data was NULL. | ||
1607 | */ | ||
1608 | TOX_ERR_FILE_SEND_CHUNK_NULL, | ||
1609 | /** | ||
1610 | * The friend_number passed did not designate a valid friend. | ||
1611 | */ | ||
1612 | TOX_ERR_FILE_SEND_CHUNK_FRIEND_NOT_FOUND, | ||
1613 | /** | ||
1614 | * This client is currently not connected to the friend. | ||
1615 | */ | ||
1616 | TOX_ERR_FILE_SEND_CHUNK_FRIEND_NOT_CONNECTED, | ||
1617 | /** | ||
1618 | * No file transfer with the given file number was found for the given friend. | ||
1619 | */ | ||
1620 | TOX_ERR_FILE_SEND_CHUNK_NOT_FOUND, | ||
1621 | /** | ||
1622 | * Attempted to send more data than requested. The requested data size is | ||
1623 | * adjusted according to maximum transmission unit and the expected end of | ||
1624 | * the file. Trying to send more will result in no data being sent. | ||
1625 | */ | ||
1626 | TOX_ERR_FILE_SEND_CHUNK_TOO_LARGE | ||
1627 | }; | ||
1628 | typedef uint8_t TOX_ERR_FILE_SEND_CHUNK; | ||
577 | 1629 | ||
578 | /* Give the number of bytes left to be sent/received. | 1630 | /** |
1631 | * Send a chunk of file data to a friend. | ||
579 | * | 1632 | * |
580 | * send_receive is 0 if we want the sending files, 1 if we want the receiving. | 1633 | * This function is called in response to the `file_request_chunk` callback. The |
1634 | * length parameter should be equal to or less than the one received though the | ||
1635 | * callback. If it is zero, the transfer is assumed complete. For files with | ||
1636 | * known size, Core will know that the transfer is complete after the last byte | ||
1637 | * has been received, so it is not necessary (though not harmful) to send a | ||
1638 | * zero-length chunk to terminate. For streams, it is necessary for the last | ||
1639 | * chunk sent to be zero-length. | ||
581 | * | 1640 | * |
582 | * return number of bytes remaining to be sent/received on success | 1641 | * @return true on success. |
583 | * return 0 on failure | ||
584 | */ | 1642 | */ |
585 | uint64_t tox_file_data_remaining(const Tox *tox, int32_t friendnumber, uint8_t filenumber, uint8_t send_receive); | 1643 | bool tox_file_send_chunk(Tox *tox, uint32_t friend_number, uint32_t file_number, const uint8_t *data, size_t length, |
1644 | TOX_ERR_FILE_SEND_CHUNK *error); | ||
1645 | |||
1646 | |||
1647 | /** | ||
1648 | * The function type for the `file_request_chunk` callback. | ||
1649 | * | ||
1650 | * If the length parameter is 0, the file transfer is finished, and the client's | ||
1651 | * resources associated with the file number should be released. After a call | ||
1652 | * with zero length, the file number can be reused for future file transfers. | ||
1653 | * | ||
1654 | * If the requested position is not equal to the client's idea of the current | ||
1655 | * file or stream position, it will need to seek. In case of read-once streams, | ||
1656 | * the client should keep the last read chunk so that a seek back can be | ||
1657 | * supported. A seek-back only ever needs to read from the last requested chunk. | ||
1658 | * This happens when a chunk was requested, but the send failed. A seek-back | ||
1659 | * request can occur an arbitrary number of times for any given chunk. | ||
1660 | * | ||
1661 | * In response to receiving this callback, the client should call the function | ||
1662 | * `tox_file_send_chunk` with the requested chunk. If the number of bytes sent | ||
1663 | * through that function is zero, the file transfer is assumed complete. A | ||
1664 | * client may choose to send less than requested, if it is reading from a | ||
1665 | * stream that doesn't have more data, yet, and it still wants to send some | ||
1666 | * data to the other side. However, this will generally be less efficient than | ||
1667 | * waiting for a full chunk size of data to be ready. | ||
1668 | * | ||
1669 | * @param friend_number The friend number of the receiving friend for this file. | ||
1670 | * @param file_number The file transfer identifier returned by tox_file_send. | ||
1671 | * @param position The file or stream position from which to continue reading. | ||
1672 | * @param length The number of bytes requested for the current chunk. | ||
1673 | */ | ||
1674 | typedef void tox_file_request_chunk_cb(Tox *tox, uint32_t friend_number, uint32_t file_number, uint64_t position, | ||
1675 | size_t length, void *user_data); | ||
586 | 1676 | ||
587 | /***************END OF FILE SENDING FUNCTIONS******************/ | 1677 | /** |
1678 | * Set the callback for the `file_request_chunk` event. Pass NULL to unset. | ||
1679 | */ | ||
1680 | void tox_callback_file_request_chunk(Tox *tox, tox_file_request_chunk_cb *function, void *user_data); | ||
588 | 1681 | ||
589 | /* | 1682 | |
590 | * Use this function to bootstrap the client. | 1683 | /******************************************************************************* |
1684 | * | ||
1685 | * :: File transmission: receiving | ||
1686 | * | ||
1687 | ******************************************************************************/ | ||
1688 | |||
1689 | |||
1690 | /** | ||
1691 | * The function type for the `file_receive` callback. | ||
1692 | * | ||
1693 | * The client should acquire resources to be associated with the file transfer. | ||
1694 | * Incoming file transfers start in the PAUSED state. After this callback | ||
1695 | * returns, a transfer can be rejected by sending a TOX_FILE_CONTROL_CANCEL | ||
1696 | * control command before any other control commands. It can be accepted by | ||
1697 | * sending TOX_FILE_CONTROL_RESUME. | ||
1698 | * | ||
1699 | * @param friend_number The friend number of the friend who is sending the file | ||
1700 | * transfer request. | ||
1701 | * @param file_number The friend-specific file number the data received is | ||
1702 | * associated with. | ||
1703 | */ | ||
1704 | typedef void tox_file_receive_cb(Tox *tox, uint32_t friend_number, uint32_t file_number, TOX_FILE_KIND kind, | ||
1705 | uint64_t file_size, const uint8_t *filename, size_t filename_length, void *user_data); | ||
1706 | |||
1707 | /** | ||
1708 | * Set the callback for the `file_receive` event. Pass NULL to unset. | ||
1709 | * | ||
1710 | * This event is triggered when a file transfer request is received. | ||
591 | */ | 1711 | */ |
1712 | void tox_callback_file_receive(Tox *tox, tox_file_receive_cb *function, void *user_data); | ||
1713 | |||
592 | 1714 | ||
593 | /* Resolves address into an IP address. If successful, sends a "get nodes" | 1715 | /** |
594 | * request to the given node with ip, port (in host byte order). | 1716 | * The function type for the `file_receive_chunk` callback. |
595 | * and public_key to setup connections | 1717 | * |
1718 | * This function is first called when a file transfer request is received, and | ||
1719 | * subsequently when a chunk of file data for an accepted request was received. | ||
596 | * | 1720 | * |
597 | * address can be a hostname or an IP address (IPv4 or IPv6). | 1721 | * When length is 0, the transfer is finished and the client should release the |
1722 | * resources it acquired for the transfer. After a call with length = 0, the | ||
1723 | * file number can be reused for new file transfers. | ||
598 | * | 1724 | * |
599 | * returns 1 if the address could be converted into an IP address | 1725 | * If position is equal to file_size (received in the file_receive callback) |
600 | * returns 0 otherwise | 1726 | * when the transfer finishes, the file was received completely. Otherwise, if |
1727 | * file_size was 0, streaming ended successfully when length is 0. | ||
1728 | * | ||
1729 | * @param friend_number The friend number of the friend who is sending the file. | ||
1730 | * @param file_number The friend-specific file number the data received is | ||
1731 | * associated with. | ||
1732 | * @param position The file position of the first byte in data. | ||
1733 | * @param data A byte array containing the received chunk. | ||
1734 | * @param length The length of the received chunk. | ||
601 | */ | 1735 | */ |
602 | int tox_bootstrap_from_address(Tox *tox, const char *address, uint16_t port, const uint8_t *public_key); | 1736 | typedef void tox_file_receive_chunk_cb(Tox *tox, uint32_t friend_number, uint32_t file_number, uint64_t position, |
1737 | const uint8_t *data, size_t length, void *user_data); | ||
603 | 1738 | ||
604 | /* return 0 if we are not connected to the DHT. | 1739 | /** |
605 | * return 1 if we are. | 1740 | * Set the callback for the `file_receive_chunk` event. Pass NULL to unset. |
606 | */ | 1741 | */ |
607 | int tox_isconnected(const Tox *tox); | 1742 | void tox_callback_file_receive_chunk(Tox *tox, tox_file_receive_chunk_cb *function, void *user_data); |
1743 | |||
1744 | |||
1745 | /******************************************************************************* | ||
1746 | * | ||
1747 | * :: Group chat management | ||
1748 | * | ||
1749 | ******************************************************************************/ | ||
1750 | |||
608 | 1751 | ||
609 | typedef struct { | 1752 | /****************************************************************************** |
610 | /* | 1753 | * |
611 | * The type of UDP socket created depends on ipv6enabled: | 1754 | * :: Group chat message sending and receiving |
612 | * If set to 0 (zero), creates an IPv4 socket which subsequently only allows | 1755 | * |
613 | * IPv4 communication | 1756 | ******************************************************************************/ |
614 | * If set to anything else (default), creates an IPv6 socket which allows both IPv4 AND | 1757 | |
615 | * IPv6 communication | 1758 | |
616 | */ | 1759 | /******************************************************************************* |
617 | uint8_t ipv6enabled; | 1760 | * |
1761 | * :: Low-level custom packet sending and receiving | ||
1762 | * | ||
1763 | ******************************************************************************/ | ||
618 | 1764 | ||
619 | /* Set to 1 to disable udp support. (default: 0) | ||
620 | This will force Tox to use TCP only which may slow things down. | ||
621 | Disabling udp support is necessary when using anonymous proxies or Tor.*/ | ||
622 | uint8_t udp_disabled; | ||
623 | 1765 | ||
624 | /* Enable proxy support. (only basic TCP socks5 proxy currently supported.) (default: 0 (disabled))*/ | 1766 | enum TOX_ERR_SEND_CUSTOM_PACKET { |
625 | uint8_t proxy_enabled; | 1767 | TOX_ERR_SEND_CUSTOM_PACKET_OK, |
626 | char proxy_address[256]; /* Proxy ip or domain in NULL terminated string format. */ | 1768 | TOX_ERR_SEND_CUSTOM_PACKET_NULL, |
627 | uint16_t proxy_port; /* Proxy port: in host byte order. */ | 1769 | /** |
628 | } Tox_Options; | 1770 | * The friend number did not designate a valid friend. |
1771 | */ | ||
1772 | TOX_ERR_SEND_CUSTOM_PACKET_FRIEND_NOT_FOUND, | ||
1773 | /** | ||
1774 | * This client is currently not connected to the friend. | ||
1775 | */ | ||
1776 | TOX_ERR_SEND_CUSTOM_PACKET_FRIEND_NOT_CONNECTED, | ||
1777 | /** | ||
1778 | * The first byte of data was not in the specified range for the packet type. | ||
1779 | * This range is 200-254 for lossy, and 160-191 for lossless packets. | ||
1780 | */ | ||
1781 | TOX_ERR_SEND_CUSTOM_PACKET_INVALID, | ||
1782 | /** | ||
1783 | * Attempted to send an empty packet. | ||
1784 | */ | ||
1785 | TOX_ERR_SEND_CUSTOM_PACKET_EMPTY, | ||
1786 | /** | ||
1787 | * Packet data length exceeded TOX_MAX_CUSTOM_PACKET_SIZE. | ||
1788 | */ | ||
1789 | TOX_ERR_SEND_CUSTOM_PACKET_TOO_LONG, | ||
1790 | /** | ||
1791 | * Send queue size exceeded. | ||
1792 | */ | ||
1793 | TOX_ERR_SEND_CUSTOM_PACKET_SENDQ | ||
1794 | }; | ||
1795 | typedef uint8_t TOX_ERR_SEND_CUSTOM_PACKET; | ||
629 | 1796 | ||
630 | /* | 1797 | /** |
631 | * Run this function at startup. | 1798 | * Send a custom lossy packet to a friend. |
1799 | * | ||
1800 | * The first byte of data must be in the range 200-254. Maximum length of a | ||
1801 | * custom packet is TOX_MAX_CUSTOM_PACKET_SIZE. | ||
632 | * | 1802 | * |
633 | * Options are some options that can be passed to the Tox instance (see above struct). | 1803 | * Lossy packets behave like UDP packets, meaning they might never reach the |
1804 | * other side or might arrive more than once (if someone is messing with the | ||
1805 | * connection) or might arrive in the wrong order. | ||
634 | * | 1806 | * |
635 | * If options is NULL, tox_new() will use default settings. | 1807 | * Unless latency is an issue, it is recommended that you use lossless custom |
1808 | * packets instead. | ||
636 | * | 1809 | * |
637 | * Initializes a tox structure | 1810 | * @param friend_number The friend number of the friend this lossy packet |
638 | * return allocated instance of tox on success. | 1811 | * should be sent to. |
639 | * return NULL on failure. | 1812 | * @param data A byte array containing the packet data. |
1813 | * @param length The length of the packet data byte array. | ||
1814 | * | ||
1815 | * @return true on success. | ||
640 | */ | 1816 | */ |
641 | Tox *tox_new(Tox_Options *options); | 1817 | bool tox_send_lossy_packet(Tox *tox, uint32_t friend_number, const uint8_t *data, size_t length, |
1818 | TOX_ERR_SEND_CUSTOM_PACKET *error); | ||
642 | 1819 | ||
643 | /* Run this before closing shop. | 1820 | /** |
644 | * Free all datastructures. */ | 1821 | * The function type for the `friend_lossy_packet` callback. |
645 | void tox_kill(Tox *tox); | 1822 | * |
1823 | * @param friend_number The friend number of the friend who sent a lossy packet. | ||
1824 | * @param data A byte array containing the received packet data. | ||
1825 | * @param length The length of the packet data byte array. | ||
1826 | */ | ||
1827 | typedef void tox_friend_lossy_packet_cb(Tox *tox, uint32_t friend_number, const uint8_t *data, size_t length, | ||
1828 | void *user_data); | ||
646 | 1829 | ||
647 | /* Return the time in milliseconds before tox_do() should be called again | 1830 | /** |
648 | * for optimal performance. | 1831 | * Set the callback for the `friend_lossy_packet` event. Pass NULL to unset. |
1832 | */ | ||
1833 | void tox_callback_friend_lossy_packet(Tox *tox, tox_friend_lossy_packet_cb *function, void *user_data); | ||
1834 | |||
1835 | |||
1836 | /** | ||
1837 | * Send a custom lossless packet to a friend. | ||
1838 | * | ||
1839 | * The first byte of data must be in the range 160-191. Maximum length of a | ||
1840 | * custom packet is TOX_MAX_CUSTOM_PACKET_SIZE. | ||
1841 | * | ||
1842 | * Lossless packet behaviour is comparable to TCP (reliability, arrive in order) | ||
1843 | * but with packets instead of a stream. | ||
1844 | * | ||
1845 | * @param friend_number The friend number of the friend this lossless packet | ||
1846 | * should be sent to. | ||
1847 | * @param data A byte array containing the packet data. | ||
1848 | * @param length The length of the packet data byte array. | ||
649 | * | 1849 | * |
650 | * returns time (in ms) before the next tox_do() needs to be run on success. | 1850 | * @return true on success. |
651 | */ | 1851 | */ |
652 | uint32_t tox_do_interval(Tox *tox); | 1852 | bool tox_send_lossless_packet(Tox *tox, uint32_t friend_number, const uint8_t *data, size_t length, |
1853 | TOX_ERR_SEND_CUSTOM_PACKET *error); | ||
653 | 1854 | ||
654 | /* The main loop that needs to be run in intervals of tox_do_interval() ms. */ | 1855 | /** |
655 | void tox_do(Tox *tox); | 1856 | * The function type for the `friend_lossless_packet` callback. |
1857 | * | ||
1858 | * @param friend_number The friend number of the friend who sent the packet. | ||
1859 | * @param data A byte array containing the received packet data. | ||
1860 | * @param length The length of the packet data byte array. | ||
1861 | */ | ||
1862 | typedef void tox_friend_lossless_packet_cb(Tox *tox, uint32_t friend_number, const uint8_t *data, size_t length, | ||
1863 | void *user_data); | ||
656 | 1864 | ||
657 | /* SAVING AND LOADING FUNCTIONS: */ | 1865 | /** |
1866 | * Set the callback for the `friend_lossless_packet` event. Pass NULL to unset. | ||
1867 | */ | ||
1868 | void tox_callback_friend_lossless_packet(Tox *tox, tox_friend_lossless_packet_cb *function, void *user_data); | ||
658 | 1869 | ||
659 | /* return size of messenger data (for saving). */ | ||
660 | uint32_t tox_size(const Tox *tox); | ||
661 | 1870 | ||
662 | /* Save the messenger in data (must be allocated memory of size Messenger_size()). */ | ||
663 | void tox_save(const Tox *tox, uint8_t *data); | ||
664 | 1871 | ||
665 | /* Load the messenger from data of size length. | 1872 | /******************************************************************************* |
1873 | * | ||
1874 | * :: Low-level network information | ||
1875 | * | ||
1876 | ******************************************************************************/ | ||
1877 | |||
1878 | |||
1879 | /** | ||
1880 | * Writes the temporary DHT public key of this instance to a byte array. | ||
1881 | * | ||
1882 | * This can be used in combination with an externally accessible IP address and | ||
1883 | * the bound port (from tox_get_udp_port) to run a temporary bootstrap node. | ||
666 | * | 1884 | * |
667 | * returns 0 on success | 1885 | * Be aware that every time a new instance is created, the DHT public key |
668 | * returns -1 on failure | 1886 | * changes, meaning this cannot be used to run a permanent bootstrap node. |
1887 | * | ||
1888 | * @param dht_id A memory region of at least TOX_PUBLIC_KEY_SIZE bytes. If this | ||
1889 | * parameter is NULL, this function has no effect. | ||
669 | */ | 1890 | */ |
670 | int tox_load(Tox *tox, const uint8_t *data, uint32_t length); | 1891 | void tox_get_dht_id(const Tox *tox, uint8_t *dht_id); |
1892 | |||
1893 | |||
1894 | enum TOX_ERR_GET_PORT { | ||
1895 | TOX_ERR_GET_PORT_OK, | ||
1896 | /** | ||
1897 | * The instance was not bound to any port. | ||
1898 | */ | ||
1899 | TOX_ERR_GET_PORT_NOT_BOUND | ||
1900 | }; | ||
1901 | typedef uint8_t TOX_ERR_GET_PORT; | ||
1902 | |||
1903 | /** | ||
1904 | * Return the UDP port this Tox instance is bound to. | ||
1905 | */ | ||
1906 | uint16_t tox_get_udp_port(const Tox *tox, TOX_ERR_GET_PORT *error); | ||
1907 | |||
1908 | /** | ||
1909 | * Return the TCP port this Tox instance is bound to. This is only relevant if | ||
1910 | * the instance is acting as a TCP relay. | ||
1911 | */ | ||
1912 | uint16_t tox_get_tcp_port(const Tox *tox, TOX_ERR_GET_PORT *error); | ||
1913 | |||
671 | 1914 | ||
672 | #ifdef __cplusplus | 1915 | #ifdef __cplusplus |
673 | } | 1916 | } |
diff --git a/toxcore/util.c b/toxcore/util.c index 969ee704..5a72c4a4 100644 --- a/toxcore/util.c +++ b/toxcore/util.c | |||
@@ -84,6 +84,35 @@ void host_to_net(uint8_t *num, uint16_t numbytes) | |||
84 | return; | 84 | return; |
85 | } | 85 | } |
86 | 86 | ||
87 | uint16_t lendian_to_host16(uint16_t lendian) | ||
88 | { | ||
89 | #ifdef WORDS_BIGENDIAN | ||
90 | return (lendian << 8) | (lendian >> 8 ); | ||
91 | #else | ||
92 | return lendian; | ||
93 | #endif | ||
94 | } | ||
95 | |||
96 | void host_to_lendian32(uint8_t *dest, uint32_t num) | ||
97 | { | ||
98 | #ifdef WORDS_BIGENDIAN | ||
99 | num = ((num << 8) & 0xFF00FF00 ) | ((num >> 8) & 0xFF00FF ); | ||
100 | num = (num << 16) | (num >> 16); | ||
101 | #endif | ||
102 | memcpy(dest, &num, sizeof(uint32_t)); | ||
103 | } | ||
104 | |||
105 | void lendian_to_host32(uint32_t *dest, const uint8_t *lendian) | ||
106 | { | ||
107 | uint32_t d; | ||
108 | memcpy(&d, lendian, sizeof(uint32_t)); | ||
109 | #ifdef WORDS_BIGENDIAN | ||
110 | d = ((d << 8) & 0xFF00FF00 ) | ((d >> 8) & 0xFF00FF ); | ||
111 | d = (d << 16) | (d >> 16); | ||
112 | #endif | ||
113 | *dest = d; | ||
114 | } | ||
115 | |||
87 | /* state load/save */ | 116 | /* state load/save */ |
88 | int load_state(load_state_callback_func load_state_callback, void *outer, | 117 | int load_state(load_state_callback_func load_state_callback, void *outer, |
89 | const uint8_t *data, uint32_t length, uint16_t cookie_inner) | 118 | const uint8_t *data, uint32_t length, uint16_t cookie_inner) |
@@ -101,8 +130,8 @@ int load_state(load_state_callback_func load_state_callback, void *outer, | |||
101 | uint32_t size_head = sizeof(uint32_t) * 2; | 130 | uint32_t size_head = sizeof(uint32_t) * 2; |
102 | 131 | ||
103 | while (length >= size_head) { | 132 | while (length >= size_head) { |
104 | memcpy(&length_sub, data, sizeof(length_sub)); | 133 | lendian_to_host32(&length_sub, data); |
105 | memcpy(&cookie_type, data + sizeof(length_sub), sizeof(cookie_type)); | 134 | lendian_to_host32(&cookie_type, data + sizeof(length_sub)); |
106 | data += size_head; | 135 | data += size_head; |
107 | length -= size_head; | 136 | length -= size_head; |
108 | 137 | ||
@@ -114,7 +143,7 @@ int load_state(load_state_callback_func load_state_callback, void *outer, | |||
114 | return -1; | 143 | return -1; |
115 | } | 144 | } |
116 | 145 | ||
117 | if ((cookie_type >> 16) != cookie_inner) { | 146 | if (lendian_to_host16((cookie_type >> 16)) != cookie_inner) { |
118 | /* something is not matching up in a bad way, give up */ | 147 | /* something is not matching up in a bad way, give up */ |
119 | #ifdef DEBUG | 148 | #ifdef DEBUG |
120 | fprintf(stderr, "state file garbeled: %04hx != %04hx\n", (cookie_type >> 16), cookie_inner); | 149 | fprintf(stderr, "state file garbeled: %04hx != %04hx\n", (cookie_type >> 16), cookie_inner); |
@@ -122,7 +151,7 @@ int load_state(load_state_callback_func load_state_callback, void *outer, | |||
122 | return -1; | 151 | return -1; |
123 | } | 152 | } |
124 | 153 | ||
125 | type = cookie_type & 0xFFFF; | 154 | type = lendian_to_host16(cookie_type & 0xFFFF); |
126 | 155 | ||
127 | if (-1 == load_state_callback(outer, data, length_sub, type)) | 156 | if (-1 == load_state_callback(outer, data, length_sub, type)) |
128 | return -1; | 157 | return -1; |
@@ -134,60 +163,25 @@ int load_state(load_state_callback_func load_state_callback, void *outer, | |||
134 | return length == 0 ? 0 : -1; | 163 | return length == 0 ? 0 : -1; |
135 | }; | 164 | }; |
136 | 165 | ||
137 | /* Converts 4 bytes to uint32_t */ | 166 | int create_recursive_mutex(pthread_mutex_t *mutex) |
138 | inline__ void bytes_to_U32(uint32_t *dest, const uint8_t *bytes) | ||
139 | { | 167 | { |
140 | *dest = | 168 | pthread_mutexattr_t attr; |
141 | #ifdef WORDS_BIGENDIAN | ||
142 | ( ( uint32_t ) * bytes ) | | ||
143 | ( ( uint32_t ) * ( bytes + 1 ) << 8 ) | | ||
144 | ( ( uint32_t ) * ( bytes + 2 ) << 16 ) | | ||
145 | ( ( uint32_t ) * ( bytes + 3 ) << 24 ) ; | ||
146 | #else | ||
147 | ( ( uint32_t ) * bytes << 24 ) | | ||
148 | ( ( uint32_t ) * ( bytes + 1 ) << 16 ) | | ||
149 | ( ( uint32_t ) * ( bytes + 2 ) << 8 ) | | ||
150 | ( ( uint32_t ) * ( bytes + 3 ) ) ; | ||
151 | #endif | ||
152 | } | ||
153 | 169 | ||
154 | /* Converts 2 bytes to uint16_t */ | 170 | if (pthread_mutexattr_init(&attr) != 0) |
155 | inline__ void bytes_to_U16(uint16_t *dest, const uint8_t *bytes) | 171 | return -1; |
156 | { | ||
157 | *dest = | ||
158 | #ifdef WORDS_BIGENDIAN | ||
159 | ( ( uint16_t ) * bytes ) | | ||
160 | ( ( uint16_t ) * ( bytes + 1 ) << 8 ); | ||
161 | #else | ||
162 | ( ( uint16_t ) * bytes << 8 ) | | ||
163 | ( ( uint16_t ) * ( bytes + 1 ) ); | ||
164 | #endif | ||
165 | } | ||
166 | 172 | ||
167 | /* Convert uint32_t to byte string of size 4 */ | 173 | if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) != 0) { |
168 | inline__ void U32_to_bytes(uint8_t *dest, uint32_t value) | 174 | pthread_mutexattr_destroy(&attr); |
169 | { | 175 | return -1; |
170 | #ifdef WORDS_BIGENDIAN | 176 | } |
171 | *(dest) = ( value ); | ||
172 | *(dest + 1) = ( value >> 8 ); | ||
173 | *(dest + 2) = ( value >> 16 ); | ||
174 | *(dest + 3) = ( value >> 24 ); | ||
175 | #else | ||
176 | *(dest) = ( value >> 24 ); | ||
177 | *(dest + 1) = ( value >> 16 ); | ||
178 | *(dest + 2) = ( value >> 8 ); | ||
179 | *(dest + 3) = ( value ); | ||
180 | #endif | ||
181 | } | ||
182 | 177 | ||
183 | /* Convert uint16_t to byte string of size 2 */ | 178 | /* Create queue mutex */ |
184 | inline__ void U16_to_bytes(uint8_t *dest, uint16_t value) | 179 | if (pthread_mutex_init(mutex, &attr) != 0) { |
185 | { | 180 | pthread_mutexattr_destroy(&attr); |
186 | #ifdef WORDS_BIGENDIAN | 181 | return -1; |
187 | *(dest) = ( value ); | 182 | } |
188 | *(dest + 1) = ( value >> 8 ); | 183 | |
189 | #else | 184 | pthread_mutexattr_destroy(&attr); |
190 | *(dest) = ( value >> 8 ); | 185 | |
191 | *(dest + 1) = ( value ); | 186 | return 0; |
192 | #endif | 187 | } |
193 | } \ No newline at end of file | ||
diff --git a/toxcore/util.h b/toxcore/util.h index 955ce8c4..7cd6bb8b 100644 --- a/toxcore/util.h +++ b/toxcore/util.h | |||
@@ -27,8 +27,9 @@ | |||
27 | 27 | ||
28 | #include <stdbool.h> | 28 | #include <stdbool.h> |
29 | #include <stdint.h> | 29 | #include <stdint.h> |
30 | #include <pthread.h> | ||
30 | 31 | ||
31 | #define inline__ inline __attribute__((always_inline)) | 32 | #define MIN(a,b) (((a)<(b))?(a):(b)) |
32 | 33 | ||
33 | void unix_time_update(); | 34 | void unix_time_update(); |
34 | uint64_t unix_time(); | 35 | uint64_t unix_time(); |
@@ -42,22 +43,16 @@ uint32_t id_copy(uint8_t *dest, const uint8_t *src); /* return value is CLIENT_I | |||
42 | void host_to_net(uint8_t *num, uint16_t numbytes); | 43 | void host_to_net(uint8_t *num, uint16_t numbytes); |
43 | #define net_to_host(x, y) host_to_net(x, y) | 44 | #define net_to_host(x, y) host_to_net(x, y) |
44 | 45 | ||
46 | uint16_t lendian_to_host16(uint16_t lendian); | ||
47 | #define host_tolendian16(x) lendian_to_host16(x) | ||
48 | |||
49 | void host_to_lendian32(uint8_t *dest, uint32_t num); | ||
50 | |||
45 | /* state load/save */ | 51 | /* state load/save */ |
46 | typedef int (*load_state_callback_func)(void *outer, const uint8_t *data, uint32_t len, uint16_t type); | 52 | typedef int (*load_state_callback_func)(void *outer, const uint8_t *data, uint32_t len, uint16_t type); |
47 | int load_state(load_state_callback_func load_state_callback, void *outer, | 53 | int load_state(load_state_callback_func load_state_callback, void *outer, |
48 | const uint8_t *data, uint32_t length, uint16_t cookie_inner); | 54 | const uint8_t *data, uint32_t length, uint16_t cookie_inner); |
49 | 55 | ||
50 | /* Converts 4 bytes to uint32_t */ | 56 | int create_recursive_mutex(pthread_mutex_t *mutex); |
51 | void bytes_to_U32(uint32_t *dest, const uint8_t *bytes); | ||
52 | |||
53 | /* Converts 2 bytes to uint16_t */ | ||
54 | void bytes_to_U16(uint16_t *dest, const uint8_t *bytes); | ||
55 | |||
56 | /* Convert uint32_t to byte string of size 4 */ | ||
57 | void U32_to_bytes(uint8_t *dest, uint32_t value); | ||
58 | |||
59 | /* Convert uint16_t to byte string of size 2 */ | ||
60 | void U16_to_bytes(uint8_t *dest, uint16_t value); | ||
61 | |||
62 | 57 | ||
63 | #endif /* __UTIL_H__ */ | 58 | #endif /* __UTIL_H__ */ |
diff --git a/toxdns/toxdns.c b/toxdns/toxdns.c index 7a7a052d..186ea82b 100644 --- a/toxdns/toxdns.c +++ b/toxdns/toxdns.c | |||
@@ -95,7 +95,7 @@ void tox_dns3_kill(void *dns3_object) | |||
95 | * This is what the string returned looks like: | 95 | * This is what the string returned looks like: |
96 | * 4haaaaipr1o3mz0bxweox541airydbovqlbju51mb4p0ebxq.rlqdj4kkisbep2ks3fj2nvtmk4daduqiueabmexqva1jc | 96 | * 4haaaaipr1o3mz0bxweox541airydbovqlbju51mb4p0ebxq.rlqdj4kkisbep2ks3fj2nvtmk4daduqiueabmexqva1jc |
97 | * | 97 | * |
98 | * returns length of string on sucess. | 98 | * returns length of string on success. |
99 | * returns -1 on failure. | 99 | * returns -1 on failure. |
100 | */ | 100 | */ |
101 | int tox_generate_dns3_string(void *dns3_object, uint8_t *string, uint16_t string_max_len, uint32_t *request_id, | 101 | int tox_generate_dns3_string(void *dns3_object, uint8_t *string, uint16_t string_max_len, uint32_t *request_id, |
diff --git a/toxdns/toxdns.h b/toxdns/toxdns.h index a0cc323b..06071b82 100644 --- a/toxdns/toxdns.h +++ b/toxdns/toxdns.h | |||
@@ -24,8 +24,15 @@ | |||
24 | #ifndef TOXDNS_H | 24 | #ifndef TOXDNS_H |
25 | #define TOXDNS_H | 25 | #define TOXDNS_H |
26 | 26 | ||
27 | #ifdef __cplusplus | ||
28 | extern "C" { | ||
29 | #endif | ||
30 | |||
27 | #include <stdint.h> | 31 | #include <stdint.h> |
28 | 32 | ||
33 | /* Clients are encouraged to set this as the maximum length names can have. */ | ||
34 | #define TOXDNS_MAX_RECOMMENDED_NAME_LENGTH 32 | ||
35 | |||
29 | /* How to use this api to make secure tox dns3 requests: | 36 | /* How to use this api to make secure tox dns3 requests: |
30 | * | 37 | * |
31 | * 1. Get the public key of a server that supports tox dns3. | 38 | * 1. Get the public key of a server that supports tox dns3. |
@@ -61,7 +68,7 @@ void tox_dns3_kill(void *dns3_object); | |||
61 | * This is what the string returned looks like: | 68 | * This is what the string returned looks like: |
62 | * 4haaaaipr1o3mz0bxweox541airydbovqlbju51mb4p0ebxq.rlqdj4kkisbep2ks3fj2nvtmk4daduqiueabmexqva1jc | 69 | * 4haaaaipr1o3mz0bxweox541airydbovqlbju51mb4p0ebxq.rlqdj4kkisbep2ks3fj2nvtmk4daduqiueabmexqva1jc |
63 | * | 70 | * |
64 | * returns length of string on sucess. | 71 | * returns length of string on success. |
65 | * returns -1 on failure. | 72 | * returns -1 on failure. |
66 | */ | 73 | */ |
67 | int tox_generate_dns3_string(void *dns3_object, uint8_t *string, uint16_t string_max_len, uint32_t *request_id, | 74 | int tox_generate_dns3_string(void *dns3_object, uint8_t *string, uint16_t string_max_len, uint32_t *request_id, |
@@ -82,4 +89,8 @@ int tox_generate_dns3_string(void *dns3_object, uint8_t *string, uint16_t string | |||
82 | int tox_decrypt_dns3_TXT(void *dns3_object, uint8_t *tox_id, uint8_t *id_record, uint32_t id_record_len, | 89 | int tox_decrypt_dns3_TXT(void *dns3_object, uint8_t *tox_id, uint8_t *id_record, uint32_t id_record_len, |
83 | uint32_t request_id); | 90 | uint32_t request_id); |
84 | 91 | ||
92 | #ifdef __cplusplus | ||
93 | } | ||
94 | #endif | ||
95 | |||
85 | #endif | 96 | #endif |
diff --git a/toxencryptsave/Makefile.inc b/toxencryptsave/Makefile.inc new file mode 100644 index 00000000..1155e954 --- /dev/null +++ b/toxencryptsave/Makefile.inc | |||
@@ -0,0 +1,45 @@ | |||
1 | lib_LTLIBRARIES += libtoxencryptsave.la | ||
2 | |||
3 | libtoxencryptsave_la_include_HEADERS = \ | ||
4 | ../toxencryptsave/toxencryptsave.h | ||
5 | |||
6 | libtoxencryptsave_la_includedir = $(includedir)/tox | ||
7 | |||
8 | libtoxencryptsave_la_SOURCES = ../toxencryptsave/crypto_pwhash_scryptsalsa208sha256/crypto_pwhash_scryptsalsa208sha256.h \ | ||
9 | ../toxencryptsave/crypto_pwhash_scryptsalsa208sha256/crypto_scrypt.h \ | ||
10 | ../toxencryptsave/crypto_pwhash_scryptsalsa208sha256/pbkdf2-sha256.c \ | ||
11 | ../toxencryptsave/crypto_pwhash_scryptsalsa208sha256/pwhash_scryptsalsa208sha256.c \ | ||
12 | ../toxencryptsave/crypto_pwhash_scryptsalsa208sha256/runtime.h \ | ||
13 | ../toxencryptsave/crypto_pwhash_scryptsalsa208sha256/utils.c \ | ||
14 | ../toxencryptsave/crypto_pwhash_scryptsalsa208sha256/crypto_scrypt-common.c \ | ||
15 | ../toxencryptsave/crypto_pwhash_scryptsalsa208sha256/export.h \ | ||
16 | ../toxencryptsave/crypto_pwhash_scryptsalsa208sha256/pbkdf2-sha256.h \ | ||
17 | ../toxencryptsave/crypto_pwhash_scryptsalsa208sha256/runtime.c \ | ||
18 | ../toxencryptsave/crypto_pwhash_scryptsalsa208sha256/scrypt_platform.c \ | ||
19 | ../toxencryptsave/crypto_pwhash_scryptsalsa208sha256/sysendian.h \ | ||
20 | ../toxencryptsave/crypto_pwhash_scryptsalsa208sha256/utils.h \ | ||
21 | ../toxencryptsave/crypto_pwhash_scryptsalsa208sha256/nosse/pwhash_scryptsalsa208sha256_nosse.c \ | ||
22 | ../toxencryptsave/crypto_pwhash_scryptsalsa208sha256/sse/pwhash_scryptsalsa208sha256_sse.c \ | ||
23 | ../toxencryptsave/toxencryptsave.h \ | ||
24 | ../toxencryptsave/toxencryptsave.c | ||
25 | |||
26 | |||
27 | libtoxencryptsave_la_CFLAGS = -I$(top_srcdir) \ | ||
28 | -I$(top_srcdir)/toxcore \ | ||
29 | $(LIBSODIUM_CFLAGS) \ | ||
30 | $(NACL_CFLAGS) \ | ||
31 | $(PTHREAD_CFLAGS) | ||
32 | |||
33 | libtoxencryptsave_la_LDFLAGS = $(TOXCORE_LT_LDFLAGS) \ | ||
34 | $(EXTRA_LT_LDFLAGS) \ | ||
35 | $(LIBSODIUM_LDFLAGS) \ | ||
36 | $(NACL_LDFLAGS) \ | ||
37 | $(MATH_LDFLAGS) \ | ||
38 | $(RT_LIBS) \ | ||
39 | $(WINSOCK2_LIBS) | ||
40 | |||
41 | libtoxencryptsave_la_LIBADD = $(LIBSODIUM_LIBS) \ | ||
42 | $(NACL_OBJECTS) \ | ||
43 | $(NAC_LIBS) \ | ||
44 | $(PTHREAD_LIBS) \ | ||
45 | libtoxcore.la | ||
diff --git a/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/crypto_pwhash_scryptsalsa208sha256.h b/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/crypto_pwhash_scryptsalsa208sha256.h new file mode 100644 index 00000000..5cb32f8d --- /dev/null +++ b/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/crypto_pwhash_scryptsalsa208sha256.h | |||
@@ -0,0 +1,92 @@ | |||
1 | #ifdef HAVE_CONFIG_H | ||
2 | #include "config.h" | ||
3 | #endif | ||
4 | #ifdef VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */ | ||
5 | |||
6 | #ifndef crypto_pwhash_scryptsalsa208sha256_H | ||
7 | #define crypto_pwhash_scryptsalsa208sha256_H | ||
8 | |||
9 | #include <stddef.h> | ||
10 | #include <stdint.h> | ||
11 | |||
12 | #include "export.h" | ||
13 | |||
14 | #ifdef __cplusplus | ||
15 | # if __GNUC__ | ||
16 | # pragma GCC diagnostic ignored "-Wlong-long" | ||
17 | # endif | ||
18 | extern "C" { | ||
19 | #endif | ||
20 | |||
21 | #define crypto_pwhash_scryptsalsa208sha256_SALTBYTES 32U | ||
22 | SODIUM_EXPORT | ||
23 | size_t crypto_pwhash_scryptsalsa208sha256_saltbytes(void); | ||
24 | |||
25 | #define crypto_pwhash_scryptsalsa208sha256_STRBYTES 102U | ||
26 | SODIUM_EXPORT | ||
27 | size_t crypto_pwhash_scryptsalsa208sha256_strbytes(void); | ||
28 | |||
29 | #define crypto_pwhash_scryptsalsa208sha256_STRPREFIX "$7$" | ||
30 | SODIUM_EXPORT | ||
31 | const char *crypto_pwhash_scryptsalsa208sha256_strprefix(void); | ||
32 | |||
33 | #define crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE 524288ULL | ||
34 | SODIUM_EXPORT | ||
35 | size_t crypto_pwhash_scryptsalsa208sha256_opslimit_interactive(void); | ||
36 | |||
37 | #define crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE 16777216ULL | ||
38 | SODIUM_EXPORT | ||
39 | size_t crypto_pwhash_scryptsalsa208sha256_memlimit_interactive(void); | ||
40 | |||
41 | #define crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_SENSITIVE 33554432ULL | ||
42 | SODIUM_EXPORT | ||
43 | size_t crypto_pwhash_scryptsalsa208sha256_opslimit_sensitive(void); | ||
44 | |||
45 | #define crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_SENSITIVE 1073741824ULL | ||
46 | SODIUM_EXPORT | ||
47 | size_t crypto_pwhash_scryptsalsa208sha256_memlimit_sensitive(void); | ||
48 | |||
49 | SODIUM_EXPORT | ||
50 | int crypto_pwhash_scryptsalsa208sha256(unsigned char * const out, | ||
51 | unsigned long long outlen, | ||
52 | const char * const passwd, | ||
53 | unsigned long long passwdlen, | ||
54 | const unsigned char * const salt, | ||
55 | unsigned long long opslimit, | ||
56 | size_t memlimit); | ||
57 | |||
58 | SODIUM_EXPORT | ||
59 | int crypto_pwhash_scryptsalsa208sha256_str(char out[crypto_pwhash_scryptsalsa208sha256_STRBYTES], | ||
60 | const char * const passwd, | ||
61 | unsigned long long passwdlen, | ||
62 | unsigned long long opslimit, | ||
63 | size_t memlimit); | ||
64 | |||
65 | SODIUM_EXPORT | ||
66 | int crypto_pwhash_scryptsalsa208sha256_str_verify(const char str[crypto_pwhash_scryptsalsa208sha256_STRBYTES], | ||
67 | const char * const passwd, | ||
68 | unsigned long long passwdlen); | ||
69 | |||
70 | SODIUM_EXPORT | ||
71 | int crypto_pwhash_scryptsalsa208sha256_ll(const uint8_t * passwd, size_t passwdlen, | ||
72 | const uint8_t * salt, size_t saltlen, | ||
73 | uint64_t N, uint32_t r, uint32_t p, | ||
74 | uint8_t * buf, size_t buflen); | ||
75 | |||
76 | #ifdef __cplusplus | ||
77 | } | ||
78 | #endif | ||
79 | |||
80 | /* Backward compatibility with version 0.5.0 */ | ||
81 | |||
82 | #define crypto_pwhash_scryptxsalsa208sha256_SALTBYTES crypto_pwhash_scryptsalsa208sha256_SALTBYTES | ||
83 | #define crypto_pwhash_scryptxsalsa208sha256_saltbytes crypto_pwhash_scryptsalsa208sha256_saltbytes | ||
84 | #define crypto_pwhash_scryptxsalsa208sha256_STRBYTES crypto_pwhash_scryptsalsa208sha256_STRBYTES | ||
85 | #define crypto_pwhash_scryptxsalsa208sha256_strbytes crypto_pwhash_scryptsalsa208sha256_strbytes | ||
86 | #define crypto_pwhash_scryptxsalsa208sha256 crypto_pwhash_scryptsalsa208sha256 | ||
87 | #define crypto_pwhash_scryptxsalsa208sha256_str crypto_pwhash_scryptsalsa208sha256_str | ||
88 | #define crypto_pwhash_scryptxsalsa208sha256_str_verify crypto_pwhash_scryptsalsa208sha256_str_verify | ||
89 | |||
90 | #endif | ||
91 | |||
92 | #endif | ||
diff --git a/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/crypto_scrypt-common.c b/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/crypto_scrypt-common.c new file mode 100644 index 00000000..5a5c5525 --- /dev/null +++ b/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/crypto_scrypt-common.c | |||
@@ -0,0 +1,257 @@ | |||
1 | #ifdef HAVE_CONFIG_H | ||
2 | #include "config.h" | ||
3 | #endif | ||
4 | #ifdef VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */ | ||
5 | |||
6 | /*- | ||
7 | * Copyright 2013 Alexander Peslyak | ||
8 | * All rights reserved. | ||
9 | * | ||
10 | * Redistribution and use in source and binary forms, with or without | ||
11 | * modification, are permitted. | ||
12 | * | ||
13 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | ||
14 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
16 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | ||
17 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
18 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
19 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
20 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
21 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
22 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||
23 | * SUCH DAMAGE. | ||
24 | */ | ||
25 | |||
26 | #include <stdint.h> | ||
27 | #include <string.h> | ||
28 | |||
29 | #include "crypto_pwhash_scryptsalsa208sha256.h" | ||
30 | #include "crypto_scrypt.h" | ||
31 | #include "runtime.h" | ||
32 | #include "utils.h" | ||
33 | |||
34 | static const char * const itoa64 = | ||
35 | "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; | ||
36 | |||
37 | static uint8_t * | ||
38 | encode64_uint32(uint8_t * dst, size_t dstlen, uint32_t src, uint32_t srcbits) | ||
39 | { | ||
40 | uint32_t bit; | ||
41 | |||
42 | for (bit = 0; bit < srcbits; bit += 6) { | ||
43 | if (dstlen < 1) { | ||
44 | return NULL; | ||
45 | } | ||
46 | *dst++ = itoa64[src & 0x3f]; | ||
47 | dstlen--; | ||
48 | src >>= 6; | ||
49 | } | ||
50 | |||
51 | return dst; | ||
52 | } | ||
53 | |||
54 | static uint8_t * | ||
55 | encode64(uint8_t * dst, size_t dstlen, const uint8_t * src, size_t srclen) | ||
56 | { | ||
57 | size_t i; | ||
58 | |||
59 | for (i = 0; i < srclen; ) { | ||
60 | uint8_t * dnext; | ||
61 | uint32_t value = 0, bits = 0; | ||
62 | do { | ||
63 | value |= (uint32_t)src[i++] << bits; | ||
64 | bits += 8; | ||
65 | } while (bits < 24 && i < srclen); | ||
66 | dnext = encode64_uint32(dst, dstlen, value, bits); | ||
67 | if (!dnext) { | ||
68 | return NULL; | ||
69 | } | ||
70 | dstlen -= dnext - dst; | ||
71 | dst = dnext; | ||
72 | } | ||
73 | |||
74 | return dst; | ||
75 | } | ||
76 | |||
77 | static int | ||
78 | decode64_one(uint32_t * dst, uint8_t src) | ||
79 | { | ||
80 | const char *ptr = strchr(itoa64, src); | ||
81 | |||
82 | if (ptr) { | ||
83 | *dst = ptr - itoa64; | ||
84 | return 0; | ||
85 | } | ||
86 | *dst = 0; | ||
87 | return -1; | ||
88 | } | ||
89 | |||
90 | static const uint8_t * | ||
91 | decode64_uint32(uint32_t * dst, uint32_t dstbits, const uint8_t * src) | ||
92 | { | ||
93 | uint32_t bit; | ||
94 | uint32_t value; | ||
95 | |||
96 | value = 0; | ||
97 | for (bit = 0; bit < dstbits; bit += 6) { | ||
98 | uint32_t one; | ||
99 | if (decode64_one(&one, *src)) { | ||
100 | *dst = 0; | ||
101 | return NULL; | ||
102 | } | ||
103 | src++; | ||
104 | value |= one << bit; | ||
105 | } | ||
106 | |||
107 | *dst = value; | ||
108 | return src; | ||
109 | } | ||
110 | |||
111 | uint8_t * | ||
112 | escrypt_r(escrypt_local_t * local, const uint8_t * passwd, size_t passwdlen, | ||
113 | const uint8_t * setting, uint8_t * buf, size_t buflen) | ||
114 | { | ||
115 | uint8_t hash[crypto_pwhash_scryptsalsa208sha256_STRHASHBYTES]; | ||
116 | escrypt_kdf_t escrypt_kdf; | ||
117 | const uint8_t *src; | ||
118 | const uint8_t *salt; | ||
119 | uint8_t *dst; | ||
120 | size_t prefixlen; | ||
121 | size_t saltlen; | ||
122 | size_t need; | ||
123 | uint64_t N; | ||
124 | uint32_t N_log2; | ||
125 | uint32_t r; | ||
126 | uint32_t p; | ||
127 | |||
128 | if (setting[0] != '$' || setting[1] != '7' || setting[2] != '$') { | ||
129 | return NULL; | ||
130 | } | ||
131 | src = setting + 3; | ||
132 | |||
133 | if (decode64_one(&N_log2, *src)) { | ||
134 | return NULL; | ||
135 | } | ||
136 | src++; | ||
137 | N = (uint64_t)1 << N_log2; | ||
138 | |||
139 | src = decode64_uint32(&r, 30, src); | ||
140 | if (!src) { | ||
141 | return NULL; | ||
142 | } | ||
143 | src = decode64_uint32(&p, 30, src); | ||
144 | if (!src) { | ||
145 | return NULL; | ||
146 | } | ||
147 | prefixlen = src - setting; | ||
148 | |||
149 | salt = src; | ||
150 | src = (uint8_t *) strrchr((char *)salt, '$'); | ||
151 | if (src) { | ||
152 | saltlen = src - salt; | ||
153 | } else { | ||
154 | saltlen = strlen((char *)salt); | ||
155 | } | ||
156 | need = prefixlen + saltlen + 1 + | ||
157 | crypto_pwhash_scryptsalsa208sha256_STRHASHBYTES_ENCODED + 1; | ||
158 | if (need > buflen || need < saltlen) { | ||
159 | return NULL; | ||
160 | } | ||
161 | #if defined(HAVE_EMMINTRIN_H) || defined(_MSC_VER) | ||
162 | escrypt_kdf = | ||
163 | sodium_runtime_has_sse2() ? escrypt_kdf_sse : escrypt_kdf_nosse; | ||
164 | #else | ||
165 | escrypt_kdf = escrypt_kdf_nosse; | ||
166 | #endif | ||
167 | if (escrypt_kdf(local, passwd, passwdlen, salt, saltlen, | ||
168 | N, r, p, hash, sizeof(hash))) { | ||
169 | return NULL; | ||
170 | } | ||
171 | |||
172 | dst = buf; | ||
173 | memcpy(dst, setting, prefixlen + saltlen); | ||
174 | dst += prefixlen + saltlen; | ||
175 | *dst++ = '$'; | ||
176 | |||
177 | dst = encode64(dst, buflen - (dst - buf), hash, sizeof(hash)); | ||
178 | sodium_memzero(hash, sizeof hash); | ||
179 | if (!dst || dst >= buf + buflen) { /* Can't happen */ | ||
180 | return NULL; | ||
181 | } | ||
182 | *dst = 0; /* NUL termination */ | ||
183 | |||
184 | return buf; | ||
185 | } | ||
186 | |||
187 | uint8_t * | ||
188 | escrypt_gensalt_r(uint32_t N_log2, uint32_t r, uint32_t p, | ||
189 | const uint8_t * src, size_t srclen, | ||
190 | uint8_t * buf, size_t buflen) | ||
191 | { | ||
192 | uint8_t *dst; | ||
193 | size_t prefixlen = | ||
194 | (sizeof "$7$" - 1U) + (1U /* N_log2 */) + (5U /* r */) + (5U /* p */); | ||
195 | size_t saltlen = BYTES2CHARS(srclen); | ||
196 | size_t need; | ||
197 | |||
198 | need = prefixlen + saltlen + 1; | ||
199 | if (need > buflen || need < saltlen || saltlen < srclen) { | ||
200 | return NULL; | ||
201 | } | ||
202 | if (N_log2 > 63 || ((uint64_t)r * (uint64_t)p >= (1U << 30))) { | ||
203 | return NULL; | ||
204 | } | ||
205 | dst = buf; | ||
206 | *dst++ = '$'; | ||
207 | *dst++ = '7'; | ||
208 | *dst++ = '$'; | ||
209 | |||
210 | *dst++ = itoa64[N_log2]; | ||
211 | |||
212 | dst = encode64_uint32(dst, buflen - (dst - buf), r, 30); | ||
213 | if (!dst) { /* Can't happen */ | ||
214 | return NULL; | ||
215 | } | ||
216 | dst = encode64_uint32(dst, buflen - (dst - buf), p, 30); | ||
217 | if (!dst) { /* Can't happen */ | ||
218 | return NULL; | ||
219 | } | ||
220 | dst = encode64(dst, buflen - (dst - buf), src, srclen); | ||
221 | if (!dst || dst >= buf + buflen) { /* Can't happen */ | ||
222 | return NULL; | ||
223 | } | ||
224 | *dst = 0; /* NUL termination */ | ||
225 | |||
226 | return buf; | ||
227 | } | ||
228 | |||
229 | int | ||
230 | crypto_pwhash_scryptsalsa208sha256_ll(const uint8_t * passwd, size_t passwdlen, | ||
231 | const uint8_t * salt, size_t saltlen, | ||
232 | uint64_t N, uint32_t r, uint32_t p, | ||
233 | uint8_t * buf, size_t buflen) | ||
234 | { | ||
235 | escrypt_kdf_t escrypt_kdf; | ||
236 | escrypt_local_t local; | ||
237 | int retval; | ||
238 | |||
239 | if (escrypt_init_local(&local)) { | ||
240 | return -1; | ||
241 | } | ||
242 | #if defined(HAVE_EMMINTRIN_H) || defined(_MSC_VER) | ||
243 | escrypt_kdf = | ||
244 | sodium_runtime_has_sse2() ? escrypt_kdf_sse : escrypt_kdf_nosse; | ||
245 | #else | ||
246 | escrypt_kdf = escrypt_kdf_nosse; | ||
247 | #endif | ||
248 | retval = escrypt_kdf(&local, | ||
249 | passwd, passwdlen, salt, saltlen, | ||
250 | N, r, p, buf, buflen); | ||
251 | if (escrypt_free_local(&local)) { | ||
252 | return -1; | ||
253 | } | ||
254 | return retval; | ||
255 | } | ||
256 | |||
257 | #endif | ||
diff --git a/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/crypto_scrypt.h b/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/crypto_scrypt.h new file mode 100644 index 00000000..3f0b7d72 --- /dev/null +++ b/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/crypto_scrypt.h | |||
@@ -0,0 +1,93 @@ | |||
1 | #ifdef HAVE_CONFIG_H | ||
2 | #include "config.h" | ||
3 | #endif | ||
4 | #ifdef VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */ | ||
5 | |||
6 | /*- | ||
7 | * Copyright 2009 Colin Percival | ||
8 | * Copyright 2013 Alexander Peslyak | ||
9 | * All rights reserved. | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or without | ||
12 | * modification, are permitted provided that the following conditions | ||
13 | * are met: | ||
14 | * 1. Redistributions of source code must retain the above copyright | ||
15 | * notice, this list of conditions and the following disclaimer. | ||
16 | * 2. Redistributions in binary form must reproduce the above copyright | ||
17 | * notice, this list of conditions and the following disclaimer in the | ||
18 | * documentation and/or other materials provided with the distribution. | ||
19 | * | ||
20 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | ||
21 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | ||
24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
26 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
28 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
29 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||
30 | * SUCH DAMAGE. | ||
31 | * | ||
32 | * This file was originally written by Colin Percival as part of the Tarsnap | ||
33 | * online backup system. | ||
34 | */ | ||
35 | #ifndef _CRYPTO_SCRYPT_H_ | ||
36 | #define _CRYPTO_SCRYPT_H_ | ||
37 | |||
38 | #include <stdint.h> | ||
39 | |||
40 | #define crypto_pwhash_scryptsalsa208sha256_STRPREFIXBYTES 14 | ||
41 | #define crypto_pwhash_scryptsalsa208sha256_STRSETTINGBYTES 57 | ||
42 | #define crypto_pwhash_scryptsalsa208sha256_STRSALTBYTES 32 | ||
43 | #define crypto_pwhash_scryptsalsa208sha256_STRSALTBYTES_ENCODED 43 | ||
44 | #define crypto_pwhash_scryptsalsa208sha256_STRHASHBYTES 32 | ||
45 | #define crypto_pwhash_scryptsalsa208sha256_STRHASHBYTES_ENCODED 43 | ||
46 | |||
47 | #define BYTES2CHARS(bytes) ((((bytes) * 8) + 5) / 6) | ||
48 | |||
49 | typedef struct { | ||
50 | void * base, * aligned; | ||
51 | size_t size; | ||
52 | } escrypt_region_t; | ||
53 | |||
54 | typedef escrypt_region_t escrypt_local_t; | ||
55 | |||
56 | extern int escrypt_init_local(escrypt_local_t * __local); | ||
57 | |||
58 | extern int escrypt_free_local(escrypt_local_t * __local); | ||
59 | |||
60 | extern void *alloc_region(escrypt_region_t * region, size_t size); | ||
61 | extern int free_region(escrypt_region_t * region); | ||
62 | |||
63 | typedef int (*escrypt_kdf_t)(escrypt_local_t * __local, | ||
64 | const uint8_t * __passwd, size_t __passwdlen, | ||
65 | const uint8_t * __salt, size_t __saltlen, | ||
66 | uint64_t __N, uint32_t __r, uint32_t __p, | ||
67 | uint8_t * __buf, size_t __buflen); | ||
68 | |||
69 | extern int escrypt_kdf_nosse(escrypt_local_t * __local, | ||
70 | const uint8_t * __passwd, size_t __passwdlen, | ||
71 | const uint8_t * __salt, size_t __saltlen, | ||
72 | uint64_t __N, uint32_t __r, uint32_t __p, | ||
73 | uint8_t * __buf, size_t __buflen); | ||
74 | |||
75 | extern int escrypt_kdf_sse(escrypt_local_t * __local, | ||
76 | const uint8_t * __passwd, size_t __passwdlen, | ||
77 | const uint8_t * __salt, size_t __saltlen, | ||
78 | uint64_t __N, uint32_t __r, uint32_t __p, | ||
79 | uint8_t * __buf, size_t __buflen); | ||
80 | |||
81 | extern uint8_t * escrypt_r(escrypt_local_t * __local, | ||
82 | const uint8_t * __passwd, size_t __passwdlen, | ||
83 | const uint8_t * __setting, | ||
84 | uint8_t * __buf, size_t __buflen); | ||
85 | |||
86 | extern uint8_t * escrypt_gensalt_r( | ||
87 | uint32_t __N_log2, uint32_t __r, uint32_t __p, | ||
88 | const uint8_t * __src, size_t __srclen, | ||
89 | uint8_t * __buf, size_t __buflen); | ||
90 | |||
91 | #endif /* !_CRYPTO_SCRYPT_H_ */ | ||
92 | |||
93 | #endif | ||
diff --git a/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/export.h b/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/export.h new file mode 100644 index 00000000..ee5b30f7 --- /dev/null +++ b/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/export.h | |||
@@ -0,0 +1,38 @@ | |||
1 | #ifdef HAVE_CONFIG_H | ||
2 | #include "config.h" | ||
3 | #endif | ||
4 | #ifdef VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */ | ||
5 | |||
6 | #ifndef __SODIUM_EXPORT_H__ | ||
7 | #define __SODIUM_EXPORT_H__ | ||
8 | |||
9 | #ifndef __GNUC__ | ||
10 | # ifdef __attribute__ | ||
11 | # undef __attribute__ | ||
12 | # endif | ||
13 | # define __attribute__(a) | ||
14 | #endif | ||
15 | |||
16 | #ifdef SODIUM_STATIC | ||
17 | # define SODIUM_EXPORT | ||
18 | #else | ||
19 | # if defined(_MSC_VER) | ||
20 | # ifdef DLL_EXPORT | ||
21 | # define SODIUM_EXPORT __declspec(dllexport) | ||
22 | # else | ||
23 | # define SODIUM_EXPORT __declspec(dllimport) | ||
24 | # endif | ||
25 | # else | ||
26 | # if defined(__SUNPRO_C) | ||
27 | # define SODIUM_EXPORT __attribute__ __global | ||
28 | # elif defined(_MSG_VER) | ||
29 | # define SODIUM_EXPORT extern __declspec(dllexport) | ||
30 | # else | ||
31 | # define SODIUM_EXPORT __attribute__ ((visibility ("default"))) | ||
32 | # endif | ||
33 | # endif | ||
34 | #endif | ||
35 | |||
36 | #endif | ||
37 | |||
38 | #endif | ||
diff --git a/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/nosse/pwhash_scryptsalsa208sha256_nosse.c b/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/nosse/pwhash_scryptsalsa208sha256_nosse.c new file mode 100644 index 00000000..97d9ba68 --- /dev/null +++ b/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/nosse/pwhash_scryptsalsa208sha256_nosse.c | |||
@@ -0,0 +1,309 @@ | |||
1 | #ifdef HAVE_CONFIG_H | ||
2 | #include "config.h" | ||
3 | #endif | ||
4 | #ifdef VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */ | ||
5 | |||
6 | /*- | ||
7 | * Copyright 2009 Colin Percival | ||
8 | * Copyright 2013 Alexander Peslyak | ||
9 | * All rights reserved. | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or without | ||
12 | * modification, are permitted provided that the following conditions | ||
13 | * are met: | ||
14 | * 1. Redistributions of source code must retain the above copyright | ||
15 | * notice, this list of conditions and the following disclaimer. | ||
16 | * 2. Redistributions in binary form must reproduce the above copyright | ||
17 | * notice, this list of conditions and the following disclaimer in the | ||
18 | * documentation and/or other materials provided with the distribution. | ||
19 | * | ||
20 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | ||
21 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | ||
24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
26 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
28 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
29 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||
30 | * SUCH DAMAGE. | ||
31 | * | ||
32 | * This file was originally written by Colin Percival as part of the Tarsnap | ||
33 | * online backup system. | ||
34 | */ | ||
35 | |||
36 | #include <errno.h> | ||
37 | #include <limits.h> | ||
38 | #include <stdint.h> | ||
39 | #include <stdlib.h> | ||
40 | #include <string.h> | ||
41 | |||
42 | #include "../pbkdf2-sha256.h" | ||
43 | #include "../sysendian.h" | ||
44 | #include "../crypto_scrypt.h" | ||
45 | |||
46 | static inline void | ||
47 | blkcpy(void * dest, const void * src, size_t len) | ||
48 | { | ||
49 | size_t * D = (size_t *) dest; | ||
50 | const size_t * S = (const size_t *) src; | ||
51 | size_t L = len / sizeof(size_t); | ||
52 | size_t i; | ||
53 | |||
54 | for (i = 0; i < L; i++) | ||
55 | D[i] = S[i]; | ||
56 | } | ||
57 | |||
58 | static inline void | ||
59 | blkxor(void * dest, const void * src, size_t len) | ||
60 | { | ||
61 | size_t * D = (size_t *) dest; | ||
62 | const size_t * S = (const size_t *) src; | ||
63 | size_t L = len / sizeof(size_t); | ||
64 | size_t i; | ||
65 | |||
66 | for (i = 0; i < L; i++) | ||
67 | D[i] ^= S[i]; | ||
68 | } | ||
69 | |||
70 | /** | ||
71 | * salsa20_8(B): | ||
72 | * Apply the salsa20/8 core to the provided block. | ||
73 | */ | ||
74 | static void | ||
75 | salsa20_8(uint32_t B[16]) | ||
76 | { | ||
77 | uint32_t x[16]; | ||
78 | size_t i; | ||
79 | |||
80 | blkcpy(x, B, 64); | ||
81 | for (i = 0; i < 8; i += 2) { | ||
82 | #define R(a,b) (((a) << (b)) | ((a) >> (32 - (b)))) | ||
83 | /* Operate on columns. */ | ||
84 | x[ 4] ^= R(x[ 0]+x[12], 7); x[ 8] ^= R(x[ 4]+x[ 0], 9); | ||
85 | x[12] ^= R(x[ 8]+x[ 4],13); x[ 0] ^= R(x[12]+x[ 8],18); | ||
86 | |||
87 | x[ 9] ^= R(x[ 5]+x[ 1], 7); x[13] ^= R(x[ 9]+x[ 5], 9); | ||
88 | x[ 1] ^= R(x[13]+x[ 9],13); x[ 5] ^= R(x[ 1]+x[13],18); | ||
89 | |||
90 | x[14] ^= R(x[10]+x[ 6], 7); x[ 2] ^= R(x[14]+x[10], 9); | ||
91 | x[ 6] ^= R(x[ 2]+x[14],13); x[10] ^= R(x[ 6]+x[ 2],18); | ||
92 | |||
93 | x[ 3] ^= R(x[15]+x[11], 7); x[ 7] ^= R(x[ 3]+x[15], 9); | ||
94 | x[11] ^= R(x[ 7]+x[ 3],13); x[15] ^= R(x[11]+x[ 7],18); | ||
95 | |||
96 | /* Operate on rows. */ | ||
97 | x[ 1] ^= R(x[ 0]+x[ 3], 7); x[ 2] ^= R(x[ 1]+x[ 0], 9); | ||
98 | x[ 3] ^= R(x[ 2]+x[ 1],13); x[ 0] ^= R(x[ 3]+x[ 2],18); | ||
99 | |||
100 | x[ 6] ^= R(x[ 5]+x[ 4], 7); x[ 7] ^= R(x[ 6]+x[ 5], 9); | ||
101 | x[ 4] ^= R(x[ 7]+x[ 6],13); x[ 5] ^= R(x[ 4]+x[ 7],18); | ||
102 | |||
103 | x[11] ^= R(x[10]+x[ 9], 7); x[ 8] ^= R(x[11]+x[10], 9); | ||
104 | x[ 9] ^= R(x[ 8]+x[11],13); x[10] ^= R(x[ 9]+x[ 8],18); | ||
105 | |||
106 | x[12] ^= R(x[15]+x[14], 7); x[13] ^= R(x[12]+x[15], 9); | ||
107 | x[14] ^= R(x[13]+x[12],13); x[15] ^= R(x[14]+x[13],18); | ||
108 | #undef R | ||
109 | } | ||
110 | for (i = 0; i < 16; i++) | ||
111 | B[i] += x[i]; | ||
112 | } | ||
113 | |||
114 | /** | ||
115 | * blockmix_salsa8(Bin, Bout, X, r): | ||
116 | * Compute Bout = BlockMix_{salsa20/8, r}(Bin). The input Bin must be 128r | ||
117 | * bytes in length; the output Bout must also be the same size. The | ||
118 | * temporary space X must be 64 bytes. | ||
119 | */ | ||
120 | static void | ||
121 | blockmix_salsa8(const uint32_t * Bin, uint32_t * Bout, uint32_t * X, size_t r) | ||
122 | { | ||
123 | size_t i; | ||
124 | |||
125 | /* 1: X <-- B_{2r - 1} */ | ||
126 | blkcpy(X, &Bin[(2 * r - 1) * 16], 64); | ||
127 | |||
128 | /* 2: for i = 0 to 2r - 1 do */ | ||
129 | for (i = 0; i < 2 * r; i += 2) { | ||
130 | /* 3: X <-- H(X \xor B_i) */ | ||
131 | blkxor(X, &Bin[i * 16], 64); | ||
132 | salsa20_8(X); | ||
133 | |||
134 | /* 4: Y_i <-- X */ | ||
135 | /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ | ||
136 | blkcpy(&Bout[i * 8], X, 64); | ||
137 | |||
138 | /* 3: X <-- H(X \xor B_i) */ | ||
139 | blkxor(X, &Bin[i * 16 + 16], 64); | ||
140 | salsa20_8(X); | ||
141 | |||
142 | /* 4: Y_i <-- X */ | ||
143 | /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ | ||
144 | blkcpy(&Bout[i * 8 + r * 16], X, 64); | ||
145 | } | ||
146 | } | ||
147 | |||
148 | /** | ||
149 | * integerify(B, r): | ||
150 | * Return the result of parsing B_{2r-1} as a little-endian integer. | ||
151 | */ | ||
152 | static inline uint64_t | ||
153 | integerify(const void * B, size_t r) | ||
154 | { | ||
155 | const uint32_t * X = (const uint32_t *)((uintptr_t)(B) + (2 * r - 1) * 64); | ||
156 | |||
157 | return (((uint64_t)(X[1]) << 32) + X[0]); | ||
158 | } | ||
159 | |||
160 | /** | ||
161 | * smix(B, r, N, V, XY): | ||
162 | * Compute B = SMix_r(B, N). The input B must be 128r bytes in length; | ||
163 | * the temporary storage V must be 128rN bytes in length; the temporary | ||
164 | * storage XY must be 256r + 64 bytes in length. The value N must be a | ||
165 | * power of 2 greater than 1. The arrays B, V, and XY must be aligned to a | ||
166 | * multiple of 64 bytes. | ||
167 | */ | ||
168 | static void | ||
169 | smix(uint8_t * B, size_t r, uint64_t N, uint32_t * V, uint32_t * XY) | ||
170 | { | ||
171 | uint32_t * X = XY; | ||
172 | uint32_t * Y = &XY[32 * r]; | ||
173 | uint32_t * Z = &XY[64 * r]; | ||
174 | uint64_t i; | ||
175 | uint64_t j; | ||
176 | size_t k; | ||
177 | |||
178 | /* 1: X <-- B */ | ||
179 | for (k = 0; k < 32 * r; k++) | ||
180 | X[k] = le32dec(&B[4 * k]); | ||
181 | |||
182 | /* 2: for i = 0 to N - 1 do */ | ||
183 | for (i = 0; i < N; i += 2) { | ||
184 | /* 3: V_i <-- X */ | ||
185 | blkcpy(&V[i * (32 * r)], X, 128 * r); | ||
186 | |||
187 | /* 4: X <-- H(X) */ | ||
188 | blockmix_salsa8(X, Y, Z, r); | ||
189 | |||
190 | /* 3: V_i <-- X */ | ||
191 | blkcpy(&V[(i + 1) * (32 * r)], Y, 128 * r); | ||
192 | |||
193 | /* 4: X <-- H(X) */ | ||
194 | blockmix_salsa8(Y, X, Z, r); | ||
195 | } | ||
196 | |||
197 | /* 6: for i = 0 to N - 1 do */ | ||
198 | for (i = 0; i < N; i += 2) { | ||
199 | /* 7: j <-- Integerify(X) mod N */ | ||
200 | j = integerify(X, r) & (N - 1); | ||
201 | |||
202 | /* 8: X <-- H(X \xor V_j) */ | ||
203 | blkxor(X, &V[j * (32 * r)], 128 * r); | ||
204 | blockmix_salsa8(X, Y, Z, r); | ||
205 | |||
206 | /* 7: j <-- Integerify(X) mod N */ | ||
207 | j = integerify(Y, r) & (N - 1); | ||
208 | |||
209 | /* 8: X <-- H(X \xor V_j) */ | ||
210 | blkxor(Y, &V[j * (32 * r)], 128 * r); | ||
211 | blockmix_salsa8(Y, X, Z, r); | ||
212 | } | ||
213 | /* 10: B' <-- X */ | ||
214 | for (k = 0; k < 32 * r; k++) | ||
215 | le32enc(&B[4 * k], X[k]); | ||
216 | } | ||
217 | |||
218 | /** | ||
219 | * escrypt_kdf(local, passwd, passwdlen, salt, saltlen, | ||
220 | * N, r, p, buf, buflen): | ||
221 | * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r, | ||
222 | * p, buflen) and write the result into buf. The parameters r, p, and buflen | ||
223 | * must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32. The parameter N | ||
224 | * must be a power of 2 greater than 1. | ||
225 | * | ||
226 | * Return 0 on success; or -1 on error. | ||
227 | */ | ||
228 | int | ||
229 | escrypt_kdf_nosse(escrypt_local_t * local, | ||
230 | const uint8_t * passwd, size_t passwdlen, | ||
231 | const uint8_t * salt, size_t saltlen, | ||
232 | uint64_t N, uint32_t _r, uint32_t _p, | ||
233 | uint8_t * buf, size_t buflen) | ||
234 | { | ||
235 | size_t B_size, V_size, XY_size, need; | ||
236 | uint8_t * B; | ||
237 | uint32_t * V, * XY; | ||
238 | size_t r = _r, p = _p; | ||
239 | uint32_t i; | ||
240 | |||
241 | /* Sanity-check parameters. */ | ||
242 | #if SIZE_MAX > UINT32_MAX | ||
243 | if (buflen > (((uint64_t)(1) << 32) - 1) * 32) { | ||
244 | errno = EFBIG; | ||
245 | return -1; | ||
246 | } | ||
247 | #endif | ||
248 | if ((uint64_t)(r) * (uint64_t)(p) >= (1 << 30)) { | ||
249 | errno = EFBIG; | ||
250 | return -1; | ||
251 | } | ||
252 | if (((N & (N - 1)) != 0) || (N < 2)) { | ||
253 | errno = EINVAL; | ||
254 | return -1; | ||
255 | } | ||
256 | if (r == 0 || p == 0) { | ||
257 | errno = EINVAL; | ||
258 | return -1; | ||
259 | } | ||
260 | if ((r > SIZE_MAX / 128 / p) || | ||
261 | #if SIZE_MAX / 256 <= UINT32_MAX | ||
262 | (r > SIZE_MAX / 256) || | ||
263 | #endif | ||
264 | (N > SIZE_MAX / 128 / r)) { | ||
265 | errno = ENOMEM; | ||
266 | return -1; | ||
267 | } | ||
268 | |||
269 | /* Allocate memory. */ | ||
270 | B_size = (size_t)128 * r * p; | ||
271 | V_size = (size_t)128 * r * N; | ||
272 | need = B_size + V_size; | ||
273 | if (need < V_size) { | ||
274 | errno = ENOMEM; | ||
275 | return -1; | ||
276 | } | ||
277 | XY_size = (size_t)256 * r + 64; | ||
278 | need += XY_size; | ||
279 | if (need < XY_size) { | ||
280 | errno = ENOMEM; | ||
281 | return -1; | ||
282 | } | ||
283 | if (local->size < need) { | ||
284 | if (free_region(local)) | ||
285 | return -1; | ||
286 | if (!alloc_region(local, need)) | ||
287 | return -1; | ||
288 | } | ||
289 | B = (uint8_t *)local->aligned; | ||
290 | V = (uint32_t *)((uint8_t *)B + B_size); | ||
291 | XY = (uint32_t *)((uint8_t *)V + V_size); | ||
292 | |||
293 | /* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */ | ||
294 | PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, 1, B, B_size); | ||
295 | |||
296 | /* 2: for i = 0 to p - 1 do */ | ||
297 | for (i = 0; i < p; i++) { | ||
298 | /* 3: B_i <-- MF(B_i, N) */ | ||
299 | smix(&B[(size_t)128 * i * r], r, N, V, XY); | ||
300 | } | ||
301 | |||
302 | /* 5: DK <-- PBKDF2(P, B, 1, dkLen) */ | ||
303 | PBKDF2_SHA256(passwd, passwdlen, B, B_size, 1, buf, buflen); | ||
304 | |||
305 | /* Success! */ | ||
306 | return 0; | ||
307 | } | ||
308 | |||
309 | #endif | ||
diff --git a/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/note_to_maintainers.txt b/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/note_to_maintainers.txt new file mode 100644 index 00000000..66bbfe2d --- /dev/null +++ b/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/note_to_maintainers.txt | |||
@@ -0,0 +1,14 @@ | |||
1 | This folder is only meant for use with nacl, i.e. when sodium is unavailable. | ||
2 | |||
3 | |||
4 | The files in this folder were mostly copied from | ||
5 | https://github.com/jedisct1/libsodium/tree/0.7.0/src/libsodium/crypto_pwhash/scryptsalsa208sha256, | ||
6 | with #ifdef VANILLA_NACL added around each of them as required for this module. | ||
7 | |||
8 | export.h, utils.h, and runtime.h were copied from | ||
9 | https://github.com/jedisct1/libsodium/tree/0.7.0/src/libsodium/include/sodium. | ||
10 | utils.h was significantly truncated. | ||
11 | |||
12 | utils.c and runtime.c were copied from | ||
13 | https://github.com/jedisct1/libsodium/blob/0.7.0/src/libsodium/sodium. | ||
14 | utils.c was also significantly truncated. | ||
diff --git a/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/pbkdf2-sha256.c b/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/pbkdf2-sha256.c new file mode 100644 index 00000000..3dfe54db --- /dev/null +++ b/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/pbkdf2-sha256.c | |||
@@ -0,0 +1,97 @@ | |||
1 | #ifdef HAVE_CONFIG_H | ||
2 | #include "config.h" | ||
3 | #endif | ||
4 | #ifdef VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */ | ||
5 | |||
6 | /*- | ||
7 | * Copyright 2005,2007,2009 Colin Percival | ||
8 | * All rights reserved. | ||
9 | * | ||
10 | * Redistribution and use in source and binary forms, with or without | ||
11 | * modification, are permitted provided that the following conditions | ||
12 | * are met: | ||
13 | * 1. Redistributions of source code must retain the above copyright | ||
14 | * notice, this list of conditions and the following disclaimer. | ||
15 | * 2. Redistributions in binary form must reproduce the above copyright | ||
16 | * notice, this list of conditions and the following disclaimer in the | ||
17 | * documentation and/or other materials provided with the distribution. | ||
18 | * | ||
19 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | ||
20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | ||
23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||
29 | * SUCH DAMAGE. | ||
30 | */ | ||
31 | |||
32 | #include <sys/types.h> | ||
33 | |||
34 | #include <stdint.h> | ||
35 | #include <stdlib.h> | ||
36 | #include <string.h> | ||
37 | |||
38 | #include <crypto_hash_sha256.h> | ||
39 | #include <crypto_auth_hmacsha256.h> | ||
40 | |||
41 | #include "pbkdf2-sha256.h" | ||
42 | #include "sysendian.h" | ||
43 | #include "utils.h" | ||
44 | |||
45 | /** | ||
46 | * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen): | ||
47 | * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and | ||
48 | * write the output to buf. The value dkLen must be at most 32 * (2^32 - 1). | ||
49 | */ | ||
50 | void | ||
51 | PBKDF2_SHA256(const uint8_t * passwd, size_t passwdlen, const uint8_t * salt, | ||
52 | size_t saltlen, uint64_t c, uint8_t * buf, size_t dkLen) | ||
53 | { | ||
54 | uint8_t key[32] = {0}; | ||
55 | size_t i; | ||
56 | uint8_t salt_and_ivec[saltlen + 4]; | ||
57 | uint8_t U[32]; | ||
58 | uint8_t T[32]; | ||
59 | uint64_t j; | ||
60 | int k; | ||
61 | size_t clen; | ||
62 | |||
63 | if (passwdlen > 32) { | ||
64 | /* For some reason libsodium allows 64byte keys meaning keys | ||
65 | * between 32byte and 64bytes are not compatible with libsodium. | ||
66 | toxencryptsave should only give 32byte passwds so this isn't an issue here.*/ | ||
67 | crypto_hash_sha256(key, passwd, passwdlen); | ||
68 | } else { | ||
69 | memcpy(key, passwd, passwdlen); | ||
70 | } | ||
71 | |||
72 | memcpy(salt_and_ivec, salt, saltlen); | ||
73 | |||
74 | for (i = 0; i * 32 < dkLen; i++) { | ||
75 | be32enc(salt_and_ivec + saltlen, (uint32_t)(i + 1)); | ||
76 | crypto_auth_hmacsha256(U, salt_and_ivec, sizeof(salt_and_ivec), key); | ||
77 | |||
78 | memcpy(T, U, 32); | ||
79 | |||
80 | for (j = 2; j <= c; j++) { | ||
81 | crypto_auth_hmacsha256(U, U, 32, key); | ||
82 | |||
83 | for (k = 0; k < 32; k++) { | ||
84 | T[k] ^= U[k]; | ||
85 | } | ||
86 | } | ||
87 | |||
88 | clen = dkLen - i * 32; | ||
89 | if (clen > 32) { | ||
90 | clen = 32; | ||
91 | } | ||
92 | memcpy(&buf[i * 32], T, clen); | ||
93 | } | ||
94 | sodium_memzero((void *) key, sizeof(key)); | ||
95 | } | ||
96 | |||
97 | #endif | ||
diff --git a/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/pbkdf2-sha256.h b/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/pbkdf2-sha256.h new file mode 100644 index 00000000..b74bc6a3 --- /dev/null +++ b/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/pbkdf2-sha256.h | |||
@@ -0,0 +1,52 @@ | |||
1 | #ifdef HAVE_CONFIG_H | ||
2 | #include "config.h" | ||
3 | #endif | ||
4 | #ifdef VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */ | ||
5 | |||
6 | /*- | ||
7 | * Copyright 2005,2007,2009 Colin Percival | ||
8 | * All rights reserved. | ||
9 | * | ||
10 | * Redistribution and use in source and binary forms, with or without | ||
11 | * modification, are permitted provided that the following conditions | ||
12 | * are met: | ||
13 | * 1. Redistributions of source code must retain the above copyright | ||
14 | * notice, this list of conditions and the following disclaimer. | ||
15 | * 2. Redistributions in binary form must reproduce the above copyright | ||
16 | * notice, this list of conditions and the following disclaimer in the | ||
17 | * documentation and/or other materials provided with the distribution. | ||
18 | * | ||
19 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | ||
20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | ||
23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||
29 | * SUCH DAMAGE. | ||
30 | * | ||
31 | */ | ||
32 | |||
33 | #ifndef _SHA256_H_ | ||
34 | #define _SHA256_H_ | ||
35 | |||
36 | #include <sys/types.h> | ||
37 | |||
38 | #include <stdint.h> | ||
39 | |||
40 | #include "crypto_auth_hmacsha256.h" | ||
41 | |||
42 | /** | ||
43 | * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen): | ||
44 | * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and | ||
45 | * write the output to buf. The value dkLen must be at most 32 * (2^32 - 1). | ||
46 | */ | ||
47 | void PBKDF2_SHA256(const uint8_t *, size_t, const uint8_t *, size_t, | ||
48 | uint64_t, uint8_t *, size_t); | ||
49 | |||
50 | #endif /* !_SHA256_H_ */ | ||
51 | |||
52 | #endif | ||
diff --git a/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/pwhash_scryptsalsa208sha256.c b/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/pwhash_scryptsalsa208sha256.c new file mode 100644 index 00000000..52c51abc --- /dev/null +++ b/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/pwhash_scryptsalsa208sha256.c | |||
@@ -0,0 +1,211 @@ | |||
1 | #ifdef HAVE_CONFIG_H | ||
2 | #include "config.h" | ||
3 | #endif | ||
4 | #ifdef VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */ | ||
5 | |||
6 | #include <errno.h> | ||
7 | #include <limits.h> | ||
8 | #include <stddef.h> | ||
9 | #include <stdint.h> | ||
10 | #include <string.h> | ||
11 | //#include <stdio.h> | ||
12 | |||
13 | #include "crypto_pwhash_scryptsalsa208sha256.h" | ||
14 | #include "crypto_scrypt.h" | ||
15 | #include "randombytes.h" | ||
16 | #include "utils.h" | ||
17 | |||
18 | #define SETTING_SIZE(saltbytes) \ | ||
19 | (sizeof "$7$" - 1U) + \ | ||
20 | (1U /* N_log2 */) + (5U /* r */) + (5U /* p */) + BYTES2CHARS(saltbytes) | ||
21 | |||
22 | static int | ||
23 | pickparams(unsigned long long opslimit, const size_t memlimit, | ||
24 | uint32_t * const N_log2, uint32_t * const p, uint32_t * const r) | ||
25 | { | ||
26 | unsigned long long maxN; | ||
27 | unsigned long long maxrp; | ||
28 | |||
29 | if (opslimit < 32768) { | ||
30 | opslimit = 32768; | ||
31 | } | ||
32 | *r = 8; | ||
33 | if (opslimit < memlimit / 32) { | ||
34 | *p = 1; | ||
35 | maxN = opslimit / (*r * 4); | ||
36 | for (*N_log2 = 1; *N_log2 < 63; *N_log2 += 1) { | ||
37 | if ((uint64_t)(1) << *N_log2 > maxN / 2) { | ||
38 | break; | ||
39 | } | ||
40 | } | ||
41 | } else { | ||
42 | maxN = memlimit / (*r * 128); | ||
43 | for (*N_log2 = 1; *N_log2 < 63; *N_log2 += 1) { | ||
44 | if ((uint64_t) (1) << *N_log2 > maxN / 2) { | ||
45 | break; | ||
46 | } | ||
47 | } | ||
48 | maxrp = (opslimit / 4) / ((uint64_t) (1) << *N_log2); | ||
49 | if (maxrp > 0x3fffffff) { | ||
50 | maxrp = 0x3fffffff; | ||
51 | } | ||
52 | *p = (uint32_t) (maxrp) / *r; | ||
53 | } | ||
54 | return 0; | ||
55 | } | ||
56 | |||
57 | size_t | ||
58 | crypto_pwhash_scryptsalsa208sha256_saltbytes(void) | ||
59 | { | ||
60 | return crypto_pwhash_scryptsalsa208sha256_SALTBYTES; | ||
61 | } | ||
62 | |||
63 | size_t | ||
64 | crypto_pwhash_scryptsalsa208sha256_strbytes(void) | ||
65 | { | ||
66 | return crypto_pwhash_scryptsalsa208sha256_STRBYTES; | ||
67 | } | ||
68 | |||
69 | const char * | ||
70 | crypto_pwhash_scryptsalsa208sha256_strprefix(void) | ||
71 | { | ||
72 | return crypto_pwhash_scryptsalsa208sha256_STRPREFIX; | ||
73 | } | ||
74 | |||
75 | size_t | ||
76 | crypto_pwhash_scryptsalsa208sha256_opslimit_interactive(void) | ||
77 | { | ||
78 | return crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE; | ||
79 | } | ||
80 | |||
81 | size_t | ||
82 | crypto_pwhash_scryptsalsa208sha256_memlimit_interactive(void) | ||
83 | { | ||
84 | return crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE; | ||
85 | } | ||
86 | |||
87 | size_t | ||
88 | crypto_pwhash_scryptsalsa208sha256_opslimit_sensitive(void) | ||
89 | { | ||
90 | return crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_SENSITIVE; | ||
91 | } | ||
92 | |||
93 | size_t | ||
94 | crypto_pwhash_scryptsalsa208sha256_memlimit_sensitive(void) | ||
95 | { | ||
96 | return crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_SENSITIVE; | ||
97 | } | ||
98 | |||
99 | int | ||
100 | crypto_pwhash_scryptsalsa208sha256(unsigned char * const out, | ||
101 | unsigned long long outlen, | ||
102 | const char * const passwd, | ||
103 | unsigned long long passwdlen, | ||
104 | const unsigned char * const salt, | ||
105 | unsigned long long opslimit, | ||
106 | size_t memlimit) | ||
107 | { | ||
108 | //fprintf(stderr, "Doing that dirty thang!!!!\n"); | ||
109 | uint32_t N_log2; | ||
110 | uint32_t p; | ||
111 | uint32_t r; | ||
112 | |||
113 | memset(out, 0, outlen); | ||
114 | if (passwdlen > SIZE_MAX || outlen > SIZE_MAX) { | ||
115 | errno = EFBIG; | ||
116 | return -1; | ||
117 | } | ||
118 | if (pickparams(opslimit, memlimit, &N_log2, &p, &r) != 0) { | ||
119 | errno = EINVAL; | ||
120 | return -1; | ||
121 | } | ||
122 | return crypto_pwhash_scryptsalsa208sha256_ll((const uint8_t *) passwd, | ||
123 | (size_t) passwdlen, | ||
124 | (const uint8_t *) salt, | ||
125 | crypto_pwhash_scryptsalsa208sha256_SALTBYTES, | ||
126 | (uint64_t) (1) << N_log2, r, p, | ||
127 | out, (size_t) outlen); | ||
128 | } | ||
129 | |||
130 | int | ||
131 | crypto_pwhash_scryptsalsa208sha256_str(char out[crypto_pwhash_scryptsalsa208sha256_STRBYTES], | ||
132 | const char * const passwd, | ||
133 | unsigned long long passwdlen, | ||
134 | unsigned long long opslimit, | ||
135 | size_t memlimit) | ||
136 | { | ||
137 | uint8_t salt[crypto_pwhash_scryptsalsa208sha256_STRSALTBYTES]; | ||
138 | char setting[crypto_pwhash_scryptsalsa208sha256_STRSETTINGBYTES + 1U]; | ||
139 | escrypt_local_t escrypt_local; | ||
140 | uint32_t N_log2; | ||
141 | uint32_t p; | ||
142 | uint32_t r; | ||
143 | |||
144 | memset(out, 0, crypto_pwhash_scryptsalsa208sha256_STRBYTES); | ||
145 | if (passwdlen > SIZE_MAX) { | ||
146 | errno = EFBIG; | ||
147 | return -1; | ||
148 | } | ||
149 | if (pickparams(opslimit, memlimit, &N_log2, &p, &r) != 0) { | ||
150 | errno = EINVAL; | ||
151 | return -1; | ||
152 | } | ||
153 | randombytes(salt, sizeof salt); | ||
154 | if (escrypt_gensalt_r(N_log2, r, p, salt, sizeof salt, | ||
155 | (uint8_t *) setting, sizeof setting) == NULL) { | ||
156 | errno = EINVAL; | ||
157 | return -1; | ||
158 | } | ||
159 | if (escrypt_init_local(&escrypt_local) != 0) { | ||
160 | return -1; | ||
161 | } | ||
162 | if (escrypt_r(&escrypt_local, (const uint8_t *) passwd, (size_t) passwdlen, | ||
163 | (const uint8_t *) setting, (uint8_t *) out, | ||
164 | crypto_pwhash_scryptsalsa208sha256_STRBYTES) == NULL) { | ||
165 | escrypt_free_local(&escrypt_local); | ||
166 | errno = EINVAL; | ||
167 | return -1; | ||
168 | } | ||
169 | escrypt_free_local(&escrypt_local); | ||
170 | |||
171 | (void) sizeof | ||
172 | (int[SETTING_SIZE(crypto_pwhash_scryptsalsa208sha256_STRSALTBYTES) | ||
173 | == crypto_pwhash_scryptsalsa208sha256_STRSETTINGBYTES ? 1 : -1]); | ||
174 | (void) sizeof | ||
175 | (int[crypto_pwhash_scryptsalsa208sha256_STRSETTINGBYTES + 1U + | ||
176 | crypto_pwhash_scryptsalsa208sha256_STRHASHBYTES_ENCODED + 1U | ||
177 | == crypto_pwhash_scryptsalsa208sha256_STRBYTES ? 1 : -1]); | ||
178 | |||
179 | return 0; | ||
180 | } | ||
181 | |||
182 | int | ||
183 | crypto_pwhash_scryptsalsa208sha256_str_verify(const char str[crypto_pwhash_scryptsalsa208sha256_STRBYTES], | ||
184 | const char * const passwd, | ||
185 | unsigned long long passwdlen) | ||
186 | { | ||
187 | char wanted[crypto_pwhash_scryptsalsa208sha256_STRBYTES]; | ||
188 | escrypt_local_t escrypt_local; | ||
189 | int ret = -1; | ||
190 | |||
191 | if (memchr(str, 0, crypto_pwhash_scryptsalsa208sha256_STRBYTES) != | ||
192 | &str[crypto_pwhash_scryptsalsa208sha256_STRBYTES - 1U]) { | ||
193 | return -1; | ||
194 | } | ||
195 | if (escrypt_init_local(&escrypt_local) != 0) { | ||
196 | return -1; | ||
197 | } | ||
198 | if (escrypt_r(&escrypt_local, (const uint8_t *) passwd, (size_t) passwdlen, | ||
199 | (const uint8_t *) str, (uint8_t *) wanted, | ||
200 | sizeof wanted) == NULL) { | ||
201 | escrypt_free_local(&escrypt_local); | ||
202 | return -1; | ||
203 | } | ||
204 | escrypt_free_local(&escrypt_local); | ||
205 | ret = sodium_memcmp(wanted, str, sizeof wanted); | ||
206 | sodium_memzero(wanted, sizeof wanted); | ||
207 | |||
208 | return ret; | ||
209 | } | ||
210 | |||
211 | #endif | ||
diff --git a/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/runtime.c b/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/runtime.c new file mode 100644 index 00000000..9b5c5131 --- /dev/null +++ b/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/runtime.c | |||
@@ -0,0 +1,140 @@ | |||
1 | #ifdef HAVE_CONFIG_H | ||
2 | #include "config.h" | ||
3 | #endif | ||
4 | #ifdef VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */ | ||
5 | |||
6 | #ifdef HAVE_ANDROID_GETCPUFEATURES | ||
7 | # include <cpu-features.h> | ||
8 | #endif | ||
9 | |||
10 | #include "runtime.h" | ||
11 | |||
12 | typedef struct CPUFeatures_ { | ||
13 | int initialized; | ||
14 | int has_neon; | ||
15 | int has_sse2; | ||
16 | int has_sse3; | ||
17 | } CPUFeatures; | ||
18 | |||
19 | static CPUFeatures _cpu_features; | ||
20 | |||
21 | #define CPUID_SSE2 0x04000000 | ||
22 | #define CPUIDECX_SSE3 0x00000001 | ||
23 | |||
24 | static int | ||
25 | _sodium_runtime_arm_cpu_features(CPUFeatures * const cpu_features) | ||
26 | { | ||
27 | #ifndef __arm__ | ||
28 | cpu_features->has_neon = 0; | ||
29 | return -1; | ||
30 | #else | ||
31 | # ifdef __APPLE__ | ||
32 | # ifdef __ARM_NEON__ | ||
33 | cpu_features->has_neon = 1; | ||
34 | # else | ||
35 | cpu_features->has_neon = 0; | ||
36 | # endif | ||
37 | # elif defined(HAVE_ANDROID_GETCPUFEATURES) && defined(ANDROID_CPU_ARM_FEATURE_NEON) | ||
38 | cpu_features->has_neon = | ||
39 | (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0x0; | ||
40 | # else | ||
41 | cpu_features->has_neon = 0; | ||
42 | # endif | ||
43 | return 0; | ||
44 | #endif | ||
45 | } | ||
46 | |||
47 | static void | ||
48 | _cpuid(unsigned int cpu_info[4U], const unsigned int cpu_info_type) | ||
49 | { | ||
50 | #ifdef _MSC_VER | ||
51 | __cpuidex((int *) cpu_info, cpu_info_type, 0); | ||
52 | #elif defined(HAVE_CPUID) | ||
53 | cpu_info[0] = cpu_info[1] = cpu_info[2] = cpu_info[3] = 0; | ||
54 | # ifdef __i386__ | ||
55 | __asm__ __volatile__ ("pushfl; pushfl; " | ||
56 | "popl %0; " | ||
57 | "movl %0, %1; xorl %2, %0; " | ||
58 | "pushl %0; " | ||
59 | "popfl; pushfl; popl %0; popfl" : | ||
60 | "=&r" (cpu_info[0]), "=&r" (cpu_info[1]) : | ||
61 | "i" (0x200000)); | ||
62 | if (((cpu_info[0] ^ cpu_info[1]) & 0x200000) == 0x0) { | ||
63 | return; | ||
64 | } | ||
65 | # endif | ||
66 | # ifdef __i386__ | ||
67 | __asm__ __volatile__ ("xchgl %%ebx, %k1; cpuid; xchgl %%ebx, %k1" : | ||
68 | "=a" (cpu_info[0]), "=&r" (cpu_info[1]), | ||
69 | "=c" (cpu_info[2]), "=d" (cpu_info[3]) : | ||
70 | "0" (cpu_info_type), "2" (0U)); | ||
71 | # elif defined(__x86_64__) | ||
72 | __asm__ __volatile__ ("xchgq %%rbx, %q1; cpuid; xchgq %%rbx, %q1" : | ||
73 | "=a" (cpu_info[0]), "=&r" (cpu_info[1]), | ||
74 | "=c" (cpu_info[2]), "=d" (cpu_info[3]) : | ||
75 | "0" (cpu_info_type), "2" (0U)); | ||
76 | # else | ||
77 | __asm__ __volatile__ ("cpuid" : | ||
78 | "=a" (cpu_info[0]), "=b" (cpu_info[1]), | ||
79 | "=c" (cpu_info[2]), "=d" (cpu_info[3]) : | ||
80 | "0" (cpu_info_type), "2" (0U)); | ||
81 | # endif | ||
82 | #else | ||
83 | cpu_info[0] = cpu_info[1] = cpu_info[2] = cpu_info[3] = 0; | ||
84 | #endif | ||
85 | } | ||
86 | |||
87 | static int | ||
88 | _sodium_runtime_intel_cpu_features(CPUFeatures * const cpu_features) | ||
89 | { | ||
90 | unsigned int cpu_info[4]; | ||
91 | unsigned int id; | ||
92 | |||
93 | _cpuid(cpu_info, 0x0); | ||
94 | if ((id = cpu_info[0]) == 0U) { | ||
95 | return -1; | ||
96 | } | ||
97 | _cpuid(cpu_info, 0x00000001); | ||
98 | #ifndef HAVE_EMMINTRIN_H | ||
99 | cpu_features->has_sse2 = 0; | ||
100 | #else | ||
101 | cpu_features->has_sse2 = ((cpu_info[3] & CPUID_SSE2) != 0x0); | ||
102 | #endif | ||
103 | |||
104 | #ifndef HAVE_PMMINTRIN_H | ||
105 | cpu_features->has_sse3 = 0; | ||
106 | #else | ||
107 | cpu_features->has_sse3 = ((cpu_info[2] & CPUIDECX_SSE3) != 0x0); | ||
108 | #endif | ||
109 | |||
110 | return 0; | ||
111 | } | ||
112 | |||
113 | int | ||
114 | sodium_runtime_get_cpu_features(void) | ||
115 | { | ||
116 | int ret = -1; | ||
117 | |||
118 | ret &= _sodium_runtime_arm_cpu_features(&_cpu_features); | ||
119 | ret &= _sodium_runtime_intel_cpu_features(&_cpu_features); | ||
120 | _cpu_features.initialized = 1; | ||
121 | |||
122 | return ret; | ||
123 | } | ||
124 | |||
125 | int | ||
126 | sodium_runtime_has_neon(void) { | ||
127 | return _cpu_features.has_neon; | ||
128 | } | ||
129 | |||
130 | int | ||
131 | sodium_runtime_has_sse2(void) { | ||
132 | return _cpu_features.has_sse2; | ||
133 | } | ||
134 | |||
135 | int | ||
136 | sodium_runtime_has_sse3(void) { | ||
137 | return _cpu_features.has_sse3; | ||
138 | } | ||
139 | |||
140 | #endif | ||
diff --git a/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/runtime.h b/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/runtime.h new file mode 100644 index 00000000..874915ef --- /dev/null +++ b/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/runtime.h | |||
@@ -0,0 +1,33 @@ | |||
1 | #ifdef HAVE_CONFIG_H | ||
2 | #include "config.h" | ||
3 | #endif | ||
4 | #ifdef VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */ | ||
5 | |||
6 | #ifndef __SODIUM_RUNTIME_H__ | ||
7 | #define __SODIUM_RUNTIME_H__ 1 | ||
8 | |||
9 | #include "export.h" | ||
10 | |||
11 | #ifdef __cplusplus | ||
12 | extern "C" { | ||
13 | #endif | ||
14 | |||
15 | SODIUM_EXPORT | ||
16 | int sodium_runtime_get_cpu_features(void); | ||
17 | |||
18 | SODIUM_EXPORT | ||
19 | int sodium_runtime_has_neon(void); | ||
20 | |||
21 | SODIUM_EXPORT | ||
22 | int sodium_runtime_has_sse2(void); | ||
23 | |||
24 | SODIUM_EXPORT | ||
25 | int sodium_runtime_has_sse3(void); | ||
26 | |||
27 | #ifdef __cplusplus | ||
28 | } | ||
29 | #endif | ||
30 | |||
31 | #endif | ||
32 | |||
33 | #endif | ||
diff --git a/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/scrypt_platform.c b/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/scrypt_platform.c new file mode 100644 index 00000000..58196514 --- /dev/null +++ b/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/scrypt_platform.c | |||
@@ -0,0 +1,107 @@ | |||
1 | #ifdef HAVE_CONFIG_H | ||
2 | #include "config.h" | ||
3 | #endif | ||
4 | #ifdef VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */ | ||
5 | |||
6 | /*- | ||
7 | * Copyright 2013 Alexander Peslyak | ||
8 | * All rights reserved. | ||
9 | * | ||
10 | * Redistribution and use in source and binary forms, with or without | ||
11 | * modification, are permitted. | ||
12 | * | ||
13 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | ||
14 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
16 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | ||
17 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
18 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
19 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
20 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
21 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
22 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||
23 | * SUCH DAMAGE. | ||
24 | */ | ||
25 | |||
26 | #ifdef HAVE_SYS_MMAN_H | ||
27 | # include <sys/mman.h> | ||
28 | #endif | ||
29 | #include <errno.h> | ||
30 | #include <stdlib.h> | ||
31 | |||
32 | #include "crypto_scrypt.h" | ||
33 | #include "runtime.h" | ||
34 | |||
35 | #if !defined(MAP_ANON) && defined(MAP_ANONYMOUS) | ||
36 | # define MAP_ANON MAP_ANONYMOUS | ||
37 | #endif | ||
38 | |||
39 | void * | ||
40 | alloc_region(escrypt_region_t * region, size_t size) | ||
41 | { | ||
42 | uint8_t * base, * aligned; | ||
43 | #ifdef MAP_ANON | ||
44 | if ((base = (uint8_t *) mmap(NULL, size, PROT_READ | PROT_WRITE, | ||
45 | #ifdef MAP_NOCORE | ||
46 | MAP_ANON | MAP_PRIVATE | MAP_NOCORE, | ||
47 | #else | ||
48 | MAP_ANON | MAP_PRIVATE, | ||
49 | #endif | ||
50 | -1, 0)) == MAP_FAILED) | ||
51 | base = NULL; | ||
52 | aligned = base; | ||
53 | #elif defined(HAVE_POSIX_MEMALIGN) | ||
54 | if ((errno = posix_memalign((void **) &base, 64, size)) != 0) | ||
55 | base = NULL; | ||
56 | aligned = base; | ||
57 | #else | ||
58 | base = aligned = NULL; | ||
59 | if (size + 63 < size) | ||
60 | errno = ENOMEM; | ||
61 | else if ((base = (uint8_t *) malloc(size + 63)) != NULL) { | ||
62 | aligned = base + 63; | ||
63 | aligned -= (uintptr_t)aligned & 63; | ||
64 | } | ||
65 | #endif | ||
66 | region->base = base; | ||
67 | region->aligned = aligned; | ||
68 | region->size = base ? size : 0; | ||
69 | return aligned; | ||
70 | } | ||
71 | |||
72 | static inline void | ||
73 | init_region(escrypt_region_t * region) | ||
74 | { | ||
75 | region->base = region->aligned = NULL; | ||
76 | region->size = 0; | ||
77 | } | ||
78 | |||
79 | int | ||
80 | free_region(escrypt_region_t * region) | ||
81 | { | ||
82 | if (region->base) { | ||
83 | #ifdef MAP_ANON | ||
84 | if (munmap(region->base, region->size)) | ||
85 | return -1; | ||
86 | #else | ||
87 | free(region->base); | ||
88 | #endif | ||
89 | } | ||
90 | init_region(region); | ||
91 | return 0; | ||
92 | } | ||
93 | |||
94 | int | ||
95 | escrypt_init_local(escrypt_local_t * local) | ||
96 | { | ||
97 | init_region(local); | ||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | int | ||
102 | escrypt_free_local(escrypt_local_t * local) | ||
103 | { | ||
104 | return free_region(local); | ||
105 | } | ||
106 | |||
107 | #endif | ||
diff --git a/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/sse/pwhash_scryptsalsa208sha256_sse.c b/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/sse/pwhash_scryptsalsa208sha256_sse.c new file mode 100644 index 00000000..856a655e --- /dev/null +++ b/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/sse/pwhash_scryptsalsa208sha256_sse.c | |||
@@ -0,0 +1,398 @@ | |||
1 | #ifdef HAVE_CONFIG_H | ||
2 | #include "config.h" | ||
3 | #endif | ||
4 | #ifdef VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */ | ||
5 | |||
6 | /*- | ||
7 | * Copyright 2009 Colin Percival | ||
8 | * Copyright 2012,2013 Alexander Peslyak | ||
9 | * All rights reserved. | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or without | ||
12 | * modification, are permitted provided that the following conditions | ||
13 | * are met: | ||
14 | * 1. Redistributions of source code must retain the above copyright | ||
15 | * notice, this list of conditions and the following disclaimer. | ||
16 | * 2. Redistributions in binary form must reproduce the above copyright | ||
17 | * notice, this list of conditions and the following disclaimer in the | ||
18 | * documentation and/or other materials provided with the distribution. | ||
19 | * | ||
20 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | ||
21 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | ||
24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
26 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
28 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
29 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||
30 | * SUCH DAMAGE. | ||
31 | * | ||
32 | * This file was originally written by Colin Percival as part of the Tarsnap | ||
33 | * online backup system. | ||
34 | */ | ||
35 | |||
36 | #if defined(HAVE_EMMINTRIN_H) || defined(_MSC_VER) | ||
37 | #if __GNUC__ | ||
38 | # pragma GCC target("sse2") | ||
39 | #endif | ||
40 | #include <emmintrin.h> | ||
41 | #if defined(__XOP__) && defined(DISABLED) | ||
42 | # include <x86intrin.h> | ||
43 | #endif | ||
44 | |||
45 | #include <errno.h> | ||
46 | #include <limits.h> | ||
47 | #include <stdint.h> | ||
48 | #include <stdlib.h> | ||
49 | #include <string.h> | ||
50 | |||
51 | #include "../pbkdf2-sha256.h" | ||
52 | #include "../sysendian.h" | ||
53 | #include "../crypto_scrypt.h" | ||
54 | |||
55 | #if defined(__XOP__) && defined(DISABLED) | ||
56 | #define ARX(out, in1, in2, s) \ | ||
57 | out = _mm_xor_si128(out, _mm_roti_epi32(_mm_add_epi32(in1, in2), s)); | ||
58 | #else | ||
59 | #define ARX(out, in1, in2, s) \ | ||
60 | { \ | ||
61 | __m128i T = _mm_add_epi32(in1, in2); \ | ||
62 | out = _mm_xor_si128(out, _mm_slli_epi32(T, s)); \ | ||
63 | out = _mm_xor_si128(out, _mm_srli_epi32(T, 32-s)); \ | ||
64 | } | ||
65 | #endif | ||
66 | |||
67 | #define SALSA20_2ROUNDS \ | ||
68 | /* Operate on "columns". */ \ | ||
69 | ARX(X1, X0, X3, 7) \ | ||
70 | ARX(X2, X1, X0, 9) \ | ||
71 | ARX(X3, X2, X1, 13) \ | ||
72 | ARX(X0, X3, X2, 18) \ | ||
73 | \ | ||
74 | /* Rearrange data. */ \ | ||
75 | X1 = _mm_shuffle_epi32(X1, 0x93); \ | ||
76 | X2 = _mm_shuffle_epi32(X2, 0x4E); \ | ||
77 | X3 = _mm_shuffle_epi32(X3, 0x39); \ | ||
78 | \ | ||
79 | /* Operate on "rows". */ \ | ||
80 | ARX(X3, X0, X1, 7) \ | ||
81 | ARX(X2, X3, X0, 9) \ | ||
82 | ARX(X1, X2, X3, 13) \ | ||
83 | ARX(X0, X1, X2, 18) \ | ||
84 | \ | ||
85 | /* Rearrange data. */ \ | ||
86 | X1 = _mm_shuffle_epi32(X1, 0x39); \ | ||
87 | X2 = _mm_shuffle_epi32(X2, 0x4E); \ | ||
88 | X3 = _mm_shuffle_epi32(X3, 0x93); | ||
89 | |||
90 | /** | ||
91 | * Apply the salsa20/8 core to the block provided in (X0 ... X3) ^ (Z0 ... Z3). | ||
92 | */ | ||
93 | #define SALSA20_8_XOR(in, out) \ | ||
94 | { \ | ||
95 | __m128i Y0 = X0 = _mm_xor_si128(X0, (in)[0]); \ | ||
96 | __m128i Y1 = X1 = _mm_xor_si128(X1, (in)[1]); \ | ||
97 | __m128i Y2 = X2 = _mm_xor_si128(X2, (in)[2]); \ | ||
98 | __m128i Y3 = X3 = _mm_xor_si128(X3, (in)[3]); \ | ||
99 | SALSA20_2ROUNDS \ | ||
100 | SALSA20_2ROUNDS \ | ||
101 | SALSA20_2ROUNDS \ | ||
102 | SALSA20_2ROUNDS \ | ||
103 | (out)[0] = X0 = _mm_add_epi32(X0, Y0); \ | ||
104 | (out)[1] = X1 = _mm_add_epi32(X1, Y1); \ | ||
105 | (out)[2] = X2 = _mm_add_epi32(X2, Y2); \ | ||
106 | (out)[3] = X3 = _mm_add_epi32(X3, Y3); \ | ||
107 | } | ||
108 | |||
109 | /** | ||
110 | * blockmix_salsa8(Bin, Bout, r): | ||
111 | * Compute Bout = BlockMix_{salsa20/8, r}(Bin). The input Bin must be 128r | ||
112 | * bytes in length; the output Bout must also be the same size. | ||
113 | */ | ||
114 | static inline void | ||
115 | blockmix_salsa8(const __m128i * Bin, __m128i * Bout, size_t r) | ||
116 | { | ||
117 | __m128i X0, X1, X2, X3; | ||
118 | size_t i; | ||
119 | |||
120 | /* 1: X <-- B_{2r - 1} */ | ||
121 | X0 = Bin[8 * r - 4]; | ||
122 | X1 = Bin[8 * r - 3]; | ||
123 | X2 = Bin[8 * r - 2]; | ||
124 | X3 = Bin[8 * r - 1]; | ||
125 | |||
126 | /* 3: X <-- H(X \xor B_i) */ | ||
127 | /* 4: Y_i <-- X */ | ||
128 | /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ | ||
129 | SALSA20_8_XOR(Bin, Bout) | ||
130 | |||
131 | /* 2: for i = 0 to 2r - 1 do */ | ||
132 | r--; | ||
133 | for (i = 0; i < r;) { | ||
134 | /* 3: X <-- H(X \xor B_i) */ | ||
135 | /* 4: Y_i <-- X */ | ||
136 | /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ | ||
137 | SALSA20_8_XOR(&Bin[i * 8 + 4], &Bout[(r + i) * 4 + 4]) | ||
138 | |||
139 | i++; | ||
140 | |||
141 | /* 3: X <-- H(X \xor B_i) */ | ||
142 | /* 4: Y_i <-- X */ | ||
143 | /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ | ||
144 | SALSA20_8_XOR(&Bin[i * 8], &Bout[i * 4]) | ||
145 | } | ||
146 | |||
147 | /* 3: X <-- H(X \xor B_i) */ | ||
148 | /* 4: Y_i <-- X */ | ||
149 | /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ | ||
150 | SALSA20_8_XOR(&Bin[i * 8 + 4], &Bout[(r + i) * 4 + 4]) | ||
151 | } | ||
152 | |||
153 | #define XOR4(in) \ | ||
154 | X0 = _mm_xor_si128(X0, (in)[0]); \ | ||
155 | X1 = _mm_xor_si128(X1, (in)[1]); \ | ||
156 | X2 = _mm_xor_si128(X2, (in)[2]); \ | ||
157 | X3 = _mm_xor_si128(X3, (in)[3]); | ||
158 | |||
159 | #define XOR4_2(in1, in2) \ | ||
160 | X0 = _mm_xor_si128((in1)[0], (in2)[0]); \ | ||
161 | X1 = _mm_xor_si128((in1)[1], (in2)[1]); \ | ||
162 | X2 = _mm_xor_si128((in1)[2], (in2)[2]); \ | ||
163 | X3 = _mm_xor_si128((in1)[3], (in2)[3]); | ||
164 | |||
165 | static inline uint32_t | ||
166 | blockmix_salsa8_xor(const __m128i * Bin1, const __m128i * Bin2, __m128i * Bout, | ||
167 | size_t r) | ||
168 | { | ||
169 | __m128i X0, X1, X2, X3; | ||
170 | size_t i; | ||
171 | |||
172 | /* 1: X <-- B_{2r - 1} */ | ||
173 | XOR4_2(&Bin1[8 * r - 4], &Bin2[8 * r - 4]) | ||
174 | |||
175 | /* 3: X <-- H(X \xor B_i) */ | ||
176 | /* 4: Y_i <-- X */ | ||
177 | /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ | ||
178 | XOR4(Bin1) | ||
179 | SALSA20_8_XOR(Bin2, Bout) | ||
180 | |||
181 | /* 2: for i = 0 to 2r - 1 do */ | ||
182 | r--; | ||
183 | for (i = 0; i < r;) { | ||
184 | /* 3: X <-- H(X \xor B_i) */ | ||
185 | /* 4: Y_i <-- X */ | ||
186 | /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ | ||
187 | XOR4(&Bin1[i * 8 + 4]) | ||
188 | SALSA20_8_XOR(&Bin2[i * 8 + 4], &Bout[(r + i) * 4 + 4]) | ||
189 | |||
190 | i++; | ||
191 | |||
192 | /* 3: X <-- H(X \xor B_i) */ | ||
193 | /* 4: Y_i <-- X */ | ||
194 | /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ | ||
195 | XOR4(&Bin1[i * 8]) | ||
196 | SALSA20_8_XOR(&Bin2[i * 8], &Bout[i * 4]) | ||
197 | } | ||
198 | |||
199 | /* 3: X <-- H(X \xor B_i) */ | ||
200 | /* 4: Y_i <-- X */ | ||
201 | /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ | ||
202 | XOR4(&Bin1[i * 8 + 4]) | ||
203 | SALSA20_8_XOR(&Bin2[i * 8 + 4], &Bout[(r + i) * 4 + 4]) | ||
204 | |||
205 | return _mm_cvtsi128_si32(X0); | ||
206 | } | ||
207 | |||
208 | #undef ARX | ||
209 | #undef SALSA20_2ROUNDS | ||
210 | #undef SALSA20_8_XOR | ||
211 | #undef XOR4 | ||
212 | #undef XOR4_2 | ||
213 | |||
214 | /** | ||
215 | * integerify(B, r): | ||
216 | * Return the result of parsing B_{2r-1} as a little-endian integer. | ||
217 | */ | ||
218 | static inline uint32_t | ||
219 | integerify(const void * B, size_t r) | ||
220 | { | ||
221 | return *(const uint32_t *)((uintptr_t)(B) + (2 * r - 1) * 64); | ||
222 | } | ||
223 | |||
224 | /** | ||
225 | * smix(B, r, N, V, XY): | ||
226 | * Compute B = SMix_r(B, N). The input B must be 128r bytes in length; | ||
227 | * the temporary storage V must be 128rN bytes in length; the temporary | ||
228 | * storage XY must be 256r + 64 bytes in length. The value N must be a | ||
229 | * power of 2 greater than 1. The arrays B, V, and XY must be aligned to a | ||
230 | * multiple of 64 bytes. | ||
231 | */ | ||
232 | static void | ||
233 | smix(uint8_t * B, size_t r, uint32_t N, void * V, void * XY) | ||
234 | { | ||
235 | size_t s = 128 * r; | ||
236 | __m128i * X = (__m128i *) V, * Y; | ||
237 | uint32_t * X32 = (uint32_t *) V; | ||
238 | uint32_t i, j; | ||
239 | size_t k; | ||
240 | |||
241 | /* 1: X <-- B */ | ||
242 | /* 3: V_i <-- X */ | ||
243 | for (k = 0; k < 2 * r; k++) { | ||
244 | for (i = 0; i < 16; i++) { | ||
245 | X32[k * 16 + i] = | ||
246 | le32dec(&B[(k * 16 + (i * 5 % 16)) * 4]); | ||
247 | } | ||
248 | } | ||
249 | |||
250 | /* 2: for i = 0 to N - 1 do */ | ||
251 | for (i = 1; i < N - 1; i += 2) { | ||
252 | /* 4: X <-- H(X) */ | ||
253 | /* 3: V_i <-- X */ | ||
254 | Y = (__m128i *)((uintptr_t)(V) + i * s); | ||
255 | blockmix_salsa8(X, Y, r); | ||
256 | |||
257 | /* 4: X <-- H(X) */ | ||
258 | /* 3: V_i <-- X */ | ||
259 | X = (__m128i *)((uintptr_t)(V) + (i + 1) * s); | ||
260 | blockmix_salsa8(Y, X, r); | ||
261 | } | ||
262 | |||
263 | /* 4: X <-- H(X) */ | ||
264 | /* 3: V_i <-- X */ | ||
265 | Y = (__m128i *)((uintptr_t)(V) + i * s); | ||
266 | blockmix_salsa8(X, Y, r); | ||
267 | |||
268 | /* 4: X <-- H(X) */ | ||
269 | /* 3: V_i <-- X */ | ||
270 | X = (__m128i *) XY; | ||
271 | blockmix_salsa8(Y, X, r); | ||
272 | |||
273 | X32 = (uint32_t *) XY; | ||
274 | Y = (__m128i *)((uintptr_t)(XY) + s); | ||
275 | |||
276 | /* 7: j <-- Integerify(X) mod N */ | ||
277 | j = integerify(X, r) & (N - 1); | ||
278 | |||
279 | /* 6: for i = 0 to N - 1 do */ | ||
280 | for (i = 0; i < N; i += 2) { | ||
281 | __m128i * V_j = (__m128i *)((uintptr_t)(V) + j * s); | ||
282 | |||
283 | /* 8: X <-- H(X \xor V_j) */ | ||
284 | /* 7: j <-- Integerify(X) mod N */ | ||
285 | j = blockmix_salsa8_xor(X, V_j, Y, r) & (N - 1); | ||
286 | V_j = (__m128i *)((uintptr_t)(V) + j * s); | ||
287 | |||
288 | /* 8: X <-- H(X \xor V_j) */ | ||
289 | /* 7: j <-- Integerify(X) mod N */ | ||
290 | j = blockmix_salsa8_xor(Y, V_j, X, r) & (N - 1); | ||
291 | } | ||
292 | |||
293 | /* 10: B' <-- X */ | ||
294 | for (k = 0; k < 2 * r; k++) { | ||
295 | for (i = 0; i < 16; i++) { | ||
296 | le32enc(&B[(k * 16 + (i * 5 % 16)) * 4], | ||
297 | X32[k * 16 + i]); | ||
298 | } | ||
299 | } | ||
300 | } | ||
301 | |||
302 | /** | ||
303 | * escrypt_kdf(local, passwd, passwdlen, salt, saltlen, | ||
304 | * N, r, p, buf, buflen): | ||
305 | * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r, | ||
306 | * p, buflen) and write the result into buf. The parameters r, p, and buflen | ||
307 | * must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32. The parameter N | ||
308 | * must be a power of 2 greater than 1. | ||
309 | * | ||
310 | * Return 0 on success; or -1 on error. | ||
311 | */ | ||
312 | int | ||
313 | escrypt_kdf_sse(escrypt_local_t * local, | ||
314 | const uint8_t * passwd, size_t passwdlen, | ||
315 | const uint8_t * salt, size_t saltlen, | ||
316 | uint64_t N, uint32_t _r, uint32_t _p, | ||
317 | uint8_t * buf, size_t buflen) | ||
318 | { | ||
319 | size_t B_size, V_size, XY_size, need; | ||
320 | uint8_t * B; | ||
321 | uint32_t * V, * XY; | ||
322 | size_t r = _r, p = _p; | ||
323 | uint32_t i; | ||
324 | |||
325 | /* Sanity-check parameters. */ | ||
326 | #if SIZE_MAX > UINT32_MAX | ||
327 | if (buflen > (((uint64_t)(1) << 32) - 1) * 32) { | ||
328 | errno = EFBIG; | ||
329 | return -1; | ||
330 | } | ||
331 | #endif | ||
332 | if ((uint64_t)(r) * (uint64_t)(p) >= (1 << 30)) { | ||
333 | errno = EFBIG; | ||
334 | return -1; | ||
335 | } | ||
336 | if (N > UINT32_MAX) { | ||
337 | errno = EFBIG; | ||
338 | return -1; | ||
339 | } | ||
340 | if (((N & (N - 1)) != 0) || (N < 2)) { | ||
341 | errno = EINVAL; | ||
342 | return -1; | ||
343 | } | ||
344 | if (r == 0 || p == 0) { | ||
345 | errno = EINVAL; | ||
346 | return -1; | ||
347 | } | ||
348 | if ((r > SIZE_MAX / 128 / p) || | ||
349 | #if SIZE_MAX / 256 <= UINT32_MAX | ||
350 | (r > SIZE_MAX / 256) || | ||
351 | #endif | ||
352 | (N > SIZE_MAX / 128 / r)) { | ||
353 | errno = ENOMEM; | ||
354 | return -1; | ||
355 | } | ||
356 | |||
357 | /* Allocate memory. */ | ||
358 | B_size = (size_t)128 * r * p; | ||
359 | V_size = (size_t)128 * r * N; | ||
360 | need = B_size + V_size; | ||
361 | if (need < V_size) { | ||
362 | errno = ENOMEM; | ||
363 | return -1; | ||
364 | } | ||
365 | XY_size = (size_t)256 * r + 64; | ||
366 | need += XY_size; | ||
367 | if (need < XY_size) { | ||
368 | errno = ENOMEM; | ||
369 | return -1; | ||
370 | } | ||
371 | if (local->size < need) { | ||
372 | if (free_region(local)) | ||
373 | return -1; | ||
374 | if (!alloc_region(local, need)) | ||
375 | return -1; | ||
376 | } | ||
377 | B = (uint8_t *)local->aligned; | ||
378 | V = (uint32_t *)((uint8_t *)B + B_size); | ||
379 | XY = (uint32_t *)((uint8_t *)V + V_size); | ||
380 | |||
381 | /* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */ | ||
382 | PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, 1, B, B_size); | ||
383 | |||
384 | /* 2: for i = 0 to p - 1 do */ | ||
385 | for (i = 0; i < p; i++) { | ||
386 | /* 3: B_i <-- MF(B_i, N) */ | ||
387 | smix(&B[(size_t)128 * i * r], r, N, V, XY); | ||
388 | } | ||
389 | |||
390 | /* 5: DK <-- PBKDF2(P, B, 1, dkLen) */ | ||
391 | PBKDF2_SHA256(passwd, passwdlen, B, B_size, 1, buf, buflen); | ||
392 | |||
393 | /* Success! */ | ||
394 | return 0; | ||
395 | } | ||
396 | #endif | ||
397 | |||
398 | #endif | ||
diff --git a/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/sysendian.h b/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/sysendian.h new file mode 100644 index 00000000..04e5c1ed --- /dev/null +++ b/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/sysendian.h | |||
@@ -0,0 +1,153 @@ | |||
1 | #ifdef HAVE_CONFIG_H | ||
2 | #include "config.h" | ||
3 | #endif | ||
4 | #ifdef VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */ | ||
5 | |||
6 | #ifndef _SYSENDIAN_H_ | ||
7 | #define _SYSENDIAN_H_ | ||
8 | |||
9 | #include <stdint.h> | ||
10 | |||
11 | /* Avoid namespace collisions with BSD <sys/endian.h>. */ | ||
12 | #define be16dec scrypt_be16dec | ||
13 | #define be16enc scrypt_be16enc | ||
14 | #define be32dec scrypt_be32dec | ||
15 | #define be32enc scrypt_be32enc | ||
16 | #define be64dec scrypt_be64dec | ||
17 | #define be64enc scrypt_be64enc | ||
18 | #define le16dec scrypt_le16dec | ||
19 | #define le16enc scrypt_le16enc | ||
20 | #define le32dec scrypt_le32dec | ||
21 | #define le32enc scrypt_le32enc | ||
22 | #define le64dec scrypt_le64dec | ||
23 | #define le64enc scrypt_le64enc | ||
24 | |||
25 | static inline uint16_t | ||
26 | be16dec(const void *pp) | ||
27 | { | ||
28 | const uint8_t *p = (uint8_t const *)pp; | ||
29 | |||
30 | return ((uint16_t)(p[1]) + ((uint16_t)(p[0]) << 8)); | ||
31 | } | ||
32 | |||
33 | static inline void | ||
34 | be16enc(void *pp, uint16_t x) | ||
35 | { | ||
36 | uint8_t * p = (uint8_t *)pp; | ||
37 | |||
38 | p[1] = x & 0xff; | ||
39 | p[0] = (x >> 8) & 0xff; | ||
40 | } | ||
41 | |||
42 | static inline uint32_t | ||
43 | be32dec(const void *pp) | ||
44 | { | ||
45 | const uint8_t *p = (uint8_t const *)pp; | ||
46 | |||
47 | return ((uint32_t)(p[3]) + ((uint32_t)(p[2]) << 8) + | ||
48 | ((uint32_t)(p[1]) << 16) + ((uint32_t)(p[0]) << 24)); | ||
49 | } | ||
50 | |||
51 | static inline void | ||
52 | be32enc(void *pp, uint32_t x) | ||
53 | { | ||
54 | uint8_t * p = (uint8_t *)pp; | ||
55 | |||
56 | p[3] = x & 0xff; | ||
57 | p[2] = (x >> 8) & 0xff; | ||
58 | p[1] = (x >> 16) & 0xff; | ||
59 | p[0] = (x >> 24) & 0xff; | ||
60 | } | ||
61 | |||
62 | static inline uint64_t | ||
63 | be64dec(const void *pp) | ||
64 | { | ||
65 | const uint8_t *p = (uint8_t const *)pp; | ||
66 | |||
67 | return ((uint64_t)(p[7]) + ((uint64_t)(p[6]) << 8) + | ||
68 | ((uint64_t)(p[5]) << 16) + ((uint64_t)(p[4]) << 24) + | ||
69 | ((uint64_t)(p[3]) << 32) + ((uint64_t)(p[2]) << 40) + | ||
70 | ((uint64_t)(p[1]) << 48) + ((uint64_t)(p[0]) << 56)); | ||
71 | } | ||
72 | |||
73 | static inline void | ||
74 | be64enc(void *pp, uint64_t x) | ||
75 | { | ||
76 | uint8_t * p = (uint8_t *)pp; | ||
77 | |||
78 | p[7] = x & 0xff; | ||
79 | p[6] = (x >> 8) & 0xff; | ||
80 | p[5] = (x >> 16) & 0xff; | ||
81 | p[4] = (x >> 24) & 0xff; | ||
82 | p[3] = (x >> 32) & 0xff; | ||
83 | p[2] = (x >> 40) & 0xff; | ||
84 | p[1] = (x >> 48) & 0xff; | ||
85 | p[0] = (x >> 56) & 0xff; | ||
86 | } | ||
87 | |||
88 | static inline uint16_t | ||
89 | le16dec(const void *pp) | ||
90 | { | ||
91 | const uint8_t *p = (uint8_t const *)pp; | ||
92 | |||
93 | return ((uint16_t)(p[0]) + ((uint16_t)(p[1]) << 8)); | ||
94 | } | ||
95 | |||
96 | static inline void | ||
97 | le16enc(void *pp, uint16_t x) | ||
98 | { | ||
99 | uint8_t * p = (uint8_t *)pp; | ||
100 | |||
101 | p[0] = x & 0xff; | ||
102 | p[1] = (x >> 8) & 0xff; | ||
103 | } | ||
104 | |||
105 | static inline uint32_t | ||
106 | le32dec(const void *pp) | ||
107 | { | ||
108 | const uint8_t *p = (uint8_t const *)pp; | ||
109 | |||
110 | return ((uint32_t)(p[0]) + ((uint32_t)(p[1]) << 8) + | ||
111 | ((uint32_t)(p[2]) << 16) + ((uint32_t)(p[3]) << 24)); | ||
112 | } | ||
113 | |||
114 | static inline void | ||
115 | le32enc(void *pp, uint32_t x) | ||
116 | { | ||
117 | uint8_t * p = (uint8_t *)pp; | ||
118 | |||
119 | p[0] = x & 0xff; | ||
120 | p[1] = (x >> 8) & 0xff; | ||
121 | p[2] = (x >> 16) & 0xff; | ||
122 | p[3] = (x >> 24) & 0xff; | ||
123 | } | ||
124 | |||
125 | static inline uint64_t | ||
126 | le64dec(const void *pp) | ||
127 | { | ||
128 | const uint8_t *p = (uint8_t const *)pp; | ||
129 | |||
130 | return ((uint64_t)(p[0]) + ((uint64_t)(p[1]) << 8) + | ||
131 | ((uint64_t)(p[2]) << 16) + ((uint64_t)(p[3]) << 24) + | ||
132 | ((uint64_t)(p[4]) << 32) + ((uint64_t)(p[5]) << 40) + | ||
133 | ((uint64_t)(p[6]) << 48) + ((uint64_t)(p[7]) << 56)); | ||
134 | } | ||
135 | |||
136 | static inline void | ||
137 | le64enc(void *pp, uint64_t x) | ||
138 | { | ||
139 | uint8_t * p = (uint8_t *)pp; | ||
140 | |||
141 | p[0] = x & 0xff; | ||
142 | p[1] = (x >> 8) & 0xff; | ||
143 | p[2] = (x >> 16) & 0xff; | ||
144 | p[3] = (x >> 24) & 0xff; | ||
145 | p[4] = (x >> 32) & 0xff; | ||
146 | p[5] = (x >> 40) & 0xff; | ||
147 | p[6] = (x >> 48) & 0xff; | ||
148 | p[7] = (x >> 56) & 0xff; | ||
149 | } | ||
150 | |||
151 | #endif /* !_SYSENDIAN_H_ */ | ||
152 | |||
153 | #endif | ||
diff --git a/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/utils.c b/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/utils.c new file mode 100644 index 00000000..e61ccf3e --- /dev/null +++ b/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/utils.c | |||
@@ -0,0 +1,78 @@ | |||
1 | #ifdef HAVE_CONFIG_H | ||
2 | #include "config.h" | ||
3 | #endif | ||
4 | #ifdef VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */ | ||
5 | |||
6 | #ifndef __STDC_WANT_LIB_EXT1__ | ||
7 | # define __STDC_WANT_LIB_EXT1__ 1 | ||
8 | #endif | ||
9 | #include <assert.h> | ||
10 | #include <errno.h> | ||
11 | #include <limits.h> | ||
12 | #include <signal.h> | ||
13 | #include <stddef.h> | ||
14 | #include <stdint.h> | ||
15 | #include <stdlib.h> | ||
16 | #include <string.h> | ||
17 | |||
18 | #ifdef HAVE_SYS_MMAN_H | ||
19 | # include <sys/mman.h> | ||
20 | #endif | ||
21 | |||
22 | #include "utils.h" | ||
23 | |||
24 | #ifdef _WIN32 | ||
25 | # include <windows.h> | ||
26 | # include <wincrypt.h> | ||
27 | #else | ||
28 | # include <unistd.h> | ||
29 | #endif | ||
30 | |||
31 | #ifdef HAVE_WEAK_SYMBOLS | ||
32 | __attribute__((weak)) void | ||
33 | __sodium_dummy_symbol_to_prevent_lto(void * const pnt, const size_t len) | ||
34 | { | ||
35 | (void) pnt; | ||
36 | (void) len; | ||
37 | } | ||
38 | #endif | ||
39 | |||
40 | void | ||
41 | sodium_memzero(void * const pnt, const size_t len) | ||
42 | { | ||
43 | #ifdef _WIN32 | ||
44 | SecureZeroMemory(pnt, len); | ||
45 | #elif defined(HAVE_MEMSET_S) | ||
46 | if (memset_s(pnt, (rsize_t) len, 0, (rsize_t) len) != 0) { | ||
47 | abort(); | ||
48 | } | ||
49 | #elif defined(HAVE_EXPLICIT_BZERO) | ||
50 | explicit_bzero(pnt, len); | ||
51 | #elif HAVE_WEAK_SYMBOLS | ||
52 | memset(pnt, 0, len); | ||
53 | __sodium_dummy_symbol_to_prevent_lto(pnt, len); | ||
54 | #else | ||
55 | volatile unsigned char *pnt_ = (volatile unsigned char *) pnt; | ||
56 | size_t i = (size_t) 0U; | ||
57 | |||
58 | while (i < len) { | ||
59 | pnt_[i++] = 0U; | ||
60 | } | ||
61 | #endif | ||
62 | } | ||
63 | |||
64 | int | ||
65 | sodium_memcmp(const void * const b1_, const void * const b2_, size_t len) | ||
66 | { | ||
67 | const unsigned char *b1 = (const unsigned char *) b1_; | ||
68 | const unsigned char *b2 = (const unsigned char *) b2_; | ||
69 | size_t i; | ||
70 | unsigned char d = (unsigned char) 0U; | ||
71 | |||
72 | for (i = 0U; i < len; i++) { | ||
73 | d |= b1[i] ^ b2[i]; | ||
74 | } | ||
75 | return (int) ((1 & ((d - 1) >> 8)) - 1); | ||
76 | } | ||
77 | |||
78 | #endif | ||
diff --git a/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/utils.h b/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/utils.h new file mode 100644 index 00000000..fb2020c3 --- /dev/null +++ b/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/utils.h | |||
@@ -0,0 +1,40 @@ | |||
1 | #ifdef HAVE_CONFIG_H | ||
2 | #include "config.h" | ||
3 | #endif | ||
4 | #ifdef VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */ | ||
5 | |||
6 | #ifndef __SODIUM_UTILS_H__ | ||
7 | #define __SODIUM_UTILS_H__ | ||
8 | |||
9 | #include <stddef.h> | ||
10 | |||
11 | #include "export.h" | ||
12 | |||
13 | #ifdef __cplusplus | ||
14 | extern "C" { | ||
15 | #endif | ||
16 | |||
17 | #if defined(__cplusplus) || !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L | ||
18 | # define _SODIUM_C99(X) | ||
19 | #else | ||
20 | # define _SODIUM_C99(X) X | ||
21 | #endif | ||
22 | |||
23 | SODIUM_EXPORT | ||
24 | void sodium_memzero(void * const pnt, const size_t len); | ||
25 | |||
26 | /* WARNING: sodium_memcmp() must be used to verify if two secret keys | ||
27 | * are equal, in constant time. | ||
28 | * It returns 0 if the keys are equal, and -1 if they differ. | ||
29 | * This function is not designed for lexicographical comparisons. | ||
30 | */ | ||
31 | SODIUM_EXPORT | ||
32 | int sodium_memcmp(const void * const b1_, const void * const b2_, size_t len); | ||
33 | |||
34 | #ifdef __cplusplus | ||
35 | } | ||
36 | #endif | ||
37 | |||
38 | #endif | ||
39 | |||
40 | #endif | ||
diff --git a/toxencryptsave/defines.h b/toxencryptsave/defines.h new file mode 100644 index 00000000..e3fca073 --- /dev/null +++ b/toxencryptsave/defines.h | |||
@@ -0,0 +1,2 @@ | |||
1 | #define TOX_ENC_SAVE_MAGIC_NUMBER "toxEsave" | ||
2 | #define TOX_ENC_SAVE_MAGIC_LENGTH 8 | ||
diff --git a/toxencryptsave/toxencryptsave.c b/toxencryptsave/toxencryptsave.c new file mode 100644 index 00000000..13a34dea --- /dev/null +++ b/toxencryptsave/toxencryptsave.c | |||
@@ -0,0 +1,346 @@ | |||
1 | /* toxencryptsave.c | ||
2 | * | ||
3 | * The Tox encrypted save functions. | ||
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 "toxencryptsave.h" | ||
29 | #include "defines.h" | ||
30 | #include "../toxcore/crypto_core.h" | ||
31 | #include "../toxcore/tox.h" | ||
32 | |||
33 | #ifdef VANILLA_NACL | ||
34 | #include "crypto_pwhash_scryptsalsa208sha256/crypto_pwhash_scryptsalsa208sha256.h" | ||
35 | #include "crypto_pwhash_scryptsalsa208sha256/utils.h" /* sodium_memzero */ | ||
36 | #include <crypto_hash_sha256.h> | ||
37 | #endif | ||
38 | |||
39 | #define TOX_PASS_ENCRYPTION_EXTRA_LENGTH (crypto_box_MACBYTES + crypto_box_NONCEBYTES \ | ||
40 | + crypto_pwhash_scryptsalsa208sha256_SALTBYTES + TOX_ENC_SAVE_MAGIC_LENGTH) | ||
41 | |||
42 | #define TOX_PASS_KEY_LENGTH (crypto_pwhash_scryptsalsa208sha256_SALTBYTES + crypto_box_KEYBYTES) | ||
43 | |||
44 | int tox_pass_encryption_extra_length() | ||
45 | { | ||
46 | return TOX_PASS_ENCRYPTION_EXTRA_LENGTH; | ||
47 | } | ||
48 | |||
49 | int tox_pass_key_length() | ||
50 | { | ||
51 | return TOX_PASS_KEY_LENGTH; | ||
52 | } | ||
53 | |||
54 | int tox_pass_salt_length() | ||
55 | { | ||
56 | return crypto_pwhash_scryptsalsa208sha256_SALTBYTES; | ||
57 | } | ||
58 | |||
59 | /* This "module" provides functions analogous to tox_load and tox_save in toxcore | ||
60 | * Clients should consider alerting their users that, unlike plain data, if even one bit | ||
61 | * becomes corrupted, the data will be entirely unrecoverable. | ||
62 | * Ditto if they forget their password, there is no way to recover the data. | ||
63 | */ | ||
64 | |||
65 | /* return size of the messenger data (for encrypted saving). */ | ||
66 | uint32_t tox_encrypted_size(const Tox *tox) | ||
67 | { | ||
68 | return tox_save_size(tox) + TOX_PASS_ENCRYPTION_EXTRA_LENGTH; | ||
69 | } | ||
70 | |||
71 | /* This retrieves the salt used to encrypt the given data, which can then be passed to | ||
72 | * derive_key_with_salt to produce the same key as was previously used. Any encrpyted | ||
73 | * data with this module can be used as input. | ||
74 | * | ||
75 | * returns -1 if the magic number is wrong | ||
76 | * returns 0 otherwise (no guarantee about validity of data) | ||
77 | */ | ||
78 | int tox_get_salt(uint8_t *data, uint8_t *salt) | ||
79 | { | ||
80 | if (memcmp(data, TOX_ENC_SAVE_MAGIC_NUMBER, TOX_ENC_SAVE_MAGIC_LENGTH) != 0) | ||
81 | return -1; | ||
82 | |||
83 | data += TOX_ENC_SAVE_MAGIC_LENGTH; | ||
84 | memcpy(salt, data, crypto_pwhash_scryptsalsa208sha256_SALTBYTES); | ||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | /* Generates a secret symmetric key from the given passphrase. out_key must be at least | ||
89 | * TOX_PASS_KEY_LENGTH bytes long. | ||
90 | * Be sure to not compromise the key! Only keep it in memory, do not write to disk. | ||
91 | * This function is fairly cheap, but irungentoo insists that you be allowed to | ||
92 | * cache the result if you want, to minimize computation for repeated encryptions. | ||
93 | * The password is zeroed after key derivation. | ||
94 | * The key should only be used with the other functions in this module, as it | ||
95 | * includes a salt. | ||
96 | * | ||
97 | * returns 0 on success | ||
98 | * returns -1 on failure | ||
99 | */ | ||
100 | int tox_derive_key_from_pass(uint8_t *passphrase, uint32_t pplength, uint8_t *out_key) | ||
101 | { | ||
102 | uint8_t salt[crypto_pwhash_scryptsalsa208sha256_SALTBYTES]; | ||
103 | randombytes(salt, sizeof salt); | ||
104 | return tox_derive_key_with_salt(passphrase, pplength, salt, out_key); | ||
105 | } | ||
106 | |||
107 | /* Same as above, except with use the given salt for deterministic key derivation. | ||
108 | * The salt must be tox_salt_length() bytes in length. | ||
109 | */ | ||
110 | int tox_derive_key_with_salt(uint8_t *passphrase, uint32_t pplength, uint8_t *salt, uint8_t *out_key) | ||
111 | { | ||
112 | if (pplength == 0) | ||
113 | return -1; | ||
114 | |||
115 | uint8_t passkey[crypto_hash_sha256_BYTES]; | ||
116 | crypto_hash_sha256(passkey, passphrase, pplength); | ||
117 | |||
118 | uint8_t key[crypto_box_KEYBYTES]; | ||
119 | |||
120 | /* Derive a key from the password */ | ||
121 | /* http://doc.libsodium.org/key_derivation/README.html */ | ||
122 | /* note that, according to the documentation, a generic pwhash interface will be created | ||
123 | * once the pwhash competition (https://password-hashing.net/) is over */ | ||
124 | if (crypto_pwhash_scryptsalsa208sha256( | ||
125 | key, sizeof(key), (char *)passkey, sizeof(passkey), salt, | ||
126 | crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE * 2, /* slightly stronger */ | ||
127 | crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE) != 0) { | ||
128 | /* out of memory most likely */ | ||
129 | return -1; | ||
130 | } | ||
131 | |||
132 | sodium_memzero(passkey, crypto_hash_sha256_BYTES); /* wipe plaintext pw */ | ||
133 | memcpy(out_key, salt, crypto_pwhash_scryptsalsa208sha256_SALTBYTES); | ||
134 | memcpy(out_key + crypto_pwhash_scryptsalsa208sha256_SALTBYTES, key, crypto_box_KEYBYTES); | ||
135 | return 0; | ||
136 | } | ||
137 | |||
138 | /* Encrypt arbitrary with a key produced by tox_derive_key_from_pass. The output | ||
139 | * array must be at least data_len + TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes long. | ||
140 | * key must be TOX_PASS_KEY_LENGTH bytes. | ||
141 | * If you already have a symmetric key from somewhere besides this module, simply | ||
142 | * call encrypt_data_symmetric in toxcore/crypto_core directly. | ||
143 | * | ||
144 | * | ||
145 | * returns 0 on success | ||
146 | * returns -1 on failure | ||
147 | */ | ||
148 | int tox_pass_key_encrypt(const uint8_t *data, uint32_t data_len, const uint8_t *key, uint8_t *out) | ||
149 | { | ||
150 | /* the output data consists of, in order: | ||
151 | * salt, nonce, mac, enc_data | ||
152 | * where the mac is automatically prepended by the encrypt() | ||
153 | * the salt+nonce is called the prefix | ||
154 | * I'm not sure what else I'm supposed to do with the salt and nonce, since we | ||
155 | * need them to decrypt the data | ||
156 | */ | ||
157 | |||
158 | /* first add the magic number */ | ||
159 | memcpy(out, TOX_ENC_SAVE_MAGIC_NUMBER, TOX_ENC_SAVE_MAGIC_LENGTH); | ||
160 | out += TOX_ENC_SAVE_MAGIC_LENGTH; | ||
161 | |||
162 | /* then add the rest prefix */ | ||
163 | memcpy(out, key, crypto_pwhash_scryptsalsa208sha256_SALTBYTES); | ||
164 | key += crypto_pwhash_scryptsalsa208sha256_SALTBYTES; | ||
165 | out += crypto_pwhash_scryptsalsa208sha256_SALTBYTES; | ||
166 | |||
167 | uint8_t nonce[crypto_box_NONCEBYTES]; | ||
168 | random_nonce(nonce); | ||
169 | memcpy(out, nonce, crypto_box_NONCEBYTES); | ||
170 | out += crypto_box_NONCEBYTES; | ||
171 | |||
172 | /* now encrypt */ | ||
173 | if (encrypt_data_symmetric(key, nonce, data, data_len, out) | ||
174 | != data_len + crypto_box_MACBYTES) { | ||
175 | return -1; | ||
176 | } | ||
177 | |||
178 | return 0; | ||
179 | } | ||
180 | |||
181 | /* Encrypts the given data with the given passphrase. The output array must be | ||
182 | * at least data_len + TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes long. This delegates | ||
183 | * to tox_derive_key_from_pass and tox_pass_key_encrypt. | ||
184 | * | ||
185 | * returns 0 on success | ||
186 | * returns -1 on failure | ||
187 | */ | ||
188 | int tox_pass_encrypt(const uint8_t *data, uint32_t data_len, uint8_t *passphrase, uint32_t pplength, uint8_t *out) | ||
189 | { | ||
190 | uint8_t key[TOX_PASS_KEY_LENGTH]; | ||
191 | |||
192 | if (tox_derive_key_from_pass(passphrase, pplength, key) == -1) | ||
193 | return -1; | ||
194 | |||
195 | return tox_pass_key_encrypt(data, data_len, key, out); | ||
196 | } | ||
197 | |||
198 | /* Save the messenger data encrypted with the given password. | ||
199 | * data must be at least tox_encrypted_size(). | ||
200 | * | ||
201 | * returns 0 on success | ||
202 | * returns -1 on failure | ||
203 | */ | ||
204 | int tox_encrypted_save(const Tox *tox, uint8_t *data, uint8_t *passphrase, uint32_t pplength) | ||
205 | { | ||
206 | /* first get plain save data */ | ||
207 | uint32_t temp_size = tox_save_size(tox); | ||
208 | uint8_t temp_data[temp_size]; | ||
209 | tox_save(tox, temp_data); | ||
210 | |||
211 | /* now encrypt */ | ||
212 | return tox_pass_encrypt(temp_data, temp_size, passphrase, pplength, data); | ||
213 | } | ||
214 | |||
215 | /* Save the messenger data encrypted with the given key from tox_derive_key. | ||
216 | * data must be at least tox_encrypted_size(). | ||
217 | * | ||
218 | * returns 0 on success | ||
219 | * returns -1 on failure | ||
220 | */ | ||
221 | int tox_encrypted_key_save(const Tox *tox, uint8_t *data, uint8_t *key) | ||
222 | { | ||
223 | /* first get plain save data */ | ||
224 | uint32_t temp_size = tox_save_size(tox); | ||
225 | uint8_t temp_data[temp_size]; | ||
226 | tox_save(tox, temp_data); | ||
227 | |||
228 | /* encrypt */ | ||
229 | return tox_pass_key_encrypt(temp_data, temp_size, key, data); | ||
230 | } | ||
231 | |||
232 | /* This is the inverse of tox_pass_key_encrypt, also using only keys produced by | ||
233 | * tox_derive_key_from_pass. | ||
234 | * | ||
235 | * returns the length of the output data (== data_len - TOX_PASS_ENCRYPTION_EXTRA_LENGTH) on success | ||
236 | * returns -1 on failure | ||
237 | */ | ||
238 | int tox_pass_key_decrypt(const uint8_t *data, uint32_t length, const uint8_t *key, uint8_t *out) | ||
239 | { | ||
240 | if (length <= TOX_PASS_ENCRYPTION_EXTRA_LENGTH | ||
241 | || 0 != memcmp(data, TOX_ENC_SAVE_MAGIC_NUMBER, TOX_ENC_SAVE_MAGIC_LENGTH)) | ||
242 | return -1; | ||
243 | |||
244 | data += TOX_ENC_SAVE_MAGIC_LENGTH; | ||
245 | |||
246 | uint32_t decrypt_length = length - TOX_PASS_ENCRYPTION_EXTRA_LENGTH; | ||
247 | //uint8_t salt[crypto_pwhash_scryptsalsa208sha256_SALTBYTES]; | ||
248 | uint8_t nonce[crypto_box_NONCEBYTES]; | ||
249 | |||
250 | //memcpy(salt, data, crypto_pwhash_scryptsalsa208sha256_SALTBYTES); | ||
251 | key += crypto_pwhash_scryptsalsa208sha256_SALTBYTES; // ignore the salt, which is only needed for kdf | ||
252 | data += crypto_pwhash_scryptsalsa208sha256_SALTBYTES; | ||
253 | memcpy(nonce, data, crypto_box_NONCEBYTES); | ||
254 | data += crypto_box_NONCEBYTES; | ||
255 | |||
256 | /* decrypt the data */ | ||
257 | if (decrypt_data_symmetric(key, nonce, data, decrypt_length + crypto_box_MACBYTES, out) | ||
258 | != decrypt_length) { | ||
259 | return -1; | ||
260 | } | ||
261 | |||
262 | return decrypt_length; | ||
263 | } | ||
264 | |||
265 | /* Decrypts the given data with the given passphrase. The output array must be | ||
266 | * at least data_len - TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes long. | ||
267 | * | ||
268 | * returns the length of the output data (== data_len - TOX_PASS_ENCRYPTION_EXTRA_LENGTH) on success | ||
269 | * returns -1 on failure | ||
270 | */ | ||
271 | int tox_pass_decrypt(const uint8_t *data, uint32_t length, uint8_t *passphrase, uint32_t pplength, uint8_t *out) | ||
272 | { | ||
273 | uint8_t passkey[crypto_hash_sha256_BYTES]; | ||
274 | crypto_hash_sha256(passkey, passphrase, pplength); | ||
275 | |||
276 | uint8_t salt[crypto_pwhash_scryptsalsa208sha256_SALTBYTES]; | ||
277 | memcpy(salt, data + TOX_ENC_SAVE_MAGIC_LENGTH, crypto_pwhash_scryptsalsa208sha256_SALTBYTES); | ||
278 | |||
279 | /* derive the key */ | ||
280 | uint8_t key[crypto_box_KEYBYTES + crypto_pwhash_scryptsalsa208sha256_SALTBYTES]; | ||
281 | |||
282 | if (crypto_pwhash_scryptsalsa208sha256( | ||
283 | key + crypto_pwhash_scryptsalsa208sha256_SALTBYTES, | ||
284 | crypto_box_KEYBYTES, (char *)passkey, sizeof(passkey), salt, | ||
285 | crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE * 2, /* slightly stronger */ | ||
286 | crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE) != 0) { | ||
287 | /* out of memory most likely */ | ||
288 | return -1; | ||
289 | } | ||
290 | |||
291 | sodium_memzero(passkey, crypto_hash_sha256_BYTES); /* wipe plaintext pw */ | ||
292 | |||
293 | return tox_pass_key_decrypt(data, length, key, out); | ||
294 | } | ||
295 | |||
296 | /* Load the messenger from encrypted data of size length. | ||
297 | * | ||
298 | * returns 0 on success | ||
299 | * returns -1 on failure | ||
300 | */ | ||
301 | int tox_encrypted_load(Tox *tox, const uint8_t *data, uint32_t length, uint8_t *passphrase, uint32_t pplength) | ||
302 | { | ||
303 | uint32_t decrypt_length = length - TOX_PASS_ENCRYPTION_EXTRA_LENGTH; | ||
304 | uint8_t temp_data[decrypt_length]; | ||
305 | |||
306 | if (tox_pass_decrypt(data, length, passphrase, pplength, temp_data) | ||
307 | != decrypt_length) | ||
308 | return -1; | ||
309 | |||
310 | return tox_load(tox, temp_data, decrypt_length); | ||
311 | } | ||
312 | |||
313 | /* Load the messenger from encrypted data of size length, with key from tox_derive_key. | ||
314 | * | ||
315 | * returns 0 on success | ||
316 | * returns -1 on failure | ||
317 | */ | ||
318 | int tox_encrypted_key_load(Tox *tox, const uint8_t *data, uint32_t length, uint8_t *key) | ||
319 | { | ||
320 | uint32_t decrypt_length = length - TOX_PASS_ENCRYPTION_EXTRA_LENGTH; | ||
321 | uint8_t temp_data[decrypt_length]; | ||
322 | |||
323 | if (tox_pass_key_decrypt(data, length, key, temp_data) | ||
324 | != decrypt_length) | ||
325 | return -1; | ||
326 | |||
327 | return tox_load(tox, temp_data, decrypt_length); | ||
328 | } | ||
329 | |||
330 | /* Determines whether or not the given data is encrypted (by checking the magic number) | ||
331 | * | ||
332 | * returns 1 if it is encrypted | ||
333 | * returns 0 otherwise | ||
334 | */ | ||
335 | int tox_is_data_encrypted(const uint8_t *data) | ||
336 | { | ||
337 | if (memcmp(data, TOX_ENC_SAVE_MAGIC_NUMBER, TOX_ENC_SAVE_MAGIC_LENGTH) == 0) | ||
338 | return 1; | ||
339 | else | ||
340 | return 0; | ||
341 | } | ||
342 | |||
343 | int tox_is_save_encrypted(const uint8_t *data) | ||
344 | { | ||
345 | return tox_is_data_encrypted(data); | ||
346 | } | ||
diff --git a/toxencryptsave/toxencryptsave.h b/toxencryptsave/toxencryptsave.h new file mode 100644 index 00000000..da13f312 --- /dev/null +++ b/toxencryptsave/toxencryptsave.h | |||
@@ -0,0 +1,196 @@ | |||
1 | /* toxencryptsave.h | ||
2 | * | ||
3 | * The Tox encrypted save functions. | ||
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 TOXENCRYPTSAVE_H | ||
25 | #define TOXENCRYPTSAVE_H | ||
26 | |||
27 | #ifdef __cplusplus | ||
28 | extern "C" { | ||
29 | #endif | ||
30 | |||
31 | #include <stdint.h> | ||
32 | |||
33 | #ifndef TOX_DEFINED | ||
34 | #define TOX_DEFINED | ||
35 | typedef struct Tox Tox; | ||
36 | #endif | ||
37 | |||
38 | // these functions provide access to these defines in toxencryptsave.c, which | ||
39 | // otherwise aren't actually available in clients... | ||
40 | int tox_pass_encryption_extra_length(); | ||
41 | |||
42 | int tox_pass_key_length(); | ||
43 | |||
44 | int tox_pass_salt_length(); | ||
45 | |||
46 | /* return size of the messenger data (for encrypted Messenger saving). */ | ||
47 | uint32_t tox_encrypted_size(const Tox *tox); | ||
48 | |||
49 | /* This "module" provides functions analogous to tox_load and tox_save in toxcore, | ||
50 | * as well as functions for encryption of arbitrary client data (e.g. chat logs). | ||
51 | * | ||
52 | * It is conceptually organized into two parts. The first part are the functions | ||
53 | * with "key" in the name. To use these functions, first derive an encryption key | ||
54 | * from a password with tox_derive_key_from_pass, and use the returned key to | ||
55 | * encrypt the data. The second part takes the password itself instead of the key, | ||
56 | * and then delegates to the first part to derive the key before de/encryption, | ||
57 | * which can simplify client code; however, key derivation is very expensive | ||
58 | * compared to the actual encryption, so clients that do a lot of encryption should | ||
59 | * favor using the first part intead of the second part. | ||
60 | * | ||
61 | * The encrypted data is prepended with a magic number, to aid validity checking | ||
62 | * (no guarantees are made of course). | ||
63 | * | ||
64 | * Clients should consider alerting their users that, unlike plain data, if even one bit | ||
65 | * becomes corrupted, the data will be entirely unrecoverable. | ||
66 | * Ditto if they forget their password, there is no way to recover the data. | ||
67 | */ | ||
68 | |||
69 | |||
70 | /******************************* BEGIN PART 2 ******************************* | ||
71 | * For simplicty, the second part of the module is presented first. The API for | ||
72 | * the first part is analgous, with some extra functions for key handling. If | ||
73 | * your code spends too much time using these functions, consider using the part | ||
74 | * 1 functions instead. | ||
75 | */ | ||
76 | |||
77 | /* Encrypts the given data with the given passphrase. The output array must be | ||
78 | * at least data_len + tox_pass_encryption_extra_length() bytes long. This delegates | ||
79 | * to tox_derive_key_from_pass and tox_pass_key_encrypt. | ||
80 | * | ||
81 | * tox_encrypted_save() is a good example of how to use this function. | ||
82 | * | ||
83 | * returns 0 on success | ||
84 | * returns -1 on failure | ||
85 | */ | ||
86 | int tox_pass_encrypt(const uint8_t *data, uint32_t data_len, uint8_t *passphrase, uint32_t pplength, uint8_t *out); | ||
87 | |||
88 | /* Save the messenger data encrypted with the given password. | ||
89 | * data must be at least tox_encrypted_size(). | ||
90 | * | ||
91 | * returns 0 on success | ||
92 | * returns -1 on failure | ||
93 | */ | ||
94 | int tox_encrypted_save(const Tox *tox, uint8_t *data, uint8_t *passphrase, uint32_t pplength); | ||
95 | |||
96 | /* Decrypts the given data with the given passphrase. The output array must be | ||
97 | * at least data_len - tox_pass_encryption_extra_length() bytes long. This delegates | ||
98 | * to tox_pass_key_decrypt. | ||
99 | * | ||
100 | * tox_encrypted_load() is a good example of how to use this function. | ||
101 | * | ||
102 | * returns the length of the output data (== data_len - tox_pass_encryption_extra_length()) on success | ||
103 | * returns -1 on failure | ||
104 | */ | ||
105 | int tox_pass_decrypt(const uint8_t *data, uint32_t length, uint8_t *passphrase, uint32_t pplength, uint8_t *out); | ||
106 | |||
107 | /* Load the messenger from encrypted data of size length. | ||
108 | * | ||
109 | * returns 0 on success | ||
110 | * returns -1 on failure | ||
111 | */ | ||
112 | int tox_encrypted_load(Tox *tox, const uint8_t *data, uint32_t length, uint8_t *passphrase, uint32_t pplength); | ||
113 | |||
114 | |||
115 | /******************************* BEGIN PART 1 ******************************* | ||
116 | * And now part "1", which does the actual encryption, and is rather less cpu | ||
117 | * intensive than part one. The first 3 functions are for key handling. | ||
118 | */ | ||
119 | |||
120 | /* Generates a secret symmetric key from the given passphrase. out_key must be at least | ||
121 | * tox_pass_key_length() bytes long. | ||
122 | * Be sure to not compromise the key! Only keep it in memory, do not write to disk. | ||
123 | * The password is zeroed after key derivation. | ||
124 | * The key should only be used with the other functions in this module, as it | ||
125 | * includes a salt. | ||
126 | * Note that this function is not deterministic; to derive the same key from a | ||
127 | * password, you also must know the random salt that was used. See below. | ||
128 | * | ||
129 | * returns 0 on success | ||
130 | * returns -1 on failure | ||
131 | */ | ||
132 | int tox_derive_key_from_pass(uint8_t *passphrase, uint32_t pplength, uint8_t *out_key); | ||
133 | |||
134 | /* Same as above, except with use the given salt for deterministic key derivation. | ||
135 | * The salt must be tox_salt_length() bytes in length. | ||
136 | */ | ||
137 | int tox_derive_key_with_salt(uint8_t *passphrase, uint32_t pplength, uint8_t *salt, uint8_t *out_key); | ||
138 | |||
139 | /* This retrieves the salt used to encrypt the given data, which can then be passed to | ||
140 | * derive_key_with_salt to produce the same key as was previously used. Any encrpyted | ||
141 | * data with this module can be used as input. | ||
142 | * | ||
143 | * returns -1 if the magic number is wrong | ||
144 | * returns 0 otherwise (no guarantee about validity of data) | ||
145 | */ | ||
146 | int tox_get_salt(uint8_t *data, uint8_t *salt); | ||
147 | |||
148 | /* Now come the functions that are analogous to the part 2 functions. */ | ||
149 | |||
150 | /* Encrypt arbitrary with a key produced by tox_derive_key_. The output | ||
151 | * array must be at least data_len + tox_pass_encryption_extra_length() bytes long. | ||
152 | * key must be tox_pass_key_length() bytes. | ||
153 | * If you already have a symmetric key from somewhere besides this module, simply | ||
154 | * call encrypt_data_symmetric in toxcore/crypto_core directly. | ||
155 | * | ||
156 | * returns 0 on success | ||
157 | * returns -1 on failure | ||
158 | */ | ||
159 | int tox_pass_key_encrypt(const uint8_t *data, uint32_t data_len, const uint8_t *key, uint8_t *out); | ||
160 | |||
161 | /* Save the messenger data encrypted with the given key from tox_derive_key. | ||
162 | * data must be at least tox_encrypted_size(). | ||
163 | * | ||
164 | * returns 0 on success | ||
165 | * returns -1 on failure | ||
166 | */ | ||
167 | int tox_encrypted_key_save(const Tox *tox, uint8_t *data, uint8_t *key); | ||
168 | |||
169 | /* This is the inverse of tox_pass_key_encrypt, also using only keys produced by | ||
170 | * tox_derive_key_from_pass. | ||
171 | * | ||
172 | * returns the length of the output data (== data_len - tox_pass_encryption_extra_length()) on success | ||
173 | * returns -1 on failure | ||
174 | */ | ||
175 | int tox_pass_key_decrypt(const uint8_t *data, uint32_t length, const uint8_t *key, uint8_t *out); | ||
176 | |||
177 | /* Load the messenger from encrypted data of size length, with key from tox_derive_key. | ||
178 | * | ||
179 | * returns 0 on success | ||
180 | * returns -1 on failure | ||
181 | */ | ||
182 | int tox_encrypted_key_load(Tox *tox, const uint8_t *data, uint32_t length, uint8_t *key); | ||
183 | |||
184 | /* Determines whether or not the given data is encrypted (by checking the magic number) | ||
185 | * | ||
186 | * returns 1 if it is encrypted | ||
187 | * returns 0 otherwise | ||
188 | */ | ||
189 | int tox_is_data_encrypted(const uint8_t *data); | ||
190 | int tox_is_save_encrypted(const uint8_t *data); // poorly-named alias for backwards compat (oh irony...) | ||
191 | |||
192 | #ifdef __cplusplus | ||
193 | } | ||
194 | #endif | ||
195 | |||
196 | #endif | ||