summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--.travis.yml2
-rw-r--r--INSTALL4
-rw-r--r--INSTALL.md85
-rw-r--r--README.md9
-rw-r--r--auto_tests/Makefile.inc15
-rw-r--r--auto_tests/TCP_test.c16
-rw-r--r--auto_tests/assoc_test.c2
-rw-r--r--auto_tests/dht_test.c80
-rw-r--r--auto_tests/encryptsave_test.c190
-rw-r--r--auto_tests/network_test.c10
-rw-r--r--auto_tests/onion_test.c65
-rw-r--r--auto_tests/tox_test.c306
-rw-r--r--auto_tests/toxav_basic_test.c155
-rw-r--r--auto_tests/toxav_many_test.c149
-rw-r--r--build/Makefile.am1
-rw-r--r--configure.ac51
-rw-r--r--docs/Avatars.md631
-rw-r--r--docs/Group-Chats.md79
-rw-r--r--docs/Prevent_Tracking.txt4
-rw-r--r--docs/TODO38
-rw-r--r--docs/Tox_middle_level_network_protocol.txt18
-rw-r--r--docs/updates/DHT.md60
-rw-r--r--libtoxav.pc.in4
-rw-r--r--libtoxcore.pc.in2
-rw-r--r--other/DHT_bootstrap.c5
-rw-r--r--other/bootstrap_daemon/README.md70
-rw-r--r--other/bootstrap_daemon/tox-bootstrapd.c81
-rw-r--r--other/bootstrap_daemon/tox-bootstrapd.conf43
-rw-r--r--other/bootstrap_daemon/tox-bootstrapd.service19
-rw-r--r--other/bootstrap_daemon/tox-bootstrapd.sh2
-rw-r--r--other/bootstrap_node_packets.c2
-rwxr-xr-xother/fun/make-funny-savefile.py122
-rw-r--r--other/osx_build_script_toxcore.sh38
-rw-r--r--testing/DHT_test.c2
-rw-r--r--testing/Makefile.inc29
-rw-r--r--testing/irc_syncbot.c350
-rw-r--r--testing/nTox.c12
-rw-r--r--testing/test_avatars.c755
-rw-r--r--toxav/Makefile.inc2
-rw-r--r--toxav/codec.c571
-rw-r--r--toxav/codec.h144
-rw-r--r--toxav/group.c525
-rw-r--r--toxav/group.h53
-rw-r--r--toxav/msi.c977
-rw-r--r--toxav/msi.h182
-rw-r--r--toxav/rtp.c451
-rw-r--r--toxav/rtp.h101
-rw-r--r--toxav/toxav.c1207
-rw-r--r--toxav/toxav.h368
-rw-r--r--toxcore/DHT.c588
-rw-r--r--toxcore/DHT.h72
-rw-r--r--toxcore/LAN_discovery.c18
-rw-r--r--toxcore/LAN_discovery.h7
-rw-r--r--toxcore/Makefile.inc6
-rw-r--r--toxcore/Messenger.c1810
-rw-r--r--toxcore/Messenger.h509
-rw-r--r--toxcore/TCP_client.c140
-rw-r--r--toxcore/TCP_client.h14
-rw-r--r--toxcore/TCP_server.c39
-rw-r--r--toxcore/TCP_server.h7
-rw-r--r--toxcore/assoc.c34
-rw-r--r--toxcore/crypto_core.c7
-rw-r--r--toxcore/crypto_core.h8
-rw-r--r--toxcore/friend_connection.c688
-rw-r--r--toxcore/friend_connection.h188
-rw-r--r--toxcore/friend_requests.c53
-rw-r--r--toxcore/friend_requests.h20
-rw-r--r--toxcore/group.c2322
-rw-r--r--toxcore/group.h380
-rw-r--r--toxcore/group_chats.c837
-rw-r--r--toxcore/group_chats.h199
-rw-r--r--toxcore/logger.c238
-rw-r--r--toxcore/logger.h95
-rw-r--r--toxcore/net_crypto.c393
-rw-r--r--toxcore/net_crypto.h82
-rw-r--r--toxcore/network.c74
-rw-r--r--toxcore/network.h54
-rw-r--r--toxcore/onion.c170
-rw-r--r--toxcore/onion.h24
-rw-r--r--toxcore/onion_announce.c33
-rw-r--r--toxcore/onion_announce.h2
-rw-r--r--toxcore/onion_client.c487
-rw-r--r--toxcore/onion_client.h94
-rw-r--r--toxcore/ping.c23
-rw-r--r--toxcore/tox.c1080
-rw-r--r--toxcore/tox.h2095
-rw-r--r--toxcore/util.c108
-rw-r--r--toxcore/util.h21
-rw-r--r--toxdns/toxdns.c2
-rw-r--r--toxdns/toxdns.h13
-rw-r--r--toxencryptsave/Makefile.inc45
-rw-r--r--toxencryptsave/crypto_pwhash_scryptsalsa208sha256/crypto_pwhash_scryptsalsa208sha256.h92
-rw-r--r--toxencryptsave/crypto_pwhash_scryptsalsa208sha256/crypto_scrypt-common.c257
-rw-r--r--toxencryptsave/crypto_pwhash_scryptsalsa208sha256/crypto_scrypt.h93
-rw-r--r--toxencryptsave/crypto_pwhash_scryptsalsa208sha256/export.h38
-rw-r--r--toxencryptsave/crypto_pwhash_scryptsalsa208sha256/nosse/pwhash_scryptsalsa208sha256_nosse.c309
-rw-r--r--toxencryptsave/crypto_pwhash_scryptsalsa208sha256/note_to_maintainers.txt14
-rw-r--r--toxencryptsave/crypto_pwhash_scryptsalsa208sha256/pbkdf2-sha256.c97
-rw-r--r--toxencryptsave/crypto_pwhash_scryptsalsa208sha256/pbkdf2-sha256.h52
-rw-r--r--toxencryptsave/crypto_pwhash_scryptsalsa208sha256/pwhash_scryptsalsa208sha256.c211
-rw-r--r--toxencryptsave/crypto_pwhash_scryptsalsa208sha256/runtime.c140
-rw-r--r--toxencryptsave/crypto_pwhash_scryptsalsa208sha256/runtime.h33
-rw-r--r--toxencryptsave/crypto_pwhash_scryptsalsa208sha256/scrypt_platform.c107
-rw-r--r--toxencryptsave/crypto_pwhash_scryptsalsa208sha256/sse/pwhash_scryptsalsa208sha256_sse.c398
-rw-r--r--toxencryptsave/crypto_pwhash_scryptsalsa208sha256/sysendian.h153
-rw-r--r--toxencryptsave/crypto_pwhash_scryptsalsa208sha256/utils.c78
-rw-r--r--toxencryptsave/crypto_pwhash_scryptsalsa208sha256/utils.h40
-rw-r--r--toxencryptsave/defines.h2
-rw-r--r--toxencryptsave/toxencryptsave.c346
-rw-r--r--toxencryptsave/toxencryptsave.h196
111 files changed, 16802 insertions, 7023 deletions
diff --git a/.gitignore b/.gitignore
index 75714388..4397a1c1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -68,3 +68,6 @@ nbproject
68# Android buildscript 68# Android buildscript
69android-toolchain-* 69android-toolchain-*
70toxcore-android-* 70toxcore-android-*
71
72# cscope files list
73cscope.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
diff --git a/INSTALL b/INSTALL
index 007e9396..20998407 100644
--- a/INSTALL
+++ b/INSTALL
@@ -12,8 +12,8 @@ without warranty of any kind.
12Basic Installation 12Basic Installation
13================== 13==================
14 14
15 Briefly, the shell commands `./configure; make; make install' should 15 Briefly, the shell command `./configure && make && make install'
16configure, build, and install this package. The following 16should configure, build, and install this package. The following
17more-detailed instructions are generic; see the `README' file for 17more-detailed instructions are generic; see the `README' file for
18instructions specific to this package. Some packages provide this 18instructions 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
diff --git a/INSTALL.md b/INSTALL.md
index 0430c1ab..c2a8c0d9 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -53,14 +53,16 @@ pkg install net-im/tox
53``` 53```
54Note, if you install from ports select NaCl for performance, and sodium if you want it to be portable. 54Note, 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
56You should get and install [libsodium](https://github.com/jedisct1/libsodium): 58You should get and install [libsodium](https://github.com/jedisct1/libsodium):
57```bash 59```bash
58git clone git://github.com/jedisct1/libsodium.git 60git clone git://github.com/jedisct1/libsodium.git
59cd libsodium 61cd libsodium
60git checkout tags/0.5.0 62git checkout tags/1.0.0
61./autogen.sh 63./autogen.sh
62./configure && make check 64./configure && make check
63sudo checkinstall --install --pkgname libsodium --pkgversion 0.5.0 --nodoc 65sudo checkinstall --install --pkgname libsodium --pkgversion 1.0.0 --nodoc
64sudo ldconfig 66sudo ldconfig
65cd .. 67cd ..
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
73git clone git://github.com/jedisct1/libsodium.git 75git clone git://github.com/jedisct1/libsodium.git
74cd libsodium 76cd libsodium
75git checkout tags/0.5.0 77git checkout tags/1.0.0
76./autogen.sh 78./autogen.sh
77./configure 79./configure
78make check 80make check
@@ -88,8 +90,8 @@ sudo ldconfig
88 90
89Then clone this repo and generate makefile: 91Then clone this repo and generate makefile:
90```bash 92```bash
91git clone git://github.com/irungentoo/ProjectTox-Core.git 93git clone git://github.com/irungentoo/toxcore.git
92cd ProjectTox-Core 94cd toxcore
93autoreconf -i 95autoreconf -i
94./configure 96./configure
95make 97make
@@ -103,6 +105,8 @@ sudo make install
103You need the latest XCode with the Developer Tools (Preferences -> Downloads -> Command Line Tools). 105You need the latest XCode with the Developer Tools (Preferences -> Downloads -> Command Line Tools).
104The 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. 106The 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
106There 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. 110There 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```
119Then clone this repo and generate makefile: 123Then clone this repo and generate makefile:
120```bash 124```bash
121git clone git://github.com/irungentoo/ProjectTox-Core.git 125git clone git://github.com/irungentoo/toxcore.git
122cd ProjectTox-Core 126cd toxcore
123autoreconf -i 127autoreconf -i
124./configure 128./configure
125make 129make
@@ -135,7 +139,7 @@ brew list libsodium
135 139
136Configure include and lib folder and build again: 140Configure 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/
139make 143make
140make install 144make 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
158You must install yasm before installing libvpx, otherwise libvpx will fail to make correctly. 162Macports: (https://www.macports.org/)
163All toxcore dependencies can be installed from MacPorts. This is often easier on PowerPC Macs,
164and 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
166package in Debian.
167
168Same: libtool autoconf automake libsodium check yasm
169Different: 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
173Verify 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
176Check if that copy has libintl_setlocale:
177nm /opt/local/lib/libintl.8.dylib | grep _libintl_setlocale
178
179Certain other tools may not be installed, or outdated, and should also be installed from MacPorts for simplicity: git cmake
180
181If 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:
182ln -s /opt/local/lib/libsodium.dylib /usr/local/lib/libsodium.dylib
183
184Much 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
160pkg-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). 186pkg-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
170Compiling and installing Tox Core 196Compiling and installing Tox Core
171 197
172```bash 198```bash
173cd ProjectTox-Core 199cd toxcore
174autoreconf -i 200autoreconf -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"
176make 203make
177make install 204make install (OS X 10.5 specific)
205should be: sudo make install
206If 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
208libtoxav.0.dylib
209libtoxcore.0.dylib
210libtoxdns.0.dylib
211libtoxencryptsave.0.dylib
212to check what CPU architecture they're compiled for:
213$ lipo -i /usr/local/lib/libtoxencryptsave.0.dylib
214You should now be able to move on to compiling Toxic/Venom or some other client application
215There 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
180If 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; 218If 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
319git clone https://github.com/jedisct1/libsodium/ 357git clone https://github.com/jedisct1/libsodium/
320cd libsodium 358cd libsodium
321git checkout tags/0.6.1 359git 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
324make 362make
@@ -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.
372MinGW 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. 411MinGW 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
374First download the source tarball from https://download.libsodium.org/libsodium/releases/ and build it. 413First download the source tarball from https://download.libsodium.org/libsodium/releases/ and build it.
375Assuming that you got the libsodium-0.5.0.tar.gz release: 414Assuming that you got the libsodium-1.0.0.tar.gz release:
376```cmd 415```cmd
377tar -zxvf libsodium-0.5.0.tar.gz 416tar -zxvf libsodium-1.0.0.tar.gz
378cd libsodium-0.5.0 417cd libsodium-1.0.0
379./configure 418./configure
380make 419make
381make install 420make install
@@ -384,12 +423,12 @@ cd ..
384 423
385You 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. 424You 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
387Next, 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. 426Next, 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
389Assuming that you now have the sources in the ProjectTox-Core directory: 428Assuming that you now have the sources in the toxcore directory:
390 429
391```cmd 430```cmd
392cd ProjectTox-Core 431cd toxcore
393autoreconf -i 432autoreconf -i
394./configure 433./configure
395make 434make
@@ -440,12 +479,12 @@ There are 2 dependencies required for libtoxav: libopus and libvpx. If they are
440 479
441Install on fedora: 480Install on fedora:
442```bash 481```bash
443yum install libopus-devel libvpx-devel 482yum install opus-devel libvpx-devel
444``` 483```
445 484
446Install on ubuntu: 485Install on ubuntu:
447```bash 486```bash
448sudo apt-get install libopus-dev libvpx-dev 487sudo apt-get install libopus-dev libvpx-dev pkg-config
449``` 488```
450If you get the "Unable to locate package libopus-dev" message, add the following ppa and try again: 489If 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:
499brew install libconfig 538brew install libconfig
500``` 539```
501OS X non-homebrew: 540OS X non-homebrew:
502Grab the following [package] (http://www.hyperrealm.com/libconfig/), uncompress and install 541Grab the following [package](http://www.hyperrealm.com/libconfig/), uncompress and install
503 542
504See this [readme](other/bootstrap_daemon/README.md) on how to set up the bootstrap daemon. 543See this [readme](other/bootstrap_daemon/README.md) on how to set up the bootstrap daemon.
505 544
diff --git a/README.md b/README.md
index 82f5beae..6fd2c5e6 100644
--- a/README.md
+++ b/README.md
@@ -3,9 +3,8 @@
3 3
4With 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 /> 4With 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
27We want Tox to be as simple as possible while remaining as secure as possible. 26We 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.
30The 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. 29The 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 @@
1if BUILD_TESTS 1if BUILD_TESTS
2 2
3TESTS = messenger_autotest crypto_test network_test assoc_test onion_test TCP_test tox_test dht_autotest 3TESTS = encryptsave_test messenger_autotest crypto_test network_test assoc_test onion_test TCP_test tox_test dht_autotest
4check_PROGRAMS = messenger_autotest crypto_test network_test assoc_test onion_test TCP_test tox_test dht_autotest 4check_PROGRAMS = encryptsave_test messenger_autotest crypto_test network_test assoc_test onion_test TCP_test tox_test dht_autotest
5 5
6AUTOTEST_CFLAGS = \ 6AUTOTEST_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
99endif 100endif
100 101
101EXTRA_DIST += $(top_srcdir)/auto_tests/friends_test.c \ No newline at end of file 102
103encryptsave_test_SOURCES = ../auto_tests/encryptsave_test.c
104
105encryptsave_test_CFLAGS = $(AUTOTEST_CFLAGS)
106
107encryptsave_test_LDADD = $(AUTOTEST_LDADD)
108
109
110EXTRA_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}
122END_TEST 123END_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
179void kill_TCP_con(struct sec_TCP_con *con)
180{
181 kill_sock(con->sock);
182 free(con);
183}
184
178int write_packet_TCP_secure_connection(struct sec_TCP_con *con, uint8_t *data, uint16_t length) 185int 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}
294END_TEST 305END_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}
461END_TEST 475END_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}
492END_TEST 508END_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}
59END_TEST 60END_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}
134END_TEST 136END_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)
45void mark_all_good(Client_data *list, uint32_t length, uint8_t ipv6) 45void 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)
58uint8_t is_furthest(const uint8_t *comp_client_id, Client_data *list, uint32_t length, const uint8_t *client_id) 59uint8_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
67int client_in_list(Client_data *list, uint32_t length, const uint8_t *client_id) 70int 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
134void test_addto_lists_bad(DHT *dht, 149void 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
177void test_addto_lists_possible_bad(DHT *dht, 191void 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
264void test_addto_lists(IP ip) 285void 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
23unsigned 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};
24unsigned 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};
25char *pw = "hunter2";
26unsigned int pwlen = 7;
27
28unsigned 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 */
32void 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
42START_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}
54END_TEST
55
56START_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}
124END_TEST
125
126START_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}
162END_TEST
163
164Suite *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
175int 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}
135END_TEST 135END_TEST
136 136
137START_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}
144END_TEST
145
146Suite *network_suite(void) 137Suite *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
32static int handled_test_1; 32static int handled_test_1;
33static int handle_test_1(void *object, IP_Port source, const uint8_t *packet, uint32_t length) 33static 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
48static int handled_test_2; 48static int handled_test_2;
49static int handle_test_2(void *object, IP_Port source, const uint8_t *packet, uint32_t length) 49static 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];
72static int handled_test_3; 72static int handled_test_3;
73uint8_t test_3_pub_key[crypto_box_PUBLICKEYBYTES]; 73uint8_t test_3_pub_key[crypto_box_PUBLICKEYBYTES];
74uint8_t test_3_ping_id[crypto_hash_sha256_BYTES]; 74uint8_t test_3_ping_id[crypto_hash_sha256_BYTES];
75static int handle_test_3(void *object, IP_Port source, const uint8_t *packet, uint32_t length) 75static 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
102uint8_t nonce[crypto_box_NONCEBYTES]; 102uint8_t nonce[crypto_box_NONCEBYTES];
103static int handled_test_4; 103static int handled_test_4;
104static int handle_test_4(void *object, IP_Port source, const uint8_t *packet, uint32_t length) 104static 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}
228END_TEST 261END_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
293void 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
262START_TEST(test_announce) 307START_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}
338END_TEST 387END_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
71uint32_t custom_packet;
72
73int 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
71uint8_t filenum; 92uint8_t filenum;
72uint32_t file_accepted; 93uint32_t file_accepted;
73uint64_t file_size; 94uint64_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
145START_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}
197END_TEST
198
124START_TEST(test_few_clients) 199START_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)
292END_TEST 414END_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
297START_TEST(test_many_clients) 419START_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}
485END_TEST
358 486
359 for (i = 0; i < NUM_TOXES; ++i) { 487#define NUM_GROUP_TOX 32
488
489void 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
499static Tox *invite_tox;
500static unsigned int invite_counter;
501
502void 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
524static unsigned int num_recv;
525
526void 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
537START_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}
363END_TEST 659END_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}
73void callback_recv_ringing ( void *av, int32_t call_index, void *_arg ) 79void 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;
80void 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}
89void 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}
112void callback_call_canceled ( void *av, int32_t call_index, void *_arg ) 106void 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}
119void callback_call_rejected ( void *av, int32_t call_index, void *_arg ) 117void 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}
128void callback_call_ended ( void *av, int32_t call_index, void *_arg ) 131void 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
136void callback_call_type_change ( void *av, int32_t call_index, void *_arg ) 144void 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
169void 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
168static 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
172static void callback_video(ToxAv *av, int32_t call_index, vpx_image_t *img, void *userdata) 206void callback_audio (void *agent, int32_t call_idx, const int16_t *PCM, uint16_t size, void *data)
173{ 207{}
174} 208
209void callback_video (void *agent, int32_t call_idx, const vpx_image_t *img, void *data)
210{}
175 211
176void register_callbacks(ToxAv *av, void *data) 212void 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/******************************************************************************/
68void callback_recv_invite ( void *av, int32_t call_index, void *_arg ) 70void 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}
75void callback_recv_ringing ( void *av, int32_t call_index, void *_arg ) 75void 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}
80void callback_recv_starting ( void *av, int32_t call_index, void *_arg ) 80void 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}
85void 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}
91void callback_call_started ( void *av, int32_t call_index, void *_arg ) 89void 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}
98void callback_call_canceled ( void *av, int32_t call_index, void *_arg ) 98void 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}
105void callback_call_rejected ( void *av, int32_t call_index, void *_arg ) 101void 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}
110void 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
118void callback_requ_timeout ( void *av, int32_t call_index, void *_arg ) 107void 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
123static void callback_audio(ToxAv *av, int32_t call_index, int16_t *data, int length, void *userdata) 112void callback_audio (void *agent, int32_t call_idx, const int16_t *PCM, uint16_t size, void *data)
124{ 113{}
125}
126 114
127static void callback_video(ToxAv *av, int32_t call_index, vpx_image_t *img, void *userdata) 115void callback_video (void *agent, int32_t call_idx, const vpx_image_t *img, void *data)
128{ 116{}
129}
130 117
131void register_callbacks(ToxAv *av, void *data) 118void 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) 263START_TEST(test_AV_three_calls)
259void 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 383END_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
385int main(int argc, char *argv[]) 400int 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
7include ../toxcore/Makefile.inc 7include ../toxcore/Makefile.inc
8include ../toxdns/Makefile.inc 8include ../toxdns/Makefile.inc
9include ../toxencryptsave/Makefile.inc
9include ../toxav/Makefile.inc 10include ../toxav/Makefile.inc
10include ../other/Makefile.inc 11include ../other/Makefile.inc
11include ../testing/Makefile.inc 12include ../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
85AC_ARG_ENABLE([logging], 85AC_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
98AC_ARG_WITH(logger-level, 98AC_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
123AC_ARG_WITH(logger-path, 126AC_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
495AC_CHECK_LIB([pthread], [pthread_self],
496 [
497 PTHREAD_LDFLAGS="-lpthread"
498 AC_SUBST(PTHREAD_LDFLAGS)
499 ]
500)
501
492if test "x$BUILD_AV" = "xyes"; then 502if 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
512if test "x$BUILD_AV" = "xyes"; then 522if 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
7User avatars are small icons or images used to identify users in the friend
8list; they exist in virtually all VoIP and IM protocols and provide an easy
9way for one user to identify another in the friend list.
10
11This document describes the implementation of avatars in the Tox protocol,
12according 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
46The Single Tox Standard Draft v.0.1.0 recommends implementing avatars as
47a purely client-side feature through a procedure that can be summarized as
48sending a specially named file as a file transfer request and accepting
49it silently. This procedure can be improved to provide the previously stated
50design considerations, but this requires a higher integration with the core
51protocol. 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
76This is a very high level description. The usage patterns expected from
77client applications are described in the section "Using Avatars in Client
78Applications", and a low level protocol description is available in the
79section "Internal Protocol Description".)
80The avatar exchange is implemented with the following new elements in the
81Tox 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
128To implement this feature, the following public symbols were added. The
129complete 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 */
138typedef enum {
139 TOX_AVATAR_FORMAT_NONE,
140 TOX_AVATAR_FORMAT_PNG
141}
142TOX_AVATAR_FORMAT;
143
144
145
146/* Set the user avatar image data. */
147int tox_set_avatar(Tox *tox, uint8_t format, const uint8_t *data, uint32_t length);
148
149/* Removes the user avatar image data. */
150int tox_unset_avatar(Tox *tox);
151
152/* Get avatar data from the current user. */
153int 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). */
156int tox_hash(uint8_t *hash, const uint8_t *data, const uint32_t datalen);
157
158/* Request avatar information from a friend. */
159int tox_request_avatar_info(const Tox *tox, const int32_t friendnumber);
160
161/* Send an unrequested avatar information to a friend. */
162int tox_send_avatar_info(Tox *tox, const int32_t friendnumber);
163
164/* Request the avatar data from a friend. */
165int tox_request_avatar_data(const Tox *tox, const int32_t friendnumber);
166
167/* Set the callback function for avatar data. */
168void 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. */
171void 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
244avatars to ensure local interoperability and should be revised if this
245code is accepted into Tox core.**
246
247It is desirable that the user avatar and the cached friends avatars could be
248shared among different Tox clients in the same system, in the spirit of the
249proposed Single Tox Standard. This not only makes switching from one client
250to another easier, but also minimizes the need of data transfers, as avatars
251already downloaded by other clients can be reused.
252
253Given 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
276Example 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
289This recommendation is partially implemented by "testing/test_avatars.c".
290
291
292
293
294
295### Common operations
296
297These are minimal examples of how perform common operations with avatar
298functions. For a complete, working, example, see `testing/test_avatars.c`.
299
300
301#### Setting an avatar for the current user
302
303In this example `load_data_file` is just an hypothetical function that loads
304data 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
313If the user is connected, this function will also notify all connected
314friends about the avatar change.
315
316If the user already have an avatar defined in the client configuration, it
317must be set before connecting to the network to avoid spurious avatar change
318notifications and unnecessary data transfers.
319
320
321
322
323#### Removing the avatar from the current user
324
325To remove the current avatar, an application must call
326
327 tox_unset_avatar(tox);
328
329the effect is the same as setting the avatar format to `TOX_AVATAR_FORMAT_NONE`
330and with no data:
331
332 tox_set_avatar(tox, TOX_AVATAR_FORMAT_NONE, NULL, 0);
333
334If the user is connected, this function will also notify all connected
335friends about the avatar change.
336
337
338
339
340
341#### Receiving avatar information from friends
342
343All 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
348As 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
360And, somewhere in the Tox initialization calls, set if as the callback to be
361triggered when an avatar information event arrives:
362
363 tox_callback_avatar_info(tox, avatar_info_cb, NULL);
364
365
366A typical client will test the currently cached avatar against the hash given
367in the avatar information event and, if needed, request the avatar data.
368
369
370
371#### Receiving avatar data from friends
372
373Avatar data events are only delivered in reply of avatar data requests which
374**should** only be sent after getting the user avatar information (format
375and hash) from an avatar information event and checking it against a local
376cache.
377
378For this, an application must define an avatar information callback which
379checks 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
400Then define an avatar data callback to store the received data in the local
401cache:
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
416And, finally, register both callbacks somewhere in the Tox initialization
417calls:
418
419 tox_callback_avatar_info(tox, avatar_info_cb, NULL);
420 tox_callback_avatar_data(tox, avatar_data_cb, NULL);
421
422
423In the previous examples, implementation of the functions to check, store
424and retrieve data from the cache were omitted for brevity. These functions
425will also need to get the friend public key (client id) from they friend
426number and, usually, convert it from a byte string to a hexadecimal
427string. 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
444The 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
457To request avatar information, an user must send a packet of type
458`PACKET_ID_AVATAR_INFO_REQ`. This packet has no data fields. Upon
459receiving this packet, a client which supports avatars should answer with
460a `PACKET_ID_AVATAR_INFO`. The sender must accept that the friend may
461not answer at all.
462
463
464
465
466### Receiving avatar information
467
468Avatar information arrives in a packet of type `PACKET_ID_AVATAR_INFO` with
469the 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
475Where '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
480and 'hash' is the SHA-256 message digest of the avatar data.
481
482This packet may be sent at any time and no previous request is required.
483Clients should send this packet upon connection or when a friend
484connects, in the same way Tox sends name, status and action information.
485
486
487
488
489
490### Requesting avatar data
491
492Transmission of avatar data is a multi-step procedure using three new packet
493types.
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
529The following procedure assumes that a client "A" is requesting avatar data
530from 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
599The major security implication of background data transfers of large objects,
600like avatars, is the possibility of exhausting the network resources from a
601client. This problem is exacerbated when there is the possibility of an
602amplification attack as happens, for example, when sending a very small
603avatar request message will force the user to reply with a larger avatar
604data message.
605
606The 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
624Another problem present in the avatars is the possibility of a friend send
625a maliciously crafted image intended to exploit vulnerabilities in image
626decoders. Without an intermediate server to recompress and validate and
627convert the images to neutral formats, the client applications must handle
628this situation by themselves using stable and secure image libraries and
629imposing limits on the maximum amount of system resources the decoding
630process can take. Images coming from Tox friends must be treated in the same
631way 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 @@
1Massive public group chats. 1Group chats.
2 2
3Note that not all this document has been implemented: only private (invite only) group chats are currently implemented. 3Note: we assume everyone in the chat trusts each other.
4 4
5Everyone generates a short term public private key pair right before joining 5These group chats work by temporarily adding the 4 "closest" people defined by a distance function
6the chat. 6in group.c in order to form a circle of connected peers. These peers then relay messages to each other.
7 7
8Note that for public group chats it is impossible to protect the chat from 8A friend invites another friend to a group chat by sending them an invite packet. The friend either ignores
9being spied on by a very dedicated attacker, encryption is therefor used as a 9the invite or responds with a response packet if he wants to join the chat. The friend invite contains the type
10form of spam/access control. 10of groupchat (text only, A/V) the friend is being invited to.
11 11
12## Joining the chats
13 12
13TODO: write more of this.
14 14
15## Protocol 15## Protocol
16 16
17Invite packets:
18Invite 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
18Node format: 21Response packet
19See 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
21Get nodes (Request):
22Packet 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```
26Valid replies: a send_nodes packet
27 24
28Send_nodes (response): 25Peer 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
33Broadcast packet: 28Peer 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
31Peer query packet:
32[uint8_t id 98][uint16_t group chat number][uint8_t id 8]
33
34Peer 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
37Title response packet:
38[uint8_t id 98][uint16_t group chat number][uint8_t id 10][title]
39
40Message 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
43Lossy 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
46Group chat types:
470: text
481: AV
38 49
39Data to send to everyone:
40TODO: 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
43Note: the message number is increased by 1 for each sent message. 51Note: the message number is increased by 1 for each sent message.
44 52
@@ -49,23 +57,22 @@ No data.
49 57
5016 - new_peer 5816 - new_peer
51Tell everyone about a new peer in the chat. 59Tell 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
5417 - ban_peer 6217 - kill_peer
55Ban a peer 63[uint16_t peer_num]
56[uint8_t public_key[public_key_len]]
57
5818 - topic change
59[uint8_t topic[topiclen]]
60 64
6148 - name change 6548 - name change
62[uint8_t name[namelen]] 66[uint8_t name[namelen]]
63 67
6449 - status change 6849 - groupchat title change
65[uint8_t (status id)] 69[uint8_t title[titlelen]]
66 70
6764 - chat message 7164 - chat message
68[uint8_t message[messagelen]] 72[uint8_t message[messagelen]]
69 73
7065 - action (/me) 7465 - 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:
117announce response packet: 117announce 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]
119encrypted with the DHT private key of Node D, the public key in the request and the nonce:[[uint8_t is_stored] 119encrypted 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)
122is_stored is 2 as a response to a peer trying to announce himself to tell the
123peer that he is currently announced successfully.
122 124
123data to route response packet: 125data 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]
diff --git a/docs/TODO b/docs/TODO
index dea513b2..54137d0d 100644
--- a/docs/TODO
+++ b/docs/TODO
@@ -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
5Networking: 5Networking:
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
9DHT: 9DHT:
@@ -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
14Lossless 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
31Friend_requests.c: 29Friend_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
49blocks UDP (or is just unpunchable) (docs/TCP_Network.txt) 43blocks 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)
52See: (https://github.com/jencka/ProjectTox-libtoxdata) 46
53
54[IN PROGRESS] GUI (no official one chosen yet, a list of promising ones follows)
55https://github.com/notsecure/uTox
56https://github.com/naxuroqa/Venom
57https://github.com/Impyy/Toxy
58https://github.com/lehitoskin/blight
59https://github.com/nurupo/ProjectTox-Qt-GUI
60https://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:
43bytes)][Encrypted message containing: [Senders real public key (32 43bytes)][Encrypted message containing: [Senders real public key (32
44bytes)][padding (32 bytes)][uint64_t number (must be sent 44bytes)][padding (32 bytes)][uint64_t number (must be sent
45back untouched in cookie response)]] 45back untouched in cookie response)]]
46Encrypted message is encrypted with sender DHT private key, recievers DHT 46Encrypted message is encrypted with sender DHT private key, receivers DHT
47public key and the nonce. 47public key and the nonce.
48 48
49cookie response packet: 49cookie 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)]]
52Encrypted message is encrypted with sender DHT private key, recievers DHT 52Encrypted message is encrypted with sender DHT private key, receivers DHT
53public key and the nonce. 53public key and the nonce.
54 54
55The Cookie should be basically: 55The Cookie should be basically:
@@ -63,7 +63,7 @@ Cookie sitting outside the encrypted part][Other Cookie (used by the other to
63respond to the handshake packet)]] 63respond to the handshake packet)]]
64 64
65The handshake packet is encrypted using the real private key of the sender, the 65The handshake packet is encrypted using the real private key of the sender, the
66real private key of the receiver and the nonce. 66real public key of the receiver and the nonce.
67 67
68 68
69Alice wants to connect to bob. 69Alice wants to connect to bob.
@@ -110,11 +110,11 @@ packet request packet: [uint8_t (1)][uint8_t num][uint8_t num][uint8_t
110num]...[uint8_t num] 110num]...[uint8_t num]
111 111
112the list of nums are a list of packet numbers the other is requesting. 112the list of nums are a list of packet numbers the other is requesting.
113to get the real packet numbers from this list take the recvbuffers buffer_start 113to get the real packet numbers from this list take the recvbuffers buffer_start
114from the packet, substract 1 to it and put it in packet_num then start from the 114from the packet, subtract 1 to it and put it in packet_num then start from the
115beggining of the num list: if num is zero, add 255 to packet_num then do the 115beginning of the num list: if num is zero, add 255 to packet_num then do the
116next num. if num isn't zero, add its value to packet_num, note that the other 116next num. if num isn't zero, add its value to packet_num, note that the other
117has requested we send this packet again to them then continue to the next num in 117has requested we send this packet again to them then continue to the next num in
118the list. 118the 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 @@
1DHT protocol 1DHT protocol
2============ 2============
3 3
4NOTE: only the protocol section is up to date, the rest needs to be rewritten.
5
4Follows pretty much the principle of the torrent DHT: http://www.bittorrent.org/beps/bep_0005.html (READ IT) 6Follows pretty much the principle of the torrent DHT: http://www.bittorrent.org/beps/bep_0005.html (READ IT)
5 7
6But: 8But:
@@ -36,39 +38,39 @@ Send a get nodes request every 20 seconds to a random good node in the client li
36 38
37When a client receives any request from another 39When 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
52When a client receives a response 54When 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
95Get nodes (Request): 97Get nodes (Request):
96Packet contents: 98Packet 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```
100Valid replies: a send_nodes packet 102Valid replies: a send_nodes packet
101 103
102Send_nodes (response (for all addresses)): 104Send_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
6Name: libtoxav 6Name: libtoxav
7Description: Tox A/V library 7Description: Tox A/V library
8Requires: 8Requires: libtoxcore
9Version: @PACKAGE_VERSION@ 9Version: @PACKAGE_VERSION@
10Libs: -L${libdir} -ltoxav @AV_LIBS@ 10Libs: -L${libdir} -ltoxav @AV_LIBS@
11Cflags: -I${includedir} \ No newline at end of file 11Cflags: -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
7Description: Tox protocol library 7Description: Tox protocol library
8Requires: 8Requires:
9Version: @PACKAGE_VERSION@ 9Version: @PACKAGE_VERSION@
10Libs: @NACL_OBJECTS_PKGCONFIG@ -L${libdir} @NACL_LDFLAGS@ -ltoxdns -ltoxcore @NACL_LIBS@ @LIBS@ @MATH_LDFLAGS@ 10Libs: @NACL_OBJECTS_PKGCONFIG@ -L${libdir} @NACL_LDFLAGS@ -ltoxdns -ltoxencryptsave -ltoxcore @NACL_LIBS@ @LIBS@ @MATH_LDFLAGS@ @PTHREAD_LDFLAGS@
11Cflags: -I${includedir} 11Cflags: -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
3This instruction primarily tested on Linux but, may be, will work on other POSIX-compliant systems.
2 4
3For security reasons we run the daemon under its own user. 5For security reasons we run the daemon under its own user.
6
4Create a new user by executing the following: 7Create a new user by executing the following:
5```sh 8```sh
6sudo useradd --system --shell /sbin/nologin --comment "Account to run Tox's DHT bootstrap daemon" --user-group tox-bootstrapd 9sudo 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
9Create a directory where the daemon will store its keys: 12Copy `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
11sudo mkdir /var/lib/tox-bootstrapd/ 14Go 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
14Restrain other users from accessing the directory: 17Restrict access to home directory:
15```sh 18```sh
16sudo chown tox-bootstrapd:tox-bootstrapd /var/lib/tox-bootstrapd/ 19sudo chmod 700 /var/lib/tox-bootstrapd
17sudo chmod 700 /var/lib/tox-bootstrapd/
18``` 20```
19 21
20Look 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
22Go over everything in `tox-bootstrapd.conf`. Make sure `pid_file_path` matches `PIDFILE` from `tox-bootstrapd.sh`.
23 23
24Place `tox-bootstrapd.conf` file to where `CFGFILE` variable from `tox-bootstrapd` tells. By default it's `/etc/tox-bootstrapd.conf`. 24Look 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
26Place `tox-bootstrapd.sh` init file at `/etc/init.d/tox-bootstrapd` (note the disappearance of ".sh" ending). 26Copy `tox-bootstrapd.sh` init file to `/etc/init.d/tox-bootstrapd` (note the disappearance of ".sh" ending).
27```sh
28sudo cp tox-bootstrapd.sh /etc/init.d/tox-bootstrapd
29```
27 30
28Set permissions for the init system to run the script: 31Set 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:
50sudo grep "tox-bootstrapd" /var/log/syslog 53sudo grep "tox-bootstrapd" /var/log/syslog
51``` 54```
52 55
56##For `systemd` users:
57
58Copy tox-bootstrap.service to /etc/systemd/system/:
59```sh
60sudo cp tox-bootstrap.service /etc/systemd/system/
61```
62
63Make 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
65You 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
69and, possibly, install `libcap2-bin` or `libcap2` package, depending of your distribution.
70
53 71
72Reload systemd units definitions, enable service for automatic start (if needed), and start it:
73```sh
74sudo systemctl daemon-reload
75sudo systemctl enable tox-bootstrap.service
76sudo 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
58sudo service tox-bootstrapd status 83sudo service tox-bootstrapd status
84
85#systemd
86sudo 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
63sudo grep "tox-bootstrapd" /var/log/syslog 92sudo grep "tox-bootstrapd" /var/log/syslog
93
94#systemd
95sudo 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. 102Common:
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
225int get_general_config(char *cfg_file_path, char **pid_file_path, char **keys_file_path, int *port, int *enable_ipv6, 236int 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
373int bootstrap_from_config(char *cfg_file_path, DHT *dht, int enable_ipv6) 395int 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
478void print_public_key(uint8_t *public_key) 500void 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).
4port = 33445 4port = 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.
9keys_file_path = "/var/lib/tox-bootstrapd/keys" 9keys_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.
14pid_file_path = "/var/run/tox-bootstrapd/tox-bootstrapd.pid" 14pid_file_path = "/var/run/tox-bootstrapd/tox-bootstrapd.pid"
15 15
16// Enable IPv6. 16// Enable IPv6.
17enable_ipv6 = false 17enable_ipv6 = true
18
19// Fallback to IPv4 in case IPv6 fails.
20enable_ipv4_fallback = true
18 21
19// Automatically bootstrap with nodes on local area network. 22// Automatically bootstrap with nodes on local area network.
20enable_lan_discovery = true 23enable_lan_discovery = true
21 24
22enable_tcp_relay = true 25enable_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.
26tcp_relay_ports = [443, 3389, 33445] 29tcp_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.
30enable_motd = true 32enable_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.
32motd = "tox-bootstrapd" 36motd = "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.
41bootstrap_nodes = ( 49bootstrap_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]
2Description=Tox DHT Bootstrap Daemon
3After=network.target
4
5[Service]
6Type=forking
7PermissionsStartOnly=true
8ExecStartPre=-/bin/mkdir /var/run/tox-bootstrapd -p
9ExecStartPre=/bin/chown tox-bootstrapd:tox-bootstrapd -R /var/run/tox-bootstrapd
10WorkingDirectory=/var/lib/tox-bootstrapd
11ExecStart=/usr/local/bin/tox-bootstrapd /etc/tox-bootstrapd.conf
12User=tox-bootstrapd
13Group=tox-bootstrapd
14PIDFile=/var/run/tox-bootstrapd/tox-bootstrapd.pid
15#CapabilityBoundingSet=CAP_NET_BIND_SERVICE
16
17[Install]
18WantedBy=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
23GROUP=tox-bootstrapd 23GROUP=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 */
37static int handle_info_request(void *object, IP_Port source, const uint8_t *packet, uint32_t length) 37static 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"""
4Generate a new (and empty) save file with predefined keys. Used to play
5with externally generated keys.
6
7(c) 2015 Alexandre Erwin Ittner
8
9Distributed under the GNU GPL v3 or later, WITHOUT ANY WARRANTY. See the
10file "COPYING" for license information.
11
12
13Usage:
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
27Example (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
35PUBLIC_KEY_LENGTH = 32
36PRIVATE_KEY_LENGTH = 32
37
38# Constants taken from messenger.c
39MESSENGER_STATE_COOKIE_GLOBAL = 0x15ed1b1f
40MESSENGER_STATE_COOKIE_TYPE = 0x01ce
41MESSENGER_STATE_TYPE_NOSPAMKEYS = 1
42MESSENGER_STATE_TYPE_DHT = 2
43MESSENGER_STATE_TYPE_FRIENDS = 3
44MESSENGER_STATE_TYPE_NAME = 4
45MESSENGER_STATE_TYPE_STATUSMESSAGE = 5
46MESSENGER_STATE_TYPE_STATUS = 6
47MESSENGER_STATE_TYPE_TCP_RELAY = 10
48MESSENGER_STATE_TYPE_PATH_NODE = 11
49
50STATUS_MESSAGE = "New user".encode("utf-8")
51
52
53
54import sys
55import struct
56import os
57
58def abort(msg):
59 print(msg)
60 exit(1)
61
62
63
64if len(sys.argv) != 5:
65 abort("Usage: %s <public key> <private key> <user name> <out file>" % (sys.argv[0]))
66
67try:
68 public_key = sys.argv[1].decode("hex")
69except:
70 abort("Bad public key")
71
72try:
73 private_key = sys.argv[2].decode("hex")
74except:
75 abort("Bad private key")
76
77if len(public_key) != PUBLIC_KEY_LENGTH:
78 abort("Public key with wrong length")
79
80if len(private_key) != PRIVATE_KEY_LENGTH:
81 abort("Private key with wrong length")
82
83user_name = sys.argv[3].encode("utf-8")
84
85if len(user_name) > 32:
86 abort("User name too long (for this script, at least)")
87
88out_file_name = sys.argv[4]
89nospam = os.urandom(4)
90
91
92def 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
98data = (
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
118try:
119 with open(out_file_name, "wb") as fp:
120 fp.write(data)
121except 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
4cd ~/Downloads/toxcore
5echo "Now working in:"`pwd`
6
7# must have working git binary, and have done git clone at least once before
8git pull
9echo "If git pull responds: Already up-to-date. you can cancel the build"
10echo "by typing anything except y or Y below"
11read -p "Continue with build? (enter y to continue): " Last_Chance
12
13# blah blah
14if [[ $Last_Chance = [Yy] ]]; then echo "Continuing!";
15else echo "Aborted!"; exit
16fi
17sleep 3
18
19# if libsodium is built with macports, link it from /opt/local/ to /usr/local
20if [ ! -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
23fi
24echo "The symlink /usr/local/lib/libsodium.dylib exists."
25sleep 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
31make clean
32make
33echo ""
34echo "Sudo is required for make install only, all other steps run without it."
35echo "Please type your sudo password below for make install:"
36sudo make install
37
38exit
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
109noinst_PROGRAMS += test_avatars
110
111test_avatars_SOURCES = ../testing/test_avatars.c
112
113test_avatars_CFLAGS = $(LIBSODIUM_CFLAGS) \
114 $(NACL_CFLAGS)
115
116test_avatars_LDADD = $(LIBSODIUM_LDFLAGS) \
117 $(NACL_LDFLAGS) \
118 libtoxcore.la \
119 $(LIBSODIUM_LIBS) \
120 $(NACL_OBJECTS) \
121 $(NACL_LIBS)
122
123
124noinst_PROGRAMS += irc_syncbot
125
126irc_syncbot_SOURCES = ../testing/irc_syncbot.c
127
128irc_syncbot_CFLAGS = $(LIBSODIUM_CFLAGS) \
129 $(NACL_CFLAGS)
130
131irc_syncbot_LDADD = $(LIBSODIUM_LDFLAGS) \
132 $(NACL_LDFLAGS) \
133 libtoxcore.la \
134 $(LIBSODIUM_LIBS) \
135 $(NACL_OBJECTS) \
136 $(NACL_LIBS)
108endif 137endif
109 138
110EXTRA_DIST += $(top_srcdir)/testing/misc_tools.c 139EXTRA_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.
30uint8_t ip[4] = {127, 0, 0, 1};
31uint16_t port = 6667;
32
33#define SILENT_TIMEOUT 20
34
35int 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 */
41uint64_t current_time_monotonic(void);
42
43uint64_t get_monotime_sec(void)
44{
45 return current_time_monotonic() / 1000;
46}
47
48int 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
84int current_group = -1;
85
86static 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
92void 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
108static 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
152void 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
204Tox *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, &copy_groupmessage, 0);
227 tox_callback_group_action(tox, &copy_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
253int 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
1004void print_invite(Tox *m, int friendnumber, const uint8_t *group_public_key, void *userdata) 1004void 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
60static bool print_debug_msgs = true;
61
62static 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
79typedef struct {
80 uint8_t format;
81 char *suffix;
82} avatar_format_data_t;
83
84static 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
92static void set_avatar(Tox *tox, const char *base_dir);
93
94
95static 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 */
111static 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 */
132static 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
151static 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 */
169static 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 */
196static 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 */
231static 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 */
253static 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
289static 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
300static 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
349static 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
381static 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
428static 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
438static 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
489static 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 */
510static 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
538static 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
601static 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
671int 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
39JitterBuffer *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
55typedef ARRAY(uint8_t) Payload;
56
57typedef struct {
58 uint16_t size; /* Max size */
59 uint16_t start;
60 uint16_t end;
61 Payload **packets;
62} PayloadBuffer;
63
64static _Bool buffer_full(const PayloadBuffer *b)
65{
66 return (b->end + 1) % b->size == b->start;
67}
68
69static _Bool buffer_empty(const PayloadBuffer *b)
70{
71 return b->end == b->start;
72}
73
74static 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
82static void buffer_read(PayloadBuffer *b, Payload **p)
83{
84 *p = b->packets[b->start];
85 b->start = (b->start + 1) % b->size;
86}
87
88static 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
97static 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
113static 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 */
123typedef struct _JitterBuffer {
124 RTPMessage **queue;
125 uint32_t size;
126 uint32_t capacity;
127 uint16_t bottom;
128 uint16_t top;
129} JitterBuffer;
130
131static 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
61static void clear_queue(JitterBuffer *q) 153static 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
71void terminate_queue(JitterBuffer *q) 163static 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
80void queue(JitterBuffer *q, RTPMessage *pk) 172static 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,
104RTPMessage *dequeue(JitterBuffer *q, int *success) 198 * 1 when there's a good packet,
199 * 2 when there's a lost packet */
200static 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 227static int init_video_decoder(CSSession *cs)
132int 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
144int init_audio_decoder(CodecState *cs, uint32_t audio_channels) 239static 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
158int reconfigure_video_encoder_resolution(CodecState *cs, uint16_t width, uint16_t height) 252static 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
181int 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
200int 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
241int init_audio_encoder(CodecState *cs, uint32_t audio_channels) 293static 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 */
322int 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
270CodecState *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 ) 337const 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
363void 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
432int 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
464int 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
484CSSession *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
540error:
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
312void codec_terminate_session ( CodecState *cs ) 567void 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
332static 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
342int energy_VAD(CodecState *cs, int16_t *PCM, uint16_t frame_size, float energy) 599/* Called from RTP */
600void 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
685end:
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
41typedef enum _Capabilities { 45#define PAIR(TYPE1__, TYPE2__) struct { TYPE1__ first; TYPE2__ second; }
42 none, 46
43 a_encoding = 1 << 0, 47typedef void (*CSAudioCallback) (void *agent, int32_t call_idx, const int16_t *PCM, uint16_t size, void *data);
44 a_decoding = 1 << 1, 48typedef 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
49extern const uint16_t min_jbuf_size; 50/**
51 * Codec capabilities
52 */
53typedef 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 */
63typedef enum {
64 cs_ErrorSettingVideoResolution = -30,
65 cs_ErrorSettingVideoBitrate = -31,
66 cs_ErrorSplittingVideoPayload = -32,
67} CSError;
68
69/**
70 * Codec session - controling codec
71 */
72typedef struct _CSSession {
50 73
51typedef 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
81typedef 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
89JitterBuffer *create_queue(unsigned int capacity); 136 /* OTHER
90void terminate_queue(JitterBuffer *q); 137 *
91void queue(JitterBuffer *q, RTPMessage *pk); 138 *
92RTPMessage *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 */
156CSSession *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 */
158void cs_kill(CSSession *cs);
94 159
95CodecState *codec_init_session ( uint32_t audio_bitrate, 160int cs_split_video_payload(CSSession *cs, const uint8_t *payload, uint16_t length);
96 uint16_t audio_frame_duration, 161const 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, 166void cs_do(CSSession *cs);
102 uint16_t max_video_height,
103 uint32_t video_bitrate );
104 167
105void 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. 170int cs_set_video_encoder_resolution(CSSession *cs, uint16_t width, uint16_t height);
109 return -1 on failure. */ 171int cs_set_video_encoder_bitrate(CSSession *cs, uint32_t video_bitrate);
110int reconfigure_video_encoder_resolution(CodecState *cs, uint16_t width, uint16_t height);
111int reconfigure_video_encoder_bitrate(CodecState *cs, uint32_t video_bitrate);
112 172
113/* Calculate energy and return 1 if has voice, 0 if not */
114int energy_VAD(CodecState *cs, int16_t *PCM, uint16_t frame_size, float energy);
115 173
174/* Internal. Called from rtp_handle_message */
175void 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
30typedef struct {
31 uint16_t sequnum;
32 uint16_t length;
33 uint8_t data[];
34} Group_Audio_Packet;
35
36typedef 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
44static 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
66static 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
76static 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 */
87static 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 */
113static 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
140typedef 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
153typedef 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
161static 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
170static 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
208static 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
227static 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
239static 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
253static void group_av_groupchat_delete(void *object, int groupnumber)
254{
255 if (object)
256 kill_group_av(object);
257}
258
259static 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
356static 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 */
392static 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 */
420int 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 */
442int 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 */
465static 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 */
490int 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 */
33int 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 */
41int 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 */
51int 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 )
97GENERIC_HEADER ( CSettings, MSIRawCSettingsType ) 97GENERIC_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 */
105typedef struct _MSIMessage { 100typedef 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
118inline__ void invoke_callback(MSISession *session, int32_t call_index, MSICallbackID id) 113static 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 */
137static int parse_raw_data ( MSIMessage *msg, const uint8_t *data, uint16_t length ) 127static 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 */
221MSIMessage *msi_new_message ( MSIMessageType type, const uint8_t type_value ) 206MSIMessage *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 */
250MSIMessage *parse_recv ( const uint8_t *data, uint16_t length ) 231MSIMessage *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 */
284uint8_t *format_output ( uint8_t *dest, MSIHeaderID id, const void *value, uint8_t value_len, uint16_t *length ) 258uint8_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 */
316uint16_t parse_send ( MSIMessage *msg, uint8_t *dest ) 290uint16_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
454typedef struct _Timer { 428typedef 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
463typedef struct _TimerHandler { 437typedef 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
475struct timer_function_args {
476 void *arg1;
477 int arg2;
478};
479 444
480/** 445static 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 */
489static 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/** 490static 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 */
546static 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 */
597static 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 */
644static 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 */
686static 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 */
711static void t_randomstr ( uint8_t *str, uint32_t size ) 529static 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 */
731typedef enum { 549typedef 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 */
751static inline__ const uint8_t *stringify_error ( MSICallError error_code ) 566static 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 */
776static int send_message ( MSISession *session, MSICall *call, MSIMessage *msg, uint32_t to ) 581static 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
796inline__ int send_reponse ( MSISession *session, MSICall *call, MSIResponse response, uint32_t to ) 601static 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
609static 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 */
813static int call_id_bigger( const uint8_t *first, const uint8_t *second) 630static 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 */
827static int flush_peer_csettings ( MSICall *call, MSIMessage *msg, int peer_id ) 639static 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
857static int terminate_call ( MSISession *session, MSICall *call );
858
859static 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
890static 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 */
913static 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 */
940static void add_peer( MSICall *call, int peer_id ) 673static 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/** 691static 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
966static MSICall *init_call ( MSISession *session, int peers, int ringing_timeout ) 705static 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 */
1026static int terminate_call ( MSISession *session, MSICall *call ) 754static 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
777static 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 */
1066static void *handle_timeout ( void *arg ) 811static 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}
1306static int handle_recv_starting ( MSISession *session, MSICall *call, MSIMessage *msg ) 999static 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}
1369static int handle_recv_error ( MSISession *session, MSICall *call, MSIMessage *msg ) 1051static 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 */
1429static void msi_handle_packet ( Messenger *messenger, int source, const uint8_t *data, uint16_t length, void *object ) 1104static 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 */
1522void msi_register_callback ( MSISession *session, MSICallbackType callback, MSICallbackID id, void *userdata ) 1196void 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/** 1203MSISession *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 */
1537MSISession *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
1261error:
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/** 1274int msi_kill ( MSISession *session )
1587 * @brief Terminate control session.
1588 *
1589 * @param session The session
1590 * @return int
1591 */
1592int 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 1314int 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 */
1636int 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 */
1696int msi_hangup ( MSISession *session, int32_t call_index ) 1368int 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 1404int 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 */
1741int 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 */
1776int msi_cancel ( MSISession *session, int32_t call_index, uint32_t peer, const char *reason ) 1436int 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 */
1821int msi_reject ( MSISession *session, int32_t call_index, const char *reason ) 1479int 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
1525int 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);
1872int msi_change_csettings(MSISession *session, int32_t call_index, MSICSettings csettings) 1540 return 0;
1541}
1542
1543int 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 1594void 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 */
1931int 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
30typedef uint8_t MSICallIDType[12]; 31typedef uint8_t MSICallIDType[12];
31typedef uint8_t MSIReasonStrType[255]; 32typedef uint8_t MSIReasonStrType[255];
32typedef void ( *MSICallbackType ) ( void *agent, int32_t call_idx, void *arg ); 33typedef 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 */
38typedef enum { 38typedef 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 */
47typedef enum { 47typedef 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 */
60typedef struct _MSICodecSettings { 60typedef 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 */
77typedef enum { 77typedef 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 */
99typedef struct _MSICallbackCont { 93typedef 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 */
108typedef struct _MSICall { /* Call info structure */ 103typedef 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 */
136typedef struct _MSISession { 128typedef 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 */
162void msi_register_callback(MSISession *session, MSICallbackType callback, MSICallbackID id, void *userdata); 149MSISession *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 */
173MSISession *msi_init_session ( Messenger *messenger, int32_t max_calls ); 154int 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 */
182int msi_terminate_session ( MSISession *session ); 159void 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 */
195int msi_invite ( MSISession *session, int32_t *call_index, MSICSettings csettings, uint32_t rngsec, 164int 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 */
208int msi_hangup ( MSISession *session, int32_t call_index ); 173int 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 */
219int msi_answer ( MSISession *session, int32_t call_index, MSICSettings csettings ); 178int 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 */
231int msi_cancel ( MSISession *session, int32_t call_index, uint32_t peer, const char *reason ); 183int 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 */
242int msi_reject ( MSISession *session, int32_t call_index, const char *reason ); 188int 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 */
255int msi_change_csettings ( MSISession *session, int32_t call_index, MSICSettings csettings ); 193int msi_stopcall ( MSISession *session, int32_t call_index );
256 194
195/**
196 * Change codec settings of the current call.
197 */
198int 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 */
265int msi_stopcall ( MSISession *session, int32_t call_index ); 203void 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>
31void toxav_handle_packet(RTPSession *_session, RTPMessage *_msg); 31void 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 */
58inline__ int check_late_message (RTPSession *session, RTPMessage *msg) 52static 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 */
77RTPHeader *extract_header ( const uint8_t *payload, int length ) 66RTPHeader *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 */
153RTPExtHeader *extract_ext_header ( const uint8_t *payload, uint16_t length ) 141RTPExtHeader *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 */
202uint8_t *add_header ( RTPHeader *header, uint8_t *payload ) 189uint8_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, &timestamp, 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 */
240uint8_t *add_ext_header ( RTPExtHeader *header, uint8_t *payload ) 230uint8_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 */
267RTPHeader *build_header ( RTPSession *session ) 261RTPHeader *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 */
310RTPMessage *msg_parse ( const uint8_t *data, int length ) 296RTPMessage *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 */
366int rtp_handle_packet ( void *object, const uint8_t *data, uint32_t length ) 344int 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 */
406RTPMessage *rtp_new_message ( RTPSession *session, const uint8_t *data, uint32_t length ) 375RTPMessage *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 */
466int rtp_send_msg ( RTPSession *session, Messenger *messenger, const uint8_t *data, uint16_t length ) 425int 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 */
498void rtp_free_msg ( RTPSession *session, RTPMessage *msg ) 445void 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/** 463RTPSession *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 */
526RTPSession *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 513void 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 */
586void 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
34typedef enum {
35 rtp_ErrorSending = -40
36} RTPError;
37/** 37/**
38 * @brief Standard rtp header 38 * Standard rtp header
39 *
40 */ 39 */
41
42typedef struct _RTPHeader { 40typedef 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 */
58typedef struct _RTPExtHeader { 54typedef 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 */
70typedef struct _RTPMessage { 64typedef 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 */
89typedef struct _RTPSession { 77typedef 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 */
126int 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 */
136void rtp_queue_adjust_limit ( RTPSession *session, uint64_t limit ); 108RTPSession *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 */
145RTPMessage *rtp_recv_msg ( RTPSession *session ); 113void 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 */
158int rtp_send_msg ( RTPSession *session, Messenger *messenger, const uint8_t *data, uint16_t length ); 118int 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 */
168void rtp_free_msg ( RTPSession *session, RTPMessage *msg ); 123void 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 */
180RTPSession *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 */
192void 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__
27typedef 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
55const ToxAvCSettings av_DefaultSettings = { 48const 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
68const uint32_t av_jbufdc = 3; 61static const uint32_t jbuf_capacity = 6;
69const uint32_t av_VADd = 40;
70
71
72static const uint8_t audio_index = 0, video_index = 1; 62static const uint8_t audio_index = 0, video_index = 1;
73 63
74typedef struct { 64typedef 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
82typedef 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
109struct _ToxAv { 74struct _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
123static void *toxav_decoding(void *arg); 89static const MSICSettings *msicsettings_cast (const ToxAvCSettings *from)
124
125static 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
142static ToxAvCSettings toxavcsettings_cast (const MSICSettings *from) 95static 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 */
170ToxAv *toxav_new( Tox *messenger, int32_t max_calls) 102ToxAv *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 */
194void toxav_kill ( ToxAv *av ) 133void 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/** 157uint32_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 */
227void 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/** 176void toxav_do(ToxAv *av)
233 * @brief Register callback for recieving audio data
234 *
235 * @param callback The callback
236 * @return void
237 */
238void 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/** 209void 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 */
251void 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/** 214void 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 */
269int 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/** 220void 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 */
282int 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 ) { 226int 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
235int 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 */
304int toxav_answer ( ToxAv *av, int32_t call_index, const ToxAvCSettings *csettings ) 240int 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 */
326int toxav_reject ( ToxAv *av, int32_t call_index, const char *reason ) 245int 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 */
349int toxav_cancel ( ToxAv *av, int32_t call_index, int peer_id, const char *reason ) 250int 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 */
371int toxav_change_settings(ToxAv *av, int32_t call_index, const ToxAvCSettings *csettings) 255int 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 */
388int toxav_stop_call ( ToxAv *av, int32_t call_index ) 260int 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/** 265int 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 */
405int 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;
514error: 354error:
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 */
532int toxav_kill_transmission ( ToxAv *av, int32_t call_index ) 370int 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/** 412static 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 */
610static 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 */
667int 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/** 446int 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 */
702int 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/** 501int 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 */
764int 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/** 525int 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 */
802int 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/** 559int 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
840int toxav_get_peer_csettings ( ToxAv *av, int32_t call_index, int peer, ToxAvCSettings *dest ) 581int 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 */
858int toxav_get_peer_id ( ToxAv *av, int32_t call_index, int peer ) 591int 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 */
875ToxAvCallState toxav_get_call_state(ToxAv *av, int32_t call_index) 600ToxAvCallState 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/** 609int 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 */
892inline__ 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
898inline__ Tox *toxav_get_tox(ToxAv *av) 615Tox *toxav_get_tox(ToxAv *av)
899{ 616{
900 return (Tox *)av->messenger; 617 return (Tox *)av->messenger;
901} 618}
902 619
903int toxav_has_activity(ToxAv *av, int32_t call_index, int16_t *PCM, uint16_t frame_size, float ref_energy) 620int 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
911static 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
934static 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 */
647int 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
958static 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 */
664int 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
1028void 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 */
685int 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
1144end:
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 @@
28extern "C" { 28extern "C" {
29#endif 29#endif
30 30
31typedef 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
34typedef void ( *ToxAVCallback ) ( void *agent, int32_t call_idx, void *arg ); 36typedef void ( *ToxAVCallback ) ( void *agent, int32_t call_idx, void *arg );
35typedef struct _ToxAv ToxAv; 37typedef void ( *ToxAvAudioCallback ) (void *agent, int32_t call_idx, const int16_t *PCM, uint16_t size, void *data);
38typedef 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 */
48typedef enum { 51typedef 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 */
71typedef enum { 68typedef enum {
72 TypeAudio = 192, 69 av_TypeAudio = 192,
73 TypeVideo 70 av_TypeVideo
74} ToxAvCallType; 71} ToxAvCallType;
75 72
76 73
77typedef enum { 74typedef 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 */
89typedef enum { 86typedef 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 */
110typedef enum { 110typedef 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 */
121typedef struct _ToxAvCodecSettings { 121typedef 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
134extern const ToxAvCSettings av_DefaultSettings; 134extern const ToxAvCSettings av_DefaultSettings;
135extern const uint32_t av_jbufdc; /* Jitter buffer default capacity */
136extern 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 */
149ToxAv *toxav_new(Tox *messenger, int32_t max_calls); 139ToxAv *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 */
157void toxav_kill(ToxAv *av); 144void 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 */
167void toxav_register_callstate_callback (ToxAv *av, ToxAVCallback callback, ToxAvCallbackID id, void *userdata); 150uint32_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 */
176void toxav_register_audio_recv_callback (ToxAv *av, void (*callback)(ToxAv *, int32_t, int16_t *, int, void *), 155void 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 */
186void toxav_register_video_recv_callback (ToxAv *av, void (*callback)(ToxAv *, int32_t, vpx_image_t *, void *), 160void 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 */
200int toxav_call(ToxAv *av, int32_t *call_index, int user, const ToxAvCSettings *csettings, int ringing_seconds); 165void 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. 170void 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 */
175int 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 */
210int toxav_hangup(ToxAv *av, int32_t call_index); 184int 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 */
221int toxav_answer(ToxAv *av, int32_t call_index, const ToxAvCSettings *csettings ); 189int 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 */
232int toxav_reject(ToxAv *av, int32_t call_index, const char *reason); 194int 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 */
244int toxav_cancel(ToxAv *av, int32_t call_index, int peer_id, const char *reason); 199int 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 */
254int toxav_change_settings(ToxAv *av, int32_t call_index, const ToxAvCSettings *csettings); 204int 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 */
264int toxav_stop_call(ToxAv *av, int32_t call_index); 210int 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 */
275int toxav_prepare_transmission(ToxAv *av, int32_t call_index, uint32_t jbuf_size, uint32_t VAD_treshold, 216int 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 */
286int toxav_kill_transmission(ToxAv *av, int32_t call_index); 221int 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 */
298int toxav_send_video ( ToxAv *av, int32_t call_index, const uint8_t *frame, unsigned int frame_size); 226int 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 */
310int toxav_send_audio ( ToxAv *av, int32_t call_index, const uint8_t *frame, unsigned int size); 235int 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 */
323int toxav_prepare_video_frame ( ToxAv *av, int32_t call_index, uint8_t *dest, int dest_max, vpx_image_t *input ); 240int 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 250int 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 */
337int 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 */
349int toxav_get_peer_csettings ( ToxAv *av, int32_t call_index, int peer, ToxAvCSettings *dest ); 256int 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 */
359int toxav_get_peer_id ( ToxAv *av, int32_t call_index, int peer ); 261int 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 */
369ToxAvCallState toxav_get_call_state ( ToxAv *av, int32_t call_index ); 266ToxAvCallState 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 */
378int toxav_capability_supported ( ToxAv *av, int32_t call_index, ToxAvCapabilities capability ); 271int toxav_capability_supported ( ToxAv *av, int32_t call_index, ToxAvCapabilities capability );
379 272
273/**
274 * Returns tox reference.
275 */
276Tox *toxav_get_tox (ToxAv *av);
277
278/**
279 * Returns number of active calls or -1 on error.
280 */
281int 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 */
293int 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
381Tox *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 */
306int 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
383int 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 */
322int 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
68Client_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
172void to_host_family(IP *ip) 167int 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 */
321static int client_or_ip_port_in_list(Client_data *list, uint32_t length, const uint8_t *client_id, IP_Port ip_port) 321static 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 */
400static int client_in_nodelist(const Node_format *list, uint32_t length, const uint8_t *client_id) 400static 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
608static uint8_t cmp_public_key[crypto_box_PUBLICKEYBYTES];
609static 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 */
655static 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 */
621static int replace_all( Client_data *list, 678static 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 */
727static 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) */
813static int getnodes(DHT *dht, IP_Port ip_port, const uint8_t *public_key, const uint8_t *client_id, 890static 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
919static int handle_getnodes(void *object, IP_Port source, const uint8_t *packet, uint32_t length) 996static 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
981static int send_hardening_getnode_res(const DHT *dht, const Node_format *sendto, const uint8_t *queried_client_id, 1051static 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
984static int handle_sendnodes_core(void *object, IP_Port source, const uint8_t *packet, uint32_t length, 1054static 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
1046static int handle_sendnodes_ipv6(void *object, IP_Port source, const uint8_t *packet, uint32_t length) 1116static 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*/
1097int DHT_addfriend(DHT *dht, const uint8_t *client_id) 1168int 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
1151int DHT_delfriend(DHT *dht, const uint8_t *client_id) 1253int 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 */
1359int route_packet(const DHT *dht, const uint8_t *client_id, const uint8_t *packet, uint32_t length) 1470int 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 */
1454int route_tofriend(const DHT *dht, const uint8_t *friend_id, const uint8_t *packet, uint32_t length) 1565int 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 */
1509static int routeone_tofriend(DHT *dht, const uint8_t *friend_id, const uint8_t *packet, uint32_t length) 1620static 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 */
1562int 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. */
1606static int handle_NATping(void *object, IP_Port source, const uint8_t *source_pubkey, const uint8_t *packet, 1697static 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 */
1886static int handle_hardening(void *object, IP_Port source, const uint8_t *source_pubkey, const uint8_t *packet, 1977static 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. */
2015static 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 */
2060uint16_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
2090void do_hardening(DHT *dht) 2105void 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
2148static int cryptopacket_handle(void *object, IP_Port source, const uint8_t *packet, uint32_t length) 2163static 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
2230void do_DHT(DHT *dht) 2245void 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
2358static 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
2377static 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 */
2401int 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
2336static int dht_load_state_callback(void *outer, const uint8_t *data, uint32_t length, uint16_t type) 2421static 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. */
67void to_net_family(IP *ip); 67void to_net_family(IP *ip);
68void to_host_family(IP *ip); 68
69/* return 0 on success, -1 on failure. */
70int to_host_family(IP *ip);
69 71
70typedef struct { 72typedef 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
125typedef struct { 129typedef 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
138typedef struct __attribute__ ((__packed__)) 150typedef 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}
143Node_format; 154Node_format;
@@ -177,7 +188,7 @@ typedef struct {
177/*----------------------------------------------------------------------------------*/ 188/*----------------------------------------------------------------------------------*/
178 189
179typedef int (*cryptopacket_handler_callback)(void *object, IP_Port ip_port, const uint8_t *source_pubkey, 190typedef 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
182typedef struct { 193typedef 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 */
244int DHT_addfriend(DHT *dht, const uint8_t *client_id); 269int 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 */
252int DHT_delfriend(DHT *dht, const uint8_t *client_id); 278int 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 */
301uint16_t closelist_nodes(DHT *dht, Node_format *nodes, uint16_t max_num); 327uint16_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 */
309uint16_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). */
312void do_DHT(DHT *dht); 330void do_DHT(DHT *dht);
313 331
@@ -332,6 +350,12 @@ void DHT_bootstrap(DHT *dht, IP_Port ip_port, const uint8_t *public_key);
332int DHT_bootstrap_from_address(DHT *dht, const char *address, uint8_t ipv6enabled, 350int 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 */
358int 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 */
342int route_packet(const DHT *dht, const uint8_t *client_id, const uint8_t *packet, uint32_t length); 366int 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 */
348int route_tofriend(const DHT *dht, const uint8_t *friend_id, const uint8_t *packet, uint32_t length); 372int 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 */
352void cryptopacket_registerhandler(DHT *dht, uint8_t byte, cryptopacket_handler_callback cb, void *object); 376void 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 */
362int 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
272static int handle_LANdiscovery(void *object, IP_Port source, const uint8_t *packet, uint32_t length) 288static 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
42static void set_friend_status(Messenger *m, int32_t friendnumber, uint8_t status); 39static void set_friend_status(Messenger *m, int32_t friendnumber, uint8_t status);
43static int write_cryptpacket_id(const Messenger *m, int32_t friendnumber, uint8_t packet_id, const uint8_t *data, 40static 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);
45static int clear_receipts(Messenger *m, int32_t friendnumber); 42static 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
48static uint8_t friend_not_valid(const Messenger *m, int32_t friendnumber) 45static 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
53static int add_online_friend(Messenger *m, int32_t friendnumber) 56static 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 */
95int32_t getfriend_id(const Messenger *m, const uint8_t *client_id) 98int32_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 */
114int getclient_id(const Messenger *m, int32_t friendnumber, uint8_t *client_id) 117int 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 */
129int 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. */ 167static int send_online_packet(Messenger *m, int32_t friendnumber)
157static 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) { 177static 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
184static int handle_status(void *object, int i, uint8_t status);
185static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len);
186static int handle_custom_lossy_packet(void *object, int friend_num, const uint8_t *packet, uint16_t length);
187
188static 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
268int32_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 */
321int 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
350int m_get_friend_connectionstatus(const Messenger *m, int32_t friendnumber) 303int32_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
358int 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
366static int clear_receipts(Messenger *m, int32_t friendnumber) 317static 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 */
391int 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
425int 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
445int 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
435static uint32_t send_message_generic(Messenger *m, int32_t friendnumber, const uint8_t *message, uint32_t length, 454static 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 */
489static int m_sendname(const Messenger *m, int32_t friendnumber, const uint8_t *name, uint16_t length) 507static 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 */
523int setname(Messenger *m, const uint8_t *name, uint16_t length) 541int 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
602int m_set_userstatus(Messenger *m, uint8_t status) 626int 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
643int 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
661int 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
694int 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
716int 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
724int m_avatar_hash(uint8_t *hash, const uint8_t *data, const uint32_t datalen)
725{
726 return m_hash(hash, data, datalen);
727}
728
729int 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
740int 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
755int 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
651int m_copy_self_statusmessage(const Messenger *m, uint8_t *buf, uint32_t maxlen) 820int 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
659uint8_t m_get_userstatus(const Messenger *m, int32_t friendnumber) 826uint8_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)
686int m_set_usertyping(Messenger *m, int32_t friendnumber, uint8_t is_typing) 853int 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
702uint8_t m_get_istyping(const Messenger *m, int32_t friendnumber) 871int 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
710static int send_statusmessage(const Messenger *m, int32_t friendnumber, const uint8_t *status, uint16_t length) 879static 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
715static int send_userstatus(const Messenger *m, int32_t friendnumber, uint8_t status) 884static 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
720static int send_user_istyping(const Messenger *m, int32_t friendnumber, uint8_t is_typing) 889static 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
726static 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
736static int send_relays(const Messenger *m, int32_t friendnumber) 895static 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. */
780void m_callback_friendrequest(Messenger *m, void (*function)(Messenger *m, const uint8_t *, const uint8_t *, uint16_t, 940void 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. */
788void m_callback_friendmessage(Messenger *m, void (*function)(Messenger *m, int32_t, const uint8_t *, uint16_t, void *), 948void 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
795void m_callback_action(Messenger *m, void (*function)(Messenger *m, int32_t, const uint8_t *, uint16_t, void *), 955void 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
802void m_callback_namechange(Messenger *m, void (*function)(Messenger *m, int32_t, const uint8_t *, uint16_t, void *), 962void 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
809void m_callback_statusmessage(Messenger *m, void (*function)(Messenger *m, int32_t, const uint8_t *, uint16_t, void *), 969void 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
816void m_callback_userstatus(Messenger *m, void (*function)(Messenger *m, int32_t, uint8_t, void *), void *userdata) 976void 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
822void m_callback_typingchange(Messenger *m, void(*function)(Messenger *m, int32_t, uint8_t, void *), void *userdata) 982void 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
828void m_callback_read_receipt(Messenger *m, void (*function)(Messenger *m, int32_t, uint32_t, void *), void *userdata) 988void 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
834void m_callback_connectionstatus(Messenger *m, void (*function)(Messenger *m, int32_t, uint8_t, void *), void *userdata) 994void 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
840void m_callback_connectionstatus_internal_av(Messenger *m, void (*function)(Messenger *m, int32_t, uint8_t, void *), 1001void 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
1008void 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
1015void 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
1022static 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
847static void break_files(const Messenger *m, int32_t friendnumber); 1039static void break_files(const Messenger *m, int32_t friendnumber);
848static void check_friend_connectionstatus(Messenger *m, int32_t friendnumber, uint8_t status) 1040static 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
884static int write_cryptpacket_id(const Messenger *m, int32_t friendnumber, uint8_t packet_id, const uint8_t *data, 1073static 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 */
907static 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 */
925static 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 */
949static 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 */
966void m_callback_group_invite(Messenger *m, void (*function)(Messenger *m, int32_t, const uint8_t *, void *), 1099void 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 */
977void 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 */
988void 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 */
1000void 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
1007static 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
1019static 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
1036static 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
1053static 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 */
1071int 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 */
1118int 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 */
1160int 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 */
1176static 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 */
1187static 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 */
1209int 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 */
1235int 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 */
1271int 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 */
1286int 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 */
1300int 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 */
1318int group_names(const Messenger *m, int groupnumber, uint8_t names[][MAX_NICK_BYTES], uint16_t lengths[], 1110int 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
1327static 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
1348static 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 */
1365void callback_file_sendrequest(Messenger *m, void (*function)(Messenger *m, int32_t, uint8_t, uint64_t, const uint8_t *, 1122void 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 */
1377void callback_file_control(Messenger *m, void (*function)(Messenger *m, int32_t, uint8_t, uint8_t, uint8_t, 1135void 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 */
1389void callback_file_data(Messenger *m, void (*function)(Messenger *m, int32_t, uint8_t, const uint8_t *, uint16_t length, 1147void 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 */
1709void m_callback_msi_packet(Messenger *m, void (*function)(Messenger *m, int32_t, const uint8_t *, uint16_t, void *), 1469void 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 */
1721int m_msi_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint16_t length) 1481int 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
1726static int handle_custom_lossy_packet(void *object, int friend_num, const uint8_t *packet, uint16_t length) 1486static 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
1740int custom_lossy_packet_registerhandler(Messenger *m, int32_t friendnumber, uint8_t byte, 1501int 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
1771static int handle_custom_lossless_packet(void *object, int friend_num, const uint8_t *packet, uint16_t length) 1531static 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
1791int custom_lossless_packet_registerhandler(Messenger *m, int32_t friendnumber, uint8_t byte, 1552int 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*/
1824static int friend_already_added(const uint8_t *client_id, void *data) 1597static 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
1843static int handle_status(void *object, int i, uint8_t status);
1844static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len);
1845
1846static 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. */
1869Messenger *new_messenger(Messenger_Options *options) 1617Messenger *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. */
1940void kill_messenger(Messenger *m) 1685void 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 */
1760static 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
1771static 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
1884static 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
1957static 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
2006static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len) 2026static 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
2251static 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. */
2273void do_friends(Messenger *m) 2306void 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
2372static time_t lastdump = 0; 2374static time_t lastdump = 0;
2373static char IDString[CLIENT_ID_SIZE * 2 + 1]; 2375static char IDString[crypto_box_PUBLICKEYBYTES * 2 + 1];
2374static char *ID2String(const uint8_t *client_id) 2376static 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 */
2395uint32_t messenger_run_interval(Messenger *m) 2397uint32_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. */
2407void do_messenger(Messenger *m) 2409void 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
2557struct SAVED_FRIEND { 2559struct 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
2674static uint8_t *z_state_save_subheader(uint8_t *data, uint32_t len, uint16_t type) 2676static 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(). */
2685void messenger_save(const Messenger *m, uint8_t *data) 2686void 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. */
2895uint32_t copy_friendlist(Messenger const *m, int32_t *out_list, uint32_t list_size) 2890uint32_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 */
2927int 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. */
2957uint32_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. */
2976uint32_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 @@
69typedef struct { 74typedef 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
123enum {
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}
129USERSTATUS; 139USERSTATUS;
130 140
141/* AVATAR_FORMAT -
142 * Data formats for user avatar images
143 */
144typedef enum {
145 AVATAR_FORMAT_NONE = 0,
146 AVATAR_FORMAT_PNG
147}
148AVATAR_FORMAT;
149
150/* AVATAR_DATACONTROL
151 * To control avatar data requests (PACKET_ID_AVATAR_DATA_CONTROL)
152 */
153typedef enum {
154 AVATAR_DATACONTROL_REQ,
155 AVATAR_DATACONTROL_ERROR
156}
157AVATAR_DATACONTROL;
158
159typedef 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}
167AVATAR_RECEIVEDATA;
168
169typedef 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}
174AVATAR_SENDDATA;
175
176
131struct File_Transfers { 177struct 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
202typedef struct Messenger Messenger;
203
156typedef struct { 204typedef 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
201typedef struct Messenger { 251struct 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 */
302int32_t m_addfriend_norequest(Messenger *m, const uint8_t *client_id); 361int32_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 */
307int32_t getfriend_id(const Messenger *m, const uint8_t *client_id); 366int32_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 */
315int getclient_id(const Messenger *m, int32_t friendnumber, uint8_t *client_id); 374int 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 */
379int 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 */
330int m_get_friend_connectionstatus(const Messenger *m, int32_t friendnumber); 395int 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 */
425int m_copy_statusmessage(const Messenger *m, int32_t friendnumber, uint8_t *buf, uint32_t maxlen); 490int m_copy_statusmessage(const Messenger *m, int32_t friendnumber, uint8_t *buf, uint32_t maxlen);
426int m_copy_self_statusmessage(const Messenger *m, uint8_t *buf, uint32_t maxlen); 491int 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)
433uint8_t m_get_userstatus(const Messenger *m, int32_t friendnumber); 498uint8_t m_get_userstatus(const Messenger *m, int32_t friendnumber);
434uint8_t m_get_self_userstatus(const Messenger *m); 499uint8_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 */
516int 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) */
521int 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 */
543int 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 */
559int 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 */
574int 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 */
584int 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 */
596int 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 */
606int 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 */
454uint8_t m_get_istyping(const Messenger *m, int32_t friendnumber); 627int 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 */
459void m_callback_friendrequest(Messenger *m, void (*function)(Messenger *m, const uint8_t *, const uint8_t *, uint16_t, 632void 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 */
465void m_callback_friendmessage(Messenger *m, void (*function)(Messenger *m, int32_t, const uint8_t *, uint16_t, void *), 638void 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 */
471void m_callback_action(Messenger *m, void (*function)(Messenger *m, int32_t, const uint8_t *, uint16_t, void *), 644void 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 */
478void m_callback_namechange(Messenger *m, void (*function)(Messenger *m, int32_t, const uint8_t *, uint16_t, void *), 651void 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 */
486void m_callback_statusmessage(Messenger *m, void (*function)(Messenger *m, int32_t, const uint8_t *, uint16_t, void *), 659void 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 */
492void m_callback_userstatus(Messenger *m, void (*function)(Messenger *m, int32_t, uint8_t, void *), void *userdata); 665void 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 */
497void m_callback_typingchange(Messenger *m, void(*function)(Messenger *m, int32_t, uint8_t, void *), void *userdata); 670void 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 */
508void m_callback_read_receipt(Messenger *m, void (*function)(Messenger *m, int32_t, uint32_t, void *), void *userdata); 681void 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 */
521void m_callback_connectionstatus(Messenger *m, void (*function)(Messenger *m, int32_t, uint8_t, void *), 694void 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 */
524void m_callback_connectionstatus_internal_av(Messenger *m, void (*function)(Messenger *m, int32_t, uint8_t, void *), 697void 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)
533void 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
540void 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 */
547void m_callback_group_action(Messenger *m, void (*function)(Messenger *m, int, int, const uint8_t *, uint16_t, void *), 714void 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 */
555void 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 */
563int 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
570int 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.
578int 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 */
584int 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 */
591int join_groupchat(Messenger *m, int32_t friendnumber, const uint8_t *friend_group_public_key); 738void 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 */
597int 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 */
603int 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 */
608int 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 */
749void 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 */
620int group_names(const Messenger *m, int groupnumber, uint8_t names[][MAX_NICK_BYTES], uint16_t lengths[], 756int 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 */
630void callback_file_sendrequest(Messenger *m, void (*function)(Messenger *m, int32_t, uint8_t, uint64_t, const uint8_t *, 765void 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 */
638void callback_file_control(Messenger *m, void (*function)(Messenger *m, int32_t, uint8_t, uint8_t, uint8_t, 774void 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 */
646void callback_file_data(Messenger *m, void (*function)(Messenger *m, int32_t, uint8_t, const uint8_t *, uint16_t length, 782void 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 */
696void m_callback_msi_packet(Messenger *m, void (*function)(Messenger *m, int32_t, const uint8_t *, uint16_t, void *), 833void 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 */
713int custom_lossy_packet_registerhandler(Messenger *m, int32_t friendnumber, uint8_t byte, 850int 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 */
731int custom_lossless_packet_registerhandler(Messenger *m, int32_t friendnumber, uint8_t byte, 869int 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 */
761uint32_t messenger_run_interval(Messenger *m); 900uint32_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. */
787uint32_t copy_friendlist(const Messenger *m, int32_t *out_list, uint32_t list_size); 926uint32_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 */
795int 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. */
800uint32_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. */
807uint32_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 */
38static int connect_sock_to(sock_t sock, IP_Port ip_port, TCP_Proxy_Info *proxy_info) 38static 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 */
74static 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
70static 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 */
104static 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
132static 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
98static void socks5_generate_connection_request(TCP_Client_Connection *TCP_conn) 160static 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 */
128static int socks5_read_connection_response(TCP_Client_Connection *TCP_conn) 190static 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
32typedef struct { 32typedef enum {
33 TCP_PROXY_NONE,
34 TCP_PROXY_HTTP,
35 TCP_PROXY_SOCKS5
36} TCP_PROXY_TYPE;
37
38typedef 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
36enum { 43enum {
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 */
188uint16_t read_TCP_length(sock_t sock) 184unsigned 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 */
204uint16_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 */
224int read_TCP_packet(sock_t sock, uint8_t *data, uint16_t length) 234int 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 */
155void kill_TCP_server(TCP_Server *TCP_server); 155void 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 */
160unsigned 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)
984void Assoc_status(const Assoc *assoc) 996void 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. */
36int crypto_cmp(const uint8_t *mem1, const uint8_t *mem2, uint32_t length) 36int 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. */
46int crypto_cmp(const uint8_t *mem1, const uint8_t *mem2, uint32_t length); 46int 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 */
34static 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 */
54static 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 */
76static 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 */
101static 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
122static 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 */
133int 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. */
150static 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
165static int friend_new_connection(Friend_Connections *fr_c, int friendcon_id);
166/* Callback for DHT ip_port changes. */
167static 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. */
185static 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
219static 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
249static 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
288static 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
315static 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
348static 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
373static 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 */
396int 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 */
411unsigned 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 */
426int 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 */
444void 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 */
455int 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 */
487int 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 */
503int 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 */
540int 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 */
567void 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 */
581int 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. */
611Friend_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. */
631void 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. */
676void 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
51enum {
52 FRIENDCONN_STATUS_NONE,
53 FRIENDCONN_STATUS_CONNECTING,
54 FRIENDCONN_STATUS_CONNECTED
55};
56
57typedef 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
89typedef 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 */
104int 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 */
111int 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 */
117unsigned 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 */
124int 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 */
128void 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 */
136int 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 */
146int 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 */
154int 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 */
161int 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 */
169int 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 */
176void 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. */
180Friend_Connections *new_friend_connections(Onion_Client *onion_c);
181
182/* main friend_connections loop. */
183void do_friend_connections(Friend_Connections *fr_c);
184
185/* Free everything related with friend_connections. */
186void 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 */
38int 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. */
64void set_nospam(Friend_Requests *fr, uint32_t num) 33void 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. */
76void callback_friendrequest(Friend_Requests *fr, void (*function)(void *, const uint8_t *, const uint8_t *, uint16_t, 45void 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. */
92static void addto_receivedlist(Friend_Requests *fr, const uint8_t *client_id) 61static 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 */
106static int request_received(Friend_Requests *fr, const uint8_t *client_id) 75static 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 */
122int remove_request_received(Friend_Requests *fr, const uint8_t *client_id) 91int 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
137static int friendreq_handlepacket(void *object, const uint8_t *source_pubkey, const uint8_t *packet, uint32_t length) 106static 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
172void friendreq_init(Friend_Requests *fr, Onion_Client *onion_c) 141void 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
31typedef struct { 31typedef 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 */
54int 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. */
57void set_nospam(Friend_Requests *fr, uint32_t num); 51void set_nospam(Friend_Requests *fr, uint32_t num);
58uint32_t get_nospam(const Friend_Requests *fr); 52uint32_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 */
65int remove_request_received(Friend_Requests *fr, const uint8_t *client_id); 59int 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 */
70void callback_friendrequest(Friend_Requests *fr, void (*function)(void *, const uint8_t *, const uint8_t *, uint16_t, 64void 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
77void set_filter_function(Friend_Requests *fr, int (*function)(const uint8_t *, void *), void *userdata); 71void 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. */
80void friendreq_init(Friend_Requests *fr, Onion_Client *onion_c); 74void 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 */
34static 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 */
54static 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 */
77static 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 */
103static 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
124static 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
141static 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 */
160static 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 */
179static 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
191static 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
205enum {
206 GROUPCHAT_CLOSEST_NONE,
207 GROUPCHAT_CLOSEST_ADDED,
208 GROUPCHAT_CLOSEST_REMOVED
209};
210
211static int friend_in_close(Group_c *g, int friendcon_id);
212static int add_conn_to_groupchat(Group_Chats *g_c, int friendcon_id, int groupnumber, uint8_t closest, uint8_t lock);
213
214static 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
294static 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
310static int send_packet_online(Friend_Connections *fr_c, int friendcon_id, uint16_t group_num, uint8_t *identifier);
311
312static 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 */
384static 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
437static 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 */
467static 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
519static 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
545static 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
568static 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 */
592static 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
601static 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
615static int handle_packet(void *object, int friendcon_id, uint8_t *data, uint16_t length);
616static 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 */
623static 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 */
667int 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
693static 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 */
699int 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 */
737int 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 */
757int 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 */
786int 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 */
806int 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 */
819unsigned 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 */
840int 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 */
855static 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 */
875static 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 */
900int 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
921static 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 */
930int 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 */
990void 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 */
1001void 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 */
1012void 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 */
1025void 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 */
1036void 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 */
1048void 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 */
1062int 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 */
1080int 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 */
1098int 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
1109static 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
1113int 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 */
1128int 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 */
1152int 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 */
1172static 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 */
1190int 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 */
1222int 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
1239static 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 */
1325static 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 */
1344static 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
1359static 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
1370static unsigned int send_peer_kill(Group_Chats *g_c, int friendcon_id, uint16_t group_num);
1371
1372static 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 */
1430static 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 */
1441static 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 */
1451static 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
1505static 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
1548static 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 */
1601static 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 */
1631static 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 */
1717static 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 */
1755int 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 */
1768int 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 */
1782int 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
1805static 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
1933static 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 */
1987static 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
2038static 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 */
2101int 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 */
2117int 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 */
2136void *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 */
2151void *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
2167static 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
2182static 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 */
2205void 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. */
2222Group_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. */
2241void 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. */
2262void 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 */
2279uint32_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. */
2298uint32_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
30enum {
31 GROUPCHAT_STATUS_NONE,
32 GROUPCHAT_STATUS_VALID,
33 GROUPCHAT_STATUS_CONNECTED
34};
35
36enum {
37 GROUPCHAT_TYPE_TEXT,
38 GROUPCHAT_TYPE_AV
39};
40
41#define MAX_LOSSY_COUNT 256
42
43typedef 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
65enum {
66 GROUPCHAT_CLOSE_NONE,
67 GROUPCHAT_CLOSE_CONNECTION,
68 GROUPCHAT_CLOSE_ONLINE
69};
70
71typedef 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
112typedef 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 */
141void 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 */
148void 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 */
155void 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 */
163void 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 */
171enum {
172 CHAT_CHANGE_PEER_ADD,
173 CHAT_CHANGE_PEER_DEL,
174 CHAT_CHANGE_PEER_NAME,
175};
176void 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 */
186int 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 */
193int 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 */
201int 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 */
209int 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 */
215int 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 */
224int 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 */
230int 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 */
236int 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 */
242int 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 */
251int 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 */
256int 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 */
261unsigned 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 */
273int 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 */
282void 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 */
290int 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 */
296uint32_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. */
303uint32_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 */
310int group_get_type(const Group_Chats *g_c, int groupnumber);
311
312/* Send current name (set in messenger) to all online groups.
313 */
314void 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 */
321int 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 */
328int 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 */
335void *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 */
342void *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 */
351int 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 */
360int 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 */
369int callback_groupchat_delete(Group_Chats *g_c, int groupnumber, void (*function)(void *, int));
370
371/* Create new groupchat instance. */
372Group_Chats *new_groupchats(Messenger *m);
373
374/* main groupchats loop. */
375void do_groupchats(Group_Chats *g_c);
376
377/* Free everything related with group chats. */
378void 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
40typedef struct {
41 uint64_t pingid;
42 //uint8_t client_id[crypto_box_PUBLICKEYBYTES];
43
44} getnodes_data;
45
46typedef struct {
47 uint8_t client_id[crypto_box_PUBLICKEYBYTES];
48 IP_Port ip_port;
49
50} groupchat_nodes;
51
52typedef 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
68static 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 */
85static 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
113static 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 */
146static 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
178static 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 */
203static 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 */
227static 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 */
260static 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 */
276static 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 */
322int 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
337static 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
358static 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
385static 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
407static 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
425static 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)
478static void send_names_new_peer(Group_Chat *chat);
479
480static 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
578static 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
607int 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
645uint32_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
650uint32_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 */
660static 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
668int 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
679uint32_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
685void 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
692void 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
699void 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
706uint32_t group_numpeers(const Group_Chat *chat)
707{
708 return chat->numpeers;
709}
710
711uint32_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
723Group_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
742static 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
762static 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
771static 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
791static 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}
796static 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
810void 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
820void 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
828void 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
833void 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
30typedef 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
47typedef 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
55typedef 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 */
94int 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 */
101void 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 */
109void 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 */
119typedef enum {
120 CHAT_CHANGE_PEER_ADD,
121 CHAT_CHANGE_PEER_DEL,
122 CHAT_CHANGE_PEER_NAME,
123} CHAT_CHANGE;
124
125void 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 */
133uint32_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 */
140uint32_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 */
147int 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 */
153uint32_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 */
162Group_Chat *new_groupchat(Networking_Core *net);
163
164
165/* Return the number of peers in the group chat.
166 */
167uint32_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 */
175uint32_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 */
182void kill_groupchat(Group_Chat *chat);
183
184/*
185 * This is the main loop.
186 */
187void 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. */
192int handle_groupchatpacket(Group_Chat *chat, IP_Port source, const uint8_t *packet, uint32_t length);
193
194
195void chat_bootstrap(Group_Chat *chat, IP_Port ip_port, const uint8_t *client_id);
196void 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
45static struct logger_config { 46
47struct 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;
50logger = { 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
56void __attribute__((destructor)) terminate_logger() 62Logger *global = NULL;
57{ 63
58 if ( !logger.log_file ) return; 64const 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); 72char *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
68unsigned logger_get_pid() 84
85/**
86 * Public Functions
87 */
88Logger *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
78const 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
91int 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); 136FAILURE:
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
148void 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
172void logger_kill_global(void)
173{
174 logger_kill(global);
175 global = NULL;
176}
126 177
127void logger_write (LoggerLevel level, const char *format, ...) 178void 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; 187Logger *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
144char *logger_timestr(char *dest, size_t max_size) 196void 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
32typedef 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 */
42int logger_init(const char *file_name, LoggerLevel level);
43const char *logger_stringify_level(LoggerLevel level);
44unsigned logger_get_pid();
45void logger_write (LoggerLevel level, const char *format, ...);
46char *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 */ 38typedef 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); 46typedef 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 */
51Logger *logger_new (const char *file_name, LOG_LEVEL level, const char *id);
67 52
68#else 53void logger_kill (Logger *log);
54void logger_kill_global (void);
69 55
56/**
57 * Global logger setter and getter.
58 */
59void logger_set_global (Logger *log);
60Logger *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) 65void 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
35static uint8_t crypt_connection_id_not_valid(const Net_Crypto *c, int crypt_connection_id) 36static 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 */
185static int udp_handle_cookie_request(void *object, IP_Port source, const uint8_t *packet, uint32_t length) 186static 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 */
208static int tcp_handle_cookie_request(const Net_Crypto *c, TCP_Client_Connection *TCP_con, uint8_t conn_id, 209static 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 */
231static int tcp_oob_handle_cookie_request(const Net_Crypto *c, TCP_Client_Connection *TCP_con, 232static 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 */
263static int handle_cookie_response(uint8_t *cookie, uint64_t *number, const uint8_t *packet, uint32_t length, 264static 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 */
336static int handle_crypto_handshake(const Net_Crypto *c, uint8_t *nonce, uint8_t *session_pk, uint8_t *peer_real_pk, 337static 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
611static 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 */
759static int send_data_packet_helper(Net_Crypto *c, int crypt_connection_id, uint32_t buffer_start, uint32_t num, 794static 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 */
780static int64_t send_lossless_packet(Net_Crypto *c, int crypt_connection_id, const uint8_t *data, uint32_t length) 815static 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 */
1634static 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 */
1606uint64_t get_connection_dht_key(const Net_Crypto *c, int crypt_connection_id, uint8_t *dht_public_key) 1710unsigned 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 */
1628int set_connection_dht_public_key(Net_Crypto *c, int crypt_connection_id, const uint8_t *dht_public_key, 1730int 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 */
1961int send_tcp_onion_request(Net_Crypto *c, const uint8_t *data, uint16_t length) 2073int 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 */
2091int 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 */
1981void tcp_onion_response_handler(Net_Crypto *c, int (*tcp_onion_callback)(void *object, const uint8_t *data, 2111void 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 */
2370int 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 */
2249static int udp_handle_packet(void *object, IP_Port source, const uint8_t *packet, uint32_t length) 2404static 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 */
2443int64_t write_cryptpacket(Net_Crypto *c, int crypt_connection_id, const uint8_t *data, uint32_t length) 2599int64_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 */
2504int send_lossy_cryptpacket(Net_Crypto *c, int crypt_connection_id, const uint8_t *data, uint32_t length) 2664int 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
85typedef struct { 91typedef 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
166typedef struct { 177typedef 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 */
241uint64_t get_connection_dht_key(const Net_Crypto *c, int crypt_connection_id, uint8_t *dht_public_key); 251unsigned 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 */
250int set_connection_dht_public_key(Net_Crypto *c, int crypt_connection_id, const uint8_t *dht_public_key, 258int 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 */
312int 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 */
309int64_t write_cryptpacket(Net_Crypto *c, int crypt_connection_id, const uint8_t *data, uint32_t length); 329int64_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 */
325int send_lossy_cryptpacket(Net_Crypto *c, int crypt_connection_id, const uint8_t *data, uint32_t length); 346int 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 */
339int add_tcp_relay(Net_Crypto *c, IP_Port ip_port, const uint8_t *public_key); 360int 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 */
343void tcp_onion_response_handler(Net_Crypto *c, int (*tcp_onion_callback)(void *object, const uint8_t *data, 364void 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 */
372int 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 */
351int send_tcp_onion_request(Net_Crypto *c, const uint8_t *data, uint16_t length); 379int 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 */
284int sendpacket(Networking_Core *net, IP_Port ip_port, const uint8_t *data, uint32_t length) 284int 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 */
754void ip_pack(uint8_t *data, const IP *source)
755{
756 data[0] = source->family;
757 memcpy(data + 1, &source->ip6, SIZE_IP6);
758}
759
760void ip_unpack(IP *target, const uint8_t *data)
761{
762 target->family = data[0];
763 memcpy(&target->ip6, data + 1, SIZE_IP6);
764}
765
766void 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
772void 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 */
783static char addresstext[96]; 767static 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 */
811int 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
138typedef union __attribute__ ((__packed__)) 136typedef 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}
145IP4; 142IP4;
146 143
147typedef union __attribute__ ((__packed__)) 144typedef 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}
155IP6; 151IP6;
156 152
157typedef struct __attribute__ ((__packed__)) 153typedef 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}
165IP; 160IP;
166 161
167typedef struct __attribute__ ((__packed__)) __attribute__((gcc_struct)) 162typedef 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 */
189const char *ip_ntoa(const IP *ip); 186const 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 */
203int 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 */
233void ipport_copy(IP_Port *target, const IP_Port *source); 247void ipport_copy(IP_Port *target, const IP_Port *source);
234 248
235
236/* packs IP into data, writes SIZE_IP bytes to data */
237void ip_pack(uint8_t *data, const IP *source);
238/* unpacks IP from data, reads SIZE_IP bytes from data */
239void ip_unpack(IP *target, const uint8_t *data);
240/* packs IP_Port into data, writes SIZE_IPPORT bytes to data */
241void ipport_pack(uint8_t *data, const IP_Port *source);
242/* unpacks IP_Port from data, reads SIZE_IPPORT bytes to data */
243void 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 */
285typedef int (*packet_handler_callback)(void *object, IP_Port ip_port, const uint8_t *data, uint32_t len); 289typedef int (*packet_handler_callback)(void *object, IP_Port ip_port, const uint8_t *data, uint16_t len);
286 290
287typedef struct { 291typedef 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. */
346int sendpacket(Networking_Core *net, IP_Port ip_port, const uint8_t *data, uint32_t length); 350int 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. */
349void networking_registerhandler(Networking_Core *net, uint8_t byte, packet_handler_callback cb, void *object); 353void 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 */
362Networking_Core *new_networking(IP ip, uint16_t port); 366Networking_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 */
49static 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. */
64static 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
85static 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. */
92static 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 */
149int 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 */
96int create_onion_packet(uint8_t *packet, uint16_t max_packet_length, const Onion_Path *path, IP_Port dest, 173int 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 */
153int create_onion_packet_tcp(uint8_t *packet, uint16_t max_packet_length, const Onion_Path *path, IP_Port dest, 228int 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 */
200int send_onion_packet(Networking_Core *net, const Onion_Path *path, IP_Port dest, const uint8_t *data, uint32_t length) 273int 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 */
220int send_onion_response(Networking_Core *net, IP_Port dest, const uint8_t *data, uint32_t length, const uint8_t *ret) 293int 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
236static int handle_send_initial(void *object, IP_Port source, const uint8_t *packet, uint32_t length) 309static 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
260int onion_send_1(const Onion *onion, const uint8_t *plain, uint32_t len, IP_Port source, const uint8_t *nonce) 333int 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
296static int handle_send_1(void *object, IP_Port source, const uint8_t *packet, uint32_t length) 370static 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
345static int handle_send_2(void *object, IP_Port source, const uint8_t *packet, uint32_t length) 420static 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
393static int handle_recv_3(void *object, IP_Port source, const uint8_t *packet, uint32_t length) 469static 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
427static int handle_recv_2(void *object, IP_Port source, const uint8_t *packet, uint32_t length) 505static 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
461static int handle_recv_1(void *object, IP_Port source, const uint8_t *packet, uint32_t length) 541static 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 */
81int create_onion_path(const DHT *dht, Onion_Path *new_path, const Node_format *nodes); 86int 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 */
93int 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 */
92int create_onion_packet(uint8_t *packet, uint16_t max_packet_length, const Onion_Path *path, IP_Port dest, 104int 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 */
105int create_onion_packet_tcp(uint8_t *packet, uint16_t max_packet_length, const Onion_Path *path, IP_Port dest, 117int 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 */
116int send_onion_packet(Networking_Core *net, const Onion_Path *path, IP_Port dest, const uint8_t *data, uint32_t length); 128int 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 */
124int send_onion_response(Networking_Core *net, IP_Port dest, const uint8_t *data, uint32_t length, const uint8_t *ret); 136int 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 */
136int onion_send_1(const Onion *onion, const uint8_t *plain, uint32_t len, IP_Port source, const uint8_t *nonce); 148int 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 */
142void set_callback_handle_recv_1(Onion *onion, int (*function)(void *, IP_Port, const uint8_t *, uint16_t), 154void 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 */
205static int in_entries(const Onion_Announce *onion_a, const uint8_t *public_key) 208static 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
286static int handle_announce_request(void *object, IP_Port source, const uint8_t *packet, uint32_t length) 289static 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
375static int handle_data_request(void *object, IP_Port source, const uint8_t *packet, uint32_t length) 382static 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 */
41int 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 */
41int onion_add_path_node(Onion_Client *onion_c, IP_Port ip_port, const uint8_t *client_id) 71static 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 */
130static int is_path_used(const Onion_Client_Paths *onion_paths, const Node_format *nodes) 180static 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 */
224static int send_onion_packet_tcp_udp(const Onion_Client *onion_c, const Onion_Path *path, IP_Port dest, 292static 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
454static int good_to_ping(Last_Pinged *last_pinged, uint8_t *last_pinged_index, const uint8_t *client_id) 522static 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
524static int handle_announce_response(void *object, IP_Port source, const uint8_t *packet, uint32_t length) 592static 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
580static int handle_data_response(void *object, IP_Port source, const uint8_t *packet, uint32_t length) 650static 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) 684static int handle_dhtpk_announce(void *object, const uint8_t *source_pubkey, const uint8_t *data, uint16_t length)
615static 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 */
696int send_onion_data(const Onion_Client *onion_c, int friend_num, const uint8_t *data, uint32_t length) 770int 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 */
764static int send_dht_fakeid(const Onion_Client *onion_c, int friend_num, const uint8_t *data, uint32_t length) 839static 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
794static int handle_dht_fakeid(void *object, IP_Port source, const uint8_t *source_pubkey, const uint8_t *packet, 869static 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 */
827static int send_fakeid_announce(const Onion_Client *onion_c, uint16_t friend_num, uint8_t onion_dht_both) 902static 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 */
874int onion_friend_num(const Onion_Client *onion_c, const uint8_t *client_id) 949int 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 */
916int onion_addfriend(Onion_Client *onion_c, const uint8_t *client_id) 991int 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 */
1003int onion_set_friend_DHT_pubkey(Onion_Client *onion_c, int friend_num, const uint8_t *dht_key, uint64_t timestamp) 1079int 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 */
1096int 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 */
1039uint64_t onion_getfriend_DHT_pubkey(const Onion_Client *onion_c, int friend_num, uint8_t *dht_key) 1124unsigned 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 */
1061int onion_getfriendip(const Onion_Client *onion_c, int friend_num, IP_Port *ip_port) 1146int 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
1098static void populate_path_nodes(Onion_Client *onion_c) 1185static 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
1200static 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
1119static void do_friend(Onion_Client *onion_c, uint16_t friendnum) 1218static 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
1192static 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. */
1208void oniondata_registerhandler(Onion_Client *onion_c, uint8_t byte, oniondata_handler_callback cb, void *object) 1291void 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
1217static void do_announce(Onion_Client *onion_c) 1300static 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
1263void do_onion_client(Onion_Client *onion_c) 1354void 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 */
1334int onion_isconnected(const Onion_Client *onion_c) 1425int 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
52typedef struct { 62typedef 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 {
66typedef struct { 76typedef 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
72typedef struct { 85typedef 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
109typedef int (*oniondata_handler_callback)(void *object, const uint8_t *source_pubkey, const uint8_t *data, 123typedef 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
112typedef struct { 126typedef 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 */
148int onion_add_path_node(Onion_Client *onion_c, IP_Port ip_port, const uint8_t *client_id); 168int 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 */
161int onion_friend_num(const Onion_Client *onion_c, const uint8_t *client_id); 181int 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 */
168int onion_addfriend(Onion_Client *onion_c, const uint8_t *client_id); 188int 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 */
195int onion_getfriendip(const Onion_Client *onion_c, int friend_num, IP_Port *ip_port); 215int 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
205int recv_tcp_relay_handler(Onion_Client *onion_c, int friend_num, int (*tcp_relay_node_callback)(void *object, 225int 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 */
237int 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 */
215int onion_set_friend_DHT_pubkey(Onion_Client *onion_c, int friend_num, const uint8_t *dht_key, uint64_t timestamp); 247int 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 */
222uint64_t onion_getfriend_DHT_pubkey(const Onion_Client *onion_c, int friend_num, uint8_t *dht_key); 254unsigned 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 */
236int send_onion_data(const Onion_Client *onion_c, int friend_num, const uint8_t *data, uint32_t length); 268int 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. */
239void oniondata_registerhandler(Onion_Client *onion_c, uint8_t byte, oniondata_handler_callback cb, void *object); 271void 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
48struct PING { 48struct 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
132static int handle_ping_request(void *_dht, IP_Port source, const uint8_t *packet, uint32_t length) 132static 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
171static int handle_ping_response(void *_dht, IP_Port source, const uint8_t *packet, uint32_t length) 171static 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 */
228static int in_list(const Client_data *list, uint32_t length, const uint8_t *client_id, IP_Port ip_port) 228static 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
32typedef struct Messenger Tox; 35typedef 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 */
41void tox_get_address(const Tox *tox, uint8_t *address)
42{
43 const Messenger *m = tox;
44 getaddress(m, address);
45}
46 40
47/* 41uint32_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 */
64int32_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. 46uint32_t tox_version_minor(void)
71 *
72 * return the friend number if success.
73 * return -1 if failure.
74 */
75int32_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. 51uint32_t tox_version_patch(void)
82 * return -1 if no such friend.
83 */
84int32_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. 56bool 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 */
96int 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. */
103int 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. 63void 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 */
115int 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. 73struct 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 */
126int 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. 86void 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 */
139uint32_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. 91Tox *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 */
153uint32_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. 172void 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 */
167int 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. 180size_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 */
180uint16_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. 186void 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 */
192int 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. 194static int address_to_ip(Messenger *m, const char *address, IP_Port *ip_port, IP_Port *ip_port_v4)
199 * returns -1 on failure.
200 */
201int 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
207int 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; 219bool 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 */
218int 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
224int tox_set_user_status(Tox *tox, uint8_t status) 246bool 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;
233int 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
239int 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. 275TOX_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 */
249int 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
255int tox_get_self_status_message(const Tox *tox, uint8_t *buf, uint32_t maxlen) 290
291void 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. 296uint32_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 */
266uint8_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
272uint8_t tox_get_self_user_status(const Tox *tox) 302void 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. 309void tox_self_get_address(const Tox *tox, uint8_t *address)
279 * returns -1 on error.
280 */
281uint64_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. 317void 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 */
293int 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. 323uint32_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 */
304uint8_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. 329void 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. */
313uint32_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)
320uint32_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. 337void 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. */
331uint32_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 */
340void 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 345bool 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 */
351void 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 */
361void 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. 365size_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 */
372void 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. 371void 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 */
383void 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. 379bool 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 */
393void 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. 397size_t tox_self_get_status_message_size(const Tox *tox)
401 * function (int32_t friendnumber, uint8_t is_typing)
402 */
403void 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. 403void 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 */
418void 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. 411void 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 */
435void 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.) ************/ 417TOX_STATUS tox_self_get_status(const Tox *tox)
443
444/* Functions to get/set the nospam part of the id.
445 */
446uint32_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
452void tox_set_nospam(Tox *tox, uint32_t nospam) 423static 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;
461void 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 */
478void 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 */
489void 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 */
500void 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. 457uint32_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 */
512void 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. 477uint32_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 */
523int 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 * 496bool 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 */
533int 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. 511uint32_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 */
545int 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 */
554int 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 */
564int 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 }
574int 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 530bool 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 */
584int 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. 549bool tox_friend_exists(const Tox *tox, uint32_t friend_number)
591 * return -1 on failure
592 */
593int 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. 555size_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 */
609int 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. 561void 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. */
619uint32_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. 570size_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. */
630uint32_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
584bool 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 */
644void 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 */
655void 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 */
666void 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
603void 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 */
678int 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 */
690int 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 */
701int 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() 609size_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 */
712int 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. 623bool 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 */
724uint64_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) {
733static 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
759int tox_bootstrap_from_address(Tox *tox, const char *address, uint16_t port, const uint8_t *public_key) 644void 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. 650TOX_STATUS tox_friend_get_status(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_QUERY *error)
767 * return 1 if we are.
768 */
769int 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 665void 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 */
780uint32_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. 671TOX_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 */
791Tox *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. 686void tox_callback_friend_connection_status(Tox *tox, tox_friend_connection_status_cb *function, void *user_data)
820 * Free all datastructures.
821 */
822void 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. */ 692bool tox_friend_get_typing(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_QUERY *error)
829void 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). */
838uint32_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) {
845void 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. */ 706void tox_callback_friend_typing(Tox *tox, tox_friend_typing_cb *function, void *user_data)
852int 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
31extern "C" { 32extern "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 */
48enum {
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 */
62typedef enum {
63 TOX_USERSTATUS_NONE,
64 TOX_USERSTATUS_AWAY,
65 TOX_USERSTATUS_BUSY,
66 TOX_USERSTATUS_INVALID
67}
68TOX_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 */
72typedef struct Tox Tox; 124typedef 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 */
85void tox_get_address(const Tox *tox, uint8_t *address); 175uint32_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. 180uint32_t tox_version_minor(void);
181
182/**
183 * Return the patch number of the library.
184 */
185uint32_t tox_version_patch(void);
186
187/**
188 * Return whether the compiled library version is compatible with the passed
189 * version numbers.
190 */
191bool 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 */
103int32_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 */
110int32_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.
114int32_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 */
121int 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 */
128int tox_del_friend(Tox *tox, int32_t friendnumber); 263enum 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};
283typedef 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
292enum 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};
306typedef 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 */
136int tox_get_friend_connection_status(const Tox *tox, int32_t friendnumber); 313struct 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 */
143int tox_friend_exists(const Tox *tox, int32_t friendnumber); 370void tox_options_default(struct Tox_Options *options);
144 371
145/* Send a text chat message to an online friend. 372
373enum 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};
380typedef 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. 392struct 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 */
157uint32_t tox_send_message(Tox *tox, int32_t friendnumber, const uint8_t *message, uint32_t length); 401void tox_options_free(struct Tox_Options *options);
402
403
404/*******************************************************************************
405 *
406 * :: Creation and destruction
407 *
408 ******************************************************************************/
409
410
411enum 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};
455typedef 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 */
171uint32_t tox_send_action(Tox *tox, int32_t friendnumber, const uint8_t *action, uint32_t length); 477Tox *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 */
181int tox_set_name(Tox *tox, const uint8_t *name, uint16_t length); 487void 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 */
191uint16_t tox_get_self_name(const Tox *tox, uint8_t *name); 496size_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 */
199int tox_get_name(const Tox *tox, int32_t friendnumber, uint8_t *name); 505void 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
515enum 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};
528typedef 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 */
204int tox_get_name_size(const Tox *tox, int32_t friendnumber); 549bool tox_bootstrap(Tox *tox, const char *address, uint16_t port, const uint8_t *public_key, TOX_ERR_BOOTSTRAP *error);
205int 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 */
215int tox_set_status_message(Tox *tox, const uint8_t *status, uint16_t length); 565bool tox_add_tcp_relay(Tox *tox, const char *address, uint16_t port, const uint8_t *public_key,
216int tox_set_user_status(Tox *tox, uint8_t userstatus); 566 TOX_ERR_BOOTSTRAP *error);
567
568
569enum 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};
589typedef 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 */
221int tox_get_status_message_size(const Tox *tox, int32_t friendnumber); 595TOX_CONNECTION tox_get_connection_status(const Tox *tox);
222int 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 */
231int tox_get_status_message(const Tox *tox, int32_t friendnumber, uint8_t *buf, uint32_t maxlen); 603typedef void tox_connection_status_cb(Tox *tox, TOX_CONNECTION connection_status, void *user_data);
232int 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 */
239uint8_t tox_get_user_status(const Tox *tox, int32_t friendnumber); 616void tox_callback_connection_status(Tox *tox, tox_connection_status_cb *function, void *user_data);
240uint8_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 */
246uint64_t tox_get_last_online(const Tox *tox, int32_t friendnumber); 623uint32_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 */
254int tox_set_user_is_typing(Tox *tox, int32_t friendnumber, uint8_t is_typing); 630void 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 */
261uint8_t tox_get_is_typing(const Tox *tox, int32_t friendnumber); 649void 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. */
266uint32_t tox_count_friendlist(const Tox *tox);
267 651
268/* Return the number of online friends in the instance m. */ 652/**
269uint32_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 */
657void 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 662uint32_t tox_self_get_nospam(const Tox *tox);
275 * of out_list will be truncated to list_size. */
276uint32_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 */
281void tox_callback_friend_request(Tox *tox, void (*function)(Tox *tox, const uint8_t *, const uint8_t *, uint16_t, 670void 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 */
287void tox_callback_friend_message(Tox *tox, void (*function)(Tox *tox, int32_t, const uint8_t *, uint16_t, void *), 678void 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 */
293void tox_callback_friend_action(Tox *tox, void (*function)(Tox *tox, int32_t, const uint8_t *, uint16_t, void *), 692enum 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};
700typedef 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 */
300void tox_callback_name_change(Tox *tox, void (*function)(Tox *tox, int32_t, const uint8_t *, uint16_t, void *), 713bool 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 */
307void tox_callback_status_message(Tox *tox, void (*function)(Tox *tox, int32_t, const uint8_t *, uint16_t, void *), 723size_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 */
313void tox_callback_user_status(Tox *tox, void (*function)(Tox *tox, int32_t, uint8_t, void *), void *userdata); 737void 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 */
318void tox_callback_typing_change(Tox *tox, void (*function)(Tox *tox, int32_t, uint8_t, void *), void *userdata); 746bool 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 */
329void tox_callback_read_receipt(Tox *tox, void (*function)(Tox *tox, int32_t, uint32_t, void *), void *userdata); 757size_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 */
342void tox_callback_connection_status(Tox *tox, void (*function)(Tox *tox, int32_t, uint8_t, void *), void *userdata); 771void 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 */
779void 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 */
349uint32_t tox_get_nospam(const Tox *tox); 784TOX_STATUS tox_self_get_status(const Tox *tox);
350void tox_set_nospam(Tox *tox, uint32_t nospam); 785
786
787/*******************************************************************************
788 *
789 * :: Friend list management
790 *
791 ******************************************************************************/
792
793
794enum 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};
829typedef 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 *
355void 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 */
853uint32_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 */
363void tox_callback_group_invite(Tox *tox, void (*function)(Tox *tox, int32_t, const uint8_t *, void *), void *userdata); 875uint32_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
878enum 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};
885typedef 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 */
369void tox_callback_group_message(Tox *tox, void (*function)(Tox *tox, int, int, const uint8_t *, uint16_t, void *), 898bool 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
908enum 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};
916typedef 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 */
376void tox_callback_group_action(Tox *tox, void (*function)(Tox *tox, int, int, const uint8_t *, uint16_t, void *), 924uint32_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
927enum 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};
935typedef 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 */
384typedef enum { 946bool 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
390void 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 */
954bool 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 */
398int tox_add_groupchat(Tox *tox); 963size_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 */
405int tox_del_groupchat(Tox *tox, int groupnumber); 974void 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 */
413int tox_group_peername(const Tox *tox, int groupnumber, int peernumber, uint8_t *name); 988enum 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};
1001typedef 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 */
419int tox_invite_friend(Tox *tox, int32_t friendnumber, int groupnumber); 1010size_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 */
426int tox_join_groupchat(Tox *tox, int32_t friendnumber, const uint8_t *friend_group_public_key); 1026bool 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 */
432int tox_group_message_send(Tox *tox, int groupnumber, const uint8_t *message, uint32_t length); 1037typedef 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 */
438int tox_group_action_send(Tox *tox, int groupnumber, const uint8_t *action, uint32_t length); 1044void 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 */
443int tox_group_number_peers(const Tox *tox, int groupnumber); 1051size_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 */
1065bool 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 */
1078typedef 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 */
455int tox_group_get_names(const Tox *tox, int groupnumber, uint8_t names[][TOX_MAX_NAME_LENGTH], uint16_t lengths[], 1086void 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. */
461uint32_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
468uint32_t tox_get_chatlist(const Tox *tox, int *out_list, uint32_t list_size); 1094 * `friend_status` callback.
1095 */
1096TOX_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 */
1105typedef 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 1112void 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 */
1127TOX_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 */
1137typedef 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 */
1150void 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 */
1162bool 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 */
1172typedef 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 */
1179void 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
511enum { 1188
512 TOX_FILECONTROL_ACCEPT, 1189enum 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. 1196typedef 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 */
522void tox_callback_file_send_request(Tox *tox, void (*function)(Tox *m, int32_t, uint8_t, uint64_t, const uint8_t *, 1208bool 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
1211enum 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};
1235typedef 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 */
1254uint32_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 */
1269uint32_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 */
1280typedef 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 */
1291void 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 */
1313typedef 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 */
1321void 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 */
1334typedef 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 */
533void tox_callback_file_control(Tox *tox, void (*function)(Tox *m, int32_t, uint8_t, uint8_t, uint8_t, const uint8_t *, 1342void 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 */
541void tox_callback_file_data(Tox *tox, void (*function)(Tox *m, int32_t, uint8_t, const uint8_t *, uint16_t length, 1355typedef 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 */
1363void 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
1374enum 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};
1398typedef 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 */
550int tox_new_file_sender(Tox *tox, int32_t friendnumber, uint64_t filesize, const uint8_t *filename, 1419bool tox_hash(uint8_t *hash, const uint8_t *data, size_t length);
551 uint16_t filename_length); 1420
1421
1422enum 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};
1441typedef uint8_t TOX_FILE_CONTROL;
1442
1443enum 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};
1471typedef 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 */
561int tox_file_send_control(Tox *tox, int32_t friendnumber, uint8_t send_receive, uint8_t filenumber, uint8_t message_id, 1483bool 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 */
569int tox_file_send_data(Tox *tox, int32_t friendnumber, uint8_t filenumber, const uint8_t *data, uint16_t length); 1498typedef 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 */
576int tox_file_data_size(const Tox *tox, int32_t friendnumber); 1507void 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
1517enum 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};
1542typedef 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 */
1599uint32_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
1603enum 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};
1628typedef 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 */
585uint64_t tox_file_data_remaining(const Tox *tox, int32_t friendnumber, uint8_t filenumber, uint8_t send_receive); 1643bool 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 */
1674typedef 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 */
1680void 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 */
1704typedef 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 */
1712void 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 */
602int tox_bootstrap_from_address(Tox *tox, const char *address, uint16_t port, const uint8_t *public_key); 1736typedef 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 */
607int tox_isconnected(const Tox *tox); 1742void 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
609typedef 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))*/ 1766enum 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};
1795typedef 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 */
641Tox *tox_new(Tox_Options *options); 1817bool 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.
645void 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 */
1827typedef 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 */
1833void 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 */
652uint32_t tox_do_interval(Tox *tox); 1852bool 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/**
655void 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 */
1862typedef 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 */
1868void 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). */
660uint32_t tox_size(const Tox *tox);
661 1870
662/* Save the messenger in data (must be allocated memory of size Messenger_size()). */
663void 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 */
670int tox_load(Tox *tox, const uint8_t *data, uint32_t length); 1891void tox_get_dht_id(const Tox *tox, uint8_t *dht_id);
1892
1893
1894enum 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};
1901typedef uint8_t TOX_ERR_GET_PORT;
1902
1903/**
1904 * Return the UDP port this Tox instance is bound to.
1905 */
1906uint16_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 */
1912uint16_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
87uint16_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
96void 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
105void 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 */
88int load_state(load_state_callback_func load_state_callback, void *outer, 117int 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 */ 166int create_recursive_mutex(pthread_mutex_t *mutex)
138inline__ 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)
155inline__ 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) {
168inline__ 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 */
184inline__ 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
33void unix_time_update(); 34void unix_time_update();
34uint64_t unix_time(); 35uint64_t unix_time();
@@ -42,22 +43,16 @@ uint32_t id_copy(uint8_t *dest, const uint8_t *src); /* return value is CLIENT_I
42void host_to_net(uint8_t *num, uint16_t numbytes); 43void 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
46uint16_t lendian_to_host16(uint16_t lendian);
47#define host_tolendian16(x) lendian_to_host16(x)
48
49void host_to_lendian32(uint8_t *dest, uint32_t num);
50
45/* state load/save */ 51/* state load/save */
46typedef int (*load_state_callback_func)(void *outer, const uint8_t *data, uint32_t len, uint16_t type); 52typedef int (*load_state_callback_func)(void *outer, const uint8_t *data, uint32_t len, uint16_t type);
47int load_state(load_state_callback_func load_state_callback, void *outer, 53int 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 */ 56int create_recursive_mutex(pthread_mutex_t *mutex);
51void bytes_to_U32(uint32_t *dest, const uint8_t *bytes);
52
53/* Converts 2 bytes to uint16_t */
54void bytes_to_U16(uint16_t *dest, const uint8_t *bytes);
55
56/* Convert uint32_t to byte string of size 4 */
57void U32_to_bytes(uint8_t *dest, uint32_t value);
58
59/* Convert uint16_t to byte string of size 2 */
60void 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 */
101int tox_generate_dns3_string(void *dns3_object, uint8_t *string, uint16_t string_max_len, uint32_t *request_id, 101int 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
28extern "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 */
67int tox_generate_dns3_string(void *dns3_object, uint8_t *string, uint16_t string_max_len, uint32_t *request_id, 74int 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
82int tox_decrypt_dns3_TXT(void *dns3_object, uint8_t *tox_id, uint8_t *id_record, uint32_t id_record_len, 89int 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 @@
1lib_LTLIBRARIES += libtoxencryptsave.la
2
3libtoxencryptsave_la_include_HEADERS = \
4 ../toxencryptsave/toxencryptsave.h
5
6libtoxencryptsave_la_includedir = $(includedir)/tox
7
8libtoxencryptsave_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
27libtoxencryptsave_la_CFLAGS = -I$(top_srcdir) \
28 -I$(top_srcdir)/toxcore \
29 $(LIBSODIUM_CFLAGS) \
30 $(NACL_CFLAGS) \
31 $(PTHREAD_CFLAGS)
32
33libtoxencryptsave_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
41libtoxencryptsave_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
18extern "C" {
19#endif
20
21#define crypto_pwhash_scryptsalsa208sha256_SALTBYTES 32U
22SODIUM_EXPORT
23size_t crypto_pwhash_scryptsalsa208sha256_saltbytes(void);
24
25#define crypto_pwhash_scryptsalsa208sha256_STRBYTES 102U
26SODIUM_EXPORT
27size_t crypto_pwhash_scryptsalsa208sha256_strbytes(void);
28
29#define crypto_pwhash_scryptsalsa208sha256_STRPREFIX "$7$"
30SODIUM_EXPORT
31const char *crypto_pwhash_scryptsalsa208sha256_strprefix(void);
32
33#define crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE 524288ULL
34SODIUM_EXPORT
35size_t crypto_pwhash_scryptsalsa208sha256_opslimit_interactive(void);
36
37#define crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE 16777216ULL
38SODIUM_EXPORT
39size_t crypto_pwhash_scryptsalsa208sha256_memlimit_interactive(void);
40
41#define crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_SENSITIVE 33554432ULL
42SODIUM_EXPORT
43size_t crypto_pwhash_scryptsalsa208sha256_opslimit_sensitive(void);
44
45#define crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_SENSITIVE 1073741824ULL
46SODIUM_EXPORT
47size_t crypto_pwhash_scryptsalsa208sha256_memlimit_sensitive(void);
48
49SODIUM_EXPORT
50int 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
58SODIUM_EXPORT
59int 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
65SODIUM_EXPORT
66int crypto_pwhash_scryptsalsa208sha256_str_verify(const char str[crypto_pwhash_scryptsalsa208sha256_STRBYTES],
67 const char * const passwd,
68 unsigned long long passwdlen);
69
70SODIUM_EXPORT
71int 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
34static const char * const itoa64 =
35 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
36
37static uint8_t *
38encode64_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
54static uint8_t *
55encode64(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
77static int
78decode64_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
90static const uint8_t *
91decode64_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
111uint8_t *
112escrypt_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
187uint8_t *
188escrypt_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
229int
230crypto_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
49typedef struct {
50 void * base, * aligned;
51 size_t size;
52} escrypt_region_t;
53
54typedef escrypt_region_t escrypt_local_t;
55
56extern int escrypt_init_local(escrypt_local_t * __local);
57
58extern int escrypt_free_local(escrypt_local_t * __local);
59
60extern void *alloc_region(escrypt_region_t * region, size_t size);
61extern int free_region(escrypt_region_t * region);
62
63typedef 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
69extern 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
75extern 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
81extern 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
86extern 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
46static inline void
47blkcpy(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
58static inline void
59blkxor(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 */
74static void
75salsa20_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 */
120static void
121blockmix_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 */
152static inline uint64_t
153integerify(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 */
168static void
169smix(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 */
228int
229escrypt_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 @@
1This folder is only meant for use with nacl, i.e. when sodium is unavailable.
2
3
4The files in this folder were mostly copied from
5https://github.com/jedisct1/libsodium/tree/0.7.0/src/libsodium/crypto_pwhash/scryptsalsa208sha256,
6with #ifdef VANILLA_NACL added around each of them as required for this module.
7
8export.h, utils.h, and runtime.h were copied from
9https://github.com/jedisct1/libsodium/tree/0.7.0/src/libsodium/include/sodium.
10utils.h was significantly truncated.
11
12utils.c and runtime.c were copied from
13https://github.com/jedisct1/libsodium/blob/0.7.0/src/libsodium/sodium.
14utils.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 */
50void
51PBKDF2_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 */
47void 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
22static int
23pickparams(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
57size_t
58crypto_pwhash_scryptsalsa208sha256_saltbytes(void)
59{
60 return crypto_pwhash_scryptsalsa208sha256_SALTBYTES;
61}
62
63size_t
64crypto_pwhash_scryptsalsa208sha256_strbytes(void)
65{
66 return crypto_pwhash_scryptsalsa208sha256_STRBYTES;
67}
68
69const char *
70crypto_pwhash_scryptsalsa208sha256_strprefix(void)
71{
72 return crypto_pwhash_scryptsalsa208sha256_STRPREFIX;
73}
74
75size_t
76crypto_pwhash_scryptsalsa208sha256_opslimit_interactive(void)
77{
78 return crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE;
79}
80
81size_t
82crypto_pwhash_scryptsalsa208sha256_memlimit_interactive(void)
83{
84 return crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE;
85}
86
87size_t
88crypto_pwhash_scryptsalsa208sha256_opslimit_sensitive(void)
89{
90 return crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_SENSITIVE;
91}
92
93size_t
94crypto_pwhash_scryptsalsa208sha256_memlimit_sensitive(void)
95{
96 return crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_SENSITIVE;
97}
98
99int
100crypto_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
130int
131crypto_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
182int
183crypto_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
12typedef struct CPUFeatures_ {
13 int initialized;
14 int has_neon;
15 int has_sse2;
16 int has_sse3;
17} CPUFeatures;
18
19static CPUFeatures _cpu_features;
20
21#define CPUID_SSE2 0x04000000
22#define CPUIDECX_SSE3 0x00000001
23
24static 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
47static 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
87static 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
113int
114sodium_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
125int
126sodium_runtime_has_neon(void) {
127 return _cpu_features.has_neon;
128}
129
130int
131sodium_runtime_has_sse2(void) {
132 return _cpu_features.has_sse2;
133}
134
135int
136sodium_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
12extern "C" {
13#endif
14
15SODIUM_EXPORT
16int sodium_runtime_get_cpu_features(void);
17
18SODIUM_EXPORT
19int sodium_runtime_has_neon(void);
20
21SODIUM_EXPORT
22int sodium_runtime_has_sse2(void);
23
24SODIUM_EXPORT
25int 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
39void *
40alloc_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
72static inline void
73init_region(escrypt_region_t * region)
74{
75 region->base = region->aligned = NULL;
76 region->size = 0;
77}
78
79int
80free_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
94int
95escrypt_init_local(escrypt_local_t * local)
96{
97 init_region(local);
98 return 0;
99}
100
101int
102escrypt_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 */
114static inline void
115blockmix_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
165static inline uint32_t
166blockmix_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 */
218static inline uint32_t
219integerify(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 */
232static void
233smix(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 */
312int
313escrypt_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
25static inline uint16_t
26be16dec(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
33static inline void
34be16enc(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
42static inline uint32_t
43be32dec(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
51static inline void
52be32enc(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
62static inline uint64_t
63be64dec(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
73static inline void
74be64enc(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
88static inline uint16_t
89le16dec(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
96static inline void
97le16enc(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
105static inline uint32_t
106le32dec(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
114static inline void
115le32enc(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
125static inline uint64_t
126le64dec(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
136static inline void
137le64enc(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
40void
41sodium_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
64int
65sodium_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
14extern "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
23SODIUM_EXPORT
24void 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 */
31SODIUM_EXPORT
32int 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
44int tox_pass_encryption_extra_length()
45{
46 return TOX_PASS_ENCRYPTION_EXTRA_LENGTH;
47}
48
49int tox_pass_key_length()
50{
51 return TOX_PASS_KEY_LENGTH;
52}
53
54int 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). */
66uint32_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 */
78int 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 */
100int 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 */
110int 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 */
148int 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 */
188int 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 */
204int 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 */
221int 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 */
238int 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 */
271int 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 */
301int 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 */
318int 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 */
335int 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
343int 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
28extern "C" {
29#endif
30
31#include <stdint.h>
32
33#ifndef TOX_DEFINED
34#define TOX_DEFINED
35typedef 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...
40int tox_pass_encryption_extra_length();
41
42int tox_pass_key_length();
43
44int tox_pass_salt_length();
45
46/* return size of the messenger data (for encrypted Messenger saving). */
47uint32_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 */
86int 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 */
94int 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 */
105int 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 */
112int 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 */
132int 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 */
137int 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 */
146int 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 */
159int 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 */
167int 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 */
175int 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 */
182int 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 */
189int tox_is_data_encrypted(const uint8_t *data);
190int 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